/*************************************************************************** * Copyright (C) 2001-2023 by Tom Hicks * * headhunter3@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "window.h" #include #include namespace OpenArena { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" void OpenArena::Window::SwapBuffers() { #if defined USE_GLX if (doubleBuffered) { glXSwapBuffers(display, window); } #elif defined USE_AGL aglSwapBuffers(_aglContext); #elif defined USE_CGL CGLFlushDrawable(cglContext); #elif defined USE_WGL ::SwapBuffers(deviceContext); #endif } bool OpenArena::Window::Open() { #if defined USE_GLX XVisualInfo* vi; Colormap cmap; int bestMode = 0; int vidModeMajorVersion; int vidModeMinorVersion; int glxMajorVersion; int glxMinorVersion; int modeNum; #if defined HAVE_XF86VIDMODE XF86VidModeModeInfo** modes; #endif Atom wmDelete; ::Window winDummy; unsigned int borderDummy; display = XOpenDisplay(0); screen = DefaultScreen(display); #if defined HAVE_XF86VIDMODE XF86VidModeQueryVersion(display, &vidModeMajorVersion, &vidModeMinorVersion); printf("XF86VidModeExtension-Version %d.%d\n", vidModeMajorVersion, vidModeMinorVersion); XF86VidModeGetAllModeLines(display, screen, &modeNum, &modes); vidMode = *modes[0]; int i; for (i = 0; i < modeNum; i++) { // Add a check for colordepth here if ((modes[i]->hdisplay == _width) && (modes[i]->vdisplay == _height)) { bestMode = i; } } #endif vi = glXChooseVisual(display, screen, attrListDbl); if (vi == NULL) { vi = glXChooseVisual(display, screen, attrListSgl); doubleBuffered = false; printf("Only Singlebuffered Visual!\n"); } else { doubleBuffered = true; printf("Got Doublebuffered Visual!\n"); } glXQueryVersion(display, &glxMajorVersion, &glxMinorVersion); printf("glX-Version %d.%d\n", glxMajorVersion, glxMinorVersion); hRC = glXCreateContext(display, vi, 0, GL_TRUE); cmap = XCreateColormap(display, RootWindow(display, vi->screen), vi->visual, AllocNone); attributes.colormap = cmap; attributes.border_pixel = 0; attributes.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | // PointerMotionMask | ButtonMotionMask | StructureNotifyMask; if (_fullscreen) { #if defined HAVE_XF86VIDMODE XF86VidModeSwitchToMode(display, screen, modes[bestMode]); XF86VidModeSetViewPort(display, screen, 0, 0); XFree(modes); #endif attributes.override_redirect = true; window = XCreateWindow(display, RootWindow(display, vi->screen), 0, 0, _width, _height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &attributes); XWarpPointer(display, None, window, 0, 0, 0, 0, 0, 0); XMapRaised(display, window); XGrabKeyboard(display, window, true, GrabModeAsync, GrabModeAsync, CurrentTime); XGrabPointer(display, window, true, ButtonPressMask, GrabModeAsync, GrabModeAsync, window, None, CurrentTime); XDefineCursor(display, window, CreateFullscreenCursor()); } else { window = XCreateWindow(display, RootWindow(display, vi->screen), 0, 0, _width, _height, 0, vi->depth, InputOutput, vi->visual, CWBorderPixel | CWColormap | CWEventMask, &attributes); wmDelete = XInternAtom(display, "WM_DELETE_WINDOW", true); XSetWMProtocols(display, window, &wmDelete, 1); XSetStandardProperties(display, window, GetName(), GetName(), None, NULL, 0, NULL); XMapRaised(display, window); XDefineCursor(display, window, CreateWindowedCursor()); } glXMakeCurrent(display, window, hRC); unsigned int twidth, theight, depth; XGetGeometry(display, window, &winDummy, &x, &y, &twidth, &theight, &borderDummy, &depth); _colorDepth = (char)depth; _height = (short)twidth; _width = (short)theight; printf("Resolution %dx%d\n", twidth, theight); printf("Depth %d\n", depth); if (glXIsDirect(display, hRC)) { printf("Congrats, you have Direct Rendering!\n"); } else { printf("Sorry, no Direct Rendering possible!\n"); } _initializer->Initialize(); return true; #elif defined USE_AGL OSStatus err = noErr; SetRect(&_bounds, 0, 0, 640, 480); err = CreateNewWindow(kDocumentWindowClass, kWindowStandardHandlerAttribute | kWindowCloseBoxAttribute | kWindowFullZoomAttribute | kWindowCollapseBoxAttribute, &_bounds, &_window); if (err != noErr) { return false; } RepositionWindow(_window, NULL, kWindowCascadeOnMainScreen); AGLDevice* devices = NULL; GLint deviceCount = 0; GLint attributes[] = {AGL_ACCELERATED, AGL_NO_RECOVERY, AGL_RGBA, AGL_DOUBLEBUFFER, AGL_NONE}; AGLPixelFormat pixelFormat; pixelFormat = aglChoosePixelFormat(devices, deviceCount, attributes); _aglContext = aglCreateContext(pixelFormat, NULL); if (!_aglContext) { exit(5); } aglDestroyPixelFormat(pixelFormat); if (!aglSetCurrentContext(_aglContext)) { exit(6); } if (!aglSetDrawable(_aglContext, GetWindowPort(_window))) { exit(7); } glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); aglSwapBuffers(_aglContext); ShowWindow(_window); #elif defined USE_CGL #error undefined method #elif defined USE_WGL unsigned int PixelFormat; WNDCLASS wc; DWORD dwExStyle; DWORD dwStyle; RECT WindowRect; WindowRect.left = (long)0; WindowRect.right = (long)_width; WindowRect.top = (long)0; WindowRect.bottom = (long)_height; instance = GetModuleHandle(NULL); wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = (WNDPROC)WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = instance; wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = "OpenArena v0.1.0"; if (!RegisterClass(&wc)) { MessageBox(NULL, "Failed To Register The Window Class.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return false; } if (_fullscreen) { DEVMODE dmScreenSettings; memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); dmScreenSettings.dmSize = sizeof(dmScreenSettings); dmScreenSettings.dmPelsWidth = _width; dmScreenSettings.dmPelsHeight = _height; dmScreenSettings.dmBitsPerPel = _colorDepth; dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { if (MessageBox(NULL, "The Requested Fullscreen Mode Is Not Supported By\nYour " "Video Card. Use Windowed Mode Instead?", "OpenArena", MB_YESNO | MB_ICONEXCLAMATION) == IDYES) _fullscreen = false; else { MessageBox(NULL, "Program Will Now Close.", "ERROR", MB_OK | MB_ICONSTOP); return false; } } } if (_fullscreen) { dwExStyle = WS_EX_APPWINDOW; dwStyle = WS_POPUP; ShowCursor(/*true*/ false); } else { ShowCursor(false); dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; dwStyle = WS_OVERLAPPEDWINDOW; } AdjustWindowRectEx(&WindowRect, dwStyle, false, dwExStyle); if (!(window = CreateWindowEx(dwExStyle, "OpenArena v0.1.0", GetName(), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle, 0, 0, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, NULL, NULL, instance, NULL))) { Close(); MessageBox(NULL, "Window Creation Error.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return false; } static PIXELFORMATDESCRIPTOR pfd = {sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, _colorDepth, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, PFD_MAIN_PLANE, 0, 0, 0, 0}; if (!(deviceContext = GetDC(window))) { Close(); MessageBox(NULL, "Can't Create A GL Device Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return false; } if (!(PixelFormat = ChoosePixelFormat(deviceContext, &pfd))) { Close(); MessageBox(NULL, "Can't Find A Suitable PixelFormat.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return false; } if (!SetPixelFormat(deviceContext, PixelFormat, &pfd)) { Close(); MessageBox(NULL, "Can't Set The PixelFormat.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return false; } if (!(glContext = wglCreateContext(deviceContext))) { Close(); MessageBox(NULL, "Can't Create A GL Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return false; } if (!wglMakeCurrent(deviceContext, glContext)) { Close(); MessageBox(NULL, "Can't Activate The GL Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return false; } ShowWindow(window, SW_SHOW); SetForegroundWindow(window); SetFocus(window); _resizer->Resize(_width, _height); if (!_initializer->Initialize()) { Close(); MessageBox(NULL, "Initialization Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION); return false; } return true; #endif return false; } void OpenArena::Window::Close() { #if defined USE_GLX if (_fullscreen) { #if defined HAVE_XF86VIDMODE XF86VidModeSwitchToMode(display, screen, &vidMode); XF86VidModeSetViewPort(display, screen, 0, 0); #endif } if (hRC) { if (!glXMakeCurrent(display, None, NULL)) { printf("Could not release drawing context.\n"); } glXDestroyContext(display, hRC); hRC = NULL; } XCloseDisplay(display); #elif defined USE_AGL if (!_fullscreen) { aglSetCurrentContext(NULL); aglDestroyContext(_aglContext); _aglContext = NULL; } #elif defined USE_CGL #error unimplemented method #elif defined USE_WGL if (_fullscreen) { ChangeDisplaySettings(NULL, 0); ShowCursor(true); } if (glContext) { if (!wglMakeCurrent(NULL, NULL)) MessageBox(NULL, "Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); if (!wglDeleteContext(glContext)) MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); glContext = NULL; } if (deviceContext && !ReleaseDC(window, deviceContext)) { MessageBox(NULL, "Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); deviceContext = NULL; } if (window && !DestroyWindow(window)) { MessageBox(NULL, "Could Not Release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); window = NULL; } if (!UnregisterClass("OpenArena v0.1.0", instance)) { MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); instance = NULL; } #endif } bool OpenArena::Window::Open(string title, int width, int height, int bits, bool fullscreenflag) { _fullscreen = fullscreenflag; _width = width; _height = height; _colorDepth = bits; _name = title; return Open(); } OpenArena::Window::Window() { _initializer = new Initializer(); _resizer = new Resizer(); } OpenArena::Window::~Window() {} void OpenArena::Window::SetInitializer(OpenArena::Window::Initializer* initializer) { _initializer = initializer; } void OpenArena::Window::SetResizer(OpenArena::Window::Resizer* resizer) { _resizer = resizer; } void OpenArena::Window::Resizer::Resize(uint32_t width, uint32_t height) { if (height == 0) height = 1; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, (float)width / (float)height, 0.1f, 100.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int OpenArena::Window::Initializer::Initialize() { glEnable(GL_TEXTURE_2D); glShadeModel(GL_SMOOTH); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearDepth(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); return true; } void OpenArena::Window::Resize(uint32_t width, uint32_t height) { _resizer->Resize(width, height); } OpenArena::Vec2i OpenArena::Window::GetMousePosition() { #ifdef USE_GLX ::Window rootWindow; ::Window childWindow; int rootX; int rootY; int mouseX; int mouseY; unsigned int mask; if (!XQueryPointer(display, window, &rootWindow, &childWindow, &rootX, &rootY, &mouseX, &mouseY, &mask)) { return Vec2i(-1, -1); } else { return Vec2i(mouseX, mouseY); } #elif defined USE_AGL #warning unimplemented method #elif defined USE_CGL #error unimplemented method #elif defined USE_WGL POINT pos; GetCursorPos(&pos); return Vec2i(pos.x, pos.y); #else return Vec2i(0, 0); #endif } void OpenArena::Window::SetMousePosition(Vec2i pos) { #if defined USE_GLX XWarpPointer(display, None, window, 0, 0, 0, 0, pos.x, pos.y); #elif defined USE_AGL #warning unimplemented method #elif defined USE_CGL #error unimplemented method #elif defined USE_WGL SetCursorPos(pos.x, pos.y); #endif } #ifdef USE_GLX Display* OpenArena::Window::GetDisplay() { return display; } Cursor OpenArena::Window::CreateWindowedCursor() { return CreateFullscreenCursor(); } Cursor OpenArena::Window::CreateFullscreenCursor() { Pixmap pixmap = XCreatePixmap(display, window, 1, 1, 1); XColor color; color.pixel = 0; color.red = 0; color.flags = DoRed; Cursor cur = XCreatePixmapCursor(display, pixmap, pixmap, &color, &color, 0, 0); XFreePixmap(display, pixmap); return cur; } #endif #pragma clang diagnostic pop } // End namespace OpenArena