#include #include //Necessary for making a window, as well as about a billion other things. #include //OpenGL ahoy! #define WM_MOUSEWHEEL 0x020A //Some reason they didn't define this themselves. #define TPF 16 //"Time per frame"--should be 16, as far as I'm concerned, which is 62.5 FPS. char Ending = 0; int rotAmnt = 0; int rotAmnt2 = 0; HGLRC hRC; HDC ghdc; HWND hWnd; WNDCLASS ckWndClass; HDC winDC; char GLRunning = 0; int InitializeGL(HDC dsthDC, unsigned int Width, unsigned int Height); void DrawFrame(); LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { //This procedure is for handling input. I've left some examples here for you. //The modern .NET C++ can probably handle all this crap for you, but lower level is more control, which is more power and speed. switch (uMsg) { case WM_CLOSE: Ending = 1; break; case WM_MOUSEWHEEL: if ((wParam >> ((sizeof (WORD)) * 16 - 1))) { // printf("Mousewheeled down!\n"); rotAmnt2-=10; } else { // printf("Mousewheeled up!\n"); rotAmnt2+=4; } break; case WM_LBUTTONDOWN: printf("Left mouse button down!\n"); break; case WM_RBUTTONDOWN: printf("Right mouse button down!\n"); break; case WM_LBUTTONUP: printf("Left mouse button up!\n"); break; case WM_RBUTTONUP: printf("Right mouse button up!\n"); break; case WM_KEYDOWN: printf("Key down! (%d)\n", wParam); break; case WM_KEYUP: printf("Key up! (%d)\n", wParam); break; case WM_ACTIVATEAPP: //When focus changes to or from the window. if (wParam==0) { if (GLRunning) { //Disable the OpenGL rendering and frame calculation while the window is out of focus. wglMakeCurrent(NULL, NULL); wglDeleteContext(hRC); ReleaseDC(hWnd, winDC); } printf("Lost focus!\n"); GLRunning = 0; } else { if (!GLRunning) { winDC = GetWindowDC(hWnd); InitializeGL(winDC, 640, 480); } printf("Regained focus!\n"); GLRunning = 1; } break; } //You'll probably want to keep this line here forever. It allows Windows to take care of the normal window functions, such as resizing. return DefWindowProc(hwnd, uMsg, wParam, lParam); } // Dispatch all waiting events. I still couldn't tell you how it works, but it works. I can tell you, though, it's complicated. void tpkWDoEvents() { MSG M; // Go until there's nothing left while (PeekMessage(&M, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&M); DispatchMessage(&M); } return; } int main() { printf("Attempting to register class...\n"); //The first thing you gotta do is set up this smelly structure so you can register the class (worthless terminology) and then make the window based on that. ckWndClass.style = CS_DBLCLKS|CS_OWNDC; ckWndClass.lpfnWndProc = (WNDPROC) WindowProc; ckWndClass.cbClsExtra = 0; ckWndClass.cbWndExtra = 0; ckWndClass.hInstance = GetModuleHandle(NULL); ckWndClass.hIcon = NULL; ckWndClass.hCursor = LoadCursor(NULL, IDC_ARROW); ckWndClass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); ckWndClass.lpszMenuName = ""; ckWndClass.lpszClassName = "ckWndClass"; if (!RegisterClass(&ckWndClass)) { printf("Failed to register class. BACKWARDS BOB.\n"); return 1; } printf("Attempting to create window...\n"); hWnd = CreateWindow(ckWndClass.lpszClassName, "Test of DeProgrammer", WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, ckWndClass.hInstance, NULL); if (hWnd == NULL) { printf("Failed to create window. BACKWARDS BOB.\n"); //Backwards Bob is what I dubbed GuyPerfect's always-backwards smiley. (-: UnregisterClass(ckWndClass.lpszClassName, ckWndClass.hInstance); return 1; } printf("Attempting to show window...\n"); ShowWindow(hWnd, SW_SHOWNORMAL); winDC = GetWindowDC(hWnd); InitializeGL(winDC, 640, 480); GLRunning = 1; while (!Ending) { //There's no real timing code here; it's just a "wait 30 ms after one frame has drawn" system. See bottom of file. tpkWDoEvents(); SleepEx(30, TRUE); if (GLRunning) { rotAmnt++; rotAmnt2+=3; if (rotAmnt > 360) rotAmnt -= 360; if (rotAmnt2 > 360) rotAmnt2 -= 360; DrawFrame(); } } GLRunning = 0; //Uninitialize OpenGL wglMakeCurrent(NULL, NULL); wglDeleteContext(hRC); ReleaseDC(hWnd, winDC); DestroyWindow(hWnd); UnregisterClass(ckWndClass.lpszClassName, ckWndClass.hInstance); //Can't forget to clean up the mess. return 0; } int InitializeGL(HDC dsthDC, unsigned int Width, unsigned int Height) { PIXELFORMATDESCRIPTOR PFD; int PixelFormat; ghdc = dsthDC; PFD.cColorBits = 32; PFD.cDepthBits = 16; PFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA; PFD.iLayerType = PFD_MAIN_PLANE; PFD.iPixelType = PFD_TYPE_RGBA; PFD.nSize = sizeof(PFD); PFD.nVersion = 1; PixelFormat = ChoosePixelFormat(ghdc, &PFD); //Don't ask me. I can't remember. :) SetPixelFormat(ghdc, PixelFormat, &PFD); hRC = wglCreateContext(ghdc); //Create the OpenGL context if (hRC == 0) return 0; wglMakeCurrent(ghdc, hRC); glViewport(0, 0, Width, Height); glMatrixMode(GL_PROJECTION); //Another one of those things that I couldn't explain to you. I don't use anything else. glLoadIdentity(); gluPerspective(45, (Width / Height), 0.1, 100); //Wanna do 2D instead of 3D? Use glOrtho(0, Width, 0, Height, -1, 1);, and you could probably make those last two parameters 0. glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //I don't know about this either, but I didn't use it in my GenGine. glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //You know what? Enough of me saying I don't know what it is. There are OpenGL tutorials out there. All *I* need to know is that it works. :) glClearColor(0, 0, 0, 0); glClearDepth(1); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glShadeModel(GL_SMOOTH); glHint(GL_FOG_HINT, GL_NICEST); //Blah blah blah, enable lighting, disable all but one light. glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHT0); glDisable(GL_LIGHT1); glDisable(GL_LIGHT2); glDisable(GL_LIGHT3); glDisable(GL_LIGHT4); glDisable(GL_LIGHT5); glDisable(GL_LIGHT6); glDisable(GL_LIGHT7); return (int) hRC; } void DrawFrame() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glTranslatef(0, 0, -8); glRotated((GLdouble) rotAmnt, 0, 1, 0); glRotated((GLdouble) rotAmnt2, 1, 0, 0); glColor4f(1, 0.5, 0, 1); glNormal3d(0, 0, 1); //You want to draw things in a certain direction. Also, the top is positive and the bottom is negative. //And in OpenGL, units can be pretty huge depending on what you're doing. //This section draws the cube, in four completely unattached faces, no texturing. glBegin(GL_TRIANGLE_STRIP); //GL_LINES, GL_POINTS, GL_LINE_LOOP are the options for this. glVertex3f(-0.5, 0.5, 0.5); glVertex3f(-0.5, -0.5, 0.5); glVertex3f(0.5, 0.5, 0.5); glVertex3f(0.5, -0.5, 0.5); glEnd(); glRotated(90, 0, 1, 0); glBegin(GL_TRIANGLE_STRIP); glVertex3f(-0.5, 0.5, 0.5); glVertex3f(-0.5, -0.5, 0.5); glVertex3f(0.5, 0.5, 0.5); glVertex3f(0.5, -0.5, 0.5); glEnd(); glRotated(90, 0, 1, 0); glBegin(GL_TRIANGLE_STRIP); glVertex3f(-0.5, 0.5, 0.5); glVertex3f(-0.5, -0.5, 0.5); glVertex3f(0.5, 0.5, 0.5); glVertex3f(0.5, -0.5, 0.5); glEnd(); glRotated(90, 0, 1, 0); glBegin(GL_TRIANGLE_STRIP); glVertex3f(-0.5, 0.5, 0.5); glVertex3f(-0.5, -0.5, 0.5); glVertex3f(0.5, 0.5, 0.5); glVertex3f(0.5, -0.5, 0.5); glEnd(); glRotated(90, 1, 0, 0); glBegin(GL_TRIANGLE_STRIP); glVertex3f(-0.5, 0.5, 0.5); glVertex3f(-0.5, -0.5, 0.5); glVertex3f(0.5, 0.5, 0.5); glVertex3f(0.5, -0.5, 0.5); glEnd(); glRotated(180, 1, 0, 0); glBegin(GL_TRIANGLE_STRIP); glVertex3f(-0.5, 0.5, 0.5); glVertex3f(-0.5, -0.5, 0.5); glVertex3f(0.5, 0.5, 0.5); glVertex3f(0.5, -0.5, 0.5); glEnd(); glPopMatrix(); glFinish(); SwapBuffers(ghdc); } //This nifty little function of mine is unused in the code, but I thought I'd toss it in for good measure. //I'm sure you'll want to use textures, and this shows you that basic idea. It won't compile as-is, though. //I left my structs out of this old program. Also, I haven't given you the rest of the texture code to peruse yet. //Texture coordinates are mapped on a 0-to-1 basis. (1,1) is the top-right corner of a texture; (0,0) is the bottom-left. //You'll pretty much always want to keep textures to power-of-two dimensions. A lot of negative side effects result if you don't. /* void DrawSprite(float dsX, float dsY, int dsIndex) { glEnable glTranslatef(dsX, minScreenHeight-dsY-SprtLoc[dsIndex].Height, 0); TextureSelect((int)TexID1,0); //TODO: Uh-huh, uh-huh...gonna need some extra code here too. glBegin(GL_TRIANGLE_STRIP); glTexCoord2d(SprtLoc[dsIndex].L, SprtLoc[dsIndex].B); glVertex3f(0, SprtLoc[dsIndex].Height, 0); glTexCoord2d(SprtLoc[dsIndex].L, SprtLoc[dsIndex].T); glVertex3f(0, 0, 0); glTexCoord2d(SprtLoc[dsIndex].R, SprtLoc[dsIndex].B); glVertex3f(SprtLoc[dsIndex].Width, SprtLoc[dsIndex].Height, 0); glTexCoord2d(SprtLoc[dsIndex].R, SprtLoc[dsIndex].T); glVertex3f(SprtLoc[dsIndex].Width, 0, 0); glEnd(); glTranslatef(-dsX, dsY-minScreenHeight+SprtLoc[dsIndex].Height, 0); }*/ //Here's another handy function. How to get the path of the program. I use this kind of thing a lot, of course. //I'm not sure if it requires string.h, but I'll include that just in case. /* #include char AppPath[255]; char *AppEXEName; void findAppPathAndName() { GetModuleFileName(NULL,(LPTSTR)&AppPath,255); AppEXEName=strrchr(AppPath, '\\')+1; *(AppEXEName-1)=0; //Makes AppPath its own string that ends before the slash; in fact, the slash itself is replaced with a null char. } */ /* And the final note, awesome timing! As far as I know, I just perfected it. #include // In the main function, most likely: LARGE_INTEGER perFreq, perCnt, StoreMS; double Change=0; GLRunning = 1; QueryPerformanceCounter(&perCnt); //Basically, this initializes the Change counter to 0. StoreMS.QuadPart=perCnt.QuadPart; while (!Ending) { tpkWDoEvents(); SleepEx(1, TRUE); QueryPerformanceFrequency(&perFreq); //Gets the frequency of the high-resolution timer. QueryPerformanceCounter(&perCnt); //Gets the count on the high-resolution timer. Change += (perCnt.QuadPart - StoreMS.QuadPart) * 1000 / perFreq.QuadPart; //Converts that change in time to milliseconds and stashes it. StoreMS.QuadPart = perCnt.QuadPart; //Also keep the current high-resolution count for subtraction next frame. if (Change>=TPF) { if (Change >= TPF * 5) Change = TPF; //Pretend that drawing has fallen too far behind to attempt to catch up. Change -= TPF; if (GLRunning) { //TODO: Decide when to draw a frame and when to only calculate one CalcFrame(); DrawFrame(); } } } */