Inside3D!
     

win32/Opengl....

 
Post new topic   Reply to topic    Inside3d Forums Forum Index -> OpenGL Programming
View previous topic :: View next topic  
Author Message
Zylyx_



Joined: 05 Dec 2007
Posts: 111
Location: scotland, uk

PostPosted: Sat Aug 29, 2009 5:49 pm    Post subject: win32/Opengl.... Reply with quote

Hi all. My head is hurting from trying to modularize window creation code using OpenGL and Win32 API.

Before anyone accuses of careless cut & paste, I wrote all of this from scratch while currently reading the OpenGL Superbible, Nehe tutorials and Game Tutorials LLC. The problem isnt that I dotn understand the code. The problem is that the compiler doesnt understand me (how great would that be?). Anyways, excuse my arrogance.

Here is my code:



gl_win32_core.h
Code:


//This file contains all of the core Win32/OpenGL function prototypes, system includes and global variables required for setting up a basic
//windowed rendering environment for OpenGL application using Win32.

#ifndef _GL_WIN32_CORE_H_
#define _GL_WIN32_CORE_H_

//Library includes
//#pragma comment(lib, "opengl32.lib")
//#pragma comment(lib, "glu32.lib")

//System includes
#include <windows.h>      // Must have for Windows platform builds
#include <tchar.h>         // Requires to convert each character in each string argument into a 2 byte character. Win32 treats all string characters as UNICODE.
#include <gl\gl.h>         // Microsoft OpenGL headers (version 1.1 by themselves)
#include <gl\glu.h>         // OpenGL Utilities

//OpenGL hRC specific
GLfloat windowWidth;
GLfloat windowHeight;                  

//Win32 specific global variables
static LPCTSTR lpszAppName = L"Swogle";
static HWND  g_hWnd;      //Window handle   
static RECT  g_rRect;      //Window rendering dimensions               
static HDC   g_hDC;         //GDI hardware device context            
static HGLRC g_hRC;         //Hardware renedeing contect for OpenGL   
static HINSTANCE g_hInstance; //App instance (id)

///////////////////////////////////
//Core Win32 function prototypes
///////////////////////////////////

//WinMain
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);

//WindowProc
LRESULT CALLBACK WndProc(HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam);

//Prog main loop
WPARAM MainLoop();

//Resiter and create new window
HWND CreateMyWindow(LPSTR strWindowName, int nWidth, int nHeight);

/////////////////////////////////////
//Core OpenGL function prototypes
////////////////////////////////////

//Set display format
void SetDCPixelFormat();

//Change window size
void ChangeSize(GLsizei w, GLsizei h);

//This draws everything to the screen
void RenderScene();

//Free all memeory associated with the program
void DeInit();

#endif



gl_win32_core.cpp

Code:

//This file contains all of the core Win32/OpenGL function implementations required for setting up a basic
//windowed rendering environment for OpenGL application using Win32.

#include "gl_win32_core.h"

//=======================================================================================================================================================
//=======================================================================================================================================================
//Core Win32 function implementations
//=======================================================================================================================================================
//=======================================================================================================================================================

/////////////////////////////////////
//WinMain function implementation
////////////////////////////////////
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
   //HWND hWnd; //Local window handle

   //Create new window
   g_hWnd = CreateMyWindow("SWOGLE 1.0", 800, 600);

   //If window handle is invalid, quit the program
   if(g_hWnd == NULL)
   {
      return TRUE;
   }

   g_hInstance = hInstance;

   //Initialize the program here
                                          
   //Run message loop and return the result
   return MainLoop();                  
}

//////////////////////////////////////////////
//CreateMyWindow() function implementation
//////////////////////////////////////////////
HWND CreateMyWindow(LPCTSTR strWindowName, int nWidth, int nHeight)
{
   HWND hWnd; //Local window handle
   WNDCLASS wc; //Window class that will be registered

   //clear the memory first
    memset(&wc, 0, sizeof(wc));
   
    //Set all of the attributes up for the window class & register it
    wc.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC; //CS_OWNDC: Tells Windows to create a device context just for this window
    wc.lpfnWndProc = WndProc;
   wc.cbClsExtra      = 0;
   wc.cbWndExtra      = 0;
    wc.hInstance = g_hInstance;
    wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
   wc.hbrBackground = NULL; //No need for background brush when using OpenGL
   wc.lpszMenuName = NULL; //No menus either
    wc.lpszClassName = lpszAppName;
   
   //Now, register the windows class with Windows
    RegisterClass(&wc);                     

   //Create the main application window
   hWnd = CreateWindow(
                     lpszAppName,
                     strWindowName,
                     WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, //WS_CLIPCHILDREN & WS_CLIPSIBLINGS are used to prevent
                     CW_USEDEFAULT,                                  //the OpenGL rendering context from rendering into other 
                     CW_USEDEFAULT,                                  //windows. An OpenGL rendering context must be associated
                     nWidth,                                        //with only one active window at a time.
                     nHeight,
                     NULL,
                     NULL,
                     g_hInstance,
                     NULL
                  );

   //If there is no window handle...
   if(!hWnd)
   {
      return NULL;
   }

   // Show the window
   ShowWindow(hWnd, SW_SHOWNORMAL);   

   // Draw the window
   UpdateWindow(hWnd);                           

   //Sets Keyboard Focus To The Window
   SetFocus(hWnd);                                 

   return hWnd;
}

/////////////////////////////////////////
//WindowProc() function implementation
////////////////////////////////////////
LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg, WPARAM wParam, LPARAM lParam)
{
   switch(nMsg)
   {
      //Setup the window for OpenGL here
   case WM_CREATE:
      {
         //Store device context
         g_hDC = GetDC(hWnd);

         //Select the pixel format
         SetDCPixelFormat();

         //Create the rendering context and make it current
         g_hRC = wglCreateContext(g_hDC);
         wglMakeCurrent(g_hDC, g_hRC);

         //Create a timer that calls specific functions 30 times a second
         SetTimer(hWnd, 30, 1, NULL);

         return 0;
      }
      //When the window is destroyed, clean up after OpenGL
   case WM_DESTROY:
      {
         //Kill timer
         KillTimer(hWnd, 101);

         //Delete any OpenGL-allocated memory here

         //Deselect current rendering context and delete it
         wglMakeCurrent(g_hDC, NULL);
         wglDeleteContext(g_hRC);

         //Terminate program after window is destroyed
         PostQuitMessage(0);

         return 0;
      }
      //Change window size appropriately (keeping all clipping bounds for the viewport and rendering volume in order)
   case WM_SIZE:
      {
         ChangeSize(LOWORD(lParam), HIWORD(lParam));
         return 0;
      }
      //Call the timer function here. The MoveSquare() function goes here, and after it is called, the window is
      //invalidated so that it will be drawn again. This happens 30 times a second.
   case WM_TIMER:
      {
         //Anim code goes here

         //Invalidate the rect
         InvalidateRect(hWnd, NULL, FALSE);

         return 0;
      }
      //The WM_PAINT message is sent by Windows everytime the screen needs to be updated. And that's what we do here
   case WM_PAINT:
      {
         //Render current scene
         RenderScene();

         //Swap buffers
         SwapBuffers(g_hDC);

         //Validate the newly painted client area
         ValidateRect(hWnd, NULL);

         return 0;
      }
   default:
      {
         return DefWindowProc(hWnd, nMsg, wParam, lParam);
      }
   }
   return 0;
}

///////////////////////////////////////
//MainLoop() function implementation
//////////////////////////////////////
WPARAM MainLoop()
{
   MSG msg;
   
   while(1)
   {
      if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) //Peek to see if there are any messages in the que...
      {
         if (!GetMessage(&msg, NULL, 0, 0)) //Same as above, except the message get's removed from the message queue
         {
            return msg.wParam; //If there is no message to get, return wParam, which returns a 0 upon normal program termination
         }

         //do the rest
         TranslateMessage(&msg);
         DispatchMessage(&msg);
      }
      else
      {
         //call game logic code here
      }
   }
   
   //Window cleanup code goes here...
   DeInit();
   
   //Return the exit code for the application.
   return msg.wParam;
}

//=======================================================================================================================================================
//=======================================================================================================================================================
//Core OpenGL function implementations
//=======================================================================================================================================================
//=======================================================================================================================================================

//////////////////////////////////////////////////////////////////////////
//Hardware device context pixel format setting function implementation
/////////////////////////////////////////////////////////////////////////
void SetDCPixelFormat()
{
   int nPixelFormat;

   static PIXELFORMATDESCRIPTOR pfd =
   {
      sizeof(PIXELFORMATDESCRIPTOR),
      1,
      PFD_DRAW_TO_WINDOW |
      PFD_SUPPORT_OPENGL |
      PFD_DOUBLEBUFFER,
      PFD_TYPE_RGBA,
      32,
      0,0,0,0,0,0,
      0,0,
      0,0,0,0,0,
      16,
      0,
      0,
      0,
      0,
      0,0,0
   };

   //Choose a best matched pixel format fitting the above description
   nPixelFormat = ChoosePixelFormat(g_hDC, &pfd);

   //Set the pixel format for the HDC
   SetPixelFormat(g_hDC, nPixelFormat, &pfd);
}

///////////////////////////////////////////
//RenderScene() function implementation 
//////////////////////////////////////////
void RenderScene()
{
   //Set the background clearing color to gray
   glClearColor(0.25f, 0.25f, 0.25f, 1.0f);

   // Clear the window with current clearing color
   glClear(GL_COLOR_BUFFER_BIT);
}

///////////////////////////////////////
//ChangeSize function implementation
//////////////////////////////////////
void ChangeSize(GLsizei w, GLsizei h)
{
   GLfloat aspectRatio; //Aspect artio for drawing the window

   //Avoid dividing by zero
   if(h == 0)
   {
      h = 1;
   }

   //Set viewport to window dimenstions (0, 0 is the clipping region; w, h are the width and height of the viewport in pixels
   glViewport(0, 0, w, h);

   //Reset coordinate system
   glMatrixMode(GL_PROJECTION);//Define projection matrix
   glLoadIdentity();//Load identity matrix for GL_PROJECTION (reset matrix)

   aspectRatio = (GLfloat)w / (GLfloat)h;

   if(w <= h)
   {
      windowWidth = 100;
      windowHeight = 100 / aspectRatio;
      glOrtho(-100.0, 100.0, -windowHeight, windowHeight, 1.0, -1.0);
   }
   else
   {
      windowWidth = 100 * aspectRatio;
      windowHeight = 100;
      glOrtho(-windowWidth, windowWidth, -100.0, 100.0, 1.0, -1.0);
   }

   glMatrixMode(GL_MODELVIEW);//Set the matrix mode to effect all of the current geometry that is drawn
   glLoadIdentity();//Reset the matrix
}

/////////////////////////////////////////////////
//Free all memeory associated with the program
////////////////////////////////////////////////
void DeInit()
{
   //Add all cleanup code associated with the window here

   //Unregister the window class
   UnregisterClass(lpszAppName, g_hInstance);
}



The error is this:
Code:
1>Compiling...
1>gl_win32_core.cpp
1>Linking...
1>gl_win32_core.obj : error LNK2019: unresolved external symbol "struct HWND__ * __cdecl CreateMyWindow(char *,int,int)" (?CreateMyWindow@@YAPAUHWND__@@PADHH@Z) referenced in function _WinMain@16
1>C:\Users\Vladeta\Desktop\game development\opengl_progs\progs\gl_win32_template\Debug\gl_win32_template.exe : fatal error LNK1120: 1 unresolved externals



My guess is that the cuplrit is my idea of making all of the window and hardware contexts, as well as the application instance, global.

However, seeing as they are declared as static, they should not loose their assigned value. If I declare them as extern, I still get the same error.

Any help is much appreciated. Smile
_________________
....noodle...
Back to top
View user's profile Send private message MSN Messenger
Spike



Joined: 05 Nov 2004
Posts: 944
Location: UK

PostPosted: Sat Aug 29, 2009 8:23 pm    Post subject: Reply with quote

your prototype of CreateMyWindow doesn't match
_________________
What's a signature?
Back to top
View user's profile Send private message Visit poster's website
mh



Joined: 12 Jan 2008
Posts: 909

PostPosted: Sat Aug 29, 2009 9:25 pm    Post subject: Reply with quote

I think your unicode thing might be causing you trouble. I'm guessing that you're probably using a more recent version of Visual C++ (possibly 2008 Express?) which defaults projects to unicode. If you go to Configuration Properties | General | Project Defaults | Character Set and set it to Multi-Byte you'll get char * compatibility back.

Totally unrelated, but maybe request a 24 bit depth buffer instead of a 16 bit one? A 24 bit depth buffer is actually really 32 bits with 8 unused, meaning that it's measurably faster on most reasonably modern - and even most older - hardware. The great thing about ChoosePixelFormat is that if 24 bits isn't available it'll just give you 16, so you've nothing to lose. There's no such thing as a 32 bit depth buffer on most hardware by the way, the options are always either 16 bit, 24 bit with 8 unused or 24 bit with 8 stencil.

Even though you're doing OpenGL I think it's well worth your while to download and study the reference topics in the DirectX SDK. Direct3D is a little bit "closer to the metal" than OpenGL is, and as such you get to learn a great deal more about format sizes and structures and suchlike (and also topics such as why writing to the front buffer is not a good idea on a lot of 3D cards - because Direct3D doesn't support it, and some drivers are written to the D3D spec with OpenGL tacked on afterwards). Learning more about the environment you're coding for is always a good thing, eh?
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
Zylyx_



Joined: 05 Dec 2007
Posts: 111
Location: scotland, uk

PostPosted: Sat Aug 29, 2009 11:11 pm    Post subject: Reply with quote

LOL! I totaly missed that. Man, that hungarian notation is hard on the eyes.

Yeah, I also made all the global variables static, otherwise I ended up getting more linker errors (still need to fully understand why though, too tired to read about it atm, probably check it out tomorrow).

Anyways, my basic framework is up adn running now.

I named it SWOGLE (Simple Windowing for OpenGL - Easy).

Now I'm going to add the following features:

1. TTF rendering
2. Keyboard and mouse input support
3. .WAV file playback


My main goal is to build a simple game ofPpong, and create basic re-usable windowing code with support for OpenGL.

The reason for this is that I'm starting my second year of my university course in computer games technology. Up until last year, we only really did graphics programming with the GBA (2D only), and we are going to start learning OpenGL and Windows programming this year.

I spent a good amount of my summer holiday learning the basics of Win32 API, and I just started learning OpenGL. When I get back to uni, my first assigment after re-learning windows programming for the first six weeks will be to make a simple GDI based 2D game. After that we start going into basic OpenGL programming.

We are also going to be learning basic PS2 programming this year, so it should be fun. But yeah, half the people last year couldnt figure out how todo the basic stuff like draw a line or a circle, but I managed to learn the ins and outs of that (bresenhams line & circle algorithm). We also did sprite programming and such, most of which I forgot by now, lol. I made a basic pong game for the GBA.

Anyways, again, to cut my life story short, thank you for your help.

I'm only starting to learn 3D graphics programming, but I'll look into the DirectX SDK docs in due time. Only after this year (in 3rd year), do we get to work with DirectX and do proper 3D graphics programming (shaders and all the bells & whistles). This year we are only doing the basic fixed function pipleline graphics programming with OpenGL. I'll definately read more into the different display formats and the effects of using different buffer sizes, although I think I read about it recently, but it kinda slipped my mind, again, lol. Guess it's always good to stay ahead.

So yeah...long post...bed time. Night!

P.S. Yeah, the MS Unicode thing very annoying. Read about it in the Windows Programming guide, something about each character being 2 bytes and not 8 bits, in order to accomodate most of the written languages. I had a funny thing happen to me recently, I set the window style to default(I thinkt to 0) after getting errors in my window creation routine, and I ended up with Chinese characters in the title bar and the message box! Fun times...
_________________
....noodle...
Back to top
View user's profile Send private message MSN Messenger
Spike



Joined: 05 Nov 2004
Posts: 944
Location: UK

PostPosted: Sun Aug 30, 2009 12:48 am    Post subject: Reply with quote

1. TTF rendering
two ways. the ms ones convert a font into a display list, which can be draw with drawlists easily enough.
a more modern way to do it is to prerender each glyph into a texture and draw that way using pixel accuracy. freetype2 can do the prerendering.

2. Keyboard and mouse input support
quake uses getcursorpos/setcursorpos to grab the cursor pos and reset it, calculating how much it moved by, thus giving a mouse delta.
good luck disabling mouse acceleration.
google for ToUnicode and WM_KEYDOWN. and figure out some sane way to map virtual keys and logical chars properly.

3. .WAV file playback
sndPlaySound for the lazy.
directsound is emulated now anyway. look into using openal or something I guess. its as fast as any other sound api nowadays, and reasonably portable.
_________________
What's a signature?
Back to top
View user's profile Send private message Visit poster's website
Zylyx_



Joined: 05 Dec 2007
Posts: 111
Location: scotland, uk

PostPosted: Sun Aug 30, 2009 11:17 am    Post subject: Reply with quote

Thanx for the info!

Yeah, the tutorial I'm currently reading uses display lists for TTF rendering, so I might try that first, but I'll check out the method you mentioned as well.

As for the sound and input, I'll read up on what you said. I'm not really interested in using any fancy api for the sound like openal or fmod, I just need the bare basics to play a .wav file.
_________________
....noodle...
Back to top
View user's profile Send private message MSN Messenger
mh



Joined: 12 Jan 2008
Posts: 909

PostPosted: Sun Aug 30, 2009 12:02 pm    Post subject: Reply with quote

PlaySound will do the WAV playback thing but it's not going to be high performance and you'll lose a lot of flexibility in terms of mixing, panning, etc. If you just want to make a noise and you're not concerned about effects or latency I guess it's fine.

DirectInput might be good for mouse input. It's a nice API that's incredibly simple to set up and use (create an interface, create a device, acquire it for use and read events). It's officially deprecated and is really just a wrapper around the standard Windows messaging functions, and doesn't work too well with some touchpads, but it does have the advantages of disabling mouse acceleration for you, you don't need to worry about stuff like re-centering the mouse after each move or showing/hiding the cursor, and you can consolidate all of your mouse code in the one place.

Don't use it for keyboard input though, that can get real messy as it uses it's own key code table which needs to be translated, and it can frequently send multiple key events with one press which will need to be filtered.
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
frag.machine



Joined: 25 Nov 2006
Posts: 728

PostPosted: Mon Aug 31, 2009 12:38 am    Post subject: Reply with quote

Well, it's a bit off-topic (since it's not OpenGL), but I stumbled at this DirectX wrapper engine another day. Even if you're not going to do 2D gaming and use Direct3D, it has a really good support to input and sound API's. Also, it supports bitmap fonts created from TTF (even has a small utility to conversion).
_________________
frag.machine - Q2K4 Project
http://fragmachine.quakedev.com/
Back to top
View user's profile Send private message Visit poster's website
Zylyx_



Joined: 05 Dec 2007
Posts: 111
Location: scotland, uk

PostPosted: Mon Aug 31, 2009 9:26 am    Post subject: Reply with quote

Hmm, that HGE engine does look interesting.

Like I said, all of this is a learning experiance for me, so I dont mind doing the bare basics (infact, i find it neccessary). But all the libs you mentioned are really good for building a full game/demo without rebuidling the wheel.

Unfortunately, for my university work we are restircted to using GDI for 2D windows graphics programming and OpenGL for 3D. We are also doing 2D graphics programming on the PS2, which I'm guessing is going to be similart to the GBA programming we did last year, probably a bit more complex.

However, coming from a minor SDL programming background, I do appreciate the easy of using straight off the shelfs libs and wrappers like the ones you mentioned. Makes life so much more easier.

Anywho, I'm gonna start implementing the TTF rendering for my Swogle lib now. Results and headaches coming soon.
_________________
....noodle...
Back to top
View user's profile Send private message MSN Messenger
frag.machine



Joined: 25 Nov 2006
Posts: 728

PostPosted: Tue Sep 01, 2009 12:30 am    Post subject: Reply with quote

I read in their forums there's at least one non-official HGE port to OpenGL. Don't know the current status, but you may want to check it out.
_________________
frag.machine - Q2K4 Project
http://fragmachine.quakedev.com/
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    Inside3d Forums Forum Index -> OpenGL Programming All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2004 phpBB Group