Sunday, February 6, 2011

The IDXGISwapChain

IDXGISwapChain *g_swapChain = NULL;

Since we will be creating them together lets explain the swap chain. A swap chain is one or more back buffers used to make rendering more smooth. While the device renders one image on your screen the swap chain buffers another image in wait which can be swapped out with the last image. When you think that your game has to process AI, movement, player and enemy health, and more as well as graphics that update 60 times a second you can see why processing the screen image early and often can be useful. It is recommended to have at least 2 buffers.

The ID3D10Device

 ID3D10Device *g_d3dDevice = NULL

Declares an ID3D10Device pointer as NULL. Later when we initialize D3D10 we will actually create it with the function D3D10CreateDeviceAndSwapChain(), but for now this is sufficient. But what exactly is the ID3D10Device? Our d3dDevice will be the access point to the video hardware. All of the methods involved in drawing to the screen and accessing VRAM are handled through this device.

DirectX 10 Programming Tutorial 1.2

/******************************************************************************
Our first program with DirectX!  Let's jump straight into code and then explain what is going on as we go.
If you are just joining me you should start here to get an idea of basic Win32 applications as this code just fits on top of that code.
******************************************************************************/

#include <D3D10.h>
#include <D3DX10.h>

//D3D Global variables
ID3D10Device *g_d3dDevice = NULL;
IDXGISwapChain *g_swapChain = NULL;
ID3D10RenderTargetView *g_renderTargetView = NULL;

//Function Declarations
bool Initialize(HWND hWnd);
void Render();
void ResizeWindow(int width, int height);
void ShutDown();

/***************************************************************************
To save space I've decided to put the definition of each of these on a separate page so click on each new type to go to a description of what each is and why we need it. Now, we have declared our device, swap chain and render target view and have functions to intialize, render, resize and shutdown. I'll start by defining these functions and then we'll go back through our Win32 app code to put them to use.
****************************************************************************/
 bool Initialize(HWND hWnd)
{
    DXGI_SWAP_CHAIN_DESC scDesc;
    ZeroMemory(&scDesc, sizeof(scDesc));
    
    //We need to define and create the swap chain
    scDesc.BufferCount = 2;
    scDesc.BufferDesc.Width = WINDOW_WIDTH;
    scDesc.BufferDesc.Height = WINDOW_HEIGHT;
    scDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    scDesc.BufferDesc.RefreshRate.Numerator = 60;
    scDesc.BufferDesc.RefreshRate.Denominator = 1;
    scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    scDesc.OutputWindow = hWnd;
    scDesc.SampleDesc.Count = 1;
    scDesc.SampleDesc.Quality = 0;
    scDesc.Windowed = TRUE;

    //Setup the debug utility for testing
    unsigned int flags = 0;

#ifdef _DEBUG
    flags |= D3D10_CREATE_DEVICE_DEBUG;
#endif

    //Create a loop to test for availability of Reference or Hardware
    //Driver type
    D3D10_DRIVER_TYPE driverType = D3D10_DRIVER_TYPE_NULL;
    D3D10_DRIVER_TYPE driverTypes[] =
    {
        D3D10_DRIVER_TYPE_HARDWARE,
        D3D10_DRIVER_TYPE_REFERENCE,
    };

    HRESULT hr = NULL;

    unsigned int numDriverTypes = sizeof(driverTypes) / sizeof(driverTypes[0]);
    for (unsigned int i = 0; i < numDriverTypes; i++)
    {
        driverType = driverTypes[i];

        hr = D3D10CreateDeviceAndSwapChain(NULL,
            driverType,
            NULL,
            flags,
            D3D10_SDK_VERSION,
            &scDesc,
            &g_swapChain,
            &g_d3dDevice);

        if(SUCCEEDED(hr))
            break;
    }

    if(FAILED(hr))
        return false;

    ID3D10Texture2D *buffer = NULL;
    hr = g_swapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&buffer);
   
    if(FAILED(hr))
        return false;

    //Create the render target view

    hr = g_d3dDevice->CreateRenderTargetView(buffer, NULL, &g_renderTargetView);

    buffer->Release();

    if(FAILED(hr))
        return false;

    //Set the render target
    g_d3dDevice->OMSetRenderTargets(1, &g_renderTargetView, NULL);


    ResizeWindow(WINDOW_WIDTH, WINDOW_HEIGHT);

    return true;
}




 void ResizeWindow(int width, int height)
{
    if(g_d3dDevice == NULL)
        return;

    D3D10_VIEWPORT vp;

    vp.Width = width;
    vp.Height = height;
    vp.MaxDepth = 1.0f;
    vp.MinDepth = 0.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;

    g_d3dDevice->RSSetViewports(1, &vp);
}

 void Render()
{
    float col[4] = { 1, 0, 0, 1 };

    g_d3dDevice->ClearRenderTargetView(g_renderTargetView, col);

    g_swapChain->Present( 0, 0 );
}

void ShutDown()
{
    // Release memory
    if(g_d3dDevice) g_d3dDevice->ClearState();
    if(g_swapChain) g_swapChain->Release();
    if(g_renderTargetView) g_renderTargetView->Release();
    if(g_d3dDevice) g_d3dDevice->Release();
}


/***************************************************************************
The Initialize() function is the longest function so far and it just gets us set up so we can do the fun stuff. Again it's description is posted separately, as well as the resize, render, and shutdown functions. Now we should put our code to use in our window.
****************************************************************************/
//To WndProc() we add:
int height,width;

//In WM_DESTROY... break;
case WM_SIZE:
    height = HIWORD(lParam);
    width = LOWORD(lParam);

    if(height == 0)
        height = 1;
    ResizeWindow(width, height);


//In WinMain()
//Replace old message loop from while(msg.message != WM_QUIT)
//to DispatchMessage(&msg) } } with:
if(Initialize(hWnd))
{
    while(true)
    {
        if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            if(msg.message == WM_QUIT) break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            Render();
        }
    }
}

/***************************************************************************
And you're done! When you compile this code you should get a blank window filled with red. You can change this color by changing the values for col in Render() realizing that the values are Red, Green, Blue, and Alpha. Alpha is the opacity and values range from 0 being none to 1 maximum See the wiki article on RGBA for more information.
***************************************************************************/
DirectX 10 Programming Tutorial 1.1

Saturday, February 5, 2011

DirectX 10 ProgrammingTutorial 1.1

DirectX is a collection of APIs(Application Programming Interfaces) that give you advanced control of video, sound,  and input on the Windows system. ***NOTE*** DirectX 10 is only available for Windows versions Vista and later. The hardest part of starting with DirectX so far for me has been, well, starting with DirectX. I'll get the code in word for word from some book or tutorial and get a whole slew of errors. I kept thinking it was poor authoring or something but I realized I just did not know how to set DirectX up properly for my IDE.  To start out you should go here to download the DirectX10 SDK.  Also, so that you can create shaders which will be needed as we progress through DX, I recommend downloading NVIDIA's FX Composer 2.5.

There are a few ways we could start but I like the way Allen Sharrod started in Ultimate Game Programming with DirectX, Second Edition so that is how I will start. But first, let's get VC++ set up for DirectX. If you have your skeleton file created from the last tutorial you should now:

1. Go to Project->Properties->Configuration Properties->VC++ Directories->Include Directories.
2. Select the down arrow and then edit.
3. Click the folder Icon. Click the ... button.
4. Navigate to the folder you installed the DirectX 10 SDK to.
5. Navigate into the folder to the Include folder.
6. Click Select Folder click OK.
7. Repeat steps 1-6 for the Library Directories navigating to the lib/x86 folder.
8. Go to Project->Properties->Configuration Properties->Linker->Input
9. Select Additional Dependencies
10. Select the down arrow, then edit
11. Add "d3d10.lib; d3dx10.lib" not including the quotes.
12. Accept the changes and you are done. You should now be able to start working on our first DirectX Program!

First Win32 application

/****NOTE****
The following code has been borrowed from many sources which I will try to note as I go through this. This blog is to benefit my learning and if it helps others at the same time, all the better. Each author has their own way they like to code and I have taken things from each which makes the most sense to me. I am not just copy and pasting other people's code, I could just give you a link if I was doing that, but I will not claim anything as to be straight from my own mind either.
****ENDNOTE****

The following is a very basic Windows program using no DirectX to start with. This is the basis, the palette, upon which the rest of the DirectX will lay upon. So to start... Open up Microsoft Visual C++ 2010 Express (click the link to download if you do not have it). When you first open up VC++ there is an option on the front screen to open a New Project, or you can click File->New->Project. You will see a screen like that below.
Click Browse to select the folder you want to put the project in, name your project, and select Empty Project, then OK to begin. You will then have an empty project in front of you that needs a file. Select File->New->File... or <CTRL>+<SHIFT>+<A> . Select ".cpp" as the type and name your .cpp file. I will use "main.cpp" to refer to this file from here on. Before we start coding let's go to Project->Properties->Configuration Properties->General->Character Set and change the character set from "Use Unicode Character Set" to "Use Multi-Byte Character Set".

Let's add some code:*/

#include <Windows.h>

#define CLASS_NAME     "First Window"
#define WINDOW_NAME    "First Window"
#define WINDOW_WIDTH    800
#define WINDOW_HEIGHT   600

HINSTANCE hInstance = NULL;
HWND hWnd = NULL;

bool InitWindow( HINSTANCE hInstance, int width, int height );
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );

/*This first part defines some global variables to create this first window. WINDOW_NAME, WINDOW_WIDTH, and WINDOW_HEIGHT are self explanatory. HINSTANCE is a windows type that holds the application instance(the executable module). HWND is a global variable that holds a Windows handle. I'll go more into what this is when we define it in InitWindow() but the handle holds the name, size, and style of the window we are creating.*/

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE      hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
    // Initialize the window
    if( !InitWindow( hInstance, WINDOW_WIDTH, WINDOW_HEIGHT))
    {
        MessageBox(NULL, "Initialization Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
    
    // Main message loop
    MSG msg = {0};
    while( msg.message != WM_QUIT)
    {
        while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) == TRUE)
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return (int)msg.wParam;
}

/*That code above is what takes the place of the typical C++ main() function.The first thing we do in our main function is initialize our window. We place the function bool InitWindow() call in an if statement which will pop up a message box error and end our program if initialization fails. We then create a MSG handle which we will use to handle messages (mouse clicks, key strokes, etc.). PeekMessage() can be replaced by GetMessage() however PeekMessage() is faster and is recommended in every game programming book I have read so far.  Now let's define our InitWindow() function there is a lot that goes into it but it's not as difficult as it looks at first:*/

bool InitWindow( HINSTANCE hInstance, int width, int height )

{

    WNDCLASSEX wncl;

    memset(&wncl, 0, sizeof(WNDCLASSEX));
    wncl.cbSize = sizeof(WNDCLASSEX);
    wncl.style = CS_HREDRAW | CS_VREDRAW;
    wncl.lpfnWndProc = WndProc;
    wncl.hInstance = hInstance;
    wncl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wncl.hCursor = LoadCursor(NULL, IDC_ARROW);
    wncl.lpszClassName = CLASS_NAME;
    wncl.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wncl))
    {
        MessageBox(NULL, "Window Class Registration Failed!", "Error!",
        MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }


    //Create the window from the class definition above

    hWnd = CreateWindowEx(NULL,

        CLASS_NAME,

        WINDOW_NAME,

        WS_OVERLAPPEDWINDOW,

        CW_USEDEFAULT,

        CW_USEDEFAULT,

        width,

        height,

        NULL,

        NULL,

        hInstance,

        NULL);

    if(!hWnd)

    {

        return false;

    }


    //Display the window

    ShowWindow(hWnd, SW_SHOW);

    UpdateWindow(hWnd);

    return true;
}

/*A lot of new stuff there, all describing your window from the cursor type to Icons used and the background of your window. The explanation for this I think is better left to another post as this one is already getting lengthy. The process you see here you will begin to get used to using DirectX as you Create and Object-> Define the Object->Register the Object. After defining and registering the window class, we then create a RECT object which is defined by the WINDOW_WIDTH and WINDOW_HEIGHT we input as variables to the InitWindow() function and sent to AdjustWindowRect() to resize the window. We then create the window with the call to CreateWindow()*/

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, 
                          WPARAM wParam, LPARAM lParam )
{
    //Handle Messages
    switch(message)
    {
    case WM_KEYDOWN:
        switch(wParam)
        {
        case VK_ESCAPE:
            PostQuitMessage(0);
            break;
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hWnd, message, wParam, lParam);

 /*You should be able to copy and paste this entry as a whole into your IDE and compile without any modifications. If you receive an error similar to "Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast ... error C2440: '=' : cannot convert from 'const char [13]' to 'LPCWSTR'" Then you have not set your character set to multi-byte. You can use the TEXT("Your text here") function instead but this is tiresome and unnecessary. 

I hope this has helped someone else in creating their first windows application. I recommend this site to get a more in depth understanding of the Win32 application we just created. */
 

New Direction

Happy New Year Coders!
    I have not posted in a while as school and life have been pretty busy but I'm going to try starting this up again. I would like to change focus, however, to C++ and more specifically game programming and... hopefully... DirectX. I have heard a lot about how DirectX has a steep learning curve and I don't think it will be easy, but I think it is the direction I want to take for now. So, since my last posts I have completed Programming Logic and my first Computer Science class (C++). I will be starting on the second semester of C++ soon on my way to a Computer Science degree. I'm also in Calculus 2 and from what I have seen of DirectX I will need a whole lot more math, so I can't wait to take Differential Equations and Linear Algebra in the coming semesters so I might understand the matrix translations I'll be dealing with in DirectX while programming my games. But that is getting ahead of myself.
    The main reason I wanted to start this up again is to help myself and give myself some practice as I am learning DirectX 10 on my own. I am going to try and start from the very beginning using the book Ultimate Game Programming with DirectX, Second Edition as my main guide using Microsoft Visual Studio 2010 .Net Express Edition as my IDE. When I get back I will post begin with getting started on the IDE and setting up a Win32 application.

Tuesday, September 21, 2010

Rock, Paper, Scissors, Pythons....?

Here's assignment for Logic turned Python. We were to describe the logic for an easy childhood game and I chose Rock, Paper, Scissors.


import random
choices = ['Rock','Paper','Scissors']
oppChoice=0
playerChoice=0

def rock(oppChoice):
    if oppChoice == 'Rock':
            print("It's a tie!")
    if oppChoice == 'Paper':
            print("You Lose! Paper covers Rock!")
    if oppChoice == 'Scissors':
            print("You Win! Rock smashes Scissors!")
          
def paper(oppChoice):
    if oppChoice == 'Paper':
            print("It's a tie!")
    if oppChoice == 'Rock':
            print("You Win! Paper covers Rock!")
    if oppChoice == 'Scissors':
            print("You Lose! Scissors cuts Paper!")
           
def scissors(oppChoice):
    if oppChoice == 'Scissors':
            print("It's a tie!")
    if oppChoice == 'Paper':
            print("You lose! Paper covers Rock!")
    if oppChoice == 'Rock':
            print("You Lose! Rock smashes Scissors!")
           
def choice(playerChoice,oppChoice):
    if playerChoice==1:
        rock(oppChoice)
    if playerChoice==2:
        paper(oppChoice)
    if playerChoice==3:
        scissors(oppChoice)
   
def RPSgame():
    oppChoice = random.choice(choices)
    playerChoice = input("Make your selection:\n[1] Rock\n[2] Paper\n[3] Scissors\n...")
    playerChoice=int(playerChoice)
    if playerChoice not in(1,2,3):
        print("Please input 1, 2, or 3 only!")
        RPSgame()
    print('You Chose', choices[playerChoice-1])
    print('Your Opponent Chose...',oppChoice)
    choice(playerChoice,oppChoice)
    playAgain = input("Try again? (Y,N)")
    if playAgain== 'Y' or 'y':
        RPSgame()
    else: return

The first 44 lines are the game's logic, just telling you if you won or lost based on your choice vs. opponent's choice. The "main" code is RPSgame() which, if you ran this code, is all you would have to type to start the game. I tried to account for incorrect input (not using 1,2, or 3 for initial input and disregard for capitalization for "y" to continue playing). The only thing in here we haven't covered thus far on the GeekSpot Blog is the use of lists. I will go into that more in depth later this week when I have more time. In the mean time, I'll leave it at:

Lists are built in brackets: []
Lists are mutable: They can be changed... added to, taken away from...
List elements are numbered starting from 0: choice[0] thus equals Rock.

There is much more to lists, lists can be used for many things and have much potential in your programming. Thanks for stopping by! If anyone has suggestions, comments or concerns about the above code, please feel free to leave a post or shoot me an email.