nuclear@11: #include nuclear@0: #include "opengl.h" nuclear@0: #include "board.h" nuclear@14: #include "game.h" nuclear@1: #include "meshgen.h" nuclear@6: #include "pnoise.h" nuclear@14: #include "revol.h" nuclear@17: #include "opt.h" nuclear@17: nuclear@17: nuclear@17: #define HSIZE 1.0 nuclear@17: #define VSIZE (2.0 * HSIZE) nuclear@17: #define BOT_THICKNESS (HSIZE * 0.01) nuclear@17: #define WALL_THICKNESS (HSIZE * 0.05) nuclear@17: #define WALL_HEIGHT (HSIZE * 0.1) nuclear@17: #define GAP (HSIZE * 0.025) nuclear@17: #define HINGE_RAD (GAP * 0.5) nuclear@17: #define HINGE_HEIGHT (VSIZE * 0.075) nuclear@17: #define PIECE_RAD (0.45 * HSIZE / 5.0) nuclear@17: #define BOARD_OFFSET (HSIZE / 2.0 + WALL_THICKNESS + HINGE_RAD * 0.25) nuclear@17: #define PIECES_PER_LAYER 5 nuclear@21: #define SLOT_WIDTH (HSIZE / 5.0) nuclear@21: #define SLOT_HEIGHT (VSIZE * 0.4) nuclear@17: nuclear@17: nuclear@18: static const vec2_t piece_cp[] = { nuclear@18: {0, 0.25}, nuclear@18: {1, 0.25}, // mid0 nuclear@18: {2, 0.5}, nuclear@18: {2.5, 0.5}, // mid1 nuclear@18: {3, 0.5}, nuclear@18: {4, 0.5}, // mid2 nuclear@18: {4, 0}, nuclear@18: {4, -0.5}, // mid3 nuclear@18: {3, -0.5}, nuclear@18: {2.5, -0.5}, // mid4 nuclear@18: {0, -0.5} nuclear@18: }; nuclear@18: static const BezCurve piece_curve = { nuclear@18: sizeof piece_cp / sizeof *piece_cp, nuclear@18: (vec2_t*)piece_cp, nuclear@18: 0.25 * PIECE_RAD nuclear@18: }; nuclear@18: nuclear@18: #define PIECE_HEIGHT (0.25 * PIECE_RAD) nuclear@18: nuclear@18: nuclear@17: Piece::Piece() nuclear@17: { nuclear@17: owner = 0; nuclear@17: slot = prev_slot = -1; nuclear@17: level = 0; nuclear@17: move_start = 0; nuclear@17: } nuclear@17: nuclear@17: void Piece::move_to(int slot, int level, bool anim) nuclear@17: { nuclear@17: int prev_slot = this->slot; nuclear@17: int prev_level = this->level; nuclear@17: nuclear@17: this->slot = slot; nuclear@17: this->level = level; nuclear@17: nuclear@17: if(anim) { nuclear@17: this->prev_slot = prev_slot; nuclear@17: this->prev_level = prev_level; nuclear@17: move_start = cur_time; nuclear@17: } nuclear@17: } nuclear@17: nuclear@21: Quad::Quad() nuclear@21: { nuclear@21: } nuclear@21: nuclear@21: Quad::Quad(const Vector3 &v0, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3) nuclear@21: : tri0(v0, v1, v2), tri1(v0, v2, v3) nuclear@21: { nuclear@21: } nuclear@21: nuclear@21: bool Quad::intersect(const Ray &ray, HitPoint *hit) const nuclear@21: { nuclear@21: return tri0.intersect(ray, hit) || tri1.intersect(ray, hit); nuclear@21: } nuclear@0: nuclear@0: Board::Board() nuclear@0: { nuclear@17: piece_obj = 0; nuclear@0: clear(); nuclear@21: nuclear@21: for(int i=0; i= NUM_SLOTS / 2; nuclear@21: nuclear@21: float z0 = top_side ? -PIECE_RAD : PIECE_RAD; nuclear@21: float z1 = top_side ? SLOT_HEIGHT : -SLOT_HEIGHT; nuclear@21: nuclear@21: slotbb[i] = Quad(p + Vector3(-SLOT_WIDTH / 2.0, 0, z0), nuclear@21: p + Vector3(SLOT_WIDTH / 2.0, 0, z0), nuclear@21: p + Vector3(SLOT_WIDTH / 2.0, 0, z1), nuclear@21: p + Vector3(-SLOT_WIDTH / 2.0, 0, z1)); nuclear@21: } 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_wire(); nuclear@14: obj[i]->draw_normals(0.075); nuclear@14: } else { nuclear@19: obj[i]->set_shader(board_sdr); nuclear@14: obj[i]->draw(); nuclear@14: } nuclear@1: } nuclear@17: nuclear@17: for(int i=0; ixform().set_translation(pos); nuclear@17: piece_obj->mtl.diffuse = opt.piece_color[pieces[i].owner]; nuclear@19: piece_obj->set_shader(piece_sdr); nuclear@17: piece_obj->draw(); nuclear@17: } nuclear@21: nuclear@21: // draw the slot bounds nuclear@21: /* nuclear@21: static const float pal[][3] = { nuclear@21: {1, 0, 0}, nuclear@21: {0, 1, 0}, nuclear@21: {0, 0, 1}, nuclear@21: {1, 1, 0}, nuclear@21: {0, 1, 1}, nuclear@21: {1, 0, 1} nuclear@21: }; nuclear@21: int idx = dbg_int % NUM_SLOTS; nuclear@21: if(idx >= 0) { nuclear@21: glUseProgram(0); nuclear@21: nuclear@21: glPushAttrib(GL_ENABLE_BIT); nuclear@21: glDisable(GL_LIGHTING); nuclear@21: glDisable(GL_CULL_FACE); nuclear@21: glDisable(GL_DEPTH_TEST); nuclear@21: nuclear@21: glBegin(GL_TRIANGLES); nuclear@21: glColor3fv(pal[idx % (sizeof pal / sizeof *pal)]); nuclear@21: glVertex3f(slotbb[idx].tri0.v[0].x, slotbb[idx].tri0.v[0].y, slotbb[idx].tri0.v[0].z); nuclear@21: glVertex3f(slotbb[idx].tri0.v[1].x, slotbb[idx].tri0.v[1].y, slotbb[idx].tri0.v[1].z); nuclear@21: glVertex3f(slotbb[idx].tri0.v[2].x, slotbb[idx].tri0.v[2].y, slotbb[idx].tri0.v[2].z); nuclear@21: glVertex3f(slotbb[idx].tri1.v[0].x, slotbb[idx].tri1.v[0].y, slotbb[idx].tri1.v[0].z); nuclear@21: glVertex3f(slotbb[idx].tri1.v[1].x, slotbb[idx].tri1.v[1].y, slotbb[idx].tri1.v[1].z); nuclear@21: glVertex3f(slotbb[idx].tri1.v[2].x, slotbb[idx].tri1.v[2].y, slotbb[idx].tri1.v[2].z); nuclear@21: glEnd(); nuclear@21: nuclear@21: glPopAttrib(); nuclear@21: } nuclear@21: */ nuclear@21: // TODO slot highlighting nuclear@0: } nuclear@0: nuclear@13: nuclear@1: bool Board::generate() nuclear@0: { nuclear@18: static const float board_spec = 0.4; nuclear@18: 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@17: obottom->xform().set_translation(Vector3(sign * BOARD_OFFSET, 0, 0)); nuclear@4: obottom->set_texture(img_field.texture()); nuclear@18: obottom->mtl.specular = Vector3(board_spec, board_spec, board_spec); 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@18: osides->mtl.specular = Vector3(board_spec, board_spec, board_spec); 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@14: gen_revol(piece, 18, 17, bezier_revol, bezier_revol_normal, (void*)&piece_curve); 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@17: //obj.push_back(opiece); nuclear@17: nuclear@17: piece_obj = opiece; 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: }