--- /dev/null
+/*
+ * The whole interface between GLWindow and the configuration stuff is rather
+ * icky, and _should_ be rewritten. It appears to work somehow, though ;-)
+ */
+
+#include <stdio.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#ifdef __linux__
+#include <unistd.h>
+#include <GL/glx.h>
+#include <X11/extensions/xf86vmode.h>
+#include <X11/keysym.h>
+#endif
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+
+#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
--- /dev/null
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <vector>
+#include <algorithm>
+#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<point> points;
+std::vector<measurement> measurements;
+std::vector<angle> 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);
+ }
+}