tavli

view src/board.cc @ 13:f3c5134b4914

generalized the surfaces of revolution evaluator a bit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 27 Jun 2015 22:33:27 +0300
parents ae1c60726c41
children 283eb6e9f0a3
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 struct BezCurve {
64 int numcp;
65 vec2_t *cp;
66 float scale;
67 };
69 static const vec2_t piece_cp[] = {
70 {0, 0.25},
71 {1, 0.25}, // mid0
72 {2, 0.5},
73 {2.5, 0.5}, // mid1
74 {3, 0.5},
75 {4, 0.5}, // mid2
76 {4, 0},
77 {4, -0.5}, // mid3
78 {3, -0.5},
79 {2.5, -0.5}, // mid4
80 {0, -0.5}
81 };
82 static const BezCurve piece_curve = {sizeof piece_cp / sizeof *piece_cp, (vec2_t*)piece_cp, 0.25 * PIECE_RAD};
85 static Vector2 piece_revol(float u, float v, void *cls)
86 {
87 BezCurve *curve = (BezCurve*)cls;
88 int nseg = (curve->numcp - 1) / 2;
90 if(v >= 1.0) v = 1.0 - 1e-6;
91 int cidx = std::min((int)(v * nseg), nseg - 1);
92 float t = fmod(v * (float)nseg, 1.0);
94 const vec2_t *cp = curve->cp + cidx * 2;
96 float resx = bezier(cp[0].x, cp[1].x, cp[1].x, cp[2].x, t);
97 float resy = bezier(cp[0].y, cp[1].y, cp[1].y, cp[2].y, t);
98 return Vector2(resx * curve->scale, resy * curve->scale);
99 }
101 static Vector2 piece_revol_normal(float u, float v, void *cls)
102 {
103 BezCurve *curve = (BezCurve*)cls;
104 int nseg = (curve->numcp - 1) / 2;
106 if(v >= 1.0) v = 1.0 - 1e-6;
107 int cidx = std::min((int)(v * nseg), nseg - 1);
108 float t = fmod(v * (float)nseg, 1.0);
110 const vec2_t *cp = curve->cp + cidx * 2;
111 Vector2 cp0 = cp[0];
112 Vector2 cp1 = cp[1];
113 Vector2 cp2 = cp[2];
115 Vector2 pprev, pnext;
116 for(int i=0; i<2; i++) {
117 pprev[i] = bezier(cp0[i], cp1[i], cp1[i], cp2[i], t - 0.05);
118 pnext[i] = bezier(cp0[i], cp1[i], cp1[i], cp2[i], t + 0.05);
119 }
121 float tx = pnext.x - pprev.x;
122 float ty = pnext.y - pprev.y;
124 return Vector2(-ty, tx);
125 }
127 bool Board::generate()
128 {
129 Mesh tmp;
130 Matrix4x4 xform;
132 obj.clear();
134 for(int i=0; i<2; i++) {
135 int sign = i * 2 - 1;
137 // generate bottom
138 Mesh *bottom = new Mesh;
139 gen_box(bottom, HSIZE, BOT_THICKNESS, HSIZE * 2.0);
140 xform.set_translation(Vector3(0, -BOT_THICKNESS / 2.0, 0));
141 bottom->apply_xform(xform);
143 Object *obottom = new Object;
144 obottom->set_mesh(bottom);
145 obottom->xform().set_translation(Vector3(sign * (HSIZE / 2.0 + WALL_THICKNESS + HINGE_RAD * 0.25), 0, 0));
146 obottom->set_texture(img_field.texture());
147 obj.push_back(obottom);
150 // generate the 4 sides
151 Mesh *sides = new Mesh;
152 gen_box(sides, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2);
153 xform.set_translation(Vector3(-(HSIZE + WALL_THICKNESS) / 2.0,
154 WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0));
155 sides->apply_xform(xform);
157 gen_box(&tmp, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2);
158 xform.set_translation(Vector3((HSIZE + WALL_THICKNESS) / 2.0,
159 WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0));
160 tmp.apply_xform(xform);
161 sides->append(tmp);
162 tmp.clear();
164 gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS);
165 xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS,
166 (VSIZE + WALL_THICKNESS) / 2.0));
167 tmp.apply_xform(xform);
168 sides->append(tmp);
169 tmp.clear();
171 gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS);
172 xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS,
173 -(VSIZE + WALL_THICKNESS) / 2.0));
174 tmp.apply_xform(xform);
175 sides->append(tmp);
176 tmp.clear();
178 // generate texture coordinates
179 sides->texcoord_gen_box();
181 Object *osides = new Object;
182 osides->set_mesh(sides);
183 osides->xform() = obottom->xform();
184 osides->set_texture(img_wood.texture());
185 osides->tex_xform().set_scaling(Vector3(2, 2, 2));
186 osides->tex_xform().rotate(-Vector3(1, 0, 0.5), M_PI / 4.0);
187 obj.push_back(osides);
189 }
192 // generate the hinges
193 Mesh *hinges = new Mesh;
194 for(int i=0; i<2; i++) {
195 float sign = i * 2 - 1;
197 // barrel
198 gen_cylinder(&tmp, HINGE_RAD, HINGE_HEIGHT, 8, 1, 1);
199 xform.reset_identity();
200 xform.translate(Vector3(0, WALL_HEIGHT - HINGE_RAD * 0.5, sign * VSIZE / 4.0));
201 xform.rotate(Vector3(-M_PI / 2.0, 0, 0));
202 tmp.apply_xform(xform);
203 hinges->append(tmp);
205 // flange
206 gen_plane(&tmp, HINGE_HEIGHT * 0.6, HINGE_HEIGHT * 0.8);
207 tmp.apply_xform(xform);
209 Matrix4x4 tex_xform;
210 tex_xform.set_rotation(Vector3(0, 0, M_PI / 2.0));
211 tmp.texcoord_apply_xform(tex_xform);
212 hinges->append(tmp);
214 // studs
215 for(int j=0; j<4; j++) {
216 Vector3 pos;
218 pos.x = (float)((j & 1) * 2 - 1) * HINGE_HEIGHT * 0.2;
219 pos.y = (float)((j & 2) - 1) * HINGE_HEIGHT * 0.3;
221 Matrix4x4 stud_xform = xform;
222 stud_xform.translate(pos);
224 Matrix4x4 squash;
225 squash.set_scaling(Vector3(1, 1, 0.5));
227 gen_sphere(&tmp, HINGE_RAD * 0.5, 8, 4);
228 tmp.apply_xform(stud_xform * squash);
229 hinges->append(tmp);
230 }
231 }
233 Object *ohinges = new Object;
234 ohinges->set_mesh(hinges);
235 ohinges->set_texture(img_hinge.texture());
236 obj.push_back(ohinges);
238 // debug object
239 /*
240 Mesh *dbgmesh = new Mesh;
241 gen_box(dbgmesh, 0.5, 0.5, 0.5);
242 xform.set_translation(Vector3(0, 0.4, 0));
243 xform.set_scaling(Vector3(1, 1, 1));
244 dbgmesh->apply_xform(xform);
245 Object *dbgobj = new Object;
246 dbgobj->set_mesh(dbgmesh);
247 dbgobj->set_texture(img_hinge.texture());
248 //dbgobj->tex_xform().set_scaling(Vector3(3, 3, 3));
249 obj.push_back(dbgobj);
250 */
252 Mesh *piece = new Mesh;
253 gen_revol(piece, 18, 17, piece_revol, piece_revol_normal, (void*)&piece_curve);
255 Object *opiece = new Object;
256 opiece->set_mesh(piece);
257 opiece->mtl.diffuse = Vector3(0.6, 0.6, 0.6);
258 opiece->mtl.specular = Vector3(0.8, 0.8, 0.8);
259 opiece->xform().set_translation(Vector3(0, 0.2, 0));
260 obj.push_back(opiece);
263 // meshgen stats
264 printf("Generated board:\n %u meshes\n", (unsigned int)obj.size());
265 unsigned int polycount = 0;
266 for(size_t i=0; i<obj.size(); i++) {
267 const Mesh *m = obj[i]->get_mesh();
268 polycount += m->get_poly_count();
269 }
270 printf(" %u polygons\n", polycount);
272 return true;
273 }
275 static float wood(float x, float y)
276 {
277 float u = x;
278 float v = y;
279 x += 1.0;
280 x *= 10.0;
281 y *= 20.0;
283 float len = sqrt(x * x + y * y) + turbulence2(u * 6.0, v * 12.0, 2) * 1.2 +
284 turbulence2(u * 0.5, v, 2) * 15.0;
285 float val = fmod(len, 1.0);
287 //val = val * 0.5 + 0.5;
288 return val < 0.0 ? 0.0 : (val > 1.0 ? 1.0 : val);
289 }
291 static float wood_tile(float x, float y)
292 {
293 float u = x;
294 float v = y;
295 x *= 10.0;
296 y *= 10.0;
298 float val = x + pnoise2(u * 6.0, v, 6, 1) * 3.0 +
299 pturbulence2(u * 4, v * 2, 4, 2, 2) * 1.5 + pturbulence2(u * 8, v * 8, 8, 8, 2) * 0.5;
301 val = fmod(val, 1.0);
302 return val < 0.0 ? 0.0 : (val > 1.0 ? 1.0 : val);
303 }
305 static bool spike(float x, float y)
306 {
307 x = fmod(x * 5.0, 1.0);
308 return y < (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x);
309 }
311 static bool circle(float x, float y, float rad)
312 {
313 x = fmod(x * 5.0, 1.0) - 0.5;
314 y = (y - 0.65) * 5.0;
315 float len = sqrt(x * x + y * y);
316 return len < rad;
317 }
319 static bool diamond(float x, float y)
320 {
321 return y >= (1.0 - (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x)) * 0.3333333 + 0.88;
322 }
324 static bool center_circle(float x, float y, float rad)
325 {
326 x = x - 0.5;
327 y = 1.0 - y;
328 return sqrt(x * x + y * y) < rad;
329 }
331 bool Board::generate_textures()
332 {
333 // ---- board field texture ----
334 static const Vector3 wcol1 = Vector3(0.6, 0.4, 0.2);
335 static const Vector3 wcol2 = Vector3(0.53, 0.32, 0.1);
336 static const Vector3 wcol3 = Vector3(0.38, 0.25, 0.08);
338 img_field.create(1024, 1024);
339 unsigned char *pptr = img_field.pixels;
340 for(int i=0; i<img_field.height; i++) {
341 float v = (float)i / (float)img_field.height;
343 for(int j=0; j<img_field.width; j++) {
344 float u = (float)j / (float)img_field.width;
346 int r = 0, g = 0, b = 0;
348 float wood_val = wood(u, v);
350 // pattern mask
351 float x = u;
352 float y = v < 0.5 ? v * 2.0 : 2.0 - v * 2.0;
353 bool inside = false;
355 inside |= (spike(x, y + 0.33333) && !spike(x, y + 0.4)) ||
356 (spike(x, y + 0.5) && !spike(x, y + 0.68));
357 inside |= (circle(x, y, 0.12) && !circle(x, y, 0.1)) || circle(x, y, 0.06);
358 inside |= (diamond(x, y) && !diamond(x, y - 0.015)) ||
359 (diamond(x, y - 0.023) && !diamond(x, y - 0.028));
360 inside |= center_circle(x, y, 0.03);
362 Vector3 wood_color = lerp(wcol1, wcol2, wood_val) * 0.9;
363 if(inside) {
364 wood_color = lerp(wcol1, wcol2, 1.0 - wood_val) * 2.0;
365 }
367 r = (int)(wood_color.x * 255.0);
368 g = (int)(wood_color.y * 255.0);
369 b = (int)(wood_color.z * 255.0);
371 pptr[0] = r > 255 ? 255 : r;
372 pptr[1] = g > 255 ? 255 : g;
373 pptr[2] = b > 255 ? 255 : b;
374 pptr += 3;
375 }
376 }
377 img_field.texture();
379 // ---- generic wood texture ----
380 img_wood.create(256, 256);
381 pptr = img_wood.pixels;
382 for(int i=0; i<img_wood.height; i++) {
383 float v = (float)i / (float)img_wood.height;
384 for(int j=0; j<img_wood.width; j++) {
385 float u = (float)j / (float)img_wood.width;
387 float wood_val = wood_tile(u, v);
388 Vector3 wood_color = lerp(wcol2, wcol3, wood_val) * 0.7;
390 int r = (int)(wood_color.x * 255.0);
391 int g = (int)(wood_color.y * 255.0);
392 int b = (int)(wood_color.z * 255.0);
394 pptr[0] = r > 255 ? 255 : r;
395 pptr[1] = g > 255 ? 255 : g;
396 pptr[2] = b > 255 ? 255 : b;
397 pptr += 3;
398 }
399 }
400 img_wood.texture();
402 // ---- metal hinge diffuse texture ----
403 Vector3 rusty_col1 = Vector3(0.43, 0.46, 0.52);
404 Vector3 rusty_col2 = Vector3(0.52, 0.47, 0.43);
406 img_hinge.create(128, 128);
407 pptr = img_hinge.pixels;
408 for(int i=0; i<img_hinge.height; i++) {
409 float v = (float)i / (float)img_hinge.height;
410 for(int j=0; j<img_hinge.width; j++) {
411 float u = (float)j / (float)img_hinge.width;
413 // rust pattern
414 float w1 = fbm2(u * 4.0, v * 4.0, 3) * 0.5 + 0.5;
415 //float w2 = fbm2(u * 8.0, v * 8.0, 1) * 0.5 + 0.5;
416 Vector3 col = lerp(rusty_col1, rusty_col2 * 0.5, w1);
418 // center hinge split
419 if(fabs(v - 0.5) < 0.01) {
420 col *= 0.5;
421 }
423 int r = (int)(col.x * 255.0);
424 int g = (int)(col.y * 255.0);
425 int b = (int)(col.z * 255.0);
427 pptr[0] = r > 255 ? 255 : (r < 0 ? 0 : r);
428 pptr[1] = g > 255 ? 255 : (g < 0 ? 0 : g);
429 pptr[2] = b > 255 ? 255 : (b < 0 ? 0 : b);
431 pptr += 3;
432 }
433 }
434 img_hinge.texture();
436 return true;
437 }