Thread: DirectX 9 sprite issue

  1. #1
    Registered User
    Join Date
    Dec 2001
    Posts
    46

    DirectX 9 sprite issue

    Hey all,

    I just realized there's a "game programming" section... So mods, please feel free to delete my post over in the windows programming section :P

    This code compiles fine, but I still don't see a sprite! The image is the right size and is in the same directory as the executable... I'm also not getting an exception when calling Draw().

    Any ideas??

    thanks!

    -maxthecat

    Code:
    #include <d3d9.h>
    #include <d3dx9.h>
    #include <d3dx9core.h>
    #include <dinput.h>
    #include <windows.h>
    
    LPDIRECT3D9 d3d;
    LPDIRECT3DDEVICE9 d3ddev;
    LPDIRECT3DSURFACE9 backbuffer;
    
    
    //LPDIRECTSURFACE9 back;
    LPDIRECTINPUT8 dinput;
    LPDIRECTINPUTDEVICE8 dikeyboard;
    LPD3DXSPRITE sprite;
    LPDIRECT3DTEXTURE9 texture;
    char keys[256];
    
    int Init_Direct3D(HWND);
    int Key_Down(int key);
    void Poll_Keyboard();
    int Game_Init(HWND);
    void Game_Run(HWND);
    //void Game_End(HWND);
    
    typedef struct {
    	int x, y;
    	int width, height;
    	int movex, movey;
    } SPRITE;
    
    SPRITE kitty;
    
    void Game_Run(HWND hwnd)
    {
    	if (d3ddev == NULL)
    		return;
    	HRESULT result;
    
    	Poll_Keyboard();
    	if (Key_Down(DIK_LEFT))
    		kitty.x -= kitty.movex;
    	
    	if (Key_Down(DIK_RIGHT))
    		kitty.x -= kitty.movey;
    	
    	if (Key_Down(DIK_ESCAPE))
    	{
    		PostMessage(hwnd, WM_DESTROY, 0, 0);
    	}
    
    	if (d3ddev->BeginScene())
    	{
    		d3ddev->ColorFill(backbuffer, NULL, D3DCOLOR_XRGB(0,0,0));
    		D3DXVECTOR2 position((float)kitty.x, (float)kitty.y);
    		result = sprite->Draw(
    			texture,
    			NULL,
    			NULL,
    			NULL,
    			0,
    			&position,
    			D3DCOLOR_XRGB(255,255,255)); 
    		if (result != MB_OK)
    		{
    			MessageBox(hwnd, "NoDrawKitty!!", "Trogdor mad!", MB_OK);
    		}
    		sprite->End();
    		d3ddev->EndScene();
    	}
    }
    
    int Game_Init(HWND hwnd)
    {
    	D3DXIMAGE_INFO d3dxImageInfo;
    
    	D3DXCreateTextureFromFileEx( d3ddev,
                                     "cat.bmp",
                                     96, 
                                     96, 
                                     1,   
                                     D3DPOOL_DEFAULT,
                                     D3DFMT_UNKNOWN,
                                     D3DPOOL_DEFAULT,
                                     D3DX_DEFAULT,
                                     D3DX_DEFAULT,
                                     D3DCOLOR_COLORVALUE(0.0f,0.0f,0.0f,1.0f),
                                     &d3dxImageInfo,
                                     NULL,
                                     &texture );
    
    	D3DXCreateSprite(d3ddev, &sprite);
    	
    	kitty.x = 100;
    	kitty.y = 150;
    	kitty.width = 96;
    	kitty.height = 96;
    	kitty.movex = 8;
    	kitty.movey = 0;
    
    	return 1;
    }
    
    int Key_Down(int key)
    {
    	return (keys[key] & 0x80);
    }
    
    void Poll_Keyboard()
    {
    	dikeyboard->GetDeviceState(sizeof(keys), (LPVOID)&keys);
    }
    
    int Init_Direct3D(HWND hwnd)
    {
    	HRESULT result;
    
    	d3d = Direct3DCreate9(D3D_SDK_VERSION);
    	if (d3d == NULL)
    	{
    		MessageBox(hwnd, "Error Initializing D3D", "Error", MB_OK);
    		return 0;
    	}
    
    	D3DPRESENT_PARAMETERS d3dpp;
    	ZeroMemory(&d3dpp, sizeof(d3dpp));
    
    	d3dpp.Windowed = TRUE;
    	d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
    	d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    	d3dpp.BackBufferCount = 1;
    	d3dpp.BackBufferWidth = 640;
    	d3dpp.BackBufferHeight = 480;
    	d3dpp.hDeviceWindow = hwnd;
    	d3dpp.EnableAutoDepthStencil = TRUE;
    	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
    	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
    
    	d3d->CreateDevice(
    		D3DADAPTER_DEFAULT,
    		D3DDEVTYPE_HAL,
    		hwnd,
    		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
    		&d3dpp,
    		&d3ddev);
    
    	if (d3ddev == NULL)
    	{
    		MessageBox(hwnd, "Failed to init d3ddev", "Error!!", MB_OK);
    		return 0;
    	}
    
    	d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
    	d3ddev->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO, &backbuffer);
    	
    	//graphics initlaized... Now for the keyboard!
    
    	result = DirectInput8Create(
    		GetModuleHandle(NULL),
    		DIRECTINPUT_VERSION,
    		IID_IDirectInput8,
    		(void**)&dinput,
    		NULL);
    
    	if (result != DI_OK)
    		return 0;
    
    	result = dinput->CreateDevice(GUID_SysKeyboard, &dikeyboard, NULL);
    	if (result != DI_OK)
    		return 0;
    
    	result = dikeyboard->SetDataFormat(&c_dfDIKeyboard);
    	if (result != DI_OK)
    		return 0;
    
    	result = dikeyboard->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
    	if (result != DI_OK)
    		return 0;
    
    	result = dikeyboard->Acquire();
    	if (result != DI_OK)
    		return 0;
    
    	return 1;
    }
    
    
    
    LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	switch (msg)
    	{
    	case WM_DESTROY:
    		if (d3ddev != NULL)
    			d3ddev->Release();
    
    		if (d3d != NULL)
    			d3d->Release();
    
    		if (dikeyboard != NULL)
    		{
    			dikeyboard->Unacquire();
    			dikeyboard->Release();
    			dikeyboard = NULL;
    		}
    
    		if (backbuffer != NULL)
    			backbuffer->Release();
    
    		if (sprite != NULL)
    			sprite->Release();
    
    		if (texture != NULL)
    			texture->Release();
    
    		/*if (dinput != NULL)
    			dinput->Release();       <------is this needed????*/
    	
    		//Game_End(hWnd);
    		
    		PostQuitMessage(0);
    	}
    	return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    
    ATOM MyRegisterClass(HINSTANCE hInstance)
    {
    	WNDCLASSEX wc;
    	wc.cbSize = sizeof(WNDCLASSEX);
    
    	wc.style = CS_HREDRAW | CS_VREDRAW;
    	wc.lpfnWndProc = (WNDPROC)WinProc;
    	wc.cbClsExtra = 0;
    	wc.cbWndExtra = 0;
    	wc.hInstance = hInstance;
    	wc.hIcon = NULL;
    	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    	wc.lpszMenuName = NULL;
    	wc.lpszClassName = "2D Sprite Test...";
    	wc.hIconSm = NULL;
    
    	return RegisterClassEx(&wc);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
    	MSG msg;
    	HWND hWnd;
    
    	MyRegisterClass(hInstance);
    
    	hWnd = CreateWindow(
    			"2D Sprite Test...",
    			"2D Sprite Test...",
    			WS_OVERLAPPED,
    			CW_USEDEFAULT,
    			CW_USEDEFAULT,
    			640,
    			480,
    			NULL,
    			NULL,
    			hInstance,
    			NULL);
    
    	if (!hWnd)
    		return FALSE;
    
    	ShowWindow(hWnd, nCmdShow);
    	UpdateWindow(hWnd);
    
    	if (!Init_Direct3D(hWnd))
    		return 0;
    
    	if (!Game_Init(hWnd))
    	{
    		MessageBox(hWnd, "Error Initializing Game", "Error ..........!", MB_OK);
    		return 0;
    	}
    	
    	int done = 0;
    	while (!done)
    	{
    		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    		{
    			if (msg.message == WM_QUIT)
    				done = 1;
    
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    		else
    			Game_Run(hWnd);
    	}
    	
    	return msg.wParam;
    }

  2. #2
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Use a D3DXVECTOR3 and set Z to 1.0f.

    Also be sure to turn off ZBuffer and turn depth buffering off.

    Code:
    m_pDevice->SetRenderState(D3DRS_ZENABLE,false);
    If this is a 2D game you won't be needing the zbuffer. If it's on, your sprite fails the test every time.


    D3DXCreateTextureFromFile() should do you fine. I only use Ex in rare instances.

  3. #3
    Registered User
    Join Date
    Dec 2001
    Posts
    46
    I see... I tried changing to a D3DXVECTOR3, but the ID3DXSprite:raw() function complains that it only takes D3DXVECTOR2 pointers. Am I doing something wrong here?

    And, thanks again, Bubba!

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Hmm, maybe they changed it since the last release. I use D3DXVECTOR3 and it works fine.

    Let me check.

    Ok either they changed it or I used D3DXVECTOR2 before w/o remembering it or I'm so used to coding my own sprite functions that I forgot all about how ID3DXSprite works.

    Well then I would say the zbuffer issue might be the problem, although I haven't gone over your code thoroughly.

    I don't use D3DXSprite and for good reason.

    You see that pointer it requires to Draw()? The texture pointer? This means that in the render for the implementation of Draw() it is using Device->SetTexture().

    Now what if you have 500 sprites all with the same texture? It will change textures 500 times when my code will only change it once and leave it there for the remaining 499.

    It is possible the render does check to see if the texture has changed, but I doubt it because it doesn't know what's in the texture, it just uses the interface. It could check to see if the file names are the same but again I doubt it. And if the texture is created from memory, how would they know if it's identical to the one just set? They wouldn't. Look in the optimizations section of the DX SDK and you will see that they tell you to only set the texture when necessary.

    Here is how I set up textures for games.

    The textures are in an array and the array is handled by a class. The array is an array of classes that wrap the IDirect3DTexture9 important interface functions for ease of use. Each texture is given an ID number and this number is simlply it's index in the array. So when rendering here is how I change textures:

    Code:
    DWORD dwID=RenderObject.GetCurTex();
    
    if (m_dwCurTexID!=m_dwID)
    {
      m_pDevice->SetTexture(0,m_pTexContainer->GetTexture(dwID));
      m_dwCurTexID=dwID;
    }
    Code:
    class CTextureContainer;
    class CTexture
    {
      friend class CTextureContainer;
      //All members here are private
    
      IDirect3DTexture9 *m_pTexture;
      ...
    };
    
    class CTextureContainer
    {
      CTexture *m_pTexArray;
      DWORD m_dwTexArraySize;
      ...
      public:
       ...
       IDirect3DTexture9 *GetTexture(dwID)
       {
          if (dwID<m_dwTexArraySize)
         {
            return m_pTexArray[dwID].m_pTexture;
         } else return NULL;
       }
    };
    You might want to think about resource management a bit more.
    Last edited by VirtualAce; 01-02-2006 at 01:53 AM.

  5. #5
    Yah. Morgul's Avatar
    Join Date
    Feb 2005
    Posts
    109
    Bubba: MSDN recommends doing all possible drawing with one sprite, for the exact reason you said.
    Sic vis pacum para bellum. If you want peace, prepare for war.

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Well the only way to accomplish that is to use one texture and then each frame of animation has u and v offsets into that texture. The only reason I've not tried this is because the limit for a texture is video mem is probably about 512x512 and while you could fit a lot of sprites into that, you still couldn't get all of them.

    Then you would have to devise a system by which you could define which larger texture the offsets were for and so on. Again it's possible, but I have not done it this way yet.
    But incrementing offsets in animation would be a lot faster than switching textures. In fact, it would scream.

  7. #7
    Registered User
    Join Date
    Dec 2001
    Posts
    46
    Bubba,

    I'm not entirely sure I follow you in your explanation above... Is there any way I could get you to post a working piece of code that implements this or point me to a good example somewhere??

    As you've by no doubt noticed, I'm very new to DirectX, and boy is it a headache finding good tutorials on DX9, especially the 2D oriented stuff... :P

    thanks again,

    -maxthecat

  8. #8
    Registered User
    Join Date
    May 2006
    Posts
    2

    D3DXSprite

    I know this is grawed thread but for the sake of all people having this problem and bumping into this forum. When drawing with D3DXSprite I have notised that it uses some other coordinate system. I couldnt find any info on this. It seems that 0,0 is the top left of the screen and x and y axis are decreasing. So to render something at 10,10 you would have to pass the vector -10,-10 to it.

  9. #9
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Yes this is true. I have not used ID3DXSprite in a long time but I did have to do some translation to the coordinates in order for it to both display and rotate correctly. My first attempts caused rotation around certain points. What I wanted was rotation about the center of the quad. The offset mentioned here is how I solved the problem.

    The reason I did not respond to this post is because any answer I gave would be implementation specific and might not help anyone else. The basics are found in the optimizations section of the DX SDK. Important ones are:

    1. Only switch textures when absolutely necessary.
    2. Send batches of primitives to be rendered instead of single primitives.
    3. Set transformation matrices only when absolutely necessary as this causes some internal DX computations that may slow down the overall performance.

    The system that I use may or may not be well-suited to any one design. It works for our design and that is why we have chosen to use it. However, in a different situation I would probably use a different design.

    Context is of prime importance in design.

  10. #10
    Registered User
    Join Date
    May 2006
    Posts
    2
    Actually I have solved my problem of using negative coordinates to display positive on screen. I accidentally passed my translation vector as center point of the sprite to the draw method. Im so ashame

    Hey its been 5 years since this thread started... oh well

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Isometric Tile Engine using DirectX
    By Wraithan in forum Game Programming
    Replies: 3
    Last Post: 07-17-2006, 12:16 PM
  2. DirectSound header issues
    By dxfoo in forum C++ Programming
    Replies: 0
    Last Post: 03-19-2006, 07:16 PM
  3. Replies: 5
    Last Post: 03-02-2006, 08:57 AM
  4. DirectX - Starting Guide?
    By Zeusbwr in forum Game Programming
    Replies: 13
    Last Post: 11-25-2004, 12:49 AM
  5. Replies: 3
    Last Post: 05-12-2003, 05:49 PM