1 /*
2 * GRacer
3 *
4 * Copyright (C) 1999 Takashi Matsuda <matsu@users.sourceforge.net>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 * USA
20 */
21
22 #include <assert.h>
23 #include <string.h>
24 #include "gr_course.h"
25 #include "gr_memory.h"
26 #include "gr_vertex.h"
27
28 enum {
29 TOKEN_NUM_GRID,
30 TOKEN_GRID,
31 TOKEN_NUM_CLINE,
32 TOKEN_CLINE,
33 TOKEN_NUM_MAT,
34 TOKEN_MAT,
35 TOKEN_NUM_SEG,
36 TOKEN_SEG,
37 TOKEN_NUM_VERT,
38 TOKEN_NUM_SURF,
39 TOKEN_TITLE,
40 TOKEN_DESC,
41 TOKEN_MODEL,
42 TOKEN_TIMESTAMP,
43
44 TOKEN_INVALID = -1,
45 };
46
47 static struct {
48 int type;
49 char *str;
50 int len;
51 } tokens[] = {
52 {TOKEN_NUM_GRID, "NUM_GRID", 8},
53 {TOKEN_GRID, "GRID", 4},
54 {TOKEN_NUM_CLINE, "NUM_CLINE", 9},
55 {TOKEN_CLINE, "CLINE", 5},
56 {TOKEN_NUM_MAT, "NUM_MAT", 7},
57 {TOKEN_MAT, "MAT", 3},
58 {TOKEN_NUM_SEG, "NUM_SEG", 7},
59 {TOKEN_SEG, "SEG", 3},
60 {TOKEN_NUM_VERT, "NUM_VERT", 8},
61 {TOKEN_NUM_SURF, "NUM_SURF", 8},
62 {TOKEN_TITLE, "TITLE", 5},
63 {TOKEN_DESC, "DESC", 4},
64 {TOKEN_MODEL, "MODEL", 5},
65 {TOKEN_TIMESTAMP, "TIMESTAMP", 9},
66 {TOKEN_INVALID, NULL, -1},
67 };
68
69
70 static int next_line (char *data, int *index);
71 static int find_token (char *data, int *index);
72 static int next_word (char *data, int *index);
73 static char* get_name (char *data, int *index);
74 static void put_name (char *str, FILE *file);
75 static GrCSegment* read_segment (GrCourse *course,
76 char *data,
77 int *index);
78 static void create_boundary (GrCSegment *seg);
79 static void initialize_surface (GrCSegment *seg);
80
81
82 static void
gr_csegment_free(GrCSegment * seg)83 gr_csegment_free (GrCSegment *seg)
84 {
85 gr_boundary_free (seg->boundary);
86 free (seg->verts);
87 free (seg->surfs);
88 }
89
90 static void
gr_course_free(GrCourse * course)91 gr_course_free (GrCourse *course)
92 {
93 int i;
94
95 free (course->title);
96 free (course->desc);
97 free (course->model);
98 free (course->timestamp);
99 free (course->grids);
100 free (course->clines);
101 free (course->mats);
102
103 for (i=0; i<course->num_segs; i++) {
104 free (course->segs[i]);
105 }
106 free (course->segs);
107
108 free (course);
109 }
110
111 GrCourse*
gr_course_new_from_file(FILE * file)112 gr_course_new_from_file (FILE *file)
113 {
114 size_t pos;
115 size_t len;
116 char *buf;
117 GrCourse *course;
118
119 pos = ftell (file);
120 fseek (file, 0, SEEK_END);
121 len = ftell (file) - pos;
122 fseek (file, pos, SEEK_SET);
123
124 buf = gr_new (char, len+1);
125 if (!buf) {
126 return NULL;
127 }
128 fread (buf, 1, len, file);
129 buf[len] = '\0';
130
131 course = gr_course_new_from_data (buf);
132 free (buf);
133
134 return course;
135 }
136
137 GrCourse*
gr_course_new_from_data(char * data)138 gr_course_new_from_data (char *data)
139 {
140 GrCourse *course = NULL;
141 GrControlLine *cline;
142 int i = 0, j, k;
143 int token;
144 float x[6];
145 float y[6];
146 float f;
147
148 if (strncmp (data, "GRACER COURSE/1.0\n", 18))
149 goto ERROR;
150
151 course = gr_new0 (GrCourse, 1);
152 if (!course)
153 return NULL;
154 gr_FREE_FUNC (course, gr_course_free);
155
156 next_line (data, &i);
157 while (data[i] != '\0') {
158 token = find_token (data, &i);
159 switch (token) {
160 case TOKEN_TITLE:
161 next_word (data, &i);
162 course->title = get_name (data, &i);
163 break;
164
165 case TOKEN_DESC:
166 next_word (data, &i);
167 course->desc = get_name (data, &i);
168 break;
169
170 case TOKEN_MODEL:
171 next_word (data, &i);
172 course->model = get_name (data, &i);
173 break;
174
175 case TOKEN_TIMESTAMP:
176 next_word (data, &i);
177 course->timestamp = get_name (data, &i);
178 break;
179
180 case TOKEN_NUM_GRID:
181 next_word (data, &i);
182 sscanf (data+i, "%d", &course->num_grids);
183 course->grids = gr_new (GrGrid, course->num_grids);
184 next_line (data, &i);
185 for (j=0; j<course->num_grids; j++) {
186 sscanf (data+i, "GRID %d %d %f %f %f",
187 &course->grids[j].flag,
188 &course->grids[j].segment,
189 &course->grids[j].x,
190 &course->grids[j].y,
191 &course->grids[j].dir);
192 next_line (data, &i);
193 }
194 break;
195
196 case TOKEN_NUM_CLINE:
197 next_word (data, &i);
198 sscanf (data+i, "%d", &course->num_clines);
199 course->clines = gr_new (GrControlLine, course->num_clines);
200 next_line (data, &i);
201 for (j=0; j<course->num_clines; j++) {
202 cline = course->clines + j;
203
204 sscanf (data+i, "CLINE %d %d",
205 &cline->segment,
206 &cline->flag);
207 next_line (data, &i);
208 for (k=0; k<6; k++) {
209 sscanf (data+i, "%f %f", &x[k], &y[k]);
210 next_line (data, &i);
211 }
212 cline->region_a[0].c.x = x[0];
213 cline->region_a[0].c.y = y[0];
214 cline->region_a[1].c.x = x[1];
215 cline->region_a[1].c.y = y[1];
216 cline->region_a[2].c.x = x[3];
217 cline->region_a[2].c.y = y[3];
218 cline->region_a[3].c.x = x[2];
219 cline->region_a[3].c.y = y[2];
220
221 cline->region_b[0].c.x = x[2];
222 cline->region_b[0].c.y = y[2];
223 cline->region_b[1].c.x = x[3];
224 cline->region_b[1].c.y = y[3];
225 cline->region_b[2].c.x = x[5];
226 cline->region_b[2].c.y = y[5];
227 cline->region_b[3].c.x = x[4];
228 cline->region_b[3].c.y = y[4];
229
230 /* calcurate boundary rectangle */
231 cline->xmax = cline->xmin = x[0];
232 cline->ymax = cline->ymin = y[0];
233 for (k=1; k<6; k++) {
234 if (cline->xmax < x[k]) {
235 cline->xmax = x[k];
236 }
237 if (cline->xmin > x[k]) {
238 cline->xmin = x[k];
239 }
240 if (cline->ymax < y[k]) {
241 cline->ymax = y[k];
242 }
243 if (cline->ymin > y[k]) {
244 cline->ymin = y[k];
245 }
246 }
247
248 /* rotate 90 degree */
249 for (k=0; k<4; k++) {
250 gr_vertex_sub_xy (cline->rot_a+k,
251 cline->region_a + (k+1) % 4,
252 cline->region_a + k);
253 f = cline->rot_a[k].c.x;
254 cline->rot_a[k].c.x = - cline->rot_a[k].c.y;
255 cline->rot_a[k].c.y = f;
256
257 gr_vertex_sub_xy (cline->rot_b+k,
258 cline->region_b + (k+1) % 4,
259 cline->region_b + k);
260 f = cline->rot_b[k].c.x;
261 cline->rot_b[k].c.x = - cline->rot_b[k].c.y;
262 cline->rot_b[k].c.y = f;
263 }
264 }
265
266 break;
267
268 case TOKEN_NUM_MAT:
269 next_word (data, &i);
270 sscanf (data+i, "%d", &course->num_mats);
271 course->mats = gr_new (GrCMaterial, course->num_mats);
272 next_line (data, &i);
273 for (j=0; j<course->num_mats; j++) {
274 sscanf (data+i, "MAT %d %f %f %f",
275 &course->mats[j].flag,
276 &course->mats[j].friction,
277 &course->mats[j].exp,
278 &course->mats[j].mu);
279 next_line (data, &i);
280 }
281 break;
282
283 case TOKEN_NUM_SEG:
284 next_word (data, &i);
285 sscanf (data+i, "%d", &course->num_segs);
286 course->segs = gr_new (GrCSegment *, course->num_segs);
287 next_line (data, &i);
288 for (j=0; j<course->num_mats; j++) {
289 course->segs[j] = read_segment (course, data, &i);
290 }
291 break;
292 }
293 }
294
295 for (i=0; i<course->num_segs; i++) {
296 initialize_surface (course->segs[i]);
297 create_boundary (course->segs[i]);
298 }
299
300 return course;
301
302 ERROR:
303 if (course) {
304 gr_DECREF (course);
305 }
306 return NULL;
307 }
308
309
310 static GrCSurface *
gr_course_find_seg_surface(GrCourse * course,float x,float y,int segment_cur)311 gr_course_find_seg_surface (GrCourse *course,
312 float x, float y,
313 int segment_cur)
314 {
315 GrSList *list;
316 GrBoundary *yboundary;
317 GrCSegment *seg;
318 int i, j;
319 GrCSurface *surf;
320 GrVertex v;
321
322 v.c.x = x;
323 v.c.y = y;
324
325 seg = course->segs[segment_cur];
326
327 for (i=100; i>0; i--) {
328 yboundary = (GrBoundary *) gr_boundary_check (seg->boundary, x, &i);
329 if (!yboundary)
330 return NULL;
331
332 for (j=100; j>0; j--) {
333 list = (GrSList *) gr_boundary_check (yboundary, y, &j);
334
335 if (!list)
336 break;
337
338 while (list) {
339 surf = (GrCSurface *) list->data;
340
341 if (gr_vertex_check_inner_xy (&v, 3, surf->v))
342 return surf;
343
344 list = list->next;
345 }
346 }
347 }
348
349 return NULL;
350 }
351
352 GrCSurface*
gr_course_find_surface(GrCourse * course,float x,float y,int segment_cur,int * segment_ret)353 gr_course_find_surface (GrCourse *course,
354 float x, float y,
355 int segment_cur,
356 int *segment_ret)
357 {
358 GrCSurface *surf;
359 int seg;
360 int i;
361
362 if (course == NULL)
363 return NULL;
364
365 surf = gr_course_find_seg_surface (course, x, y, segment_cur);
366 if (surf) {
367 *segment_ret = segment_cur;
368 return surf;
369 }
370 for (i=1; i<course->num_segs/2; i++) {
371 seg = (segment_cur + i) % course->num_segs;
372 surf = gr_course_find_seg_surface (course, x, y, seg);
373 if (surf) {
374 *segment_ret = seg;
375 return surf;
376 }
377 seg = (segment_cur - i) % course->num_segs;
378 surf = gr_course_find_seg_surface (course, x, y, seg);
379 if (surf) {
380 *segment_ret = seg;
381 return surf;
382 }
383 }
384
385 return NULL;
386 }
387
388 void
gr_course_write_file(GrCourse * course,FILE * file)389 gr_course_write_file (GrCourse *course, FILE *file)
390 {
391 int i, j;
392 GrControlLine *cline;
393
394 fputs ("GRACER COURSE/1.0\n", file);
395
396 fputs ("TITLE ", file);
397 put_name (course->title, file);
398 fputc('\n', file);
399
400 fputs ("DESC ", file);
401 put_name (course->desc, file);
402 fputc('\n', file);
403
404 fputs ("MODEL ", file);
405 put_name (course->model, file);
406 fputc('\n', file);
407
408 fputs ("TIMESTAMP ", file);
409 put_name (course->timestamp, file);
410 fputc('\n', file);
411
412 fprintf (file, "NUM_GRID %d\n", course->num_grids);
413 for (i=0; i<course->num_grids; i++) {
414 fprintf (file, "GRID %d %d %f %f %f\n",
415 course->grids[i].flag,
416 course->grids[i].segment,
417 course->grids[i].x,
418 course->grids[i].y,
419 course->grids[i].dir);
420 }
421 fprintf (file, "NUM_CLINE %d\n", course->num_clines);
422 for (i=0; i<course->num_clines; i++) {
423 cline = course->clines + i;
424
425 fprintf (file, "CLINE %d %d\n", cline->flag, cline->segment);
426 fprintf (file, "%f %f\n", cline->region_a[0].c.x, cline->region_a[0].c.y);
427 fprintf (file, "%f %f\n", cline->region_a[1].c.x, cline->region_a[1].c.y);
428 fprintf (file, "%f %f\n", cline->region_a[3].c.x, cline->region_a[3].c.y);
429 fprintf (file, "%f %f\n", cline->region_a[2].c.x, cline->region_a[2].c.y);
430 fprintf (file, "%f %f\n", cline->region_b[3].c.x, cline->region_b[3].c.y);
431 fprintf (file, "%f %f\n", cline->region_b[2].c.x, cline->region_b[2].c.y);
432 }
433 fprintf (file, "NUM_MAT %d\n", course->num_mats);
434 for (i=0; i<course->num_mats; i++) {
435 fprintf (file, "MAT %d %f %f %f\n",
436 course->mats[i].flag,
437 course->mats[i].friction,
438 course->mats[i].exp,
439 course->mats[i].mu);
440 }
441 fprintf (file, "NUM_SEG %d\n", course->num_segs);
442 for (i=0; i<course->num_segs; i++) {
443 fprintf (file, "SEG %d %f %f %f %f %f %f\n",
444 course->segs[i]->flag,
445 course->segs[i]->max.c.x,
446 course->segs[i]->min.c.x,
447 course->segs[i]->max.c.y,
448 course->segs[i]->min.c.y,
449 course->segs[i]->max.c.z,
450 course->segs[i]->min.c.z);
451 fprintf (file, "NUM_VERT %d\n", course->segs[i]->num_verts);
452 for (j=0; j<course->segs[i]->num_verts; j++) {
453 fprintf (file, "%f %f %f\n",
454 course->segs[i]->verts[j].c.x,
455 course->segs[i]->verts[j].c.y,
456 course->segs[i]->verts[j].c.z);
457 }
458 fprintf (file, "NUM_SURF %d\n", course->segs[i]->num_surfs);
459 for (j=0; j<course->segs[i]->num_surfs; j++) {
460 fprintf (file, "%d %d %d %d %d\n",
461 course->segs[i]->surfs[j].flag,
462 course->segs[i]->surfs[j].mat,
463 course->segs[i]->surfs[j].p[0],
464 course->segs[i]->surfs[j].p[1],
465 course->segs[i]->surfs[j].p[2]);
466 }
467 }
468 }
469
470 static int
find_token(char * data,int * index)471 find_token (char *data, int *index)
472 {
473 int i;
474 int j;
475 char c;
476
477 i = next_word (data, index);
478
479 if (data[i] != '\0') {
480 for (j=0; tokens[j].str != NULL; j++) {
481 if (!strncmp (data+i, tokens[j].str, tokens[j].len) &&
482 (c = data[i+tokens[j].len],
483 c == ' ' || c == '\t' || c == '\n' || c == '\0'))
484 {
485 i += tokens[j].len;
486 *index = i;
487 return tokens[j].type;
488 }
489 }
490 }
491
492 return TOKEN_INVALID;
493 }
494
495 static int
next_line(char * data,int * index)496 next_line (char *data, int *index)
497 {
498 int i = *index;
499
500 for (; data[i] != '\0' && data[i] != '\n'; i++) {}
501 if (data[i] != 0) {
502 i++;
503 }
504 *index = i;
505
506 return i;
507 }
508
509
510 static int
next_word(char * data,int * index)511 next_word (char *data, int *index)
512 {
513 int i = *index;
514
515 while (data[i] == ' ' || data[i] == '\t' || data[i] == '\n') {
516 i++;
517 }
518
519 *index = i;
520
521 return i;
522 }
523
524 static char *
get_name(char * data,int * index)525 get_name (char *data, int *index)
526 {
527 char *name = NULL;
528 char *tmp;
529 int i = *index;
530 int len;
531
532 if (data[i] == '"') {
533 i++;
534 tmp = strchr (data+i, '"');
535 len = tmp - (data + i);
536 if (len > 0) {
537 name = gr_new (char, len+1);
538 strncpy (name, data+i, len);
539 name[len] = '\0';
540 }
541 i += len + 1;
542 } else {
543 tmp = strpbrk (data+i, " \t");
544 len = tmp - (data + i);
545 name = gr_new (char, len+1);
546 strncpy (name, data+i, len);
547 name[len] = '\0';
548 i += len;
549 }
550
551 *index = i;
552 return name;
553 }
554
555 static GrCSegment *
read_segment(GrCourse * course,char * data,int * i)556 read_segment (GrCourse *course, char *data, int *i)
557 {
558 GrCSegment *seg;
559 int j;
560
561 seg = gr_new (GrCSegment, 1);
562 memset (seg, 0, sizeof(GrCSegment));
563
564 sscanf (data+*i, "SEG %d %f %f %f %f %f %f",
565 &seg->flag,
566 &seg->max.c.x, &seg->min.c.x,
567 &seg->max.c.y, &seg->min.c.y,
568 &seg->max.c.z, &seg->min.c.z);
569 next_line (data, i);
570
571 sscanf (data+*i, "NUM_VERT %d", &seg->num_verts);
572 next_line (data, i);
573 seg->verts = gr_new (GrVertex, seg->num_verts);
574 for (j=0; j<seg->num_verts; j++) {
575 sscanf (data+*i, "%f %f %f",
576 &seg->verts[j].c.x, &seg->verts[j].c.y, &seg->verts[j].c.z);
577 next_line (data, i);
578 }
579
580 sscanf (data+*i, "NUM_SURF %d", &seg->num_surfs);
581 next_line (data, i);
582 seg->surfs = gr_new (GrCSurface, seg->num_surfs);
583 for (j=0; j<seg->num_surfs; j++) {
584 sscanf (data+*i, "%d %d %d %d %d",
585 &seg->surfs[j].flag,
586 &seg->surfs[j].mat,
587 &seg->surfs[j].p[0],
588 &seg->surfs[j].p[1],
589 &seg->surfs[j].p[2]);
590 seg->surfs[j].v[0] = seg->verts[seg->surfs[j].p[0]];
591 seg->surfs[j].v[1] = seg->verts[seg->surfs[j].p[1]];
592 seg->surfs[j].v[2] = seg->verts[seg->surfs[j].p[2]];
593 next_line (data, i);
594 }
595
596 return seg;
597 }
598
599 static void
put_name(char * str,FILE * file)600 put_name (char *str, FILE *file)
601 {
602 int i;
603 fputc ('"', file);
604 if (str) {
605 for (i=0; str[i] != '\0'; i++) {
606 if (str[i] == '"' || str[i] == '\\') {
607 fputc ('\\', file);
608 }
609 fputc (str[i], file);
610 }
611 }
612 fputc ('"', file);
613 }
614
615 static void
create_boundary(GrCSegment * seg)616 create_boundary (GrCSegment *seg)
617 {
618 int i, j;
619 float val;
620 float xmx, xmn, ymx, ymn, zmx, zmn;
621 GrSList **list;
622 GrBoundary **b;
623
624 seg->boundary = gr_boundary_new (100, seg->min.c.x - 0.1, seg->max.c.x + 0.1,
625 (GrBoundaryDestroyCB) gr_boundary_free);
626 assert (seg->boundary);
627
628 for (i=0; i<seg->num_surfs; i++) {
629 xmx = xmn = seg->verts[seg->surfs[i].p[0]].c.x;
630 ymx = ymn = seg->verts[seg->surfs[i].p[0]].c.y;
631 zmx = zmn = seg->verts[seg->surfs[i].p[0]].c.z;
632 for (j=1; j<3; j++) {
633 val = seg->verts[seg->surfs[i].p[j]].c.x;
634 if (xmx < val) xmx = val;
635 if (xmn > val) xmn = val;
636
637 val = seg->verts[seg->surfs[i].p[j]].c.y;
638 if (ymx < val) ymx = val;
639 if (ymn > val) ymn = val;
640
641 val = seg->verts[seg->surfs[i].p[j]].c.z;
642 if (zmx < val) zmx = val;
643 if (zmn > val) zmn = val;
644 }
645
646 b = (GrBoundary **) gr_boundary_register (seg->boundary, xmx, xmn);
647 assert (b);
648
649 if (!(*b)) {
650 *b = gr_boundary_new (100, seg->min.c.y - 0.1, seg->max.c.y + 0.1,
651 (GrBoundaryDestroyCB) gr_boundary_free);
652 assert (*b);
653 }
654
655 b = (GrBoundary **) gr_boundary_register (*b, ymx, ymn);
656 assert (b);
657
658 if (!(*b)) {
659 *b = gr_boundary_new (100, seg->min.c.z - 0.1, seg->max.c.z + 0.1,
660 (GrBoundaryDestroyCB) gr_slist_free);
661 assert (*b);
662 }
663
664 list = (GrSList **) gr_boundary_register (*b, zmn, zmx);
665 assert (list);
666
667 *list = gr_slist_prepend (*list, (void *) i);
668 }
669 }
670
671 static void
initialize_surface(GrCSegment * seg)672 initialize_surface (GrCSegment *seg)
673 {
674 int i, j;
675 GrVertex v[3], tmp;
676 GrCSurface *surf;
677
678 for (i=0; i<seg->num_surfs; i++) {
679 surf = seg->surfs + i;
680
681 v[0] = seg->verts[surf->p[0]];
682 v[1] = seg->verts[surf->p[1]];
683 v[2] = seg->verts[surf->p[2]];
684 gr_plane_init (&surf->plane, v+0, v+1, v+2);
685
686 for (j=0; j<3; j++) {
687 gr_matrix_mult_vertex (&surf->plane.m, v+j, surf->v+j);
688 }
689 for (j=0; j<3; j++) {
690 gr_vertex_sub (&tmp, surf->v+((j+1) % 3), surf->v+j);
691 gr_vertex_cross (surf->rv+j, gr_vertex_unit_z, &tmp);
692 }
693 }
694 }
695
696 int
gr_course_check_control_line(GrCourse * course,GrCLineInfo * cinfo)697 gr_course_check_control_line (GrCourse *course, GrCLineInfo *cinfo)
698 {
699 int i, j;
700 GrVertex v;
701 GrControlLine *cline;
702 float product = 0;
703 GrCLineType new_res;
704
705 if (!course || !cinfo)
706 return 0;
707
708 new_res = (cinfo->res & GR_CLINE_MASK) >> 2;
709
710 for (i=0; i<course->num_clines; i++) {
711 if (cinfo->current.pos.c.x < course->clines[i].xmin ||
712 cinfo->current.pos.c.x > course->clines[i].xmax ||
713 cinfo->current.pos.c.y < course->clines[i].ymin ||
714 cinfo->current.pos.c.y > course->clines[i].ymax)
715 continue;
716
717 cline = course->clines + i;
718
719 /* CHECK REGION A */
720 for (j=0; j<4; j++) {
721 gr_vertex_sub_xy (&v, &cinfo->current.pos, cline->region_a + j);
722 product = gr_vertex_product_xy (&v, cline->rot_a + j);
723 if (product < 0) {
724 break;
725 }
726 }
727 if (j == 4) {
728 cinfo->res = new_res | GR_CLINE_CURRENT_A;
729 cinfo->current.cline = i;
730 return 1;
731 }
732
733 /* CHECK REGION B */
734 for (j=0; j<4; j++) {
735 gr_vertex_sub_xy (&v, &cinfo->current.pos, cline->region_b + j);
736 product = gr_vertex_product_xy (&v, cline->rot_b + j);
737 if (product < 0) {
738 break;
739 }
740 }
741 if (j == 4) {
742 cinfo->res = new_res | GR_CLINE_CURRENT_B;
743 cinfo->current.cline = i;
744
745 if (new_res & GR_CLINE_PREV_A) {
746 /* calc cross ratio */
747
748 gr_vertex_sub_xy (&v, &cinfo->prev.pos, cline->region_b);
749 cinfo->cross_ratio = product
750 / (product - gr_vertex_product_xy (&v, cline->rot_b));
751 }
752
753 return 1;
754 }
755 }
756
757 cinfo->res = new_res | GR_CLINE_CURRENT_C;
758 return 1;
759 }
760
761
762 void
gr_course_foreach_surface(GrCourse * course,GrVertex * center,float r,GrCSurfaceCallback callback,void * data)763 gr_course_foreach_surface (GrCourse *course,
764 GrVertex *center,
765 float r,
766 GrCSurfaceCallback callback,
767 void *data)
768 {
769 GrBoundary *xboundary;
770 GrBoundary *yboundary;
771 GrBoundary *zboundary;
772 GrCSegment *segment;
773 int i, j, k, seg, surf;
774 float xmax, xmin;
775 float ymax, ymin;
776 float zmax, zmin;
777 GrSList *ylist = NULL;
778 GrSList *zlist = NULL;
779 GrSList *list = NULL;
780 GrSList *slist = NULL;
781
782 assert (course);
783 assert (center);
784 assert (callback);
785
786 xmax = center->c.x + r;
787 xmin = center->c.x - r;
788 ymax = center->c.y + r;
789 ymin = center->c.y - r;
790 zmax = center->c.z + r;
791 zmin = center->c.z - r;
792
793 for (seg=0; seg<course->num_segs; seg++) {
794 segment = course->segs[seg];
795 if (xmax < segment->min.c.x || xmin > segment->max.c.x ||
796 ymax < segment->min.c.y || ymin > segment->max.c.y ||
797 zmax < segment->min.c.z || zmin > segment->max.c.z) {
798 continue;
799 }
800 xboundary = segment->boundary;
801
802 for (i=100; i>0; i--) {
803 ylist = gr_boundary_check_region (xboundary, xmin, xmax, &i);
804
805 while (ylist) {
806 yboundary = (GrBoundary *) ylist->data;
807
808 for (j=100; j>0; j--) {
809 zlist = gr_boundary_check_region (yboundary, ymin, ymax, &j);
810
811 while (zlist) {
812 zboundary = (GrBoundary *) zlist->data;
813
814 for (k=100; k>0; k--) {
815 list = gr_boundary_check_region (zboundary, zmin, zmax, &k);
816
817 while (list) {
818 slist = list->data;
819 while (slist) {
820 surf = (int) slist->data;
821
822 if ((*callback) (course, seg, surf, data)) {
823 goto FINISH;
824 }
825 slist = slist->next;
826 }
827
828 list = gr_slist_remove (list);
829 }
830 }
831 zlist = gr_slist_remove (zlist);
832 }
833 }
834 ylist = gr_slist_remove (ylist);
835 }
836 }
837 }
838
839 FINISH:
840 if (list)
841 gr_slist_free (list);
842 if (ylist)
843 gr_slist_free (ylist);
844 if (zlist)
845 gr_slist_free (zlist);
846 }
847
848 void
gr_course_foreach_surface_xy(GrCourse * course,GrVertex * pos,GrCSurfaceXYCallback callback,void * data)849 gr_course_foreach_surface_xy (GrCourse *course,
850 GrVertex *pos,
851 GrCSurfaceXYCallback callback,
852 void *data)
853 {
854 GrBoundary *xboundary;
855 GrBoundary *yboundary;
856 GrBoundary *zboundary;
857 GrCSegment *segment;
858 GrCSurface *surface;
859 int i, j, k, seg, surf;
860 GrSList *list = NULL, *slist;
861 GrVertex cross;
862
863 assert (course);
864 assert (callback);
865
866 for (seg=0; seg<course->num_segs; seg++) {
867 segment = course->segs[seg];
868 if (pos->c.x < segment->min.c.x || pos->c.x > segment->max.c.x ||
869 pos->c.y < segment->min.c.y || pos->c.y > segment->max.c.y) {
870 continue;
871 }
872 xboundary = segment->boundary;
873
874 for (i=100; i>0; i--) {
875 yboundary = gr_boundary_check (xboundary, pos->c.x, &i);
876
877 if (!yboundary)
878 return;
879
880 for (j=100; j>0; j--) {
881 zboundary = gr_boundary_check (yboundary, pos->c.y, &j);
882
883 if (!zboundary)
884 return;
885
886 for (k=100; k>0; k--) {
887 list = gr_boundary_check_region (zboundary,
888 segment->min.c.z,
889 segment->max.c.z, &k);
890
891 while (list) {
892 slist = list->data;
893 while (slist) {
894 surf = (int) slist->data;
895 surface = segment->surfs + surf;
896
897 if (gr_plane_get_crossing (&surface->plane, &cross,
898 pos, gr_vertex_unit_z) &&
899 gr_course_surface_check_inner (surface, &cross)) {
900 if ((*callback) (course, seg, surf, cross.c.z, data)) {
901 goto FINISH;
902 }
903 }
904 slist = slist->next;
905 }
906
907 list = gr_slist_remove (list);
908 }
909 }
910 }
911 }
912 }
913
914 FINISH:
915 if (list)
916 gr_slist_free (list);
917 }
918
919 int
gr_course_surface_check_inner(GrCSurface * surf,GrVertex * p)920 gr_course_surface_check_inner (GrCSurface *surf, GrVertex *p)
921 {
922 int i;
923 GrVertex tmp;
924
925 for (i=0; i<3; i++) {
926 gr_vertex_sub (&tmp, p, surf->v+i);
927 if (gr_vertex_product_xy (&tmp, surf->rv+i) < -0.05)
928 return 0;
929 }
930
931 return 1;
932 }
933
934