4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
/**********************************************
21
* Copyright (C) 2001-2003 Bertrand 'blam' LAMY
22
**********************************************/
34
#include "watercube.h"
38
extern GLfloat white[4];
39
extern GLfloat black[4];
40
extern P3_renderer* renderer;
41
extern int engine_option;
42
extern P3_material* current_material;
43
extern P3_material* light_shader;
44
extern int shadow_display_list;
47
P3_class P3_class_mesh = {
49
(batch_func) P3_mesh_batch,
50
(render_func) P3_mesh_render,
51
(shadow_func) P3_mesh_shadow,
52
(raypick_func) P3_mesh_raypick,
53
(raypick_b_func) P3_mesh_raypick_b,
57
P3_mesh* P3_mesh_new (P3_mesh* mesh) {
58
if (mesh == NULL) mesh = (P3_mesh*) malloc (sizeof (P3_mesh));
59
mesh->class = &P3_class_mesh;
60
P3_xmesh_initialize ((P3_xmesh*) mesh);
66
static void P3_mesh_face_list_dealloc (P3_mesh_face_list* flist) {
71
static void P3_mesh_display_list_dealloc (P3_mesh_display_list* dlist) {
73
if (engine_option & P3_GL_INITED) {
74
for (i = 0; i < dlist->nb_list_opaque + dlist->nb_list_alpha; i++) {
75
glDeleteLists ((dlist->dlists + i)->dlist, 1);
82
static void P3_mesh_free_xtra1 (P3_mesh* mesh) {
83
if (mesh->xtra1 != NULL) {
84
if (mesh->option & P3_MESH_TREE) {
85
P3_xnode_dealloc ((P3_xnode*) mesh->xtra1);
86
mesh->option -= P3_MESH_TREE;
87
} else if (mesh->option & P3_MESH_CELL_SHADING) {
88
/* shader is not decrefed cause it belongs to the mesh->materials array */
89
// P3_mesh_face_list_dealloc ((P3_mesh_face_list*) mesh->xtra1);
90
mesh->option -= P3_MESH_CELL_SHADING;
91
// mesh->option -= P3_MESH_FACE_LIST;
92
mesh->option -= P3_MESH_HAS_SPHERE;
93
} else if (mesh->option & P3_MESH_DISPLAY_LISTS) {
94
P3_mesh_display_list_dealloc ((P3_mesh_display_list*) mesh->xtra1);
95
mesh->option -= P3_MESH_DISPLAY_LISTS;
101
static void P3_mesh_free_xtra2 (P3_mesh* mesh) {
102
if (mesh->xtra2 != NULL) {
103
if (mesh->option & P3_MESH_FACE_LIST) {
104
P3_mesh_face_list_dealloc ((P3_mesh_face_list*) mesh->xtra2);
105
mesh->option -= P3_MESH_FACE_LIST;
106
mesh->option -= P3_MESH_HAS_SPHERE;
107
} else if (mesh->option & P3_MESH_HAS_SPHERE) {
109
mesh->option -= P3_MESH_HAS_SPHERE;
115
void P3_mesh_dealloc (P3_mesh* mesh) {
116
P3_mesh_free_xtra1 (mesh);
117
P3_mesh_free_xtra2 (mesh);
118
P3_xmesh_free_data ((P3_xmesh*) mesh);
121
void P3_mesh_check_fx (P3_mesh* mesh) {
126
if (mesh->option & P3_MESH_DISPLAY_LISTS) P3_mesh_free_xtra1 (mesh);
127
if (!(mesh->option & P3_MESH_VERTEX_OPTIONS)) {
128
mesh->vertex_options = (char*) calloc (mesh->nb_vertices, sizeof (char));
129
mesh->option |= P3_MESH_VERTEX_OPTIONS;
131
if (!(mesh->option & P3_MESH_WARFOGS)) {
132
mesh->vertex_warfogs = (GLfloat**) malloc (mesh->nb_vertices * sizeof (GLfloat*));
133
mesh->option |= P3_MESH_WARFOGS;
134
if (mesh->option & P3_MESH_DIFFUSES) {
135
for (i = 0; i < mesh->nb_vertices; i++) mesh->vertex_warfogs[i] = mesh->vertex_diffuses[i];
137
if (mesh->nb_values >= 4) {
138
color = mesh->values;
140
i = P3_xmesh_register_value ((P3_xmesh*) mesh, white, 4);
141
color = mesh->values + i;
143
for (i = 0; i < mesh->nb_vertices; i++) mesh->vertex_warfogs[i] = color;
153
void P3_mesh_raypick (P3_mesh* mesh, P3_raypick_data* data, P3_raypickable* parent) {
155
raydata = P3_raypickable_get_raypick_data (parent, data);
156
if (mesh->option & P3_MESH_TREE) {
157
P3_xmesh_node_raypick ((P3_xmesh*) mesh, (P3_xnode*) mesh->xtra1, raydata, data, parent);
159
if (mesh->option & P3_MESH_HAS_SPHERE &&
160
P3_sphere_raypick (raydata, (GLfloat*) mesh->xtra2) == P3_FALSE) {
163
if (mesh->option & P3_MESH_FACE_LIST) {
164
P3_mesh_face_list* flist = (P3_mesh_face_list*) mesh->xtra2;
166
for (i = 0; i < flist->nb_faces; i++) {
167
P3_xmesh_face_raypick ((P3_xmesh*) mesh, flist->faces[i], raydata, data, parent);
170
P3_xmesh_raypick ((P3_xmesh*) mesh, raydata, data, parent);
175
int P3_mesh_raypick_b (P3_mesh* mesh, P3_raypick_data* data, P3_raypickable* parent) {
177
raydata = P3_raypickable_get_raypick_data (parent, data);
178
if (mesh->option & P3_MESH_TREE) {
179
return P3_xmesh_node_raypick_b ((P3_xmesh*) mesh, (P3_xnode*) mesh->xtra1, raydata, data);
181
if (mesh->option & P3_MESH_HAS_SPHERE &&
182
P3_sphere_raypick (raydata, (GLfloat*) mesh->xtra2) == P3_FALSE) {
185
if (mesh->option & P3_MESH_FACE_LIST) {
186
P3_mesh_face_list* flist = (P3_mesh_face_list*) mesh->xtra2;
188
for (i = 0; i < flist->nb_faces; i++) {
189
if (P3_xmesh_face_raypick_b ((P3_xmesh*) mesh, flist->faces[i], raydata, data) == P3_TRUE) {
194
return P3_xmesh_raypick_b ((P3_xmesh*) mesh, raydata, data);
201
/*===================+
202
| XTRA CONSTRUCTORS |
203
+===================*/
205
static void P3_mesh_create_faces_list (P3_mesh_face_list* flist, P3_mesh* mesh) {
209
face = (P3_xface*) mesh->faces;
210
while ((void*) face < mesh->faces + mesh->faces_size) {
211
face = ((void*) face) + P3_xmesh_face_size ((P3_xmesh*) mesh, face);
214
flist->faces = (P3_xface**) malloc (flist->nb_faces * sizeof (P3_xface*));
216
face = (P3_xface*) mesh->faces;
217
while ((void*) face < mesh->faces + mesh->faces_size) {
218
flist->faces[i] = face;
219
face = ((void*) face) + P3_xmesh_face_size ((P3_xmesh*) mesh, face);
224
static void P3_mesh_display_list_init (P3_mesh* mesh) {
225
P3_mesh_display_list* dlists;
226
P3_display_list* dlist;
229
dlists = (P3_mesh_display_list*) mesh->xtra1;
230
P3_xmesh_option_activate (mesh->option);
231
for (i = 0; i < dlists->nb_list_opaque + dlists->nb_list_alpha; i++) {
232
dlist = dlists->dlists + i;
233
dlist->dlist = glGenLists (1);
234
P3_material_activate (dlist->material);
235
P3_xface_option_activate (dlist->option);
236
glNewList (dlist->dlist, GL_COMPILE);
237
if (dlist->option & P3_FACE_TRIANGLE) {
238
glBegin (GL_TRIANGLES);
239
} else if (dlist->option & P3_FACE_QUAD) {
243
while ((void*) face < mesh->faces + mesh->faces_size) {
244
if ((face->option & P3_DISPLAY_LIST_OPTIONS) == dlist->option && face->pack->material == dlist->material) {
245
if (face->option & P3_FACE_QUAD) P3_xmesh_quad_render ((P3_xmesh*) mesh, face);
246
else P3_xmesh_triangle_render ((P3_xmesh*) mesh, face);
248
face = ((void*) face) + P3_xmesh_face_size ((P3_xmesh*) mesh, face);
252
P3_xface_option_inactivate (dlist->option);
254
P3_xmesh_option_inactivate (mesh->option);
255
mesh->option |= P3_MESH_INITED;
258
void P3_mesh_build_tree (P3_mesh* mesh) {
259
P3_mesh_free_xtra1 (mesh);
260
mesh->xtra1 = P3_xmesh_build_tree ((P3_xmesh*) mesh);
261
mesh->option |= P3_MESH_TREE;
264
void P3_mesh_optimize_tree (P3_mesh* mesh, GLfloat collapse, int mode, GLfloat param) {
265
if (mesh->option & P3_MESH_TREE)
266
P3_xmesh_optimize_tree ((P3_xnode*) mesh->xtra1, collapse, mode, param);
269
void P3_mesh_set_xtra1_display_lists (P3_mesh* mesh) {
270
P3_mesh_display_list* displist;
275
P3_mesh_free_xtra1 (mesh);
276
displist = (P3_mesh_display_list*) malloc (sizeof (P3_mesh_display_list));
277
displist->nb_list_opaque = 0;
278
displist->nb_list_alpha = 0;
280
displist->dlists = NULL;
281
for (k = 0; k < 2; k++) {
282
face = (P3_xface*) mesh->faces;
283
max = mesh->faces + mesh->faces_size;
284
while ((void*) face < max) {
285
if ((face->option & P3_FACE_ALPHA && k == 1) || (!(face->option & P3_FACE_ALPHA) && k == 0)) {
286
for (i = 0; i < nb; i++) {
287
dl = displist->dlists + i;
288
if (dl->material == face->pack->material && dl->option == (face->option & P3_DISPLAY_LIST_OPTIONS)) {
294
displist->dlists = (P3_display_list*) realloc (displist->dlists, (nb + 1) * sizeof (P3_display_list));
295
dl = displist->dlists + nb;
296
dl->material = face->pack->material;
297
dl->option = face->option & P3_DISPLAY_LIST_OPTIONS;
298
if (dl->option & P3_FACE_ALPHA) (displist->nb_list_alpha)++;
299
else (displist->nb_list_opaque)++;
303
face = ((void*) face) + P3_xmesh_face_size ((P3_xmesh*) mesh, face);
306
mesh->xtra1 = displist;
307
mesh->option |= P3_MESH_DISPLAY_LISTS;
310
void P3_mesh_set_xtra1_cell_shading (P3_mesh* mesh, P3_material* shader, GLfloat* color, GLfloat line_width_factor) {
311
P3_mesh_cell_shading* cshade;
312
P3_mesh_free_xtra1 (mesh);
313
cshade = (P3_mesh_cell_shading*) malloc (sizeof (P3_mesh_cell_shading));
314
cshade->shader = shader;
315
if (shader != NULL) P3_xmesh_register_material ((P3_xmesh*) mesh, shader);
316
memcpy (cshade->line_color, color, 4 * sizeof (GLfloat));
317
cshade->line_width_factor = line_width_factor;
318
mesh->option |= P3_MESH_CELL_SHADING;
319
mesh->xtra1 = cshade;
322
void P3_mesh_set_xtra2_sphere (P3_mesh* mesh) {
323
P3_mesh_free_xtra2 (mesh);
324
mesh->xtra2 = malloc (4 * sizeof (GLfloat));
325
if (mesh->nb_coords > 0) {
326
P3_sphere_from_points ((GLfloat*) mesh->xtra2, mesh->coords, mesh->nb_coords);
328
mesh->option |= P3_MESH_HAS_SPHERE;
331
void P3_mesh_set_xtra2_face_list (P3_mesh* mesh) {
332
P3_mesh_face_list* flist;
333
flist = (P3_mesh_face_list*) malloc (sizeof (P3_mesh_face_list));
334
P3_sphere_from_points (flist->sphere, mesh->coords, mesh->nb_coords);
335
P3_mesh_create_faces_list (flist, mesh);
336
P3_mesh_free_xtra2 (mesh);
338
mesh->option |= P3_MESH_FACE_LIST;
339
mesh->option |= P3_MESH_HAS_SPHERE;
347
void P3_mesh_batch_outline (P3_mesh* mesh, P3_instance* inst, P3_frustum* frustum) {
349
// TO DO computation + rendering can be done during rendering ???
351
P3_chain* face_batched;
356
P3_xface** neighbors;
362
if (((P3_mesh_cell_shading*) mesh->xtra1)->line_width_factor <= 0.0) {
363
/* no outline to draw */
366
/* compute distance between camera and mesh to adjust outline width */
367
if (mesh->option & P3_MESH_HAS_SPHERE) {
368
d = P3_sphere_distance_point ((GLfloat*) mesh->xtra2, frustum->position);
370
d = ((P3_mesh_cell_shading*) mesh->xtra1)->line_width_factor;
372
d = ((P3_mesh_cell_shading*) mesh->xtra1)->line_width_factor / d;
373
// d = ((P3_mesh_cell_shading*) mesh->xtra1)->line_width_factor * 0.5 * (1.0 + 1.0 / d);
377
/* batch in secondpass */
378
P3_chunk_add_float (renderer->data, d);
379
/* compute line to draw */
380
max = (P3_chain*) (renderer->faces->content + renderer->faces->nb);
381
face_batched = (P3_chain*) (renderer->faces->content + renderer->face_start);
382
faces = face_batched;
383
while (faces < max) {
384
face = (P3_xface*) faces->data;
385
plane = face->normal;
386
if (plane[0] * frustum->position[0] + plane[1] * frustum->position[1] + plane[2] * frustum->position[2] + plane[3] > 0.0)
387
face->option |= P3_FACE_FRONT;
389
face->option |= P3_FACE_BACK;
393
faces = face_batched;
394
while (faces < max) {
395
face = (P3_xface*) faces->data;
396
if (face->option & P3_FACE_FRONT) {
397
if (face->option & P3_FACE_QUAD) {
398
neighbors = (P3_xface**) (&(face->v4) + 1);
401
neighbors = (P3_xface**) (&(face->v4));
404
/* test if neighbors are back */
405
for (k = 0; k < nbv; k++) {
407
if (n == NULL || n->option & P3_FACE_BACK) {
408
/* add edge k = vertices k and k + 1 */
409
P3_chunk_add_int (renderer->data, (&(face->v1))[k]);
411
P3_chunk_add_int (renderer->data, (&(face->v1))[k + 1]);
413
P3_chunk_add_int (renderer->data, face->v1);
421
P3_chunk_add_int (renderer->data, -1);
422
/* remove face added option */
423
faces = face_batched;
424
while (faces < max) {
425
((P3_xface*) faces->data)->option &= ~(P3_FACE_FRONT | P3_FACE_BACK);
430
void P3_mesh_batch (P3_mesh* mesh, P3_instance* inst) {
431
P3_frustum* frustum = P3_renderer_get_frustum (inst);
432
if (mesh->option & P3_MESH_HAS_SPHERE &&
433
P3_sphere_in_frustum (frustum, (GLfloat*) mesh->xtra2) == P3_FALSE) {
436
if (mesh->option & P3_MESH_DISPLAY_LISTS) {
437
P3_mesh_display_list* dlist = (P3_mesh_display_list*) mesh->xtra1;
438
if (dlist->nb_list_opaque > 0) P3_renderer_batch (renderer->opaque, mesh, inst, -1);
439
if (dlist->nb_list_alpha > 0) P3_renderer_batch (renderer->alpha, mesh, inst, -1);
441
P3_xmesh_batch_start (inst);
442
/* batch each face */
443
if (mesh->option & P3_MESH_TREE) {
444
P3_xmesh_node_batch ((P3_xmesh*) mesh, (P3_xnode*) mesh->xtra1, frustum);
445
} else if (mesh->option & P3_MESH_FACE_LIST) {
446
P3_mesh_face_list* flist = (P3_mesh_face_list*) mesh->xtra2;
448
for (i = 0; i < flist->nb_faces; i++) {
449
P3_xmesh_face_batch ((P3_xmesh*) mesh, flist->faces[i]);
452
void* face = mesh->faces;
453
void* max = mesh->faces + mesh->faces_size;
455
P3_xmesh_face_batch ((P3_xmesh*) mesh, (P3_xface*) face);
456
face += P3_xmesh_face_size ((P3_xmesh*) mesh, face);
459
P3_xmesh_batch_end ();
460
if (mesh->option & P3_MESH_CELL_SHADING) {
461
P3_renderer_batch (renderer->secondpass, mesh, inst, renderer->data->nb);
462
P3_mesh_batch_outline (mesh, inst, frustum);
467
static void P3_mesh_prepare_cell_shading_shades (P3_mesh* mesh, GLfloat* shades, P3_list* lights) {
474
if (mesh->option & P3_MESH_VERTEX_NORMALS) {
475
/* 1 shade per vnormal */
476
for (i = 0; i < lights->nb; i++) {
477
light = (P3_light*) P3_list_get (lights, i);
478
if (light->option & P3_LIGHT_DIRECTIONAL) {
479
/* directional light */
480
ptr1 = mesh->vnormals;
481
for (j = 0; j < mesh->nb_vnormals; j++) {
482
tmp = - P3_vector_dot_product (ptr1, light->data);
483
if (tmp > 0.0) shades[j] += tmp;
487
/* positional light */
488
ptr1 = mesh->vnormals;
489
for (j = 0; j < mesh->nb_vnormals; j++) {
490
/* search the coord that correspond to this vertex normal */
491
for (k = 0; k < mesh->nb_vertices; k++) {
492
if (mesh->vertex_normals[k] == ptr1) break;
494
ptr2 = mesh->vertex_coords[k];
495
v[0] = light->data[0] - ptr2[0];
496
v[1] = light->data[1] - ptr2[1];
497
v[2] = light->data[2] - ptr2[2];
498
P3_vector_normalize (v);
499
tmp = P3_vector_dot_product (ptr1, v);
500
if (tmp > 0.0) shades[j] += tmp;
506
/* 1 shade per coord */
507
for (i = 0; i < lights->nb; i++) {
508
light = (P3_light*) P3_list_get (lights, i);
509
if (light->option & P3_LIGHT_DIRECTIONAL) {
510
/* directional light */
511
ptr1 = mesh->vnormals;
512
for (j = 0; j < mesh->nb_vnormals; j++) {
513
tmp = - P3_vector_dot_product (ptr1, light->data);
514
if (tmp > 0.0) shades[j] += tmp;
518
/* positional light */
519
ptr1 = mesh->vnormals;
521
for (j = 0; j < mesh->nb_vnormals; j++) {
522
v[0] = light->data[0] - ptr2[0];
523
v[1] = light->data[1] - ptr2[1];
524
v[2] = light->data[2] - ptr2[2];
525
P3_vector_normalize (v);
526
tmp = P3_vector_dot_product (ptr1, v);
527
if (tmp > 0.0) shades[j] += tmp;
536
void P3_mesh_prepare_cell_shading (P3_mesh* mesh, P3_instance* inst, GLfloat* shades) {
538
P3_light_list_cast_into (renderer->top_lights, (P3_coordsys*) inst);
539
P3_light_list_cast_into (renderer->c_context->lights, (P3_coordsys*) inst);
540
if (mesh->nb_vnormals > 0) {
541
for (n = 0; n < mesh->nb_vnormals; n++) shades[n] = 0.0;
542
P3_mesh_prepare_cell_shading_shades (mesh, shades, renderer->top_lights);
543
P3_mesh_prepare_cell_shading_shades (mesh, shades, renderer->c_context->lights);
544
/* clip shade texcoord values */
545
for (n = 0; n < mesh->nb_vnormals; n++) {
546
/* do not clip with interval [0, 1] because smooth magnification of texture
549
if (shades[n] > 0.95) shades[n] = 0.95;
550
if (shades[n] < 0.05) shades[n] = 0.05;
555
void P3_mesh_render_outline (P3_mesh* mesh) {
559
data = renderer->data->content + renderer->data->nb;
560
glLineWidth (*((GLfloat*) data));
561
glColor4fv (((P3_mesh_cell_shading*) mesh->xtra1)->line_color);
562
glDisable (GL_LIGHTING);
563
glDepthFunc (GL_LEQUAL);
564
P3_material_inactivate (current_material);
565
current_material = NULL;
566
ptr = (int*) (data + sizeof (GLfloat));
567
if (renderer->colors == NULL) {
572
glVertex3fv (mesh->vertex_coords[i]);
577
GLfloat* color_ptr = ((P3_mesh_cell_shading*) mesh->xtra1)->line_color;
578
GLfloat alpha = color_ptr[3];
584
color_ptr[3] = renderer->colors[i][3];
585
glColor4fv (color_ptr);
586
glVertex3fv (mesh->vertex_coords[i]);
590
color_ptr[3] = alpha;
591
glDisable (GL_BLEND);
593
glEnable (GL_LIGHTING);
594
glDepthFunc (GL_LESS);
598
void P3_mesh_render (P3_mesh* mesh, P3_instance* inst) {
600
P3_xmesh_option_activate (mesh->option);
601
if (mesh->option & P3_MESH_WARFOGS) {
602
renderer->colors = mesh->vertex_warfogs;
603
} else if (mesh->option & P3_MESH_DIFFUSES) {
604
renderer->colors = mesh->vertex_diffuses;
606
renderer->colors = NULL;
608
if (mesh->option & P3_MESH_DISPLAY_LISTS) {
609
P3_mesh_display_list* displist = (P3_mesh_display_list*) mesh->xtra1;
610
P3_display_list* dlists;
611
P3_display_list* dlist;
613
if (!(mesh->option & P3_MESH_INITED)) P3_mesh_display_list_init (mesh);
614
if (renderer->state == P3_RENDERER_STATE_OPAQUE) {
615
dlists = displist->dlists;
616
nb = displist->nb_list_opaque;
618
dlists = displist->dlists + displist->nb_list_opaque;
619
nb = displist->nb_list_alpha;
621
for (i = 0; i < nb; i++) {
623
P3_xface_option_activate (dlist->option);
624
P3_material_activate (dlist->material);
625
glCallList (dlist->dlist);
626
P3_xface_option_inactivate (dlist->option);
629
if (mesh->option & P3_MESH_CELL_SHADING) {
630
if (renderer->state == P3_RENDERER_STATE_SECONDPASS) {
631
P3_mesh_render_outline (mesh);
635
chunk = P3_get_chunk ();
636
P3_chunk_register (chunk, mesh->nb_vnormals * sizeof (GLfloat));
637
shades = (GLfloat*) chunk->content;
638
P3_mesh_prepare_cell_shading (mesh, inst, shades);
640
light_shader = ((P3_mesh_cell_shading*) mesh->xtra1)->shader;
641
P3_xmesh_pack_render_cellshaded ((P3_xmesh*) mesh, shades);
642
P3_drop_chunk (chunk);
645
P3_xmesh_pack_render ((P3_xmesh*) mesh);
648
P3_xmesh_option_inactivate (mesh->option);
656
int P3_mesh_shadow (P3_mesh* mesh, P3_instance* inst, P3_light* light) {
658
// TO DO assume mesh has a face list
660
P3_mesh_face_list* fl = (P3_mesh_face_list*) mesh->xtra2;
662
P3_xface** neighbors;
667
GLfloat b = renderer->c_camera->back;
669
if (!(mesh->option & P3_MESH_SHADOW_CAST)) return P3_FALSE;
670
/* tag all faces front or back */
671
P3_light_cast_into (light, (P3_coordsys*) inst);
672
if (light->option & P3_LIGHT_DIRECTIONAL) {
676
P3_cone_from_sphere_and_vector (cone, (GLfloat*) mesh->xtra2, light->data, b);
677
for (i = 0; i < fl->nb_faces; i++) {
679
if (mesh->option & P3_MESH_VERTEX_OPTIONS) {
680
if (mesh->vertex_options[face->v1] & P3_VERTEX_INVISIBLE &&
681
mesh->vertex_options[face->v2] & P3_VERTEX_INVISIBLE &&
682
mesh->vertex_options[face->v3] & P3_VERTEX_INVISIBLE &&
683
(face->option & P3_FACE_TRIANGLE || mesh->vertex_options[face->v4] & P3_VERTEX_INVISIBLE)) {
687
/* consider double sided faces as the others faces. that's not 100% working
688
* but it's the best I can do
690
if (P3_vector_dot_product (light->data, face->normal) >= 0.0) {
691
face->option |= P3_FACE_BACK;
696
face->option |= P3_FACE_FRONT;
703
if (P3_cone_from_sphere_and_origin (cone, (GLfloat*) mesh->xtra2, light->data, b) == P3_FALSE) return P3_FALSE;
704
for (i = 0; i < fl->nb_faces; i++) {
706
if (mesh->option & P3_MESH_VERTEX_OPTIONS) {
707
if (mesh->vertex_options[face->v1] & P3_VERTEX_INVISIBLE &&
708
mesh->vertex_options[face->v2] & P3_VERTEX_INVISIBLE &&
709
mesh->vertex_options[face->v3] & P3_VERTEX_INVISIBLE &&
710
(face->option & P3_FACE_TRIANGLE || mesh->vertex_options[face->v4] & P3_VERTEX_INVISIBLE)) {
714
if (light->data[0] * face->normal[0] + light->data[1] * face->normal[1] + light->data[2] * face->normal[2] + face->normal[3] > 0.0) {
715
face->option |= P3_FACE_FRONT;
717
face->option |= P3_FACE_BACK;
722
/* draw shadow volume 1rst step */
723
glStencilFunc (GL_ALWAYS, 1, 0xFFFFFFFF);
725
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);
726
glLoadMatrixf (inst->render_matrix);
727
glNewList (shadow_display_list, GL_COMPILE_AND_EXECUTE);
729
/* test if camera is inside the shadow */
730
frustum = P3_renderer_get_frustum (inst);
731
coord[0] = 0.5 * (frustum->points[0] + frustum->points[6]);
732
coord[1] = 0.5 * (frustum->points[1] + frustum->points[7]);
733
coord[2] = 0.5 * (frustum->points[2] + frustum->points[8]);
734
coord[3] = P3_point_distance_to (coord, frustum->points);
735
if (P3_sphere_is_in_cone (coord, cone) == P3_TRUE) {
736
/* camera is inside the shadow => special case
737
* we must draw the intersection of the shadow volume with the camera front plane
738
* by chance we already have functions to do such thing in the watercube ;)
740
P3_watercube_underwater* underwater;
741
P3_chunk* chunk = P3_get_chunk ();
748
m1 = P3_coordsys_get_root_matrix ((P3_coordsys*) inst);
749
m2 = P3_coordsys_get_inverted_root_matrix ((P3_coordsys*) renderer->c_camera);
750
/* find edges and draw shadow volume */
751
for (i = 0; i < fl->nb_faces; i++) {
753
if (face->option & P3_FACE_BACK) {
754
/* test if neighbors are front */
755
if (face->option & P3_FACE_QUAD) {
756
neighbors = (P3_xface**) (&(face->v4) + 1);
759
neighbors = (P3_xface**) (&(face->v4));
762
for (k = 0; k < nbv; k++) {
763
if (neighbors[k] == NULL || neighbors[k]->option & P3_FACE_FRONT) {
765
// TO DO avoid pushing 2 vertices with the same coord
767
/* add edge k = vertices k and k + 1 */
768
coord_ptr = mesh->vertex_coords[(&(face->v1))[k]];
769
glVertex3fv (coord_ptr);
770
/* push coord far away */
771
if (light->option & P3_LIGHT_DIRECTIONAL) {
772
coord[0] = coord_ptr[0] + b * light->data[0];
773
coord[1] = coord_ptr[1] + b * light->data[1];
774
coord[2] = coord_ptr[2] + b * light->data[2];
777
coord[0] = coord_ptr[0] - light->data[0];
778
coord[1] = coord_ptr[1] - light->data[1];
779
coord[2] = coord_ptr[2] - light->data[2];
780
P3_vector_normalize (coord);
781
coord[0] = coord_ptr[0] + b * coord[0];
782
coord[1] = coord_ptr[1] + b * coord[1];
783
coord[2] = coord_ptr[2] + b * coord[2];
787
coord_ptr2 = mesh->vertex_coords[(&(face->v1))[k + 1]];
789
coord_ptr2 = mesh->vertex_coords[face->v1];
791
/* push coord far away */
792
if (light->option & P3_LIGHT_DIRECTIONAL) {
793
coord2[0] = coord_ptr2[0] + b * light->data[0];
794
coord2[1] = coord_ptr2[1] + b * light->data[1];
795
coord2[2] = coord_ptr2[2] + b * light->data[2];
796
glVertex3fv (coord2);
798
coord2[0] = coord_ptr2[0] - light->data[0];
799
coord2[1] = coord_ptr2[1] - light->data[1];
800
coord2[2] = coord_ptr2[2] - light->data[2];
801
P3_vector_normalize (coord2);
802
coord2[0] = coord_ptr2[0] + b * coord2[0];
803
coord2[1] = coord_ptr2[1] + b * coord2[1];
804
coord2[2] = coord_ptr2[2] + b * coord2[2];
805
glVertex3fv (coord2);
807
glVertex3fv (coord_ptr2);
808
/* convert point to camera coordsys */
809
P3_point_by_matrix_copy (coord3, coord_ptr, m1);
810
P3_point_by_matrix_copy (coord4, coord_ptr2, m1);
811
P3_point_by_matrix (coord, m1);
812
P3_point_by_matrix (coord2, m1);
813
P3_point_by_matrix (coord, m2);
814
P3_point_by_matrix (coord2, m2);
815
P3_point_by_matrix (coord3, m2);
816
P3_point_by_matrix (coord4, m2);
817
P3_watercube_underwater_intersect_face (chunk, coord3, coord, coord2);
818
P3_watercube_underwater_intersect_face (chunk, coord2, coord4, coord3);
825
glDisable (GL_CULL_FACE);
826
glDisable (GL_DEPTH_TEST);
828
if (chunk->nb == 0) {
829
/* 2 cases: front plane entirely inside the shadow or entirely outside
830
* use a raypicking to be sure
832
P3_raypick_data rdata;
834
rdata.option = P3_RAYPICK_HALF_LINE;
835
rdata.raypicked = P3_get_list ();
836
rdata.raypick_data = P3_get_chunk ();
837
if (light->option & P3_LIGHT_DIRECTIONAL) {
838
rdata.root_data[0] = renderer->r_frustum->position[0];
839
rdata.root_data[1] = renderer->r_frustum->position[1];
840
rdata.root_data[2] = renderer->r_frustum->position[2];
841
coord_ptr = P3_coordsys_get_root_matrix ((P3_coordsys*) light);
842
rdata.root_data[6] = renderer->c_camera->back;
843
rdata.root_data[3] = rdata.root_data[0] + rdata.root_data[6] * coord_ptr[ 8];
844
rdata.root_data[4] = rdata.root_data[1] + rdata.root_data[6] * coord_ptr[ 9];
845
rdata.root_data[5] = rdata.root_data[2] + rdata.root_data[6] * coord_ptr[10];
847
coord_ptr = P3_coordsys_get_root_matrix ((P3_coordsys*) light);
848
memcpy (rdata.root_data, coord_ptr + 12, 3 * sizeof (GLfloat));
849
rdata.root_data[3] = renderer->r_frustum->position[0] - rdata.root_data[0];
850
rdata.root_data[4] = renderer->r_frustum->position[1] - rdata.root_data[1];
851
rdata.root_data[5] = renderer->r_frustum->position[2] - rdata.root_data[2];
852
rdata.root_data[6] = P3_vector_length (rdata.root_data + 3);
853
f = 1.0 / rdata.root_data[6];
854
rdata.root_data[3] *= f;
855
rdata.root_data[4] *= f;
856
rdata.root_data[5] *= f;
858
if (P3_mesh_raypick_b (mesh, &rdata, (P3_raypickable*) inst) == P3_TRUE) {
859
/* all the screen must be shadowed
860
* that's cool I have the coordinate of the edge of the screen in the gl vertex array ;)
862
glDrawArrays (GL_QUADS, 0, 4);
864
for (i = 0; i < rdata.raypicked->nb; i++) {
865
((P3_raypickable*) P3_list_get (rdata.raypicked, i))->raypick_data = -1;
867
P3_drop_list (rdata.raypicked);
868
P3_drop_chunk (rdata.raypick_data);
869
} else if (chunk->nb > 0) {
870
underwater = P3_watercube_underwater_join_segments ((GLfloat*) chunk->content, chunk->nb / (3 * sizeof (GLfloat)));
871
P3_watercube_underwater_draw_segments (underwater);
872
free (underwater->points);
873
free (underwater->seq_sizes);
876
P3_drop_chunk (chunk);
877
glEnable (GL_CULL_FACE);
878
glEnable (GL_DEPTH_TEST);
879
/* draw shadow volume 2nd step */
880
glLoadMatrixf (inst->render_matrix);
881
glFrontFace (GL_CCW);
882
glStencilFunc (GL_ALWAYS, 0, 0xFFFFFFFF);
883
glStencilOp (GL_KEEP, GL_KEEP, GL_DECR);
884
glCallList (shadow_display_list);
886
/* find edges and draw shadow volume */
887
for (i = 0; i < fl->nb_faces; i++) {
889
if (face->option & P3_FACE_BACK) {
890
/* test if neighbors are front */
891
if (face->option & P3_FACE_QUAD) {
892
neighbors = (P3_xface**) (&(face->v4) + 1);
895
neighbors = (P3_xface**) (&(face->v4));
898
for (k = 0; k < nbv; k++) {
899
if (neighbors[k] == NULL || neighbors[k]->option & P3_FACE_FRONT) {
901
// TO DO avoid pushing 2 vertices with the same coord
903
/* add edge k = vertices k and k + 1 */
904
coord_ptr = mesh->vertex_coords[(&(face->v1))[k]];
905
glVertex3fv (coord_ptr);
906
/* push coord far away */
907
if (light->option & P3_LIGHT_DIRECTIONAL) {
908
glVertex3f (coord_ptr[0] + b * light->data[0], coord_ptr[1] + b * light->data[1], coord_ptr[2] + b * light->data[2]);
910
coord[0] = coord_ptr[0] - light->data[0];
911
coord[1] = coord_ptr[1] - light->data[1];
912
coord[2] = coord_ptr[2] - light->data[2];
913
P3_vector_normalize (coord);
914
glVertex3f (coord_ptr[0] + b * coord[0], coord_ptr[1] + b * coord[1], coord_ptr[2] + b * coord[2]);
917
coord_ptr = mesh->vertex_coords[(&(face->v1))[k + 1]];
919
coord_ptr = mesh->vertex_coords[face->v1];
921
/* push coord far away */
922
if (light->option & P3_LIGHT_DIRECTIONAL) {
923
glVertex3f (coord_ptr[0] + b * light->data[0], coord_ptr[1] + b * light->data[1], coord_ptr[2] + b * light->data[2]);
925
coord[0] = coord_ptr[0] - light->data[0];
926
coord[1] = coord_ptr[1] - light->data[1];
927
coord[2] = coord_ptr[2] - light->data[2];
928
P3_vector_normalize (coord);
929
glVertex3f (coord_ptr[0] + b * coord[0], coord_ptr[1] + b * coord[1], coord_ptr[2] + b * coord[2]);
931
glVertex3fv (coord_ptr);
938
/* draw shadow volume 2nd step */
939
glFrontFace (GL_CCW);
940
glStencilFunc (GL_ALWAYS, 0, 0xFFFFFFFF);
941
glStencilOp (GL_KEEP, GL_KEEP, GL_DECR);
942
glCallList (shadow_display_list);
944
/* remove face tag */
945
for (i = 0; i < fl->nb_faces; i++) fl->faces[i]->option &= ~(P3_FACE_FRONT | P3_FACE_BACK);
950
/*==================+
952
+==================*/
954
static void P3_mesh_display_list_get_data (P3_mesh* mesh, P3_mesh_display_list* dlist, P3_chunk* chunk) {
957
P3_chunk_save_int (chunk, dlist->nb_list_opaque);
958
P3_chunk_save_int (chunk, dlist->nb_list_alpha);
959
for (i = 0; i < dlist->nb_list_opaque + dlist->nb_list_alpha; i++) {
960
dl = dlist->dlists + i;
961
P3_chunk_save_int (chunk, dl->option);
962
P3_chunk_save_int (chunk, P3_xmesh_get_material_index ((P3_xmesh*) mesh, dl->material));
966
static void P3_mesh_cell_shading_get_data (P3_mesh* mesh, P3_mesh_cell_shading* cshade, P3_chunk* chunk) {
967
P3_chunk_save (chunk, cshade->line_color, 4 * sizeof (GLfloat));
968
P3_chunk_save_float (chunk, cshade->line_width_factor);
969
if (cshade->shader == NULL) {
970
P3_chunk_save_int (chunk, -1);
972
P3_chunk_save_int (chunk, P3_xmesh_get_material_index ((P3_xmesh*) mesh, cshade->shader));
976
void P3_mesh_get_data (P3_mesh* mesh, P3_chunk* chunk) {
980
if (i & P3_MESH_INITED) i -= P3_MESH_INITED;
981
P3_chunk_save_int (chunk, i);
983
if (mesh->option & P3_MESH_DISPLAY_LISTS) {
984
P3_mesh_display_list_get_data (mesh, (P3_mesh_display_list*) mesh->xtra1, chunk);
986
if (mesh->option & P3_MESH_HAS_SPHERE) {
987
P3_chunk_save (chunk, (GLfloat*) mesh->xtra2, 4 * sizeof (GLfloat));
989
if (mesh->option & P3_MESH_CELL_SHADING) {
990
P3_mesh_cell_shading_get_data (mesh, (P3_mesh_cell_shading*) mesh->xtra1, chunk);
993
P3_xmesh_get_data ((P3_xmesh*) mesh, chunk);
995
if (mesh->option & P3_MESH_TREE) {
996
P3_xnode_get_data ((P3_xnode*) mesh->xtra1, (P3_xmesh*) mesh, chunk);
1000
static P3_mesh_display_list* P3_mesh_display_list_set_data (P3_mesh* mesh, P3_chunk* chunk) {
1001
P3_mesh_display_list* dlist;
1002
P3_display_list* dl;
1006
dlist = (P3_mesh_display_list*) malloc (sizeof (P3_mesh_display_list));
1007
dlist->nb_list_opaque = P3_chunk_load_int (chunk);
1008
dlist->nb_list_alpha = P3_chunk_load_int (chunk);
1009
nb = dlist->nb_list_opaque + dlist->nb_list_alpha;
1010
dlist->dlists = (P3_display_list*) malloc (nb * sizeof (P3_display_list));
1011
for (i = 0; i < nb; i++) {
1012
dl = dlist->dlists + i;
1013
dl->option = P3_chunk_load_int (chunk);
1014
n = P3_chunk_load_int (chunk);
1016
dl->material = NULL;
1018
dl->material = mesh->materials[n];
1024
static void P3_mesh_cell_shading_set_data (P3_mesh* mesh, P3_mesh_cell_shading* cshade, P3_chunk* chunk) {
1026
P3_chunk_load (chunk, cshade->line_color, 4 * sizeof (GLfloat));
1027
cshade->line_width_factor = P3_chunk_load_float (chunk);
1028
n = P3_chunk_load_int (chunk);
1030
cshade->shader = NULL;
1032
cshade->shader = mesh->materials[n];
1036
void P3_mesh_set_data (P3_mesh* mesh, P3_chunk* chunk) {
1038
mesh->option = P3_chunk_load_int (chunk);
1042
if (mesh->option & P3_MESH_DISPLAY_LISTS) mesh->xtra1 = P3_mesh_display_list_set_data (mesh, chunk);
1043
if (mesh->option & P3_MESH_FACE_LIST) {
1044
P3_mesh_face_list* flist = (P3_mesh_face_list*) malloc (sizeof (P3_mesh_face_list));
1045
P3_chunk_load (chunk, flist->sphere, 4 * sizeof (GLfloat));
1046
mesh->xtra2 = flist;
1047
} else if (mesh->option & P3_MESH_HAS_SPHERE) {
1048
GLfloat* sphere = (GLfloat*) malloc (4 * sizeof (GLfloat));
1049
P3_chunk_load (chunk, sphere, 4 * sizeof (GLfloat));
1050
mesh->xtra2 = sphere;
1052
if (mesh->option & P3_MESH_CELL_SHADING) {
1053
P3_mesh_cell_shading* cshade = (P3_mesh_cell_shading*) malloc (sizeof (P3_mesh_cell_shading));
1054
P3_mesh_cell_shading_set_data (mesh, cshade, chunk);
1055
mesh->xtra1 = cshade;
1058
P3_xmesh_set_data ((P3_xmesh*) mesh, chunk);
1060
if (mesh->option & P3_MESH_TREE) mesh->xtra1 = P3_xnode_set_data ((P3_xmesh*) mesh, chunk);
1061
/* xtra initialization */
1062
if (mesh->option & P3_MESH_FACE_LIST) P3_mesh_create_faces_list ((P3_mesh_face_list*) mesh->xtra2, mesh);