1

I am writing a WIN32 DirectX 9 program in which I load a few textures (a person and a background) and display them on the screen. However, they become warped (stretched), not being a one-to-one representation of what I drew in Paint. I tried different window sizes and different screen resolutions, but it still doesn't work.

I can force a very close imitation of the original thing by calling D3DXMatrixTransformation2D before drawing the sprite. However, that doesn't fix the problem. My program relies on me knowing exactly where the person is in relevence to the background (in reality, the background moves and the person stays in the middle of the screen).

Is there something simple I am missing or is it that I just can't do that for some reason? I can give code if it more than a simple fix, but I hope not. For the record, I recieve no errors or warnings; it's just a visual and movement-tracking issue. Thank you.

EDIT: Here's some code:

    //start of program
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

    //Define and register the Windows Class ***Function
    createWindowClass(hInstance);

    //Create the window (still not shown)
    HWND hWnd = CreateWindow("Sample Window Class", "Person With Ship", WS_OVERLAPPEDWINDOW, 
        CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL);

    //Define and create the DirectX9 object ***Function
    HRESULT hr = createDirectX(hWnd);

    D3DXCreateSprite(d3dDevice, &sprite);
    D3DXCreateTextureFromFile(d3dDevice, "landingPad2.png", &texture);
    D3DXCreateTextureFromFile(d3dDevice, "person.png", &person);
    //D3DXCreateTextureFromFile(d3dDevice, "secondRoom.png", &secondRoom);





    //Set up text
    LPD3DXFONT mFont;
    D3DXCreateFont(d3dDevice, 20, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, 
        DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), &mFont );


    //Finally show window
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    //setup keyboard
    RAWINPUTDEVICE Rid[1]; // array of structs for input devices
    Rid[0].usUsagePage = 1; // use 1 for most inputs
    Rid[0].usUsage = 6; //2-mouse, 4-joystick, 6-keyboard
    Rid[0].dwFlags = 0; //use 0
    Rid[0].hwndTarget=NULL; //use NULL
    RegisterRawInputDevices(Rid,1,sizeof(RAWINPUTDEVICE)); // registers all of the input devices


    //MAIN LOOP!!
    MSG msg;
    ZeroMemory(&msg, sizeof(msg));
    while (msg.message!=WM_QUIT) 
    {
        while(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        updateGraphics(hr, mFont);
        updatePosition();

    }
    mFont->Release();
    texture->Release();
    return msg.wParam;
}


void createWindowClass(HINSTANCE hInstance)
{
    const LPCSTR CLASS_NAME  = "Sample Window Class";

    //create windows object
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX); 
    wcex.style= CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc= (WNDPROC)WndProc;
    wcex.cbClsExtra= 0;
    wcex.cbWndExtra= 0;
    wcex.hInstance= hInstance;
    wcex.hIcon= 0;
    wcex.hCursor= LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName= 0;
    wcex.lpszClassName= CLASS_NAME;
    wcex.hIconSm= 0;

    //register windows class
    RegisterClassEx(&wcex);
}

HRESULT createDirectX(HWND hWnd)
{
    //create directx object
    d3dObject = Direct3DCreate9(D3D_SDK_VERSION);
    if (d3dObject==NULL)
    {
        exit(1);
    }

    //Present Parameters struct
    D3DPRESENT_PARAMETERS presParams;

    //Sets everything to 0
    ZeroMemory(&presParams, sizeof(presParams));

    presParams.Windowed = TRUE;
    presParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
    presParams.BackBufferFormat = D3DFMT_UNKNOWN;
    presParams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;

    //DIRECT3D Stuff (not used currently)
    //presParams.EnableAutoDepthStencil = TRUE;
    //presParams.AutoDepthStencilFormat = D3DFMT_D16;
    //d3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
    //D3DXMatrixIdentity( &worldMatrix );

    HRESULT hr = d3dObject->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &presParams, &d3dDevice);
    return hr;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) 
    {
        case WM_INPUT:
        {


            UINT bufferSize;
            GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &bufferSize, sizeof (RAWINPUTHEADER));

            // Create a buffer of the correct size
            BYTE *buffer=new BYTE[bufferSize];

            // Call the function again, this time with the buffer to get the data
            GetRawInputData((HRAWINPUT)lParam, RID_INPUT, (LPVOID)buffer, &bufferSize, sizeof (RAWINPUTHEADER));

            PRAWINPUT raw = (RAWINPUT*) buffer;

            getInput(raw);

            break;
        }
        case WM_COMMAND:
        {
            int wmId    = LOWORD(wParam); 
            int wmEvent = HIWORD(wParam); 

            // Parse the menu selections:
            switch (wmId)
            {
                case IDM_EXIT:
                   DestroyWindow(hWnd);
                break;
            }
            break;
        }
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

void getInput(PRAWINPUT raw)
{
    if (raw->header.dwType== RIM_TYPEKEYBOARD)
            {
                USHORT keyCode = raw->data.keyboard.VKey;

                switch(keyCode)
                {
                    case VK_LEFT:
                        keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
                        if (keyUp == false)
                            counterTrue = true;
                        else
                            counterTrue = false;
                        break;
                    case VK_RIGHT:
                        keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
                        if (keyUp == false)
                            clockwiseTrue = true;
                        else
                            clockwiseTrue = false;
                        break;
                    case VK_UP:
                        keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
                        if (keyUp == false)
                            upTrue = true;
                        else
                            upTrue = false;
                        break;
                    case VK_DOWN:
                        keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
                        if (keyUp == false)
                            downTrue = true;
                        else
                            downTrue = false;
                        break;
                    default:
                        break;
                }
                if (keyCode == 'A')
                {
                    keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
                    if (keyUp == false)
                        leftTrue = true;
                    else
                        leftTrue = false;
                }
                if (keyCode == 'D')
                {
                    keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
                    if (keyUp == false)
                        rightTrue = true;
                    else
                        rightTrue = false;
                }
                if (keyCode == 'W')
                {
                    keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
                    if (keyUp == false)
                        upTrue = true;
                    else
                        upTrue = false;
                }
                if (keyCode == 'S')
                {
                    keyUp=raw->data.keyboard.Flags & RI_KEY_BREAK;
                    if (keyUp == false)
                        downTrue = true;
                    else
                        downTrue = false;
                }
        }
}

void updateGraphics(HRESULT hr, LPD3DXFONT mFont)
{
        hr = d3dDevice->Clear(0, NULL, D3DCLEAR_TARGET| D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
        hr = d3dDevice->BeginScene();



        sprite->Begin(D3DXSPRITE_ALPHABLEND);

        // Texture being used is 64 by 64:
        D3DXVECTOR2 spriteCentre=D3DXVECTOR2(rotationCenter.x, rotationCenter.y);

        // Screen position of the sprite
        D3DXVECTOR2 trans=D3DXVECTOR2(pos.x, pos.y);

        // Build our matrix to rotate, scale and position our sprite
        D3DXMATRIX mat;

        D3DXVECTOR2 scaling(0.5798f, 0.784f);

        // out, scaling centre, scaling rotation, scaling, rotation centre, rotation, translation
        D3DXMatrixTransformation2D(&mat,NULL, NULL, &scaling,&spriteCentre,rotation,NULL/*&trans*/);

        // Tell the sprite about the matrix
        sprite->SetTransform(&mat);

        sprite->Draw(texture, NULL, &rotationCenter, &pos, 0xFFFFFFFF);

        scaling.x = 0.53;
        scaling.y = 0.57f;

        D3DXMatrixTransformation2D(&mat,NULL,0.0, &scaling,&spriteCentre, 0,NULL/*&trans*/);
        sprite->SetTransform(&mat);

        sprite->Draw(person, NULL, NULL, &personPos, 0xFFFFFFFF);

        sprite->End();

        DisplaySomeText(mFont);

        d3dDevice->EndScene();
        d3dDevice->Present(NULL, NULL, NULL, NULL);
}

void updatePosition()
{
        if (clockwiseTrue == true)
        {
            rotation -= (float)0.03;
        }
        else if (counterTrue == true)
        {
            rotation += (float)0.03;
        }

        if (rotation >(PI))
        {
            rotation -= (float)(2*PI);
        }
        if (rotation <= -(PI))
        {
            rotation += (float)(2*PI);
        }

        if (upTrue == true)
        {
            pos.y += (3*cos(rotation));
            pos.x += (3*sin(rotation));
        }
        else if (downTrue == true)
        {
            pos.y -= (3*cos(rotation));
            pos.x -= (3*sin(rotation));
        }

        if (leftTrue == true)
        {
            pos.x += (3*cos(rotation));
            pos.y -= (3*sin(rotation));
        }
        else if (rightTrue == true)
        {
            pos.x -= (3*cos(rotation));
            pos.y += (3*sin(rotation));
        }

        //collision detection
        if (rotation >=0 && rotation < (PI/2))
        {
            if (pos.y - (30*cos(rotation)) - (30*sin(rotation)) < -138 && pos.x < 350 && pos.x > -550)
            {
                pos.y = -142 + (30*cos(rotation)) + (30*sin(rotation));
            }
        }
        if (rotation < 0 && rotation > -(PI/2))
        {
            if (pos.y - (51*cos(rotation)) + (14*sin(rotation)) < -142 && pos.x < 350 && pos.x > -550)
            {
                pos.y = -142 + (51*cos(rotation)) - (14*sin(rotation));
            }
        }
        if (rotation < -(PI/2) && rotation > -(PI))
        {
            if (pos.y + (51*cos(rotation)) + (14*sin(rotation)) < -142 && pos.x < 350 && pos.x > -550)
            {
                pos.y = -142 - (51*cos(rotation)) - (14*sin(rotation));
            }
        }
        if (rotation > (PI/2) && rotation <= (PI))
        {
            if (pos.y + (51*cos(rotation)) - (14*sin(rotation)) < -142 && pos.x < 350 && pos.x > -550)
            {
                pos.y = -142 - (51*cos(rotation)) + (14*sin(rotation));
            }
        }
}

void DisplaySomeText(LPD3DXFONT mFont)
{

// Create a colour for the text - in this case blue
D3DCOLOR fontColor = D3DCOLOR_ARGB(255,0,0,255);    

// Create a rectangle to indicate where on the screen it should be drawn
RECT rct;
rct.left=200;
rct.right=780;
rct.top=10;
rct.bottom=rct.top+20;





TCHAR cX[30] = "x";
TCHAR cY[30] = "y";
TCHAR cR[30] = "r";
TCHAR cQ[30] = "q";
size_t cchDest = 30;

LPCTSTR pszFormat = TEXT("%f");

HRESULT har = StringCchPrintf(cX, cchDest, pszFormat, pos.x);
HRESULT her = StringCchPrintf(cY, cchDest, pszFormat, pos.y);
HRESULT hir = StringCchPrintf(cR, cchDest, pszFormat, rotation);
HRESULT hur = StringCchPrintf(cQ, cchDest, pszFormat, (pos.y - (43*cos(rotation))));


mFont->DrawText(NULL, cX, -1, &rct, 0, fontColor);

rct.left += 100;

mFont->DrawText(NULL, cY, -1, &rct, 0, fontColor);

rct.left += 100;

mFont->DrawText(NULL, cR, -1, &rct, 0, fontColor);

rct.left += 100;

mFont->DrawText(NULL, cQ, -1, &rct, 0, fontColor);

}
Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
Ryan K
  • 3,985
  • 4
  • 39
  • 42
  • what kind of geometry do you try to paint with that texture? how is the view set up? Is there perspective turned on? – vines May 01 '11 at 22:55
  • its a picture of a room with a person on it. The view is from straight up in the air. Don't know anything about perspective, at least from an on/off point of view (no pun). – Ryan K May 02 '11 at 02:07
  • The scaling of the image depends on sprite geometry, texture coordinates of its vertexes and the transformation matrices. Until we know exactly, how it all is set up, we just can't tell where you are wrong :) What you want is to work in screen coordinates with orthogonal projection matrix, but it can be achieved in several ways... – vines May 02 '11 at 02:34
  • Added some code (actually all of it) – Ryan K May 02 '11 at 15:40
  • Nope, I just couldn't compile it yesterday due to some old-and-badly-installed-SDK-related issues... but I'll try again today :) – vines May 03 '11 at 13:56
  • By the way, why do you do the D3DXVECTOR2 scaling(0.5798f, 0.784f); thing? This alone would prevent the image to be rendered with pixel accuracy because of floating-point roundings.. – vines May 03 '11 at 13:59
  • Ok, no problem. That is how I force the image to be accurate. If I leave this out (and then put NULL in the D3DXMatrixTransformation2D calls), then it's distored. This is how it origionally was. I only added the transformation so I can rotate the image. Thanks again! – Ryan K May 03 '11 at 17:16
  • You know, I've just compiled the code with scaling commented out and see my two square textures (256x256) as pure squares... Post a screenshot, maybe? :) – vines May 03 '11 at 23:25
  • Hmmm...i need 10 reputation to post images. I'll need to find a website so I can upload there. In the meantime, is my problem my texture is bigger than the screen? Currently, my screen is 800x600 and my texture (at least in paint) is 1200x800. – Ryan K May 04 '11 at 12:31
  • Ok, here's a link: http://i704.photobucket.com/albums/ww45/Megawolf492/screenshot.png . You can see my window on the left and my paint image on the right. The 200 pixels thing was derived using paint. – Ryan K May 04 '11 at 12:33
  • Texture bigger than screen usually isn't an issue (I once used 4096x4096 on GeForce2 =) ) I'll check it myself when I get home, but for now: try to use background texture with dimensions being powers of 2, both rectangular and square. – vines May 04 '11 at 12:58
  • Ahhhh! There we go. Displays perfectly now, for both images. I never though that it would go funky because it wasn't in powers of 2. It's kinda a small pain but much less than before. Thank you for all of your time! – Ryan K May 04 '11 at 20:00

1 Answers1

1

So, finally: the issue was due to the texture dimensions not being powers of two :) This behaviour is quite usual, but it is still hardware-dependent: in theory there may exist some videocards which handle arbitrary texture sizes the same way as power-of-two-sized ones. To know that they do we'd have to check their capabilities via IDirect3DDevice9::GetDeviceCaps.

vines
  • 5,160
  • 1
  • 27
  • 49