Rendering Multiple Rectangles

Started by
7 comments, last by Boaty 14 years, 5 months ago
Hey everyone. You may remember me from that time I was trying to render a rectangle :P Well...now I'm trying to render a whole bunch of them. Edit: Alrighty! I've made a ton of progress. I'm at the point where 40 rectangles render very neatly at the top of the screen, except for one thing: There are a couple points where there will be random strands of yellow (the rectangle color at the moment) that seem to connect rectangles. Breakout Image Any ideas...? I have a theory that it has to do with the Triangle Strip topology, but I don't really know how I would go about fixing it (which means I'll be messing with code for the next hour or so :D)

//--------------------------------------------------------------------------------------
// File:  Main.cpp
//--------------------------------------------------------------------------------------
#include <windows.h>
#include <d3d10.h>
#include <d3dx10.h>

//--------------------------------------------------------------------------------------
// Structures
//--------------------------------------------------------------------------------------
struct SimpleVertices
{
    D3DXVECTOR3 UpLeft;
	D3DXVECTOR3 UpRight;
	D3DXVECTOR3	DownLeft;
	D3DXVECTOR3	DownRight;
};

//--------------------------------------------------------------------------------------
// Global Variables
//--------------------------------------------------------------------------------------
HINSTANCE               g_hInst = NULL;
HWND                    g_hWnd = NULL;
D3D10_DRIVER_TYPE       g_driverType = D3D10_DRIVER_TYPE_NULL;
ID3D10Device*           g_pd3dDevice = NULL;
IDXGISwapChain*         g_pSwapChain = NULL;
ID3D10RenderTargetView* g_pRenderTargetView = NULL;
ID3D10Effect*           g_pEffect = NULL;
ID3D10EffectTechnique*  g_pTechnique = NULL;
ID3D10InputLayout*      g_pVertexLayout = NULL;
ID3D10Buffer*           g_pVertexBuffer = NULL;
bool rectHit[4][10];
SimpleVertices rect[4][10];

//--------------------------------------------------------------------------------------
// Forward declarations
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow );
HRESULT InitDevice();
void CleanupDevice();
LRESULT CALLBACK    WndProc( HWND, UINT, WPARAM, LPARAM );
void Render();

//--------------------------------------------------------------------------------------
// Entry point to the program. Initializes everything and goes into a message processing 
// loop. Idle time is used to render the scene.
//--------------------------------------------------------------------------------------
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow )
{
    if( FAILED( InitWindow( hInstance, nCmdShow ) ) )
        return 0;

    if( FAILED( InitDevice() ) )
    {
        CleanupDevice();
        return 0;
    }

    // Main message loop
    MSG msg = {0};
    while( WM_QUIT != msg.message )
    {
        if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
        else
        {
            Render();
        }
    }

    CleanupDevice();

    return ( int )msg.wParam;
}


//--------------------------------------------------------------------------------------
// Register class and create window
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow )
{
    // Register class
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof( WNDCLASSEX );
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = NULL;
    wcex.hCursor = NULL;
    wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = L"Breakout";
    wcex.hIconSm = NULL;
    if( !RegisterClassEx( &wcex ) )
        return E_FAIL;

    // Create window
    g_hInst = hInstance;
    RECT rc = { 0, 0, 640, 480 };
    AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );
    g_hWnd = CreateWindow( L"Breakout", L"Breakout", WS_OVERLAPPEDWINDOW,
                           CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance,
                           NULL );
    if( !g_hWnd )
        return E_FAIL;

    ShowWindow( g_hWnd, nCmdShow );

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Create Direct3D device and swap chain
//--------------------------------------------------------------------------------------
HRESULT InitDevice()
{	
    HRESULT hr = S_OK;

    RECT rc;
    GetClientRect( g_hWnd, &rc );
    UINT width = rc.right - rc.left;
    UINT height = rc.bottom - rc.top;

    UINT createDeviceFlags = 0;
#ifdef _DEBUG
    createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG;
#endif

    D3D10_DRIVER_TYPE driverTypes[] =
    {
        D3D10_DRIVER_TYPE_HARDWARE,
        D3D10_DRIVER_TYPE_REFERENCE,
    };
    UINT numDriverTypes = sizeof( driverTypes ) / sizeof( driverTypes[0] );

    DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory( &sd, sizeof( sd ) );
    sd.BufferCount = 1;
    sd.BufferDesc.Width = width;
    sd.BufferDesc.Height = height;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.OutputWindow = g_hWnd;
    sd.SampleDesc.Count = 1;
    sd.SampleDesc.Quality = 0;
    sd.Windowed = TRUE;

    for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
    {
        g_driverType = driverTypes[driverTypeIndex];
        hr = D3D10CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags,
                                            D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice );
        if( SUCCEEDED( hr ) )
            break;
    }
    if( FAILED( hr ) )
        return hr;

    // Create a render target view
    ID3D10Texture2D* pBuffer;
    hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), ( LPVOID* )&pBuffer );
    if( FAILED( hr ) )
        return hr;

    hr = g_pd3dDevice->CreateRenderTargetView( pBuffer, NULL, &g_pRenderTargetView );
    pBuffer->Release();
    if( FAILED( hr ) )
        return hr;

    g_pd3dDevice->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL );

    // Setup the viewport
    D3D10_VIEWPORT vp;
    vp.Width = width;
    vp.Height = height;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;
    g_pd3dDevice->RSSetViewports( 1, &vp );

    // Create the effect
    DWORD dwShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
    // Set the D3D10_SHADER_DEBUG flag to embed debug information in the shaders.
    // Setting this flag improves the shader debugging experience, but still allows 
    // the shaders to be optimized and to run exactly the way they will run in 
    // the release configuration of this program.
    dwShaderFlags |= D3D10_SHADER_DEBUG;
    #endif
    hr = D3DX10CreateEffectFromFile( L"Triangle.fx", NULL, NULL, "fx_4_0", dwShaderFlags, 0,
                                         g_pd3dDevice, NULL, NULL, &g_pEffect, NULL, NULL );
    if( FAILED( hr ) )
    {
        MessageBox( NULL,
                    L"The FX file cannot be located.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
        return hr;
    }

    // Obtain the technique
    g_pTechnique = g_pEffect->GetTechniqueByName( "Render" );

    // Define the input layout
    D3D10_INPUT_ELEMENT_DESC layout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
    };
    UINT numElements = sizeof( layout ) / sizeof( layout[0] );

    // Create the input layout
    D3D10_PASS_DESC PassDesc;
    g_pTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
    hr = g_pd3dDevice->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature,
                                          PassDesc.IAInputSignatureSize, &g_pVertexLayout );
    if( FAILED( hr ) )
        return hr;

    // Set the input layout
    g_pd3dDevice->IASetInputLayout( g_pVertexLayout );

    // Create vertex buffer
	float beginX = -1.0f + 0.205f;
	float beginY = 1.0f - 0.1f;
	float brickWidth = 0.15f;
	float brickHeight = 0.1f;
	float spacer = 0.01f;

	for (int row = 0; row < 4; row++)
	{
		for (int col = 0; col < 10; col++)
		{
			rectHit[row][col] = false;
			rect[row][col].UpLeft = D3DXVECTOR3(beginX, beginY, 0.5f);
			rect[row][col].UpRight = D3DXVECTOR3((beginX + brickWidth), beginY, 0.5f);
			rect[row][col].DownLeft = D3DXVECTOR3(beginX, (beginY - brickHeight), 0.5f);
			rect[row][col]
			.DownRight = D3DXVECTOR3((beginX + brickWidth), (beginY - brickHeight), 0.5f);
			
			beginX += (brickWidth + spacer);
		}
		beginX = (-1.0f + 0.205f);
		beginY -= (brickHeight + spacer);
	}

    D3D10_BUFFER_DESC bd;
    bd.Usage = D3D10_USAGE_DEFAULT;
    bd.ByteWidth = sizeof( SimpleVertices ) * 40;
    bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
    bd.CPUAccessFlags = 0;
    bd.MiscFlags = 0;
    D3D10_SUBRESOURCE_DATA InitData;
    InitData.pSysMem = rect;
    hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
    if( FAILED( hr ) )
        return hr;

    // Set vertex buffer
    UINT stride = sizeof( D3DXVECTOR3 );
    UINT offset = 0;
    g_pd3dDevice->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );

    // Set primitive topology
    g_pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Clean up the objects we've created
//--------------------------------------------------------------------------------------
void CleanupDevice()
{
    if( g_pd3dDevice ) g_pd3dDevice->ClearState();

    if( g_pVertexBuffer ) g_pVertexBuffer->Release();
    if( g_pVertexLayout ) g_pVertexLayout->Release();
    if( g_pEffect ) g_pEffect->Release();
    if( g_pRenderTargetView ) g_pRenderTargetView->Release();
    if( g_pSwapChain ) g_pSwapChain->Release();
    if( g_pd3dDevice ) g_pd3dDevice->Release();
}


//--------------------------------------------------------------------------------------
// Called every time the application receives a message
//--------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    PAINTSTRUCT ps;
    HDC hdc;

    switch( message )
    {
        case WM_PAINT:
            hdc = BeginPaint( hWnd, &ps );
            EndPaint( hWnd, &ps );
            break;

        case WM_DESTROY:
            PostQuitMessage( 0 );
            break;

        default:
            return DefWindowProc( hWnd, message, wParam, lParam );
    }

    return 0;
}


//--------------------------------------------------------------------------------------
// Render a frame
//--------------------------------------------------------------------------------------
void Render()
{
    // Clear the back buffer 
    float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // red,green,blue,alpha
    g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor );

    // Render the rectangles
    D3D10_TECHNIQUE_DESC techDesc;
    g_pTechnique->GetDesc( &techDesc );
    for( UINT p = 0; p < techDesc.Passes; ++p )
	{
        g_pTechnique->GetPassByIndex( p )->Apply( 0 );
        g_pd3dDevice->Draw( 40*4, 0 );
    }

    // Present the information rendered to the back buffer to the front buffer (the screen)
    g_pSwapChain->Present( 0, 0 );
}




[Edited by - Boaty on October 31, 2009 12:55:41 PM]
------------------------------do{ WriteGames(); CompileGames(); PlayGames();}while(Me + DX9 + C++ = True♥)†Boaty Program Creed†
Advertisement
Since you put 40*4 vertices in the buffer, Draw must use 40*4, not just 4. Also, I think your vertices might end up outside the screen. Usually in D3D10 the right side of the screen is always 1.0f, and not width. So you would have to divide all the coordinates by width, unless I'm missing something.
Thank you for the remark on Draw. I actually have something appearing on screen now :D
Many of my rectangles are outside of the screen, so I'll work with your remark on 1.0f being the right side. Thanks again! I'll report back in a few.

Edit:
I'm getting a lot of this:
D3D10: WARNING: ID3D10Device::Draw: Vertex Buffer at the input vertex slot 0 is not big enough for what the Draw*() call expects to traverse. This is OK, as reading off the end of the Buffer is defined to return 0. However the developer probably did not intend to make use of this behavior. [ EXECUTION WARNING #356: DEVICE_DRAW_VERTEX_BUFFER_TOO_SMALL ]
D3D10: INFO: Reference Rasterizer: Read of data past end of Buffer with size 1920 in bytes. This has defined behavior, however may not have been intended. (Shown only once until Present() gets called.) [ EXECUTION INFO #334: REF_INFO ]
------------------------------do{ WriteGames(); CompileGames(); PlayGames();}while(Me + DX9 + C++ = True♥)†Boaty Program Creed†
Your stride parameter to IASetVertexBuffers should be sizeof(D3DXVECTOR3), as it is the stride of only one vertex, not the whole rectangle. As of now, it will skip the 3 next vertices, and keep drawing with the first vertex of the next rectangle instead (unless you have a shader that somehow handles 4 vertices).
Thanks, that got rid of that warning which is probably more like an error...however, now all the 'rectangles' (they didn't really look like rectangles...but they were there) are now gone.

So there has to be something that I need to modify, but I just don't know what.

Edit:
As a note, I was messing with tutorial 2, to try and figure out some of the vertex stuff. The origin is in the middle of the screen. Along the X axis, the left-most is -1.0 and the right-most is 1.0. Along the Y axis, the top-most is 1.0, and the bottom-most is -1.0.

It's exactly like a Cartesian grid.
------------------------------do{ WriteGames(); CompileGames(); PlayGames();}while(Me + DX9 + C++ = True♥)†Boaty Program Creed†
Perhaps face-culling is on. Try re-arranging your vertices. Set top left to top right coordinates, and top right to top left coordinates. Not sure if that's it, but could be.
Hmm, that's not it.

Edit:
Might it be the primitive topology?

Edit 2:
Wow, after about 5 minutes of searching, I can't even find a freaking list of the primitive topologies. Anyone know a good reference?
------------------------------do{ WriteGames(); CompileGames(); PlayGames();}while(Me + DX9 + C++ = True♥)†Boaty Program Creed†
Primitive Topologies (Direct3D 10), and D3D10_PRIMITIVE_TOPOLOGY for the actual names to use in code.
Thank you! Gah, all I found when googling were books on DX10.

Edit:

Well, it seems that Triangle Strips are going to be the way to go...so now I'm at a loss once again.

Edit 2:

Got it! I was adding to my Y position variable. I needed to subtract because the Y values decrease from top to bottom. :D

Now just to make them look like they're supposed to...
------------------------------do{ WriteGames(); CompileGames(); PlayGames();}while(Me + DX9 + C++ = True♥)†Boaty Program Creed†

This topic is closed to new replies.

Advertisement