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