-
Notifications
You must be signed in to change notification settings - Fork 4
/
OGLScreen.cpp
445 lines (363 loc) · 10.3 KB
/
OGLScreen.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
/*
* OGLRendering.cpp
*
* Created on: Oct 13, 2011
* Author: iraklis
*/
#include <mastdlib.h>
#include "OGLScreen.h"
#include <madmath.h>
// Namespaces we want to access.
using namespace MAUtil; // Class Moblet
using namespace NativeUI; // WebView widget.
OGLScreen::OGLScreen(MAHandle particleImage): Screen()
{
mParticleImageHandle = particleImage;
mGLViewInitialized = false;
mEnvironmentInitialized = false;
mVariablesInitialized = false;
mShouldRender = false;
ax = ay = az = 0;
mTotalTime = 0;
mFrameCounter = 0;
createUI();
mPrevTime = maGetMilliSecondCount();
//Setthe timer that controls the rendering
Environment::getEnvironment().addTimer(this,10,0);
}
OGLScreen::~OGLScreen()
{
delete mParticles;
}
void OGLScreen::createUI()
{
//Increase flow button
mAddButton = new Button();
mAddButton->fillSpaceHorizontally();
mAddButton->wrapContentVertically();
mAddButton->setText("Increase");
mAddButton->addButtonListener(this);
//Decrease flow button
mRemoveButton = new Button();
mRemoveButton->fillSpaceHorizontally();
mRemoveButton->wrapContentVertically();
mRemoveButton->setText("Decrease");
mRemoveButton->addButtonListener(this);
HorizontalLayout* hLayout = new HorizontalLayout();
hLayout->wrapContentVertically();
hLayout->addChild(mAddButton);
hLayout->addChild(mRemoveButton);
mFPSLabel = new Label();
mFPSLabel->setText("FPS:");
mFPSLabel->wrapContentVertically();
mFPSLabel->fillSpaceHorizontally();
mFlowLabel = new Label();
mFlowLabel->setText("Flow:");
mFlowLabel->wrapContentVertically();
mFlowLabel->fillSpaceHorizontally();
HorizontalLayout* hLayout2 = new HorizontalLayout();
hLayout2->wrapContentVertically();
hLayout2->addChild(mFPSLabel);
hLayout2->addChild(mFlowLabel);
//The widget that renders the animation
mGLView = new GLView(MAW_GL_VIEW);
mGLView->addGLViewListener(this);
VerticalLayout* vLayout = new VerticalLayout();
vLayout->addChild(hLayout);
vLayout->addChild(hLayout2);
vLayout->addChild(mGLView);
setMainWidget(vLayout);
setTitle("Native Rendering");
}
void OGLScreen::buttonClicked(Widget* button)
{
//Notify the JavaScript code that a button was clicked
if(button == mAddButton){
mHTMLScreen->getWebView()->callJS("increaseFlow()");
}
else if(button == mRemoveButton){
mHTMLScreen->getWebView()->callJS("decreaseFlow()");
}
}
void OGLScreen::enableAddButton(bool state)
{
if(state)
{
mAddButton->setEnabled(true);
mAddButton->setFontColor(0x000000);
}
else
{
mAddButton->setEnabled(false);
mAddButton->setFontColor(0x969696);
}
}
void OGLScreen::enableRemoveButton(bool state)
{
if(state)
{
mRemoveButton->setEnabled(true);
mRemoveButton->setFontColor(0x000000);
}
else
{
mRemoveButton->setEnabled(false);
mRemoveButton->setFontColor(0x969696);
}
}
void OGLScreen::glViewReady(GLView* glView)
{
//Set this GLView to receive OpenGL commands
mGLView->bind();
// Create the texture we will use for rendering.
createTexture();
// Flag that the GLView has been initialized.
mGLViewInitialized = true;
// Initialize OpenGL.
initGL();
}
void OGLScreen::initVariables(HTMLScreen *htmlScreen,int maxParticles,
int particleLifetime, float gravityScale,
int screenWidth, int screenHeight)
{
MAX_PARTICLES = maxParticles;
PARTICLE_LIFETIME = particleLifetime;
GRAVITY_SCALE = gravityScale;
SCREN_WIDTH = screenWidth;
SCREEN_HEIGHT = screenHeight;
//Initialize the list of particles
mParticles = new particle[MAX_PARTICLES];
for(int i = 0; i < MAX_PARTICLES; i++)
{
//All particles in the list start out as inactive
mParticles[i].alive = false;
}
mHTMLScreen = htmlScreen;
mVariablesInitialized = true;
// Initialize OpenGL.
initGL();
}
/**
* Create the texture used for rendering.
*/
void OGLScreen::createTexture()
{
// Create an OpenGL 2D texture from the image resource.
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &mParticleTexture);
glBindTexture(GL_TEXTURE_2D, mParticleTexture);
maOpenGLTexImage2D(mParticleImageHandle);
// Set texture parameters.
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
/**
* Setup the projection matrix.
*/
void OGLScreen::setViewport(int width, int height)
{
// Set the viewport to fill the GLView
glViewport(0, 0, (GLint)mGLView->getWidth(), (GLint)mGLView->getHeight());
// Select the projection matrix.
glMatrixMode(GL_PROJECTION);
// Reset the projection matrix.
glLoadIdentity();
//Set an orthographic projection
//The Y axis is set upside-down to
//match the coordinate system of the
//HTML5 canvas
glOrthof((GLfloat)(-width / 2),
(GLfloat)(+width / 2),
(GLfloat)(-height / 2),
(GLfloat)(+height / 2),
0,1
);
}
/**
* Standard OpenGL initialization.
*/
void OGLScreen::initGL()
{
//This function is called twice, but executes it's code
//Only when both the other two initialization methods
//have been executed
if(!(mGLViewInitialized && mVariablesInitialized))
{
return;
}
//Configure the viewport
setViewport(SCREN_WIDTH, SCREEN_HEIGHT);
// Enable texture mapping.
glEnable(GL_TEXTURE_2D);
// Enable smooth shading.
glShadeModel(GL_SMOOTH);
// Set the depth value used when clearing the depth buffer.
glClearDepthf(1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
mEnvironmentInitialized = true;
}
void OGLScreen::renderParticleObject()
{
// Array used for object coordinates.
GLfloat vcoords[4][3];
// Array used for texture coordinates.
GLfloat tcoords[4][2];
// Array used to convert from QUAD to TRIANGLE_STRIP.
// QUAD is not available on the OpenGL implementation
// we are using.
GLubyte indices[4] = {0, 1, 3, 2};
// Select the texture to use when rendering the box.
glBindTexture(GL_TEXTURE_2D, mParticleTexture);
// Define the particle.
tcoords[0][0] = 1.0f; tcoords[0][1] = 0.0f;
vcoords[0][0] = -1.0f; vcoords[0][1] = -1.0f; vcoords[0][2] = 0.0f;
tcoords[1][0] = 0.0f; tcoords[1][1] = 0.0f;
vcoords[1][0] = 1.0f; vcoords[1][1] = -1.0f; vcoords[1][2] = 0.0f;
tcoords[2][0] = 0.0f; tcoords[2][1] = 1.0f;
vcoords[2][0] = 1.0f; vcoords[2][1] = 1.0f; vcoords[2][2] = 0.0f;
tcoords[3][0] = 1.0f; tcoords[3][1] = 1.0f;
vcoords[3][0] = -1.0f; vcoords[3][1] = 1.0f; vcoords[3][2] = 0.0f;
// Set pointers to vertex coordinates and texture coordinates.
glVertexPointer(3, GL_FLOAT, 0, vcoords);
glTexCoordPointer(2, GL_FLOAT, 0, tcoords);
// Enable texture and vertex arrays
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//Render each active particle
for(int i = 0; i < MAX_PARTICLES; i++) {
if(mParticles[i].alive)
{
glPushMatrix();
//Position the particle in the X and Y axis
glTranslatef(mParticles[i].x, mParticles[i].y, 0.0f);
//Scale to simulate the Z axis, since this is a 2D
//image and we are using an Orthographic projection
glScalef(mParticles[i].z / 2, mParticles[i].z / 2, 0.0f);
// This draws the particle.
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);
glPopMatrix();
}
}
// Disable texture and vertex arrays
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
void OGLScreen::draw(int currentTime)
{
// The GL_View must be initialized before we can do any drawing.
if (!mEnvironmentInitialized)
{
return;
}
// Set the background color to be used when clearing the screen.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Clear the screen and the depth buffer.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use the model matrix.
glMatrixMode(GL_MODELVIEW);
// Reset the model matrix.
glLoadIdentity();
//The time since the last frame
int cycleTime = (currentTime - mPrevTime);
for(int i = 0; i < MAX_PARTICLES; i++) {
particle* p = mParticles + i;
if(p->alive == true)
{
//Each particle's time since the last frame is
//usually equal to cycleTime, unless the particle
//has just been created. Then it has a shorter time.
int particleTime = cycleTime;
if(p->addTime > mPrevTime)
{
particleTime = (currentTime - p->addTime);
}
//Calculate the new velocity vector
p->zv += az*particleTime;
p->xv += ax*particleTime;
p->yv += ay*particleTime;
//Calculate the new position vector
p->z += p->zv*particleTime;
p->x += p->xv*particleTime;
p->y += p->yv*particleTime;
}
}
//Render the particles at their new positions
renderParticleObject();
// Wait (blocks) until all GL drawing commands to finish.
glFinish();
mGLView->redraw();
}
void OGLScreen::shouldRender(bool render)
{
mShouldRender = render;
}
void OGLScreen::sensorEvent(MASensor a)
{
//Set the new gravity vector
ax = a.values[0] * GRAVITY_SCALE;
ay = a.values[1] * GRAVITY_SCALE;
az = a.values[2] * GRAVITY_SCALE;
}
void OGLScreen::runTimerEvent()
{
//Execute only if the screen is active
if(mShouldRender)
{
//Get the current system time
int currentTime = maGetMilliSecondCount();
//Calculate and draw the positions for the new frame
draw(currentTime);
//Deactivate any particles past their time
removeOldParticles(currentTime);
mFrameCounter++;
mTotalTime += currentTime - mPrevTime;
if(mFrameCounter == 100)
{
char buffer[32];
sprintf(buffer,"FPS:%4.1f", 100000.0f / mTotalTime);
mFPSLabel->setText(buffer);
mTotalTime = 0;
mFrameCounter = 0;
}
mPrevTime = currentTime;
}
}
void OGLScreen::addNewParticles(float x, float y, float z,
float xv, float yv, float zv, int flow)
{
//Mark the time this particle was added
int currentTime = maGetMilliSecondCount();
char buffer[32];
sprintf(buffer,"Flow:%d", flow);
mFlowLabel->setText(buffer);
//Find an inactive particle to initialize and activate
for(int i = 0; i < MAX_PARTICLES; i++)
{
if(!mParticles[i].alive)
{
mParticles[i].alive = true;
mParticles[i].addTime = currentTime;
mParticles[i].xv = xv;
mParticles[i].yv = yv;
mParticles[i].zv = zv;
mParticles[i].x = x;
mParticles[i].y = y;
mParticles[i].z = z;
break;
}
}
}
void OGLScreen::removeOldParticles(int currentTime)
{
for(int i = 0; i < MAX_PARTICLES; i++)
{
if(mParticles[i].alive == true && //if the particle is active
(mParticles[i].addTime + PARTICLE_LIFETIME < currentTime //but past it's time
|| mParticles[i].z < 0)) //Or if it fell below the 0 level
{
//Deactivate it
mParticles[i].alive = false;
}
}
}