tavli

view src/board.cc @ 12:ae1c60726c41

better pieces
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 27 Jun 2015 13:53:43 +0300
parents a8e26f163f99
children f3c5134b4914
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 static Vector2 piece_revol_normal(float u, float v, void *cls)
88 {
89 if(v >= 1.0) v = 1.0 - 1e-6;
90 int idx = std::min((int)(v * piece_ncurves), piece_ncurves - 1);
91 float t = fmod(v * (float)piece_ncurves, 1.0);
93 Vector2 pprev, pnext;
94 for(int i=0; i<2; i++) {
95 float start = piece_cp[idx][0][i];
96 float mid = piece_cp[idx][1][i];
97 float end = piece_cp[idx][2][i];
99 pprev[i] = bezier(start, mid, mid, end, t - 0.05);
100 pnext[i] = bezier(start, mid, mid, end, t + 0.05);
101 }
103 float tx = pnext.x - pprev.x;
104 float ty = pnext.y - pprev.y;
106 return Vector2(-ty, tx);
107 }
109 bool Board::generate()
110 {
111 Mesh tmp;
112 Matrix4x4 xform;
114 obj.clear();
116 for(int i=0; i<2; i++) {
117 int sign = i * 2 - 1;
119 // generate bottom
120 Mesh *bottom = new Mesh;
121 gen_box(bottom, HSIZE, BOT_THICKNESS, HSIZE * 2.0);
122 xform.set_translation(Vector3(0, -BOT_THICKNESS / 2.0, 0));
123 bottom->apply_xform(xform);
125 Object *obottom = new Object;
126 obottom->set_mesh(bottom);
127 obottom->xform().set_translation(Vector3(sign * (HSIZE / 2.0 + WALL_THICKNESS + HINGE_RAD * 0.25), 0, 0));
128 obottom->set_texture(img_field.texture());
129 obj.push_back(obottom);
132 // generate the 4 sides
133 Mesh *sides = new Mesh;
134 gen_box(sides, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2);
135 xform.set_translation(Vector3(-(HSIZE + WALL_THICKNESS) / 2.0,
136 WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0));
137 sides->apply_xform(xform);
139 gen_box(&tmp, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2);
140 xform.set_translation(Vector3((HSIZE + WALL_THICKNESS) / 2.0,
141 WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0));
142 tmp.apply_xform(xform);
143 sides->append(tmp);
144 tmp.clear();
146 gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS);
147 xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS,
148 (VSIZE + WALL_THICKNESS) / 2.0));
149 tmp.apply_xform(xform);
150 sides->append(tmp);
151 tmp.clear();
153 gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS);
154 xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS,
155 -(VSIZE + WALL_THICKNESS) / 2.0));
156 tmp.apply_xform(xform);
157 sides->append(tmp);
158 tmp.clear();
160 // generate texture coordinates
161 sides->texcoord_gen_box();
163 Object *osides = new Object;
164 osides->set_mesh(sides);
165 osides->xform() = obottom->xform();
166 osides->set_texture(img_wood.texture());
167 osides->tex_xform().set_scaling(Vector3(2, 2, 2));
168 osides->tex_xform().rotate(-Vector3(1, 0, 0.5), M_PI / 4.0);
169 obj.push_back(osides);
171 }
174 // generate the hinges
175 Mesh *hinges = new Mesh;
176 for(int i=0; i<2; i++) {
177 float sign = i * 2 - 1;
179 // barrel
180 gen_cylinder(&tmp, HINGE_RAD, HINGE_HEIGHT, 8, 1, 1);
181 xform.reset_identity();
182 xform.translate(Vector3(0, WALL_HEIGHT - HINGE_RAD * 0.5, sign * VSIZE / 4.0));
183 xform.rotate(Vector3(-M_PI / 2.0, 0, 0));
184 tmp.apply_xform(xform);
185 hinges->append(tmp);
187 // flange
188 gen_plane(&tmp, HINGE_HEIGHT * 0.6, HINGE_HEIGHT * 0.8);
189 tmp.apply_xform(xform);
191 Matrix4x4 tex_xform;
192 tex_xform.set_rotation(Vector3(0, 0, M_PI / 2.0));
193 tmp.texcoord_apply_xform(tex_xform);
194 hinges->append(tmp);
196 // studs
197 for(int j=0; j<4; j++) {
198 Vector3 pos;
200 pos.x = (float)((j & 1) * 2 - 1) * HINGE_HEIGHT * 0.2;
201 pos.y = (float)((j & 2) - 1) * HINGE_HEIGHT * 0.3;
203 Matrix4x4 stud_xform = xform;
204 stud_xform.translate(pos);
206 Matrix4x4 squash;
207 squash.set_scaling(Vector3(1, 1, 0.5));
209 gen_sphere(&tmp, HINGE_RAD * 0.5, 8, 4);
210 tmp.apply_xform(stud_xform * squash);
211 hinges->append(tmp);
212 }
213 }
215 Object *ohinges = new Object;
216 ohinges->set_mesh(hinges);
217 ohinges->set_texture(img_hinge.texture());
218 obj.push_back(ohinges);
220 // debug object
221 /*
222 Mesh *dbgmesh = new Mesh;
223 gen_box(dbgmesh, 0.5, 0.5, 0.5);
224 xform.set_translation(Vector3(0, 0.4, 0));
225 xform.set_scaling(Vector3(1, 1, 1));
226 dbgmesh->apply_xform(xform);
227 Object *dbgobj = new Object;
228 dbgobj->set_mesh(dbgmesh);
229 dbgobj->set_texture(img_hinge.texture());
230 //dbgobj->tex_xform().set_scaling(Vector3(3, 3, 3));
231 obj.push_back(dbgobj);
232 */
234 Mesh *piece = new Mesh;
235 gen_revol(piece, 18, 17, piece_revol, piece_revol_normal, 0);
237 Object *opiece = new Object;
238 opiece->set_mesh(piece);
239 opiece->mtl.diffuse = Vector3(0.6, 0.6, 0.6);
240 opiece->mtl.specular = Vector3(0.8, 0.8, 0.8);
241 opiece->xform().set_translation(Vector3(0, 0.2, 0));
242 obj.push_back(opiece);
245 // meshgen stats
246 printf("Generated board:\n %u meshes\n", (unsigned int)obj.size());
247 unsigned int polycount = 0;
248 for(size_t i=0; i<obj.size(); i++) {
249 const Mesh *m = obj[i]->get_mesh();
250 polycount += m->get_poly_count();
251 }
252 printf(" %u polygons\n", polycount);
254 return true;
255 }
257 static float wood(float x, float y)
258 {
259 float u = x;
260 float v = y;
261 x += 1.0;
262 x *= 10.0;
263 y *= 20.0;
265 float len = sqrt(x * x + y * y) + turbulence2(u * 6.0, v * 12.0, 2) * 1.2 +
266 turbulence2(u * 0.5, v, 2) * 15.0;
267 float val = fmod(len, 1.0);
269 //val = val * 0.5 + 0.5;
270 return val < 0.0 ? 0.0 : (val > 1.0 ? 1.0 : val);
271 }
273 static float wood_tile(float x, float y)
274 {
275 float u = x;
276 float v = y;
277 x *= 10.0;
278 y *= 10.0;
280 float val = x + pnoise2(u * 6.0, v, 6, 1) * 3.0 +
281 pturbulence2(u * 4, v * 2, 4, 2, 2) * 1.5 + pturbulence2(u * 8, v * 8, 8, 8, 2) * 0.5;
283 val = fmod(val, 1.0);
284 return val < 0.0 ? 0.0 : (val > 1.0 ? 1.0 : val);
285 }
287 static bool spike(float x, float y)
288 {
289 x = fmod(x * 5.0, 1.0);
290 return y < (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x);
291 }
293 static bool circle(float x, float y, float rad)
294 {
295 x = fmod(x * 5.0, 1.0) - 0.5;
296 y = (y - 0.65) * 5.0;
297 float len = sqrt(x * x + y * y);
298 return len < rad;
299 }
301 static bool diamond(float x, float y)
302 {
303 return y >= (1.0 - (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x)) * 0.3333333 + 0.88;
304 }
306 static bool center_circle(float x, float y, float rad)
307 {
308 x = x - 0.5;
309 y = 1.0 - y;
310 return sqrt(x * x + y * y) < rad;
311 }
313 bool Board::generate_textures()
314 {
315 // ---- board field texture ----
316 static const Vector3 wcol1 = Vector3(0.6, 0.4, 0.2);
317 static const Vector3 wcol2 = Vector3(0.53, 0.32, 0.1);
318 static const Vector3 wcol3 = Vector3(0.38, 0.25, 0.08);
320 img_field.create(1024, 1024);
321 unsigned char *pptr = img_field.pixels;
322 for(int i=0; i<img_field.height; i++) {
323 float v = (float)i / (float)img_field.height;
325 for(int j=0; j<img_field.width; j++) {
326 float u = (float)j / (float)img_field.width;
328 int r = 0, g = 0, b = 0;
330 float wood_val = wood(u, v);
332 // pattern mask
333 float x = u;
334 float y = v < 0.5 ? v * 2.0 : 2.0 - v * 2.0;
335 bool inside = false;
337 inside |= (spike(x, y + 0.33333) && !spike(x, y + 0.4)) ||
338 (spike(x, y + 0.5) && !spike(x, y + 0.68));
339 inside |= (circle(x, y, 0.12) && !circle(x, y, 0.1)) || circle(x, y, 0.06);
340 inside |= (diamond(x, y) && !diamond(x, y - 0.015)) ||
341 (diamond(x, y - 0.023) && !diamond(x, y - 0.028));
342 inside |= center_circle(x, y, 0.03);
344 Vector3 wood_color = lerp(wcol1, wcol2, wood_val) * 0.9;
345 if(inside) {
346 wood_color = lerp(wcol1, wcol2, 1.0 - wood_val) * 2.0;
347 }
349 r = (int)(wood_color.x * 255.0);
350 g = (int)(wood_color.y * 255.0);
351 b = (int)(wood_color.z * 255.0);
353 pptr[0] = r > 255 ? 255 : r;
354 pptr[1] = g > 255 ? 255 : g;
355 pptr[2] = b > 255 ? 255 : b;
356 pptr += 3;
357 }
358 }
359 img_field.texture();
361 // ---- generic wood texture ----
362 img_wood.create(256, 256);
363 pptr = img_wood.pixels;
364 for(int i=0; i<img_wood.height; i++) {
365 float v = (float)i / (float)img_wood.height;
366 for(int j=0; j<img_wood.width; j++) {
367 float u = (float)j / (float)img_wood.width;
369 float wood_val = wood_tile(u, v);
370 Vector3 wood_color = lerp(wcol2, wcol3, wood_val) * 0.7;
372 int r = (int)(wood_color.x * 255.0);
373 int g = (int)(wood_color.y * 255.0);
374 int b = (int)(wood_color.z * 255.0);
376 pptr[0] = r > 255 ? 255 : r;
377 pptr[1] = g > 255 ? 255 : g;
378 pptr[2] = b > 255 ? 255 : b;
379 pptr += 3;
380 }
381 }
382 img_wood.texture();
384 // ---- metal hinge diffuse texture ----
385 Vector3 rusty_col1 = Vector3(0.43, 0.46, 0.52);
386 Vector3 rusty_col2 = Vector3(0.52, 0.47, 0.43);
388 img_hinge.create(128, 128);
389 pptr = img_hinge.pixels;
390 for(int i=0; i<img_hinge.height; i++) {
391 float v = (float)i / (float)img_hinge.height;
392 for(int j=0; j<img_hinge.width; j++) {
393 float u = (float)j / (float)img_hinge.width;
395 // rust pattern
396 float w1 = fbm2(u * 4.0, v * 4.0, 3) * 0.5 + 0.5;
397 //float w2 = fbm2(u * 8.0, v * 8.0, 1) * 0.5 + 0.5;
398 Vector3 col = lerp(rusty_col1, rusty_col2 * 0.5, w1);
400 // center hinge split
401 if(fabs(v - 0.5) < 0.01) {
402 col *= 0.5;
403 }
405 int r = (int)(col.x * 255.0);
406 int g = (int)(col.y * 255.0);
407 int b = (int)(col.z * 255.0);
409 pptr[0] = r > 255 ? 255 : (r < 0 ? 0 : r);
410 pptr[1] = g > 255 ? 255 : (g < 0 ? 0 : g);
411 pptr[2] = b > 255 ? 255 : (b < 0 ? 0 : b);
413 pptr += 3;
414 }
415 }
416 img_hinge.texture();
418 return true;
419 }