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