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