tavli

view src/board.cc @ 11:a8e26f163f99

poulia
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 27 Jun 2015 08:01:51 +0300
parents 8a167149985d
children ae1c60726c41
line source
1 #include <float.h>
2 #include "opengl.h"
3 #include "board.h"
4 #include "meshgen.h"
5 #include "pnoise.h"
7 Board::Board()
8 {
9 puck_obj = 0;
10 clear();
11 }
13 Board::~Board()
14 {
15 destroy();
16 }
18 bool Board::init()
19 {
20 if(!generate_textures()) {
21 return false;
22 }
23 if(!generate()) {
24 return false;
25 }
27 return true;
28 }
30 void Board::destroy()
31 {
32 for(size_t i=0; i<obj.size(); i++) {
33 delete obj[i];
34 }
35 obj.clear();
37 delete puck_obj;
38 puck_obj = 0;
39 }
41 void Board::clear()
42 {
43 memset(slots, 0, sizeof slots);
44 }
46 void Board::draw() const
47 {
48 for(size_t i=0; i<obj.size(); i++) {
49 obj[i]->draw();
50 }
51 }
53 #define HSIZE 1.0
54 #define VSIZE (2.0 * HSIZE)
55 #define BOT_THICKNESS (HSIZE * 0.01)
56 #define WALL_THICKNESS (HSIZE * 0.05)
57 #define WALL_HEIGHT (HSIZE * 0.1)
58 #define GAP (HSIZE * 0.025)
59 #define HINGE_RAD (GAP * 0.5)
60 #define HINGE_HEIGHT (VSIZE * 0.075)
61 #define PIECE_RAD (0.45 * HSIZE / 5.0)
63 static const float piece_cp[][3][2] = {
64 {{0, 0.25}, {1, 0.25}, {2, 0.5}},
65 {{2, 0.5}, {2.5, 0.5}, {3, 0.5}},
66 {{3, 0.5}, {4, 0.5}, {4, 0}},
67 {{4, 0}, {4, -0.5}, {3, -0.5}},
68 {{3, -0.5}, {2.5, -0.5}, {0, -0.5}},
69 //{{2, -0.5}, {1, -0.25}, {0, -0.25}}
70 };
71 static const int piece_ncurves = sizeof piece_cp / sizeof *piece_cp;
73 static Vector2 piece_revol(float u, float v, void *cls)
74 {
75 if(v >= 1.0) v = 1.0 - 1e-6;
76 int idx = std::min((int)(v * piece_ncurves), piece_ncurves - 1);
77 float t = fmod(v * (float)piece_ncurves, 1.0);
79 Vector2 res;
80 for(int i=0; i<2; i++) {
81 float mid = piece_cp[idx][1][i];
82 res[i] = bezier(piece_cp[idx][0][i], mid, mid, piece_cp[idx][2][i], t);
83 }
84 return res * 0.25 * PIECE_RAD;
85 }
87 bool Board::generate()
88 {
89 Mesh tmp;
90 Matrix4x4 xform;
92 obj.clear();
94 for(int i=0; i<2; i++) {
95 int sign = i * 2 - 1;
97 // generate bottom
98 Mesh *bottom = new Mesh;
99 gen_box(bottom, HSIZE, BOT_THICKNESS, HSIZE * 2.0);
100 xform.set_translation(Vector3(0, -BOT_THICKNESS / 2.0, 0));
101 bottom->apply_xform(xform);
103 Object *obottom = new Object;
104 obottom->set_mesh(bottom);
105 obottom->xform().set_translation(Vector3(sign * (HSIZE / 2.0 + WALL_THICKNESS + HINGE_RAD * 0.25), 0, 0));
106 obottom->set_texture(img_field.texture());
107 obj.push_back(obottom);
110 // generate the 4 sides
111 Mesh *sides = new Mesh;
112 gen_box(sides, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2);
113 xform.set_translation(Vector3(-(HSIZE + WALL_THICKNESS) / 2.0,
114 WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0));
115 sides->apply_xform(xform);
117 gen_box(&tmp, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2);
118 xform.set_translation(Vector3((HSIZE + WALL_THICKNESS) / 2.0,
119 WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0));
120 tmp.apply_xform(xform);
121 sides->append(tmp);
122 tmp.clear();
124 gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS);
125 xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS,
126 (VSIZE + WALL_THICKNESS) / 2.0));
127 tmp.apply_xform(xform);
128 sides->append(tmp);
129 tmp.clear();
131 gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS);
132 xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS,
133 -(VSIZE + WALL_THICKNESS) / 2.0));
134 tmp.apply_xform(xform);
135 sides->append(tmp);
136 tmp.clear();
138 // generate texture coordinates
139 sides->texcoord_gen_box();
141 Object *osides = new Object;
142 osides->set_mesh(sides);
143 osides->xform() = obottom->xform();
144 osides->set_texture(img_wood.texture());
145 osides->tex_xform().set_scaling(Vector3(2, 2, 2));
146 osides->tex_xform().rotate(-Vector3(1, 0, 0.5), M_PI / 4.0);
147 obj.push_back(osides);
149 }
152 // generate the hinges
153 Mesh *hinges = new Mesh;
154 for(int i=0; i<2; i++) {
155 float sign = i * 2 - 1;
157 // barrel
158 gen_cylinder(&tmp, HINGE_RAD, HINGE_HEIGHT, 8, 1, 1);
159 xform.reset_identity();
160 xform.translate(Vector3(0, WALL_HEIGHT - HINGE_RAD * 0.5, sign * VSIZE / 4.0));
161 xform.rotate(Vector3(-M_PI / 2.0, 0, 0));
162 tmp.apply_xform(xform);
163 hinges->append(tmp);
165 // flange
166 gen_plane(&tmp, HINGE_HEIGHT * 0.6, HINGE_HEIGHT * 0.8);
167 tmp.apply_xform(xform);
169 Matrix4x4 tex_xform;
170 tex_xform.set_rotation(Vector3(0, 0, M_PI / 2.0));
171 tmp.texcoord_apply_xform(tex_xform);
172 hinges->append(tmp);
174 // studs
175 for(int j=0; j<4; j++) {
176 Vector3 pos;
178 pos.x = (float)((j & 1) * 2 - 1) * HINGE_HEIGHT * 0.2;
179 pos.y = (float)((j & 2) - 1) * HINGE_HEIGHT * 0.3;
181 Matrix4x4 stud_xform = xform;
182 stud_xform.translate(pos);
184 Matrix4x4 squash;
185 squash.set_scaling(Vector3(1, 1, 0.5));
187 gen_sphere(&tmp, HINGE_RAD * 0.5, 8, 4);
188 tmp.apply_xform(stud_xform * squash);
189 hinges->append(tmp);
190 }
191 }
193 Object *ohinges = new Object;
194 ohinges->set_mesh(hinges);
195 ohinges->set_texture(img_hinge.texture());
196 obj.push_back(ohinges);
198 // debug object
199 /*
200 Mesh *dbgmesh = new Mesh;
201 gen_box(dbgmesh, 0.5, 0.5, 0.5);
202 xform.set_translation(Vector3(0, 0.4, 0));
203 xform.set_scaling(Vector3(1, 1, 1));
204 dbgmesh->apply_xform(xform);
205 Object *dbgobj = new Object;
206 dbgobj->set_mesh(dbgmesh);
207 dbgobj->set_texture(img_hinge.texture());
208 //dbgobj->tex_xform().set_scaling(Vector3(3, 3, 3));
209 obj.push_back(dbgobj);
210 */
212 Mesh *piece = new Mesh;
213 gen_revol(piece, 18, 15, piece_revol, 0);
215 Object *opiece = new Object;
216 opiece->set_mesh(piece);
217 opiece->xform().set_translation(Vector3(0, 0.2, 0));
218 obj.push_back(opiece);
221 // meshgen stats
222 printf("Generated board:\n %u meshes\n", (unsigned int)obj.size());
223 unsigned int polycount = 0;
224 for(size_t i=0; i<obj.size(); i++) {
225 const Mesh *m = obj[i]->get_mesh();
226 polycount += m->get_poly_count();
227 }
228 printf(" %u polygons\n", polycount);
230 return true;
231 }
233 static float wood(float x, float y)
234 {
235 float u = x;
236 float v = y;
237 x += 1.0;
238 x *= 10.0;
239 y *= 20.0;
241 float len = sqrt(x * x + y * y) + turbulence2(u * 6.0, v * 12.0, 2) * 1.2 +
242 turbulence2(u * 0.5, v, 2) * 15.0;
243 float val = fmod(len, 1.0);
245 //val = val * 0.5 + 0.5;
246 return val < 0.0 ? 0.0 : (val > 1.0 ? 1.0 : val);
247 }
249 static float wood_tile(float x, float y)
250 {
251 float u = x;
252 float v = y;
253 x *= 10.0;
254 y *= 10.0;
256 float val = x + pnoise2(u * 6.0, v, 6, 1) * 3.0 +
257 pturbulence2(u * 4, v * 2, 4, 2, 2) * 1.5 + pturbulence2(u * 8, v * 8, 8, 8, 2) * 0.5;
259 val = fmod(val, 1.0);
260 return val < 0.0 ? 0.0 : (val > 1.0 ? 1.0 : val);
261 }
263 static bool spike(float x, float y)
264 {
265 x = fmod(x * 5.0, 1.0);
266 return y < (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x);
267 }
269 static bool circle(float x, float y, float rad)
270 {
271 x = fmod(x * 5.0, 1.0) - 0.5;
272 y = (y - 0.65) * 5.0;
273 float len = sqrt(x * x + y * y);
274 return len < rad;
275 }
277 static bool diamond(float x, float y)
278 {
279 return y >= (1.0 - (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x)) * 0.3333333 + 0.88;
280 }
282 static bool center_circle(float x, float y, float rad)
283 {
284 x = x - 0.5;
285 y = 1.0 - y;
286 return sqrt(x * x + y * y) < rad;
287 }
289 bool Board::generate_textures()
290 {
291 // ---- board field texture ----
292 static const Vector3 wcol1 = Vector3(0.6, 0.4, 0.2);
293 static const Vector3 wcol2 = Vector3(0.53, 0.32, 0.1);
294 static const Vector3 wcol3 = Vector3(0.38, 0.25, 0.08);
296 img_field.create(1024, 1024);
297 unsigned char *pptr = img_field.pixels;
298 for(int i=0; i<img_field.height; i++) {
299 float v = (float)i / (float)img_field.height;
301 for(int j=0; j<img_field.width; j++) {
302 float u = (float)j / (float)img_field.width;
304 int r = 0, g = 0, b = 0;
306 float wood_val = wood(u, v);
308 // pattern mask
309 float x = u;
310 float y = v < 0.5 ? v * 2.0 : 2.0 - v * 2.0;
311 bool inside = false;
313 inside |= (spike(x, y + 0.33333) && !spike(x, y + 0.4)) ||
314 (spike(x, y + 0.5) && !spike(x, y + 0.68));
315 inside |= (circle(x, y, 0.12) && !circle(x, y, 0.1)) || circle(x, y, 0.06);
316 inside |= (diamond(x, y) && !diamond(x, y - 0.015)) ||
317 (diamond(x, y - 0.023) && !diamond(x, y - 0.028));
318 inside |= center_circle(x, y, 0.03);
320 Vector3 wood_color = lerp(wcol1, wcol2, wood_val) * 0.9;
321 if(inside) {
322 wood_color = lerp(wcol1, wcol2, 1.0 - wood_val) * 2.0;
323 }
325 r = (int)(wood_color.x * 255.0);
326 g = (int)(wood_color.y * 255.0);
327 b = (int)(wood_color.z * 255.0);
329 pptr[0] = r > 255 ? 255 : r;
330 pptr[1] = g > 255 ? 255 : g;
331 pptr[2] = b > 255 ? 255 : b;
332 pptr += 3;
333 }
334 }
335 img_field.texture();
337 // ---- generic wood texture ----
338 img_wood.create(256, 256);
339 pptr = img_wood.pixels;
340 for(int i=0; i<img_wood.height; i++) {
341 float v = (float)i / (float)img_wood.height;
342 for(int j=0; j<img_wood.width; j++) {
343 float u = (float)j / (float)img_wood.width;
345 float wood_val = wood_tile(u, v);
346 Vector3 wood_color = lerp(wcol2, wcol3, wood_val) * 0.7;
348 int r = (int)(wood_color.x * 255.0);
349 int g = (int)(wood_color.y * 255.0);
350 int b = (int)(wood_color.z * 255.0);
352 pptr[0] = r > 255 ? 255 : r;
353 pptr[1] = g > 255 ? 255 : g;
354 pptr[2] = b > 255 ? 255 : b;
355 pptr += 3;
356 }
357 }
358 img_wood.texture();
360 // ---- metal hinge diffuse texture ----
361 Vector3 rusty_col1 = Vector3(0.43, 0.46, 0.52);
362 Vector3 rusty_col2 = Vector3(0.52, 0.47, 0.43);
364 img_hinge.create(128, 128);
365 pptr = img_hinge.pixels;
366 for(int i=0; i<img_hinge.height; i++) {
367 float v = (float)i / (float)img_hinge.height;
368 for(int j=0; j<img_hinge.width; j++) {
369 float u = (float)j / (float)img_hinge.width;
371 // rust pattern
372 float w1 = fbm2(u * 4.0, v * 4.0, 3) * 0.5 + 0.5;
373 //float w2 = fbm2(u * 8.0, v * 8.0, 1) * 0.5 + 0.5;
374 Vector3 col = lerp(rusty_col1, rusty_col2 * 0.5, w1);
376 // center hinge split
377 if(fabs(v - 0.5) < 0.01) {
378 col *= 0.5;
379 }
381 int r = (int)(col.x * 255.0);
382 int g = (int)(col.y * 255.0);
383 int b = (int)(col.z * 255.0);
385 pptr[0] = r > 255 ? 255 : (r < 0 ? 0 : r);
386 pptr[1] = g > 255 ? 255 : (g < 0 ? 0 : g);
387 pptr[2] = b > 255 ? 255 : (b < 0 ? 0 : b);
389 pptr += 3;
390 }
391 }
392 img_hinge.texture();
394 return true;
395 }