Skip navigation

Category Archives: game

I’m constantly trying to find where video game characters and ideas come from.

The latest in the series is

Demon Hunter from Warcraft 3 < = > William Wallace from Braveheart?

Watch the movie again, and the efficacy with which he cuts down his enemies. A good clip.

anatarranatur.

Advertisements

Well, the diablo 3 trailer gave me an electric sensation of awesome.

The flavor — indian / arabic / somehow it always plays on ancient religion.

While the older Diablo installments seemed to play mostly on Christian tradition, it appears that Diablo 3 will have a middle eastern / indian / more exotic flavour.

Excited to see it

This is an extremely entertaining flashback about ff1 by Jin-Ning Tioh.

ff1

GLUT files

//////////////////////////////////////////
//                                      //
// MOST BASIC GLUT APPLICATION          //
//                                      //
// You found this at bobobobo's weblog, //
// https://bobobobo.wordpress.com        //
//                                      //
// Creation date:  Feb 9/08            //
// Last modified:  Feb 9/08             //
//                                      //
//////////////////////////////////////////

// GLUT is short for "OpenGL Utility Toolkit".
//
// GLUT was originally created by a genius named Mark Kilgard.
//
// GLUT exists only to allow you to easily create a
// window and draw your really cool 3D graphics into that
// window using OpenGL function calls.

// GLUT is NOT really suited to create full blown games,
// and you really should take a look at programming Windows
// if you want to do that.

// BUT, GLUT is a good place to start to understand
// OpenGL in a really simple way.

// GLUT is GREAT for simple projects and demos.

// Its clean, its simple, and it pretty much does
// all the stuff you wanna do in a demo of a short
// program.

///////////////////////////
// GLUT in Visual Studio 2005.

// Here I am explaining how to get GLUT running
// ASSUMING you're using Visual Studio 2005.

// BEFORE STARTING TO RUN THIS PROGRAM:  You must
// first INSTALL GLUT onto your system.
//      TO INSTALL GLUT on your Windows system:
//      1.  Get glut-3.7.6-bin.zip from:
// http://www.xmission.com/~nate/glut.html
//
//      2.  Unzip the file and copy glut32.dll file to:
//C:\Windows\system32
//
//      3.  Copy glut32.lib to:
//C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Lib
//
//      4.  Copy glut.h to:
//C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Include\gl

/////////
// Got it installed?  Good!  Let's continue.
/////////


// The first thing we're going to do in our GLUT application is import the
// libraries we'll need:
#include <iostream>  // include the standard
// input/output, so we can write text to the console window
using namespace std;    
#include <glut.h>  // include the OpenGL Utility Toolkit
// -- (Remember, you HAVE TO to follow instructions above
// and INSTALL GLUT first!)

// IMPORTANT:  YOU MUST #include <iostream> BEFORE <glut.h> BEFORE 
// OTHERWISE you will get an 'exit' : redefinition error.

/// render function.  This is THE function that
/// TELLS openGL what to DRAW inside our Window.
void render()
{
    glClear( GL_COLOR_BUFFER_BIT );

	#pragma region drawing code
	glPushMatrix();
		glColor3d( 1.0, 1.0, 1.0 );
		glutSolidTeapot( 0.5 );

		glColor3d( 0.0, 0.0, 1.0 );
		glTranslated( 0.0, 0.6, 0.0 );
		glutSolidTeapot( 0.25 );
	glPopMatrix();
	#pragma endregion

    glutSwapBuffers() ;
}

// Next, we'll write our main() function:
int main( int argc, char** argv )
{


/*
A note about argc and argv — CAN skip, but is good to know

Notice that main() has 2 parameters between the brackets. You might not be used to that, because normally we’d just write int main(). It turns out that when you write a GLUT application, you have to have (int argc, char** argv) between the brackets there. Now, you can take my word for it, because its not REALLY important to understanding OpenGL as to why you need argc and argv, or you can read the paragraph below to understand.

argc and argv are the command line arguments. Here’s an example.

Open the Windows command prompt (to open cmd prompt, go to START->Run, then type cmd in the box that appears there. You should see a black console window, like the one that your basic console C++ apps run in. In the black window, after the C:\Documents and Settings> type in this line:
explorer

What should happen is your windows file explorer should pop up.

Now go back to the command prompt and type in
explorer “C:\Program Files”

Notice now that the Windows disk explorer now opens in the folder “C:\Program Files”

In the above example, “C:\Program Files” is a command line argument that modifies the behaviour of the disk explorer upon its launch.

In the same way, your GLUT app will accept a string or two from the operating system environment that tell it how it should set itself up. We never have to deal with argc and argv DIRECTLY in our GLUT apps, but its good to know.
*/


    // Ok, now for the actual code of our program:

    // these next few lines "speak" to GLUT.
    // Think of GLUT like a living entity.
    // Each time you write a function call
    // that begins with glut___(something),
    // you are COMMANDING GLUT to DO SOMETHING.

    // We're going to write SEVEN (7) commands to GLUT in this program.

    glutInit(&argc, argv);              // initialize GLUT!
// (ask GLUT to
// initialize itself and get ready
// to draw graphics)

    glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);      // Tell GLUT to
// be prepared to draw in all of red, green and blue
// colors (mixes of red, green and
// blue get you all 16 million
// colors available), Also double buffer the display (REQUIRED windows 7)

    glutInitWindowPosition(120,260);    // this tells GLUT
// that WHEN I decide to create a window,
// I want that Window to start
// up 120 pixels from the left
// edge of the screen, and 260
// pixels from the top edge
// of the screen.

    glutInitWindowSize(600,600);        // This tells GLUT
// that WHEN I create a window, I want
// that window to have a width
// of 600 pixels (first number is
// width), and a height of 600
// pixels (second # is height)


// Next, actually CREATE the window.  Will use
// all the information I specified above about
// window position and window size to
// create this window.
    glutCreateWindow("WOO HOO!  This is my GLUT Window!");

    glutDisplayFunc( render );          // "attach" the
// function with name "render" to 
// the "draw" event.  WHENEVER
// my window needs to be "drawn",
// AUTOMATICALLY, GLUT will CALL
// the render() function.

// When does my window need to be
// drawn you ask??  Why, whenever
// it receives a PAINT EVENT from
// the Windows O/S, of course!
// (a window gets a paint event whenever
// the windows O/S recognizes that
// a part of it needs to be redrawn.
// For example, if another window blocks
// your window, and then that
// other window is removed, then
// your window will get a paint event.)

    glutMainLoop();     // START RUNNING THE APP.
    // GOTO render() function.
    // Program is now WAITING for 'messages'
    // from the user, or from the Windows O/S.
    // _PROGRAM CONTROL NEVER RETURNS
    // TO THIS LINE OF CODE AGAIN FOR THE
    // LIFE OF THIS PROGRAM!!_
}





/* 
     ____   __   __      __   __  ___
    / _  \ /  / /  /    /  /  \ \/  /
   / _/ / /  / /  /    /  /    \   /
  / _/ \ /  / /  /__  /  /__   /  /
 /_____//__/ /______//______/ /__/

*/

Check out the Visual Studio project files on esnips

I want the HWND and HINSTANCE of a console window. How do I get it?

hwnd console

NOTE: A few comments at the bottom of this post have pointed out the existence of several functions that actually make this easier than I have shown here: particularly HWND hwnd = GetConsoleWindow();. There’s also GetModuleHandle(), used as Hardijzer mentions in the comments below, thought I might not have used this had I been aware of it. The complete listing of console functions is here on msdn.

Its actually easy! The short of it is:


// console app
#include <iostream>
using namespace std;

#include <windows.h>

int main()
{
  char title[500];  // to hold title

  // get title of console window
  GetConsoleTitleA( title, 500 );

  // get HWND of console, based on its title
  HWND hwndConsole = FindWindowA( NULL, title );

  // get HINSTANCE of console, based on HWND
  HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndConsole, GWL_HINSTANCE);

  //alternate way
  HWND hwndC = GetConsoleWindow() ; /* Great!!  This function
  cleverly "retrieves the window handle
  used by the console associated with the calling process", 
  as msdn says */
  
  // Then we could just get the HINSTANCE:
  HINSTANCE hInstC = GetModuleHandle( 0 ) ; // HMODULE=HINSTANCE
  //HINSTANCE hInstCons = (HINSTANCE)GetWindowLong( hwndC, GWL_HINSTANCE );
}

See msdn article on FindWindow function.

The GetWindowLong() function, in the msdn spotlight.

We now have the HWND of the console in variable hwndConsole, and the HINSTANCE of the console window in hInstance.

Now, you COULD create a window up, because you have the HINSTANCE now. The example below illustrates the “long” of it:

//////////////////////////////////////////
//                                      //
// Getting the HWND of the Console      //
//                                      //
// You found this at bobobobo's weblog, //
// https://bobobobo.wordpress.com        //
//                                      //
// Creation date:  Feb 3/08             //
// Last modified:  Feb 3/08             //
//                                      //
//////////////////////////////////////////
#include <iostream>
using namespace std;

#include <windows.h>

// So you need the handle (HWND) for the
// console window for your app.

// Who knows why.  Maybe ya just
// want it.

///////////////////////////////
// In this example, I'm:
//  1) using the HWND of the console window 
//     to get the HINSTANCE of the console window
//     (GetWindowLong() function)
//
//  2) using the HINSTANCE and HWND of the
//     console window to create a regular
//     window with a WndProc and a message
//     loop and all (WNDCLASS structure,
//     RegisterClass(), then CreateWindow())

// based off of MSDN KB article
// http://support.microsoft.com/kb/124103

// prototype for the WndProc of the window that
// we're gonna create.
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam );

/////////////////
// Normally, windowed apps would start
// at WinMain().
// However, remember that this is REALLY
// a console application, and we're just
// spawning a window out of it.
// This application starts at first line of main().
int main()
{
    // console window exists as soon as app start

    // get its hwnd using combo of "GetConsoleWindowTitle()"
    // and "FindWindow()"

    // Why did i call this _REGION_A_? see end notes!
    #pragma region _REGION_A_ - get HWND of console
    
    char t[500];

    GetConsoleTitleA( t, 500 );     // retrieve the text
    // of the title bar of the console window

    cout << "The title of the console window is:" << endl;
    cout << t << endl << endl;

    HWND hwndConsole = FindWindowA( NULL, t );  // FindWindowA actually
    // can get you the HWND of a window, based
    // on the text in its title bar!
    
    // Let's check to see it worked.  If the console window
    // moves after the function call below, then we know
    // that hwndConsole is really a valid handle to the console
    // window!
    MoveWindow( hwndConsole, 20, 20, 500, 500, true );  // test hwnd

    #pragma endregion

    #pragma region _REGION_B - get HINSTANCE and create a window!
    ////////////////////////
    // Getting the HINSTANCE given the HWND
    //
    // Want the HINSTANCE of a window, but
    // you only have its HWND?
    //
    // Here's how you generally get the HINSTANCE
    // of the console, based off of the HWND of
    // the console.
    HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndConsole, GWL_HINSTANCE);
    
    ////////////////////
    // Now I'm going to create an ACTUAL WINDOW.
    //
    // Note that you always need a HINSTANCE
    // to create a window, which is why I just
    // got it in the line just above here.
    WNDCLASS wc = {0};
    wc.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.hCursor = LoadCursor( hInstance, IDC_ARROW );
    wc.hIcon = LoadIcon( hInstance, IDI_APPLICATION );
    wc.hInstance = hInstance;
    wc.lpfnWndProc = WndProc;
    wc.lpszClassName = TEXT("peter");   // name of window class .. I choose peter
    wc.style = CS_HREDRAW | CS_VREDRAW;

    if (! RegisterClass( &wc ) )
    {
        cout << "Problem with your WNDCLASS, foo." << endl;
        return 1;   // ERR, SO QUIT
    }
    
    // Create a real live window!
    // (see https://bobobobo.wordpress.com/2008/01/31/how-to-create-a-basic-window-in-c/
    // for more details on basic windows)
    HWND hwndWindow = CreateWindow(  TEXT("peter"),
                    TEXT("the window"),
                    WS_OVERLAPPEDWINDOW,
                    520, 20, 300, 300,
                    NULL,   // if you make this hwndConsole, then
                            // the console becomes this window's parent
                            // Then, this window wouldn't get an
                            // entry in the taskbar
                    NULL,
                   
                    hInstance, NULL );

    ShowWindow( hwndWindow, SW_SHOWNORMAL );    // ShowWindow() on msdn
    UpdateWindow( hwndWindow );
    #pragma endregion

    // Enter regular message loop, to process messages for
    // our window.
    #pragma region _REGION_C - message loop
    MSG msg;
    while( GetMessage( &msg, hwndWindow, 0, 0 ) )
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    #pragma endregion

    return msg.wParam;
}



////////////
// The WndProc for the Window that
// we eventually open up
// (This WndProc is _NOT_ FOR THE CONSOLE WINDOW!)
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam )
{
    switch( message )
    {
        case WM_CREATE:
            cout << "WINDOW SPEAKING TO YOU THROUGH THE CONSOLE." << endl;
            cout << "I'm alive!" << endl << endl;
            Beep( 40, 40 );
            return 0;
            break;

        case WM_PAINT:  // paint event
            {
                cout << "PAINT EVENT!  time to repaint!!" << endl;
                PAINTSTRUCT ps;
                HDC hdc;
                BeginPaint( hwnd, &ps );
                EndPaint( hwnd, &ps );
                return 0;
            }
            break;

        case WM_LBUTTONDOWN:    // left clicking on the client area of the window (white part)
            cout << "WHY R YA MOUSE DOWN'IN ME AT x=" << LOWORD(lparam) << " y=" << HIWORD(lparam) << " SON" << endl;
            return 0;
            break;

        case WM_NCLBUTTONDOWN:  // NONCLIENT area leftbutton down (click on "title bar" part of window)
            //cout << "AAAH!! YER GONNA MOVE ME SON.  CAREFUL SON." << endl;
            //return 0;     // this is an interesting one.
            // try UNCOMMENTING the return 0; statement here.
            // Notice that you can NO LONGER move or manipulate
            // the window by clicking on its "title bar"
            // if you return 0; from here.  The reason for that
            // is the window movement is actually handled by
            // DefWindowProc().  That's why its so important
            // to remember to pass events you don't handle to
            // DefWindowProc() -- if you don't then the Window
            // won't act in the "default" way you're so used to
            // other windows acting in (in fact, it won't even
            // show up properly)
            break;

        case WM_CHAR:   // character key
            cout << "WHY R U CHARRING ME WITH " << (char)wparam << " FOR SON" << endl;
            return 0;
            break;

        case WM_MOVE:   // moving the window
            cout << "WHY R U MOVIN' ME TO x=" << LOWORD(lparam) << " y=" << HIWORD(lparam) << " FOR SON" << endl;
            return 0;
            break;

        case WM_SIZE:
            cout << "WHY R YA SIZIN' ME TO SIZE width=" << LOWORD(lparam) << " height=" << HIWORD(lparam) << " FOR SON"<< endl;
            return 0;
            break;

        case WM_DESTROY:    // killing the window
            cout << "NOOO!!  I . . . shall . . . return !!" << endl;
            PostQuitMessage( 0 );
            return 0;
            break;
    }
    
    return DefWindowProc( hwnd, message, wparam, lparam );
}









////////////////////////
// END NOTES:
//
// If you read the MSDN article carefully,
// it says some shit about wanting to 
// SetConsoleTitle( "stupid unique title");
// The reason for that is, there is an OFF
// CHANCE that PERHAPS there's more than one
// window with the same exact TITLE
// as our console window.
//
// There's a bit of code at the bottom of the
// Visual Studio project files that shows
// how to do that.
// 

/* 
     ____   __   __      __   __  ___
    / _  \ /  / /  /    /  /  \ \/  /
   / _/ / /  / /  /    /  /    \   /
  / _/ \ /  / /  /__  /  /__   /  /
 /_____//__/ /______//______/ /__/

*/

Visual Studio 2005 project files, hosted by esnips (thanks esnips!)

//////////////////////////////////////////
//                                      //
// A Fast Windows Program               //
//                                      //
// You found this at bobobobo's weblog, //
// https://bobobobo.wordpress.com        //
//                                      //
// Creation date:  Feb 3/08             //
// Last modified:  Feb 9/08             //
//                                      //
//////////////////////////////////////////

#include <windows.h>
#include <math.h>   // for sin() and cos() in calculating npc pos

// Function prototypes.
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam );
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow );

////////////////////////////
// Introduction:
// 
// In the "MostBasicWindow" project, we talked
// about creating a basic window, and how
// MOST NORMAL Windows programs use something
// called "EVENT DRIVEN PROGRAMMING".

// If you don't remember, please review
// PREREQUISITES:  BASIC WINDOWS PROGRAMMING
// (see https://bobobobo.wordpress.com/2008/01/31/how-to-create-a-basic-window-in-c/
// to get started).

// In EVENT DRIVEN PROGRAMMING, your
// program is entirely driven by EVENTS.

// If there are no events, then your
// Windows program DOES NOTHING AT ALL,
// until the next EVENT is passed to it
// by the Windows O/S in the form of a 
// MESSAGE.

// Now, this is a PROBLEM when it comes
// to programming a GAME AS A Windows application.

// If your app NORMALLY does nothing
// except when the user interacts with
// the application, then every time
// the user let go of all of the keys
// on the keyboard, the game would just
// simply PAUSE.  This is because
// the normal structure of a Windows
// application is to execute code
// IN RESPONSE TO EVENTS THAT COME
// to the window.  If there are no
// events, then the application is idle.

// That structure makes perfect sense
// for applications like MSWord or firefox, and its
// the only way things are sane inside
// that Windows Government and the
// processor doesn't blow up when you
// have 50 windows open at the same time.

// However, GAMES are different than normal
// standard windows apps like Firefox or
// MSWord.

// Games need to CONSTANTLY be running.  Games
// need to constantly update their state.
// Even if the player isn't doing anything,
// the game AI has to keep computing what
// the MONSTERS will do next.  The game
// has to have a concept of TIME that keeps
// on going on, even when the player isn't
// pressing any keys too.

///////////////////////
// RECALL:  The NORMAL WINDOWS PROGRAM MESSAGE LOOP:
/*
    while( GetMessage( &msg, NULL, 0, 0 ) )
    {
        // GetMessage is a function that will not
        // return until the Windows O/S HAS A message
        // for our program.

        // Since the GetMessage() function call is
        // INSIDE the bracket for the while Loop,
        // this means that our program is essentially
        // "put on hold" or halted until the GetMessage function
        // returns.

        // If and when the user interacts with our
        // application's window, then the GetMessage()
        // function WILL return and the variable
        // msg will be filled with interesting details
        // about exactly what the user did to the window.

        TranslateMessage( &msg );   // translates 
        // the message so WndProc can process it
        // more easily.

        DispatchMessage( &msg );    // this line RESULTS IN
        // a call to WndProc(), passing the message and
        // the HWND.  This is OUR APPS CHANCE
        // to execute some code in response
        // to user events.
    }
*/

// The point is, GAMES CAN'T _WAIT_ FOR
// MESSAGES FROM THE WINDOWS O/S TO BE
// ALLOWED TO EXECUTE THEIR CODE!!

// Games need to run very quickly, and
// execute the following instructions
// __at least__ 60 times a second!

// {
//      checkWhatKeysUserIsPushingDown();
//      makeChangesToGameStateAndCalculateNextFrame();
//      draw();
// }

// Because GetMessage() blocks (doesn't return
// control to our app immediately!), it really
// creates a bottleneck for us!

// IN OTHER WORDS, WE HAVE TO STOP USING
// THE GetMessage() function!

// For our game, we DO NOT want to be WAITING
// for messages AT ALL.  Instead, we will
// use something else called PeekMessage()
// to VERY QUICKLY check to see if the
// Windows O/S has any messages for our
// Window.

// IF the Windows Government does have a message for us,
// THEN we process that message, then its
// back to our computing and drawing functions
// as usual.

// IF the Windows O/S DOES NOT
// have any messages for our Window, WE
// WANT TO CONTINUE RUNNING OUR OWN CODE
// ANYWAY -- WE DO NOT WANT TO GIVE UP
// CONTROL TO THE WINDOWS O/S.

#pragma region globals
HWND hwnd;      // store the HWND in a global now,
                // so our DRAW function can use it freely.

// player x and y positions.
float playerXPos = 50;
float playerYPos = 50;

// NPC x and y positions.
float npcXPos = 80;
float npcYPos = 80;
#pragma endregion

void check_for_user_input_through_keyboard()
{
    float diff = 0.01f;

    if( GetAsyncKeyState( VK_UP ) )
    {
        // up key being pushed, move player up
        playerYPos -= diff;
    }

    if( GetAsyncKeyState( VK_DOWN ) )
    {
        playerYPos += diff;
    }

    if( GetAsyncKeyState( VK_RIGHT ) )
    {
        playerXPos += diff;
    }

    if( GetAsyncKeyState( VK_LEFT ) )
    {
        playerXPos -= diff;
    }
}

// In this function, we're calculating
// the motion of the "npc unit" - very simple
void calculate_next_frame_of_our_program_by_shuffling_npc_around()
{
    // let's move the NPC unit around, in a circle.
    static float pos = 0.0f;
    pos += 0.1f;

    npcXPos += 0.01*sin( 0.001*pos );
    npcYPos += 0.01*cos( 0.001*pos );
}

void draw()
{
    HDC hdcTotalArtist = GetDC( hwnd ); // get the "handle to device context"
                                        // for our Window.

    // The "device context" is like a "total artist"
    // that has pens, brushes, and a canvas to draw to.

    // I explain that more below, but for now, let's
    // draw the player:
    Ellipse( hdcTotalArtist, (int)playerXPos, (int)playerYPos, (int)(playerXPos + 10), (int)(playerYPos + 10) );

    ////////////
    // Changing the pen color:
    // Now the npc unit should be a different color.
    // so this is REALLY QUICKLY how you change
    // the color of the "pen" that you're using
    // to draw.

    // The "device context" of our window is
    // like a TOTAL ARTIST.
    // The "device context" contains:
        // canvas
        // pens
        // brushes
        // and more!

    // In order to change the style in which the
    // standard GDI functions (like Ellipse) are
    // drawing, we would have to CHANGE THE
    // PROPERTIES OF THE DEVICE CONTEXT TO WHICH
    // WE ARE DRAWING.

    // So what we do is, we:
        // 1.  CREATE A NEW redpen,
        //      WITH ALL THE PROPERTIES
        //      WE WANT IT TO HAVE (solid lines, can select width as well)
        // 
        // 2.  GIVE THAT redpen TO
        //     THE device context "total artist"
        //     by using the SelectObject() function.
        //     Note that the hdc total artist can
        //     only hold ONE PEN at a time.  So
        //     you'll see in the code that when we
        //     give the hdc total artist
        //     a new pen, WE MUST CATCH THE OLD ONE
        //     IN A VARIABLE!
        //
        // 3.  DRAW AGAIN using the Ellipse()
        //     gdi function.  Since the Ellipse()
        //     function WILL draw to an HDC,
        //     then we will see RED ELLIPSE, since
        //     we just gave the hdc total artist
        //     a red pen.

    // "select the pen into" the device context
    // by using the SelectObject() function.

    // This in a sense is like GIVING the device
    // context a new brush with which to draw,
    // or a new pen with which to draw.
    HPEN redpen = (HPEN)CreatePen( PS_SOLID, 2, RGB( 255, 0, 0 ) );
    HPEN oldpen = (HPEN)SelectObject( hdcTotalArtist, redpen );

    // draw with redpen
    Ellipse( hdcTotalArtist, (int)npcXPos, (int)npcYPos, (int)npcXPos + 10, (int)npcYPos + 10 );

    // select back the old pen, then delete the red pen
    redpen = (HPEN)SelectObject( hdcTotalArtist, oldpen );
    DeleteObject( redpen );

    ReleaseDC( hwnd, hdcTotalArtist );
}

////////////////////////////
// In a C++ Windows app, the starting point is WinMain().
int WINAPI WinMain( HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR szCmdLine,
                    int iCmdShow )
{
    #pragma region part 1 - STARTUP STUFF
    WNDCLASS wc;
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
    wc.hCursor = LoadCursor( NULL, IDC_ARROW );         
    wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );     
    wc.hInstance = hInstance;         
    wc.lpfnWndProc = WndProc;         
    wc.lpszClassName = TEXT("Philip");
    wc.lpszMenuName = 0; 
    wc.style = CS_HREDRAW | CS_VREDRAW;

    // B.  Register the WNDCLASS with Windows, THEN
    //     create the window.
    RegisterClass( &wc );
    hwnd = CreateWindow(
        TEXT("Philip"),
        TEXT("Fast windows app!!"),
        WS_OVERLAPPEDWINDOW,
        10, 10,
        400, 400,
        NULL, NULL,
        hInstance, NULL );      

    // Next, SHOW and PAINT the window!
    // You won't see the window if you DO NOT
    // call ShowWindow();
    ShowWindow(hwnd, iCmdShow );
	UpdateWindow(hwnd);
    #pragma endregion

    // first, we create the MSG structure.
    MSG msg;

    #pragma region OLD GETMESSAGE LOOP -- NORMALLY YOU SHOULD JUST DELETE THIS PART
    // -- commented out, but I STRONGLY ENCOURAGE
    // you to try commenting it back in to see
    // how it behaves and why we CAN'T be using
    // GetMessage() for our games.

    // IT DOES WORK, but its INCREDIBLY, INCREDIBLY
    // slow.

    // And on top of the extreme SLOW, you have to constantly
    // be inputting "messages" into the window in order
    // for anything to happen! (for the npc to move!)

    /*
    SetWindowText( hwnd, TEXT("SLOW MODE!!! - Press ESC for fast mode") );
    while( GetMessage( &msg, NULL, 0, 0 ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg ); 

        check_for_user_input_through_keyboard();
        calculate_next_frame_of_our_program_by_shuffling_npc_around();
        draw();
    }
    */
    #pragma endregion

    #pragma region part 2 - ENTER A LOOP TO CONTINUALLY KEEP CHECKING WITH WIN O/S FOR USER INTERACTION

    // Notice we changed the loop structure from the old
    // GetMessage() structure.  We're using PeekMessage() now.

    // It goes like this now:

    // while(FOREVER)
    // {
    //    if ( there's a message for our window )
    //    {
    //      translate and dispatch to WndProc for processing();
    //    }
    //  
    //    check_for_user_input_through_keyboard();
    //    calculate_next_frame_of_our_program_by_shuffling_npc_around();
    //    draw();
    // 
    // }
    SetWindowText( hwnd, TEXT("Fast windows app!!") );  // (in case you uncommented
                                                        // the GetMessage() above )
    while( 1 )  // LOOP FOREVER
    {
        // 1.  PROCESS MESSAGES FROM WINDOWS
        if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
        {
            // Now, this is DIFFERENT than GetMessage()!
            // PeekMessage is NOT a BLOCKING FUNCTION.
            // That is, PeekMessage() returns immediately
            // with either a TRUE (there was a message
            // for our window)
            // or a FALSE (there was no message for our window).

            // If there was a message for our window, then
            // we want to translate and dispatch that message.

            // otherwise, we want to be free to run
            // the next frame of our program.
            if( msg.message == WM_QUIT )
            {
                break;  // BREAK OUT OF INFINITE LOOP
                        // if user is trying to quit!
            }
            else
            {
              TranslateMessage( &msg );   // translates 
              DispatchMessage( &msg );    // this line RESULTS IN
              // a call to WndProc(), passing the message and
              // the HWND.

              // Note that in this program, all we're really using
              // the messaging system for is for
              // processing the QUIT message that occurs
              // when the user clicks the X on the window
              // to close it.

              // ALL OTHER application processing happens
              // in the 3 lines of code below
              // (the 'check_for_user ... ' stuff)
           }
        }
        else
        {
           check_for_user_input_through_keyboard();
           calculate_next_frame_of_our_program_by_shuffling_npc_around();
           draw();
        }
    }
    #pragma endregion

    return msg.wParam;
}

LRESULT CALLBACK WndProc(   HWND hwnd,      
                            UINT message,  
                            WPARAM wparam,  
                            LPARAM lparam ) 
{
    switch( message )
    {
    case WM_CREATE:
        // upon creation, let the speaker beep at 50Hz, for 10ms.
        Beep( 50, 10 );
        return 0;
        break;

    case WM_PAINT:
        {
            // we would place our Windows painting code here.
            HDC hdc;
            PAINTSTRUCT ps;
            hdc = BeginPaint( hwnd, &ps );

            // draw nothing here.
            // drawing happens in the 
            // draw() function that
            // we MANUALLY call ourselves.

            // We DO NOT rely on messages to
            // tell us when to draw when creating
            // game!  Instead, we draw when
            // we want to.

            // WHY?  Because the WM_PAINT message
            // only comes to your window WHEN
            // the Windows O/S THINKS your window
            // needs to be redrawn.  That includes
            // only events like "if your window
            // was blocked by another window,
            // then it needs to be repainted"

            // Our fast game NEEDS to be redrawn
            // 60 times a second AT LEAST, so we
            // totally BYPASS the normal windows
            // system, and draw in our draw()
            // function of our own accord.

            EndPaint( hwnd, &ps );
        }
        return 0;
        break;

    case WM_KEYDOWN:
        switch( wparam )
        {
        case VK_ESCAPE:
            PostQuitMessage( 0 );
            break;
        default:
            break;
        }
        return 0;

    case WM_DESTROY:
        PostQuitMessage( 0 ) ;
        return 0;
        break;
    }

    return DefWindowProc( hwnd, message, wparam, lparam );
}

///////////////////////
// Closing notes:
//
// IF you'll notice, when you run this
// program, if you look at your task
// manager, (CTRL+ALT+DEL), NOTICE your
// windows application (should show up
// in processes list as BasicWindowsProgramming_GameStructure.exe)
// is now a CPU HOG.  Its taking somewhere
// close to 40-50% of CPU time.

// THIS IS GOOD. YOUR APP IS TAKING
// CONTROL OF THE SYSTEM RESOURCES
// (CPU TIME).
//
// If its a game, THIS IS EXACTLY WHAT YOU
// WANT.  Games need to hog the system
// resources in order to run the best
// they possibly can given the user's
// hardware.

// Using this Windows program structure -
// a "greedy" structure if you will -
// we can create games that run as
// fast as they can.

/* 
     ____   __   __      __   __  ___
    / _  \ /  / /  /    /  /  \ \/  /
   / _/ / /  / /  /    /  /    \   /
  / _/ \ /  / /  /__  /  /__   /  /
 /_____//__/ /______//______/ /__/

*/

Visual Studio 2005 Project files hosted by esnips! (thanks esnips!)

Many, many people, when starting out with DirectX or other Microsoft technologies, go and look for a simple book on the topic.

Many newbies do not know about MSDN. Or, if they do know about MSDN, they don’t know just HOW GOOD and complete it is, simply because they’ve never tried to use it before.

The MSDN documentation CAN BE a bit annoying, simply because its so damn huge.

It is very well organized though, and if you browse through the tree hierarchy on the left (once you’ve got a good starting point!), then its very useful indeed.

The search tool doesn’t always find you the article you’re looking for though, so sometimes trying different search strings can help. Just because a bunch of weird irrelevant stuff turns up in an MSDN search, doesn’t mean that MSDN doesn’t have what you’re looking for!

IN FACT, MOST OF THE BOOKS out there on DirectX SIMPLY ADAPT OR EXPAND ON THE MSDN DOCUMENTATION. A LOT of the time, the book just provides you a subset of what MSDN provides, while not making the material all that much clearer. SOME of the books on DirectX out there are like drinking from a murky pond, while the clearer (not 100% clear, though) lake is right next to it.

As I mentioned, it can be a TAD annoying to have to LOOK FOR the appropriate MSDN article.

So here’s a pageful of links:

MAIN LINK TO DirectX SDK DOCUMENTATION, (NOVEMBER 2007) C++

The rest of these links you can find by simply following the above DirectX links, but I’m including them here for convenience.

MSDN docs on DirectInput

MSDN docs on DirectSound

More interesting stuff from MS. . .

Microsoft XNA presentations – has stuff from Gamefest, SIGGRAPH, and GDC (near the bottom of the page)

Note that there IS a huge difference between d3dx9.lib and d3d9.lib.

Getting error LNK2019: unresolved external symbol _D3DXVec3Normalize@8 referenced in function?

Do this

  1. In visual studio 2005, Go to TOOLS->OPTIONS.

    In that window that comes up, in the left hand side of the window, pick “PROJECTS AND SOLUTIONS” -> VC++ DIRECTORIES from the tree.

    d3d linker error fix

    ALSO do this:
    d3d include

  2. In every code file, include a line at the top that says:

    #pragma comment(lib, "d3dx9.lib")   // d3dx9.lib contains actual code for D3DX functions (like D3DXVec3Normalize)
    

Why?

Although d3dx9.h contains the function prototypes and signatures for the D3DX functions, it DOES NOT contain the actual implementation code.

The implementation code is provided IN “d3dx9.lib” which is why you have to LINK it to the executable at compile time.

really old but good article on DirectX

Kim swift is cool.

Her presentation is good. At the beginning, she’s got great confidence, but then she does get a tad quivery.

She’s entertaining to listen to and funny. People didn’t laugh at the right moments though. The audience seemed a bit dead really, and they also cough a lot.

I find when a speaker opens with a really good joke that everyone can laugh at, to break the ice at the very beginning, then people will laugh readily at the right points throughout.

Nonetheless, she makes quite a few good points in her pres.

Timestamps for highlights:

  • 6:40: students have advantage when making class project they should use: you can take a high risk innovation for your project, and have the execution fail (it was a bad idea after all), but its not always possible to try high risk projects once in a company
  • 9:00: Design simplicity – pick one core piece of gameplay and iterate on it. “one piece of gameplay used in a whole different bunch of permutations.” – e.g: the portal
  • 11:30: Design Democracy.
    * All designers on team.
  • 13:40: Getting to Valve.
    * Here she summarizes the story of how the Valve team picked up the Narbacular team.
  • 14:40: Valve Lessons
  • 18:00: Coworkers will determine your growth
    * True that.
  • 19:20: Playtesting
    * Playtesting rigor – not rigorous testing doesn’t yield value

Here’s a link to the original narbacular drop demo. I really liked it when I played it. When you first open narbacular, its like WOW. This is brilliant.

So to sum, Kim swift. If she were available at taverns in DOTA maps, I would use her.

anyone tried “rappelz”?

http://rappelz.gpotato.com/ad/event.php

Hmm. It looks interesting

here

I just heard about this really cool looking “mario fusion” fangame that some dude is making.

I’ve got to check that out when its released!

There’s tons of information out there on physics programming.

Some of the sites I’ve now bookmarked:

Chris Hecker of MSFT
Erin Catto of Blizzard

In particular, I really liked the talk on Advanced Prototyping, which was delivered by CHecker and another bloke called Chaim Gingold. Great stuff.

Some more random stuff:
bokmann’s blog – but a mere software engineer
gsl

Also in News, I have found the home of the great and powerful John Miles, creator of the Miles Sound System.

EDIT: don’t listen to me

“Even if our application is throttled to a specific frame rate through a timer, the actual time between frames will vary.”

Assume I have the player’s position, velocity and acceleration in 3 vectors:

pos
vel
accel

– Player controls the acceleration vector though the keyboard.

– Game calcs velocity of character in next frame based on acceleration vector.

vel = accel * (time_passed_since_last_frame);
pos = vel * (time_passed_since_last_frame);

Or, more accurately

pos += vel * time_passed_since_last_frame + accel * time_passed_since_last_frame * time_passed_since_last_frame * 0.5f;
vel += accel * time_passed_since_last_frame;

So those are just
d = v1t + 0.5*at2
v = a * t

This works OK for moving the player around on the map, as long as frame rate is CONSTANT.

But what if a frame takes longer than usual to calculate?

Then (time_passed_since_last_frame) is TOO LARGE.

Motion becomes jerky, blocky. Player can move really far in just one frame, if that frame took particularly long to crunch out. So, this means that a collision can be missed!

Also it is a major problem when it comes to things like JUMPING.

The way I had it before, was when the player jumps by pressing the space bar, the player gets a force applied to him in the upwards direction for exactly 5 frames.

accel = (x, 1, z);

Since the amount of time that it takes to crunch out each frame varies, the player would jump different heights, depending on when / where the player was when he pressed the spacebar.

This was a problem. Was this acceptable? Did it happen in other games? I studied Quake III in action to see if the player jump height deviated at all. Not even by a pixel. Plus when you think about games like Warcraft 3 (that can run a replay out EXACTLY the same way, every time) there’s no room for this kind of error.

The player should jump exactly the same height (in game units) no matter when or where he jumps. Clearly not acceptable.

The only solution I can think of to this problem now is to treat “time” like a sort of “fuel” for the jump action.

When the player presses space bar, don’t measure the amount of “time” to apply the jump for in frames, but measure it in “seconds”.

When first jump:

player_jump_fuel = 1.0;

On every compute of player position:

if( player_jump_fuel - time_passed_since_last_frame < 0 )
{
    // overshot jump fuel.  e.g. frame took 0.1 seconds to compute, but only 0.07 seconds of jump fuel remain.
    // compute jump velocity using player_jump_fuel and NOT time_passed_since_last_frame
}

For a while, I was thinking the only solution is to NOT use time-based motion and the high performance timer. Instead, one should just decide that a “frame” represents 0.0166666666666666667 seconds (1/60 seconds) and compute next positions based on that.

And that’s actually a good solution when you think about it.

Using only the ‘virtual second’ if you wanted to slow the whole game down, all you have to do is set a global to make that “frame” represent 0.0111111111111111 seconds

So my conclusion (for now) is that using “real-time” offers absolutely no benefits while at the same time introducing a possibility of error.

If you can have perfect precision at no cost, why should you throw that to the wind?