ruby-glfw 0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (206) hide show
  1. data/README +1 -0
  2. data/README.API +73 -0
  3. data/Rakefile +120 -0
  4. data/examples/boing.rb +519 -0
  5. data/examples/gears.rb +327 -0
  6. data/examples/keytest.rb +117 -0
  7. data/examples/listmodes.rb +20 -0
  8. data/examples/mipmaps.rb +104 -0
  9. data/examples/mipmaps.tga +0 -0
  10. data/examples/particles.rb +837 -0
  11. data/examples/pong3d.rb +741 -0
  12. data/examples/pong3d_field.tga +0 -0
  13. data/examples/pong3d_instr.tga +0 -0
  14. data/examples/pong3d_menu.tga +0 -0
  15. data/examples/pong3d_title.tga +0 -0
  16. data/examples/pong3d_winner1.tga +0 -0
  17. data/examples/pong3d_winner2.tga +0 -0
  18. data/examples/splitview.rb +432 -0
  19. data/examples/triangle.rb +89 -0
  20. data/examples/wave.rb +294 -0
  21. data/ext/glfw/glfw.c +1094 -0
  22. data/ext/glfw/mkrf_conf.rb +70 -0
  23. data/glfw-src/Makefile +220 -0
  24. data/glfw-src/compile.ami +61 -0
  25. data/glfw-src/compile.bat +217 -0
  26. data/glfw-src/compile.sh +607 -0
  27. data/glfw-src/docs/Makefile +57 -0
  28. data/glfw-src/docs/Reference.pdf +0 -0
  29. data/glfw-src/docs/UsersGuide.pdf +0 -0
  30. data/glfw-src/docs/cleanup.bat +22 -0
  31. data/glfw-src/docs/glfwdoc.sty +80 -0
  32. data/glfw-src/docs/glfwrm.tex +3034 -0
  33. data/glfw-src/docs/glfwug.tex +2024 -0
  34. data/glfw-src/docs/readme.txt +80 -0
  35. data/glfw-src/examples/Makefile.amigaos.gcc +70 -0
  36. data/glfw-src/examples/Makefile.amigaos.vbcc +70 -0
  37. data/glfw-src/examples/Makefile.dos.djgpp +71 -0
  38. data/glfw-src/examples/Makefile.macosx.gcc +96 -0
  39. data/glfw-src/examples/Makefile.win32.bcc +75 -0
  40. data/glfw-src/examples/Makefile.win32.cross-mgw +79 -0
  41. data/glfw-src/examples/Makefile.win32.cygwin +79 -0
  42. data/glfw-src/examples/Makefile.win32.lcc +74 -0
  43. data/glfw-src/examples/Makefile.win32.mgw +75 -0
  44. data/glfw-src/examples/Makefile.win32.msvc +74 -0
  45. data/glfw-src/examples/Makefile.win32.ow +74 -0
  46. data/glfw-src/examples/Makefile.win32.pellesc +74 -0
  47. data/glfw-src/examples/Makefile.x11.in +54 -0
  48. data/glfw-src/examples/boing.c +606 -0
  49. data/glfw-src/examples/bundle.sh +46 -0
  50. data/glfw-src/examples/gears.c +382 -0
  51. data/glfw-src/examples/keytest.c +264 -0
  52. data/glfw-src/examples/listmodes.c +48 -0
  53. data/glfw-src/examples/mipmaps.c +126 -0
  54. data/glfw-src/examples/mipmaps.tga +0 -0
  55. data/glfw-src/examples/mtbench.c +301 -0
  56. data/glfw-src/examples/mthello.c +48 -0
  57. data/glfw-src/examples/particles.c +1148 -0
  58. data/glfw-src/examples/pong3d.c +839 -0
  59. data/glfw-src/examples/pong3d_field.tga +0 -0
  60. data/glfw-src/examples/pong3d_instr.tga +0 -0
  61. data/glfw-src/examples/pong3d_menu.tga +0 -0
  62. data/glfw-src/examples/pong3d_title.tga +0 -0
  63. data/glfw-src/examples/pong3d_winner1.tga +0 -0
  64. data/glfw-src/examples/pong3d_winner2.tga +0 -0
  65. data/glfw-src/examples/splitview.c +506 -0
  66. data/glfw-src/examples/triangle.c +108 -0
  67. data/glfw-src/examples/wave.c +397 -0
  68. data/glfw-src/images/opengl.gif +0 -0
  69. data/glfw-src/images/osicert.gif +0 -0
  70. data/glfw-src/include/GL/glfw.h +486 -0
  71. data/glfw-src/lib/amigaos/Makefile.amigaos.gcc +128 -0
  72. data/glfw-src/lib/amigaos/Makefile.amigaos.vbcc +128 -0
  73. data/glfw-src/lib/amigaos/SDI_compiler.h +94 -0
  74. data/glfw-src/lib/amigaos/amigaos_enable.c +51 -0
  75. data/glfw-src/lib/amigaos/amigaos_fullscreen.c +319 -0
  76. data/glfw-src/lib/amigaos/amigaos_glext.c +61 -0
  77. data/glfw-src/lib/amigaos/amigaos_init.c +284 -0
  78. data/glfw-src/lib/amigaos/amigaos_joystick.c +359 -0
  79. data/glfw-src/lib/amigaos/amigaos_thread.c +494 -0
  80. data/glfw-src/lib/amigaos/amigaos_time.c +206 -0
  81. data/glfw-src/lib/amigaos/amigaos_window.c +830 -0
  82. data/glfw-src/lib/amigaos/platform.h +337 -0
  83. data/glfw-src/lib/dos/Makefile.dos.djgpp +146 -0
  84. data/glfw-src/lib/dos/dos_enable.c +51 -0
  85. data/glfw-src/lib/dos/dos_events.c +173 -0
  86. data/glfw-src/lib/dos/dos_fullscreen.c +101 -0
  87. data/glfw-src/lib/dos/dos_glext.c +59 -0
  88. data/glfw-src/lib/dos/dos_init.c +105 -0
  89. data/glfw-src/lib/dos/dos_irq.s +246 -0
  90. data/glfw-src/lib/dos/dos_joystick.c +94 -0
  91. data/glfw-src/lib/dos/dos_keyboard.c +694 -0
  92. data/glfw-src/lib/dos/dos_mouse.c +337 -0
  93. data/glfw-src/lib/dos/dos_thread.c +267 -0
  94. data/glfw-src/lib/dos/dos_time.c +309 -0
  95. data/glfw-src/lib/dos/dos_window.c +563 -0
  96. data/glfw-src/lib/dos/platform.h +341 -0
  97. data/glfw-src/lib/enable.c +295 -0
  98. data/glfw-src/lib/fullscreen.c +95 -0
  99. data/glfw-src/lib/glext.c +201 -0
  100. data/glfw-src/lib/image.c +629 -0
  101. data/glfw-src/lib/init.c +108 -0
  102. data/glfw-src/lib/input.c +280 -0
  103. data/glfw-src/lib/internal.h +210 -0
  104. data/glfw-src/lib/joystick.c +101 -0
  105. data/glfw-src/lib/macosx/Makefile.macosx.gcc +172 -0
  106. data/glfw-src/lib/macosx/Makefile.macosx.gcc.universal +166 -0
  107. data/glfw-src/lib/macosx/libglfw.pc.in +11 -0
  108. data/glfw-src/lib/macosx/macosx_enable.c +42 -0
  109. data/glfw-src/lib/macosx/macosx_fullscreen.c +126 -0
  110. data/glfw-src/lib/macosx/macosx_glext.c +52 -0
  111. data/glfw-src/lib/macosx/macosx_init.c +194 -0
  112. data/glfw-src/lib/macosx/macosx_joystick.c +50 -0
  113. data/glfw-src/lib/macosx/macosx_thread.c +414 -0
  114. data/glfw-src/lib/macosx/macosx_time.c +112 -0
  115. data/glfw-src/lib/macosx/macosx_window.c +1279 -0
  116. data/glfw-src/lib/macosx/platform.h +349 -0
  117. data/glfw-src/lib/stream.c +194 -0
  118. data/glfw-src/lib/tga.c +405 -0
  119. data/glfw-src/lib/thread.c +340 -0
  120. data/glfw-src/lib/time.c +83 -0
  121. data/glfw-src/lib/win32/Makefile.win32.bcc +265 -0
  122. data/glfw-src/lib/win32/Makefile.win32.cross-mgw +274 -0
  123. data/glfw-src/lib/win32/Makefile.win32.cygwin +279 -0
  124. data/glfw-src/lib/win32/Makefile.win32.lcc +246 -0
  125. data/glfw-src/lib/win32/Makefile.win32.mgw +243 -0
  126. data/glfw-src/lib/win32/Makefile.win32.msvc +242 -0
  127. data/glfw-src/lib/win32/Makefile.win32.ow +242 -0
  128. data/glfw-src/lib/win32/Makefile.win32.pellesc +242 -0
  129. data/glfw-src/lib/win32/glfwdll.def +67 -0
  130. data/glfw-src/lib/win32/glfwdll_mgw1.def +67 -0
  131. data/glfw-src/lib/win32/glfwdll_mgw2.def +67 -0
  132. data/glfw-src/lib/win32/glfwdll_pellesc.def +65 -0
  133. data/glfw-src/lib/win32/libglfw.pc.in +11 -0
  134. data/glfw-src/lib/win32/platform.h +474 -0
  135. data/glfw-src/lib/win32/win32_dllmain.c +60 -0
  136. data/glfw-src/lib/win32/win32_enable.c +155 -0
  137. data/glfw-src/lib/win32/win32_fullscreen.c +317 -0
  138. data/glfw-src/lib/win32/win32_glext.c +85 -0
  139. data/glfw-src/lib/win32/win32_init.c +356 -0
  140. data/glfw-src/lib/win32/win32_joystick.c +234 -0
  141. data/glfw-src/lib/win32/win32_thread.c +511 -0
  142. data/glfw-src/lib/win32/win32_time.c +146 -0
  143. data/glfw-src/lib/win32/win32_window.c +1714 -0
  144. data/glfw-src/lib/window.c +727 -0
  145. data/glfw-src/lib/x11/Makefile.x11.in +243 -0
  146. data/glfw-src/lib/x11/platform.h +415 -0
  147. data/glfw-src/lib/x11/x11_enable.c +51 -0
  148. data/glfw-src/lib/x11/x11_fullscreen.c +524 -0
  149. data/glfw-src/lib/x11/x11_glext.c +69 -0
  150. data/glfw-src/lib/x11/x11_init.c +275 -0
  151. data/glfw-src/lib/x11/x11_joystick.c +371 -0
  152. data/glfw-src/lib/x11/x11_keysym2unicode.c +902 -0
  153. data/glfw-src/lib/x11/x11_thread.c +507 -0
  154. data/glfw-src/lib/x11/x11_time.c +154 -0
  155. data/glfw-src/lib/x11/x11_window.c +1746 -0
  156. data/glfw-src/license.txt +21 -0
  157. data/glfw-src/readme.html +927 -0
  158. data/glfw-src/support/d/examples/Makefile +59 -0
  159. data/glfw-src/support/d/examples/boing.d +610 -0
  160. data/glfw-src/support/d/examples/gears.d +379 -0
  161. data/glfw-src/support/d/examples/keytest.d +272 -0
  162. data/glfw-src/support/d/examples/listmodes.d +48 -0
  163. data/glfw-src/support/d/examples/mipmaps.d +126 -0
  164. data/glfw-src/support/d/examples/mtbench.d +304 -0
  165. data/glfw-src/support/d/examples/mthello.d +54 -0
  166. data/glfw-src/support/d/examples/particles.d +1150 -0
  167. data/glfw-src/support/d/examples/pong3d.d +840 -0
  168. data/glfw-src/support/d/examples/splitview.d +486 -0
  169. data/glfw-src/support/d/examples/triangle.d +108 -0
  170. data/glfw-src/support/d/examples/wave.d +400 -0
  171. data/glfw-src/support/d/imports/gl.d +4539 -0
  172. data/glfw-src/support/d/imports/glfw.d +349 -0
  173. data/glfw-src/support/d/imports/glu.d +328 -0
  174. data/glfw-src/support/d/lib/glfwdll.def +64 -0
  175. data/glfw-src/support/d/lib/glu32.def +56 -0
  176. data/glfw-src/support/d/lib/makefile +12 -0
  177. data/glfw-src/support/d/lib/opengl32.def +372 -0
  178. data/glfw-src/support/d/readme.html +83 -0
  179. data/glfw-src/support/delphi/examples/Triangle.dpr +105 -0
  180. data/glfw-src/support/delphi/lib/glfw.pas +437 -0
  181. data/glfw-src/support/delphi/readme.html +97 -0
  182. data/glfw-src/support/lua/examples/gears.lua +383 -0
  183. data/glfw-src/support/lua/examples/test1.lua +68 -0
  184. data/glfw-src/support/lua/readme.html +128 -0
  185. data/glfw-src/support/lua/src/luaglfw.c +1179 -0
  186. data/glfw-src/support/lua/src/luaglfw.h +48 -0
  187. data/glfw-src/support/lua/src/runlua.c +82 -0
  188. data/glfw-src/support/masm/examples/fpc.mac +47 -0
  189. data/glfw-src/support/masm/examples/makeit.bat +66 -0
  190. data/glfw-src/support/masm/examples/triangle.asm +232 -0
  191. data/glfw-src/support/masm/include/glfw.inc +326 -0
  192. data/glfw-src/support/masm/include/glu32.inc +55 -0
  193. data/glfw-src/support/masm/include/opengl32.inc +372 -0
  194. data/glfw-src/support/masm/lib/glfwdll.lib +0 -0
  195. data/glfw-src/support/masm/readme.html +170 -0
  196. data/glfw-src/support/msvc80/GLFW.sln +26 -0
  197. data/glfw-src/support/msvc80/GLFW.vcproj +257 -0
  198. data/glfw-src/support/msvc80/GLFWDLL.vcproj +287 -0
  199. data/glfw-src/support/visualbasic/bindings/glfw.bas +320 -0
  200. data/glfw-src/support/visualbasic/bindings/glu32.bas +284 -0
  201. data/glfw-src/support/visualbasic/bindings/opengl32.bas +999 -0
  202. data/glfw-src/support/visualbasic/examples/Triangle.bas +101 -0
  203. data/glfw-src/support/visualbasic/readme.html +164 -0
  204. data/website/index.html +84 -0
  205. data/website/style.css +110 -0
  206. 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
+ }