summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Romanick <ian.d.romanick@intel.com>2010-01-12 15:03:09 -0800
committerIan Romanick <ian.d.romanick@intel.com>2010-01-12 15:03:09 -0800
commitb4357ac128da7d42a5e7052864fc94d1c74d65ff (patch)
tree79e5fb86415c7ba4438555a035e63d43bd793c3d
parenta2357a6c2419437ec74146a750b37e43a4e85327 (diff)
Add gluArcball structure and support functions
This adds basic code to implement the class arcball user interface control.
-rw-r--r--include/glu3.h65
-rw-r--r--src/Makefile.am2
-rw-r--r--src/arcball.c148
3 files changed, 214 insertions, 1 deletions
diff --git a/include/glu3.h b/include/glu3.h
index 3d7a10b..f3cbfcf 100644
--- a/include/glu3.h
+++ b/include/glu3.h
@@ -215,10 +215,58 @@ struct GLUmat4Stack {
#endif /* __cplusplus */
};
+
+struct GLUarcball {
+ /**
+ * Base location of the viewport.
+ */
+ /*@{*/
+ unsigned viewport_x;
+ unsigned viewport_y;
+ /*@}*/
+
+ /**
+ * Dimensions of the viewport.
+ */
+ /*@{*/
+ unsigned viewport_width;
+ unsigned viewport_height;
+ /*@}*/
+
+ /**
+ * Screen X/Y location of initial mouse click.
+ */
+ /*@{*/
+ unsigned click_x;
+ unsigned click_y;
+ /*@}*/
+
+
+#ifdef __cplusplus
+ void viewport(unsigned x, unsigned y, unsigned width, unsigned height)
+ {
+ viewport_x = x;
+ viewport_y = y;
+ viewport_width = width;
+ viewport_height = height;
+ }
+
+ void click(unsigned x, unsigned y)
+ {
+ click_x = x;
+ click_y = y;
+ }
+
+ GLUmat4 drag(unsigned end_x, unsigned end_y);
+#endif /* __cplusplus */
+};
+
+
#ifndef __cplusplus
typedef struct GLUvec4 GLUvec4;
typedef struct GLUmat4 GLUmat4;
typedef struct GLUmat4Stack GLUmat4Stack;
+typedef struct GLUarcball GLUarcball;
#endif /* __cplusplus */
@@ -681,6 +729,15 @@ extern const GLchar *gluLoadTextFile(const char *file_name);
*/
extern void gluUnloadTextFile(const GLchar *text);
+extern void gluArcballViewport(GLUarcball *ball, unsigned x, unsigned y,
+ unsigned width, unsigned height);
+
+extern void gluArcballClick(GLUarcball *ball, unsigned start_x,
+ unsigned start_y);
+
+extern void gluArcballDrag(GLUarcball *ball, GLUmat4 *transformation,
+ unsigned end_x, unsigned end_y);
+
#ifdef __cplusplus
};
#endif
@@ -972,6 +1029,14 @@ inline GLUmat4 gluInverse4(const GLUmat4 &m)
return result;
}
+
+inline GLUmat4 GLUarcball::drag(unsigned end_x, unsigned end_y)
+{
+ GLUmat4 result;
+
+ gluArcballDrag(this, & result, end_x, end_y);
+ return result;
+}
#endif /* __cplusplus */
#include "glu3_scalar.h"
diff --git a/src/Makefile.am b/src/Makefile.am
index 9bd643c..6230523 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,7 +24,7 @@ AM_CXXFLAGS=-I../include
AM_CFLAGS=-I../include
lib_LIBRARIES = libGLU3.a
-libGLU3_a_SOURCES = matrix.c load_text.c
+libGLU3_a_SOURCES = matrix.c load_text.c arcball.c
libGLU3includedir = ${includedir}
libGLU3include_HEADERS = ../include/glu3.h ../include/glu3_scalar.h
diff --git a/src/arcball.c b/src/arcball.c
new file mode 100644
index 0000000..5c27d04
--- /dev/null
+++ b/src/arcball.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2009 Ian D. Romanick
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <math.h>
+#include "glu3.h"
+
+
+static void
+map_to_sphere(float x, float y, GLUvec4 *v)
+{
+ const float length_squared = (x * x) + (y * y);
+
+
+ if (length_squared > 1.0f) {
+ const float n = 1.0f / sqrt(length_squared);
+
+ v->values[0] = x * n;
+ v->values[1] = y * n;
+ v->values[2] = 0.0f;
+ } else {
+ v->values[0] = x;
+ v->values[1] = y;
+ v->values[2] = sqrt(1.0 - length_squared);
+ }
+
+ v->values[3] = 0.0;
+}
+
+
+static float
+remap_x(float w_factor, unsigned x)
+{
+ return (x * w_factor) - 1.0f;
+}
+
+
+static float
+remap_y(float h_factor, unsigned y)
+{
+ return 1.0f - (y * h_factor);
+}
+
+
+static void
+get_transformation(GLUmat4 *mat, const GLUvec4 *quat)
+{
+ const float xx = quat->values[0] * quat->values[0];
+ const float xy = quat->values[0] * quat->values[1];
+ const float xz = quat->values[0] * quat->values[2];
+ const float xw = quat->values[0] * quat->values[3];
+
+ const float yy = quat->values[1] * quat->values[1];
+ const float yz = quat->values[1] * quat->values[2];
+ const float yw = quat->values[1] * quat->values[3];
+
+ const float zz = quat->values[2] * quat->values[2];
+ const float zw = quat->values[2] * quat->values[3];
+
+
+ mat->col[0].values[0] = 1.0f - 2.0f * (yy + zz);
+ mat->col[0].values[1] = 2.0f * (xy + zw);
+ mat->col[0].values[2] = 2.0f * (xz - yw);
+ mat->col[0].values[3] = 0.0f;
+
+ mat->col[1].values[0] = 2.0f * (xy - zw);
+ mat->col[1].values[1] = 1.0f - 2.0f * (xx + zz);
+ mat->col[1].values[2] = 2.0f * (yz + xw);
+ mat->col[1].values[3] = 0.0f;
+
+ mat->col[2].values[0] = 2.0f * (xz + yw);
+ mat->col[2].values[1] = 2.0f * (yz - xw);
+ mat->col[2].values[2] = 1.0f - 2.0f * (xx + yy);
+ mat->col[2].values[3] = 0.0f;
+
+ mat->col[3].values[0] = 0.0f;
+ mat->col[3].values[1] = 0.0f;
+ mat->col[3].values[2] = 0.0f;
+ mat->col[3].values[3] = 1.0f;
+}
+
+
+void
+gluArcballClick(GLUarcball *ball, unsigned x, unsigned y)
+{
+ ball->click_x = x;
+ ball->click_y = y;
+}
+
+
+void
+gluArcballDrag(GLUarcball *ball, GLUmat4 *result, unsigned x, unsigned y)
+{
+ GLUvec4 end;
+ GLUvec4 pick;
+ GLUvec4 axis;
+ float w_factor;
+ float h_factor;
+
+
+ if ((ball->viewport_width == 0.0) || (ball->viewport_height == 0.0)) {
+ memcpy(result, & gluIdentityMatrix, sizeof(gluIdentityMatrix));
+ return;
+ }
+
+ w_factor = 2.0f / (float)(ball->viewport_width - 1);
+ h_factor = 2.0f / (float)(ball->viewport_height - 1);
+
+ map_to_sphere(remap_x(w_factor, ball->click_x - ball->viewport_x),
+ remap_y(h_factor, ball->click_y - ball->viewport_y),
+ & pick);
+ map_to_sphere(remap_x(w_factor, x - ball->viewport_x),
+ remap_y(h_factor, y - ball->viewport_y),
+ & end);
+
+
+ gluCross4v(& axis, & pick, & end);
+
+ const float length_squared = gluLengthSqr4v(& axis);
+ if (length_squared > 0.0000001) {
+ axis.values[3] = gluDot3_4v(& pick, & end);
+ } else {
+ axis.values[0] = 0.0f;
+ axis.values[1] = 0.0f;
+ axis.values[2] = 0.0f;
+ axis.values[3] = 0.0f;
+ }
+
+ get_transformation(result, & axis);
+}