diff --git a/bazaar/GLCanvas/GLCanvas.cpp b/bazaar/GLCanvas/GLCanvas.cpp new file mode 100644 index 000000000..0a579d62d --- /dev/null +++ b/bazaar/GLCanvas/GLCanvas.cpp @@ -0,0 +1,93 @@ +#include + +using namespace Upp; + + +GLCanvas::GLCanvas() { + WantFocus(); + + trackBall.Init(this); + + SetCamera(); +} + +Image GLCanvas::MouseEvent(int event, Point p, int zdelta, dword keyflags) { + Image img = trackBall.MouseEvent(event, p, zdelta, keyflags); + Refresh(); + return img; +} + +void GLCanvas::SetUpLighting() { + float light1_ambient[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + float light1_diffuse[4] = { 1.0f, 0.9f, 0.9f, 1.0f }; + float light1_specular[4] = { 1.0f, 0.7f, 0.7f, 1.0f }; + float light1_position[4] = { -1.0, 1.0, 1.0, 0.0f }; + glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient); + glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse); + glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular); + glLightfv(GL_LIGHT1, GL_POSITION, light1_position); + glEnable(GL_LIGHT1); + + float light2_ambient[4] = { 0.2f, 0.2f, 0.2f, 1.0f }; + float light2_diffuse[4] = { 0.9f, 0.9f, 0.9f, 1.0f }; + float light2_specular[4] = { 0.7f, 0.7f, 0.7f, 1.0f }; + float light2_position[4] = { 1.0, -1.0, -1.0, 0.0f }; + glLightfv(GL_LIGHT2, GL_AMBIENT, light2_ambient); + glLightfv(GL_LIGHT2, GL_DIFFUSE, light2_diffuse); + glLightfv(GL_LIGHT2, GL_SPECULAR, light2_specular); + glLightfv(GL_LIGHT2, GL_POSITION, light2_position); + //glEnable(GL_LIGHT2); + + float front_emission[4] = { 0.3f, 0.2f, 0.1f, 0.0f }; + float front_ambient[4] = { 0.2f, 0.2f, 0.2f, 0.0f }; + float front_diffuse[4] = { 0.95f, 0.95f, 0.8f, 0.0f }; + float front_specular[4] = { 0.6f, 0.6f, 0.6f, 0.0f }; + glMaterialfv(GL_FRONT, GL_EMISSION, front_emission); + glMaterialfv(GL_FRONT, GL_AMBIENT, front_ambient); + glMaterialfv(GL_FRONT, GL_DIFFUSE, front_diffuse); + glMaterialfv(GL_FRONT, GL_SPECULAR, front_specular); + glMaterialf(GL_FRONT, GL_SHININESS, 16.0); + glColor4fv(front_diffuse); + + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); + glEnable(GL_CULL_FACE); + glColorMaterial(GL_FRONT, GL_DIFFUSE); + glEnable(GL_COLOR_MATERIAL); + + glEnable(GL_LIGHTING); + glShadeModel(GL_SMOOTH); +} + +void GLCanvas::SetCamera(void) { + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + gluPerspective(trackBall.GetZoomFactor(), (float)GetSize().cx / (float)GetSize().cy, 1, 10000); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(0.0, 0.0, (float)GetSize().cy/2., 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); +} + +void GLCanvas::Layout() { + GLCtrl::Layout(); + glMatrixMode (GL_MODELVIEW); + glViewport (0, 0, GetSize().cx, GetSize().cy); + glLoadIdentity(); + SetCamera(); + trackBall.Reshape(GetSize().cx, GetSize().cy); +} + +void GLCanvas::GLPaint() { + glClearColor(1, 1, 1, 0); + glClearDepth(0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + SetCamera(); + glTranslatef(0, 0, 0); + trackBall.Matrix(); + + glPushMatrix(); + glDisable(GL_BLEND); + SetUpLighting(); + WhenPaint(); + glPopMatrix(); +} \ No newline at end of file diff --git a/bazaar/GLCanvas/GLCanvas.h b/bazaar/GLCanvas/GLCanvas.h new file mode 100644 index 000000000..ec69c1f67 --- /dev/null +++ b/bazaar/GLCanvas/GLCanvas.h @@ -0,0 +1,89 @@ +#ifndef _GLCanvas_GLCanvas_h_ +#define _GLCanvas_GLCanvas_h_ + +#include +#include "trackball.h" +#include "surface.h" + +class GLCanvas : public GLCtrl { +public: + typedef GLCanvas CLASSNAME; + + GLCanvas(); + +private: + TrackBall trackBall; + + void SetUpLighting(); + void SetCamera(); + +protected: + virtual void Layout(); + virtual Image MouseEvent(int event, Point p, int zdelta, dword keyflags); + +public: + void PaintLine(double x0, double y0, double z0, double x1, double y1, double z1, Color color) { + glBegin(GL_LINES); + glColor4d(color.GetR()/255., color.GetG()/255., color.GetB()/255., 1); + glVertex3d(x0, y0, z0); + glVertex3d(x1, y1, z1); // + glEnd(); + } + + void PaintAxis(double x, double y, double z) { + PaintLine(0, 0, 0, x, 0, 0, LtRed()); + PaintLine(0, 0, 0, 0, y, 0, LtGreen()); + PaintLine(0, 0, 0, 0, 0, z, LtBlue()); + } + + void PaintSurface(Surface &surf, Color linCol = LtGreen()) { + PaintSurface0(surf, linCol, false, false); + if (surf.x0z) + PaintSurface0(surf, linCol, false, true); + if (surf.y0z) + PaintSurface0(surf, linCol, true, false); + } + + void SetZoomFactor(double factor) {trackBall.SetZoomFactor(factor);} + + Function WhenPaint; + + virtual void GLPaint(); + +private: + void PaintSurface0(Surface &surf, Color linCol, bool simX, bool simY) { + double xsig = simX ? -1 : 1; + double ysig = simY ? -1 : 1; + + for (int ip = 0; ip < surf.panels.GetCount(); ++ip) { + Panel &panel = surf.panels[ip]; + Point3D &p0 = surf.nodes[panel.id0]; + Point3D &p1 = surf.nodes[panel.id1]; + Point3D &p2 = surf.nodes[panel.id2]; + Point3D &p3 = surf.nodes[panel.id3]; + + /*glBegin(GL_QUADS); + glColor4d(1.0, 0.5, 0.0, 1); + if (!sim) { + glVertex3d(p0.x, p0.y*ysig, p0.z); + glVertex3d(p1.x, p1.y*ysig, p1.z); + glVertex3d(p2.x, p2.y*ysig, p2.z); + glVertex3d(p3.x, p3.y*ysig, p3.z); + } else { + glVertex3d(p3.x, p3.y*ysig, p3.z); + glVertex3d(p2.x, p2.y*ysig, p2.z); + glVertex3d(p1.x, p1.y*ysig, p1.z); + glVertex3d(p0.x, p0.y*ysig, p0.z); + } + glEnd();*/ + + PaintLine(p0.x*xsig, p0.y*ysig, p0.z, p1.x*xsig, p1.y*ysig, p1.z, linCol); + PaintLine(p1.x*xsig, p1.y*ysig, p1.z, p2.x*xsig, p2.y*ysig, p2.z, linCol); + PaintLine(p2.x*xsig, p2.y*ysig, p2.z, p3.x*xsig, p3.y*ysig, p3.z, linCol); + PaintLine(p3.x*xsig, p3.y*ysig, p3.z, p0.x*xsig, p0.y*ysig, p0.z, linCol); + } + } +}; + + +#endif diff --git a/bazaar/GLCanvas/GLCanvas.upp b/bazaar/GLCanvas/GLCanvas.upp new file mode 100644 index 000000000..18e49ccd0 --- /dev/null +++ b/bazaar/GLCanvas/GLCanvas.upp @@ -0,0 +1,15 @@ +description "A basic canvas for OpenGL drawings\377B255,170,0"; + +uses + GLCtrl; + +file + GLCanvas.cpp, + GLCanvas.h, + surface.h, + trackball.cpp, + trackball.h, + trkball.c, + trkball.h; + + spellcheck_comments "EN-GB" \ No newline at end of file diff --git a/bazaar/GLCanvas/surface.h b/bazaar/GLCanvas/surface.h new file mode 100644 index 000000000..52bd53f73 --- /dev/null +++ b/bazaar/GLCanvas/surface.h @@ -0,0 +1,93 @@ +#ifndef _GLCanvas_surface_h_ +#define _GLCanvas_surface_h_ + +class Panel : public Moveable { +public: + int id0, id1, id2, id3; + + String ToString() const { return FormatInt(id0) + "," + FormatInt(id1) + "," + FormatInt(id2) + "," + FormatInt(id3); } +}; + +class Point3D : public Moveable { +public: + double x, y, z; + + String ToString() const { return FormatDouble(x) + "," + FormatDouble(y) + "," + FormatDouble(z); } +}; + + +template +inline T const& maxNotNull(T const& a, T const& b) { + if (IsNull(a)) + return b; + else if (IsNull(b)) + return a; + else + return a > b ? a : b; +} + +template +inline T const& minNotNull(T const& a, T const& b) { + if (IsNull(a)) + return b; + else if (IsNull(b)) + return a; + else + return a < b ? a : b; +} + + +class VolumeEnvelope { +public: + VolumeEnvelope() {Reset();} + void Reset() { + maxX = minX = maxY = minY = maxZ = minZ = Null; + } + + void MixEnvelope(VolumeEnvelope &env) { + maxX = maxNotNull(env.maxX, maxX); + minX = minNotNull(env.minX, minX); + maxY = maxNotNull(env.maxY, maxY); + minY = minNotNull(env.minY, minY); + maxZ = maxNotNull(env.maxZ, maxZ); + minZ = minNotNull(env.minZ, minZ); + } + + double maxX, minX, maxY, minY, maxZ, minZ; +}; + +class Surface { +public: + Surface() : x0z(false), y0z(false) {} + Vector nodes; + Vector panels; + bool x0z, y0z; + String file; + VolumeEnvelope env; + + bool Check() { + for (int i = 0; i < panels.GetCount(); ++i) + if (!panels[i].id0 || !panels[i].id1 || !panels[i].id2 || !panels[i].id3) + return false; + return true; + } + void GetLimits() { + env.maxX = env.maxY = env.maxZ = -DBL_MAX; + env.minX = env.minY = env.minZ = DBL_MAX; + for (int i = 0; i < nodes.GetCount(); ++i) { + env.maxX = max(env.maxX, nodes[i].x); + env.minX = min(env.minX, nodes[i].x); + env.maxY = max(env.maxY, nodes[i].y); + env.minY = min(env.minY, nodes[i].y); + env.maxZ = max(env.maxZ, nodes[i].z); + env.minZ = min(env.minZ, nodes[i].z); + } + } + String GetLastError() {return lastError;} + String lastError; + +private: + inline bool CheckId(int id) {return id >= 0 && id < nodes.GetCount()-1;} +}; + +#endif diff --git a/bazaar/GLCanvas/trackball.cpp b/bazaar/GLCanvas/trackball.cpp new file mode 100644 index 000000000..c95039d48 --- /dev/null +++ b/bazaar/GLCanvas/trackball.cpp @@ -0,0 +1,63 @@ +#include "TrackBall.h" +#include "trkball.h" + +#ifdef PLATFORM_POSIX +#include +#elif defined(WIN32) +#include +#endif + +TrackBall::TrackBall() { + owner = NULL; + buttonRot = Ctrl::LEFT; + tracking = false; + zoomFactor = 10; + //trackball(curquat, 0, -.5, -1, 1); + curquat[0] = 0.15f; curquat[1] = 0.35f; curquat[2] = 0.85f; curquat[3] = 0.35f; +} + +void TrackBall::Init(Ctrl *ow) { + owner = ow; +} + +void TrackBall::Matrix() { + GLfloat m[4][4]; + + build_rotmatrix(m, curquat); + glMultMatrixf(&m[0][0]); +} + +void TrackBall::Reshape(int w, int h) { + width = w; + height = h; +} + +Image TrackBall::MouseEvent(int event, Point p, int zdelta, dword keyflags) { + if ((event & Ctrl::ACTION) == Ctrl::MOUSEWHEEL) { + zoomFactor = min(180., zoomFactor * (1 - zdelta/1000.)); + owner->Refresh(); + } else if ((event & Ctrl::BUTTON) == buttonRot && (event & Ctrl::ACTION) == Ctrl::DOWN) { + tracking = true; + beginx = p.x; + beginy = p.y; + } else { + if ((event & Ctrl::BUTTON) == buttonRot && (event & Ctrl::ACTION) == Ctrl::UP) + tracking = false; + else if((event & Ctrl::ACTION) == Ctrl::MOUSEMOVE) { + if (tracking) { + trackball( + lastquat, + float((2.0 * beginx - width) / width), + float((height - 2.0 * beginy) / height), + float((2.0 * p.x - width) / width), + float((height - 2.0 * p.y) / height) + ); + beginx = p.x; + beginy = p.y; + add_quats(lastquat, curquat, curquat); + owner->Refresh(); + } + } + } + return Image::Hand(); +} diff --git a/bazaar/GLCanvas/trackball.h b/bazaar/GLCanvas/trackball.h new file mode 100644 index 000000000..0e684d092 --- /dev/null +++ b/bazaar/GLCanvas/trackball.h @@ -0,0 +1,41 @@ +#ifndef _FTGL_Demo_TrackBall_h_ +#define _FTGL_Demo_TrackBall_h_ + +#include + +using namespace Upp; + +class TrackBall { +public: + typedef TrackBall CLASSNAME; + + TrackBall(); + void Init(Ctrl *owner); + + void Matrix(void); + void Reshape(int width, int height); + void SetZoomFactor(double factor) {factor = zoomFactor;} + double GetZoomFactor() {return zoomFactor;} + void SetButtonRot(int but = Ctrl::LEFT) {buttonRot = but; } + + + virtual Image MouseEvent(int event, Point p, int zdelta, dword keyflags); + + float curquat[4]; + +private: + Ctrl *owner; + +// float curquat[4]; + float lastquat[4]; + int beginx, beginy; + + int width, height; + + int buttonRot; + bool tracking; + + double zoomFactor; +}; + +#endif diff --git a/bazaar/GLCanvas/trkball.c b/bazaar/GLCanvas/trkball.c new file mode 100644 index 000000000..04346d431 --- /dev/null +++ b/bazaar/GLCanvas/trkball.c @@ -0,0 +1,326 @@ +/* + * (c) Copyright 1993, 1994, Silicon Graphics, Inc. + * ALL RIGHTS RESERVED + * Permission to use, copy, modify, and distribute this software for + * any purpose and without fee is hereby granted, provided that the above + * copyright notice appear in all copies and that both the copyright notice + * and this permission notice appear in supporting documentation, and that + * the name of Silicon Graphics, Inc. not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" + * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON + * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, + * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY + * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, + * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF + * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN + * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE + * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer Software + * clause at DFARS 252.227-7013 and/or in similar or successor + * clauses in the FAR or the DOD or NASA FAR Supplement. + * Unpublished-- rights reserved under the copyright laws of the + * United States. Contractor/manufacturer is Silicon Graphics, + * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ + +/* + * Trackball code: + * + * Implementation of a virtual trackball. + * Implemented by Gavin Bell, lots of ideas from Thant Tessman and + * the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129. + * + * Vector manip code: + * + * Original code from: + * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli + * + * Much mucking with by: + * Gavin Bell + */ + +#include +#include "trkball.h" + +/* + * This size should really be based on the distance from the center of + * rotation to the point on the object underneath the mouse. That + * point would then track the mouse as closely as possible. This is a + * simple example, though, so that is left as an Exercise for the + * Programmer. + */ +#define TRACKBALLSIZE (0.4f) + +/* + * Local function prototypes (not defined in trackball.h) + */ +static float tb_project_to_sphere(float, float, float); +static void normalize_quat(float [4]); + +static void +vzero(float *v) +{ + v[0] = 0.0; + v[1] = 0.0; + v[2] = 0.0; +} + +static void +vset(float *v, float x, float y, float z) +{ + v[0] = x; + v[1] = y; + v[2] = z; +} + +static void +vsub(const float *src1, const float *src2, float *dst) +{ + dst[0] = src1[0] - src2[0]; + dst[1] = src1[1] - src2[1]; + dst[2] = src1[2] - src2[2]; +} + +static void +vcopy(const float *v1, float *v2) +{ + register int i; + for (i = 0 ; i < 3 ; i++) + v2[i] = v1[i]; +} + +static void +vcross(const float *v1, const float *v2, float *cross) +{ + float temp[3]; + + temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]); + temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]); + temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]); + vcopy(temp, cross); +} + +static float +vlength(const float *v) +{ + return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); +} + +static void +vscale(float *v, float div) +{ + v[0] *= div; + v[1] *= div; + v[2] *= div; +} + +static void +vnormal(float *v) +{ + vscale(v,1.0f/vlength(v)); +} + +static float +vdot(const float *v1, const float *v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +static void +vadd(const float *src1, const float *src2, float *dst) +{ + dst[0] = src1[0] + src2[0]; + dst[1] = src1[1] + src2[1]; + dst[2] = src1[2] + src2[2]; +} + +/* + * Ok, simulate a track-ball. Project the points onto the virtual + * trackball, then figure out the axis of rotation, which is the cross + * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0) + * Note: This is a deformed trackball-- is a trackball in the center, + * but is deformed into a hyperbolic sheet of rotation away from the + * center. This particular function was chosen after trying out + * several variations. + * + * It is assumed that the arguments to this routine are in the range + * (-1.0 ... 1.0) + */ +void +trackball(float q[4], float p1x, float p1y, float p2x, float p2y) +{ + float a[3]; /* Axis of rotation */ + float phi; /* how much to rotate about axis */ + float p1[3], p2[3], d[3]; + float t; + + if (p1x == p2x && p1y == p2y) { + /* Zero rotation */ + vzero(q); + q[3] = 1.0; + return; + } + + /* + * First, figure out z-coordinates for projection of P1 and P2 to + * deformed sphere + */ + vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y)); + vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y)); + + /* + * Now, we want the cross product of P1 and P2 + */ + vcross(p2,p1,a); + + /* + * Figure out how much to rotate around that axis. + */ + vsub(p1,p2,d); + t = vlength(d) / (2.0f*TRACKBALLSIZE); + + /* + * Avoid problems with out-of-control values... + */ + if (t > 1.0f) t = 1.0f; + if (t < -1.0f) t = -1.0f; + phi = 2.0f * asin(t); + + axis_to_quat(a,phi,q); +} + +/* + * Given an axis and angle, compute quaternion. + */ +void +axis_to_quat(float a[3], float phi, float q[4]) +{ + vnormal(a); + vcopy(a,q); + vscale(q,sin(phi/2.0f)); + q[3] = cos(phi/2.0f); +} + +/* + * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet + * if we are away from the center of the sphere. + */ +static float +tb_project_to_sphere(float r, float x, float y) +{ + float d, t, z; + + d = sqrt(x*x + y*y); + if (d < r * 0.70710678118654752440f) { /* Inside sphere */ + z = sqrt(r*r - d*d); + } else { /* On hyperbola */ + t = r / 1.41421356237309504880f; + z = t*t / d; + } + return z; +} + +/* + * Given two rotations, e1 and e2, expressed as quaternion rotations, + * figure out the equivalent single rotation and stuff it into dest. + * + * This routine also normalizes the result every RENORMCOUNT times it is + * called, to keep error from creeping in. + * + * NOTE: This routine is written so that q1 or q2 may be the same + * as dest (or each other). + */ + +#define RENORMCOUNT 97 + +void +add_quats(float q1[4], float q2[4], float dest[4]) +{ + static int count=0; + float t1[4], t2[4], t3[4]; + float tf[4]; + + vcopy(q1,t1); + vscale(t1,q2[3]); + + vcopy(q2,t2); + vscale(t2,q1[3]); + + vcross(q2,q1,t3); + vadd(t1,t2,tf); + vadd(t3,tf,tf); + tf[3] = q1[3] * q2[3] - vdot(q1,q2); + + dest[0] = tf[0]; + dest[1] = tf[1]; + dest[2] = tf[2]; + dest[3] = tf[3]; + + if (++count > RENORMCOUNT) { + count = 0; + normalize_quat(dest); + } +} + +/* + * Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0 + * If they don't add up to 1.0, dividing by their magnitued will + * renormalize them. + * + * Note: See the following for more information on quaternions: + * + * - Shoemake, K., Animating rotation with quaternion curves, Computer + * Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985. + * - Pletinckx, D., Quaternion calculus as a basic tool in computer + * graphics, The Visual Computer 5, 2-13, 1989. + */ +static void +normalize_quat(float q[4]) +{ + int i; + float mag; + + mag = (q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]); + for (i = 0; i < 4; i++) q[i] /= mag; +} + +/* + * Build a rotation matrix, given a quaternion rotation. + * + */ +void +build_rotmatrix(float m[4][4], float q[4]) +{ + m[0][0] = 1.0f - 2.0f * (q[1] * q[1] + q[2] * q[2]); + m[0][1] = 2.0f * (q[0] * q[1] - q[2] * q[3]); + m[0][2] = 2.0f * (q[2] * q[0] + q[1] * q[3]); + m[0][3] = 0.0f; + + m[1][0] = 2.0f * (q[0] * q[1] + q[2] * q[3]); + m[1][1]= 1.0f - 2.0f * (q[2] * q[2] + q[0] * q[0]); + m[1][2] = 2.0f * (q[1] * q[2] - q[0] * q[3]); + m[1][3] = 0.0f; + + m[2][0] = 2.0f * (q[2] * q[0] - q[1] * q[3]); + m[2][1] = 2.0f * (q[1] * q[2] + q[0] * q[3]); + m[2][2] = 1.0f - 2.0f * (q[1] * q[1] + q[0] * q[0]); + m[2][3] = 0.0f; + + m[3][0] = 0.0f; + m[3][1] = 0.0f; + m[3][2] = 0.0f; + m[3][3] = 1.0f; +} + diff --git a/bazaar/GLCanvas/trkball.h b/bazaar/GLCanvas/trkball.h new file mode 100644 index 000000000..c010b78e1 --- /dev/null +++ b/bazaar/GLCanvas/trkball.h @@ -0,0 +1,85 @@ +/* + * (c) Copyright 1993, 1994, Silicon Graphics, Inc. + * ALL RIGHTS RESERVED + * Permission to use, copy, modify, and distribute this software for + * any purpose and without fee is hereby granted, provided that the above + * copyright notice appear in all copies and that both the copyright notice + * and this permission notice appear in supporting documentation, and that + * the name of Silicon Graphics, Inc. not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" + * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON + * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, + * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY + * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, + * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF + * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN + * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE + * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer Software + * clause at DFARS 252.227-7013 and/or in similar or successor + * clauses in the FAR or the DOD or NASA FAR Supplement. + * Unpublished-- rights reserved under the copyright laws of the + * United States. Contractor/manufacturer is Silicon Graphics, + * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ +/* + * trackball.h + * A virtual trackball implementation + * Written by Gavin Bell for Silicon Graphics, November 1988. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Pass the x and y coordinates of the last and current positions of + * the mouse, scaled so they are from (-1.0 ... 1.0). + * + * The resulting rotation is returned as a quaternion rotation in the + * first paramater. + */ +void +trackball(float q[4], float p1x, float p1y, float p2x, float p2y); + +/* + * Given two quaternions, add them together to get a third quaternion. + * Adding quaternions to get a compound rotation is analagous to adding + * translations to get a compound translation. When incrementally + * adding rotations, the first argument here should be the new + * rotation, the second and third the total rotation (which will be + * over-written with the resulting new total rotation). + */ +void +add_quats(float *q1, float *q2, float *dest); + +/* + * A useful function, builds a rotation matrix in Matrix based on + * given quaternion. + */ +void +build_rotmatrix(float m[4][4], float q[4]); + +/* + * This function computes a quaternion based on an axis (defined by + * the given vector) and an angle about which to rotate. The angle is + * expressed in radians. The result is put into the third argument. + */ +void +axis_to_quat(float a[3], float phi, float q[4]); + +#ifdef __cplusplus +} +#endif