tavli

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