Start to add OpenGL support to SolveSpace, for the graphical view.

I've got the user interface to pan and rotate an object, more or
less works.

[git-p4: depot-paths = "//depot/solvespace/": change = 1654]
This commit is contained in:
Jonathan Westhues 2008-03-27 01:53:51 -08:00
parent fcdf43d487
commit e426fe8a53
8 changed files with 319 additions and 10 deletions

View File

@ -12,9 +12,10 @@ W32OBJS = $(OBJDIR)\w32main.obj \
SSOBJS = $(OBJDIR)\solvespace.obj \
$(OBJDIR)\cmdline.obj \
$(OBJDIR)\graphicswin.obj \
$(OBJDIR)\util.obj \
LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib
LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib opengl32.lib glu32.lib
all: $(OBJDIR)/solvespace.exe
@cp $(OBJDIR)/solvespace.exe .

15
dsc.h
View File

@ -5,10 +5,23 @@
typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef struct {
typedef struct VectorTag Vector;
typedef struct VectorTag {
double x, y, z;
Vector Cross(Vector b);
double Vector::Dot(Vector b);
Vector RotatedAbout(Vector axis, double theta);
double Magnitude(void);
Vector ScaledBy(double v);
} Vector;
typedef struct {
double x, y;
} Point2d;
template <class T, class H> struct IdList {
typedef struct {
T v;

View File

@ -1,5 +1,9 @@
#include "solvespace.h"
#include <stdarg.h>
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include "solvespace.h"
const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 0, "&File", 0, NULL },
@ -33,3 +37,99 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ -1 },
};
void GraphicsWindow::Init(void) {
offset.x = offset.y = offset.z = 0.9;
scale = 1;
projRight.x = 1; projRight.y = projRight.z = 0;
projDown.y = 1; projDown.z = projDown.x = 0;
}
void GraphicsWindow::NormalizeProjectionVectors(void) {
Vector norm = projRight.Cross(projDown);
projDown = norm.Cross(projRight);
projDown = projDown.ScaledBy(1/projDown.Magnitude());
projRight = projRight.ScaledBy(1/projRight.Magnitude());
}
void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
bool middleDown, bool rightDown, bool shiftDown, bool ctrlDown)
{
if(middleDown) {
double dx = (x - orig.mouse.x) / scale;
double dy = (y - orig.mouse.y) / scale;
if(shiftDown) {
offset.x = orig.offset.x + dx*projRight.x + dy*projDown.x;
offset.y = orig.offset.y + dx*projRight.y + dy*projDown.y;
offset.z = orig.offset.z + dx*projRight.z + dy*projDown.z;
} else if(ctrlDown) {
double theta = atan2(orig.mouse.y, orig.mouse.x);
theta -= atan2(y, x);
Vector normal = orig.projRight.Cross(orig.projDown);
projRight = orig.projRight.RotatedAbout(normal, theta);
projDown = orig.projDown.RotatedAbout(normal, theta);
NormalizeProjectionVectors();
} else {
double s = 0.3*(PI/180); // degrees per pixel
projRight = orig.projRight.RotatedAbout(orig.projDown, -s*dx);
projDown = orig.projDown.RotatedAbout(orig.projRight, s*dy);
NormalizeProjectionVectors();
orig.projRight = projRight;
orig.projDown = projDown;
orig.mouse.x = x;
orig.mouse.y = y;
}
Invalidate();
}
}
void GraphicsWindow::MouseMiddleDown(double x, double y) {
orig.offset = offset;
orig.projDown = projDown;
orig.projRight = projRight;
orig.mouse.x = x;
orig.mouse.y = y;
}
void GraphicsWindow::MouseLeftDown(double x, double y) {
}
void GraphicsWindow::Paint(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScaled(scale*2.0/w, scale*2.0/h, 0);
double tx = projRight.Dot(offset);
double ty = projDown.Dot(offset);
double mat[16];
MakeMatrix(mat, projRight.x, projRight.y, projRight.z, tx,
projDown.x, projDown.y, projDown.z, ty,
0, 0, 0, 0,
0, 0, 0, 1);
glMultMatrixd(mat);
glEnable(GL_DEPTH_TEST);
glClearIndex((GLfloat)0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLUquadricObj *quadObj;
quadObj = gluNewQuadric();
gluQuadricDrawStyle(quadObj, GLU_LINE);
gluSphere(quadObj, 300, 4, 4);
}

View File

@ -4,6 +4,7 @@ SolveSpace SS;
void SolveSpace::Init(void) {
TW.Init();
GW.Init();
int i;
for(i = 0; i < 20; i++) {

View File

@ -5,6 +5,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "dsc.h"
#include "ui.h"
#include "sketch.h"
@ -13,8 +14,17 @@
#define oops() do { dbp("oops at line %d, file %s", __LINE__, __FILE__); \
exit(-1); } while(0)
void dbp(char *str, ...);
void Invalidate(void);
#define arraylen(x) (sizeof((x))/sizeof((x)[0]))
#define PI (3.1415926535897931)
void MakeMatrix(double *mat, double a11, double a12, double a13, double a14,
double a21, double a22, double a23, double a24,
double a31, double a32, double a33, double a34,
double a41, double a42, double a43, double a44);
typedef struct {
TextWindow TW;

18
ui.h
View File

@ -64,16 +64,26 @@ typedef struct {
// coordinates of the 3d sketch points. We will use an axonometric
// projection.
Vector offset;
double scale;
Vector projRight;
Vector projDown;
double scale;
struct {
Vector offset;
Vector projRight;
Vector projDown;
Point2d mouse;
} orig;
void Init(void);
void NormalizeProjectionVectors(void);
// These are called by the platform-specific code.
void Paint(void);
void Paint(int w, int h);
void MouseMoved(double x, double y, bool leftDown, bool middleDown,
bool rightDown);
void MouseLeftClick(double x, double y);
bool rightDown, bool shiftDown, bool ctrlDown);
void MouseLeftDown(double x, double y);
void MouseLeftDoubleClick(double x, double y);
void MouseMiddleDown(double x, double y);
void MouseScroll(int delta);
} GraphicsWindow;

80
util.cpp Normal file
View File

@ -0,0 +1,80 @@
#include "solvespace.h"
void MakeMatrix(double *mat, double a11, double a12, double a13, double a14,
double a21, double a22, double a23, double a24,
double a31, double a32, double a33, double a34,
double a41, double a42, double a43, double a44)
{
mat[ 0] = a11;
mat[ 1] = a21;
mat[ 2] = a31;
mat[ 3] = a41;
mat[ 4] = a12;
mat[ 5] = a22;
mat[ 6] = a32;
mat[ 7] = a42;
mat[ 8] = a13;
mat[ 9] = a23;
mat[10] = a33;
mat[11] = a43;
mat[12] = a14;
mat[13] = a24;
mat[14] = a34;
mat[15] = a44;
}
Vector Vector::Cross(Vector b)
{
Vector r;
r.x = -(z*b.y) + (y*b.z);
r.y = (z*b.x) - (x*b.z);
r.z = -(y*b.x) + (x*b.y);
return r;
}
double Vector::Dot(Vector b)
{
return (x*b.x + y*b.y + z*b.z);
}
Vector Vector::RotatedAbout(Vector axis, double theta)
{
double c = cos(theta);
double s = sin(theta);
Vector r;
r.x = (x)*(c + (1 - c)*(axis.x)*(axis.x)) +
(y)*((1 - c)*(axis.x)*(axis.y) - s*(axis.z)) +
(z)*((1 - c)*(axis.x)*(axis.z) + s*(axis.y));
r.y = (x)*((1 - c)*(axis.y)*(axis.x) + s*(axis.z)) +
(y)*(c + (1 - c)*(axis.y)*(axis.y)) +
(z)*((1 - c)*(axis.y)*(axis.z) - s*(axis.x));
r.z = (x)*((1 - c)*(axis.z)*(axis.x) - s*(axis.y)) +
(y)*((1 - c)*(axis.z)*(axis.y) + s*(axis.x)) +
(z)*(c + (1 - c)*(axis.z)*(axis.z));
return r;
}
double Vector::Magnitude(void)
{
return sqrt(x*x + y*y + z*z);
}
Vector Vector::ScaledBy(double v)
{
Vector r;
r.x = x * v;
r.y = y * v;
r.z = z * v;
return r;
}

View File

@ -1,5 +1,7 @@
#include <windows.h>
#include <commctrl.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
@ -197,6 +199,40 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
return 1;
}
static HGLRC CreateGlContext(HDC hdc)
{
PIXELFORMATDESCRIPTOR pfd;
int pixelFormat;
memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER;
pfd.dwLayerMask = PFD_MAIN_PLANE;
pfd.iPixelType = PFD_TYPE_COLORINDEX;
pfd.cColorBits = 8;
pfd.cDepthBits = 16;
pfd.cAccumBits = 0;
pfd.cStencilBits = 0;
pixelFormat = ChoosePixelFormat(hdc, &pfd);
if(!pixelFormat) oops();
if(!SetPixelFormat(hdc, pixelFormat, &pfd)) oops();
HGLRC hgrc = wglCreateContext(hdc);
wglMakeCurrent(hdc, hgrc);
return hgrc;
}
void Invalidate(void)
{
InvalidateRect(GraphicsWnd, NULL, FALSE);
InvalidateRect(TextWnd, NULL, FALSE);
}
LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
@ -208,6 +244,64 @@ LRESULT CALLBACK GraphicsWndProc(HWND hwnd, UINT msg, WPARAM wParam,
InvalidateRect(TextWnd, NULL, FALSE);
break;
case WM_ERASEBKGND:
break;
case WM_SIZE:
InvalidateRect(GraphicsWnd, NULL, FALSE);
break;
case WM_PAINT: {
InvalidateRect(GraphicsWnd, NULL, FALSE);
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HGLRC hgrc = CreateGlContext(hdc);
RECT r;
GetClientRect(GraphicsWnd, &r);
int w = r.right - r.left;
int h = r.bottom - r.top;
SS.GW.Paint(w, h);
SwapBuffers(hdc);
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hgrc);
EndPaint(hwnd, &ps);
break;
}
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN: {
int x = LOWORD(lParam);
int y = HIWORD(lParam);
RECT r;
GetClientRect(GraphicsWnd, &r);
x = x - (r.right - r.left)/2;
y = (r.bottom - r.top)/2 - y;
if(msg == WM_LBUTTONDOWN) {
SS.GW.MouseLeftDown(x, y);
} else if(msg == WM_MBUTTONDOWN) {
SS.GW.MouseMiddleDown(x, y);
} else if(msg == WM_MOUSEMOVE) {
SS.GW.MouseMoved(x, y,
!!(wParam & MK_LBUTTON),
!!(wParam & MK_MBUTTON),
!!(wParam & MK_RBUTTON),
!!(wParam & MK_SHIFT),
!!(wParam & MK_CONTROL));
} else {
oops();
}
break;
}
case WM_CLOSE:
case WM_DESTROY:
PostQuitMessage(0);
@ -260,7 +354,7 @@ static void CreateMainWindows(void)
wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_OWNDC |
CS_DBLCLKS;
wc.lpfnWndProc = (WNDPROC)GraphicsWndProc;
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszClassName = "GraphicsWnd";
wc.lpszMenuName = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
@ -271,8 +365,8 @@ static void CreateMainWindows(void)
HMENU top = CreateGraphicsWindowMenus();
GraphicsWnd = CreateWindowEx(0, "GraphicsWnd", "SolveSpace (View Sketch)",
WS_OVERLAPPED | WS_THICKFRAME | WS_CLIPCHILDREN | WS_MAXIMIZEBOX |
WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX,
600, 300, 400, 400, NULL, top, Instance, NULL);
WS_MINIMIZEBOX | WS_SYSMENU | WS_SIZEBOX | WS_CLIPSIBLINGS,
600, 300, 200, 200, NULL, top, Instance, NULL);
if(!GraphicsWnd) oops();