ruby-glfw 0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }