1 /*
2  * Tux Racer
3  * Copyright (C) 1999-2001 Jasmin F. Patry
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  */
19 
20 #include "tux_shadow.h"
21 #include "gl_util.h"
22 #include "tux.h"
23 #include "hier.h"
24 #include "phys_sim.h"
25 #include "textures.h"
26 
27 #define SHADOW_HEIGHT 0.1
28 
29 
30 /*
31  * Make the shadow darker if the stencil buffer is active
32  */
33 #ifdef USE_STENCIL_BUFFER
34 
35 static colour_t shadow_colour = { 0.0, 0.0, 0.0, 0.3 };
36 
37 #else
38 
39 static colour_t shadow_colour = { 0.0, 0.0, 0.0, 0.1 };
40 
41 #endif /* USE_STENCIL_BUFFER */
42 
draw_tux_shadow()43 void draw_tux_shadow()
44 {
45     matrixgl_t model_matrix;
46     char *tux_root_node_name;
47     scene_node_t *tux_root_node;
48 
49     if ( ! getparam_draw_tux_shadow() )
50 	return;
51 
52     set_gl_options( TUX_SHADOW );
53 
54     glColor4f( shadow_colour.r, shadow_colour.g, shadow_colour.b,
55 	       shadow_colour.a );
56 
57     make_identity_matrix( model_matrix );
58 
59     tux_root_node_name = get_tux_root_node();
60 
61     if ( get_scene_node( tux_root_node_name, &tux_root_node ) != TCL_OK ) {
62 	check_assertion( 0, "couldn't find tux's root node" );
63     }
64 
65     traverse_dag_for_shadow( tux_root_node, model_matrix );
66 }
67 
traverse_dag_for_shadow(scene_node_t * node,matrixgl_t model_matrix)68 void traverse_dag_for_shadow( scene_node_t *node, matrixgl_t model_matrix )
69 {
70     matrixgl_t new_model_matrix;
71     scene_node_t *child;
72 
73     check_assertion( node != NULL, "node is NULL" );
74 
75     multiply_matrices(new_model_matrix, model_matrix, node->trans);
76 
77     if ( node->geom == Sphere && node->render_shadow ) {
78 	draw_shadow_sphere( new_model_matrix );
79     }
80 
81     child = node->child;
82     while (child != NULL) {
83 
84         traverse_dag_for_shadow(child, new_model_matrix);
85 
86         child = child->next;
87     }
88 }
89 
draw_shadow_sphere(matrixgl_t model_matrix)90 void draw_shadow_sphere( matrixgl_t model_matrix )
91 {
92     scalar_t theta, phi, d_theta, d_phi, eps, twopi;
93     scalar_t x, y, z;
94     int div = getparam_tux_shadow_sphere_divisions();
95 
96     eps = 1e-15;
97     twopi = M_PI * 2.0;
98 
99     d_theta = d_phi = M_PI / div;
100 
101     for ( phi = 0.0; phi + eps < M_PI; phi += d_phi ) {
102 	scalar_t cos_theta, sin_theta;
103 	scalar_t sin_phi, cos_phi;
104 	scalar_t sin_phi_d_phi, cos_phi_d_phi;
105 
106 	sin_phi = sin( phi );
107 	cos_phi = cos( phi );
108 	sin_phi_d_phi = sin( phi + d_phi );
109 	cos_phi_d_phi = cos( phi + d_phi );
110 
111         if ( phi <= eps ) {
112 
113             glBegin( GL_TRIANGLE_FAN );
114 		draw_shadow_vertex( 0., 0., 1., model_matrix );
115 
116                 for ( theta = 0.0; theta + eps < twopi; theta += d_theta ) {
117 		    sin_theta = sin( theta );
118 		    cos_theta = cos( theta );
119 
120                     x = cos_theta * sin_phi_d_phi;
121 		    y = sin_theta * sin_phi_d_phi;
122                     z = cos_phi_d_phi;
123 		    draw_shadow_vertex( x, y, z, model_matrix );
124                 }
125 
126 		x = sin_phi_d_phi;
127 		y = 0.0;
128 		z = cos_phi_d_phi;
129 		draw_shadow_vertex( x, y, z, model_matrix );
130             glEnd();
131 
132         } else if ( phi + d_phi + eps >= M_PI ) {
133 
134             glBegin( GL_TRIANGLE_FAN );
135 		draw_shadow_vertex( 0., 0., -1., model_matrix );
136 
137                 for ( theta = twopi; theta - eps > 0; theta -= d_theta ) {
138 		    sin_theta = sin( theta );
139 		    cos_theta = cos( theta );
140 
141                     x = cos_theta * sin_phi;
142                     y = sin_theta * sin_phi;
143                     z = cos_phi;
144 		    draw_shadow_vertex( x, y, z, model_matrix );
145                 }
146                 x = sin_phi;
147                 y = 0.0;
148                 z = cos_phi;
149 		draw_shadow_vertex( x, y, z, model_matrix );
150             glEnd();
151 
152         } else {
153 
154             glBegin( GL_TRIANGLE_STRIP );
155 
156                 for ( theta = 0.0; theta + eps < twopi; theta += d_theta ) {
157 		    sin_theta = sin( theta );
158 		    cos_theta = cos( theta );
159 
160                     x = cos_theta * sin_phi;
161                     y = sin_theta * sin_phi;
162                     z = cos_phi;
163 		    draw_shadow_vertex( x, y, z, model_matrix );
164 
165                     x = cos_theta * sin_phi_d_phi;
166                     y = sin_theta * sin_phi_d_phi;
167                     z = cos_phi_d_phi;
168 		    draw_shadow_vertex( x, y, z, model_matrix );
169                 }
170                 x = sin_phi;
171                 y = 0.0;
172                 z = cos_phi;
173 		draw_shadow_vertex( x, y, z, model_matrix );
174 
175                 x = sin_phi_d_phi;
176                 y = 0.0;
177                 z = cos_phi_d_phi;
178 		draw_shadow_vertex( x, y, z, model_matrix );
179 
180             glEnd();
181 
182         }
183     }
184 
185 }
186 
draw_shadow_vertex(scalar_t x,scalar_t y,scalar_t z,matrixgl_t model_matrix)187 void draw_shadow_vertex( scalar_t x, scalar_t y, scalar_t z,
188 			 matrixgl_t model_matrix )
189 {
190     point_t pt;
191     scalar_t old_y;
192     vector_t nml;
193 
194     pt = make_point( x, y, z );
195     pt = transform_point( model_matrix, pt );
196 
197     old_y = pt.y;
198 
199     nml = find_course_normal( pt.x, pt.z );
200     pt.y = find_y_coord( pt.x, pt.z ) + SHADOW_HEIGHT;
201 
202     if ( pt.y > old_y )
203 	pt.y = old_y;
204 
205     glNormal3f( nml.x, nml.y, nml.z );
206     glVertex3f( pt.x, pt.y, pt.z );
207 }
208