Sign in to follow this  

ID3DXLine::DrawTransform

This topic is 3651 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm working on 2d sprite game in a 645x480 window. Origin (0,0) is the upper-left most corner of the client area. One of the features in the game I'm implementing is drawing lines with the windows cursor. I've been using ID3DXLine::Draw to do my line rendering, and its worked great, but I ended up wanting to render my line under some sprites, and over others. I had to switch to ID3DXLine::DrawTransform to set my line's depth, since Draw doesn't seem to have any support for it, unlike ID3DXSprite. I created and passed a view and orthogonal projection matrix, based on my screen size, to DrawTransform expecting it to turn out exactly like Draw. The line does render and the orientation is correct, but the problem is that the results of DrawTransform and Draw don't seem to match up. When I pass the same line to both, I get two lines rendered in different positions. DrawTransform seems to have a larger unit scale, so the farther to the right and bottom of the screen I go, the less accurate it is. The sprites of my other game objects interact properly with the line rendered with Draw, but not DrawTransform. After rendering, I planned to add translation transforms to adjust the line depth. For some strange reason, changing my window size to 650x505 fixes the problem, but I really want to keep my window size. Can anyone help? What transform matrix am I supposed to pass to DrawTransform to get it to behave exactly like Draw?

Share this post


Link to post
Share on other sites
Forgive me asking but why does the original window have to be 645 x 480? It is an odd resolution - did you mean 640 x 480 which is a standard 4:3 aspect ratio?

The transform you passed to DrawTransform has the following explanation in the SDK help:-

Quote:

pTransform
[in] A scale, rotate, and translate (SRT) matrix for transforming the points. See D3DXMATRIX. If this matrix is a projection matrix, any stippled lines will be drawn with a perspective-correct stippling pattern. Or, you can transform the vertices and use ID3DXLine::Draw to draw the line with a nonperspective-correct stipple pattern.


The problem sounds like a perspective error. Or perhaps your perspective matrix you are using for the lines and the one used to create the projrction matrix are not the same (i would use the actual same matrix).

Quote:

I created and passed a view and orthogonal projection matrix...


A view or orthoganal or projection matrix are not the same.

If you use a normal matrix the lines will be correct if drawn in world space with a depth of 0.5*width where you range is -0.5*width < x < 0.5*width and 0.5*height < y < -0.5*width ASSUMING THE VIEW IS FROM THE ORIGIN. As you are using 2D this is a fair assumption.

I have not tried with a projection matrix but i assume a simiar relationship is observed.

I have a suspician you may have set your apsect ratio to 4:3 (x/y = 1.4) when your resolution isnt. The Draw function is independant of aspect ratio - it works solely in screen coordinates. The DrawTransform is dependant on aspect ratio so would show the difference.

Your stated original resolution has aspect of 1.34375 where as your resolution that works is 1.287 so i am not sure where it has gone wrong.

Perhaps post code if this has not helped.

Regards

Share this post


Link to post
Share on other sites
Quote:
Forgive me asking but why does the original window have to be 645 x 480? It is an odd resolution - did you mean 640 x 480 which is a standard 4:3 aspect ratio?


640, pardon.

I've checked the SDK already, and I thought I understood it, but I'm not quite sure my interpretation is correct anymore. Isn't aspect ratio computed from the width/height parameters you pass to D3DXMatrixOrthoLH?

Here are the relevant sections of my code I'm having trouble with...

Macros:


#define SCREEN_WIDTH_F 640.0f
#define SCREEN_HEIGHT_F 480.0f




Creating the Window:


g_hWnd = CreateWindowEx (
0,
szClassName,
"Program Name",
WS_CAPTION|WS_BORDER|WS_SYSMENU,
CW_USEDEFAULT,
CW_USEDEFAULT,
SCREEN_WIDTH_F,
SCREEN_HEIGHT_F,
HWND_DESKTOP,
NULL,
hThisInstance,
NULL
);




Rendering the Lines:


D3DXMATRIX matView;
D3DXVECTOR3 vEye(SCREEN_WIDTH_F / 2, SCREEN_HEIGHT_F / 2, 1.0f),
vAt(SCREEN_WIDTH_F / 2, SCREEN_HEIGHT_F / 2, -1.0f),
vUp(0.0f,-1.0f,0.0f);
D3DXMatrixLookAtLH(&matView,&vEye,&vAt,&vUp);

D3DXMATRIX matProj;
D3DXMatrixOrthoLH(&matProj, SCREEN_WIDTH_F, SCREEN_HEIGHT_F, 1.0f, -1.0f);

D3DXMATRIX matTran;
D3DXMatrixTranslation(&matTran, 0.0f, 0.0f, LN_DEPTH);
D3DXMATRIX matFinal = matView*matProj;

pD3DLine->Begin();
D3DXVECTOR3 test[] = {D3DXVECTOR3(100,100,0), D3DXVECTOR3(620,470,0)};
D3DXVECTOR2 test2[] = {D3DXVECTOR2(100,100), D3DXVECTOR2(620,470)};
pD3DLine->DrawTransform(&test[0],2,&matFinal,D3DCOLOR_COLORVALUE(1.0f, 1.0f, 1.0f, 1.0));
pD3DLine->Draw(test2,2,D3DCOLOR_COLORVALUE(1.0f, 1.0f, 0.0f, 1.0));
pD3DLine->End();




Here's an image with the result...

http://www.4freeimagehost.com/show.php?i=616b05d99f58.jpg

White line is drawn with DrawTransform
Yellow line is drawn with Draw

If I change the CreateWindowEx parameters for window width and height to 650x505 (but not the Ortho parameters), the yellow and white lines synch up.

Thanks for the assistance...

Share this post


Link to post
Share on other sites
Your right. That all looks fine to me and i was talking rubbish before.

The code is fine as far as i can tell ecept you have the lines;-

D3DXMATRIX matTran;
D3DXMatrixTranslation(&matTran, 0.0f, 0.0f, LN_DEPTH);


which is not used - at least not in the part you showed. Apart from that i dont know what to say.

Good luck

galapogos

Share this post


Link to post
Share on other sites
You're right, I didn't use that line of code, because I wanted to render the line properly first before I twiddled with the depth.

I managed to find another way to fix the problem. Here's what I did:


D3DXMATRIX matView;
D3DXVECTOR3 vEye(SCREEN_WIDTH_F / 2 - 2, SCREEN_HEIGHT_F / 2 - 12, 1.0f),
vAt(SCREEN_WIDTH_F / 2 - 2, SCREEN_HEIGHT_F / 2 - 12, -1.0f),
vUp(0.0f,-1.0f,0.0f);
D3DXMatrixLookAtLH(&matView,&vEye,&vAt,&vUp);

D3DXMATRIX matProj;
D3DXMatrixOrthoLH(&matProj, SCREEN_WIDTH_F - 4, SCREEN_HEIGHT_F - 24, 1.0f, -1.0f);


I'm not entirely sure why this works, but I suspect that it's because the device is larger than the client region of the window. I think it might include the height of the toolbar and the width of the borders, but the numbers I'm getting with GetSystemMetrics aren't adding up. My borders are supposed to be only a pixel thick, and my toolbar is 19 pixels in height. If there are borders on the left and right side of the window, my width should only grow by 2 pixels, so I don't know where the extra 2 are coming from. Same problem with the toolbar. 19 pixels, borders on top and the bottom add up to 21 pixels. If I include that tiny space between the toolbar and the client area, I can squeeze out an extra pixel... so there are still two pixels missing. Odd.

Share this post


Link to post
Share on other sites
Ah! I see. I had that problem a while back but i forgot about it.

My solution was found on the net where there is an efficient way of stating your resolution independant in windows borders etc. I recomend as (a) different users can have different border thicknesses so it is not good to assume it will always be -12 or whatever and (b) It lets you states the windows properties (ie do you want a message bar or title or the little buttons in the top right.

This is my code from an old project:-


//Register Class and Create new Window
RegisterClass(&windowClass);
//Calculate the proper size for the window given a client of resX x resY
debug.PrintEndl("...Correcting for borders/menu's (etc)...");
DWORD dwFrameWidth = GetSystemMetrics( SM_CXSIZEFRAME );
DWORD dwFrameHeight = GetSystemMetrics( SM_CYSIZEFRAME );
DWORD dwMenuHeight = GetSystemMetrics( SM_CYMENU );
DWORD dwCaptionHeight = GetSystemMetrics( SM_CYCAPTION );
DWORD dwWindowWidth = width + (dwFrameWidth * 2);
DWORD dwWindowHeight = height + (dwFrameHeight * 2) +
dwCaptionHeight; //if have menu add dwMenuHeight

// Create and show the main window(with PROPER sizes!!!
DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_CAPTION & ~WS_SYSMENU; //hold mouse over WS_OVERLAPPEDWINDOW to see all options.


mainWindow = CreateWindow(TEXT("MY_WINDOWS_CLASS"), appName, dwStyle,
CW_USEDEFAULT, CW_USEDEFAULT, dwWindowWidth,
dwWindowHeight, NULL, NULL, hInstance, NULL);



I think it is mostly self explanatory but you will need to adapt to your needs.

The line:-

// Create and show the main window(with PROPER sizes!!!
DWORD dwStyle = WS_OVERLAPPEDWINDOW & ~WS_CAPTION & ~WS_SYSMENU; //hold mouse over WS_OVERLAPPEDWINDOW to see all options.


..is the most inter esting as by changing the flags you put into dwstyle changes the windows properties (in windows).

The full list is:-
Quote:

WS_BORDER Creates a window that has a border.

WS_CAPTION Creates a window that has a title bar (implies the WS_BORDER style). Cannot be used with the WS_DLGFRAME style.

WS_CHILD Creates a child window. Cannot be used with the WS_POPUP style.

WS_CHILDWINDOW Same as the WS_CHILD style.

WS_CLIPCHILDREN Excludes the area occupied by child windows when you draw within the parent window. Used when you create the parent window.

WS_CLIPSIBLINGS Clips child windows relative to each other; that is, when a particular child window receives a paint message, the WS_CLIPSIBLINGS style clips all other overlapped child windows out of the region of the child window to be updated. (If WS_CLIPSIBLINGS is not given and child windows overlap, when you draw within the client area of a child window, it is possible to draw within the client area of a neighboring child window.) For use with the WS_CHILD style only.

WS_DISABLED Creates a window that is initially disabled.

WS_DLGFRAME Creates a window with a double border but no title.

WS_GROUP Specifies the first control of a group of controls in which the user can move from one control to the next with the arrow keys. All controls defined with the WS_GROUP style FALSE after the first control belong to the same group. The next control with the WS_GROUP style starts the next group (that is, one group ends where the next begins).

WS_HSCROLL Creates a window that has a horizontal scroll bar.

WS_ICONIC Creates a window that is initially minimized. Same as the WS_MINIMIZE style.

WS_MAXIMIZE Creates a window of maximum size.

WS_MAXIMIZEBOX Creates a window that has a Maximize button.

WS_MINIMIZE Creates a window that is initially minimized. For use with the WS_OVERLAPPED style only.

WS_MINIMIZEBOX Creates a window that has a Minimize button.

WS_OVERLAPPED Creates an overlapped window. An overlapped window usually has a caption and a border.

WS_OVERLAPPEDWINDOW Creates an overlapped window with the WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX styles.

WS_POPUP Creates a pop-up window. Cannot be used with the WS_CHILD style.

WS_POPUPWINDOW Creates a pop-up window with the WS_BORDER, WS_POPUP, and WS_SYSMENU styles. The WS_CAPTION style must be combined with the WS_POPUPWINDOW style to make the Control menu visible.

WS_SIZEBOX Creates a window that has a sizing border. Same as the WS_THICKFRAME style.

WS_SYSMENU Creates a window that has a Control-menu box in its title bar. Used only for windows with title bars.

WS_TABSTOP Specifies one of any number of controls through which the user can move by using the TAB key. The TAB key moves the user to the next control specified by the WS_TABSTOP style.

WS_THICKFRAME Creates a window with a thick frame that can be used to size the window.

WS_TILED Creates an overlapped window. An overlapped window has a title bar and a border. Same as the WS_OVERLAPPED style.

WS_TILEDWINDOW Creates an overlapped window with the WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX styles. Same as the WS_OVERLAPPEDWINDOW style.

WS_VISIBLE Creates a window that is initially visible.

WS_VSCROLL Creates a window that has a vertical scroll bar.


Finally i would mention you should be carefull when playing with some of these flags as they are not all useful or recomended with a DX application.

Also remember to keep track of what elements your window has - you may need to update DWORD dwWindowWidth and DWORD dwWindowHeight if you are adding/removing elements.

NOTE:- ignor all lines starting with debug.whatever.. this is just my custom log file generator and is not relevant for you.

Regards

Share this post


Link to post
Share on other sites
Sorry, I haven't been able to work on this in awhile. Thanks for responding.

Quote:

My solution was found on the net where there is an efficient way of stating your resolution independant in windows borders etc. I recomend as (a) different users can have different border thicknesses so it is not good to assume it will always be -12 or whatever and (b) It lets you states the windows properties (ie do you want a message bar or title or the little buttons in the top right.


I agree with (a), which is why I'm looking for a better solution to this problem.

I actually already make use of dwstyles when I use CreateWindowEx... you'll actually notice it on the code I posted before, but the line I use is:

WS_CAPTION|WS_BORDER|WS_SYSMENU


What I end up with visually is a window with a simple title bar and thin, non-resizable borders. The only things on the title bar are the window title and the 'X' system menu button for closing the window.

I've also already used GetSystemMetrics, I mentioned it here:

Quote:
I think it might include the height of the toolbar and the width of the borders, but the numbers I'm getting with GetSystemMetrics aren't adding up.


Here's the code I use:


int y_menu = GetSystemMetrics(SM_CYMENU); //19
int y_caption = GetSystemMetrics(SM_CYCAPTION); //19
int x_border = GetSystemMetrics(SM_CXBORDER); //1
int y_border = GetSystemMetrics(SM_CYBORDER); //1
int x_edge = GetSystemMetrics(SM_CXEDGE); //2
int y_edge = GetSystemMetrics(SM_CYEDGE); //2



I ran this code with breakpoints to check the run-time values of my window's properties. The commented numbers next to each line is the value I'm getting at run-time.

Logically, what I expected was to simply add y_caption (19) and y_border (1x2) to the height. The resulting value in pixels would be 21. For the width, I would add 1 pixel for both the left and right borders (2).

But when I add this to my client area height and pass the values to D3DXMatrixOrthoLH and D3DXMatrixLookAtLH, I end up with my old problem of the DrawTransform not synching up with Draw.

By trial and error, I found the correct values to be height plus 24 instead of 21, and width plus 4, instead of 2. These values synch up DrawTransform with Draw.

So what I'm wondering is, where do the extra 2 pixels for the width, and the extra 3 pixels for the height come from? Should I be using SM_CXEDGE instead of SM_CXBORDER even though I'm not using a 3d border? Am I missing some other padding INSIDE the window? Perhaps around the client area or around the title bar?

Share this post


Link to post
Share on other sites

This topic is 3651 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this