From 2aa7199d36d895ec75bc6d63c9fc077cc31d5d6b Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Tue, 22 Jan 2013 17:18:14 +0100 Subject: [PATCH 1/1] Initial checkin for move to Git (no prior version history available). --- LICENSE | 2 + glwindow.cpp | 436 +++++++++++++++++++++++++++++++++++++++++++++++++++ glwindow.h | 55 +++++++ main.cpp | 267 +++++++++++++++++++++++++++++++ spec.txt | 19 +++ 5 files changed, 779 insertions(+) create mode 100644 LICENSE create mode 100644 glwindow.cpp create mode 100644 glwindow.h create mode 100644 main.cpp create mode 100644 spec.txt diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6f1f2cd --- /dev/null +++ b/LICENSE @@ -0,0 +1,2 @@ +Copyright 2007 Steinar H. Gunderson. +Licensed under the GPL, v2. diff --git a/glwindow.cpp b/glwindow.cpp new file mode 100644 index 0000000..eec09ca --- /dev/null +++ b/glwindow.cpp @@ -0,0 +1,436 @@ +/* + * The whole interface between GLWindow and the configuration stuff is rather + * icky, and _should_ be rewritten. It appears to work somehow, though ;-) + */ + +#include + +#ifdef WIN32 +#include +#endif + +#ifdef __linux__ +#include +#include +#include +#include +#endif + +#include +#include + +#include "glwindow.h" + +#ifdef WIN32 +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); + +/* this is ugly, but so is Win32 ;-) */ +GLWindow *win; +#endif + +#define DEMOLIB_XASPECT 4.0 +#define DEMOLIB_YASPECT 3.0 + +void GLWindow::resize(int x, int y, int w, int h) +{ + /* Prevent division by zero */ + if (h == 0) { + h = 1; + } + + float aspect = (float)w / (float)h; + if (aspect > DEMOLIB_XASPECT / DEMOLIB_YASPECT) { + int new_w = (int)((float)h * DEMOLIB_XASPECT / DEMOLIB_YASPECT); + x += (w - new_w) / 2; + w = new_w; + } else if (aspect < DEMOLIB_XASPECT / DEMOLIB_YASPECT) { + int new_h = (int)((float)w * DEMOLIB_YASPECT / DEMOLIB_XASPECT); + y += (h - new_h) / 2; + h = new_h; + } + + glViewport(x, y, w, h); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(53.0f, (GLfloat)w / (GLfloat)h, 1.0f, 500.0f); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + +#ifdef __linux__ +// XClearWindow(this->dpy, this->win); +#endif +} + +GLWindow::GLWindow(const char *title, int width, int height, int bpp, bool fullscreen, int zbuffer, int visual_id) +{ +#ifdef WIN32 + GLuint PixelFormat; + WNDCLASS wc; + DWORD dwExStyle; + DWORD dwStyle; + DEVMODE dmScreenSettings; + + if (visual_id != -1) { + EnumDisplaySettings(NULL, visual_id, &dmScreenSettings); + width = dmScreenSettings.dmPelsWidth; + height = dmScreenSettings.dmPelsHeight; + bpp = dmScreenSettings.dmBitsPerPel; + } else { + memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); + dmScreenSettings.dmSize = sizeof(dmScreenSettings); + dmScreenSettings.dmPelsWidth = width; + dmScreenSettings.dmPelsHeight = height; + dmScreenSettings.dmBitsPerPel = bpp; + dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + } + win = this; + + RECT WindowRect; + WindowRect.left = (long)0; + WindowRect.right = (long)width; + WindowRect.top = (long)0; + WindowRect.bottom = (long)height; + +#endif /* WIN32 */ +#ifdef __linux__ + XVisualInfo *vi; + int dpyWidth = 0, dpyHeight = 0; + int i; + XF86VidModeModeInfo **modes; + int modeNum; + int bestMode; + Atom wmDelete; + Window winDummy; + unsigned int borderDummy; + + static int attrList[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, + GLX_DEPTH_SIZE, zbuffer, + GLX_STENCIL_SIZE, 4, + None + }; +#endif /* __linux__ */ + + this->x = 0; + this->y = 0; + this->width = width; + this->height = height; + this->bpp = bpp; + this->fullscreen = fullscreen; + this->zbuffer = zbuffer; + this->done = 0; + +#ifdef WIN32 + this->hInstance = GetModuleHandle(NULL); + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = this->hInstance; + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = "Excess-OGL"; + + if( !RegisterClass(&wc) ) throw "Couldn't register Window Class"; + +#endif /* WIN32 */ +#ifdef __linux__ + /* set best mode to current */ + bestMode = 0; + + /* get a connection */ + this->dpy = XOpenDisplay(0); + this->screen = DefaultScreen(this->dpy); + + if (fullscreen) { + XF86VidModeGetAllModeLines(this->dpy, this->screen, &modeNum, &modes); + + /* save desktop-resolution before switching modes */ + this->deskMode = *modes[0]; + + /* look for mode with requested resolution */ + for (i = 0; i < modeNum; i++) { + if ((modes[i]->hdisplay == width) && (modes[i]->vdisplay == height)) { + bestMode = i; + } + } + + /* if we don't have it, bomb out */ + if (bestMode == 0 && (modes[0]->hdisplay != width || modes[0]->vdisplay != height)) { + throw "Couldn't set requested screen mode."; + } + } + + if (visual_id != -1) { + XVisualInfo tmplate; + int nret; + + tmplate.visualid = visual_id; + vi = XGetVisualInfo(this->dpy, VisualIDMask, &tmplate, &nret); + if (vi == NULL) { + throw "Couldn't get selected visual!"; + } + } else { + /* get an appropriate visual */ + vi = glXChooseVisual(this->dpy, this->screen, attrList); + if (vi == NULL) { + throw "Couldn't get double-buffered visual"; + } + } + + /* create a GLX context */ + this->ctx = glXCreateContext(this->dpy, vi, NULL, GL_TRUE); + + /* create a color map (umm, needed?) */ + Colormap cmap = XCreateColormap(this->dpy, RootWindow(this->dpy, vi->screen), + vi->visual, AllocNone); + this->attr.colormap = cmap; + + /* make a blank cursor */ + { + static char data[1] = {0}; + Cursor cursor; + Pixmap blank; + XColor dummy; + + blank = XCreateBitmapFromData(this->dpy, RootWindow(this->dpy, vi->screen), data, 1, 1); + if (blank == None) + throw "Out of memory!"; + cursor = XCreatePixmapCursor(this->dpy, blank, blank, &dummy, &dummy, 0, 0); + XFreePixmap(this->dpy, blank); + this->attr.cursor = cursor; + } + + this->attr.border_pixel = 0; +#endif /* __linux__ */ + + /* change screen mode */ + if (fullscreen) { +#ifdef WIN32 + if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { + throw "Couldn't set requested screen mode."; + } +#endif /* WIN32 */ +#ifdef __linux__ + XF86VidModeSwitchToMode(this->dpy, this->screen, modes[bestMode]); + XF86VidModeSetViewPort(this->dpy, this->screen, 0, 0); + dpyWidth = modes[bestMode]->hdisplay; + dpyHeight = modes[bestMode]->vdisplay; + XFree(modes); +#endif /* __linux__ */ + } + + /* create the window */ +#ifdef WIN32 + if (fullscreen) { + dwExStyle = WS_EX_APPWINDOW; + dwStyle = WS_POPUP; + ShowCursor(FALSE); + } else { + dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + dwStyle = WS_OVERLAPPEDWINDOW; + } + + AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); + + if (!(hWnd = CreateWindowEx(dwExStyle, + "Excess-OGL", + title, + dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + 0, 0, + WindowRect.right - WindowRect.left, + WindowRect.bottom - WindowRect.top, + NULL, + NULL, + this->hInstance, + NULL))) { + delete this; + throw "Could not change screenmode"; + } +#endif +#ifdef __linux__ + this->attr.background_pixel = 0; + + if (fullscreen) { + /* create a fullscreen window */ + this->attr.override_redirect = True; + this->attr.event_mask = KeyPressMask | ButtonPressMask | + StructureNotifyMask; + + this->win = XCreateWindow(this->dpy, RootWindow(this->dpy, vi->screen), + 0, 0, dpyWidth, dpyHeight, 0, vi->depth, InputOutput, vi->visual, + CWColormap | CWCursor | CWEventMask | CWOverrideRedirect, + &this->attr); + XWarpPointer(this->dpy, None, this->win, 0, 0, 0, 0, 0, 0); + XMapRaised(this->dpy, this->win); + XGrabKeyboard(this->dpy, this->win, True, GrabModeAsync, + GrabModeAsync, CurrentTime); + XGrabPointer(this->dpy, this->win, True, ButtonPressMask, + GrabModeAsync, GrabModeAsync, this->win, None, CurrentTime); + } else { + /* create a window in window mode*/ + this->attr.event_mask = KeyPressMask | ButtonPressMask | + StructureNotifyMask; + this->win = XCreateWindow(this->dpy, RootWindow(this->dpy, vi->screen), + 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, + CWColormap | CWBorderPixel | CWEventMask, &this->attr); + + /* only set window title and handle wm_delete_events if in windowed mode */ + wmDelete = XInternAtom(this->dpy, "WM_DELETE_WINDOW", True); + XSetWMProtocols(this->dpy, this->win, &wmDelete, 1); + XSetStandardProperties(this->dpy, this->win, title, + title, None, NULL, 0, NULL); + XMapRaised(this->dpy, this->win); + } +#endif /* __linux__ */ + +#ifdef WIN32 + static PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, + bpp, + 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, 0, 0, 0, + zbuffer, + 8, + 0, + PFD_MAIN_PLANE, + 0, + 0, 0, 0 + }; + + hDC = GetDC(hWnd); + PixelFormat = ChoosePixelFormat(hDC, &pfd); + if (PixelFormat == 0) { + throw "Could not find a usable pixelformat"; + } + SetPixelFormat(hDC, PixelFormat, &pfd); + hRC = wglCreateContext(hDC); + wglMakeCurrent(hDC, hRC); + ShowWindow(hWnd, SW_SHOW); + SetForegroundWindow(hWnd); + SetFocus(hWnd); + + SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); +#endif /* WIN32 */ +#ifdef __linux__ + /* connect the glx-context to the window */ + glXMakeCurrent(this->dpy, this->win, this->ctx); + XClearWindow(this->dpy, this->win); + XGetGeometry(this->dpy, this->win, &winDummy, &this->x, &this->y, + &this->width, &this->height, &borderDummy, &this->bpp); + if (!glXIsDirect(this->dpy, this->ctx)) { + throw "No direct rendering (hardware acceleration) available!"; + } + + nice(-7); +#endif /* __linux__ */ + + this->resize(0, 0, this->width, this->height); +} + +GLWindow::~GLWindow() +{ +#ifdef __linux__ + if (this->ctx) { + if (!glXMakeCurrent(this->dpy, None, NULL)) { + throw "Could not release drawing context."; + } + glXDestroyContext(this->dpy, this->ctx); + this->ctx = NULL; + } +#endif + + if (fullscreen) { +#ifdef __linux__ + XF86VidModeSwitchToMode(this->dpy, this->screen, &this->deskMode); + XF86VidModeSetViewPort(this->dpy, this->screen, 0, 0); +#endif +#ifdef WIN32 + ChangeDisplaySettings(NULL,0); + ShowCursor(TRUE); +#endif + } + +#ifdef __linux__ + XCloseDisplay(this->dpy); +#endif + +#ifdef WIN32 + if (hRC) { + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hRC); + hRC = NULL; + } + + if (hDC != NULL && ReleaseDC(hWnd, hDC)) hDC = NULL; + if (hWnd != NULL && DestroyWindow(hWnd)) hWnd = NULL; + UnregisterClass("Excess-OGL", hInstance); +#endif +} + +void GLWindow::flip() +{ +#ifdef WIN32 + MSG msg; + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) { + this->done = TRUE; + } else { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + SwapBuffers(this->hDC); +#endif +#ifdef __linux__ + glXSwapBuffers(this->dpy, this->win); +#endif +} + +bool GLWindow::is_done() +{ + return this->done; +} + +#ifdef WIN32 +LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) { + case WM_SYSCOMMAND: + switch (wParam) { + case SC_SCREENSAVE: + case SC_MONITORPOWER: + return 0; + } + break; + + case WM_CLOSE: + PostQuitMessage(0); + return 0; + + case WM_KEYUP: + if (wParam == VK_ESCAPE) + PostQuitMessage(0); + return 0; + + case WM_SIZE: + win->resize(0, 0, LOWORD(lParam), HIWORD(lParam)); + return 0; + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} +#endif //WIN32 diff --git a/glwindow.h b/glwindow.h new file mode 100644 index 0000000..5a3162d --- /dev/null +++ b/glwindow.h @@ -0,0 +1,55 @@ +#ifndef _GLWINDOW_H +#define _GLWINDOW_H + +#ifdef WIN32 +#include +#endif + +#ifdef __linux__ +#include +#include +#include +#endif + +#include +#include + +class GLWindow { +public: + GLWindow(const char *title, int width, int height, int bpp, bool fullscreen, int zbuffer, int visual_id); + ~GLWindow(); + void resize(int x, int y, int w, int h); + void flip(); + bool is_done(); + + friend class DemoHandler; + friend class DirectSoundAudioDriver; + +protected: +#ifdef WIN32 + HDC hDC; + HGLRC hRC; + HWND hWnd; + HINSTANCE hInstance; +#endif +#ifdef __linux__ + Display *dpy; + int screen; + Window win; + GLXContext ctx; + XSetWindowAttributes attr; + Bool fs; + XF86VidModeModeInfo deskMode; +#endif + + char *title; + bool fullscreen; + int x, y; + unsigned int width, height; + unsigned int bpp; + int zbuffer; + bool done; + void initGL(); +}; + +#endif diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..3e197d0 --- /dev/null +++ b/main.cpp @@ -0,0 +1,267 @@ +#include +#include +#include +#include +#include +#include +#include +#include "glwindow.h" + +struct point { + double x, y; + double px, py; + double ax, ay; +}; +struct measurement { + int p1, p2; + double d; + double stress; + double alpha; +}; +struct angle { + int p1, p2, p3; + double rad; + double stress; + double alpha; +}; +std::vector points; +std::vector measurements; +std::vector angles; + +void reload() +{ + FILE *file = fopen("spec.txt", "r"); + unsigned num_points; + fscanf(file, "%u", &num_points); + + if (num_points < points.size()) { + points.erase(points.begin() + num_points, points.end()); + } else if (num_points > points.size()) { + for (int i = points.size(); i < num_points; ++i) { + point p; + if (i == 0) { + p.x = p.y = 0.0; + } else { + p.x = rand() / (RAND_MAX + 1.0); + p.y = rand() / (RAND_MAX + 1.0); + } + if (i == 1) { + p.y = 0.0; + } + p.px = p.x; + p.py = p.y; + points.push_back(p); + } + } + + measurements.erase(measurements.begin(), measurements.end()); + angles.erase(angles.begin(), angles.end()); + + for ( ;; ) { + char buf[256]; + if (fscanf(file, "%s", &buf) != 1) + break; + + if (buf[0] == 'd') { + measurement l; + if (fscanf(file, "%u %u %lf %lf", &l.p1, &l.p2, &l.d, &l.alpha) != 4) + break; + measurements.push_back(l); + } + if (buf[0] == 'a') { + angle a; + if (fscanf(file, "%u %u %u %lf %lf", &a.p1, &a.p2, &a.p3, &a.rad, &a.alpha) != 5) + break; + a.rad *= M_PI / 180.0; + angles.push_back(a); + } + } + + fclose(file); +} + +void recalc() +{ + double dt = 1.0/60.0; + double k = 0.01; + double k_angle = 0.02; + double f = 0.02 * dt; + + for (unsigned i = 0; i < points.size(); ++i) { + points[i].ax = points[i].ay = 0.0; + } + + for (unsigned i = 0; i < measurements.size(); ++i) { + double dx = points[measurements[i].p2].x - points[measurements[i].p1].x; + double dy = points[measurements[i].p2].y - points[measurements[i].p1].y; + double d = sqrt(dx*dx + dy*dy); + measurements[i].stress = fabs(d - measurements[i].d); + + points[measurements[i].p1].ax += (d - measurements[i].d) * dx/d * k; + points[measurements[i].p1].ay += (d - measurements[i].d) * dy/d * k; + points[measurements[i].p2].ax -= (d - measurements[i].d) * dx/d * k; + points[measurements[i].p2].ay -= (d - measurements[i].d) * dy/d * k; + } + + for (unsigned i = 0; i < angles.size(); ++i) { + double cx = points[angles[i].p1].x - points[angles[i].p2].x; + double cy = points[angles[i].p1].y - points[angles[i].p2].y; + double c = sqrt(cx*cx + cy*cy); + + double bx = points[angles[i].p3].x - points[angles[i].p2].x; + double by = points[angles[i].p3].y - points[angles[i].p2].y; + double b = sqrt(bx*bx + by*by); + + double alpha = acos((bx*cx + by*cy) / (b*c)); + angles[i].stress = fabs(alpha - angles[i].rad); + + double tp3x = -by / b; + double tp3y = bx / b; + + double tp1x = cy / c; + double tp1y = -cx / c; + + points[angles[i].p1].ax -= (alpha - angles[i].rad) * tp1x * k_angle; + points[angles[i].p1].ay -= (alpha - angles[i].rad) * tp1y * k_angle; + points[angles[i].p3].ax -= (alpha - angles[i].rad) * tp3x * k_angle; + points[angles[i].p3].ay -= (alpha - angles[i].rad) * tp3y * k_angle; + } + + // constraints + if (points.size() >= 1) { + points[0].ax = points[0].ay = 0.0; + } + if (points.size() >= 2) { + points[1].ay = 0.0; + } + + // Verlet integration + for (unsigned i = 0; i < points.size(); ++i) { + double nx = (2.0 - f) * points[i].x - (1.0 - f) * points[i].px + points[i].ax * dt * dt; + double ny = (2.0 - f) * points[i].y - (1.0 - f) * points[i].py + points[i].ay * dt * dt; + points[i].px = points[i].x; + points[i].py = points[i].y; + points[i].x = nx; + points[i].y = ny; + } + + if (points.size() >= 2) { + if (points[1].x < 0.0) { + points[1].x = -points[1].x; + points[1].px = -points[1].px; + points[1].ax = -points[1].ax; + } + } +} + +void redraw(GLWindow &win) +{ + glClear(GL_COLOR_BUFFER_BIT); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //glEnable(GL_LINE_SMOOTH); + //glLineWidth(5.0); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-1.0, 1.0, -1.0, 1.0, 0.0, 1.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glScalef(0.1, 0.1, 0.1); + + glPointSize(5.0); + glColor4f(1.0, 1.0, 1.0, 1.0); + + glBegin(GL_POINTS); + for (int i = 0; i < points.size(); ++i) { + glVertex2f(points[i].x, points[i].y); + } + glEnd(); + + glBegin(GL_LINES); + for (int i = 0; i < measurements.size(); ++i) { + double sfac = std::min(5.0 * (fabs(measurements[i].stress) / measurements[i].d), 1.0); + double r, g, b; + if (sfac < 0.5) { + r = 2.0 * sfac; + g = 1.0; + b = 0.0; + } else { + r = 1.0; + g = 1.0 - 2.0 * (sfac - 0.5); + b = 0.0; + } + + glColor4f(r, g, b, measurements[i].alpha); + glVertex2f(points[measurements[i].p1].x, points[measurements[i].p1].y); + glVertex2f(points[measurements[i].p2].x, points[measurements[i].p2].y); + } + glEnd(); + + win.flip(); +} + +void randomize(double Z) +{ + for (int i = 2; i < points.size(); ++i) { + points[i].x += Z * (rand() / (RAND_MAX + 1.0) - .5); + points[i].y += Z * (rand() / (RAND_MAX + 1.0) - .5); + } +} + +void destress() +{ + double max_stress = 0.0; + int p1, p2; + + for (int i = 0; i < measurements.size(); ++i) { + if (measurements[i].p1 <= 1 || + measurements[i].p2 <= 1) + continue; + + if (measurements[i].stress > max_stress) { + max_stress = measurements[i].stress; + p1 = measurements[i].p1; + p2 = measurements[i].p2; + } + } + + std::swap(points[p1], points[p2]); +} + +int main(void) +{ + GLWindow glw("foo", 640, 480, 32, false, 16, -1); + int one = 1; + + srand((time_t)time(NULL)); + + ioctl(0, FIONBIO, &one); + reload(); + + for ( ;; ) { + char ch; + while (read(0, &ch, 1) == 1) { + if (ch == 'r') { + reload(); + } + if (ch == 'z') { + randomize(0.005); + } + if (ch == 'Z') { + randomize(0.1); + } + if (ch == 's') { + destress(); + } + } + recalc(); + recalc(); + recalc(); + recalc(); + recalc(); + redraw(glw); + } +} diff --git a/spec.txt b/spec.txt new file mode 100644 index 0000000..e6e7483 --- /dev/null +++ b/spec.txt @@ -0,0 +1,19 @@ +8 +d 0 1 2.1 1.0 +d 1 2 4.4 1.0 +d 2 3 3.1 1.0 +d 3 4 4.5 1.0 +d 4 5 2.2 1.0 +d 5 6 10.0 1.0 +d 6 7 2.2 1.0 +d 7 0 10.0 1.0 +d 0 2 5.5 0.5 +d 2 7 5.5 0.5 +d 3 5 5.5 0.5 +d 3 6 5.0 0.5 +d 3 7 5.7 0.5 +d 1 4 6.0 0.1 +d 0 5 10.0 0.1 +d 0 4 8.0 0.1 +d 1 5 8.0 0.1 +d 0 6 11.0 0.1 -- 2.39.2