1 //  ---------------------------------------------------------------------------
2 //
3 //  @file       TwSimpleSFML.cpp
4 //  @brief      A simple example that uses AntTweakBar with OpenGL and SFML.
5 //              This example draws moving cubic particles with some
6 //              interactive control on particles generation.
7 //
8 //              AntTweakBar: http://anttweakbar.sourceforge.net/doc
9 //              OpenGL:      http://www.opengl.org
10 //              SFML:        http://www.sfml-dev.org
11 //
12 //  @author     Philippe Decaudin
13 //
14 //  ---------------------------------------------------------------------------
15 
16 
17 #include <AntTweakBar.h>
18 
19 #if defined(_WIN32)
20 //  MiniSFML16.h is provided to avoid the need of having SFML installed to
21 //  recompile this example. Do not use it in your own programs, better
22 //  install and use the actual SFML library SDK.
23 #   define USE_MINI_SFML
24 #endif
25 
26 #ifdef USE_MINI_SFML
27 #   include "../src/MiniSFML16.h"
28 #else
29 #   include <SFML/Graphics.hpp>
30 #endif
31 
32 #if defined(_WIN32)
33 #   include <windows.h> // required by gl.h
34 #endif
35 #include <GL/gl.h>
36 #include <GL/glu.h>
37 
38 #include <list>
39 #include <cstdlib>
40 #include <cmath>
41 
42 
43 // Pseudo-random value between -1 and 1
Random()44 float Random()
45 {
46     return 2.0f * ((float)rand() / RAND_MAX) - 1.0f;
47 }
48 
49 // Particle randomly initialized
50 struct Particle
51 {
52     float Size;
53     float Position[3];      // [px, py, pz]
54     float Speed[3];         // [vx, vy, vz]
55     float RotationAxis[3];  // [rx, ry, rz]
56     float RotationAngle;    // in degree
57     float RotationSpeed;
58     float Color[3];         // [r, g, b]
59     float Age;
ParticleParticle60     Particle(float size, float speedDir[3], float speedNorm, float color[3]) // Constructor
61     {
62         Size = size * (1.0f + 0.2f * Random());
63         Position[0] = Position[1] = Position[2] = 0;
64         Speed[0] = speedNorm * (speedDir[0] + 0.1f * Random());
65         Speed[1] = speedNorm * (speedDir[1] + 0.1f * Random());
66         Speed[2] = speedNorm * (speedDir[2] + 0.1f * Random());
67         RotationAxis[0] = Random();
68         RotationAxis[1] = Random();
69         RotationAxis[2] = Random();
70         RotationAngle = 360.0f * Random();
71         RotationSpeed = 360.0f * Random();
72         Color[0] = color[0] + 0.2f * Random();
73         Color[1] = color[1] + 0.2f * Random();
74         Color[2] = color[2] + 0.2f * Random();
75         Age = 0;
76     }
UpdateParticle77     void Update(float dt) // Apply one animation step
78     {
79         Position[0] += dt * Speed[0];
80         Position[1] += dt * Speed[1];
81         Position[2] += dt * Speed[2];
82         Speed[1] -= dt * 9.81f; // gravity
83         RotationAngle += dt * RotationSpeed;
84         Age += dt;
85     }
86 };
87 
88 
89 // Main
main()90 int main()
91 {
92     // Create main window
93     sf::RenderWindow app(sf::VideoMode(800, 600), "AntTweakBar simple example using SFML");
94     app.PreserveOpenGLStates(true);
95 
96     // Particules
97     std::list<Particle> particles;
98     std::list<Particle>::iterator p;
99     float birthCount = 0;
100     float birthRate = 20;               // number of particles generated per second
101     float maxAge = 3.0f;                // particles life time
102     float speedDir[3] = {0, 1, 0};      // initial particles speed direction
103     float speedNorm = 7.0f;             // initial particles speed amplitude
104     float size = 0.1f;                  // particles size
105     float color[3] = {0.8f, 0.6f, 0};   // particles color
106     float bgColor[3] = {0, 0.6f, 0.6f}; // background color
107 
108 
109     // Initialize AntTweakBar
110     TwInit(TW_OPENGL, NULL);
111 
112     // Tell the window size to AntTweakBar
113     TwWindowSize(app.GetWidth(), app.GetHeight());
114 
115     // Create a tweak bar
116     TwBar *bar = TwNewBar("Particles");
117     TwDefine(" GLOBAL help='This example shows how to integrate AntTweakBar with SFML and OpenGL.' "); // Message added to the help bar.
118 
119     // Change bar position
120     int barPos[2] = {16, 240};
121     TwSetParam(bar, NULL, "position", TW_PARAM_INT32, 2, &barPos);
122 
123     // Add 'birthRate' to 'bar': this is a modifiable variable of type TW_TYPE_FLOAT in range [0.1, 100]. Its shortcuts are [+] and [-].
124     TwAddVarRW(bar, "Birth rate", TW_TYPE_FLOAT, &birthRate, " min=0.1 max=100 step=0.1 keyIncr='+' keyDecr='-' ");
125 
126     // Add 'speedNorm' to 'bar': this is a modifiable variable of type TW_TYPE_FLOAT in range [0.1, 10]. Its shortcuts are [s] and [S].
127     TwAddVarRW(bar, "Speed", TW_TYPE_FLOAT, &speedNorm, " min=0.1 max=10 step=0.1 keyIncr='s' keyDecr='S' ");
128 
129     // Add 'speedDir' to 'bar': this is a modifiable variable of type TW_TYPE_DIR3F. Just displaying the arrow widget
130     TwAddVarRW(bar, "Direction", TW_TYPE_DIR3F, &speedDir, " opened=true showval=false ");
131 
132     // Add 'color' to 'bar': this is a modifiable variable of type TW_TYPE_COLOR3F. Switched to HLS
133     TwAddVarRW(bar, "Color", TW_TYPE_COLOR3F, &color, " colorMode=hls opened=true ");
134 
135     // Add 'bgColor' to 'bar': this is a modifiable variable of type TW_TYPE_COLOR3F. Switched to HLS
136     TwAddVarRW(bar, "Background color", TW_TYPE_COLOR3F, &bgColor, " colorMode=hls opened=true ");
137 
138     // Initialize OpenGL states
139     glEnable(GL_DEPTH_TEST);
140     glMatrixMode(GL_PROJECTION);
141     glLoadIdentity();
142     gluPerspective(90.f, (float)app.GetWidth()/app.GetHeight(), 0.1f, 100.f);
143     glMatrixMode(GL_MODELVIEW);
144     glEnable(GL_LIGHTING);
145     glEnable(GL_LIGHT0);
146     glEnable(GL_NORMALIZE);
147     glEnable(GL_COLOR_MATERIAL);
148     glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
149 
150     // Init time
151     sf::Clock clock;
152     float time = clock.GetElapsedTime();
153 
154     // Main loop
155     while (app.IsOpened())
156     {
157         // Process events
158         sf::Event event;
159         while (app.GetEvent(event))
160         {
161             // Send event to AntTweakBar
162             int handled = TwEventSFML(&event, 1, 6); // Assume SFML version 1.6 here
163 
164             // If event has not been handled by AntTweakBar, process it
165             if( !handled )
166             {
167                 // Close or Escape
168                 if (event.Type == sf::Event::Closed
169                     || (event.Type == sf::Event::KeyPressed && event.Key.Code == sf::Key::Escape))
170                     app.Close();
171 
172                 // Resize
173                 if (event.Type == sf::Event::Resized)
174                 {
175                     glViewport(0, 0, event.Size.Width, event.Size.Height);
176                     glMatrixMode(GL_PROJECTION);
177                     glLoadIdentity();
178                     gluPerspective(90.f, (float)event.Size.Width/event.Size.Height, 1.f, 500.f);
179                     glMatrixMode(GL_MODELVIEW);
180 
181                     // TwWindowSize has been called by TwEventSFML,
182                     // so it is not necessary to call it again here.
183                 }
184             }
185         }
186 
187         if (!app.IsOpened())
188             continue;
189 
190         // Update time
191         float dt = clock.GetElapsedTime() - time;
192         if (dt < 0) dt = 0;
193         time += dt;
194 
195         // Update particles
196         p = particles.begin();
197         while (p != particles.end())
198         {
199             p->Update(dt);
200             if (p->Age >= maxAge)
201                 p = particles.erase(p); // Die!
202             else
203                 ++p;
204         }
205 
206         // Generate new particles
207         birthCount += dt * birthRate;
208         while (birthCount >= 1.0f)
209         {
210             particles.push_back(Particle(size, speedDir, speedNorm, color));
211             birthCount--;
212         }
213 
214         // Clear depth buffer
215         glClearColor(bgColor[0], bgColor[1], bgColor[2], 1);
216         glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
217 
218         // Draw particles
219         for (p = particles.begin(); p != particles.end(); ++p)
220         {
221             glColor4fv(p->Color);
222             glLoadIdentity();
223             glTranslatef(0.0f, -1.0f, -3.0f); // Camera position
224             glTranslatef(p->Position[0], p->Position[1], p->Position[2]);
225             glScalef(p->Size, p->Size, p->Size);
226             glRotatef(p->RotationAngle, p->RotationAxis[0], p->RotationAxis[1], p->RotationAxis[2]);
227 
228             // Draw a cube
229             glBegin(GL_QUADS);
230                 glNormal3f(0,0,-1); glVertex3f(0,0,0); glVertex3f(0,1,0); glVertex3f(1,1,0); glVertex3f(1,0,0); // front face
231                 glNormal3f(0,0,+1); glVertex3f(0,0,1); glVertex3f(1,0,1); glVertex3f(1,1,1); glVertex3f(0,1,1); // back face
232                 glNormal3f(-1,0,0); glVertex3f(0,0,0); glVertex3f(0,0,1); glVertex3f(0,1,1); glVertex3f(0,1,0); // left face
233                 glNormal3f(+1,0,0); glVertex3f(1,0,0); glVertex3f(1,1,0); glVertex3f(1,1,1); glVertex3f(1,0,1); // right face
234                 glNormal3f(0,-1,0); glVertex3f(0,0,0); glVertex3f(1,0,0); glVertex3f(1,0,1); glVertex3f(0,0,1); // bottom face
235                 glNormal3f(0,+1,0); glVertex3f(0,1,0); glVertex3f(0,1,1); glVertex3f(1,1,1); glVertex3f(1,1,0); // top face
236             glEnd();
237         }
238 
239         TwDraw();
240 
241         // Finally, display the rendered frame on screen
242         app.Display();
243     }
244 
245     // Un-initialize AntTweakBar
246     TwTerminate();
247 
248     return EXIT_SUCCESS;
249 }
250