1 //  ---------------------------------------------------------------------------
2 //
3 //  @file       TwSimpleGLUT.c
4 //  @brief      A simple example that uses AntTweakBar with OpenGL and GLUT.
5 //
6 //              AntTweakBar: http://anttweakbar.sourceforge.net/doc
7 //              OpenGL:      http://www.opengl.org
8 //              GLUT:        http://opengl.org/resources/libraries/glut
9 //
10 //  @author     Philippe Decaudin
11 //  @date       2006/05/20
12 //
13 //  ---------------------------------------------------------------------------
14 
15 
16 #include <AntTweakBar.h>
17 
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <math.h>
21 
22 #if defined(_WIN32) || defined(_WIN64)
23 //  MiniGLUT.h is provided to avoid the need of having GLUT installed to
24 //  recompile this example. Do not use it in your own programs, better
25 //  install and use the actual GLUT library SDK.
26 #   define USE_MINI_GLUT
27 #endif
28 
29 #if defined(USE_MINI_GLUT)
30 #   include "../src/MiniGLUT.h"
31 #elif defined(_MACOSX)
32 #   include <GLUT/glut.h>
33 #else
34 #   include <GL/glut.h>
35 #endif
36 
37 // This example displays one of the following shapes
38 typedef enum { SHAPE_TEAPOT=1, SHAPE_TORUS, SHAPE_CONE } Shape;
39 #define NUM_SHAPES 3
40 Shape g_CurrentShape = SHAPE_TORUS;
41 // Shapes scale
42 float g_Zoom = 1.0f;
43 // Shape orientation (stored as a quaternion)
44 float g_Rotation[] = { 0.0f, 0.0f, 0.0f, 1.0f };
45 // Auto rotate
46 int g_AutoRotate = 0;
47 int g_RotateTime = 0;
48 float g_RotateStart[] = { 0.0f, 0.0f, 0.0f, 1.0f };
49 // Shapes material
50 float g_MatAmbient[] = { 0.5f, 0.0f, 0.0f, 1.0f };
51 float g_MatDiffuse[] = { 1.0f, 1.0f, 0.0f, 1.0f };
52 // Light parameter
53 float g_LightMultiplier = 1.0f;
54 float g_LightDirection[] = { -0.57735f, -0.57735f, -0.57735f };
55 
56 
57 // Routine to set a quaternion from a rotation axis and angle
58 // ( input axis = float[3] angle = float  output: quat = float[4] )
SetQuaternionFromAxisAngle(const float * axis,float angle,float * quat)59 void SetQuaternionFromAxisAngle(const float *axis, float angle, float *quat)
60 {
61     float sina2, norm;
62     sina2 = (float)sin(0.5f * angle);
63     norm = (float)sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]);
64     quat[0] = sina2 * axis[0] / norm;
65     quat[1] = sina2 * axis[1] / norm;
66     quat[2] = sina2 * axis[2] / norm;
67     quat[3] = (float)cos(0.5f * angle);
68 }
69 
70 
71 // Routine to convert a quaternion to a 4x4 matrix
72 // ( input: quat = float[4]  output: mat = float[4*4] )
ConvertQuaternionToMatrix(const float * quat,float * mat)73 void ConvertQuaternionToMatrix(const float *quat, float *mat)
74 {
75     float yy2 = 2.0f * quat[1] * quat[1];
76     float xy2 = 2.0f * quat[0] * quat[1];
77     float xz2 = 2.0f * quat[0] * quat[2];
78     float yz2 = 2.0f * quat[1] * quat[2];
79     float zz2 = 2.0f * quat[2] * quat[2];
80     float wz2 = 2.0f * quat[3] * quat[2];
81     float wy2 = 2.0f * quat[3] * quat[1];
82     float wx2 = 2.0f * quat[3] * quat[0];
83     float xx2 = 2.0f * quat[0] * quat[0];
84     mat[0*4+0] = - yy2 - zz2 + 1.0f;
85     mat[0*4+1] = xy2 + wz2;
86     mat[0*4+2] = xz2 - wy2;
87     mat[0*4+3] = 0;
88     mat[1*4+0] = xy2 - wz2;
89     mat[1*4+1] = - xx2 - zz2 + 1.0f;
90     mat[1*4+2] = yz2 + wx2;
91     mat[1*4+3] = 0;
92     mat[2*4+0] = xz2 + wy2;
93     mat[2*4+1] = yz2 - wx2;
94     mat[2*4+2] = - xx2 - yy2 + 1.0f;
95     mat[2*4+3] = 0;
96     mat[3*4+0] = mat[3*4+1] = mat[3*4+2] = 0;
97     mat[3*4+3] = 1;
98 }
99 
100 
101 // Routine to multiply 2 quaternions (ie, compose rotations)
102 // ( input q1 = float[4] q2 = float[4]  output: qout = float[4] )
MultiplyQuaternions(const float * q1,const float * q2,float * qout)103 void MultiplyQuaternions(const float *q1, const float *q2, float *qout)
104 {
105     float qr[4];
106 	qr[0] = q1[3]*q2[0] + q1[0]*q2[3] + q1[1]*q2[2] - q1[2]*q2[1];
107 	qr[1] = q1[3]*q2[1] + q1[1]*q2[3] + q1[2]*q2[0] - q1[0]*q2[2];
108 	qr[2] = q1[3]*q2[2] + q1[2]*q2[3] + q1[0]*q2[1] - q1[1]*q2[0];
109 	qr[3]  = q1[3]*q2[3] - (q1[0]*q2[0] + q1[1]*q2[1] + q1[2]*q2[2]);
110     qout[0] = qr[0]; qout[1] = qr[1]; qout[2] = qr[2]; qout[3] = qr[3];
111 }
112 
113 
114 // Return elapsed time in milliseconds
GetTimeMs()115 int GetTimeMs()
116 {
117 #if !defined(_WIN32)
118     return glutGet(GLUT_ELAPSED_TIME);
119 #else
120     // glutGet(GLUT_ELAPSED_TIME) seems buggy on Windows
121     return (int)GetTickCount();
122 #endif
123 }
124 
125 
126 // Callback function called by GLUT to render screen
Display(void)127 void Display(void)
128 {
129     float v[4]; // will be used to set light parameters
130     float mat[4*4]; // rotation matrix
131 
132     // Clear frame buffer
133     glClearColor(0, 0, 0, 1);
134     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
135 
136     glEnable(GL_DEPTH_TEST);
137     glDisable(GL_CULL_FACE);
138     glEnable(GL_NORMALIZE);
139 
140     // Set light
141     glEnable(GL_LIGHTING);
142     glEnable(GL_LIGHT0);
143     v[0] = v[1] = v[2] = g_LightMultiplier*0.4f; v[3] = 1.0f;
144     glLightfv(GL_LIGHT0, GL_AMBIENT, v);
145     v[0] = v[1] = v[2] = g_LightMultiplier*0.8f; v[3] = 1.0f;
146     glLightfv(GL_LIGHT0, GL_DIFFUSE, v);
147     v[0] = -g_LightDirection[0]; v[1] = -g_LightDirection[1]; v[2] = -g_LightDirection[2]; v[3] = 0.0f;
148     glLightfv(GL_LIGHT0, GL_POSITION, v);
149 
150     // Set material
151     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, g_MatAmbient);
152     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, g_MatDiffuse);
153 
154     // Rotate and draw shape
155     glPushMatrix();
156     glTranslatef(0.5f, -0.3f, 0.0f);
157     if( g_AutoRotate )
158     {
159         float axis[3] = { 0, 1, 0 };
160         float angle = (float)(GetTimeMs()-g_RotateTime)/1000.0f;
161         float quat[4];
162         SetQuaternionFromAxisAngle(axis, angle, quat);
163         MultiplyQuaternions(g_RotateStart, quat, g_Rotation);
164     }
165     ConvertQuaternionToMatrix(g_Rotation, mat);
166     glMultMatrixf(mat);
167     glScalef(g_Zoom, g_Zoom, g_Zoom);
168     glCallList(g_CurrentShape);
169     glPopMatrix();
170 
171     // Draw tweak bars
172     TwDraw();
173 
174     // Present frame buffer
175     glutSwapBuffers();
176 
177     // Recall Display at next frame
178     glutPostRedisplay();
179 }
180 
181 
182 // Callback function called by GLUT when window size changes
Reshape(int width,int height)183 void Reshape(int width, int height)
184 {
185     // Set OpenGL viewport and camera
186     glViewport(0, 0, width, height);
187     glMatrixMode(GL_PROJECTION);
188     glLoadIdentity();
189     gluPerspective(40, (double)width/height, 1, 10);
190     glMatrixMode(GL_MODELVIEW);
191     glLoadIdentity();
192     gluLookAt(0,0,5, 0,0,0, 0,1,0);
193     glTranslatef(0, 0.6f, -1);
194 
195     // Send the new window size to AntTweakBar
196     TwWindowSize(width, height);
197 }
198 
199 
200 // Function called at exit
Terminate(void)201 void Terminate(void)
202 {
203     glDeleteLists(SHAPE_TEAPOT, NUM_SHAPES);
204 
205     TwTerminate();
206 }
207 
208 
209 //  Callback function called when the 'AutoRotate' variable value of the tweak bar has changed
SetAutoRotateCB(const void * value,void * clientData)210 void TW_CALL SetAutoRotateCB(const void *value, void *clientData)
211 {
212     (void)clientData; // unused
213 
214     g_AutoRotate = *(const int *)value; // copy value to g_AutoRotate
215     if( g_AutoRotate!=0 )
216     {
217         // init rotation
218         g_RotateTime = GetTimeMs();
219         g_RotateStart[0] = g_Rotation[0];
220         g_RotateStart[1] = g_Rotation[1];
221         g_RotateStart[2] = g_Rotation[2];
222         g_RotateStart[3] = g_Rotation[3];
223 
224         // make Rotation variable read-only
225         TwDefine(" TweakBar/ObjRotation readonly ");
226     }
227     else
228         // make Rotation variable read-write
229         TwDefine(" TweakBar/ObjRotation readwrite ");
230 }
231 
232 
233 //  Callback function called by the tweak bar to get the 'AutoRotate' value
GetAutoRotateCB(void * value,void * clientData)234 void TW_CALL GetAutoRotateCB(void *value, void *clientData)
235 {
236     (void)clientData; // unused
237     *(int *)value = g_AutoRotate; // copy g_AutoRotate to value
238 }
239 
240 
241 // Main
main(int argc,char * argv[])242 int main(int argc, char *argv[])
243 {
244     TwBar *bar; // Pointer to the tweak bar
245     float axis[] = { 0.7f, 0.7f, 0.0f }; // initial model rotation
246     float angle = 0.8f;
247 
248     // Initialize GLUT
249     glutInit(&argc, argv);
250     glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
251     glutInitWindowSize(640, 480);
252     glutCreateWindow("AntTweakBar simple example using GLUT");
253     glutCreateMenu(NULL);
254 
255     // Set GLUT callbacks
256     glutDisplayFunc(Display);
257     glutReshapeFunc(Reshape);
258     atexit(Terminate);  // Called after glutMainLoop ends
259 
260     // Initialize AntTweakBar
261     TwInit(TW_OPENGL, NULL);
262 
263     // Set GLUT event callbacks
264     // - Directly redirect GLUT mouse button events to AntTweakBar
265     glutMouseFunc((GLUTmousebuttonfun)TwEventMouseButtonGLUT);
266     // - Directly redirect GLUT mouse motion events to AntTweakBar
267     glutMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
268     // - Directly redirect GLUT mouse "passive" motion events to AntTweakBar (same as MouseMotion)
269     glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
270     // - Directly redirect GLUT key events to AntTweakBar
271     glutKeyboardFunc((GLUTkeyboardfun)TwEventKeyboardGLUT);
272     // - Directly redirect GLUT special key events to AntTweakBar
273     glutSpecialFunc((GLUTspecialfun)TwEventSpecialGLUT);
274     // - Send 'glutGetModifers' function pointer to AntTweakBar;
275     //   required because the GLUT key event functions do not report key modifiers states.
276     TwGLUTModifiersFunc(glutGetModifiers);
277 
278     // Create some 3D objects (stored in display lists)
279     glNewList(SHAPE_TEAPOT, GL_COMPILE);
280     glutSolidTeapot(1.0);
281     glEndList();
282     glNewList(SHAPE_TORUS, GL_COMPILE);
283     glutSolidTorus(0.3, 1.0, 16, 32);
284     glEndList();
285     glNewList(SHAPE_CONE, GL_COMPILE);
286     glutSolidCone(1.0, 1.5, 64, 4);
287     glEndList();
288 
289     // Create a tweak bar
290     bar = TwNewBar("TweakBar");
291     TwDefine(" GLOBAL help='This example shows how to integrate AntTweakBar with GLUT and OpenGL.' "); // Message added to the help bar.
292     TwDefine(" TweakBar size='200 400' color='96 216 224' "); // change default tweak bar size and color
293 
294     // Add 'g_Zoom' to 'bar': this is a modifable (RW) variable of type TW_TYPE_FLOAT. Its key shortcuts are [z] and [Z].
295     TwAddVarRW(bar, "Zoom", TW_TYPE_FLOAT, &g_Zoom,
296                " min=0.01 max=2.5 step=0.01 keyIncr=z keyDecr=Z help='Scale the object (1=original size).' ");
297 
298     // Add 'g_Rotation' to 'bar': this is a variable of type TW_TYPE_QUAT4F which defines the object's orientation
299     TwAddVarRW(bar, "ObjRotation", TW_TYPE_QUAT4F, &g_Rotation,
300                " label='Object rotation' opened=true help='Change the object orientation.' ");
301 
302     // Add callback to toggle auto-rotate mode (callback functions are defined above).
303     TwAddVarCB(bar, "AutoRotate", TW_TYPE_BOOL32, SetAutoRotateCB, GetAutoRotateCB, NULL,
304                " label='Auto-rotate' key=space help='Toggle auto-rotate mode.' ");
305 
306     // Add 'g_LightMultiplier' to 'bar': this is a variable of type TW_TYPE_FLOAT. Its key shortcuts are [+] and [-].
307     TwAddVarRW(bar, "Multiplier", TW_TYPE_FLOAT, &g_LightMultiplier,
308                " label='Light booster' min=0.1 max=4 step=0.02 keyIncr='+' keyDecr='-' help='Increase/decrease the light power.' ");
309 
310     // Add 'g_LightDirection' to 'bar': this is a variable of type TW_TYPE_DIR3F which defines the light direction
311     TwAddVarRW(bar, "LightDir", TW_TYPE_DIR3F, &g_LightDirection,
312                " label='Light direction' opened=true help='Change the light direction.' ");
313 
314     // Add 'g_MatAmbient' to 'bar': this is a variable of type TW_TYPE_COLOR3F (3 floats color, alpha is ignored)
315     // and is inserted into a group named 'Material'.
316     TwAddVarRW(bar, "Ambient", TW_TYPE_COLOR3F, &g_MatAmbient, " group='Material' ");
317 
318     // Add 'g_MatDiffuse' to 'bar': this is a variable of type TW_TYPE_COLOR3F (3 floats color, alpha is ignored)
319     // and is inserted into group 'Material'.
320     TwAddVarRW(bar, "Diffuse", TW_TYPE_COLOR3F, &g_MatDiffuse, " group='Material' ");
321 
322     // Add the enum variable 'g_CurrentShape' to 'bar'
323     // (before adding an enum variable, its enum type must be declared to AntTweakBar as follow)
324     {
325         // ShapeEV associates Shape enum values with labels that will be displayed instead of enum values
326         TwEnumVal shapeEV[NUM_SHAPES] = { {SHAPE_TEAPOT, "Teapot"}, {SHAPE_TORUS, "Torus"}, {SHAPE_CONE, "Cone"} };
327         // Create a type for the enum shapeEV
328         TwType shapeType = TwDefineEnum("ShapeType", shapeEV, NUM_SHAPES);
329         // add 'g_CurrentShape' to 'bar': this is a variable of type ShapeType. Its key shortcuts are [<] and [>].
330         TwAddVarRW(bar, "Shape", shapeType, &g_CurrentShape, " keyIncr='<' keyDecr='>' help='Change object shape.' ");
331     }
332 
333     // Store time
334     g_RotateTime = GetTimeMs();
335     // Init rotation
336     SetQuaternionFromAxisAngle(axis, angle, g_Rotation);
337     SetQuaternionFromAxisAngle(axis, angle, g_RotateStart);
338 
339     // Call the GLUT main loop
340     glutMainLoop();
341 
342     return 0;
343 }
344 
345