nuclear@11: #include nuclear@0: #include "opengl.h" nuclear@0: #include "board.h" nuclear@1: #include "meshgen.h" nuclear@6: #include "pnoise.h" nuclear@0: nuclear@0: Board::Board() nuclear@0: { nuclear@2: puck_obj = 0; nuclear@0: clear(); nuclear@0: } nuclear@0: nuclear@0: Board::~Board() nuclear@0: { nuclear@0: destroy(); nuclear@0: } nuclear@0: nuclear@0: bool Board::init() nuclear@0: { nuclear@4: if(!generate_textures()) { nuclear@4: return false; nuclear@4: } nuclear@1: if(!generate()) { nuclear@0: return false; nuclear@0: } nuclear@1: nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: void Board::destroy() nuclear@0: { nuclear@2: for(size_t i=0; idraw(); nuclear@1: } nuclear@0: } nuclear@0: nuclear@1: #define HSIZE 1.0 nuclear@1: #define VSIZE (2.0 * HSIZE) nuclear@1: #define BOT_THICKNESS (HSIZE * 0.01) nuclear@1: #define WALL_THICKNESS (HSIZE * 0.05) nuclear@1: #define WALL_HEIGHT (HSIZE * 0.1) nuclear@1: #define GAP (HSIZE * 0.025) nuclear@1: #define HINGE_RAD (GAP * 0.5) nuclear@1: #define HINGE_HEIGHT (VSIZE * 0.075) nuclear@11: #define PIECE_RAD (0.45 * HSIZE / 5.0) nuclear@11: nuclear@11: static const float piece_cp[][3][2] = { nuclear@11: {{0, 0.25}, {1, 0.25}, {2, 0.5}}, nuclear@11: {{2, 0.5}, {2.5, 0.5}, {3, 0.5}}, nuclear@11: {{3, 0.5}, {4, 0.5}, {4, 0}}, nuclear@11: {{4, 0}, {4, -0.5}, {3, -0.5}}, nuclear@11: {{3, -0.5}, {2.5, -0.5}, {0, -0.5}}, nuclear@11: //{{2, -0.5}, {1, -0.25}, {0, -0.25}} nuclear@11: }; nuclear@11: static const int piece_ncurves = sizeof piece_cp / sizeof *piece_cp; nuclear@11: nuclear@11: static Vector2 piece_revol(float u, float v, void *cls) nuclear@11: { nuclear@11: if(v >= 1.0) v = 1.0 - 1e-6; nuclear@11: int idx = std::min((int)(v * piece_ncurves), piece_ncurves - 1); nuclear@11: float t = fmod(v * (float)piece_ncurves, 1.0); nuclear@11: nuclear@11: Vector2 res; nuclear@11: for(int i=0; i<2; i++) { nuclear@11: float mid = piece_cp[idx][1][i]; nuclear@11: res[i] = bezier(piece_cp[idx][0][i], mid, mid, piece_cp[idx][2][i], t); nuclear@11: } nuclear@11: return res * 0.25 * PIECE_RAD; nuclear@11: } nuclear@1: nuclear@12: static Vector2 piece_revol_normal(float u, float v, void *cls) nuclear@12: { nuclear@12: if(v >= 1.0) v = 1.0 - 1e-6; nuclear@12: int idx = std::min((int)(v * piece_ncurves), piece_ncurves - 1); nuclear@12: float t = fmod(v * (float)piece_ncurves, 1.0); nuclear@12: nuclear@12: Vector2 pprev, pnext; nuclear@12: for(int i=0; i<2; i++) { nuclear@12: float start = piece_cp[idx][0][i]; nuclear@12: float mid = piece_cp[idx][1][i]; nuclear@12: float end = piece_cp[idx][2][i]; nuclear@12: nuclear@12: pprev[i] = bezier(start, mid, mid, end, t - 0.05); nuclear@12: pnext[i] = bezier(start, mid, mid, end, t + 0.05); nuclear@12: } nuclear@12: nuclear@12: float tx = pnext.x - pprev.x; nuclear@12: float ty = pnext.y - pprev.y; nuclear@12: nuclear@12: return Vector2(-ty, tx); nuclear@12: } nuclear@12: nuclear@1: bool Board::generate() nuclear@0: { nuclear@4: Mesh tmp; nuclear@1: Matrix4x4 xform; nuclear@1: nuclear@2: obj.clear(); nuclear@2: nuclear@4: for(int i=0; i<2; i++) { nuclear@4: int sign = i * 2 - 1; nuclear@1: nuclear@4: // generate bottom nuclear@4: Mesh *bottom = new Mesh; nuclear@4: gen_box(bottom, HSIZE, BOT_THICKNESS, HSIZE * 2.0); nuclear@4: xform.set_translation(Vector3(0, -BOT_THICKNESS / 2.0, 0)); nuclear@4: bottom->apply_xform(xform); nuclear@2: nuclear@4: Object *obottom = new Object; nuclear@4: obottom->set_mesh(bottom); nuclear@4: obottom->xform().set_translation(Vector3(sign * (HSIZE / 2.0 + WALL_THICKNESS + HINGE_RAD * 0.25), 0, 0)); nuclear@4: obottom->set_texture(img_field.texture()); nuclear@4: obj.push_back(obottom); nuclear@2: nuclear@1: nuclear@4: // generate the 4 sides nuclear@4: Mesh *sides = new Mesh; nuclear@4: gen_box(sides, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2); nuclear@4: xform.set_translation(Vector3(-(HSIZE + WALL_THICKNESS) / 2.0, nuclear@4: WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0)); nuclear@4: sides->apply_xform(xform); nuclear@1: nuclear@4: gen_box(&tmp, WALL_THICKNESS, WALL_HEIGHT, VSIZE + WALL_THICKNESS * 2); nuclear@4: xform.set_translation(Vector3((HSIZE + WALL_THICKNESS) / 2.0, nuclear@4: WALL_HEIGHT / 2.0 - BOT_THICKNESS, 0)); nuclear@4: tmp.apply_xform(xform); nuclear@4: sides->append(tmp); nuclear@4: tmp.clear(); nuclear@1: nuclear@4: gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS); nuclear@4: xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS, nuclear@4: (VSIZE + WALL_THICKNESS) / 2.0)); nuclear@4: tmp.apply_xform(xform); nuclear@4: sides->append(tmp); nuclear@4: tmp.clear(); nuclear@1: nuclear@4: gen_box(&tmp, HSIZE, WALL_HEIGHT, WALL_THICKNESS); nuclear@4: xform.set_translation(Vector3(0, WALL_HEIGHT / 2.0 - BOT_THICKNESS, nuclear@4: -(VSIZE + WALL_THICKNESS) / 2.0)); nuclear@4: tmp.apply_xform(xform); nuclear@4: sides->append(tmp); nuclear@4: tmp.clear(); nuclear@4: nuclear@6: // generate texture coordinates nuclear@6: sides->texcoord_gen_box(); nuclear@6: nuclear@4: Object *osides = new Object; nuclear@4: osides->set_mesh(sides); nuclear@4: osides->xform() = obottom->xform(); nuclear@6: osides->set_texture(img_wood.texture()); nuclear@6: osides->tex_xform().set_scaling(Vector3(2, 2, 2)); nuclear@6: osides->tex_xform().rotate(-Vector3(1, 0, 0.5), M_PI / 4.0); nuclear@4: obj.push_back(osides); nuclear@4: nuclear@4: } nuclear@2: nuclear@2: nuclear@1: // generate the hinges nuclear@1: Mesh *hinges = new Mesh; nuclear@7: for(int i=0; i<2; i++) { nuclear@7: float sign = i * 2 - 1; nuclear@1: nuclear@7: // barrel nuclear@11: gen_cylinder(&tmp, HINGE_RAD, HINGE_HEIGHT, 8, 1, 1); nuclear@7: xform.reset_identity(); nuclear@7: xform.translate(Vector3(0, WALL_HEIGHT - HINGE_RAD * 0.5, sign * VSIZE / 4.0)); nuclear@7: xform.rotate(Vector3(-M_PI / 2.0, 0, 0)); nuclear@7: tmp.apply_xform(xform); nuclear@7: hinges->append(tmp); nuclear@1: nuclear@7: // flange nuclear@7: gen_plane(&tmp, HINGE_HEIGHT * 0.6, HINGE_HEIGHT * 0.8); nuclear@7: tmp.apply_xform(xform); nuclear@7: nuclear@7: Matrix4x4 tex_xform; nuclear@7: tex_xform.set_rotation(Vector3(0, 0, M_PI / 2.0)); nuclear@7: tmp.texcoord_apply_xform(tex_xform); nuclear@7: hinges->append(tmp); nuclear@7: nuclear@7: // studs nuclear@7: for(int j=0; j<4; j++) { nuclear@7: Vector3 pos; nuclear@7: nuclear@7: pos.x = (float)((j & 1) * 2 - 1) * HINGE_HEIGHT * 0.2; nuclear@7: pos.y = (float)((j & 2) - 1) * HINGE_HEIGHT * 0.3; nuclear@7: nuclear@7: Matrix4x4 stud_xform = xform; nuclear@7: stud_xform.translate(pos); nuclear@7: nuclear@7: Matrix4x4 squash; nuclear@7: squash.set_scaling(Vector3(1, 1, 0.5)); nuclear@7: nuclear@7: gen_sphere(&tmp, HINGE_RAD * 0.5, 8, 4); nuclear@7: tmp.apply_xform(stud_xform * squash); nuclear@7: hinges->append(tmp); nuclear@7: } nuclear@7: } nuclear@1: nuclear@2: Object *ohinges = new Object; nuclear@2: ohinges->set_mesh(hinges); nuclear@7: ohinges->set_texture(img_hinge.texture()); nuclear@2: obj.push_back(ohinges); nuclear@1: nuclear@6: // debug object nuclear@7: /* nuclear@7: Mesh *dbgmesh = new Mesh; nuclear@6: gen_box(dbgmesh, 0.5, 0.5, 0.5); nuclear@6: xform.set_translation(Vector3(0, 0.4, 0)); nuclear@7: xform.set_scaling(Vector3(1, 1, 1)); nuclear@6: dbgmesh->apply_xform(xform); nuclear@6: Object *dbgobj = new Object; nuclear@6: dbgobj->set_mesh(dbgmesh); nuclear@7: dbgobj->set_texture(img_hinge.texture()); nuclear@7: //dbgobj->tex_xform().set_scaling(Vector3(3, 3, 3)); nuclear@7: obj.push_back(dbgobj); nuclear@7: */ nuclear@2: nuclear@11: Mesh *piece = new Mesh; nuclear@12: gen_revol(piece, 18, 17, piece_revol, piece_revol_normal, 0); nuclear@11: nuclear@11: Object *opiece = new Object; nuclear@11: opiece->set_mesh(piece); nuclear@12: opiece->mtl.diffuse = Vector3(0.6, 0.6, 0.6); nuclear@12: opiece->mtl.specular = Vector3(0.8, 0.8, 0.8); nuclear@11: opiece->xform().set_translation(Vector3(0, 0.2, 0)); nuclear@11: obj.push_back(opiece); nuclear@11: nuclear@11: nuclear@8: // meshgen stats nuclear@8: printf("Generated board:\n %u meshes\n", (unsigned int)obj.size()); nuclear@8: unsigned int polycount = 0; nuclear@8: for(size_t i=0; iget_mesh(); nuclear@8: polycount += m->get_poly_count(); nuclear@8: } nuclear@8: printf(" %u polygons\n", polycount); nuclear@8: nuclear@1: return true; nuclear@0: } nuclear@4: nuclear@5: static float wood(float x, float y) nuclear@5: { nuclear@5: float u = x; nuclear@5: float v = y; nuclear@5: x += 1.0; nuclear@5: x *= 10.0; nuclear@5: y *= 20.0; nuclear@5: nuclear@5: float len = sqrt(x * x + y * y) + turbulence2(u * 6.0, v * 12.0, 2) * 1.2 + nuclear@5: turbulence2(u * 0.5, v, 2) * 15.0; nuclear@5: float val = fmod(len, 1.0); nuclear@5: nuclear@5: //val = val * 0.5 + 0.5; nuclear@5: return val < 0.0 ? 0.0 : (val > 1.0 ? 1.0 : val); nuclear@5: } nuclear@5: nuclear@6: static float wood_tile(float x, float y) nuclear@6: { nuclear@6: float u = x; nuclear@6: float v = y; nuclear@6: x *= 10.0; nuclear@6: y *= 10.0; nuclear@6: nuclear@6: float val = x + pnoise2(u * 6.0, v, 6, 1) * 3.0 + nuclear@6: pturbulence2(u * 4, v * 2, 4, 2, 2) * 1.5 + pturbulence2(u * 8, v * 8, 8, 8, 2) * 0.5; nuclear@6: nuclear@6: val = fmod(val, 1.0); nuclear@6: return val < 0.0 ? 0.0 : (val > 1.0 ? 1.0 : val); nuclear@6: } nuclear@6: nuclear@4: static bool spike(float x, float y) nuclear@4: { nuclear@4: x = fmod(x * 5.0, 1.0); nuclear@4: return y < (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x); nuclear@4: } nuclear@4: nuclear@4: static bool circle(float x, float y, float rad) nuclear@4: { nuclear@4: x = fmod(x * 5.0, 1.0) - 0.5; nuclear@4: y = (y - 0.65) * 5.0; nuclear@4: float len = sqrt(x * x + y * y); nuclear@4: return len < rad; nuclear@4: } nuclear@4: nuclear@4: static bool diamond(float x, float y) nuclear@4: { nuclear@4: return y >= (1.0 - (x < 0.5 ? 2.0 * x : 2.0 - 2.0 * x)) * 0.3333333 + 0.88; nuclear@4: } nuclear@4: nuclear@4: static bool center_circle(float x, float y, float rad) nuclear@4: { nuclear@4: x = x - 0.5; nuclear@4: y = 1.0 - y; nuclear@4: return sqrt(x * x + y * y) < rad; nuclear@4: } nuclear@4: nuclear@4: bool Board::generate_textures() nuclear@4: { nuclear@6: // ---- board field texture ---- nuclear@5: static const Vector3 wcol1 = Vector3(0.6, 0.4, 0.2); nuclear@6: static const Vector3 wcol2 = Vector3(0.53, 0.32, 0.1); nuclear@6: static const Vector3 wcol3 = Vector3(0.38, 0.25, 0.08); nuclear@5: nuclear@8: img_field.create(1024, 1024); nuclear@6: unsigned char *pptr = img_field.pixels; nuclear@6: for(int i=0; i 255 ? 255 : r; nuclear@5: pptr[1] = g > 255 ? 255 : g; nuclear@5: pptr[2] = b > 255 ? 255 : b; nuclear@4: pptr += 3; nuclear@4: } nuclear@4: } nuclear@6: img_field.texture(); nuclear@4: nuclear@6: // ---- generic wood texture ---- nuclear@6: img_wood.create(256, 256); nuclear@6: pptr = img_wood.pixels; nuclear@6: for(int i=0; i 255 ? 255 : r; nuclear@6: pptr[1] = g > 255 ? 255 : g; nuclear@6: pptr[2] = b > 255 ? 255 : b; nuclear@6: pptr += 3; nuclear@6: } nuclear@6: } nuclear@6: img_wood.texture(); nuclear@7: nuclear@7: // ---- metal hinge diffuse texture ---- nuclear@7: Vector3 rusty_col1 = Vector3(0.43, 0.46, 0.52); nuclear@7: Vector3 rusty_col2 = Vector3(0.52, 0.47, 0.43); nuclear@7: nuclear@7: img_hinge.create(128, 128); nuclear@7: pptr = img_hinge.pixels; nuclear@7: for(int i=0; i 255 ? 255 : (r < 0 ? 0 : r); nuclear@7: pptr[1] = g > 255 ? 255 : (g < 0 ? 0 : g); nuclear@7: pptr[2] = b > 255 ? 255 : (b < 0 ? 0 : b); nuclear@7: nuclear@7: pptr += 3; nuclear@7: } nuclear@7: } nuclear@7: img_hinge.texture(); nuclear@7: nuclear@4: return true; nuclear@4: }