blackbook3d 0.5.0

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 (134) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +341 -0
  3. data/README.md +92 -0
  4. data/SETUP.md +70 -0
  5. data/data/assets/Texture/A011a.tga +0 -0
  6. data/data/assets/untitled.awp3d +0 -0
  7. data/data/cube.mtl +12 -0
  8. data/data/cube.obj +246 -0
  9. data/data/cube.raw +12 -0
  10. data/data/engine_conf.json +9 -0
  11. data/data/fighter.raw +19198 -0
  12. data/data/font/100.raw +78 -0
  13. data/data/font/101.raw +99 -0
  14. data/data/font/102.raw +58 -0
  15. data/data/font/103.raw +258 -0
  16. data/data/font/104.raw +55 -0
  17. data/data/font/105.raw +48 -0
  18. data/data/font/106.raw +72 -0
  19. data/data/font/107.raw +6 -0
  20. data/data/font/108.raw +2 -0
  21. data/data/font/109.raw +105 -0
  22. data/data/font/110.raw +55 -0
  23. data/data/font/111.raw +96 -0
  24. data/data/font/112.raw +78 -0
  25. data/data/font/113.raw +78 -0
  26. data/data/font/114.raw +53 -0
  27. data/data/font/115.raw +132 -0
  28. data/data/font/116.raw +56 -0
  29. data/data/font/117.raw +54 -0
  30. data/data/font/118.raw +5 -0
  31. data/data/font/119.raw +11 -0
  32. data/data/font/120.raw +10 -0
  33. data/data/font/121.raw +6 -0
  34. data/data/font/122.raw +6 -0
  35. data/data/font/33.raw +118 -0
  36. data/data/font/37.raw +194 -0
  37. data/data/font/38.raw +200 -0
  38. data/data/font/39.raw +4 -0
  39. data/data/font/40.raw +48 -0
  40. data/data/font/41.raw +48 -0
  41. data/data/font/42.raw +226 -0
  42. data/data/font/43.raw +10 -0
  43. data/data/font/45.raw +2 -0
  44. data/data/font/46.raw +46 -0
  45. data/data/font/47.raw +2 -0
  46. data/data/font/48.raw +96 -0
  47. data/data/font/49.raw +2 -0
  48. data/data/font/50.raw +87 -0
  49. data/data/font/51.raw +145 -0
  50. data/data/font/52.raw +15 -0
  51. data/data/font/53.raw +76 -0
  52. data/data/font/54.raw +121 -0
  53. data/data/font/55.raw +4 -0
  54. data/data/font/56.raw +194 -0
  55. data/data/font/57.raw +133 -0
  56. data/data/font/61.raw +4 -0
  57. data/data/font/63.raw +117 -0
  58. data/data/font/65.raw +11 -0
  59. data/data/font/66.raw +108 -0
  60. data/data/font/67.raw +96 -0
  61. data/data/font/68.raw +54 -0
  62. data/data/font/69.raw +10 -0
  63. data/data/font/70.raw +8 -0
  64. data/data/font/71.raw +100 -0
  65. data/data/font/72.raw +10 -0
  66. data/data/font/73.raw +2 -0
  67. data/data/font/74.raw +39 -0
  68. data/data/font/75.raw +9 -0
  69. data/data/font/76.raw +4 -0
  70. data/data/font/77.raw +13 -0
  71. data/data/font/78.raw +8 -0
  72. data/data/font/79.raw +96 -0
  73. data/data/font/80.raw +56 -0
  74. data/data/font/81.raw +124 -0
  75. data/data/font/82.raw +94 -0
  76. data/data/font/83.raw +120 -0
  77. data/data/font/84.raw +6 -0
  78. data/data/font/85.raw +76 -0
  79. data/data/font/86.raw +5 -0
  80. data/data/font/87.raw +11 -0
  81. data/data/font/88.raw +10 -0
  82. data/data/font/89.raw +7 -0
  83. data/data/font/90.raw +6 -0
  84. data/data/font/91.raw +6 -0
  85. data/data/font/93.raw +6 -0
  86. data/data/font/94.raw +5 -0
  87. data/data/font/95.raw +2 -0
  88. data/data/font/97.raw +174 -0
  89. data/data/font/98.raw +100 -0
  90. data/data/font/99.raw +96 -0
  91. data/data/ground.raw +12 -0
  92. data/data/man.mtl +12 -0
  93. data/data/man.obj +7547 -0
  94. data/data/robo.mtl +11 -0
  95. data/data/robo.obj +42065 -0
  96. data/data/space.json +49 -0
  97. data/data/sphere.raw +1216 -0
  98. data/data/texture/Charcoal-2.jpg +0 -0
  99. data/data/texture/man.png +0 -0
  100. data/data/texture/man.tif +0 -0
  101. data/data/texture/t.jpg +0 -0
  102. data/data/texture/wood.jpg +0 -0
  103. data/data/texture/wood.png +0 -0
  104. data/data/texture/x.jpg +0 -0
  105. data/data/untitled.raw +124 -0
  106. data/data/w.raw +12474 -0
  107. data/data/wings.raw +45670 -0
  108. data/lib/BlackBook/anim.rb +184 -0
  109. data/lib/BlackBook/b3dobject.rb +475 -0
  110. data/lib/BlackBook/base.rb +79 -0
  111. data/lib/BlackBook/camera.rb +202 -0
  112. data/lib/BlackBook/color.rb +29 -0
  113. data/lib/BlackBook/constants.rb +327 -0
  114. data/lib/BlackBook/engine.rb +172 -0
  115. data/lib/BlackBook/functions.rb +650 -0
  116. data/lib/BlackBook/light.rb +91 -0
  117. data/lib/BlackBook/logger.rb +86 -0
  118. data/lib/BlackBook/material.rb +98 -0
  119. data/lib/BlackBook/registry.rb +71 -0
  120. data/lib/BlackBook/space.rb +396 -0
  121. data/lib/BlackBook/stime.rb +64 -0
  122. data/lib/Plugins/string_color.rb +74 -0
  123. data/lib/blackbook/version.rb +5 -0
  124. data/lib/blackbook.rb +52 -0
  125. data/lib/plugins.rb +32 -0
  126. data/lib/ui/button.rb +115 -0
  127. data/lib/ui/edit.rb +105 -0
  128. data/lib/ui/text.rb +284 -0
  129. data/lib/ui/ui.rb +88 -0
  130. data/lib/ui/ui_element.rb +45 -0
  131. data/lib/ui/window.rb +138 -0
  132. data/lib/ui.rb +30 -0
  133. data/lib/zipfile.rb +27 -0
  134. metadata +254 -0
@@ -0,0 +1,650 @@
1
+ ##############################################################################
2
+ # BlackBook 3D Engine
3
+ # Copyright (C) 2015 Sinan ISLEKDEMIR
4
+ #
5
+ # This program is free software; you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation; either version 2 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License along
16
+ # with this program; if not, write to the Free Software Foundation, Inc.,
17
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
+ ##############################################################################
19
+
20
+ ################################################################
21
+ # Project BlackBook
22
+ # Lead Engineer: Sinan ISLEKDEMIR
23
+ # Simulation Engine Ruby Sources
24
+ ################################################################
25
+
26
+ require 'opengl'
27
+ require 'pp'
28
+
29
+ # Local Libs
30
+ require 'BlackBook/constants'
31
+
32
+ # Mathematics related general functions
33
+ module BlackBook
34
+ #
35
+ # glhProjectf (works only from perspective projection.
36
+ # With the orthogonal projection it gives different results than
37
+ # standard gluProject.
38
+ # https://www.opengl.org/wiki/GluProject_and_gluUnProject_code
39
+ #
40
+ # @param obj [CVector] Object Coordinates
41
+ # @param mv [Array] Model View Matrix
42
+ # @param p [Array] Projection Matrix
43
+ # @param v [Array] Viewport Matrix
44
+ #
45
+ # @return [Array] Window Coordinates
46
+ def glh_project_f(obj, mv, p, v)
47
+ mv = mv.flatten
48
+ p = p.flatten
49
+ v = v.flatten
50
+ # Transformation vector
51
+ f = []
52
+ # Modelview Transform
53
+ f[0] = mv[0] * obj.x + mv[4] * obj.y + mv[8] * obj.z + mv[12]
54
+ f[1] = mv[1] * obj.x + mv[5] * obj.y + mv[9] * obj.z + mv[13]
55
+ f[2] = mv[2] * obj.x + mv[6] * obj.y + mv[10] * obj.z + mv[14]
56
+ f[3] = mv[3] * obj.x + mv[7] * obj.y + mv[11] * obj.z + mv[15]
57
+ # Projection transform the final row of projection
58
+ # matrix is always [0 0 -1 0]
59
+ # so we optimize for that.
60
+ f[4] = p[0] * f[0] + p[4] * f[1] + p[8] * f[2] + p[12] * f[3]
61
+ f[5] = p[1] * f[0] + p[5] * f[1] + p[9] * f[2] + p[13] * f[3]
62
+ f[6] = p[2] * f[0] + p[6] * f[1] + p[10] * f[2] + p[14] * f[3]
63
+ f[7] = -f[2]
64
+ # The result normalizes between -1 and 1
65
+ return [nil, nil] if f[7] == 0.0
66
+ f[7] = 1.0 / f[7]
67
+ # Perspective division
68
+ f[4] *= f[7]
69
+ f[5] *= f[7]
70
+ f[6] *= f[7]
71
+ # Window coordinates
72
+ # Map x, y to range 0-1
73
+ window_coordinate = []
74
+ window_coordinate[0] = (f[4] * 0.5 + 0.5) * v[2] + v[0]
75
+ window_coordinate[1] = (f[5] * 0.5 + 0.5) * v[3] + v[1]
76
+ # This is only correct when glDepthRange(0.0, 1.0)
77
+ window_coordinate[2] = (1.0 * f[6]) * 0.5
78
+ window_coordinate
79
+ end
80
+
81
+ #
82
+ # Multiply 4 x 4 matrices
83
+ # @param m1 [Array] Array of 4x4 matrice
84
+ # @param m2 [Array] Array of 4x4 matrice
85
+ #
86
+ # @return [Array] Result array
87
+ def multiply_matrices_4by4(m1, m2)
88
+ raise 'Matrices must be array' unless m1.is_a?(Array) && m2.is_a?(Array)
89
+ r = []
90
+ r[0] = m1[0] * m2[0] + m1[4] * m2[1] + m1[8] * m2[2] + m1[12] * m2[3]
91
+ r[4] = m1[0] * m2[4] + m1[4] * m2[5] + m1[8] * m2[6] + m1[12] * m2[7]
92
+ r[8] = m1[0] * m2[8] + m1[4] * m2[9] + m1[8] * m2[10] + m1[12] * m2[11]
93
+ r[12] = m1[0] * m2[12] + m1[4] * m2[13] + m1[8] * m2[14] + m1[12] * m2[15]
94
+ r[1] = m1[1] * m2[0] + m1[5] * m2[1] + m1[9] * m2[2] + m1[13] * m2[3]
95
+ r[5] = m1[1] * m2[4] + m1[5] * m2[5] + m1[9] * m2[6] + m1[13] * m2[7]
96
+ r[9] = m1[1] * m2[8] + m1[5] * m2[9] + m1[9] * m2[10] + m1[13] * m2[11]
97
+ r[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15]
98
+ r[2] = m1[2] * m2[0] + m1[6] * m2[1] + m1[10] * m2[2] + m1[14] * m2[3]
99
+ r[6] = m1[2] * m2[4] + m1[6] * m2[5] + m1[10] * m2[6] + m1[14] * m2[7]
100
+ r[10] = m1[2] * m2[8] + m1[6] * m2[9] + m1[10] * m2[10] + m1[14] * m2[11]
101
+ r[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15]
102
+ r[3] = m1[3] * m2[0] + m1[7] * m2[1] + m1[11] * m2[2] + m1[15] * m2[3]
103
+ r[7] = m1[3] * m2[4] + m1[7] * m2[5] + m1[11] * m2[6] + m1[15] * m2[7]
104
+ r[11] = m1[3] * m2[8] + m1[7] * m2[9] + m1[11] * m2[10] + m1[15] * m2[11]
105
+ r[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15]
106
+ r
107
+ end
108
+
109
+ #
110
+ # Multiply matrix array with a vector array
111
+ # Vector held as array for quick usage
112
+ #
113
+ # @param m [Array] Matrix
114
+ # @param v [Array] Vector
115
+ #
116
+ # @return [Array] Result
117
+ def multiply_matrix_by_vector( matrix, vector )
118
+ [matrix, vector].map { |x| raise "#{x} must be array" unless x.is_a? Array}
119
+ m, v, r = matrix, vector, []
120
+ r[0] = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3]
121
+ r[1] = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3]
122
+ r[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3]
123
+ r[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3]
124
+ r
125
+ end
126
+
127
+ #
128
+ # Return array position from x-y coordinates
129
+ # @param x [Integer] X Coordinate
130
+ # @param y [Integer] Y Coordinate
131
+ #
132
+ # @return [Integer] Array index
133
+ def _mat(x, y)
134
+ raise 'Coords must be Integer' unless x.is_a?(Integer) && y.is_a?(Integer)
135
+ y * 4 + x
136
+ end
137
+
138
+ #
139
+ # Return item of matrix array from x-y coordinates
140
+ # @param m [Array] Matrix
141
+ # @param x [Integer] X Coordinate
142
+ # @param y [Integer] Y Coordinate
143
+ #
144
+ # @return [type] [description]
145
+ def mat(m, x, y)
146
+ raise 'Matrix must be array' unless m.is_a? Array
147
+ m[_mat(x, y)]
148
+ end
149
+
150
+ #
151
+ # Invert matrix array
152
+ # @param m [Array] Matrix
153
+ #
154
+ # @return [Array] Inverted matrix
155
+ def glh_invert_matrix_f2(m)
156
+ raise "Matrix must be array" unless m.is_a? Array
157
+ out = []
158
+ r0 = []
159
+ r1 = []
160
+ r2 = []
161
+ r3 = []
162
+ r0[0] = mat(m, 0, 0)
163
+ r0[1] = mat(m, 0, 1)
164
+ r0[2] = mat(m, 0, 2)
165
+ r0[3] = mat(m, 0, 3)
166
+ r0[4] = 1.0
167
+ r0[5] = r0[6] = r0[7] = 0.0
168
+ r1[0] = mat(m, 1, 0)
169
+ r1[1] = mat(m, 1, 1)
170
+ r1[2] = mat(m, 1, 2)
171
+ r1[3] = mat(m, 1, 3)
172
+ r1[5] = 1.0
173
+ r1[4] = r1[6] = r1[7] = 0.0
174
+ r2[0] = mat(m, 2, 0)
175
+ r2[1] = mat(m, 2, 1)
176
+ r2[2] = mat(m, 2, 2)
177
+ r2[3] = mat(m, 2, 3)
178
+ r2[6] = 1.0
179
+ r2[4] = r2[5] = r2[7] = 0.0
180
+ r3[0] = mat(m, 3, 0)
181
+ r3[1] = mat(m, 3, 1)
182
+ r3[2] = mat(m, 3, 2)
183
+ r3[3] = mat(m, 3, 3)
184
+ r3[7] = 1.0
185
+ r3[4] = r3[5] = r3[6] = 0.0
186
+
187
+ case
188
+ when r3[0].abs > r2[0] then r3, r2 = r2, r3
189
+ when r2[0].abs > r1[0] then r2, r1 = r1, r2
190
+ when r1[0].abs > r0[0] then r1, r0 = r0, r1
191
+ end
192
+
193
+ return 0 if r0[0] == 0.0
194
+
195
+ m1 = r1[0] / r0[0]
196
+ m2 = r2[0] / r0[0]
197
+ m3 = r3[0] / r0[0]
198
+
199
+ [1, 2, 3].map do |x|
200
+ r1[x] -= m1 * r0[x]
201
+ r2[x] -= m2 * r0[x]
202
+ r3[x] -= m3 * r0[x]
203
+ end
204
+
205
+ [4, 5, 6, 7].map do |x|
206
+ unless x == 0.0
207
+ r1[x] -= m1 * r0[x]
208
+ r2[x] -= m2 * r0[x]
209
+ r3[x] -= m3 * r0[x]
210
+ end
211
+ end
212
+
213
+ r3, r2 = r2, r3 if r3[1].abs > r2[1].abs
214
+ r2, r1 = r1, r2 if r2[1].abs > r1[1].abs
215
+
216
+ return 0 if r1[1] == 0.0
217
+
218
+ m2 = r2[1] / r1[1]
219
+ m3 = r3[1] / r1[1]
220
+
221
+ r2[2] -= m2 * r1[2]
222
+ r3[2] -= m3 * r1[2]
223
+ r2[3] -= m2 * r1[3]
224
+ r3[3] -= m3 * r1[3]
225
+
226
+ [4, 5, 6, 7].map do |x|
227
+ unless r1[x] == 0.0
228
+ r2[x] -= m2 * r1[x]
229
+ r3[x] -= m3 * r1[x]
230
+ end
231
+ end
232
+
233
+ r3, r2 = r2, r3 if r3[2].abs > r2[2].abs
234
+
235
+ return 0 if r2[2] == 0.0
236
+
237
+ [3, 4, 5, 6, 7].map do |x|
238
+ r3[x] -= r3[2] / r2[2] * r2[x]
239
+ end
240
+
241
+ return 0 if 0.0 == r3[3]
242
+
243
+ [4, 5, 6, 7].map do |x|
244
+ r3[x] *= 1.0 / r3[3]
245
+ r2[x] = 1.0 / r2[2] * (r2[x] - r3[x] * r2[3])
246
+ r1[x] -= r3[x] * r1[3]
247
+ r0[x] -= r3[x] * r0[3]
248
+ r1[x] = 1.0 / r1[1] * (r1[x] - r2[x] * r1[2])
249
+ r0[x] -= r2[x] * r0[2]
250
+ r0[x] = 1.0 / r0[0] * (r0[x] - r1[x] * r0[1])
251
+ end
252
+
253
+ out[_mat(0, 0)] = r0[4]
254
+ out[_mat(0, 1)] = r0[5]
255
+ out[_mat(0, 2)] = r0[6]
256
+ out[_mat(0, 3)] = r0[7]
257
+ out[_mat(1, 0)] = r1[4]
258
+ out[_mat(1, 1)] = r1[5]
259
+ out[_mat(1, 2)] = r1[6]
260
+ out[_mat(1, 3)] = r1[7]
261
+ out[_mat(2, 0)] = r2[4]
262
+ out[_mat(2, 1)] = r2[5]
263
+ out[_mat(2, 2)] = r2[6]
264
+ out[_mat(2, 3)] = r2[7]
265
+ out[_mat(3, 0)] = r3[4]
266
+ out[_mat(3, 1)] = r3[5]
267
+ out[_mat(3, 2)] = r3[6]
268
+ out[_mat(3, 3)] = r3[7]
269
+ out
270
+ end
271
+
272
+ #
273
+ # GLU Unproject
274
+ # https://www.opengl.org/wiki/GluProject_and_gluUnProject_code
275
+ #
276
+ # @param wx [Float] Window X Coordinate
277
+ # @param wy [Float] Window Y Coordinate
278
+ # @param wz [Float] Window Z Coordinate
279
+ # @param m [Array] Model View Matrix
280
+ # @param p [Array] Projection Matrix
281
+ # @param v [Array] Viewport Matrix
282
+ #
283
+ # @return [CVector] Object coordinates
284
+ def glh_unprojectf(wx, wy, wz, m, p, v)
285
+ # Transformation matrices
286
+ m_in = []
287
+ # Calculation for inverting a matrix, compute projection x modelview
288
+ # and store in A[16]
289
+ m = m.flatten
290
+ p = p.flatten
291
+ v = v.flatten
292
+ a = multiply_matrices_4by4(p, m)
293
+ invert_m = glh_invert_matrix_f2(a)
294
+ return 0 if invert_m == 0
295
+ m_in[0] = (wx - v[0].to_f) / v[2].to_f * 2.0 - 1.0
296
+ m_in[1] = (wy - v[1].to_f) / v[3].to_f * 2.0 - 1.0
297
+ m_in[2] = 2.0 * wz - 1.0
298
+ m_in[3] = 1.0
299
+ out = multiply_matrix_by_vector(invert_m, m_in)
300
+ return 0 if out[3] == 0
301
+ out[3] = 1.0 / out[3]
302
+ CVector.new(out[0] * out[3], out[1] * out[3], out[2] * out[3])
303
+ end
304
+
305
+ #
306
+ # Cross Product of two vectors
307
+ # @param x1 [Float] [X1 Element of vector]
308
+ # @param y1 [Float] [Y1 Element of vector]
309
+ # @param z1 [Float] [Z1 Element of vector]
310
+ # @param x2 [Float] [X2 Element of vector]
311
+ # @param y2 [Float] [Y2 Element of vector]
312
+ # @param z2 [Float] [Z2 Element of vector]
313
+ #
314
+ # @return [Array] Array of vector elements [x, y, z]
315
+ def cross_prod(x1, y1, z1, x2, y2, z2)
316
+ [(y1 * z2 - y2 * z1), (x2 * z1 - x1 * z2), (x1 * y2 - x2 * y1)]
317
+ end
318
+
319
+ #
320
+ # GLULookAt Alternative Function
321
+ # @param eye [CVector] [Eye position]
322
+ # @param look_at [CVector] [Target position]
323
+ # @param up [CVector] [Up vector of camera]
324
+ #
325
+ # @return [Boolean] Success
326
+ def look_at(eye, look_at, up)
327
+ z = CVector.new(eye.x - look_at.x, eye.y - look_at.y, eye.z - look_at.z, 1)
328
+ z.normalize
329
+ y = CVector.new(up.x, up.y, up.z, 1)
330
+ x = y.cross(z)
331
+ y = z.cross(x)
332
+ x.normalize
333
+ y.normalize
334
+ mat = [x.x, y.x, z.x, 0, x.y, y.y, z.y, 0, x.z, y.z, z.z, 0, 0, 0, 0, 1]
335
+ GL.MultMatrixf(mat)
336
+ GL.Translatef(-eye.x, -eye.y, -eye.z)
337
+ end
338
+
339
+ #
340
+ # GLUPerspective Alternative
341
+ # @param fovY [Float] Field of view
342
+ # @param aspect [Float] Aspect ratio of view
343
+ # @param znear [Float] Near Plane
344
+ # @param zfar [Float] Far Plane
345
+ #
346
+ # @return [Boolean] Success
347
+ def perspective(fov_y, aspect, znear, zfar)
348
+ pi = 3.1415926535897932384626433832795
349
+ fh = Math.tan((fov_y / 2) / 180 * pi) * znear
350
+ fw = fh * aspect
351
+ GL.Frustum(-fw, fw, -fh, fh, znear, zfar)
352
+ end
353
+
354
+ #
355
+ # Draw grid
356
+ #
357
+ # @return [Boolean] Success
358
+ def draw_grid
359
+ count = BlackBook::Registry.instance.read('grid_count') || 200
360
+ size = BlackBook::Registry.instance.read('grid_size')
361
+ GL.PushMatrix
362
+ GL.Translatef(0.0, 0.0, 0.0)
363
+
364
+ GL.Disable(GL::LIGHTING)
365
+ GL.Color3f(0.8, 0.8, 0.8)
366
+ x = (count / 2) * size * -1.0
367
+ y = (count / 2) * size * -1.0
368
+ 1.upto(count - 1) do |i|
369
+ GL.Begin(GL::LINES)
370
+ GL.Vertex(x + (size * i), y, 0)
371
+ GL.Vertex(x + (size * i), -y, 0)
372
+ GL.End()
373
+ GL.Begin(GL::LINES)
374
+ GL.Vertex(x, y + (size * i), 0)
375
+ GL.Vertex(-x, y + (size * i), 0)
376
+ GL.End()
377
+ end
378
+ GL.LineWidth 3
379
+ GL.Color3f(1.0, 0.0, 0.0)
380
+ GL.Begin(GL::LINES)
381
+ GL.Vertex3f(0, 0, 0)
382
+ GL.Vertex3f(100.0, 0, 0)
383
+ GL.End
384
+ GL.Color3f(0.0, 1.0, 0.0)
385
+ GL.Begin(GL::LINES)
386
+ GL.Vertex3f(0, 0, 0)
387
+ GL.Vertex3f(0.0, 100.0, 0)
388
+ GL.End
389
+ GL.Color3f(0.0, 0.0, 1.0)
390
+ GL.Begin(GL::LINES)
391
+ GL.Vertex3f(0, 0, 0)
392
+ GL.Vertex3f(0.0, 0.0, 100.0)
393
+ GL.End
394
+ GL.LineWidth 1
395
+
396
+ GL.Enable(GL::LIGHTING)
397
+ GL.PopMatrix
398
+ end
399
+
400
+ #
401
+ # CVector to color.
402
+ # RGBA (0-255, 0-255, 0-255, 0-1)
403
+ # @param color_vector [CVector] Color vector
404
+ #
405
+ # @return [Boolean] Success
406
+ def apply_color(color_vector)
407
+ r = color_vector.x == 0 ? 0 : color_vector.x / 255.0
408
+ g = color_vector.y == 0 ? 0 : color_vector.y / 255.0
409
+ b = color_vector.z == 0 ? 0 : color_vector.z / 255.0
410
+ GL.Color4f(
411
+ r,
412
+ g,
413
+ b,
414
+ color_vector.w
415
+ )
416
+ end
417
+
418
+ #
419
+ # Draw 2D Box
420
+ # @param options [Hash]
421
+ # options[:x, :y, :z, :w, :color, :border, :border_color]
422
+ #
423
+ # @return [Boolean] Success
424
+ def draw_box_2d( opts = {} )
425
+ GL.PushMatrix
426
+ GL.Disable(GL::LIGHTING)
427
+ GL.Enable(GL::COLOR_MATERIAL)
428
+ GL.Enable(GL::BLEND)
429
+ GL.BlendFunc(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA)
430
+ GL.Translatef(opts[:x], opts[:y], opts[:z])
431
+ # Border
432
+ if opts[:border]
433
+ apply_color(opts[:border_color]) if opts[:border_color]
434
+ line_width = opts[:border_size] || 1
435
+ # hackaround for compare float-nil error
436
+ opts[:height] ||= 0
437
+ GL.LineWidth(line_width)
438
+ GL.Begin(GL::LINE_STRIP)
439
+ GL.Vertex2d(-line_width, -line_width)
440
+ GL.Vertex2d(-line_width, opts[:height] + line_width)
441
+ GL.Vertex2d(opts[:width] + line_width, opts[:height] + line_width)
442
+ GL.Vertex2d(opts[:width] + line_width, -line_width)
443
+ GL.Vertex2d(-line_width, -line_width)
444
+ GL.End
445
+ end
446
+ # Window
447
+ apply_color(opts[:color])
448
+ GL.Begin(GL::QUADS)
449
+ GL.Vertex2d(0, 0)
450
+ GL.Vertex2d(0, opts[:height])
451
+ GL.Vertex2d(opts[:width], opts[:height])
452
+ GL.Vertex2d(opts[:width], 0)
453
+ GL.End
454
+ GL.PopMatrix
455
+ end
456
+
457
+ #
458
+ # Degrees to Radians Conversion
459
+ # @param degrees [Float] Degrees
460
+ #
461
+ # @return [Float] Radians
462
+ def deg_to_rad(degrees)
463
+ degrees * (Math::PI / 180.0)
464
+ end
465
+
466
+ #
467
+ # Radians to Degrees
468
+ # @param radians [Float] Radians
469
+ #
470
+ # @return [Float] Degrees
471
+ def rad_to_deg(radians)
472
+ result = radians * (180.0 / Math::PI)
473
+ result += 360 if result.negative?
474
+ result = 360 - result if result > 360
475
+ return result
476
+ end
477
+
478
+ #
479
+ # Calculate Normal of a given Triangle
480
+ # @param p1 [CVector] Triangle Vector A
481
+ # @param p2 [CVector] Triangle Vector B
482
+ # @param p3 [CVector] Triangle Vector C
483
+ #
484
+ # @return [CVector] Normal Vector
485
+ def calc_plane_normal(p1, p2, p3)
486
+ v1 = p2.sub(p1)
487
+ v2 = p3.sub(p1)
488
+ result = v1.cross(v2)
489
+ return result.normalize
490
+ end
491
+
492
+ #
493
+ # Convert Array to Vector
494
+ # @param data [Array] Array of floats
495
+ #
496
+ # @return [CVector] Result Vector
497
+ def array_to_vector( data = [] )
498
+ raise 'Data must be array' unless data.is_a? Array
499
+ CVector.new(data[0], data[1], data[2], 1)
500
+ end
501
+
502
+ #
503
+ # Draw Circle
504
+ # @param r [Float] Radius
505
+ # @param num_segments [Integer] Number of segments
506
+ #
507
+ # @return [type] [description]
508
+ def draw_circle(r, num_segments)
509
+ pi = 3.1415926535897932384626433832795
510
+ GL.Begin(GL::LINE_LOOP)
511
+ (0..num_segments).each do |ii|
512
+ theta = 2.0 * pi * ii.to_f / num_segments.to_f
513
+ x = r * Math.cos(theta)
514
+ y = r * Math.sin(theta)
515
+ GL.Vertex2f(x, y)
516
+ end
517
+ GL.End
518
+ end
519
+
520
+ #
521
+ # Vector combine
522
+ # @param [CVector] first vector
523
+ # @param [CVector] second vector
524
+ # @param [CVector] Factor
525
+ # @return [CVector] Result
526
+ def vector_combine(v1, v2, t)
527
+ CVector.new(
528
+ v1.x + (t * v2.x),
529
+ v1.y + (t * v2.y),
530
+ v1.z + (t * v2.z),
531
+ v1.w + (t * v2.w)
532
+ )
533
+ end
534
+
535
+ #
536
+ # RayCastTriangleIntersect
537
+ #
538
+ # @param [CVector] ray_start
539
+ # @param [CVector] ray_vector
540
+ # @param [CVector] p1
541
+ # @param [CVector] p2
542
+ # @param [CVector] p3
543
+ #
544
+ # @return [Hash] :hit boolean, :point CVector, :normal CVector
545
+ def raycast_triangle_intersect(ray_start, ray_vector, p1, p2, p3)
546
+ e2 = 1e-30
547
+ result = {}
548
+ result[:point] = CVector.new(0, 0, 0)
549
+ result[:normal] = CVector.new(0, 0, 0)
550
+ result[:hit] = false
551
+ pvec = CVector.new(0, 0, 0)
552
+ v1 = CVector.new(0, 0, 0)
553
+ v2 = CVector.new(0, 0, 0)
554
+ qvec = CVector.new(0, 0, 0)
555
+ tvec = CVector.new(0, 0, 0)
556
+ t = 0.0
557
+ u = 0.0
558
+ v = 0.0
559
+ det = 0.0
560
+ inv_det = 0.0
561
+ v1 = p2.sub(p1)
562
+ v2 = p3.sub(p1)
563
+ pvec = ray_vector.cross(v2)
564
+ det = v1.dot(pvec)
565
+ return result if det < e2 && det > -e2
566
+ inv_det = 1.0 / det
567
+ tvec = ray_start.sub(p1)
568
+ u = tvec.dot(pvec) * inv_det
569
+ return result if u < 0 || u > 1
570
+ qvec = tvec.cross(v1)
571
+ v = tvec.dot(pvec) * inv_det
572
+ result[:hit] = (v >= 0) && (u + v <= 1)
573
+ if result[:hit]
574
+ t = v2.dot(qvec) * inv_det
575
+ if t > 0
576
+ result[:point] = BlackBook.vector_combine(
577
+ ray_start,
578
+ ray_vector,
579
+ t
580
+ )
581
+ result[:normal] = v1.cross(v2)
582
+ result[:normal].normalize
583
+ else
584
+ result[:hit] = false
585
+ end
586
+ end
587
+ result
588
+ end
589
+
590
+ #
591
+ # Raycast Plane Intersect
592
+ # @param [CVector] ray_start
593
+ # @param [CVector] ray_vector
594
+ # @param [CVector] plane_point
595
+ # @param [CVector] plane_normal
596
+ # @return [Hash] result
597
+ #
598
+ def raycast_plane_intersect(ray_start, ray_vector, plane_point, plane_normal)
599
+ result = {}
600
+ result[:point] = CVector.new(0, 0, 0)
601
+ e2 = 1e-30
602
+ sp = CVector.new(0, 0, 0)
603
+ t = 0.0
604
+ d = 0.0
605
+ d = ray_vector.dot(plane_normal)
606
+ result[:hit] = ((d > e2) || (d < -e2))
607
+ if result[:hit]
608
+ sp = plane_point.sub(ray_start)
609
+ d = 1 / d
610
+ t = sp.dot(plane_normal) * d
611
+ if t > 0
612
+ result[:point] = BlackBook.vector_combine(ray_start, ray_vector, t)
613
+ else
614
+ result[:hit] = false
615
+ end
616
+ end
617
+ result
618
+ end
619
+
620
+ #
621
+ # Check if given point lays on the defined line
622
+ # @param [CVector] point
623
+ # @param [CVector] line_start
624
+ # @param [CVector] line_end
625
+ # @return [Boolean] result
626
+ #
627
+ def point_on_line(point, line_start, line_end)
628
+ e2 = 1e-30
629
+ line_length = line_start.distance line_end
630
+ point_to_start = line_start.distance point
631
+ point_to_end = line_end.distance point
632
+ c = point_to_start + point_to_end - line_length
633
+ puts 'Line length: ' + line_length.to_s
634
+ puts 'P2S: ' + point_to_start.to_s
635
+ puts 'P2E: ' + point_to_end.to_s
636
+ c.abs < e2
637
+ end
638
+
639
+ # Transform vector by matrix
640
+ # @param [CVector] Vector
641
+ # @param [Array] Matrix
642
+ def vector_transform(v, m)
643
+ result = CVector.new(0.0, 0.0, 0.0)
644
+ result.x = v.x * m[0][0] + v.y * m[1][0] + v.z * m[2][0] + v.w * m[3][0]
645
+ result.y = v.x * m[0][1] + v.y * m[1][1] + v.z * m[2][1] + v.w * m[3][1]
646
+ result.z = v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2] + v.w * m[3][2]
647
+ result.w = v.x * m[0][3] + v.y * m[1][3] + v.z * m[2][3] + v.w * m[3][3]
648
+ result
649
+ end
650
+ end