ruby-glfw 0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -0
- data/README.API +73 -0
- data/Rakefile +120 -0
- data/examples/boing.rb +519 -0
- data/examples/gears.rb +327 -0
- data/examples/keytest.rb +117 -0
- data/examples/listmodes.rb +20 -0
- data/examples/mipmaps.rb +104 -0
- data/examples/mipmaps.tga +0 -0
- data/examples/particles.rb +837 -0
- data/examples/pong3d.rb +741 -0
- data/examples/pong3d_field.tga +0 -0
- data/examples/pong3d_instr.tga +0 -0
- data/examples/pong3d_menu.tga +0 -0
- data/examples/pong3d_title.tga +0 -0
- data/examples/pong3d_winner1.tga +0 -0
- data/examples/pong3d_winner2.tga +0 -0
- data/examples/splitview.rb +432 -0
- data/examples/triangle.rb +89 -0
- data/examples/wave.rb +294 -0
- data/ext/glfw/glfw.c +1094 -0
- data/ext/glfw/mkrf_conf.rb +70 -0
- data/glfw-src/Makefile +220 -0
- data/glfw-src/compile.ami +61 -0
- data/glfw-src/compile.bat +217 -0
- data/glfw-src/compile.sh +607 -0
- data/glfw-src/docs/Makefile +57 -0
- data/glfw-src/docs/Reference.pdf +0 -0
- data/glfw-src/docs/UsersGuide.pdf +0 -0
- data/glfw-src/docs/cleanup.bat +22 -0
- data/glfw-src/docs/glfwdoc.sty +80 -0
- data/glfw-src/docs/glfwrm.tex +3034 -0
- data/glfw-src/docs/glfwug.tex +2024 -0
- data/glfw-src/docs/readme.txt +80 -0
- data/glfw-src/examples/Makefile.amigaos.gcc +70 -0
- data/glfw-src/examples/Makefile.amigaos.vbcc +70 -0
- data/glfw-src/examples/Makefile.dos.djgpp +71 -0
- data/glfw-src/examples/Makefile.macosx.gcc +96 -0
- data/glfw-src/examples/Makefile.win32.bcc +75 -0
- data/glfw-src/examples/Makefile.win32.cross-mgw +79 -0
- data/glfw-src/examples/Makefile.win32.cygwin +79 -0
- data/glfw-src/examples/Makefile.win32.lcc +74 -0
- data/glfw-src/examples/Makefile.win32.mgw +75 -0
- data/glfw-src/examples/Makefile.win32.msvc +74 -0
- data/glfw-src/examples/Makefile.win32.ow +74 -0
- data/glfw-src/examples/Makefile.win32.pellesc +74 -0
- data/glfw-src/examples/Makefile.x11.in +54 -0
- data/glfw-src/examples/boing.c +606 -0
- data/glfw-src/examples/bundle.sh +46 -0
- data/glfw-src/examples/gears.c +382 -0
- data/glfw-src/examples/keytest.c +264 -0
- data/glfw-src/examples/listmodes.c +48 -0
- data/glfw-src/examples/mipmaps.c +126 -0
- data/glfw-src/examples/mipmaps.tga +0 -0
- data/glfw-src/examples/mtbench.c +301 -0
- data/glfw-src/examples/mthello.c +48 -0
- data/glfw-src/examples/particles.c +1148 -0
- data/glfw-src/examples/pong3d.c +839 -0
- data/glfw-src/examples/pong3d_field.tga +0 -0
- data/glfw-src/examples/pong3d_instr.tga +0 -0
- data/glfw-src/examples/pong3d_menu.tga +0 -0
- data/glfw-src/examples/pong3d_title.tga +0 -0
- data/glfw-src/examples/pong3d_winner1.tga +0 -0
- data/glfw-src/examples/pong3d_winner2.tga +0 -0
- data/glfw-src/examples/splitview.c +506 -0
- data/glfw-src/examples/triangle.c +108 -0
- data/glfw-src/examples/wave.c +397 -0
- data/glfw-src/images/opengl.gif +0 -0
- data/glfw-src/images/osicert.gif +0 -0
- data/glfw-src/include/GL/glfw.h +486 -0
- data/glfw-src/lib/amigaos/Makefile.amigaos.gcc +128 -0
- data/glfw-src/lib/amigaos/Makefile.amigaos.vbcc +128 -0
- data/glfw-src/lib/amigaos/SDI_compiler.h +94 -0
- data/glfw-src/lib/amigaos/amigaos_enable.c +51 -0
- data/glfw-src/lib/amigaos/amigaos_fullscreen.c +319 -0
- data/glfw-src/lib/amigaos/amigaos_glext.c +61 -0
- data/glfw-src/lib/amigaos/amigaos_init.c +284 -0
- data/glfw-src/lib/amigaos/amigaos_joystick.c +359 -0
- data/glfw-src/lib/amigaos/amigaos_thread.c +494 -0
- data/glfw-src/lib/amigaos/amigaos_time.c +206 -0
- data/glfw-src/lib/amigaos/amigaos_window.c +830 -0
- data/glfw-src/lib/amigaos/platform.h +337 -0
- data/glfw-src/lib/dos/Makefile.dos.djgpp +146 -0
- data/glfw-src/lib/dos/dos_enable.c +51 -0
- data/glfw-src/lib/dos/dos_events.c +173 -0
- data/glfw-src/lib/dos/dos_fullscreen.c +101 -0
- data/glfw-src/lib/dos/dos_glext.c +59 -0
- data/glfw-src/lib/dos/dos_init.c +105 -0
- data/glfw-src/lib/dos/dos_irq.s +246 -0
- data/glfw-src/lib/dos/dos_joystick.c +94 -0
- data/glfw-src/lib/dos/dos_keyboard.c +694 -0
- data/glfw-src/lib/dos/dos_mouse.c +337 -0
- data/glfw-src/lib/dos/dos_thread.c +267 -0
- data/glfw-src/lib/dos/dos_time.c +309 -0
- data/glfw-src/lib/dos/dos_window.c +563 -0
- data/glfw-src/lib/dos/platform.h +341 -0
- data/glfw-src/lib/enable.c +295 -0
- data/glfw-src/lib/fullscreen.c +95 -0
- data/glfw-src/lib/glext.c +201 -0
- data/glfw-src/lib/image.c +629 -0
- data/glfw-src/lib/init.c +108 -0
- data/glfw-src/lib/input.c +280 -0
- data/glfw-src/lib/internal.h +210 -0
- data/glfw-src/lib/joystick.c +101 -0
- data/glfw-src/lib/macosx/Makefile.macosx.gcc +172 -0
- data/glfw-src/lib/macosx/Makefile.macosx.gcc.universal +166 -0
- data/glfw-src/lib/macosx/libglfw.pc.in +11 -0
- data/glfw-src/lib/macosx/macosx_enable.c +42 -0
- data/glfw-src/lib/macosx/macosx_fullscreen.c +126 -0
- data/glfw-src/lib/macosx/macosx_glext.c +52 -0
- data/glfw-src/lib/macosx/macosx_init.c +194 -0
- data/glfw-src/lib/macosx/macosx_joystick.c +50 -0
- data/glfw-src/lib/macosx/macosx_thread.c +414 -0
- data/glfw-src/lib/macosx/macosx_time.c +112 -0
- data/glfw-src/lib/macosx/macosx_window.c +1279 -0
- data/glfw-src/lib/macosx/platform.h +349 -0
- data/glfw-src/lib/stream.c +194 -0
- data/glfw-src/lib/tga.c +405 -0
- data/glfw-src/lib/thread.c +340 -0
- data/glfw-src/lib/time.c +83 -0
- data/glfw-src/lib/win32/Makefile.win32.bcc +265 -0
- data/glfw-src/lib/win32/Makefile.win32.cross-mgw +274 -0
- data/glfw-src/lib/win32/Makefile.win32.cygwin +279 -0
- data/glfw-src/lib/win32/Makefile.win32.lcc +246 -0
- data/glfw-src/lib/win32/Makefile.win32.mgw +243 -0
- data/glfw-src/lib/win32/Makefile.win32.msvc +242 -0
- data/glfw-src/lib/win32/Makefile.win32.ow +242 -0
- data/glfw-src/lib/win32/Makefile.win32.pellesc +242 -0
- data/glfw-src/lib/win32/glfwdll.def +67 -0
- data/glfw-src/lib/win32/glfwdll_mgw1.def +67 -0
- data/glfw-src/lib/win32/glfwdll_mgw2.def +67 -0
- data/glfw-src/lib/win32/glfwdll_pellesc.def +65 -0
- data/glfw-src/lib/win32/libglfw.pc.in +11 -0
- data/glfw-src/lib/win32/platform.h +474 -0
- data/glfw-src/lib/win32/win32_dllmain.c +60 -0
- data/glfw-src/lib/win32/win32_enable.c +155 -0
- data/glfw-src/lib/win32/win32_fullscreen.c +317 -0
- data/glfw-src/lib/win32/win32_glext.c +85 -0
- data/glfw-src/lib/win32/win32_init.c +356 -0
- data/glfw-src/lib/win32/win32_joystick.c +234 -0
- data/glfw-src/lib/win32/win32_thread.c +511 -0
- data/glfw-src/lib/win32/win32_time.c +146 -0
- data/glfw-src/lib/win32/win32_window.c +1714 -0
- data/glfw-src/lib/window.c +727 -0
- data/glfw-src/lib/x11/Makefile.x11.in +243 -0
- data/glfw-src/lib/x11/platform.h +415 -0
- data/glfw-src/lib/x11/x11_enable.c +51 -0
- data/glfw-src/lib/x11/x11_fullscreen.c +524 -0
- data/glfw-src/lib/x11/x11_glext.c +69 -0
- data/glfw-src/lib/x11/x11_init.c +275 -0
- data/glfw-src/lib/x11/x11_joystick.c +371 -0
- data/glfw-src/lib/x11/x11_keysym2unicode.c +902 -0
- data/glfw-src/lib/x11/x11_thread.c +507 -0
- data/glfw-src/lib/x11/x11_time.c +154 -0
- data/glfw-src/lib/x11/x11_window.c +1746 -0
- data/glfw-src/license.txt +21 -0
- data/glfw-src/readme.html +927 -0
- data/glfw-src/support/d/examples/Makefile +59 -0
- data/glfw-src/support/d/examples/boing.d +610 -0
- data/glfw-src/support/d/examples/gears.d +379 -0
- data/glfw-src/support/d/examples/keytest.d +272 -0
- data/glfw-src/support/d/examples/listmodes.d +48 -0
- data/glfw-src/support/d/examples/mipmaps.d +126 -0
- data/glfw-src/support/d/examples/mtbench.d +304 -0
- data/glfw-src/support/d/examples/mthello.d +54 -0
- data/glfw-src/support/d/examples/particles.d +1150 -0
- data/glfw-src/support/d/examples/pong3d.d +840 -0
- data/glfw-src/support/d/examples/splitview.d +486 -0
- data/glfw-src/support/d/examples/triangle.d +108 -0
- data/glfw-src/support/d/examples/wave.d +400 -0
- data/glfw-src/support/d/imports/gl.d +4539 -0
- data/glfw-src/support/d/imports/glfw.d +349 -0
- data/glfw-src/support/d/imports/glu.d +328 -0
- data/glfw-src/support/d/lib/glfwdll.def +64 -0
- data/glfw-src/support/d/lib/glu32.def +56 -0
- data/glfw-src/support/d/lib/makefile +12 -0
- data/glfw-src/support/d/lib/opengl32.def +372 -0
- data/glfw-src/support/d/readme.html +83 -0
- data/glfw-src/support/delphi/examples/Triangle.dpr +105 -0
- data/glfw-src/support/delphi/lib/glfw.pas +437 -0
- data/glfw-src/support/delphi/readme.html +97 -0
- data/glfw-src/support/lua/examples/gears.lua +383 -0
- data/glfw-src/support/lua/examples/test1.lua +68 -0
- data/glfw-src/support/lua/readme.html +128 -0
- data/glfw-src/support/lua/src/luaglfw.c +1179 -0
- data/glfw-src/support/lua/src/luaglfw.h +48 -0
- data/glfw-src/support/lua/src/runlua.c +82 -0
- data/glfw-src/support/masm/examples/fpc.mac +47 -0
- data/glfw-src/support/masm/examples/makeit.bat +66 -0
- data/glfw-src/support/masm/examples/triangle.asm +232 -0
- data/glfw-src/support/masm/include/glfw.inc +326 -0
- data/glfw-src/support/masm/include/glu32.inc +55 -0
- data/glfw-src/support/masm/include/opengl32.inc +372 -0
- data/glfw-src/support/masm/lib/glfwdll.lib +0 -0
- data/glfw-src/support/masm/readme.html +170 -0
- data/glfw-src/support/msvc80/GLFW.sln +26 -0
- data/glfw-src/support/msvc80/GLFW.vcproj +257 -0
- data/glfw-src/support/msvc80/GLFWDLL.vcproj +287 -0
- data/glfw-src/support/visualbasic/bindings/glfw.bas +320 -0
- data/glfw-src/support/visualbasic/bindings/glu32.bas +284 -0
- data/glfw-src/support/visualbasic/bindings/opengl32.bas +999 -0
- data/glfw-src/support/visualbasic/examples/Triangle.bas +101 -0
- data/glfw-src/support/visualbasic/readme.html +164 -0
- data/website/index.html +84 -0
- data/website/style.css +110 -0
- metadata +301 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
//========================================================================
|
2
|
+
// This is a small test application for GLFW.
|
3
|
+
// The program prints "Hello world!", using two threads.
|
4
|
+
//========================================================================
|
5
|
+
|
6
|
+
#include <stdio.h>
|
7
|
+
#include <GL/glfw.h>
|
8
|
+
|
9
|
+
|
10
|
+
//========================================================================
|
11
|
+
// HelloFun() - Thread function
|
12
|
+
//========================================================================
|
13
|
+
|
14
|
+
void GLFWCALL HelloFun( void *arg )
|
15
|
+
{
|
16
|
+
// Print the first part of the message
|
17
|
+
printf( "Hello " );
|
18
|
+
}
|
19
|
+
|
20
|
+
|
21
|
+
//========================================================================
|
22
|
+
// main() - Main function (main thread)
|
23
|
+
//========================================================================
|
24
|
+
|
25
|
+
int main( void )
|
26
|
+
{
|
27
|
+
GLFWthread thread;
|
28
|
+
|
29
|
+
// Initialise GLFW
|
30
|
+
if( !glfwInit() )
|
31
|
+
{
|
32
|
+
return 0;
|
33
|
+
}
|
34
|
+
|
35
|
+
// Create thread
|
36
|
+
thread = glfwCreateThread( HelloFun, NULL );
|
37
|
+
|
38
|
+
// Wait for thread to die
|
39
|
+
glfwWaitThread( thread, GLFW_WAIT );
|
40
|
+
|
41
|
+
// Print the rest of the message
|
42
|
+
printf( "world!\n" );
|
43
|
+
|
44
|
+
// Terminate GLFW
|
45
|
+
glfwTerminate();
|
46
|
+
|
47
|
+
return 0;
|
48
|
+
}
|
@@ -0,0 +1,1148 @@
|
|
1
|
+
//========================================================================
|
2
|
+
// This is a simple, but cool particle engine (buzz-word meaning many
|
3
|
+
// small objects that are treated as points and drawn as textures
|
4
|
+
// projected on simple geometry).
|
5
|
+
//
|
6
|
+
// This demonstration generates a colorful fountain-like animation. It
|
7
|
+
// uses several advanced OpenGL teqhniques:
|
8
|
+
//
|
9
|
+
// 1) Lighting (per vertex)
|
10
|
+
// 2) Alpha blending
|
11
|
+
// 3) Fog
|
12
|
+
// 4) Texturing
|
13
|
+
// 5) Display lists (for drawing the static environment geometry)
|
14
|
+
// 6) Vertex arrays (for drawing the particles)
|
15
|
+
// 7) GL_EXT_separate_specular_color is used (if available)
|
16
|
+
//
|
17
|
+
// Even more so, this program uses multi threading. The program is
|
18
|
+
// essentialy divided into a main rendering thread and a particle physics
|
19
|
+
// calculation thread. My benchmarks under Windows 2000 on a single
|
20
|
+
// processor system show that running this program as two threads instead
|
21
|
+
// of a single thread means no difference (there may be a very marginal
|
22
|
+
// advantage for the multi threaded case). On dual processor systems I
|
23
|
+
// have had reports of 5-25% of speed increase when running this program
|
24
|
+
// as two threads instead of one thread.
|
25
|
+
//
|
26
|
+
// The default behaviour of this program is to use two threads. To force
|
27
|
+
// a single thread to be used, use the command line switch -s.
|
28
|
+
//
|
29
|
+
// To run a fixed length benchmark (60 s), use the command line switch -b.
|
30
|
+
//
|
31
|
+
// Benchmark results (640x480x16, best of three tests):
|
32
|
+
//
|
33
|
+
// CPU GFX 1 thread 2 threads
|
34
|
+
// Athlon XP 2700+ GeForce Ti4200 (oc) 757 FPS 759 FPS
|
35
|
+
// P4 2.8 GHz (SMT) GeForce FX5600 548 FPS 550 FPS
|
36
|
+
//
|
37
|
+
// One more thing: Press 'w' during the demo to toggle wireframe mode.
|
38
|
+
//========================================================================
|
39
|
+
|
40
|
+
#include <stdlib.h>
|
41
|
+
#include <stdio.h>
|
42
|
+
#include <string.h>
|
43
|
+
#include <math.h>
|
44
|
+
#include <GL/glfw.h>
|
45
|
+
|
46
|
+
// Define tokens for GL_EXT_separate_specular_color if not already defined
|
47
|
+
#ifndef GL_EXT_separate_specular_color
|
48
|
+
#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT 0x81F8
|
49
|
+
#define GL_SINGLE_COLOR_EXT 0x81F9
|
50
|
+
#define GL_SEPARATE_SPECULAR_COLOR_EXT 0x81FA
|
51
|
+
#endif // GL_EXT_separate_specular_color
|
52
|
+
|
53
|
+
// Some <math.h>'s do not define M_PI
|
54
|
+
#ifndef M_PI
|
55
|
+
#define M_PI 3.141592654
|
56
|
+
#endif
|
57
|
+
|
58
|
+
// Desired fullscreen resolution
|
59
|
+
#define WIDTH 640
|
60
|
+
#define HEIGHT 480
|
61
|
+
|
62
|
+
|
63
|
+
//========================================================================
|
64
|
+
// Type definitions
|
65
|
+
//========================================================================
|
66
|
+
|
67
|
+
typedef struct { float x,y,z; } VEC;
|
68
|
+
|
69
|
+
// This structure is used for interleaved vertex arrays (see the
|
70
|
+
// DrawParticles function) - Note: This structure SHOULD be packed on most
|
71
|
+
// systems. It uses 32-bit fields on 32-bit boundaries, and is a multiple
|
72
|
+
// of 64 bits in total (6x32=3x64). If it does not work, try using pragmas
|
73
|
+
// or whatever to force the structure to be packed.
|
74
|
+
typedef struct {
|
75
|
+
GLfloat s, t; // Texture coordinates
|
76
|
+
GLuint rgba; // Color (four ubytes packed into an uint)
|
77
|
+
GLfloat x, y, z; // Vertex coordinates
|
78
|
+
} VERTEX;
|
79
|
+
|
80
|
+
|
81
|
+
//========================================================================
|
82
|
+
// Program control global variables
|
83
|
+
//========================================================================
|
84
|
+
|
85
|
+
// "Running" flag (true if program shall continue to run)
|
86
|
+
int running;
|
87
|
+
|
88
|
+
// Window dimensions
|
89
|
+
int width, height;
|
90
|
+
|
91
|
+
// "wireframe" flag (true if we use wireframe view)
|
92
|
+
int wireframe;
|
93
|
+
|
94
|
+
// "multithreading" flag (true if we use multithreading)
|
95
|
+
int multithreading;
|
96
|
+
|
97
|
+
// Thread synchronization
|
98
|
+
struct {
|
99
|
+
double t; // Time (s)
|
100
|
+
float dt; // Time since last frame (s)
|
101
|
+
int p_frame; // Particle physics frame number
|
102
|
+
int d_frame; // Particle draw frame number
|
103
|
+
GLFWcond p_done; // Condition: particle physics done
|
104
|
+
GLFWcond d_done; // Condition: particle draw done
|
105
|
+
GLFWmutex particles_lock; // Particles data sharing mutex
|
106
|
+
} thread_sync;
|
107
|
+
|
108
|
+
|
109
|
+
//========================================================================
|
110
|
+
// Texture declarations (we hard-code them into the source code, since
|
111
|
+
// they are so simple)
|
112
|
+
//========================================================================
|
113
|
+
|
114
|
+
#define P_TEX_WIDTH 8 // Particle texture dimensions
|
115
|
+
#define P_TEX_HEIGHT 8
|
116
|
+
#define F_TEX_WIDTH 16 // Floor texture dimensions
|
117
|
+
#define F_TEX_HEIGHT 16
|
118
|
+
|
119
|
+
// Texture object IDs
|
120
|
+
GLuint particle_tex_id, floor_tex_id;
|
121
|
+
|
122
|
+
// Particle texture (a simple spot)
|
123
|
+
const unsigned char particle_texture[ P_TEX_WIDTH * P_TEX_HEIGHT ] = {
|
124
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
125
|
+
0x00, 0x00, 0x11, 0x22, 0x22, 0x11, 0x00, 0x00,
|
126
|
+
0x00, 0x11, 0x33, 0x88, 0x77, 0x33, 0x11, 0x00,
|
127
|
+
0x00, 0x22, 0x88, 0xff, 0xee, 0x77, 0x22, 0x00,
|
128
|
+
0x00, 0x22, 0x77, 0xee, 0xff, 0x88, 0x22, 0x00,
|
129
|
+
0x00, 0x11, 0x33, 0x77, 0x88, 0x33, 0x11, 0x00,
|
130
|
+
0x00, 0x00, 0x11, 0x33, 0x22, 0x11, 0x00, 0x00,
|
131
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
132
|
+
};
|
133
|
+
|
134
|
+
// Floor texture (your basic checkered floor)
|
135
|
+
const unsigned char floor_texture[ F_TEX_WIDTH * F_TEX_HEIGHT ] = {
|
136
|
+
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
137
|
+
0xff, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
138
|
+
0xf0, 0xcc, 0xee, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0x66, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30,
|
139
|
+
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xee, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
140
|
+
0xf0, 0xf0, 0xf0, 0xf0, 0xcc, 0xf0, 0xf0, 0xf0, 0x30, 0x30, 0x55, 0x30, 0x30, 0x44, 0x30, 0x30,
|
141
|
+
0xf0, 0xdd, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
142
|
+
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x60, 0x30,
|
143
|
+
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
144
|
+
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
145
|
+
0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0xf0, 0xff, 0xf0, 0xf0, 0xdd, 0xf0, 0xf0, 0xff,
|
146
|
+
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x55, 0x33, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0,
|
147
|
+
0x30, 0x44, 0x66, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
148
|
+
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xaa, 0xf0, 0xf0, 0xcc, 0xf0,
|
149
|
+
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xdd, 0xf0,
|
150
|
+
0x30, 0x30, 0x30, 0x77, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
151
|
+
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
152
|
+
};
|
153
|
+
|
154
|
+
|
155
|
+
//========================================================================
|
156
|
+
// These are fixed constants that control the particle engine. In a
|
157
|
+
// modular world, these values should be variables...
|
158
|
+
//========================================================================
|
159
|
+
|
160
|
+
// Maximum number of particles
|
161
|
+
#define MAX_PARTICLES 3000
|
162
|
+
|
163
|
+
// Life span of a particle (in seconds)
|
164
|
+
#define LIFE_SPAN 8.0f
|
165
|
+
|
166
|
+
// A new particle is born every [BIRTH_INTERVAL] second
|
167
|
+
#define BIRTH_INTERVAL (LIFE_SPAN/(float)MAX_PARTICLES)
|
168
|
+
|
169
|
+
// Particle size (meters)
|
170
|
+
#define PARTICLE_SIZE 0.7f
|
171
|
+
|
172
|
+
// Gravitational constant (m/s^2)
|
173
|
+
#define GRAVITY 9.8f
|
174
|
+
|
175
|
+
// Base initial velocity (m/s)
|
176
|
+
#define VELOCITY 8.0f
|
177
|
+
|
178
|
+
// Bounce friction (1.0 = no friction, 0.0 = maximum friction)
|
179
|
+
#define FRICTION 0.75f
|
180
|
+
|
181
|
+
// "Fountain" height (m)
|
182
|
+
#define FOUNTAIN_HEIGHT 3.0f
|
183
|
+
|
184
|
+
// Fountain radius (m)
|
185
|
+
#define FOUNTAIN_RADIUS 1.6f
|
186
|
+
|
187
|
+
// Minimum delta-time for particle phisics (s)
|
188
|
+
#define MIN_DELTA_T (BIRTH_INTERVAL*0.5)
|
189
|
+
|
190
|
+
|
191
|
+
//========================================================================
|
192
|
+
// Particle system global variables
|
193
|
+
//========================================================================
|
194
|
+
|
195
|
+
// This structure holds all state for a single particle
|
196
|
+
typedef struct {
|
197
|
+
float x,y,z; // Position in space
|
198
|
+
float vx,vy,vz; // Velocity vector
|
199
|
+
float r,g,b; // Color of particle
|
200
|
+
float life; // Life of particle (1.0 = newborn, < 0.0 = dead)
|
201
|
+
int active; // Tells if this particle is active
|
202
|
+
} PARTICLE;
|
203
|
+
|
204
|
+
// Global vectors holding all particles. We use two vectors for double
|
205
|
+
// buffering.
|
206
|
+
static PARTICLE particles[ MAX_PARTICLES ];
|
207
|
+
|
208
|
+
// Global variable holding the age of the youngest particle
|
209
|
+
static float min_age;
|
210
|
+
|
211
|
+
// Color of latest born particle (used for fountain lighting)
|
212
|
+
static float glow_color[4];
|
213
|
+
|
214
|
+
// Position of latest born particle (used for fountain lighting)
|
215
|
+
static float glow_pos[4];
|
216
|
+
|
217
|
+
|
218
|
+
//========================================================================
|
219
|
+
// Object material and fog configuration constants
|
220
|
+
//========================================================================
|
221
|
+
|
222
|
+
const GLfloat fountain_diffuse[4] = {0.7f,1.0f,1.0f,1.0f};
|
223
|
+
const GLfloat fountain_specular[4] = {1.0f,1.0f,1.0f,1.0f};
|
224
|
+
const GLfloat fountain_shininess = 12.0f;
|
225
|
+
const GLfloat floor_diffuse[4] = {1.0f,0.6f,0.6f,1.0f};
|
226
|
+
const GLfloat floor_specular[4] = {0.6f,0.6f,0.6f,1.0f};
|
227
|
+
const GLfloat floor_shininess = 18.0f;
|
228
|
+
const GLfloat fog_color[4] = {0.1f, 0.1f, 0.1f, 1.0f};
|
229
|
+
|
230
|
+
|
231
|
+
//========================================================================
|
232
|
+
// InitParticle() - Initialize a new particle
|
233
|
+
//========================================================================
|
234
|
+
|
235
|
+
void InitParticle( PARTICLE *p, double t )
|
236
|
+
{
|
237
|
+
float xy_angle, velocity;
|
238
|
+
|
239
|
+
// Start position of particle is at the fountain blow-out
|
240
|
+
p->x = 0.0f;
|
241
|
+
p->y = 0.0f;
|
242
|
+
p->z = FOUNTAIN_HEIGHT;
|
243
|
+
|
244
|
+
// Start velocity is up (Z)...
|
245
|
+
p->vz = 0.7f + (0.3/4096.0) * (float) (rand() & 4095);
|
246
|
+
|
247
|
+
// ...and a randomly chosen X/Y direction
|
248
|
+
xy_angle = (2.0*M_PI/4096.0) * (float) (rand() & 4095);
|
249
|
+
p->vx = 0.4f * (float) cos( xy_angle );
|
250
|
+
p->vy = 0.4f * (float) sin( xy_angle );
|
251
|
+
|
252
|
+
// Scale velocity vector according to a time-varying velocity
|
253
|
+
velocity = VELOCITY*(0.8f + 0.1f*(float)(sin( 0.5*t )+sin( 1.31*t )));
|
254
|
+
p->vx *= velocity;
|
255
|
+
p->vy *= velocity;
|
256
|
+
p->vz *= velocity;
|
257
|
+
|
258
|
+
// Color is time-varying
|
259
|
+
p->r = 0.7f + 0.3f * (float) sin( 0.34*t + 0.1 );
|
260
|
+
p->g = 0.6f + 0.4f * (float) sin( 0.63*t + 1.1 );
|
261
|
+
p->b = 0.6f + 0.4f * (float) sin( 0.91*t + 2.1 );
|
262
|
+
|
263
|
+
// Store settings for fountain glow lighting
|
264
|
+
glow_pos[0] = 0.4f * (float) sin( 1.34*t );
|
265
|
+
glow_pos[1] = 0.4f * (float) sin( 3.11*t );
|
266
|
+
glow_pos[2] = FOUNTAIN_HEIGHT + 1.0f;
|
267
|
+
glow_pos[3] = 1.0f;
|
268
|
+
glow_color[0] = p->r;
|
269
|
+
glow_color[1] = p->g;
|
270
|
+
glow_color[2] = p->b;
|
271
|
+
glow_color[3] = 1.0f;
|
272
|
+
|
273
|
+
// The particle is new-born and active
|
274
|
+
p->life = 1.0f;
|
275
|
+
p->active = 1;
|
276
|
+
}
|
277
|
+
|
278
|
+
|
279
|
+
//========================================================================
|
280
|
+
// UpdateParticle() - Update a particle
|
281
|
+
//========================================================================
|
282
|
+
|
283
|
+
#define FOUNTAIN_R2 (FOUNTAIN_RADIUS+PARTICLE_SIZE/2)*(FOUNTAIN_RADIUS+PARTICLE_SIZE/2)
|
284
|
+
|
285
|
+
void UpdateParticle( PARTICLE *p, float dt )
|
286
|
+
{
|
287
|
+
// If the particle is not active, we need not do anything
|
288
|
+
if( !p->active )
|
289
|
+
{
|
290
|
+
return;
|
291
|
+
}
|
292
|
+
|
293
|
+
// The particle is getting older...
|
294
|
+
p->life = p->life - dt * (1.0f / LIFE_SPAN);
|
295
|
+
|
296
|
+
// Did the particle die?
|
297
|
+
if( p->life <= 0.0f )
|
298
|
+
{
|
299
|
+
p->active = 0;
|
300
|
+
return;
|
301
|
+
}
|
302
|
+
|
303
|
+
// Update particle velocity (apply gravity)
|
304
|
+
p->vz = p->vz - GRAVITY * dt;
|
305
|
+
|
306
|
+
// Update particle position
|
307
|
+
p->x = p->x + p->vx * dt;
|
308
|
+
p->y = p->y + p->vy * dt;
|
309
|
+
p->z = p->z + p->vz * dt;
|
310
|
+
|
311
|
+
// Simple collision detection + response
|
312
|
+
if( p->vz < 0.0f )
|
313
|
+
{
|
314
|
+
// Particles should bounce on the fountain (with friction)
|
315
|
+
if( (p->x*p->x + p->y*p->y) < FOUNTAIN_R2 &&
|
316
|
+
p->z < (FOUNTAIN_HEIGHT + PARTICLE_SIZE/2) )
|
317
|
+
{
|
318
|
+
p->vz = -FRICTION * p->vz;
|
319
|
+
p->z = FOUNTAIN_HEIGHT + PARTICLE_SIZE/2 +
|
320
|
+
FRICTION * (FOUNTAIN_HEIGHT +
|
321
|
+
PARTICLE_SIZE/2 - p->z);
|
322
|
+
}
|
323
|
+
|
324
|
+
// Particles should bounce on the floor (with friction)
|
325
|
+
else if( p->z < PARTICLE_SIZE/2 )
|
326
|
+
{
|
327
|
+
p->vz = -FRICTION * p->vz;
|
328
|
+
p->z = PARTICLE_SIZE/2 +
|
329
|
+
FRICTION * (PARTICLE_SIZE/2 - p->z);
|
330
|
+
}
|
331
|
+
|
332
|
+
}
|
333
|
+
}
|
334
|
+
|
335
|
+
|
336
|
+
//========================================================================
|
337
|
+
// ParticleEngine() - The main frame for the particle engine. Called once
|
338
|
+
// per frame.
|
339
|
+
//========================================================================
|
340
|
+
|
341
|
+
void ParticleEngine( double t, float dt )
|
342
|
+
{
|
343
|
+
int i;
|
344
|
+
float dt2;
|
345
|
+
|
346
|
+
// Update particles (iterated several times per frame if dt is too
|
347
|
+
// large)
|
348
|
+
while( dt > 0.0f )
|
349
|
+
{
|
350
|
+
// Calculate delta time for this iteration
|
351
|
+
dt2 = dt < MIN_DELTA_T ? dt : MIN_DELTA_T;
|
352
|
+
|
353
|
+
// Update particles
|
354
|
+
for( i = 0; i < MAX_PARTICLES; i ++ )
|
355
|
+
{
|
356
|
+
UpdateParticle( &particles[ i ], dt2 );
|
357
|
+
}
|
358
|
+
|
359
|
+
// Increase minimum age
|
360
|
+
min_age += dt2;
|
361
|
+
|
362
|
+
// Should we create any new particle(s)?
|
363
|
+
while( min_age >= BIRTH_INTERVAL )
|
364
|
+
{
|
365
|
+
min_age -= BIRTH_INTERVAL;
|
366
|
+
|
367
|
+
// Find a dead particle to replace with a new one
|
368
|
+
for( i = 0; i < MAX_PARTICLES; i ++ )
|
369
|
+
{
|
370
|
+
if( !particles[ i ].active )
|
371
|
+
{
|
372
|
+
InitParticle( &particles[ i ], t + min_age );
|
373
|
+
UpdateParticle( &particles[ i ], min_age );
|
374
|
+
break;
|
375
|
+
}
|
376
|
+
}
|
377
|
+
}
|
378
|
+
|
379
|
+
// Decrease frame delta time
|
380
|
+
dt -= dt2;
|
381
|
+
}
|
382
|
+
}
|
383
|
+
|
384
|
+
|
385
|
+
//========================================================================
|
386
|
+
// DrawParticles() - Draw all active particles. We use OpenGL 1.1 vertex
|
387
|
+
// arrays for this in order to accelerate the drawing.
|
388
|
+
//========================================================================
|
389
|
+
|
390
|
+
#define BATCH_PARTICLES 70 // Number of particles to draw in each batch
|
391
|
+
// (70 corresponds to 7.5 KB = will not blow
|
392
|
+
// the L1 data cache on most CPUs)
|
393
|
+
#define PARTICLE_VERTS 4 // Number of vertices per particle
|
394
|
+
|
395
|
+
void DrawParticles( double t, float dt )
|
396
|
+
{
|
397
|
+
int i, particle_count;
|
398
|
+
VERTEX vertex_array[ BATCH_PARTICLES * PARTICLE_VERTS ], *vptr;
|
399
|
+
float alpha;
|
400
|
+
GLuint rgba;
|
401
|
+
VEC quad_lower_left, quad_lower_right;
|
402
|
+
GLfloat mat[ 16 ];
|
403
|
+
PARTICLE *pptr;
|
404
|
+
|
405
|
+
// Here comes the real trick with flat single primitive objects (s.c.
|
406
|
+
// "billboards"): We must rotate the textured primitive so that it
|
407
|
+
// always faces the viewer (is coplanar with the view-plane).
|
408
|
+
// We:
|
409
|
+
// 1) Create the primitive around origo (0,0,0)
|
410
|
+
// 2) Rotate it so that it is coplanar with the view plane
|
411
|
+
// 3) Translate it according to the particle position
|
412
|
+
// Note that 1) and 2) is the same for all particles (done only once).
|
413
|
+
|
414
|
+
// Get modelview matrix. We will only use the upper left 3x3 part of
|
415
|
+
// the matrix, which represents the rotation.
|
416
|
+
glGetFloatv( GL_MODELVIEW_MATRIX, mat );
|
417
|
+
|
418
|
+
// 1) & 2) We do it in one swift step:
|
419
|
+
// Although not obvious, the following six lines represent two matrix/
|
420
|
+
// vector multiplications. The matrix is the inverse 3x3 rotation
|
421
|
+
// matrix (i.e. the transpose of the same matrix), and the two vectors
|
422
|
+
// represent the lower left corner of the quad, PARTICLE_SIZE/2 *
|
423
|
+
// (-1,-1,0), and the lower right corner, PARTICLE_SIZE/2 * (1,-1,0).
|
424
|
+
// The upper left/right corners of the quad is always the negative of
|
425
|
+
// the opposite corners (regardless of rotation).
|
426
|
+
quad_lower_left.x = (-PARTICLE_SIZE/2) * (mat[0] + mat[1]);
|
427
|
+
quad_lower_left.y = (-PARTICLE_SIZE/2) * (mat[4] + mat[5]);
|
428
|
+
quad_lower_left.z = (-PARTICLE_SIZE/2) * (mat[8] + mat[9]);
|
429
|
+
quad_lower_right.x = (PARTICLE_SIZE/2) * (mat[0] - mat[1]);
|
430
|
+
quad_lower_right.y = (PARTICLE_SIZE/2) * (mat[4] - mat[5]);
|
431
|
+
quad_lower_right.z = (PARTICLE_SIZE/2) * (mat[8] - mat[9]);
|
432
|
+
|
433
|
+
// Don't update z-buffer, since all particles are transparent!
|
434
|
+
glDepthMask( GL_FALSE );
|
435
|
+
|
436
|
+
// Enable blending
|
437
|
+
glEnable( GL_BLEND );
|
438
|
+
glBlendFunc( GL_SRC_ALPHA, GL_ONE );
|
439
|
+
|
440
|
+
// Select particle texture
|
441
|
+
if( !wireframe )
|
442
|
+
{
|
443
|
+
glEnable( GL_TEXTURE_2D );
|
444
|
+
glBindTexture( GL_TEXTURE_2D, particle_tex_id );
|
445
|
+
}
|
446
|
+
|
447
|
+
// Set up vertex arrays. We use interleaved arrays, which is easier to
|
448
|
+
// handle (in most situations) and it gives a linear memeory access
|
449
|
+
// access pattern (which may give better performance in some
|
450
|
+
// situations). GL_T2F_C4UB_V3F means: 2 floats for texture coords,
|
451
|
+
// 4 ubytes for color and 3 floats for vertex coord (in that order).
|
452
|
+
// Most OpenGL cards / drivers are optimized for this format.
|
453
|
+
glInterleavedArrays( GL_T2F_C4UB_V3F, 0, vertex_array );
|
454
|
+
|
455
|
+
// Is particle physics carried out in a separate thread?
|
456
|
+
if( multithreading )
|
457
|
+
{
|
458
|
+
// Wait for particle physics thread to be done
|
459
|
+
glfwLockMutex( thread_sync.particles_lock );
|
460
|
+
while( running && thread_sync.p_frame <= thread_sync.d_frame )
|
461
|
+
{
|
462
|
+
glfwWaitCond( thread_sync.p_done, thread_sync.particles_lock,
|
463
|
+
0.1 );
|
464
|
+
}
|
465
|
+
|
466
|
+
// Store the frame time and delta time for the physics thread
|
467
|
+
thread_sync.t = t;
|
468
|
+
thread_sync.dt = dt;
|
469
|
+
|
470
|
+
// Update frame counter
|
471
|
+
thread_sync.d_frame ++;
|
472
|
+
}
|
473
|
+
else
|
474
|
+
{
|
475
|
+
// Perform particle physics in this thread
|
476
|
+
ParticleEngine( t, dt );
|
477
|
+
}
|
478
|
+
|
479
|
+
// Loop through all particles and build vertex arrays.
|
480
|
+
particle_count = 0;
|
481
|
+
vptr = vertex_array;
|
482
|
+
pptr = particles;
|
483
|
+
for( i = 0; i < MAX_PARTICLES; i ++ )
|
484
|
+
{
|
485
|
+
if( pptr->active )
|
486
|
+
{
|
487
|
+
// Calculate particle intensity (we set it to max during 75%
|
488
|
+
// of its life, then it fades out)
|
489
|
+
alpha = 4.0f * pptr->life;
|
490
|
+
if( alpha > 1.0f )
|
491
|
+
{
|
492
|
+
alpha = 1.0f;
|
493
|
+
}
|
494
|
+
|
495
|
+
// Convert color from float to 8-bit (store it in a 32-bit
|
496
|
+
// integer using endian independent type casting)
|
497
|
+
((GLubyte *)&rgba)[0] = (GLubyte)(pptr->r * 255.0f);
|
498
|
+
((GLubyte *)&rgba)[1] = (GLubyte)(pptr->g * 255.0f);
|
499
|
+
((GLubyte *)&rgba)[2] = (GLubyte)(pptr->b * 255.0f);
|
500
|
+
((GLubyte *)&rgba)[3] = (GLubyte)(alpha * 255.0f);
|
501
|
+
|
502
|
+
// 3) Translate the quad to the correct position in modelview
|
503
|
+
// space and store its parameters in vertex arrays (we also
|
504
|
+
// store texture coord and color information for each vertex).
|
505
|
+
|
506
|
+
// Lower left corner
|
507
|
+
vptr->s = 0.0f;
|
508
|
+
vptr->t = 0.0f;
|
509
|
+
vptr->rgba = rgba;
|
510
|
+
vptr->x = pptr->x + quad_lower_left.x;
|
511
|
+
vptr->y = pptr->y + quad_lower_left.y;
|
512
|
+
vptr->z = pptr->z + quad_lower_left.z;
|
513
|
+
vptr ++;
|
514
|
+
|
515
|
+
// Lower right corner
|
516
|
+
vptr->s = 1.0f;
|
517
|
+
vptr->t = 0.0f;
|
518
|
+
vptr->rgba = rgba;
|
519
|
+
vptr->x = pptr->x + quad_lower_right.x;
|
520
|
+
vptr->y = pptr->y + quad_lower_right.y;
|
521
|
+
vptr->z = pptr->z + quad_lower_right.z;
|
522
|
+
vptr ++;
|
523
|
+
|
524
|
+
// Upper right corner
|
525
|
+
vptr->s = 1.0f;
|
526
|
+
vptr->t = 1.0f;
|
527
|
+
vptr->rgba = rgba;
|
528
|
+
vptr->x = pptr->x - quad_lower_left.x;
|
529
|
+
vptr->y = pptr->y - quad_lower_left.y;
|
530
|
+
vptr->z = pptr->z - quad_lower_left.z;
|
531
|
+
vptr ++;
|
532
|
+
|
533
|
+
// Upper left corner
|
534
|
+
vptr->s = 0.0f;
|
535
|
+
vptr->t = 1.0f;
|
536
|
+
vptr->rgba = rgba;
|
537
|
+
vptr->x = pptr->x - quad_lower_right.x;
|
538
|
+
vptr->y = pptr->y - quad_lower_right.y;
|
539
|
+
vptr->z = pptr->z - quad_lower_right.z;
|
540
|
+
vptr ++;
|
541
|
+
|
542
|
+
// Increase count of drawable particles
|
543
|
+
particle_count ++;
|
544
|
+
}
|
545
|
+
|
546
|
+
// If we have filled up one batch of particles, draw it as a set
|
547
|
+
// of quads using glDrawArrays.
|
548
|
+
if( particle_count >= BATCH_PARTICLES )
|
549
|
+
{
|
550
|
+
// The first argument tells which primitive type we use (QUAD)
|
551
|
+
// The second argument tells the index of the first vertex (0)
|
552
|
+
// The last argument is the vertex count
|
553
|
+
glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count );
|
554
|
+
particle_count = 0;
|
555
|
+
vptr = vertex_array;
|
556
|
+
}
|
557
|
+
|
558
|
+
// Next particle
|
559
|
+
pptr ++;
|
560
|
+
}
|
561
|
+
|
562
|
+
// We are done with the particle data: Unlock mutex and signal physics
|
563
|
+
// thread
|
564
|
+
if( multithreading )
|
565
|
+
{
|
566
|
+
glfwUnlockMutex( thread_sync.particles_lock );
|
567
|
+
glfwSignalCond( thread_sync.d_done );
|
568
|
+
}
|
569
|
+
|
570
|
+
// Draw final batch of particles (if any)
|
571
|
+
glDrawArrays( GL_QUADS, 0, PARTICLE_VERTS * particle_count );
|
572
|
+
|
573
|
+
// Disable vertex arrays (Note: glInterleavedArrays implicitly called
|
574
|
+
// glEnableClientState for vertex, texture coord and color arrays)
|
575
|
+
glDisableClientState( GL_VERTEX_ARRAY );
|
576
|
+
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
577
|
+
glDisableClientState( GL_COLOR_ARRAY );
|
578
|
+
|
579
|
+
// Disable texturing and blending
|
580
|
+
glDisable( GL_TEXTURE_2D );
|
581
|
+
glDisable( GL_BLEND );
|
582
|
+
|
583
|
+
// Allow Z-buffer updates again
|
584
|
+
glDepthMask( GL_TRUE );
|
585
|
+
}
|
586
|
+
|
587
|
+
|
588
|
+
//========================================================================
|
589
|
+
// Fountain geometry specification
|
590
|
+
//========================================================================
|
591
|
+
|
592
|
+
#define FOUNTAIN_SIDE_POINTS 14
|
593
|
+
#define FOUNTAIN_SWEEP_STEPS 32
|
594
|
+
|
595
|
+
static const float fountain_side[ FOUNTAIN_SIDE_POINTS*2 ] = {
|
596
|
+
1.2f, 0.0f, 1.0f, 0.2f, 0.41f, 0.3f, 0.4f, 0.35f,
|
597
|
+
0.4f, 1.95f, 0.41f, 2.0f, 0.8f, 2.2f, 1.2f, 2.4f,
|
598
|
+
1.5f, 2.7f, 1.55f,2.95f, 1.6f, 3.0f, 1.0f, 3.0f,
|
599
|
+
0.5f, 3.0f, 0.0f, 3.0f
|
600
|
+
};
|
601
|
+
|
602
|
+
static const float fountain_normal[ FOUNTAIN_SIDE_POINTS*2 ] = {
|
603
|
+
1.0000f, 0.0000f, 0.6428f, 0.7660f, 0.3420f, 0.9397f, 1.0000f, 0.0000f,
|
604
|
+
1.0000f, 0.0000f, 0.3420f,-0.9397f, 0.4226f,-0.9063f, 0.5000f,-0.8660f,
|
605
|
+
0.7660f,-0.6428f, 0.9063f,-0.4226f, 0.0000f,1.00000f, 0.0000f,1.00000f,
|
606
|
+
0.0000f,1.00000f, 0.0000f,1.00000f
|
607
|
+
};
|
608
|
+
|
609
|
+
|
610
|
+
//========================================================================
|
611
|
+
// DrawFountain() - Draw a fountain
|
612
|
+
//========================================================================
|
613
|
+
|
614
|
+
void DrawFountain( void )
|
615
|
+
{
|
616
|
+
static GLuint fountain_list = 0;
|
617
|
+
double angle;
|
618
|
+
float x, y;
|
619
|
+
int m, n;
|
620
|
+
|
621
|
+
// The first time, we build the fountain display list
|
622
|
+
if( !fountain_list )
|
623
|
+
{
|
624
|
+
// Start recording of a new display list
|
625
|
+
fountain_list = glGenLists( 1 );
|
626
|
+
glNewList( fountain_list, GL_COMPILE_AND_EXECUTE );
|
627
|
+
|
628
|
+
// Set fountain material
|
629
|
+
glMaterialfv( GL_FRONT, GL_DIFFUSE, fountain_diffuse );
|
630
|
+
glMaterialfv( GL_FRONT, GL_SPECULAR, fountain_specular );
|
631
|
+
glMaterialf( GL_FRONT, GL_SHININESS, fountain_shininess );
|
632
|
+
|
633
|
+
// Build fountain using triangle strips
|
634
|
+
for( n = 0; n < FOUNTAIN_SIDE_POINTS-1; n ++ )
|
635
|
+
{
|
636
|
+
glBegin( GL_TRIANGLE_STRIP );
|
637
|
+
for( m = 0; m <= FOUNTAIN_SWEEP_STEPS; m ++ )
|
638
|
+
{
|
639
|
+
angle = (double) m * (2.0*M_PI/(double)FOUNTAIN_SWEEP_STEPS);
|
640
|
+
x = (float) cos( angle );
|
641
|
+
y = (float) sin( angle );
|
642
|
+
|
643
|
+
// Draw triangle strip
|
644
|
+
glNormal3f( x * fountain_normal[ n*2+2 ],
|
645
|
+
y * fountain_normal[ n*2+2 ],
|
646
|
+
fountain_normal[ n*2+3 ] );
|
647
|
+
glVertex3f( x * fountain_side[ n*2+2 ],
|
648
|
+
y * fountain_side[ n*2+2 ],
|
649
|
+
fountain_side[ n*2+3 ] );
|
650
|
+
glNormal3f( x * fountain_normal[ n*2 ],
|
651
|
+
y * fountain_normal[ n*2 ],
|
652
|
+
fountain_normal[ n*2+1 ] );
|
653
|
+
glVertex3f( x * fountain_side[ n*2 ],
|
654
|
+
y * fountain_side[ n*2 ],
|
655
|
+
fountain_side[ n*2+1 ] );
|
656
|
+
}
|
657
|
+
glEnd();
|
658
|
+
}
|
659
|
+
|
660
|
+
// End recording of display list
|
661
|
+
glEndList();
|
662
|
+
}
|
663
|
+
else
|
664
|
+
{
|
665
|
+
// Playback display list
|
666
|
+
glCallList( fountain_list );
|
667
|
+
}
|
668
|
+
}
|
669
|
+
|
670
|
+
|
671
|
+
//========================================================================
|
672
|
+
// TesselateFloor() - Recursive function for building variable tesselated
|
673
|
+
// floor
|
674
|
+
//========================================================================
|
675
|
+
|
676
|
+
void TesselateFloor( float x1, float y1, float x2, float y2,
|
677
|
+
int recursion )
|
678
|
+
{
|
679
|
+
float delta, x, y;
|
680
|
+
|
681
|
+
// Last recursion?
|
682
|
+
if( recursion >= 5 )
|
683
|
+
{
|
684
|
+
delta = 999999.0f;
|
685
|
+
}
|
686
|
+
else
|
687
|
+
{
|
688
|
+
x = fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2);
|
689
|
+
y = fabs(y1) < fabs(y2) ? fabs(y1) : fabs(y2);
|
690
|
+
delta = x*x + y*y;
|
691
|
+
}
|
692
|
+
|
693
|
+
// Recurse further?
|
694
|
+
if( delta < 0.1f )
|
695
|
+
{
|
696
|
+
x = (x1+x2) * 0.5f;
|
697
|
+
y = (y1+y2) * 0.5f;
|
698
|
+
TesselateFloor( x1,y1, x, y, recursion + 1 );
|
699
|
+
TesselateFloor( x,y1, x2, y, recursion + 1 );
|
700
|
+
TesselateFloor( x1, y, x,y2, recursion + 1 );
|
701
|
+
TesselateFloor( x, y, x2,y2, recursion + 1 );
|
702
|
+
}
|
703
|
+
else
|
704
|
+
{
|
705
|
+
glTexCoord2f( x1*30.0f, y1*30.0f );
|
706
|
+
glVertex3f( x1*80.0f, y1*80.0f , 0.0f );
|
707
|
+
glTexCoord2f( x2*30.0f, y1*30.0f );
|
708
|
+
glVertex3f( x2*80.0f, y1*80.0f , 0.0f );
|
709
|
+
glTexCoord2f( x2*30.0f, y2*30.0f );
|
710
|
+
glVertex3f( x2*80.0f, y2*80.0f , 0.0f );
|
711
|
+
glTexCoord2f( x1*30.0f, y2*30.0f );
|
712
|
+
glVertex3f( x1*80.0f, y2*80.0f , 0.0f );
|
713
|
+
}
|
714
|
+
}
|
715
|
+
|
716
|
+
|
717
|
+
//========================================================================
|
718
|
+
// DrawFloor() - Draw floor. We builde the floor recursively, and let the
|
719
|
+
// tesselation in the centre (near x,y=0,0) be high, while the selleation
|
720
|
+
// around the edges be low.
|
721
|
+
//========================================================================
|
722
|
+
|
723
|
+
void DrawFloor( void )
|
724
|
+
{
|
725
|
+
static GLuint floor_list = 0;
|
726
|
+
|
727
|
+
// Select floor texture
|
728
|
+
if( !wireframe )
|
729
|
+
{
|
730
|
+
glEnable( GL_TEXTURE_2D );
|
731
|
+
glBindTexture( GL_TEXTURE_2D, floor_tex_id );
|
732
|
+
}
|
733
|
+
|
734
|
+
// The first time, we build the floor display list
|
735
|
+
if( !floor_list )
|
736
|
+
{
|
737
|
+
// Start recording of a new display list
|
738
|
+
floor_list = glGenLists( 1 );
|
739
|
+
glNewList( floor_list, GL_COMPILE_AND_EXECUTE );
|
740
|
+
|
741
|
+
// Set floor material
|
742
|
+
glMaterialfv( GL_FRONT, GL_DIFFUSE, floor_diffuse );
|
743
|
+
glMaterialfv( GL_FRONT, GL_SPECULAR, floor_specular );
|
744
|
+
glMaterialf( GL_FRONT, GL_SHININESS, floor_shininess );
|
745
|
+
|
746
|
+
// Draw floor as a bunch of triangle strips (high tesselation
|
747
|
+
// improves lighting)
|
748
|
+
glNormal3f( 0.0f, 0.0f, 1.0f );
|
749
|
+
glBegin( GL_QUADS );
|
750
|
+
TesselateFloor( -1.0f,-1.0f, 0.0f,0.0f, 0 );
|
751
|
+
TesselateFloor( 0.0f,-1.0f, 1.0f,0.0f, 0 );
|
752
|
+
TesselateFloor( 0.0f, 0.0f, 1.0f,1.0f, 0 );
|
753
|
+
TesselateFloor( -1.0f, 0.0f, 0.0f,1.0f, 0 );
|
754
|
+
glEnd();
|
755
|
+
|
756
|
+
// End recording of display list
|
757
|
+
glEndList();
|
758
|
+
}
|
759
|
+
else
|
760
|
+
{
|
761
|
+
// Playback display list
|
762
|
+
glCallList( floor_list );
|
763
|
+
}
|
764
|
+
|
765
|
+
glDisable( GL_TEXTURE_2D );
|
766
|
+
|
767
|
+
}
|
768
|
+
|
769
|
+
|
770
|
+
//========================================================================
|
771
|
+
// SetupLights() - Position and configure light sources
|
772
|
+
//========================================================================
|
773
|
+
|
774
|
+
void SetupLights( void )
|
775
|
+
{
|
776
|
+
float l1pos[4], l1amb[4], l1dif[4], l1spec[4];
|
777
|
+
float l2pos[4], l2amb[4], l2dif[4], l2spec[4];
|
778
|
+
|
779
|
+
// Set light source 1 parameters
|
780
|
+
l1pos[0] = 0.0f; l1pos[1] = -9.0f; l1pos[2] = 8.0f; l1pos[3] = 1.0f;
|
781
|
+
l1amb[0] = 0.2f; l1amb[1] = 0.2f; l1amb[2] = 0.2f; l1amb[3] = 1.0f;
|
782
|
+
l1dif[0] = 0.8f; l1dif[1] = 0.4f; l1dif[2] = 0.2f; l1dif[3] = 1.0f;
|
783
|
+
l1spec[0] = 1.0f; l1spec[1] = 0.6f; l1spec[2] = 0.2f; l1spec[3] = 0.0f;
|
784
|
+
|
785
|
+
// Set light source 2 parameters
|
786
|
+
l2pos[0] = -15.0f; l2pos[1] = 12.0f; l2pos[2] = 1.5f; l2pos[3] = 1.0f;
|
787
|
+
l2amb[0] = 0.0f; l2amb[1] = 0.0f; l2amb[2] = 0.0f; l2amb[3] = 1.0f;
|
788
|
+
l2dif[0] = 0.2f; l2dif[1] = 0.4f; l2dif[2] = 0.8f; l2dif[3] = 1.0f;
|
789
|
+
l2spec[0] = 0.2f; l2spec[1] = 0.6f; l2spec[2] = 1.0f; l2spec[3] = 0.0f;
|
790
|
+
|
791
|
+
// Configure light sources in OpenGL
|
792
|
+
glLightfv( GL_LIGHT1, GL_POSITION, l1pos );
|
793
|
+
glLightfv( GL_LIGHT1, GL_AMBIENT, l1amb );
|
794
|
+
glLightfv( GL_LIGHT1, GL_DIFFUSE, l1dif );
|
795
|
+
glLightfv( GL_LIGHT1, GL_SPECULAR, l1spec );
|
796
|
+
glLightfv( GL_LIGHT2, GL_POSITION, l2pos );
|
797
|
+
glLightfv( GL_LIGHT2, GL_AMBIENT, l2amb );
|
798
|
+
glLightfv( GL_LIGHT2, GL_DIFFUSE, l2dif );
|
799
|
+
glLightfv( GL_LIGHT2, GL_SPECULAR, l2spec );
|
800
|
+
glLightfv( GL_LIGHT3, GL_POSITION, glow_pos );
|
801
|
+
glLightfv( GL_LIGHT3, GL_DIFFUSE, glow_color );
|
802
|
+
glLightfv( GL_LIGHT3, GL_SPECULAR, glow_color );
|
803
|
+
|
804
|
+
// Enable light sources
|
805
|
+
glEnable( GL_LIGHT1 );
|
806
|
+
glEnable( GL_LIGHT2 );
|
807
|
+
glEnable( GL_LIGHT3 );
|
808
|
+
}
|
809
|
+
|
810
|
+
|
811
|
+
//========================================================================
|
812
|
+
// Draw() - Main rendering function
|
813
|
+
//========================================================================
|
814
|
+
|
815
|
+
void Draw( double t )
|
816
|
+
{
|
817
|
+
double xpos, ypos, zpos, angle_x, angle_y, angle_z;
|
818
|
+
static double t_old = 0.0;
|
819
|
+
float dt;
|
820
|
+
|
821
|
+
// Calculate frame-to-frame delta time
|
822
|
+
dt = (float)(t-t_old);
|
823
|
+
t_old = t;
|
824
|
+
|
825
|
+
// Setup viewport
|
826
|
+
glViewport( 0, 0, width, height );
|
827
|
+
|
828
|
+
// Clear color and Z-buffer
|
829
|
+
glClearColor( 0.1f, 0.1f, 0.1f, 1.0f );
|
830
|
+
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
831
|
+
|
832
|
+
// Setup projection
|
833
|
+
glMatrixMode( GL_PROJECTION );
|
834
|
+
glLoadIdentity();
|
835
|
+
gluPerspective( 65.0, (double)width/(double)height, 1.0, 60.0 );
|
836
|
+
|
837
|
+
// Setup camera
|
838
|
+
glMatrixMode( GL_MODELVIEW );
|
839
|
+
glLoadIdentity();
|
840
|
+
|
841
|
+
// Rotate camera
|
842
|
+
angle_x = 90.0 - 10.0;
|
843
|
+
angle_y = 10.0 * sin( 0.3 * t );
|
844
|
+
angle_z = 10.0 * t;
|
845
|
+
glRotated( -angle_x, 1.0, 0.0, 0.0 );
|
846
|
+
glRotated( -angle_y, 0.0, 1.0, 0.0 );
|
847
|
+
glRotated( -angle_z, 0.0, 0.0, 1.0 );
|
848
|
+
|
849
|
+
// Translate camera
|
850
|
+
xpos = 15.0 * sin( (M_PI/180.0) * angle_z ) +
|
851
|
+
2.0 * sin( (M_PI/180.0) * 3.1 * t );
|
852
|
+
ypos = -15.0 * cos( (M_PI/180.0) * angle_z ) +
|
853
|
+
2.0 * cos( (M_PI/180.0) * 2.9 * t );
|
854
|
+
zpos = 4.0 + 2.0 * cos( (M_PI/180.0) * 4.9 * t );
|
855
|
+
glTranslated( -xpos, -ypos, -zpos );
|
856
|
+
|
857
|
+
// Enable face culling
|
858
|
+
glFrontFace( GL_CCW );
|
859
|
+
glCullFace( GL_BACK );
|
860
|
+
glEnable( GL_CULL_FACE );
|
861
|
+
|
862
|
+
// Enable lighting
|
863
|
+
SetupLights();
|
864
|
+
glEnable( GL_LIGHTING );
|
865
|
+
|
866
|
+
// Enable fog (dim details far away)
|
867
|
+
glEnable( GL_FOG );
|
868
|
+
glFogi( GL_FOG_MODE, GL_EXP );
|
869
|
+
glFogf( GL_FOG_DENSITY, 0.05f );
|
870
|
+
glFogfv( GL_FOG_COLOR, fog_color );
|
871
|
+
|
872
|
+
// Draw floor
|
873
|
+
DrawFloor();
|
874
|
+
|
875
|
+
// Enable Z-buffering
|
876
|
+
glEnable( GL_DEPTH_TEST );
|
877
|
+
glDepthFunc( GL_LEQUAL );
|
878
|
+
glDepthMask( GL_TRUE );
|
879
|
+
|
880
|
+
// Draw fountain
|
881
|
+
DrawFountain();
|
882
|
+
|
883
|
+
// Disable fog & lighting
|
884
|
+
glDisable( GL_LIGHTING );
|
885
|
+
glDisable( GL_FOG );
|
886
|
+
|
887
|
+
// Draw all particles (must be drawn after all solid objects have been
|
888
|
+
// drawn!)
|
889
|
+
DrawParticles( t, dt );
|
890
|
+
|
891
|
+
// Z-buffer not needed anymore
|
892
|
+
glDisable( GL_DEPTH_TEST );
|
893
|
+
}
|
894
|
+
|
895
|
+
|
896
|
+
//========================================================================
|
897
|
+
// Resize() - GLFW window resize callback function
|
898
|
+
//========================================================================
|
899
|
+
|
900
|
+
void GLFWCALL Resize( int x, int y )
|
901
|
+
{
|
902
|
+
width = x;
|
903
|
+
height = y > 0 ? y : 1; // Prevent division by zero in aspect calc.
|
904
|
+
}
|
905
|
+
|
906
|
+
|
907
|
+
//========================================================================
|
908
|
+
// Input callback functions
|
909
|
+
//========================================================================
|
910
|
+
|
911
|
+
void GLFWCALL KeyFun( int key, int action )
|
912
|
+
{
|
913
|
+
if( action == GLFW_PRESS )
|
914
|
+
{
|
915
|
+
switch( key )
|
916
|
+
{
|
917
|
+
case GLFW_KEY_ESC:
|
918
|
+
running = 0;
|
919
|
+
break;
|
920
|
+
case 'W':
|
921
|
+
wireframe = !wireframe;
|
922
|
+
glPolygonMode( GL_FRONT_AND_BACK,
|
923
|
+
wireframe ? GL_LINE : GL_FILL );
|
924
|
+
break;
|
925
|
+
default:
|
926
|
+
break;
|
927
|
+
}
|
928
|
+
}
|
929
|
+
}
|
930
|
+
|
931
|
+
|
932
|
+
//========================================================================
|
933
|
+
// PhysicsThreadFun() - Thread for updating particle physics
|
934
|
+
//========================================================================
|
935
|
+
|
936
|
+
void GLFWCALL PhysicsThreadFun( void *arg )
|
937
|
+
{
|
938
|
+
while( running )
|
939
|
+
{
|
940
|
+
// Lock mutex
|
941
|
+
glfwLockMutex( thread_sync.particles_lock );
|
942
|
+
|
943
|
+
// Wait for particle drawing to be done
|
944
|
+
while( running && thread_sync.p_frame > thread_sync.d_frame )
|
945
|
+
{
|
946
|
+
glfwWaitCond( thread_sync.d_done, thread_sync.particles_lock,
|
947
|
+
0.1 );
|
948
|
+
}
|
949
|
+
|
950
|
+
// No longer running?
|
951
|
+
if( !running )
|
952
|
+
{
|
953
|
+
break;
|
954
|
+
}
|
955
|
+
|
956
|
+
// Update particles
|
957
|
+
ParticleEngine( thread_sync.t, thread_sync.dt );
|
958
|
+
|
959
|
+
// Update frame counter
|
960
|
+
thread_sync.p_frame ++;
|
961
|
+
|
962
|
+
// Unlock mutex and signal drawing thread
|
963
|
+
glfwUnlockMutex( thread_sync.particles_lock );
|
964
|
+
glfwSignalCond( thread_sync.p_done );
|
965
|
+
}
|
966
|
+
}
|
967
|
+
|
968
|
+
|
969
|
+
//========================================================================
|
970
|
+
// main()
|
971
|
+
//========================================================================
|
972
|
+
|
973
|
+
int main( int argc, char **argv )
|
974
|
+
{
|
975
|
+
int i, frames, benchmark;
|
976
|
+
double t0, t;
|
977
|
+
GLFWthread physics_thread = 0;
|
978
|
+
|
979
|
+
// Use multithreading by default, but don't benchmark
|
980
|
+
multithreading = 1;
|
981
|
+
benchmark = 0;
|
982
|
+
|
983
|
+
// Check command line arguments
|
984
|
+
for( i = 1; i < argc; i ++ )
|
985
|
+
{
|
986
|
+
// Use benchmarking?
|
987
|
+
if( strcmp( argv[i], "-b" ) == 0 )
|
988
|
+
{
|
989
|
+
benchmark = 1;
|
990
|
+
}
|
991
|
+
|
992
|
+
// Force multithreading off?
|
993
|
+
else if( strcmp( argv[i], "-s" ) == 0 )
|
994
|
+
{
|
995
|
+
multithreading = 0;
|
996
|
+
}
|
997
|
+
|
998
|
+
// With a Finder launch on Mac OS X we get a bogus -psn_0_46268417
|
999
|
+
// kind of argument (actual numbers vary). Ignore it.
|
1000
|
+
else if( strncmp( argv[i], "-psn_", 5) == 0 );
|
1001
|
+
|
1002
|
+
// Usage
|
1003
|
+
else
|
1004
|
+
{
|
1005
|
+
if( strcmp( argv[i], "-?" ) != 0 )
|
1006
|
+
{
|
1007
|
+
printf( "Unknonwn option %s\n\n", argv[ i ] );
|
1008
|
+
}
|
1009
|
+
printf( "Usage: %s [options]\n", argv[ 0 ] );
|
1010
|
+
printf( "\n");
|
1011
|
+
printf( "Options:\n" );
|
1012
|
+
printf( " -b Benchmark (run program for 60 s)\n" );
|
1013
|
+
printf( " -s Run program as single thread (default is to use two threads)\n" );
|
1014
|
+
printf( " -? Display this text\n" );
|
1015
|
+
printf( "\n");
|
1016
|
+
printf( "Program runtime controls:\n" );
|
1017
|
+
printf( " w Toggle wireframe mode\n" );
|
1018
|
+
printf( " ESC Exit program\n" );
|
1019
|
+
exit( 0 );
|
1020
|
+
}
|
1021
|
+
}
|
1022
|
+
|
1023
|
+
// Initialize GLFW
|
1024
|
+
glfwInit();
|
1025
|
+
|
1026
|
+
// Open OpenGL fullscreen window
|
1027
|
+
if( !glfwOpenWindow( WIDTH, HEIGHT, 5,6,5,0, 16,0, GLFW_FULLSCREEN ) )
|
1028
|
+
{
|
1029
|
+
glfwTerminate();
|
1030
|
+
exit( 0 );
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
// Set window title
|
1034
|
+
glfwSetWindowTitle( "Particle engine" );
|
1035
|
+
|
1036
|
+
// Disable VSync (we want to get as high FPS as possible!)
|
1037
|
+
glfwSwapInterval( 0 );
|
1038
|
+
|
1039
|
+
// Window resize callback function
|
1040
|
+
glfwSetWindowSizeCallback( Resize );
|
1041
|
+
|
1042
|
+
// Set keyboard input callback function
|
1043
|
+
glfwSetKeyCallback( KeyFun );
|
1044
|
+
|
1045
|
+
// Upload particle texture
|
1046
|
+
glGenTextures( 1, &particle_tex_id );
|
1047
|
+
glBindTexture( GL_TEXTURE_2D, particle_tex_id );
|
1048
|
+
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
|
1049
|
+
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
|
1050
|
+
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
|
1051
|
+
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
1052
|
+
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
1053
|
+
glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, P_TEX_WIDTH, P_TEX_HEIGHT,
|
1054
|
+
0, GL_LUMINANCE, GL_UNSIGNED_BYTE, particle_texture );
|
1055
|
+
|
1056
|
+
// Upload floor texture
|
1057
|
+
glGenTextures( 1, &floor_tex_id );
|
1058
|
+
glBindTexture( GL_TEXTURE_2D, floor_tex_id );
|
1059
|
+
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
|
1060
|
+
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
|
1061
|
+
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
|
1062
|
+
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
1063
|
+
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
1064
|
+
glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, F_TEX_WIDTH, F_TEX_HEIGHT,
|
1065
|
+
0, GL_LUMINANCE, GL_UNSIGNED_BYTE, floor_texture );
|
1066
|
+
|
1067
|
+
// Check if we have GL_EXT_separate_specular_color, and if so use it
|
1068
|
+
// (This extension should ALWAYS be used when OpenGL lighting is used
|
1069
|
+
// together with texturing, since it gives more realistic results)
|
1070
|
+
if( glfwExtensionSupported( "GL_EXT_separate_specular_color" ) )
|
1071
|
+
{
|
1072
|
+
glLightModeli( GL_LIGHT_MODEL_COLOR_CONTROL_EXT,
|
1073
|
+
GL_SEPARATE_SPECULAR_COLOR_EXT );
|
1074
|
+
}
|
1075
|
+
|
1076
|
+
// Set filled polygon mode as default (not wireframe)
|
1077
|
+
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
|
1078
|
+
wireframe = 0;
|
1079
|
+
|
1080
|
+
// Clear particle system
|
1081
|
+
for( i = 0; i < MAX_PARTICLES; i ++ )
|
1082
|
+
{
|
1083
|
+
particles[ i ].active = 0;
|
1084
|
+
}
|
1085
|
+
min_age = 0.0f;
|
1086
|
+
|
1087
|
+
// Set "running" flag
|
1088
|
+
running = 1;
|
1089
|
+
|
1090
|
+
// Set initial times
|
1091
|
+
thread_sync.t = 0.0;
|
1092
|
+
thread_sync.dt = 0.001f;
|
1093
|
+
|
1094
|
+
// Init threading
|
1095
|
+
if( multithreading )
|
1096
|
+
{
|
1097
|
+
thread_sync.p_frame = 0;
|
1098
|
+
thread_sync.d_frame = 0;
|
1099
|
+
thread_sync.particles_lock = glfwCreateMutex();
|
1100
|
+
thread_sync.p_done = glfwCreateCond();
|
1101
|
+
thread_sync.d_done = glfwCreateCond();
|
1102
|
+
physics_thread = glfwCreateThread( PhysicsThreadFun, NULL );
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
// Main loop
|
1106
|
+
t0 = glfwGetTime();
|
1107
|
+
frames = 0;
|
1108
|
+
while( running )
|
1109
|
+
{
|
1110
|
+
// Get frame time
|
1111
|
+
t = glfwGetTime() - t0;
|
1112
|
+
|
1113
|
+
// Draw...
|
1114
|
+
Draw( t );
|
1115
|
+
|
1116
|
+
// Swap buffers
|
1117
|
+
glfwSwapBuffers();
|
1118
|
+
|
1119
|
+
// Check if window was closed
|
1120
|
+
running = running && glfwGetWindowParam( GLFW_OPENED );
|
1121
|
+
|
1122
|
+
// Increase frame count
|
1123
|
+
frames ++;
|
1124
|
+
|
1125
|
+
// End of benchmark?
|
1126
|
+
if( benchmark && t >= 60.0 )
|
1127
|
+
{
|
1128
|
+
running = 0;
|
1129
|
+
}
|
1130
|
+
}
|
1131
|
+
t = glfwGetTime() - t0;
|
1132
|
+
|
1133
|
+
// Wait for particle physics thread to die
|
1134
|
+
if( multithreading )
|
1135
|
+
{
|
1136
|
+
glfwWaitThread( physics_thread, GLFW_WAIT );
|
1137
|
+
}
|
1138
|
+
|
1139
|
+
// Display profiling information
|
1140
|
+
printf( "%d frames in %.2f seconds = %.1f FPS", frames, t,
|
1141
|
+
(double)frames / t );
|
1142
|
+
printf( " (multithreading %s)\n", multithreading ? "on" : "off" );
|
1143
|
+
|
1144
|
+
// Terminate OpenGL
|
1145
|
+
glfwTerminate();
|
1146
|
+
|
1147
|
+
return 0;
|
1148
|
+
}
|