0
votes

I'm sure there is a simple answer to this one somewhere. I currently have a program which correctly renders a .png image as a texture over a rectangle of vertices. This all works fine and displays correctly.

My question is how do I go about rendering a second texture onscreen using a separate image? The easiest/optimal way (I know they are probably different!) The second image I want to add will serve as the background image. I have tried duplicating the CUSTOMVERTEX structure, vertex buffer, separate vertex data, translation matrix, texture stage setting etc.. for the second texture I want to use, but I can only successfully render one on the screen, something is getting overwritten. Unfortunately I am still learning texturing and am missing the right approach. Is a completely separate vertex setup even required?

The code below reflects my working code so far, displaying an image as a texture overlayed on a rectangle of vertices. What should I add to setup & render a separate texture for my background?

    //////////////////////////////////////////////////////
    // I N V A D E R S
    //////////////////////////////////////////////////////


    #include <Windows.h>    // Windows library (for window functions, menus, dialog boxes, etc)
    #include <d3dx9.h>      // Direct 3D library (for all Direct 3D functions).


    //-----START-----DEFINE GLOBAL ELEMENTS----------//
    LPDIRECT3D9             D3D_Object           = NULL; // Name of the Direct3D Obeject. Used to create the D3DDevice
    LPDIRECT3DDEVICE9       D3D_Device           = NULL; // Name of the rendering device
    LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer      = NULL; // Buffer to hold vertices for the rectangle
    LPDIRECT3DTEXTURE9      D3D_Tex_Background   = NULL; // The texture for the background
    LPDIRECT3DTEXTURE9      D3D_Tex_Invader      = NULL; // The texture for the invader

    float g_InvaderX = -50, g_InvaderY = 0, g_InvaderZ = 0;  // starting cooordinates of object

    // A structure for our custom vertex type, containing the vertex & texture coordinates
    struct CUSTOMVERTEX
    {
        D3DXVECTOR3 position;   // Vertex coordinates
        FLOAT u, v;             // Texture coordinates
    };

    // The structure of a vertex in our vertex buffer...
    #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_TEX1)  // it will contain xyz coordinates & a texture


    //////////////////////////////////////////////////////
    // Setup Direct3D
    //////////////////////////////////////////////////////
    HRESULT SetupD3D(HWND hWnd)     
    {
        // Create the D3D object.
        if (NULL == (D3D_Object = Direct3DCreate9(D3D_SDK_VERSION))) return E_FAIL;

        // Set up the structure used to create the D3D Device
        D3DPRESENT_PARAMETERS d3dpp;
        ZeroMemory(&d3dpp, sizeof(d3dpp));
        d3dpp.Windowed = TRUE;                      // application will be windowed
        d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;   // back to front buffer behavior - DISCARD = random data used for error checking
        d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;    // back buffer format - UNKNOWN = use current display resolution to retain consistency
        d3dpp.EnableAutoDepthStencil = TRUE;        // D3D device to create and manage depth and stencil buffer automatically
        d3dpp.AutoDepthStencilFormat = D3DFMT_D16;  // format of the surfaces which hold the depth & stencil buffers - D16 = 16Bit colours


        // Create the D3D Device - on successful completion return a pointer to the created device D3D_Device
        if (FAILED(D3D_Object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                        D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                        &d3dpp, &D3D_Device)))
        {
            return E_FAIL;      // return error if D3D Device creation has failed
        }

        return S_OK;
    }


    //////////////////////////////////////////////////////
    // DIRECT3D CLEANUP
    //
    // Release (delete) all the resources used by this program.
    // Only release things if they are valid (i.e. have a valid pointer).
    // If not, the program will crash at this point.
    //////////////////////////////////////////////////////
    void CleanUp()
    {
        // Delete the textures
        if (D3D_Tex_Background != NULL)  D3D_Tex_Background -> Release();
        if (D3D_Tex_Invader != NULL)     D3D_Tex_Invader -> Release();

        // Release other D3D Device resources
        if (g_pVertexBuffer != NULL) g_pVertexBuffer -> Release();
        if (D3D_Device != NULL)      D3D_Device -> Release();
        if (D3D_Object != NULL)      D3D_Object  -> Release();
    }


    //////////////////////////////////////////////////////
    // Setup the camera
    //////////////////////////////////////////////////////
    void SetupMatrices()
    {
        // Setup View Matrix
         D3DXVECTOR3 vCamera(5.0f, 5.0f, -100.0f);  
         D3DXVECTOR3 vLookat(5.0f, 5.0f, 0.0f);
         D3DXVECTOR3 vUpVector(0.0f, 1.0f, 0.0f);
         D3DXMATRIX matrixView;
         D3DXMatrixLookAtLH(&matrixView, &vCamera, &vLookat, &vUpVector);
         D3D_Device -> SetTransform(D3DTS_VIEW, &matrixView);

         // Setup Projection Matrix
         // This transforms 2D geometry into a 3D space
         D3DXMATRIX matrixProjection;
         D3DXMatrixPerspectiveFovLH(&matrixProjection, D3DX_PI/4, 1.0f, 1.0f, 800.0f);
         D3D_Device -> SetTransform(D3DTS_PROJECTION, &matrixProjection);
    }


    //////////////////////////////////////////////////////
    // SETUP GEOMETRY - 
    // Define a square using the required verticies
    //////////////////////////////////////////////////////
    HRESULT SetupGeometry()
    {
        // Calculate the number of vertices required for the desired graphic
        int Vertices = 2 * 3;   // Six vertices required for the 2 triangles which make up the square.

        // Calculate the size in bytes of the buffer which will hold the vertex information
        // based on the number of verticies required and the elements contained within the CUSTOMVERTEX structure
        int BufferSize = Vertices * sizeof(CUSTOMVERTEX);

        // Create the vertex buffer which will store the vertex data to render
        // (buffer size, special instructions, vertex buffer format, target memory location for buffer,pointer to vertex buffer, future use only)
        if (FAILED(D3D_Device -> CreateVertexBuffer(BufferSize, 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVertexBuffer, NULL)))
        {
            return E_FAIL; // if the vertex buffer could not be created.
        }

    //////////////////////////////////////////////////////
    // Fill vertex buffer with required vertex & texture info
    //////////////////////////////////////////////////////
        CUSTOMVERTEX *pVertices;            // Create a pointer to the first vertex in the buffer.
        if (FAILED(g_pVertexBuffer -> Lock(0, 0, (void**)&pVertices, 0)))  // lock the buffer to prevent interference, allow access using the
        {                                                                  // &pVerticies pointer

            return E_FAIL;  // if the pointer to the vertex buffer could not be established.
        }

        // Fill the vertex buffers with data concerning both vertex and texture locations

        // Triangle 1
        // Vertex 0
        pVertices[0].position.x = 0;    // Vertex coordinates
        pVertices[0].position.y = 0;
        pVertices[0].position.z = 0;
        pVertices[0].u        = 0;      // texture coordinates
        pVertices[0].v        = 1;

        // Vertex 1
        pVertices[1].position.x = 0;
        pVertices[1].position.y = 10;
        pVertices[1].position.z = 0;
        pVertices[1].u        = 0;
        pVertices[1].v        = 0;

        // Vertex 2
        pVertices[2].position.x = 10;
        pVertices[2].position.y = 0;
        pVertices[2].position.z = 0;
        pVertices[2].u        = 1;
        pVertices[2].v        = 1;

        // Triangle 2
        // Vertex 3
        pVertices[3].position.x = 10;
        pVertices[3].position.y = 0;
        pVertices[3].position.z = 0;
        pVertices[3].u        = 1;
        pVertices[3].v        = 1;

        // Vertex 4
        pVertices[4].position.x = 0;
        pVertices[4].position.y = 10;
        pVertices[4].position.z = 0;
        pVertices[4].u        = 0;
        pVertices[4].v        = 0;

        // Vertex 5
        pVertices[5].position.x = 10;
        pVertices[5].position.y = 10;
        pVertices[5].position.z = 0;
        pVertices[5].u        = 1;
        pVertices[5].v        = 0;

        // Unlock the vertex buffer...
        g_pVertexBuffer -> Unlock();

        return S_OK;
    }


    //////////////////////////////////////////////////////
    // Load the textures for the invaders and background
    //////////////////////////////////////////////////////
    void LoadTextures()
    {
            //D3DXCreateTextureFromFile(D3D_Device,         // Direct3D Device name
            //                        "background.jpg",     // Source file in program folder
            //                        &D3D_Tex_Background);     // address of target texture object


            D3DXCreateTextureFromFile(D3D_Device, 
                                      "invader300x300.png", 
                                      &D3D_Tex_Invader);        
    }


    //////////////////////////////////////////////////////
    // Render
    //////////////////////////////////////////////////////
    void Render()
    {
        // Clearing the current frame & Z buffers
        // (rectangles to clear, rectangle coords, clear current buffer & Z buffer, RGB background colour of screen, initial z buffer value, initial
        // stencil buffer value)
        D3D_Device -> Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

        // Once current frame has been cleared, begin drawing new frame
        // lock is created at this point to prevent anything else drawing on the frame
        if (SUCCEEDED(D3D_Device -> BeginScene()))
        {   

            // Construct a translation matrix to move the Invader
            D3DXMATRIX TranslateMatrix;
            D3DXMatrixTranslation(&TranslateMatrix, g_InvaderX, g_InvaderY, g_InvaderZ);
            D3D_Device -> SetTransform(D3DTS_WORLD, &TranslateMatrix);


            // Render the contents of the vertex buffer.
            D3D_Device -> SetStreamSource(0, g_pVertexBuffer, 0, sizeof(CUSTOMVERTEX));
            D3D_Device -> SetFVF(D3DFVF_CUSTOMVERTEX);
            D3D_Device -> DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);


            // Select the invader texture, and initialise the texture stage state...
            D3D_Device -> SetTexture(0,                 // the texture stage being set
                                     D3D_Tex_Invader);  // the object associated with the texture image
            D3D_Device -> SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
            D3D_Device -> SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);


            // Update the invader's x co-ordinate.
            //if (g_RectX <=14.5)                           
            g_InvaderX += 0.5f;

            // Drawing of the scene has finished
            D3D_Device -> EndScene();
        }

        // Present the back frame buffer contents to the screen (front frame buffer swaped with back fram buffer)
        D3D_Device -> Present(NULL, NULL, NULL, NULL);
    }


    //////////////////////////////////////////////////////
    // Windows Message Handling
    //////////////////////////////////////////////////////
    LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        switch (msg)
        {
            case WM_DESTROY:
            {
                PostQuitMessage(0);
                return 0;
            }
        }

        return DefWindowProc(hWnd, msg, wParam, lParam);
    }


    //////////////////////////////////////////////////////
    // Create the application window
    //////////////////////////////////////////////////////
    int WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, int)
    {
        // Register the window class
        WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
                         GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                         "Invaders", NULL};
        RegisterClassEx(&wc);

        // Create the application window
        HWND hWnd = CreateWindow( "Invaders",           // Window class's name
                                  "I N V A D E R S",    // Title bar text
                                  WS_OVERLAPPEDWINDOW,  // The window style
                                  100,                  // window horizontal position
                                  500,                  // window vertical position
                                  800,                  // window width
                                  800,                  // window height
                                  GetDesktopWindow(),   // the parent window's module
                                  NULL,                 // the window's menu handle
                                  wc.hInstance,         // the instance handle
                                  NULL);




        // Initialize Direct3D
        if (SUCCEEDED(SetupD3D(hWnd)))
        {
            // Create the scene geometry
            if (SUCCEEDED(SetupGeometry()))
            {
                // Load the required texture(s) from files into memeory 
                LoadTextures();

                // Display the window onscreen
                ShowWindow(hWnd, SW_SHOWDEFAULT);
                UpdateWindow(hWnd);

                // Initialse the Viewpoint / Camera based on defined settings
                SetupMatrices();

                // Enter message loop to handle any messages MS Windows sends to the application
                MSG msg;
                ZeroMemory(&msg, sizeof(msg));
                while (msg.message != WM_QUIT)
                {
                    if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
                    {
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                    }
                    else
                        Render();
                }
            }
        }

        CleanUp(); // release resources used ( delete all dynamically allocated objects)

        UnregisterClass("Server", wc.hInstance);

        return 0;
    }   // end WinMain
1

1 Answers

2
votes

It seems that you need more basic understanding of programming with directx. Try to do some tutorials like this or this, they are quiet useful.

To your specific question: It seems that you want to make a 2D-Game with images that are drawn onto the screen. Therefore it's easier to use the D3DFVF_XYZRHW (doc), because so you can render untransformed vertices with 2D-Coordinates. To render the background first draw a fullscreen sized quad with you image applied. After that you render your ships in front of that. If your ship isn't drawed, mabye the Z-Buffering determined that your background is in front of it and clipped it away. For 2D-Games either you deactivate ZBuffering or set the depth in the vertices.