tavli

annotate src/board.cc @ 24:0aadb519b5ee

correct highlighting
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 08 Jul 2015 15:11:58 +0300
parents 3e6430028d54
children
rev   line source
nuclear@11 1 #include <float.h>
nuclear@0 2 #include "opengl.h"
nuclear@0 3 #include "board.h"
nuclear@14 4 #include "game.h"
nuclear@1 5 #include "meshgen.h"
nuclear@6 6 #include "pnoise.h"
nuclear@14 7 #include "revol.h"
nuclear@17 8 #include "opt.h"
nuclear@24 9 #include "shadow.h"
nuclear@17 10
nuclear@17 11
nuclear@17 12 #define HSIZE 1.0
nuclear@17 13 #define VSIZE (2.0 * HSIZE)
nuclear@17 14 #define BOT_THICKNESS (HSIZE * 0.01)
nuclear@17 15 #define WALL_THICKNESS (HSIZE * 0.05)
nuclear@17 16 #define WALL_HEIGHT (HSIZE * 0.1)
nuclear@17 17 #define GAP (HSIZE * 0.025)
nuclear@17 18 #define HINGE_RAD (GAP * 0.5)
nuclear@17 19 #define HINGE_HEIGHT (VSIZE * 0.075)
nuclear@17 20 #define PIECE_RAD (0.45 * HSIZE / 5.0)
nuclear@17 21 #define BOARD_OFFSET (HSIZE / 2.0 + WALL_THICKNESS + HINGE_RAD * 0.25)
nuclear@17 22 #define PIECES_PER_LAYER 5
nuclear@21 23 #define SLOT_WIDTH (HSIZE / 5.0)
nuclear@21 24 #define SLOT_HEIGHT (VSIZE * 0.4)
nuclear@17 25
nuclear@17 26
nuclear@18 27 static const vec2_t piece_cp[] = {
nuclear@18 28 {0, 0.25},
nuclear@18 29 {1, 0.25}, // mid0
nuclear@18 30 {2, 0.5},
nuclear@18 31 {2.5, 0.5}, // mid1
nuclear@18 32 {3, 0.5},
nuclear@18 33 {4, 0.5}, // mid2
nuclear@18 34 {4, 0},
nuclear@18 35 {4, -0.5}, // mid3
nuclear@18 36 {3, -0.5},
nuclear@18 37 {2.5, -0.5}, // mid4
nuclear@18 38 {0, -0.5}
nuclear@18 39 };
nuclear@18 40 static const BezCurve piece_curve = {
nuclear@18 41 sizeof piece_cp / sizeof *piece_cp,
nuclear@18 42 (vec2_t*)piece_cp,
nuclear@18 43 0.25 * PIECE_RAD
nuclear@18 44 };
nuclear@18 45
nuclear@18 46 #define PIECE_HEIGHT (0.25 * PIECE_RAD)
nuclear@18 47
nuclear@18 48
nuclear@17 49 Piece::Piece()
nuclear@17 50 {
nuclear@17 51 owner = 0;
nuclear@17 52 slot = prev_slot = -1;
nuclear@17 53 level = 0;
nuclear@17 54 move_start = 0;
nuclear@17 55 }
nuclear@17 56
nuclear@17 57 void Piece::move_to(int slot, int level, bool anim)
nuclear@17 58 {
nuclear@17 59 int prev_slot = this->slot;
nuclear@17 60 int prev_level = this->level;
nuclear@17 61
nuclear@17 62 this->slot = slot;
nuclear@17 63 this->level = level;
nuclear@17 64
nuclear@17 65 if(anim) {
nuclear@17 66 this->prev_slot = prev_slot;
nuclear@17 67 this->prev_level = prev_level;
nuclear@17 68 move_start = cur_time;
nuclear@17 69 }
nuclear@17 70 }
nuclear@17 71
nuclear@21 72 Quad::Quad()
nuclear@21 73 {
nuclear@21 74 }
nuclear@21 75
nuclear@21 76 Quad::Quad(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3)
nuclear@21 77 : tri0(v0, v1, v2), tri1(v0, v2, v3)
nuclear@21 78 {
nuclear@21 79 }
nuclear@21 80
nuclear@21 81 bool Quad::intersect(const Ray &ray, HitPoint *hit) const
nuclear@21 82 {
nuclear@21 83 return tri0.intersect(ray, hit) || tri1.intersect(ray, hit);
nuclear@21 84 }
nuclear@0 85
nuclear@0 86 Board::Board()
nuclear@0 87 {
nuclear@17 88 piece_obj = 0;
nuclear@22 89 slot_sel = -1;
nuclear@0 90 clear();
nuclear@21 91
nuclear@21 92 for(int i=0; i<NUM_SLOTS; i++) {
nuclear@21 93 Vector3 p = piece_pos(i, 0);
nuclear@21 94 bool top_side = i >= NUM_SLOTS / 2;
nuclear@21 95
nuclear@21 96 float z0 = top_side ? -PIECE_RAD : PIECE_RAD;
nuclear@21 97 float z1 = top_side ? SLOT_HEIGHT : -SLOT_HEIGHT;
nuclear@21 98
nuclear@21 99 slotbb[i] = Quad(p + Vector3(-SLOT_WIDTH / 2.0, 0, z0),
nuclear@21 100 p + Vector3(SLOT_WIDTH / 2.0, 0, z0),
nuclear@21 101 p + Vector3(SLOT_WIDTH / 2.0, 0, z1),
nuclear@21 102 p + Vector3(-SLOT_WIDTH / 2.0, 0, z1));
nuclear@21 103 }
nuclear@0 104 }
nuclear@0 105
nuclear@0 106 Board::~Board()
nuclear@0 107 {
nuclear@0 108 destroy();
nuclear@0 109 }
nuclear@0 110
nuclear@0 111 bool Board::init()
nuclear@0 112 {
nuclear@4 113 if(!generate_textures()) {
nuclear@4 114 return false;
nuclear@4 115 }
nuclear@1 116 if(!generate()) {
nuclear@0 117 return false;
nuclear@0 118 }
nuclear@1 119
nuclear@0 120 return true;
nuclear@0 121 }
nuclear@0 122
nuclear@0 123 void Board::destroy()
nuclear@0 124 {
nuclear@2 125 for(size_t i=0; i<obj.size(); i++) {
nuclear@2 126 delete obj[i];
nuclear@1 127 }
nuclear@2 128 obj.clear();
nuclear@1 129
nuclear@17 130 delete piece_obj;
nuclear@17 131 piece_obj = 0;
nuclear@0 132 }
nuclear@0 133
nuclear@0 134 void Board::clear()
nuclear@0 135 {
nuclear@17 136 memset(hist, 0, sizeof hist);
nuclear@17 137
nuclear@17 138 for(int i=0; i<MAX_PIECES; i++) {
nuclear@17 139 pieces[i].owner = i < PLAYER_PIECES ? MINE : OTHER;
nuclear@17 140 move_piece(i, -1, false);
nuclear@17 141 }
nuclear@17 142 }
nuclear@17 143
nuclear@17 144 void Board::setup()
nuclear@17 145 {
nuclear@17 146 static const int initial[] = { 0, 0, 0, 0, 5, 0, 3, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 2 };
nuclear@17 147
nuclear@17 148 clear();
nuclear@17 149
nuclear@17 150 int id = 0;
nuclear@17 151 for(int i=0; i<NUM_SLOTS; i++) {
nuclear@17 152 for(int j=0; j<initial[i]; j++) {
nuclear@17 153 move_piece(id, i, false);
nuclear@17 154 move_piece(PLAYER_PIECES + id, NUM_SLOTS - i - 1, false);
nuclear@17 155 ++id;
nuclear@17 156 }
nuclear@17 157 }
nuclear@17 158 }
nuclear@17 159
nuclear@17 160 int Board::slot_pieces(int slot) const
nuclear@17 161 {
nuclear@17 162 return hist[slot + 1];
nuclear@17 163 }
nuclear@17 164
nuclear@17 165 bool Board::move_piece(int id, int slot, bool anim)
nuclear@17 166 {
nuclear@17 167 // TODO do validity checking first
nuclear@17 168 int prev_slot = pieces[id].slot;
nuclear@17 169
nuclear@17 170 pieces[id].move_to(slot, slot_pieces(slot), anim);
nuclear@17 171 --hist[prev_slot + 1];
nuclear@17 172 ++hist[slot + 1];
nuclear@17 173 return true;
nuclear@17 174 }
nuclear@17 175
nuclear@17 176 Vector3 Board::piece_pos(int slot, int level) const
nuclear@17 177 {
nuclear@17 178 int top_side = slot / 10;
nuclear@17 179 int sidx = (top_side ? (19 - slot) : slot) % 5;
nuclear@17 180 int left_side = (top_side ? (19 - slot) : slot) / 5;
nuclear@17 181
nuclear@17 182 Vector3 pos;
nuclear@17 183
nuclear@17 184 if(left_side) {
nuclear@17 185 pos.x = -(sidx * HSIZE / 5.0 + BOARD_OFFSET - HSIZE / 2.0) - PIECE_RAD;
nuclear@17 186 } else {
nuclear@17 187 pos.x = (4 - sidx) * HSIZE / 5.0 + BOARD_OFFSET - HSIZE / 2.0 + PIECE_RAD;
nuclear@17 188 }
nuclear@17 189
nuclear@17 190 int layer = level / PIECES_PER_LAYER;
nuclear@17 191 int layer_level = level % PIECES_PER_LAYER;
nuclear@17 192
nuclear@18 193 pos.y = (layer + 0.5) * PIECE_HEIGHT;
nuclear@17 194
nuclear@17 195 pos.z = (-VSIZE * 0.5 + PIECE_RAD + PIECE_RAD * 2.0 * layer_level);
nuclear@21 196 if(!top_side) {
nuclear@17 197 pos.z = -pos.z;
nuclear@17 198 }
nuclear@17 199
nuclear@17 200 return pos;
nuclear@0 201 }
nuclear@0 202
nuclear@21 203 int Board::slot_hit(const Ray &ray) const
nuclear@21 204 {
nuclear@21 205 for(int i=0; i<NUM_SLOTS; i++) {
nuclear@21 206 if(slotbb[i].intersect(ray)) {
nuclear@21 207 return i;
nuclear@21 208 }
nuclear@21 209 }
nuclear@21 210 return -1;
nuclear@21 211 }
nuclear@21 212
nuclear@22 213 void Board::select_slot(int idx)
nuclear@22 214 {
nuclear@22 215 slot_sel = idx < 0 || idx >= NUM_SLOTS ? -1 : idx;
nuclear@22 216 }
nuclear@22 217
nuclear@22 218 int Board::get_selected_slot() const
nuclear@22 219 {
nuclear@22 220 return slot_sel;
nuclear@22 221 }
nuclear@22 222
nuclear@0 223 void Board::draw() const
nuclear@0 224 {
nuclear@19 225 bool use_shadows = opt.shadows && sdr_shadow;
nuclear@19 226 unsigned int board_sdr = use_shadows ? sdr_shadow : sdr_phong;
nuclear@19 227 unsigned int piece_sdr = use_shadows ? sdr_shadow_notex : sdr_phong_notex;
nuclear@19 228
nuclear@2 229 for(size_t i=0; i<obj.size(); i++) {
nuclear@14 230 if(wireframe) {
nuclear@14 231 obj[i]->draw_wire();
nuclear@14 232 obj[i]->draw_normals(0.075);
nuclear@14 233 } else {
nuclear@19 234 obj[i]->set_shader(board_sdr);
nuclear@14 235 obj[i]->draw();
nuclear@14 236 }
nuclear@1 237 }
nuclear@17 238
nuclear@17 239 for(int i=0; i<MAX_PIECES; i++) {
nuclear@17 240 Vector3 pos = piece_pos(pieces[i].slot, pieces[i].level);
nuclear@17 241 piece_obj->xform().set_translation(pos);
nuclear@17 242 piece_obj->mtl.diffuse = opt.piece_color[pieces[i].owner];
nuclear@19 243 piece_obj->set_shader(piece_sdr);
nuclear@17 244 piece_obj->draw();
nuclear@17 245 }
nuclear@21 246
nuclear@24 247 // don't draw any UI stuff and highlighting polygons if we're doing
nuclear@24 248 // the shadow buffer pass
nuclear@24 249 if(shadow_pass)
nuclear@24 250 return;
nuclear@24 251
nuclear@22 252 /*static const float pal[][3] = {
nuclear@21 253 {1, 0, 0},
nuclear@21 254 {0, 1, 0},
nuclear@21 255 {0, 0, 1},
nuclear@21 256 {1, 1, 0},
nuclear@21 257 {0, 1, 1},
nuclear@21 258 {1, 0, 1}
nuclear@22 259 };*/
nuclear@22 260 int idx = slot_sel % NUM_SLOTS;
nuclear@21 261 if(idx >= 0) {
nuclear@21 262 glUseProgram(0);
nuclear@21 263
nuclear@21 264 glPushAttrib(GL_ENABLE_BIT);
nuclear@21 265 glDisable(GL_LIGHTING);
nuclear@21 266 glDisable(GL_CULL_FACE);
nuclear@22 267 glEnable(GL_DEPTH_TEST);
nuclear@22 268 glEnable(GL_TEXTURE_2D);
nuclear@22 269 glBindTexture(GL_TEXTURE_2D, img_highlight.texture());
nuclear@22 270 glEnable(GL_BLEND);
nuclear@24 271 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
nuclear@22 272
nuclear@22 273 glDepthMask(0);
nuclear@21 274
nuclear@21 275 glBegin(GL_TRIANGLES);
nuclear@22 276 //glColor3fv(pal[idx % (sizeof pal / sizeof *pal)]);
nuclear@24 277 glColor4f(1, 1, 1, 0.6);
nuclear@22 278 glTexCoord2f(0, 0);
nuclear@21 279 glVertex3f(slotbb[idx].tri0.v[0].x, slotbb[idx].tri0.v[0].y, slotbb[idx].tri0.v[0].z);
nuclear@22 280 glTexCoord2f(1, 0);
nuclear@21 281 glVertex3f(slotbb[idx].tri0.v[1].x, slotbb[idx].tri0.v[1].y, slotbb[idx].tri0.v[1].z);
nuclear@22 282 glTexCoord2f(1, 1);
nuclear@21 283 glVertex3f(slotbb[idx].tri0.v[2].x, slotbb[idx].tri0.v[2].y, slotbb[idx].tri0.v[2].z);
nuclear@22 284 glTexCoord2f(0, 0);
nuclear@21 285 glVertex3f(slotbb[idx].tri1.v[0].x, slotbb[idx].tri1.v[0].y, slotbb[idx].tri1.v[0].z);
nuclear@22 286 glTexCoord2f(1, 1);
nuclear@21 287 glVertex3f(slotbb[idx].tri1.v[1].x, slotbb[idx].tri1.v[1].y, slotbb[idx].tri1.v[1].z);
nuclear@22 288 glTexCoord2f(0, 1);
nuclear@21 289 glVertex3f(slotbb[idx].tri1.v[2].x, slotbb[idx].tri1.v[2].y, slotbb[idx].tri1.v[2].z);
nuclear@21 290 glEnd();
nuclear@21 291
nuclear@22 292 glDepthMask(1);
nuclear@22 293
nuclear@24 294 glColor4f(0, 1, 0, 0.6);
nuclear@24 295 glEnable(GL_CULL_FACE);
nuclear@24 296 glCullFace(GL_FRONT);
nuclear@24 297 for(int i=0; i<MAX_PIECES; i++) {
nuclear@24 298 if(pieces[i].slot == idx) {
nuclear@24 299 Vector3 pos = piece_pos(pieces[i].slot, pieces[i].level);
nuclear@24 300 piece_obj->xform().set_translation(pos);
nuclear@24 301 piece_obj->xform().scale(Vector3(1.05, 1.05, 1.05));
nuclear@24 302 piece_obj->set_shader(0);
nuclear@24 303 piece_obj->draw();
nuclear@24 304 }
nuclear@24 305 }
nuclear@24 306 glCullFace(GL_BACK);
nuclear@24 307
nuclear@21 308 glPopAttrib();
nuclear@21 309 }
nuclear@0 310 }
nuclear@0 311
nuclear@13 312
nuclear@1 313 bool Board::generate()
nuclear@0 314 {
nuclear@18 315 static const float board_spec = 0.4;
nuclear@18 316
nuclear@4 317 Mesh tmp;
nuclear@1 318 Matrix4x4 xform;
nuclear@1 319
nuclear@2 320 obj.clear();
nuclear@2 321
nuclear@4 322 for(int i=0; i<2; i++) {
nuclear@4 323 int sign = i * 2 - 1;
nuclear@1 324
nuclear@4 325 // generate bottom
nuclear@4 326 Mesh *bottom = new Mesh;
nuclear@4 327 gen_box(bottom, HSIZE, BOT_THICKNESS, HSIZE * 2.0);
nuclear@4 328 xform.set_translation(Vector3(0, -BOT_THICKNESS / 2.0, 0));
nuclear@4 329 bottom->apply_xform(xform);
nuclear@2 330
nuclear@4 331 Object *obottom = new Object;
nuclear@4 332 obottom->set_mesh(bottom);
nuclear@17 333 obottom->xform().set_translation(Vector3(sign * BOARD_OFFSET, 0, 0));
nuclear@4 334 obottom->set_texture(img_field.texture());
nuclear@18 335 obottom->mtl.specular = Vector3(board_spec, board_spec, board_spec);
nuclear@4 336 obj.push_back(obottom);
nuclear@2 337
nuclear@1 338
nuclear@4 339 // generate the 4 sides
nuclear@4 340 Mesh *sides = new Mesh;
nuclear@4 341 gen_box(sides, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2);
nuclear@4 342 xform.set_translation(Vector3(-(HSIZE + WALL_THICKNESS) / 2.0,
nuclear@4 343 WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0));
nuclear@4 344 sides->apply_xform(xform);
nuclear@1 345
nuclear@4 346 gen_box(&tmp, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2);
nuclear@4 347 xform.set_translation(Vector3((HSIZE + WALL_THICKNESS) / 2.0,
nuclear@4 348 WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0));
nuclear@4 349 tmp.apply_xform(xform);
nuclear@4 350 sides->append(tmp);
nuclear@4 351 tmp.clear();
nuclear@1 352
nuclear@4 353 gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS);
nuclear@4 354 xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS,
nuclear@4 355 (VSIZE + WALL_THICKNESS) / 2.0));
nuclear@4 356 tmp.apply_xform(xform);
nuclear@4 357 sides->append(tmp);
nuclear@4 358 tmp.clear();
nuclear@1 359
nuclear@4 360 gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS);
nuclear@4 361 xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS,
nuclear@4 362 -(VSIZE + WALL_THICKNESS) / 2.0));
nuclear@4 363 tmp.apply_xform(xform);
nuclear@4 364 sides->append(tmp);
nuclear@4 365 tmp.clear();
nuclear@4 366
nuclear@6 367 // generate texture coordinates
nuclear@6 368 sides->texcoord_gen_box();
nuclear@6 369
nuclear@4 370 Object *osides = new Object;
nuclear@4 371 osides->set_mesh(sides);
nuclear@4 372 osides->xform() = obottom->xform();
nuclear@6 373 osides->set_texture(img_wood.texture());
nuclear@6 374 osides->tex_xform().set_scaling(Vector3(2, 2, 2));
nuclear@6 375 osides->tex_xform().rotate(-Vector3(1, 0, 0.5), M_PI / 4.0);
nuclear@18 376 osides->mtl.specular = Vector3(board_spec, board_spec, board_spec);
nuclear@4 377 obj.push_back(osides);
nuclear@4 378
nuclear@4 379 }
nuclear@2 380
nuclear@2 381
nuclear@1 382 // generate the hinges
nuclear@1 383 Mesh *hinges = new Mesh;
nuclear@7 384 for(int i=0; i<2; i++) {
nuclear@7 385 float sign = i * 2 - 1;
nuclear@1 386
nuclear@7 387 // barrel
nuclear@11 388 gen_cylinder(&tmp, HINGE_RAD, HINGE_HEIGHT, 8, 1, 1);
nuclear@7 389 xform.reset_identity();
nuclear@7 390 xform.translate(Vector3(0, WALL_HEIGHT - HINGE_RAD * 0.5, sign * VSIZE / 4.0));
nuclear@7 391 xform.rotate(Vector3(-M_PI / 2.0, 0, 0));
nuclear@7 392 tmp.apply_xform(xform);
nuclear@7 393 hinges->append(tmp);
nuclear@1 394
nuclear@7 395 // flange
nuclear@7 396 gen_plane(&tmp, HINGE_HEIGHT * 0.6, HINGE_HEIGHT * 0.8);
nuclear@7 397 tmp.apply_xform(xform);
nuclear@7 398
nuclear@7 399 Matrix4x4 tex_xform;
nuclear@7 400 tex_xform.set_rotation(Vector3(0, 0, M_PI / 2.0));
nuclear@7 401 tmp.texcoord_apply_xform(tex_xform);
nuclear@7 402 hinges->append(tmp);
nuclear@7 403
nuclear@7 404 // studs
nuclear@7 405 for(int j=0; j<4; j++) {
nuclear@7 406 Vector3 pos;
nuclear@7 407
nuclear@7 408 pos.x = (float)((j & 1) * 2 - 1) * HINGE_HEIGHT * 0.2;
nuclear@7 409 pos.y = (float)((j & 2) - 1) * HINGE_HEIGHT * 0.3;
nuclear@7 410
nuclear@7 411 Matrix4x4 stud_xform = xform;
nuclear@7 412 stud_xform.translate(pos);
nuclear@7 413
nuclear@7 414 Matrix4x4 squash;
nuclear@7 415 squash.set_scaling(Vector3(1, 1, 0.5));
nuclear@7 416
nuclear@7 417 gen_sphere(&tmp, HINGE_RAD * 0.5, 8, 4);
nuclear@7 418 tmp.apply_xform(stud_xform * squash);
nuclear@7 419 hinges->append(tmp);
nuclear@7 420 }
nuclear@7 421 }
nuclear@1 422
nuclear@2 423 Object *ohinges = new Object;
nuclear@2 424 ohinges->set_mesh(hinges);
nuclear@7 425 ohinges->set_texture(img_hinge.texture());
nuclear@2 426 obj.push_back(ohinges);
nuclear@1 427
nuclear@6 428 // debug object
nuclear@7 429 /*
nuclear@7 430 Mesh *dbgmesh = new Mesh;
nuclear@6 431 gen_box(dbgmesh, 0.5, 0.5, 0.5);
nuclear@6 432 xform.set_translation(Vector3(0, 0.4, 0));
nuclear@7 433 xform.set_scaling(Vector3(1, 1, 1));
nuclear@6 434 dbgmesh->apply_xform(xform);
nuclear@6 435 Object *dbgobj = new Object;
nuclear@6 436 dbgobj->set_mesh(dbgmesh);
nuclear@7 437 dbgobj->set_texture(img_hinge.texture());
nuclear@7 438 //dbgobj->tex_xform().set_scaling(Vector3(3, 3, 3));
nuclear@7 439 obj.push_back(dbgobj);
nuclear@7 440 */
nuclear@2 441
nuclear@11 442 Mesh *piece = new Mesh;
nuclear@14 443 gen_revol(piece, 18, 17, bezier_revol, bezier_revol_normal, (void*)&piece_curve);
nuclear@11 444
nuclear@11 445 Object *opiece = new Object;
nuclear@11 446 opiece->set_mesh(piece);
nuclear@12 447 opiece->mtl.diffuse = Vector3(0.6, 0.6, 0.6);
nuclear@12 448 opiece->mtl.specular = Vector3(0.8, 0.8, 0.8);
nuclear@11 449 opiece->xform().set_translation(Vector3(0, 0.2, 0));
nuclear@17 450 //obj.push_back(opiece);
nuclear@17 451
nuclear@17 452 piece_obj = opiece;
nuclear@11 453
nuclear@8 454 // meshgen stats
nuclear@8 455 printf("Generated board:\n %u meshes\n", (unsigned int)obj.size());
nuclear@8 456 unsigned int polycount = 0;
nuclear@8 457 for(size_t i=0; i<obj.size(); i++) {
nuclear@8 458 const Mesh *m = obj[i]->get_mesh();
nuclear@8 459 polycount += m->get_poly_count();
nuclear@8 460 }
nuclear@8 461 printf(" %u polygons\n", polycount);
nuclear@8 462
nuclear@1 463 return true;
nuclear@0 464 }
nuclear@4 465
nuclear@5 466 static float wood(float x, float y)
nuclear@5 467 {
nuclear@5 468 float u = x;
nuclear@5 469 float v = y;
nuclear@5 470 x += 1.0;
nuclear@5 471 x *= 10.0;
nuclear@5 472 y *= 20.0;
nuclear@5 473
nuclear@5 474 float len = sqrt(x * x + y * y) + turbulence2(u * 6.0, v * 12.0, 2) * 1.2 +
nuclear@5 475 turbulence2(u * 0.5, v, 2) * 15.0;
nuclear@5 476 float val = fmod(len, 1.0);
nuclear@5 477
nuclear@5 478 //val = val * 0.5 + 0.5;
nuclear@5 479 return val < 0.0 ? 0.0 : (val > 1.0 ? 1.0 : val);
nuclear@5 480 }
nuclear@5 481
nuclear@6 482 static float wood_tile(float x, float y)
nuclear@6 483 {
nuclear@6 484 float u = x;
nuclear@6 485 float v = y;
nuclear@6 486 x *= 10.0;
nuclear@6 487 y *= 10.0;
nuclear@6 488
nuclear@6 489 float val = x + pnoise2(u * 6.0, v, 6, 1) * 3.0 +
nuclear@6 490 pturbulence2(u * 4, v * 2, 4, 2, 2) * 1.5 + pturbulence2(u * 8, v * 8, 8, 8, 2) * 0.5;
nuclear@6 491
nuclear@6 492 val = fmod(val, 1.0);
nuclear@6 493 return val < 0.0 ? 0.0 : (val > 1.0 ? 1.0 : val);
nuclear@6 494 }
nuclear@6 495
nuclear@4 496 static bool spike(float x, float y)
nuclear@4 497 {
nuclear@4 498 x = fmod(x * 5.0, 1.0);
nuclear@4 499 return y < (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x);
nuclear@4 500 }
nuclear@4 501
nuclear@4 502 static bool circle(float x, float y, float rad)
nuclear@4 503 {
nuclear@4 504 x = fmod(x * 5.0, 1.0) - 0.5;
nuclear@4 505 y = (y - 0.65) * 5.0;
nuclear@4 506 float len = sqrt(x * x + y * y);
nuclear@4 507 return len < rad;
nuclear@4 508 }
nuclear@4 509
nuclear@4 510 static bool diamond(float x, float y)
nuclear@4 511 {
nuclear@4 512 return y >= (1.0 - (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x)) * 0.3333333 + 0.88;
nuclear@4 513 }
nuclear@4 514
nuclear@4 515 static bool center_circle(float x, float y, float rad)
nuclear@4 516 {
nuclear@4 517 x = x - 0.5;
nuclear@4 518 y = 1.0 - y;
nuclear@4 519 return sqrt(x * x + y * y) < rad;
nuclear@4 520 }
nuclear@4 521
nuclear@22 522 static bool field_pattern(float x, float y)
nuclear@22 523 {
nuclear@22 524 y = y < 0.5 ? y * 2.0 : 2.0 - y * 2.0;
nuclear@22 525 bool inside = false;
nuclear@22 526
nuclear@22 527 inside |= (spike(x, y + 0.33333) && !spike(x, y + 0.4)) ||
nuclear@22 528 (spike(x, y + 0.5) && !spike(x, y + 0.68));
nuclear@22 529 inside |= (circle(x, y, 0.12) && !circle(x, y, 0.1)) || circle(x, y, 0.06);
nuclear@22 530 inside |= (diamond(x, y) && !diamond(x, y - 0.015)) ||
nuclear@22 531 (diamond(x, y - 0.023) && !diamond(x, y - 0.028));
nuclear@22 532 inside |= center_circle(x, y, 0.03);
nuclear@22 533
nuclear@22 534 return inside;
nuclear@22 535 }
nuclear@22 536
nuclear@4 537 bool Board::generate_textures()
nuclear@4 538 {
nuclear@6 539 // ---- board field texture ----
nuclear@5 540 static const Vector3 wcol1 = Vector3(0.6, 0.4, 0.2);
nuclear@6 541 static const Vector3 wcol2 = Vector3(0.53, 0.32, 0.1);
nuclear@6 542 static const Vector3 wcol3 = Vector3(0.38, 0.25, 0.08);
nuclear@5 543
nuclear@8 544 img_field.create(1024, 1024);
nuclear@6 545 unsigned char *pptr = img_field.pixels;
nuclear@6 546 for(int i=0; i<img_field.height; i++) {
nuclear@6 547 float v = (float)i / (float)img_field.height;
nuclear@4 548
nuclear@6 549 for(int j=0; j<img_field.width; j++) {
nuclear@6 550 float u = (float)j / (float)img_field.width;
nuclear@4 551
nuclear@22 552 // pattern mask
nuclear@22 553 bool inside = field_pattern(u, v);
nuclear@4 554
nuclear@5 555 float wood_val = wood(u, v);
nuclear@5 556 Vector3 wood_color = lerp(wcol1, wcol2, wood_val) * 0.9;
nuclear@4 557 if(inside) {
nuclear@5 558 wood_color = lerp(wcol1, wcol2, 1.0 - wood_val) * 2.0;
nuclear@4 559 }
nuclear@4 560
nuclear@22 561 int r = (int)(wood_color.x * 255.0);
nuclear@22 562 int g = (int)(wood_color.y * 255.0);
nuclear@22 563 int b = (int)(wood_color.z * 255.0);
nuclear@5 564
nuclear@5 565 pptr[0] = r > 255 ? 255 : r;
nuclear@5 566 pptr[1] = g > 255 ? 255 : g;
nuclear@5 567 pptr[2] = b > 255 ? 255 : b;
nuclear@22 568 pptr[3] = 255;
nuclear@22 569 pptr += 4;
nuclear@4 570 }
nuclear@4 571 }
nuclear@6 572 img_field.texture();
nuclear@4 573
nuclear@22 574
nuclear@22 575 // ---- slot highlighting texture ----
nuclear@22 576 img_highlight.create(128, 256);
nuclear@22 577 pptr = img_highlight.pixels;
nuclear@22 578 for(int i=0; i<img_highlight.height; i++) {
nuclear@22 579 float v = (float)i / (float)img_highlight.height;
nuclear@22 580 for(int j=0; j<img_highlight.width; j++) {
nuclear@22 581 float u = (float)j / (float)img_highlight.width;
nuclear@22 582
nuclear@22 583 bool inside = field_pattern(u / 5.0, v * 0.445);
nuclear@22 584
nuclear@22 585 pptr[0] = 255;
nuclear@22 586 pptr[1] = 255;
nuclear@22 587 pptr[2] = 255;
nuclear@22 588 pptr[3] = inside ? 255 : 0;
nuclear@22 589 pptr += 4;
nuclear@22 590 }
nuclear@22 591 }
nuclear@22 592 img_highlight.texture();
nuclear@22 593
nuclear@23 594 float kern[] = {1, 5, 11, 18, 22, 18, 11, 5, 1};
nuclear@23 595 convolve_horiz_image(&img_highlight, kern, sizeof kern / sizeof *kern);
nuclear@23 596 convolve_vert_image(&img_highlight, kern, sizeof kern / sizeof *kern);
nuclear@22 597
nuclear@6 598 // ---- generic wood texture ----
nuclear@6 599 img_wood.create(256, 256);
nuclear@6 600 pptr = img_wood.pixels;
nuclear@6 601 for(int i=0; i<img_wood.height; i++) {
nuclear@6 602 float v = (float)i / (float)img_wood.height;
nuclear@6 603 for(int j=0; j<img_wood.width; j++) {
nuclear@6 604 float u = (float)j / (float)img_wood.width;
nuclear@6 605
nuclear@6 606 float wood_val = wood_tile(u, v);
nuclear@6 607 Vector3 wood_color = lerp(wcol2, wcol3, wood_val) * 0.7;
nuclear@6 608
nuclear@6 609 int r = (int)(wood_color.x * 255.0);
nuclear@6 610 int g = (int)(wood_color.y * 255.0);
nuclear@6 611 int b = (int)(wood_color.z * 255.0);
nuclear@6 612
nuclear@6 613 pptr[0] = r > 255 ? 255 : r;
nuclear@6 614 pptr[1] = g > 255 ? 255 : g;
nuclear@6 615 pptr[2] = b > 255 ? 255 : b;
nuclear@22 616 pptr[3] = 255;
nuclear@22 617 pptr += 4;
nuclear@6 618 }
nuclear@6 619 }
nuclear@6 620 img_wood.texture();
nuclear@7 621
nuclear@7 622 // ---- metal hinge diffuse texture ----
nuclear@7 623 Vector3 rusty_col1 = Vector3(0.43, 0.46, 0.52);
nuclear@7 624 Vector3 rusty_col2 = Vector3(0.52, 0.47, 0.43);
nuclear@7 625
nuclear@7 626 img_hinge.create(128, 128);
nuclear@7 627 pptr = img_hinge.pixels;
nuclear@7 628 for(int i=0; i<img_hinge.height; i++) {
nuclear@7 629 float v = (float)i / (float)img_hinge.height;
nuclear@7 630 for(int j=0; j<img_hinge.width; j++) {
nuclear@7 631 float u = (float)j / (float)img_hinge.width;
nuclear@7 632
nuclear@7 633 // rust pattern
nuclear@7 634 float w1 = fbm2(u * 4.0, v * 4.0, 3) * 0.5 + 0.5;
nuclear@9 635 //float w2 = fbm2(u * 8.0, v * 8.0, 1) * 0.5 + 0.5;
nuclear@7 636 Vector3 col = lerp(rusty_col1, rusty_col2 * 0.5, w1);
nuclear@7 637
nuclear@7 638 // center hinge split
nuclear@7 639 if(fabs(v - 0.5) < 0.01) {
nuclear@7 640 col *= 0.5;
nuclear@7 641 }
nuclear@7 642
nuclear@7 643 int r = (int)(col.x * 255.0);
nuclear@7 644 int g = (int)(col.y * 255.0);
nuclear@7 645 int b = (int)(col.z * 255.0);
nuclear@7 646
nuclear@7 647 pptr[0] = r > 255 ? 255 : (r < 0 ? 0 : r);
nuclear@7 648 pptr[1] = g > 255 ? 255 : (g < 0 ? 0 : g);
nuclear@7 649 pptr[2] = b > 255 ? 255 : (b < 0 ? 0 : b);
nuclear@22 650 pptr[3] = 255;
nuclear@7 651
nuclear@22 652 pptr += 4;
nuclear@7 653 }
nuclear@7 654 }
nuclear@7 655 img_hinge.texture();
nuclear@7 656
nuclear@4 657 return true;
nuclear@4 658 }