init
[carveJwlIkooP6JGAAIwe30JlM.git] / road.h
1 float const k_road_width = 4.0f;
2
3 #define ROAD_PATCH_NODES 1024
4 #define ROAD_SEGMENT_VERTICES 8
5 #define ROAD_SEGMENT_INDICES ((3*2)*5)
6 #define ROAD_INDEX_BUFFER_SIZE (ROAD_SEGMENT_INDICES * (ROAD_PATCH_NODES-2))
7 #define ROAD_RENDER_DIST 12
8 #define ROAD_RENDER_DIST_INDICES (ROAD_SEGMENT_INDICES*ROAD_RENDER_DIST)
9
10 typedef struct road_node
11 {
12 v3f pos,
13 side,
14 fwd;
15
16 } road_node;
17
18 typedef struct road_patch
19 {
20 road_node nodes[ ROAD_PATCH_NODES ];
21
22 int active_id;
23 road_node *active;
24 }
25 road_patch;
26
27 static void road_get_range( road_patch *road, int range, int *start, int *end )
28 {
29 *start = VG_MIN( VG_MAX( 0, road->active_id-range ), ROAD_PATCH_NODES-2 );
30 *end = VG_MIN( VG_MAX( 0, road->active_id+range ), ROAD_PATCH_NODES-2 );
31 }
32
33 static int test_edge_with_norm( v3f p0, v3f p1, v3f norm, v3f p )
34 {
35 v3f edge, edge_norm, v1;
36
37 v3_sub( p1, p0, edge );
38 v3_cross( edge, norm, edge_norm );
39 v3_sub( p0, p, v1 );
40
41 if( v3_dot( edge_norm, v1 ) > 0.0f )
42 {
43 vg_line( p0, p1, 0xff0000ff );
44 return 0;
45 }
46 else
47 {
48 vg_line( p0, p1, 0xff00ff00 );
49 return 1;
50 }
51 }
52
53 static int patch_seg_test_inside( road_node *node, v3f p )
54 {
55 road_node *next = node + 1;
56
57 v3f norm,
58 sa, sb, sc, sd;
59
60 v3_muls( node->side, -k_road_width, sa );
61 v3_add( node->pos, sa, sa );
62
63 v3_muls( next->side, -k_road_width, sb );
64 v3_add( next->pos, sb, sb );
65
66 v3_muls( next->side, k_road_width, sc );
67 v3_add( next->pos, sc, sc );
68
69 v3_muls( node->side, k_road_width, sd );
70 v3_add( node->pos, sd, sd );
71
72 v3_cross( node->side, node->fwd, norm );
73
74 if( !test_edge_with_norm( sa, sb, norm, p ) ) return 0;
75 if( !test_edge_with_norm( sb, sc, norm, p ) ) return 0;
76 if( !test_edge_with_norm( sc, sd, norm, p ) ) return 0;
77 if( !test_edge_with_norm( sd, sa, norm, p ) ) return 0;
78
79 return 1;
80 }
81
82 static void road_patch_setplayer( road_patch *road, v3f pos )
83 {
84 int idx_start, idx_end;
85 road_get_range( road, ROAD_RENDER_DIST, &idx_start, &idx_end );
86
87 for( int i = idx_start; i < idx_end; i ++ )
88 {
89 if( patch_seg_test_inside( road->nodes + i, pos ) )
90 {
91 road->active_id = i;
92 road->active = road->nodes + i;
93 return;
94 }
95 }
96 }
97
98 static void road_patch_init( road_patch *road )
99 {
100 road->active = road->nodes + road->active_id;
101 }
102
103 static void road_generate( road_patch *road )
104 {
105 v3f dir_fwd = { 1.0f, 0.0f, 0.0f },
106 dir_up = { 0.0f, 1.0f, 0.0f },
107 dir_side = { 0.0f, 0.0f, 1.0f },
108 current_point = { 0.0f, 0.0f, 0.0f };
109
110 float current_rotation_amt = 0.0f,
111 current_pitch_amt = -0.2f,
112 current_roll_amt = 0.00f;
113
114 for( int i = 0; i < ROAD_PATCH_NODES; i ++ )
115 {
116 road_node *node = road->nodes + i;
117
118 if( (float)rand()/(float)(RAND_MAX) < 0.3f )
119 {
120 current_rotation_amt = (float)rand()/(float)(RAND_MAX)*0.6f-0.3f;
121 current_pitch_amt = (float)rand()/(float)(RAND_MAX)*0.03f-0.015f;
122 }
123
124 v3_rotate( dir_up, current_roll_amt, dir_fwd, dir_up );
125 v3_cross( dir_fwd, dir_up, dir_side );
126 dir_side[1] = 0.0f;
127
128 v3_rotate( dir_fwd, current_rotation_amt, (v3f){0.f, 1.f, 0.f}, dir_fwd );
129 v3_rotate( dir_fwd, current_pitch_amt, dir_side, dir_fwd );
130 v3_rotate( dir_up, current_pitch_amt, dir_side, dir_up );
131
132 v3_muladds( current_point, dir_fwd, 7.0f, current_point );
133
134 v3_copy( current_point, node->pos );
135 v3_copy( dir_side, node->side );
136 v3_copy( dir_fwd, node->fwd );
137 current_pitch_amt = 0.f;
138
139 node->pos[1] += (float)rand()/(float)(RAND_MAX)*0.2f;
140 }
141
142 road->active_id = 0;
143 }
144
145 void draw_road_patch_dev( road_patch *road )
146 {
147 v3f dir;
148 v3f norm;
149 v3f p0 = { 0.0f, 0.0f, 0.0f }, p1 = { 0.0f, 0.0f, 0.0f };
150 v3f p2; v3f p3;
151
152 for( int i = 0; i < ROAD_PATCH_NODES-1; i ++ )
153 {
154 road_node *node = &road->nodes[i];
155 road_node *next = &road->nodes[i+1];
156
157 vg_line( node->pos, next->pos, 0x55ffcc22 );
158
159 // Get line dir
160 v3_sub( next->pos, node->pos, dir );
161 v3_normalize( dir );
162
163 // Perpendicular vector
164 norm[0] = -dir[2];
165 norm[1] = 0.f;
166 norm[2] = dir[0];
167
168 v3_muls( node->side, k_road_width, p2 );
169 v3_add( p2, node->pos, p2 );
170 v3_muls( node->side, -k_road_width, p3 );
171 v3_add( p3, node->pos, p3 );
172
173 vg_line( p3, p1, 0xccffcc22 );
174 vg_line( p2, p0, 0xccffcc22 );
175
176 v3_copy( p3, p1 );
177 v3_copy( p2, p0 );
178 }
179 }
180
181 static void sample_road( road_patch *patch, v3f pos )
182 {
183 v3f v1, norm;
184 v3_sub( patch->active->pos, pos, v1 );
185 v3_cross( patch->active->side, patch->active->fwd, norm );
186
187 float d = v3_dot( norm, v1 );
188 v3_muladds( pos, norm, d, pos );
189 }
190
191 static int triangle_raycast( v3f pA, v3f pB, v3f pC, v3f ray, float *height )
192 {
193 v2f v0, v1, v2, vp, vp2;
194 float d, bca = 0.f, bcb = 0.f, bcc = 0.f;
195
196 v0[0] = pB[0] - pA[0];
197 v0[1] = pB[2] - pA[2];
198 v1[0] = pC[0] - pA[0];
199 v1[1] = pC[2] - pA[2];
200 v2[0] = pB[0] - pC[0];
201 v2[1] = pB[2] - pC[2];
202
203 d = 1.f / (v0[0]*v1[1] - v1[0]*v0[1]);
204
205 #if 0
206 /* Backface culling */
207 if( v2_cross( v0, v1 ) > 0.f )
208 return;
209 #endif
210
211 vp[0] = ray[0] - pA[0];
212 vp[1] = ray[2] - pA[2];
213
214 if( v2_cross( v0, vp ) > 0.f ) return 0;
215 if( v2_cross( vp, v1 ) > 0.f ) return 0;
216
217 vp2[0] = ray[0] - pB[0];
218 vp2[1] = ray[2] - pB[2];
219
220 if( v2_cross( vp2, v2 ) > 0.f ) return 0;
221
222 bcb = (vp[0]*v1[1] - v1[0]*vp[1]) * d;
223 bcc = (v0[0]*vp[1] - vp[0]*v0[1]) * d;
224 bca = 1.f - bcb - bcc;
225
226 *height = pA[1]*bca + pB[1]*bcb + pC[1]*bcc;
227 return 1;
228 }
229
230
231 static int sample_road_height( road_patch *road, v3f pos )
232 {
233 v3f norm,
234 sa, sb, sc, sd;
235
236 int idx_start, idx_end;
237 road_get_range( road, ROAD_RENDER_DIST, &idx_start, &idx_end );
238
239 for( int i = idx_start; i < idx_end; i ++ )
240 {
241 road_node *node = &road->nodes[i],
242 *next = &road->nodes[i+1];
243
244 v3_muls( node->side, -k_road_width, sa );
245 v3_add( node->pos, sa, sa );
246
247 v3_muls( next->side, -k_road_width, sb );
248 v3_add( next->pos, sb, sb );
249
250 v3_muls( next->side, k_road_width, sc );
251 v3_add( next->pos, sc, sc );
252
253 v3_muls( node->side, k_road_width, sd );
254 v3_add( node->pos, sd, sd );
255
256 /* Triangle 1 */
257 float height;
258
259 if( triangle_raycast( sa, sc, sb, pos, &height ) )
260 {
261 pos[1] = height;
262 return 1;
263 }
264
265 if( triangle_raycast( sa, sd, sc, pos, &height ) )
266 {
267 pos[1] = height;
268 return 1;
269 }
270 }
271
272 return 0;
273 }