Jump to content

  • Log In with Google      Sign In   
  • Create Account

Awesome job so far everyone! Please give us your feedback on how our article efforts are going. We still need more finished articles for our May contest theme: Remake the Classics

DirectX problem - my C++ program freezes!


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
17 replies to this topic

#1 thedd   Members   -  Reputation: 133

Like
0Likes
Like

Posted 21 October 2012 - 07:45 AM

Hello!
I'm learning DirectX 9 programming, but I've got this problem: I'm simply trying to render 3 lines to represent the 3 axis in the 3D space, but the program I wrote freezes.

I have to open up the Task Manager and close Visual Studio (which during the debug says "Run-Time Check Failure #2 - Stack around the variable 'pVoid' was corrupted")

This is the source code:

Entry point:
http://pastebin.com/BbVdeeNR

AxisRender.cpp:
http://pastebin.com/CNBubgJM

AxisRender.h:
http://pastebin.com/au7j41gw

Thank you in advance for your help!

Sponsor:

#2 Asesh   Members   -  Reputation: 264

Like
0Likes
Like

Posted 21 October 2012 - 12:22 PM

Seems like it's because you have not specified usage parameter when calling CreateVertexBuffer? You should also check the return value of Lock. Just went through my old code and this is what I had done:

CHECK_COM(m_pD3DDevice->CreateVertexBuffer(4 * sizeof(SVertexData), D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &m_pD3DPlaneVertexBuffer, NULL));
CHECK_COM(m_pD3DPlaneVertexBuffer->Lock(0, 0, reinterpret_cast<void **>(&pPlaneVertexBuffer), 0));
pPlaneVertexBuffer[0] = SVertexData(-1.0f, -1.0f, 1.0f, 0.0f, 1.0f);
pPlaneVertexBuffer[1] = SVertexData(-1.0f, 1.0f, 1.0f, 0.0f, 0.0);
pPlaneVertexBuffer[2] = SVertexData(1.0f, 1.0f, 1.0f, 1.0f, 0.0f);
pPlaneVertexBuffer[3] = SVertexData(1.0f, -1.0f, 1.0f, 1.0f, 1.0f);
CHECK_COM(m_pD3DPlaneVertexBuffer->Unlock());

and @line 41: memcpy(&pVoid, Vertices, 6 * sizeof(AxisRenderFV)); you could do this instead: memcpy(&pVoid, Vertices, sizeof(Vertices));

#3 thedd   Members   -  Reputation: 133

Like
0Likes
Like

Posted 21 October 2012 - 12:58 PM

Nope, it doesn't work even with the Usage parameter :(

#4 hunpro   Members   -  Reputation: 428

Like
1Likes
Like

Posted 21 October 2012 - 03:00 PM

Hi,
'memcpy(&pVoid..' has a (big) problem: pVoid is a pointer, and you wanto to copy data to where it points, not where the pVoid variable is stored. Use pVoid instead of &pVoid. With your current code, you overwrite pVoids value, so it points somewhere else, and trash some remaining memory after pVoid, so you end up with that mean message.

#5 thedd   Members   -  Reputation: 133

Like
0Likes
Like

Posted 21 October 2012 - 03:05 PM

Oh! Right... It was a oversight :(
Thank you very much!

#6 thedd   Members   -  Reputation: 133

Like
0Likes
Like

Posted 21 October 2012 - 03:27 PM

Ok, now there's another runtime problem.

Eccezione first-chance a 0x75e3c41f in DX9-Cube.exe: Eccezione di Microsoft C++: long nella posizione di memoria 0x003bf4fc..

In english, it is something like

First-chance exception at 0x75e3c41f in DX9-Cube.exe: Microsoft C++ Exception: long in memory position 0x003bf3fc

(the memory addresses change every time)

I've tried to set some breakpoints, and it seems that the problem happens when axis.Render() is executed, but it can't figure out what's going on wrong :(

#7 thedd   Members   -  Reputation: 133

Like
0Likes
Like

Posted 23 October 2012 - 07:53 AM

Bump :(

#8 hunpro   Members   -  Reputation: 428

Like
0Likes
Like

Posted 24 October 2012 - 06:01 PM

I think i got this error once when i called DrawPrimitveUP() outside of the d3ddev->BeginScene() d3ddev->EndScene() pair. Just a wild guess.

#9 L. Spiro   Crossbones+   -  Reputation: 5181

Like
1Likes
Like

Posted 24 October 2012 - 06:28 PM

You should be using the DirectX Debug Runtime, enabled via the DirectX Control Panel.
It will report more information on this and other errors.


L. Spiro
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#10 Khatharr   Members   -  Reputation: 1575

Like
1Likes
Like

Posted 24 October 2012 - 10:49 PM

Whoa.

Hey, if you're writing a member function you can refer to members directly. The only time you need to say "this->m_Var" is when you have a function-local variable or argument named "m_Var" and you want to refer to the member variable instead of the local one.

You need to check return values of DriectX functions religiously. Probably your vbuffer isn't getting set up correctly.

As was mentioned earlier, since you're talking about an array there (not a pointer) you can just say "sizeof(Vertices)." That also protects you in case you make a change to the size of the array for some reason: You won't have to change the size calculations. (Also in the memcpy() later.)

You need to check the return value not just of lock, but of anything that can return an error. I know it makes the code look big and clunky, and you have to type a bit more than usual, but it will save you a LOT of problems in the long run:

1) It means that you're more aware of possible problem states before you're even done writing the code.
2) If a runtime error happens you get to know what's going on immediately instead of having to debug for an hour.
3) Chicks dig it. Really. You wouldn't believe how many women will flock to you just for checking all your return values.
4) A lot of libraries (like DirectX) use error codes to alert you to a temporary or correctable problem - you can recover from the error easily without the program crashing (or it might not even really be an error).

Something else to look at:
AxisRender::AxisRender(float p_lenght, DWORD color)
{
		this->lenght = p_lenght;
}
should be:

AxisRender::AxisRender(float p_lenght, DWORD color) :
  VertexBuffer(NULL),
  d3ddev(NULL),
  lenght(p_lenght),
  color(color)
{
		//NOP
}

Initializer lists run faster than initializations in the constructor function body. When you write a constructor you should copy and paste all your member variables into the initializer list and then set a default value for all of them there in the same order. Even include the ones that don't matter, like initializing your pointers to NULL - if you don't then the compiler will do it anyway behind the scenes. Doing this also means that won't have forgotten to initialize the member variable 'color'.

I haven't messed with DirectX for a month or two but I think in render_frame() you want to set up the camera prior to calling the axis render. In this case it should correct on the second frame, since the camera setup from the previous frame will be inherited, but generally you want to set up all your matrices and then do your render call, since rendering uses the existing matrix to draw pixels with.

Keep at it, boss. Good luck! Posted Image

Edited by Khatharr, 24 October 2012 - 11:22 PM.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

#11 kauna   Members   -  Reputation: 1138

Like
1Likes
Like

Posted 25 October 2012 - 05:53 AM

Even include the ones that don't matter, like initializing your pointers to NULL - if you don't then the compiler will do it anyway behind the scenes.


I think that the reality is worse, the compiler won't initialize your values to anything (and they will contain garbage) unless you are running debug build. In which case the pointers won't contain NULL either but something more debug friendly such as 0xcccccccc or 0xbaadf00d etc.

Otherwise, the points in this message chain is that OP should
- check the return values of the functions (look for MSDN which functions have return values).
- look for bad pointers. (For example, that map doesn't return NULL pointer).
- run the program step by step with a debugger
- use Direct3D debug libraries

Cheers!

#12 thedd   Members   -  Reputation: 133

Like
0Likes
Like

Posted 25 October 2012 - 01:18 PM

Guys, thank you VERY much!
You have no idea about how much your advises are precious to me Posted Image

Ok, so now I'm using Debug runtime, and I get this output by the debugger:

Eccezione first-chance a 0x7538c41f in DX9-Cube.exe: Eccezione di Microsoft C++: long nella posizione di memoria 0x0036f510..
Direct3D9: (ERROR) :DrawPrimitive failed.
Direct3D9: (ERROR) :Vertex shader declaration is not set

But, why? Why should there be an error about a vertex shader if I do not have one?

Also, I can't really understand this:
AxisRender::AxisRender(float p_lenght, DWORD color) :  VertexBuffer(NULL),  d3ddev(NULL),  length(p_length),  color(color){			 //NOP}
Well, I understand it, but I'm curious to understand the low-level difference from this to assigning variables normally as I was doing Posted Image

Hey, if you're writing a member function you can refer to members directly. The only time you need to say "this->m_Var" is when you have a function-local variable or argument named "m_Var" and you want to refer to the member variable instead of the local one.

I know, but I always to this, always in Java because I like to remove any small possibility of ambiguity
But if you tell me that removing this-> would make the code faster, I will definitely do it!

As was mentioned earlier, since you're talking about an array there (not a pointer) you can just say "sizeof(Vertices)." That also protects you in case you make a change to the size of the array for some reason: You won't have to change the size calculations. (Also in the memcpy() later.)

Yeah, I actually did this some minutes after posting the thread

Edited by thedd, 25 October 2012 - 02:00 PM.


#13 thedd   Members   -  Reputation: 133

Like
0Likes
Like

Posted 25 October 2012 - 01:59 PM

(deleted, see previous post)

Edited by thedd, 25 October 2012 - 02:00 PM.


#14 kauna   Members   -  Reputation: 1138

Like
0Likes
Like

Posted 25 October 2012 - 04:51 PM

"Vertex shader declaration is not set" is a good starting point. You'll need a vertex shader declaration:

http://doc.51windows.net/Directx9_SDK/?url=/directx9_sdk/graphics/programmingguide/gettingstarted/vertexdeclaration/vertexdeclaration.htm

Best regards!

#15 thedd   Members   -  Reputation: 133

Like
0Likes
Like

Posted 26 October 2012 - 07:12 AM

No, I have not! Hahaha it was so easy!
I just forgot to set which FVF I was using during the rendering.

This single line solved all my errors :D
this->d3ddev->SetFVF(AxisRenderFVF);


#16 kauna   Members   -  Reputation: 1138

Like
1Likes
Like

Posted 26 October 2012 - 08:07 AM

Yes, FVF or the Flexible Vertex Format is one way to set the vertex declaration.
However, if you want to upgrade to D3D 10-11 some day, the vertex declaration is the way to go. The vertex declaration has also more freedom.

Cheers!

#17 thedd   Members   -  Reputation: 133

Like
0Likes
Like

Posted 26 October 2012 - 09:49 AM

Oh, right... Thank you :)

#18 Khatharr   Members   -  Reputation: 1575

Like
0Likes
Like

Posted 01 November 2012 - 05:39 PM

Sorry for the late reply, I'm only online occasionally. I'm really glad you got it working!

I know, but I always to this, always in Java because I like to remove any small possibility of ambiguity
But if you tell me that removing this-> would make the code faster, I will definitely do it!


I'm not sure that it would be faster since an object member has an offset based lookup in either case. I'd have to check the disassembly to see if there's a difference. The reason that I brought it up is that as a general rule you want to shy away from bringing customs from one language into another. If you're just coding as a hobbyist then it's not a big deal since you'll probably eventually just grow out of it (or not, but it's not bothering anyone). If you plan to code professionally then people will look down on that kind of thing because it makes the code larger and harder to read and it means that you're doing a lot of extra typing.

If you're concerned about ambiguity then it's good to remember that C++ is a very strongly typed language. The compiler will most likely tell you if you're doing something crazy. The naming convention that I've been using lately is working out well for me (Someone else on the forum suggested it and I tried it out. Thanks to them!).

Basically it's like this:
g_GlobalVariableName
a_ArgumentVariableName
m_MemberVariableName
localVariableName

Again, though, it's an issue of trying to find an efficient writing style rather than an issue of compiled code performance, so it depends on what your long term programming goals are (hobby vs career).
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS