tavli

view src/board.cc @ 17:16a420432aa3

pieces on the board
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 28 Jun 2015 23:04:37 +0300
parents b1a195c3ee16
children 986c0b76513f
line source
1 #include <float.h>
2 #include "opengl.h"
3 #include "board.h"
4 #include "game.h"
5 #include "meshgen.h"
6 #include "pnoise.h"
7 #include "revol.h"
8 #include "opt.h"
11 #define HSIZE 1.0
12 #define VSIZE (2.0 * HSIZE)
13 #define BOT_THICKNESS (HSIZE * 0.01)
14 #define WALL_THICKNESS (HSIZE * 0.05)
15 #define WALL_HEIGHT (HSIZE * 0.1)
16 #define GAP (HSIZE * 0.025)
17 #define HINGE_RAD (GAP * 0.5)
18 #define HINGE_HEIGHT (VSIZE * 0.075)
19 #define PIECE_RAD (0.45 * HSIZE / 5.0)
20 #define BOARD_OFFSET (HSIZE / 2.0 + WALL_THICKNESS + HINGE_RAD * 0.25)
21 #define PIECES_PER_LAYER 5
24 Piece::Piece()
25 {
26 owner = 0;
27 slot = prev_slot = -1;
28 level = 0;
29 move_start = 0;
30 }
32 void Piece::move_to(int slot, int level, bool anim)
33 {
34 int prev_slot = this->slot;
35 int prev_level = this->level;
37 this->slot = slot;
38 this->level = level;
40 if(anim) {
41 this->prev_slot = prev_slot;
42 this->prev_level = prev_level;
43 move_start = cur_time;
44 }
45 }
48 Board::Board()
49 {
50 piece_obj = 0;
51 clear();
52 }
54 Board::~Board()
55 {
56 destroy();
57 }
59 bool Board::init()
60 {
61 if(!generate_textures()) {
62 return false;
63 }
64 if(!generate()) {
65 return false;
66 }
68 return true;
69 }
71 void Board::destroy()
72 {
73 for(size_t i=0; i<obj.size(); i++) {
74 delete obj[i];
75 }
76 obj.clear();
78 delete piece_obj;
79 piece_obj = 0;
80 }
82 void Board::clear()
83 {
84 memset(hist, 0, sizeof hist);
86 for(int i=0; i<MAX_PIECES; i++) {
87 pieces[i].owner = i < PLAYER_PIECES ? MINE : OTHER;
88 move_piece(i, -1, false);
89 }
90 }
92 void Board::setup()
93 {
94 static const int initial[] = { 0, 0, 0, 0, 5, 0, 3, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
96 clear();
98 int id = 0;
99 for(int i=0; i<NUM_SLOTS; i++) {
100 for(int j=0; j<initial[i]; j++) {
101 move_piece(id, i, false);
102 move_piece(PLAYER_PIECES + id, NUM_SLOTS - i - 1, false);
103 ++id;
104 }
105 }
106 }
108 int Board::slot_pieces(int slot) const
109 {
110 return hist[slot + 1];
111 }
113 bool Board::move_piece(int id, int slot, bool anim)
114 {
115 // TODO do validity checking first
116 int prev_slot = pieces[id].slot;
118 pieces[id].move_to(slot, slot_pieces(slot), anim);
119 --hist[prev_slot + 1];
120 ++hist[slot + 1];
121 return true;
122 }
124 Vector3 Board::piece_pos(int slot, int level) const
125 {
126 int top_side = slot / 10;
127 int sidx = (top_side ? (19 - slot) : slot) % 5;
128 int left_side = (top_side ? (19 - slot) : slot) / 5;
130 Vector3 pos;
132 if(left_side) {
133 pos.x = -(sidx * HSIZE / 5.0 + BOARD_OFFSET - HSIZE / 2.0) - PIECE_RAD;
134 } else {
135 pos.x = (4 - sidx) * HSIZE / 5.0 + BOARD_OFFSET - HSIZE / 2.0 + PIECE_RAD;
136 }
138 int layer = level / PIECES_PER_LAYER;
139 int layer_level = level % PIECES_PER_LAYER;
141 pos.y = (layer + 1) * 0.25 * PIECE_RAD;
143 pos.z = (-VSIZE * 0.5 + PIECE_RAD + PIECE_RAD * 2.0 * layer_level);
144 if(top_side) {
145 pos.z = -pos.z;
146 }
148 return pos;
149 }
151 void Board::draw() const
152 {
153 for(size_t i=0; i<obj.size(); i++) {
154 if(wireframe) {
155 obj[i]->draw_wire();
156 obj[i]->draw_normals(0.075);
157 } else {
158 obj[i]->draw();
159 }
160 }
162 for(int i=0; i<MAX_PIECES; i++) {
163 Vector3 pos = piece_pos(pieces[i].slot, pieces[i].level);
164 piece_obj->xform().set_translation(pos);
165 piece_obj->mtl.diffuse = opt.piece_color[pieces[i].owner];
166 piece_obj->draw();
167 }
168 }
171 static const vec2_t piece_cp[] = {
172 {0, 0.25},
173 {1, 0.25}, // mid0
174 {2, 0.5},
175 {2.5, 0.5}, // mid1
176 {3, 0.5},
177 {4, 0.5}, // mid2
178 {4, 0},
179 {4, -0.5}, // mid3
180 {3, -0.5},
181 {2.5, -0.5}, // mid4
182 {0, -0.5}
183 };
184 static const BezCurve piece_curve = {
185 sizeof piece_cp / sizeof *piece_cp,
186 (vec2_t*)piece_cp,
187 0.25 * PIECE_RAD
188 };
191 bool Board::generate()
192 {
193 Mesh tmp;
194 Matrix4x4 xform;
196 obj.clear();
198 for(int i=0; i<2; i++) {
199 int sign = i * 2 - 1;
201 // generate bottom
202 Mesh *bottom = new Mesh;
203 gen_box(bottom, HSIZE, BOT_THICKNESS, HSIZE * 2.0);
204 xform.set_translation(Vector3(0, -BOT_THICKNESS / 2.0, 0));
205 bottom->apply_xform(xform);
207 Object *obottom = new Object;
208 obottom->set_mesh(bottom);
209 obottom->xform().set_translation(Vector3(sign * BOARD_OFFSET, 0, 0));
210 obottom->set_texture(img_field.texture());
211 obj.push_back(obottom);
214 // generate the 4 sides
215 Mesh *sides = new Mesh;
216 gen_box(sides, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2);
217 xform.set_translation(Vector3(-(HSIZE + WALL_THICKNESS) / 2.0,
218 WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0));
219 sides->apply_xform(xform);
221 gen_box(&tmp, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2);
222 xform.set_translation(Vector3((HSIZE + WALL_THICKNESS) / 2.0,
223 WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0));
224 tmp.apply_xform(xform);
225 sides->append(tmp);
226 tmp.clear();
228 gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS);
229 xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS,
230 (VSIZE + WALL_THICKNESS) / 2.0));
231 tmp.apply_xform(xform);
232 sides->append(tmp);
233 tmp.clear();
235 gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS);
236 xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS,
237 -(VSIZE + WALL_THICKNESS) / 2.0));
238 tmp.apply_xform(xform);
239 sides->append(tmp);
240 tmp.clear();
242 // generate texture coordinates
243 sides->texcoord_gen_box();
245 Object *osides = new Object;
246 osides->set_mesh(sides);
247 osides->xform() = obottom->xform();
248 osides->set_texture(img_wood.texture());
249 osides->tex_xform().set_scaling(Vector3(2, 2, 2));
250 osides->tex_xform().rotate(-Vector3(1, 0, 0.5), M_PI / 4.0);
251 obj.push_back(osides);
253 }
256 // generate the hinges
257 Mesh *hinges = new Mesh;
258 for(int i=0; i<2; i++) {
259 float sign = i * 2 - 1;
261 // barrel
262 gen_cylinder(&tmp, HINGE_RAD, HINGE_HEIGHT, 8, 1, 1);
263 xform.reset_identity();
264 xform.translate(Vector3(0, WALL_HEIGHT - HINGE_RAD * 0.5, sign * VSIZE / 4.0));
265 xform.rotate(Vector3(-M_PI / 2.0, 0, 0));
266 tmp.apply_xform(xform);
267 hinges->append(tmp);
269 // flange
270 gen_plane(&tmp, HINGE_HEIGHT * 0.6, HINGE_HEIGHT * 0.8);
271 tmp.apply_xform(xform);
273 Matrix4x4 tex_xform;
274 tex_xform.set_rotation(Vector3(0, 0, M_PI / 2.0));
275 tmp.texcoord_apply_xform(tex_xform);
276 hinges->append(tmp);
278 // studs
279 for(int j=0; j<4; j++) {
280 Vector3 pos;
282 pos.x = (float)((j & 1) * 2 - 1) * HINGE_HEIGHT * 0.2;
283 pos.y = (float)((j & 2) - 1) * HINGE_HEIGHT * 0.3;
285 Matrix4x4 stud_xform = xform;
286 stud_xform.translate(pos);
288 Matrix4x4 squash;
289 squash.set_scaling(Vector3(1, 1, 0.5));
291 gen_sphere(&tmp, HINGE_RAD * 0.5, 8, 4);
292 tmp.apply_xform(stud_xform * squash);
293 hinges->append(tmp);
294 }
295 }
297 Object *ohinges = new Object;
298 ohinges->set_mesh(hinges);
299 ohinges->set_texture(img_hinge.texture());
300 obj.push_back(ohinges);
302 // debug object
303 /*
304 Mesh *dbgmesh = new Mesh;
305 gen_box(dbgmesh, 0.5, 0.5, 0.5);
306 xform.set_translation(Vector3(0, 0.4, 0));
307 xform.set_scaling(Vector3(1, 1, 1));
308 dbgmesh->apply_xform(xform);
309 Object *dbgobj = new Object;
310 dbgobj->set_mesh(dbgmesh);
311 dbgobj->set_texture(img_hinge.texture());
312 //dbgobj->tex_xform().set_scaling(Vector3(3, 3, 3));
313 obj.push_back(dbgobj);
314 */
316 Mesh *piece = new Mesh;
317 gen_revol(piece, 18, 17, bezier_revol, bezier_revol_normal, (void*)&piece_curve);
319 Object *opiece = new Object;
320 opiece->set_mesh(piece);
321 opiece->mtl.diffuse = Vector3(0.6, 0.6, 0.6);
322 opiece->mtl.specular = Vector3(0.8, 0.8, 0.8);
323 opiece->xform().set_translation(Vector3(0, 0.2, 0));
324 opiece->set_shader(sdr_phong_notex);
325 //obj.push_back(opiece);
327 piece_obj = opiece;
329 // meshgen stats
330 printf("Generated board:\n %u meshes\n", (unsigned int)obj.size());
331 unsigned int polycount = 0;
332 for(size_t i=0; i<obj.size(); i++) {
333 const Mesh *m = obj[i]->get_mesh();
334 polycount += m->get_poly_count();
335 }
336 printf(" %u polygons\n", polycount);
338 return true;
339 }
341 static float wood(float x, float y)
342 {
343 float u = x;
344 float v = y;
345 x += 1.0;
346 x *= 10.0;
347 y *= 20.0;
349 float len = sqrt(x * x + y * y) + turbulence2(u * 6.0, v * 12.0, 2) * 1.2 +
350 turbulence2(u * 0.5, v, 2) * 15.0;
351 float val = fmod(len, 1.0);
353 //val = val * 0.5 + 0.5;
354 return val < 0.0 ? 0.0 : (val > 1.0 ? 1.0 : val);
355 }
357 static float wood_tile(float x, float y)
358 {
359 float u = x;
360 float v = y;
361 x *= 10.0;
362 y *= 10.0;
364 float val = x + pnoise2(u * 6.0, v, 6, 1) * 3.0 +
365 pturbulence2(u * 4, v * 2, 4, 2, 2) * 1.5 + pturbulence2(u * 8, v * 8, 8, 8, 2) * 0.5;
367 val = fmod(val, 1.0);
368 return val < 0.0 ? 0.0 : (val > 1.0 ? 1.0 : val);
369 }
371 static bool spike(float x, float y)
372 {
373 x = fmod(x * 5.0, 1.0);
374 return y < (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x);
375 }
377 static bool circle(float x, float y, float rad)
378 {
379 x = fmod(x * 5.0, 1.0) - 0.5;
380 y = (y - 0.65) * 5.0;
381 float len = sqrt(x * x + y * y);
382 return len < rad;
383 }
385 static bool diamond(float x, float y)
386 {
387 return y >= (1.0 - (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x)) * 0.3333333 + 0.88;
388 }
390 static bool center_circle(float x, float y, float rad)
391 {
392 x = x - 0.5;
393 y = 1.0 - y;
394 return sqrt(x * x + y * y) < rad;
395 }
397 bool Board::generate_textures()
398 {
399 // ---- board field texture ----
400 static const Vector3 wcol1 = Vector3(0.6, 0.4, 0.2);
401 static const Vector3 wcol2 = Vector3(0.53, 0.32, 0.1);
402 static const Vector3 wcol3 = Vector3(0.38, 0.25, 0.08);
404 img_field.create(1024, 1024);
405 unsigned char *pptr = img_field.pixels;
406 for(int i=0; i<img_field.height; i++) {
407 float v = (float)i / (float)img_field.height;
409 for(int j=0; j<img_field.width; j++) {
410 float u = (float)j / (float)img_field.width;
412 int r = 0, g = 0, b = 0;
414 float wood_val = wood(u, v);
416 // pattern mask
417 float x = u;
418 float y = v < 0.5 ? v * 2.0 : 2.0 - v * 2.0;
419 bool inside = false;
421 inside |= (spike(x, y + 0.33333) && !spike(x, y + 0.4)) ||
422 (spike(x, y + 0.5) && !spike(x, y + 0.68));
423 inside |= (circle(x, y, 0.12) && !circle(x, y, 0.1)) || circle(x, y, 0.06);
424 inside |= (diamond(x, y) && !diamond(x, y - 0.015)) ||
425 (diamond(x, y - 0.023) && !diamond(x, y - 0.028));
426 inside |= center_circle(x, y, 0.03);
428 Vector3 wood_color = lerp(wcol1, wcol2, wood_val) * 0.9;
429 if(inside) {
430 wood_color = lerp(wcol1, wcol2, 1.0 - wood_val) * 2.0;
431 }
433 r = (int)(wood_color.x * 255.0);
434 g = (int)(wood_color.y * 255.0);
435 b = (int)(wood_color.z * 255.0);
437 pptr[0] = r > 255 ? 255 : r;
438 pptr[1] = g > 255 ? 255 : g;
439 pptr[2] = b > 255 ? 255 : b;
440 pptr += 3;
441 }
442 }
443 img_field.texture();
445 // ---- generic wood texture ----
446 img_wood.create(256, 256);
447 pptr = img_wood.pixels;
448 for(int i=0; i<img_wood.height; i++) {
449 float v = (float)i / (float)img_wood.height;
450 for(int j=0; j<img_wood.width; j++) {
451 float u = (float)j / (float)img_wood.width;
453 float wood_val = wood_tile(u, v);
454 Vector3 wood_color = lerp(wcol2, wcol3, wood_val) * 0.7;
456 int r = (int)(wood_color.x * 255.0);
457 int g = (int)(wood_color.y * 255.0);
458 int b = (int)(wood_color.z * 255.0);
460 pptr[0] = r > 255 ? 255 : r;
461 pptr[1] = g > 255 ? 255 : g;
462 pptr[2] = b > 255 ? 255 : b;
463 pptr += 3;
464 }
465 }
466 img_wood.texture();
468 // ---- metal hinge diffuse texture ----
469 Vector3 rusty_col1 = Vector3(0.43, 0.46, 0.52);
470 Vector3 rusty_col2 = Vector3(0.52, 0.47, 0.43);
472 img_hinge.create(128, 128);
473 pptr = img_hinge.pixels;
474 for(int i=0; i<img_hinge.height; i++) {
475 float v = (float)i / (float)img_hinge.height;
476 for(int j=0; j<img_hinge.width; j++) {
477 float u = (float)j / (float)img_hinge.width;
479 // rust pattern
480 float w1 = fbm2(u * 4.0, v * 4.0, 3) * 0.5 + 0.5;
481 //float w2 = fbm2(u * 8.0, v * 8.0, 1) * 0.5 + 0.5;
482 Vector3 col = lerp(rusty_col1, rusty_col2 * 0.5, w1);
484 // center hinge split
485 if(fabs(v - 0.5) < 0.01) {
486 col *= 0.5;
487 }
489 int r = (int)(col.x * 255.0);
490 int g = (int)(col.y * 255.0);
491 int b = (int)(col.z * 255.0);
493 pptr[0] = r > 255 ? 255 : (r < 0 ? 0 : r);
494 pptr[1] = g > 255 ? 255 : (g < 0 ? 0 : g);
495 pptr[2] = b > 255 ? 255 : (b < 0 ? 0 : b);
497 pptr += 3;
498 }
499 }
500 img_hinge.texture();
502 return true;
503 }