diff options
author | Ian Romanick <ian.d.romanick@intel.com> | 2010-01-12 15:03:09 -0800 |
---|---|---|
committer | Ian Romanick <ian.d.romanick@intel.com> | 2010-01-12 15:03:09 -0800 |
commit | b4357ac128da7d42a5e7052864fc94d1c74d65ff (patch) | |
tree | 79e5fb86415c7ba4438555a035e63d43bd793c3d | |
parent | a2357a6c2419437ec74146a750b37e43a4e85327 (diff) |
Add gluArcball structure and support functions
This adds basic code to implement the class arcball user interface control.
-rw-r--r-- | include/glu3.h | 65 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/arcball.c | 148 |
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); +} |