#include "DisplayClass.h" #include "gl.h" #include "Keys.h" //#include //#include #ifdef _WIN32 #else #include #include #include #include #include #include #endif #define MIN_FRAME_DELTA 16 //#define MIN_FRAME_DELTA 41 #define DEFAULT_WIDTH 640 #define DEFAULT_HEIGHT 640 //#define DEFAULT_HEIGHT 200 //#define DEFAULT_WIDTH 200 Keyset keys; void initGL(bool multisample); void resize(int width, int height); void initGL(bool multisample) { glClearColor(0.0, 0.0, 0.0, 1.0);//glClearColor(1.0, 0.85, 0.06, 1.0); glClearDepth(1.0); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #ifndef _WIN32 if(multisample) glEnable(GL_MULTISAMPLE_ARB); #endif resize(DEFAULT_WIDTH, DEFAULT_HEIGHT); glEnable(GL_LIGHTING); static const float light[] = {1, 1, 1, 0}; static const float lightColor[] = {1, 1, 1, 1}; glLightfv(GL_LIGHT0, GL_POSITION, light); glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor); glEnable(GL_LIGHT0); //glEnable(GL_CULL_FACE); //glFrontFace(GL_CCW); } void resize(int width, int height) { if(height==0) { height=1; } glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(50.0f, (GLfloat)width/(GLfloat)height, 0.1, 1000); glMatrixMode(GL_MODELVIEW); glViewport(0, 0, width, height); } #ifdef _WIN32 bool WGLInit(HINSTANCE hInstance, HWND *hWnd, HDC *hDC, HGLRC *hRC); void WGLUninit(HWND hWnd, HDC hDC, HGLRC hRC); LRESULT CALLBACK wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); bool WGLInit(HINSTANCE hInstance, HWND *hWnd, HDC *hDC, HGLRC *hRC) { WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = (WNDPROC)wndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = 0; wc.lpszMenuName = 0; wc.lpszClassName = "3D"; if (!RegisterClass(&wc)) { MessageBox(0, "Failed To Register The Window Class.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; // Exit And Return FALSE } DWORD dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; DWORD dwStyle = WS_OVERLAPPEDWINDOW; RECT windowRect; windowRect.left = 0; windowRect.right = DEFAULT_WIDTH; windowRect.top = 0; windowRect.bottom = DEFAULT_HEIGHT; AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle); *hWnd = CreateWindowEx(dwExStyle, "3D" /* Class Name */, "3D" /* Title*/, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle, 0, 0, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, 0, 0, hInstance, 0); if(!*hWnd) { MessageBox(0, "Window Creation Error.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; } static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor 1, // Version Number PFD_DRAW_TO_WINDOW | // Format Must Support Window PFD_SUPPORT_OPENGL | // Format Must Support OpenGL PFD_DOUBLEBUFFER, // Must Support Double Buffering PFD_TYPE_RGBA, // Request An RGBA Format 16, // Select Our Color Depth 0, 0, 0, 0, 0, 0, // Color Bits Ignored 0, // No Alpha Buffer 0, // Shift Bit Ignored 0, // No Accumulation Buffer 0, 0, 0, 0, // Accumulation Bits Ignored 16, // 16Bit Z-Buffer (Depth Buffer) 0, // No Stencil Buffer 0, // No Auxiliary Buffer PFD_MAIN_PLANE, // Main Drawing Layer 0, // Reserved 0, 0, 0 // Layer Masks Ignored }; *hDC=GetDC(*hWnd); if (!*hDC) { WGLUninit(*hWnd, 0, 0); MessageBox(0, "Can't Create A GL Device Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; } GLuint pixelFormat = ChoosePixelFormat(*hDC, &pfd); if(!pixelFormat) { WGLUninit(*hWnd, *hDC, 0); MessageBox(0, "Can't Find A Suitable PixelFormat.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; } if(!SetPixelFormat(*hDC, pixelFormat, &pfd)) { WGLUninit(*hWnd, *hDC, 0); MessageBox(0, "Can't Set The PixelFormat.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; } *hRC=wglCreateContext(*hDC); if(!*hRC) { WGLUninit(*hWnd, *hDC, 0); MessageBox(0, "Can't Create A GL Rendering Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; } if(!wglMakeCurrent(*hDC, *hRC)) { WGLUninit(*hWnd, *hDC, *hRC); MessageBox(0, "Can't Activate The GL Rendering Context.", "ERROR", MB_OK|MB_ICONEXCLAMATION); return false; } ShowWindow(*hWnd, SW_SHOW); SetForegroundWindow(*hWnd); SetFocus(*hWnd); return true; } void WGLUninit(HWND hWnd, HDC hDC, HGLRC hRC) { wglMakeCurrent(0, 0); if(hRC) wglDeleteContext(hRC); if(hDC) ReleaseDC(hWnd, hDC); if(hWnd) DestroyWindow(hWnd); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HWND hWnd = 0; HDC hDC = 0; HGLRC hRC = 0; if(!WGLInit(hInstance, &hWnd, &hDC, &hRC)) { return 0; } initGL(false); bool running = true; MSG msg; while(running) { unsigned long delta = 0; unsigned long ticks = GetTickCount(); while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if(msg.message == WM_QUIT) { running = false; break; } else // If Not, Deal With Window Messages { TranslateMessage(&msg); // Translate The Message DispatchMessage(&msg); // Dispatch The Message } } void resize(int width, int height); delta = GetTickCount()-ticks; if(delta < MIN_FRAME_DELTA) { Sleep(MIN_FRAME_DELTA - delta); delta = GetTickCount()-ticks; } ticks += delta; static DisplayClass render(5, 15, 5); render.renderScene(delta, keys); SwapBuffers(hDC); } WGLUninit(hWnd, hDC, hRC); return msg.wParam; } LRESULT CALLBACK wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_CLOSE: PostQuitMessage(0); return 0; case WM_SIZE: resize(LOWORD(lParam), HIWORD(lParam)); return 0; case WM_KEYDOWN: case WM_KEYUP: bool pressed = (uMsg == WM_KEYDOWN); switch(wParam) { case VK_Escape: PostQuitMessage(0); break; case VK_Up: case VK_W: case VK_KP_8: case VK_KP_Up: keys.set(KEY_UP, pressed); break; case VK_Left: case VK_A: case VK_KP_4: case VK_KP_Left: keys.set(KEY_LEFT, pressed); break; case VK_Right: case VK_D: case VK_KP_6: case VK_KP_Right: keys.set(KEY_RIGHT, pressed); break; case VK_Down: case VK_S: case VK_KP_2: case VK_KP_Down: keys.set(KEY_DOWN, pressed); break; case VK_Page_Up: case VK_minus: case VK_KP_Subtract: case VK_KP_Page_Up: keys.set(KEY_ZOOM_OUT, pressed); break; case VK_Page_Down: case VK_plus: case VK_KP_Add: case VK_KP_Page_Down: keys.set(KEY_ZOOM_IN, pressed); break; case VK_HOME: case VK_KP_HOME: keys.set(KEY_TOP, pressed); break; case VK_END: case VK_KP_END: keys.set(KEY_BOTTOM, pressed); break; } default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } } #else bool GLXinit(Display *disp, Atom windele, Window *wnd, GLXContext *gc, bool *multisample) { static const int msAttributeList[] = {GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_X_RENDERABLE, True, GLX_DOUBLEBUFFER, True, GLX_DEPTH_SIZE, 1, GLX_SAMPLE_BUFFERS, 1, GLX_SAMPLES, 4, None}; static const int attributeList[] = {GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_X_RENDERABLE, True, GLX_DOUBLEBUFFER, True, GLX_DEPTH_SIZE, 1, None}; bool ok = false; *multisample = true; int nElements; GLXFBConfig *fbConfig = glXChooseFBConfig(disp, DefaultScreen(disp), msAttributeList, &nElements); if(!fbConfig || !nElements) { if(fbConfig) { XFree(fbConfig); } *multisample = false; fbConfig = glXChooseFBConfig(disp, DefaultScreen(disp), attributeList, &nElements); } if(fbConfig && nElements) { XVisualInfo *vi = glXGetVisualFromFBConfig(disp, *fbConfig); if(vi) { Colormap cmap = XCreateColormap(disp, RootWindow(disp, vi->screen), vi->visual, AllocNone); XSetWindowAttributes swa; swa.colormap = cmap; swa.border_pixel = 0; swa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask/* | PointerMotionMask | ButtonPressMask | ButtonReleaseMask*/; *wnd = XCreateWindow(disp, RootWindow(disp, vi->screen), 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa); XClassHint chint; chint.res_name = const_cast("3D"); chint.res_class = const_cast("3d"); XSetClassHint(disp, *wnd, &chint); char *str = const_cast("3D"); XTextProperty name; if(XStringListToTextProperty(&str, 1, &name) != 0) { XSetWMName(disp, *wnd, &name); XFree(name.value); } XSetWMProtocols(disp, *wnd, &windele, 1); XMapWindow(disp, *wnd); *gc = glXCreateContext(disp, vi, NULL, True); glXMakeCurrent(disp, *wnd, *gc); ok = true; XFree(vi); } } if(fbConfig) XFree(fbConfig); XSync(disp, 0); return ok; } int main(int argc, char *argv[]) { Display *disp = XOpenDisplay(0); Atom windele = XInternAtom(disp, "WM_DELETE_WINDOW", False); Window wnd; GLXContext gc; if(argc != 4) { std::cerr << "Wrong paramter count" << std::endl; return 1; } bool multisample; if(!GLXinit(disp, windele, &wnd, &gc, &multisample)) return 1; initGL(multisample); GLint samples; glGetIntegerv(GL_SAMPLES, &samples); // std::cerr << "Using " << samples << " samples" << std::endl; bool running = true; unsigned long delta = 0; unsigned long frames = 0, tocks = 0; struct timeval tv; gettimeofday(&tv, NULL); unsigned long ticks = tv.tv_usec; while(running) { while(XPending(disp)) { XEvent event; XNextEvent(disp, &event); switch(event.type) { case ConfigureNotify: resize(event.xconfigure.width, event.xconfigure.height); break; case ClientMessage: if(static_cast(event.xclient.data.l[0]) == windele) running = false; break; case KeyPress: case KeyRelease: KeySym keysym = XKeycodeToKeysym(disp, event.xkey.keycode, 0); bool pressed = (event.type == KeyPress); switch(keysym) { case XK_Escape: running = false; break; case XK_Up: case XK_w: case XK_KP_8: case XK_KP_Up: keys.set(KEY_UP, pressed); break; case XK_Left: case XK_a: case XK_KP_4: case XK_KP_Left: keys.set(KEY_LEFT, pressed); break; case XK_Right: case XK_d: case XK_KP_6: case XK_KP_Right: keys.set(KEY_RIGHT, pressed); break; case XK_Down: case XK_s: case XK_KP_2: case XK_KP_Down: keys.set(KEY_DOWN, pressed); break; case XK_Page_Up: case XK_minus: case XK_KP_Subtract: case XK_KP_Page_Up: keys.set(KEY_ZOOM_OUT, pressed); break; case XK_Page_Down: case XK_plus: case XK_KP_Add: case XK_KP_Page_Down: keys.set(KEY_ZOOM_IN, pressed); break; case XK_Home: case XK_KP_Home: keys.set(KEY_TOP, pressed); break; case XK_End: case XK_KP_End: keys.set(KEY_BOTTOM, pressed); break; } } } if(!running) break; static DisplayClass render(std::atoi(argv[1]), std::atoi(argv[2]), std::atoi(argv[3])); render.renderScene(delta, keys); glXSwapBuffers(disp, wnd); XSync(disp, 0); long slept = 0; gettimeofday(&tv, NULL); delta = ((tv.tv_usec + 1000000 - ticks)%1000000)/1000; if(delta < MIN_FRAME_DELTA) { usleep((MIN_FRAME_DELTA-delta)*1000); slept += (MIN_FRAME_DELTA-delta); gettimeofday(&tv, NULL); delta = ((tv.tv_usec + 1000000 - ticks)%1000000)/1000; } ticks = (ticks + delta*1000) % 1000000; frames++; tocks += delta*1000; if(tocks > 1000000) { // std::cerr << frames << " fps; slept a total of " << slept << " ms" << std::endl; frames = 0; tocks -= 1000000; slept = 0; } } XDestroyWindow(disp, wnd); glXDestroyContext(disp, gc); XCloseDisplay(disp); return 0; } #endif