]> icculus.org git repositories - btb/d2x.git/blob - main/editor/meddraw.c
fix misleading indentation, add explicit braces, etc
[btb/d2x.git] / main / editor / meddraw.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  *
16  * Med drawing functions.
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "conf.h"
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #ifdef __MSDOS__
29 #include <process.h>
30 #endif
31
32 #include "inferno.h"
33 #include "gr.h"
34 #include "ui.h"
35 #include "editor.h"
36 #include "key.h"
37 #include "mono.h"
38 #include "dxxerror.h"
39 #include "u_mem.h"
40 #include "func.h"
41 #include "texmap.h"
42
43
44 //      Colors used in editor for indicating various kinds of segments.
45 #define SELECT_COLOR            BM_XRGB( 63/2 , 41/2 ,  0/2)
46 #define FOUND_COLOR                     BM_XRGB(  0/2 , 30/2 , 45/2)
47 #define WARNING_COLOR           BM_XRGB( 63/2 ,  0/2 ,  0/2)
48 #define AXIS_COLOR                      BM_XRGB( 63/2 ,  0/2 , 63/2)
49 #define PLAINSEG_COLOR          BM_XRGB( 45/2 , 45/2 , 45/2)
50 #define MARKEDSEG_COLOR BM_XRGB(  0/2 , 63/2 ,  0/2)
51 #define MARKEDSIDE_COLOR        BM_XRGB(  0/2 , 63/2 , 63/2)
52 #define CURSEG_COLOR            BM_XRGB( 63/2 , 63/2 , 63/2)
53 #define CURSIDE_COLOR           BM_XRGB( 63/2 , 63/2 ,  0/2)
54 #define CUREDGE_COLOR           BM_XRGB(  0   , 63/2 ,  0  )
55 #define GROUPSEG_COLOR          BM_XRGB(         0/2 ,  0/2 , 63/2)
56 #define  GROUPSIDE_COLOR        BM_XRGB(        63/2 ,  0/2 , 45/2)
57 #define         GROUP_COLOR                     BM_XRGB(  0/2 , 45/2 ,  0/2)    
58 #define ROBOT_COLOR                     BM_XRGB( 31   ,  0   ,  0  )
59 #define PLAYER_COLOR            BM_XRGB(  0   ,  0   , 31  )
60
61 #define DOUBLE_BUFFER 1
62
63 int     Search_mode=0;                      //if true, searching for segments at given x,y
64 int Search_x,Search_y;
65 int     Automap_test=0;         //      Set to 1 to show wireframe in automap mode.
66
67 void draw_seg_objects(segment *seg)
68 {
69         int objnum;
70
71         for (objnum=seg->objects;objnum!=-1;objnum=Objects[objnum].next) {
72                 object *obj = &Objects[objnum];
73                 g3s_point sphere_point;
74
75                 if ((obj->type==OBJ_PLAYER) && (objnum > 0 ))
76                         gr_setcolor(BM_XRGB( 0,  25, 0  ));
77                 else
78                         gr_setcolor(obj==ConsoleObject?PLAYER_COLOR:ROBOT_COLOR);
79
80                 g3_rotate_point(&sphere_point,&obj->pos);
81
82                 g3_draw_sphere(&sphere_point,obj->size);
83         }
84
85 }
86
87 void draw_line(int pnum0,int pnum1)
88 {
89         g3_draw_line(&Segment_points[pnum0],&Segment_points[pnum1]);
90 }
91
92 // ----------------------------------------------------------------------------
93 void draw_segment(segment *seg)
94 {
95         short   *svp;
96         int     nv;
97         g3s_codes cc;
98
99         if (seg->segnum == -1)          //this segment doesn't exitst
100                 return;
101
102         med_get_vertex_list(seg,&nv,&svp);                              // set nv = number of vertices, svp = pointer to vertex indices
103         cc=rotate_list(nv,svp);
104
105         if (! cc.and) {         //all off screen?
106                 int i;
107
108                 for (i=0;i<4;i++) draw_line(svp[i],svp[i+4]);
109
110                 for (i=0;i<3;i++) {
111                         draw_line(svp[i]  ,svp[i+1]);
112                         draw_line(svp[i+4],svp[i+4+1]);
113                 }
114
115                 draw_line(svp[0],svp[3]);
116                 draw_line(svp[0+4],svp[3+4]);
117
118         }
119
120 }
121
122 //for looking for segment under a mouse click
123 void check_segment(segment *seg)
124 {
125         short   *svp;
126         int     nv;
127         g3s_codes cc;
128
129         med_get_vertex_list(seg,&nv,&svp);                              // set nv = number of vertices, svp = pointer to vertex indices
130         cc=rotate_list(nv,svp);
131
132         if (! cc.and) {         //all off screen?
133                 int fn;
134
135                 gr_setcolor(0);
136                 gr_pixel(Search_x,Search_y);    //set our search pixel to color zero
137                 gr_setcolor(1);                                 //and render in color one
138
139                 for (fn=0;fn<6;fn++) {
140                         g3s_point *vert_list[4];
141                         
142                         vert_list[0] = &Segment_points[seg->verts[Side_to_verts[fn][0]]];
143                         vert_list[1] = &Segment_points[seg->verts[Side_to_verts[fn][1]]];
144                         vert_list[2] = &Segment_points[seg->verts[Side_to_verts[fn][2]]];
145                         g3_check_and_draw_poly(3,vert_list,NULL,NULL);
146
147                         vert_list[1] = &Segment_points[seg->verts[Side_to_verts[fn][2]]];
148                         vert_list[2] = &Segment_points[seg->verts[Side_to_verts[fn][3]]];
149                         g3_check_and_draw_poly(3,vert_list,NULL,NULL);
150
151                 }
152
153                 if (gr_ugpixel(&grd_curcanv->cv_bitmap,Search_x,Search_y) == 1)
154                  {
155                         if (N_found_segs < MAX_FOUND_SEGS)
156                                 Found_segs[N_found_segs++] = SEG_PTR_2_NUM(seg);
157                         else
158                                 Warning("Found too many segs! (limit=%d)",MAX_FOUND_SEGS);
159                  }
160         }
161 }
162
163 // ----------------------------------------------------------------------------
164 void draw_seg_side(segment *seg,int side)
165 {
166         short   *svp;
167         int     nv;
168         g3s_codes cc;
169
170         med_get_vertex_list(seg,&nv,&svp);                              // set nv = number of vertices, svp = pointer to vertex indices
171         cc=rotate_list(nv,svp);
172
173         if (! cc.and) {         //all off screen?
174                 int i;
175
176                 for (i=0;i<3;i++)
177                         draw_line(svp[Side_to_verts[side][i]],svp[Side_to_verts[side][i+1]]);
178
179                 draw_line(svp[Side_to_verts[side][i]],svp[Side_to_verts[side][0]]);
180
181         }
182 }
183
184 void draw_side_edge(segment *seg,int side,int edge)
185 {
186         short   *svp;
187         int     nv;
188         g3s_codes cc;
189
190         med_get_vertex_list(seg,&nv,&svp);                              // set nv = number of vertices, svp = pointer to vertex indices
191         cc=rotate_list(nv,svp);
192
193         if (! cc.and)           //on screen?
194                 draw_line(svp[Side_to_verts[side][edge]],svp[Side_to_verts[side][(edge+1)%4]]);
195 }
196
197 int Show_triangulations=0;
198
199 //edge types - lower number types have precedence
200 #define ET_FACING               0       //this edge on a facing face
201 #define ET_NOTFACING    1       //this edge on a non-facing face
202 #define ET_NOTUSED      2       //no face uses this edge
203 #define ET_NOTEXTANT    3       //would exist if side were triangulated 
204
205 #define ET_EMPTY                255     //this entry in array is empty
206
207 //colors for those types
208 //int edge_colors[] = {BM_RGB(45/2,45/2,45/2),
209 //                                                      BM_RGB(45/3,45/3,45/3),         //BM_RGB(0,0,45),       //
210 //                                                      BM_RGB(45/4,45/4,45/4)};        //BM_RGB(0,45,0)};      //
211
212 int edge_colors[] = { 54, 59, 64 };
213                                                         
214
215 typedef struct seg_edge {
216         union {
217                 struct {short v0,v1;} __pack__ n;
218                 long vv;
219         }v;
220         ushort  type;
221         ubyte           face_count, backface_count;
222 } seg_edge;
223
224 #define MAX_EDGES (MAX_VERTICES*4)
225
226 seg_edge edge_list[MAX_EDGES];
227
228 short   used_list[MAX_EDGES];   //which entries in edge_list have been used
229 int n_used;
230
231 int edge_list_size;             //set each frame
232
233 #define HASH(a,b)  ((a*5+b) % edge_list_size)
234
235 //define edge numberings
236 short edges[] = {
237                 0*8+1,  // edge  0
238                 0*8+3,  // edge  1
239                 0*8+4,  // edge  2
240                 1*8+2,  // edge  3
241                 1*8+5,  //      edge  4
242                 2*8+3,  //      edge  5
243                 2*8+6,  //      edge  6
244                 3*8+7,  //      edge  7
245                 4*8+5,  //      edge  8
246                 4*8+7,  //      edge  9
247                 5*8+6,  //      edge 10
248                 6*8+7,  //      edge 11
249
250                 0*8+5,  //      right cross
251                 0*8+7,  // top cross
252                 1*8+3,  //      front  cross
253                 2*8+5,  // bottom cross
254                 2*8+7,  // left cross
255                 4*8+6,  //      back cross
256
257 //crosses going the other way
258
259                 1*8+4,  //      other right cross
260                 3*8+4,  // other top cross
261                 0*8+2,  //      other front  cross
262                 1*8+6,  // other bottom cross
263                 3*8+6,  // other left cross
264                 5*8+7,  //      other back cross
265 };
266
267 #define N_NORMAL_EDGES                  12              //the normal edges of a box
268 #define N_EXTRA_EDGES                   12              //ones created by triangulation
269 #define N_EDGES_PER_SEGMENT (N_NORMAL_EDGES+N_EXTRA_EDGES)
270
271 #define swap(a,b) do {int t; t=(a); (a)=(b); (b)=t;} while (0)
272
273 //given two vertex numbers on a segment (range 0..7), tell what edge number it is
274 int find_edge_num(int v0,int v1)
275 {
276         int             i;
277         short           vv;
278         short           *edgep = edges;
279
280         if (v0 > v1) swap(v0,v1);
281
282         vv = v0*8+v1;
283
284 //      for (i=0;i<N_EDGES_PER_SEGMENT;i++)
285 //              if (edges[i]==vv) return i;
286
287         for (i=N_EDGES_PER_SEGMENT; i; i--)
288                 if (*edgep++ == vv)
289                         return (N_EDGES_PER_SEGMENT-i);
290
291         Error("couldn't find edge for %d,%d",v0,v1);
292
293         //return -1;
294 }
295
296
297 //finds edge, filling in edge_ptr. if found old edge, returns index, else return -1
298 int find_edge(int v0,int v1,seg_edge **edge_ptr)
299 {
300         long vv;
301         short hash,oldhash;
302         int ret;
303
304         vv = (v1<<16) + v0;
305
306         oldhash = hash = HASH(v0,v1);
307
308         ret = -1;
309
310         while (ret==-1) {
311
312                 if (edge_list[hash].type == ET_EMPTY) ret=0;
313                 else if (edge_list[hash].v.vv == vv) ret=1;
314                 else {
315                         if (++hash==edge_list_size) hash=0;
316                         if (hash==oldhash) Error("Edge list full!");
317                 }
318         }
319
320         *edge_ptr = &edge_list[hash];
321
322         if (ret == 0)
323                 return -1;
324         else
325                 return hash;
326
327 }
328
329 //adds an edge to the edge list
330 void add_edge(int v0,int v1,ubyte type)
331 {
332         int found;
333
334         seg_edge *e;
335
336 //mprintf(0, "Verts = %2i %2i, type = %i ", v0, v1, type);
337         if (v0 > v1) swap(v0,v1);
338
339         found = find_edge(v0,v1,&e);
340
341         if (found == -1) {
342                 e->v.n.v0 = v0;
343                 e->v.n.v1 = v1;
344                 e->type = type;
345                 used_list[n_used] = e-edge_list;
346                 if (type == ET_FACING)
347                         edge_list[used_list[n_used]].face_count++;
348                 else if (type == ET_NOTFACING)
349                         edge_list[used_list[n_used]].backface_count++;
350 //mprintf(0, "Facing count = %i, Not facing count = %i\n", edge_list[used_list[n_used]].face_count, edge_list[used_list[n_used]].backface_count);
351                 n_used++;
352         } else {
353                 if (type < e->type)
354                         e->type = type;
355                 if (type == ET_FACING)
356                         edge_list[found].face_count++;
357                 else if (type == ET_NOTFACING)
358                         edge_list[found].backface_count++;
359 //mprintf(0, "Facing count = %i, Not facing count = %i\n", edge_list[found].face_count, edge_list[found].backface_count);
360         }
361 }
362
363 //adds a segment's edges to the edge list
364 void add_edges(segment *seg)
365 {
366         short   *svp;
367         int     nv;
368         g3s_codes cc;
369
370         med_get_vertex_list(seg,&nv,&svp);                              // set nv = number of vertices, svp = pointer to vertex indices
371         cc=rotate_list(nv,svp);
372
373         if (! cc.and) {         //all off screen?
374                 int     i,sn,fn,vn;
375                 int     flag;
376                 ubyte   edge_flags[N_EDGES_PER_SEGMENT];
377
378                 for (i=0;i<N_NORMAL_EDGES;i++) edge_flags[i]=ET_NOTUSED;
379                 for (;i<N_EDGES_PER_SEGMENT;i++) edge_flags[i]=ET_NOTEXTANT;
380
381                 for (sn=0;sn<MAX_SIDES_PER_SEGMENT;sn++) {
382                         side    *sidep = &seg->sides[sn];
383                         int     num_faces, num_vertices;
384                         int     vertex_list[6];
385
386                         create_all_vertex_lists(&num_faces, vertex_list, SEGMENT_NUMBER(seg), sn);
387                         if (num_faces == 1)
388                                 num_vertices = 4;
389                         else
390                                 num_vertices = 3;
391
392                         for (fn=0; fn<num_faces; fn++) {
393                                 int     en;
394                                 int     *v0;
395
396                                 //Note: normal check appears to be the wrong way since the normals points in, but we're looking from the outside
397                                 if (g3_check_normal_facing(&Vertices[seg->verts[vertex_list[fn*3]]],&sidep->normals[fn]))
398                                         flag = ET_NOTFACING;
399                                 else
400                                         flag = ET_FACING;
401
402                                 v0 = &vertex_list[fn*3];
403
404                                 for (vn=0; vn<num_vertices-1; vn++) {
405
406                                         // en = find_edge_num(vertex_list[fn*3 + vn], vertex_list[fn*3 + (vn+1)%num_vertices]);
407                                         en = find_edge_num(*v0, *(v0+1));
408                                         
409                                         if (en!=-1)
410                                                 if (flag < edge_flags[en]) edge_flags[en] = flag;
411
412                                         v0++;
413                                 }
414                                 en = find_edge_num(*v0, vertex_list[fn*3]);
415                                 if (en!=-1)
416                                         if (flag < edge_flags[en]) edge_flags[en] = flag;
417                         }
418                 }
419
420                 for (i=0; i<N_EDGES_PER_SEGMENT; i++)
421                         if (i<N_NORMAL_EDGES || (edge_flags[i]!=ET_NOTEXTANT && Show_triangulations))
422                                 add_edge(seg->verts[edges[i]/8],seg->verts[edges[i]&7],edge_flags[i]);
423                 
424
425         }
426 }
427
428 // ----------------------------------------------------------------------------
429 void draw_trigger_side(segment *seg,int side)
430 {
431         short   *svp;
432         int     nv;
433         g3s_codes cc;
434
435         med_get_vertex_list(seg,&nv,&svp);                              // set nv = number of vertices, svp = pointer to vertex indices
436         cc=rotate_list(nv,svp);
437
438         if (! cc.and) {         //all off screen?
439                 // Draw diagonals
440                 draw_line(svp[Side_to_verts[side][0]],svp[Side_to_verts[side][2]]);
441                 //g3_draw_line(svp[Side_to_verts[side][1]],svp[Side_to_verts[side][3]]);
442         }
443 }
444
445 // ----------------------------------------------------------------------------
446 void draw_wall_side(segment *seg,int side)
447 {
448         short   *svp;
449         int     nv;
450         g3s_codes cc;
451
452         med_get_vertex_list(seg,&nv,&svp);                              // set nv = number of vertices, svp = pointer to vertex indices
453         cc=rotate_list(nv,svp);
454
455         if (! cc.and) {         //all off screen?
456                 // Draw diagonals
457                 draw_line(svp[Side_to_verts[side][0]],svp[Side_to_verts[side][2]]);
458                 draw_line(svp[Side_to_verts[side][1]],svp[Side_to_verts[side][3]]);
459
460         }
461 }
462
463 #define WALL_BLASTABLE_COLOR                            BM_XRGB( 31/2 ,  0/2 ,  0/2)  // RED
464 #define WALL_DOOR_COLOR                                 BM_XRGB(  0/2 ,  0/2 , 31/2)    // DARK BLUE
465 #define WALL_DOOR_LOCKED_COLOR                  BM_XRGB(  0/2 ,  0/2 , 63/2)    // BLUE
466 #define WALL_AUTO_DOOR_COLOR                            BM_XRGB(  0/2 , 31/2 ,  0/2)    //      DARK GREEN
467 #define WALL_AUTO_DOOR_LOCKED_COLOR     BM_XRGB(  0/2 , 63/2 ,  0/2)    // GREEN
468 #define WALL_ILLUSION_COLOR                             BM_XRGB( 63/2 ,  0/2 , 63/2)    // PURPLE
469
470 #define TRIGGER_COLOR                                           BM_XRGB( 63/2 , 63/2 ,  0/2)    // YELLOW
471 #define TRIGGER_DAMAGE_COLOR                            BM_XRGB( 63/2 , 63/2 ,  0/2)    // YELLOW
472
473 // ----------------------------------------------------------------------------------------------------------------
474 // Draws special walls (for now these are just removable walls.)
475 void draw_special_wall( segment *seg, int side )
476 {
477         gr_setcolor(PLAINSEG_COLOR);
478
479         if (Walls[seg->sides[side].wall_num].type == WALL_BLASTABLE)
480                 gr_setcolor(WALL_BLASTABLE_COLOR);      
481         if (Walls[seg->sides[side].wall_num].type == WALL_DOOR)
482                 gr_setcolor(WALL_DOOR_COLOR);
483         if (Walls[seg->sides[side].wall_num].type == WALL_ILLUSION)
484                 gr_setcolor(GROUPSIDE_COLOR);   
485         if (Walls[seg->sides[side].wall_num].flags & WALL_DOOR_LOCKED)
486                 gr_setcolor(WALL_DOOR_LOCKED_COLOR);
487         if (Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO)
488                 gr_setcolor(WALL_AUTO_DOOR_COLOR);
489         if (Walls[seg->sides[side].wall_num].flags & WALL_DOOR_LOCKED)
490         if (Walls[seg->sides[side].wall_num].flags & WALL_DOOR_AUTO)
491                 gr_setcolor(WALL_AUTO_DOOR_LOCKED_COLOR);
492         if (Walls[seg->sides[side].wall_num].type == WALL_OPEN)
493                 gr_setcolor(PLAINSEG_COLOR);
494         
495         draw_wall_side(seg,side);
496
497         if (Walls[seg->sides[side].wall_num].trigger != -1) {
498                 int trigger_num;
499
500                 trigger_num = Walls[seg->sides[side].wall_num].trigger;
501
502                 gr_setcolor(TRIGGER_COLOR);
503                 draw_trigger_side(seg,side);
504                 }
505
506
507         gr_setcolor(PLAINSEG_COLOR);
508 }
509
510
511 // ----------------------------------------------------------------------------------------------------------------
512 // Recursively parse mine structure, drawing segments.
513 void draw_mine_sub(int segnum,int depth)
514 {
515         segment *mine_ptr;
516
517         if (Been_visited[segnum]) return;               // If segment already drawn, return.
518
519         Been_visited[segnum] = 1;               // Say that this segment has been drawn.
520
521         mine_ptr = &Segments[segnum];
522
523         // If this segment is active, process it, else skip it.
524
525         if (mine_ptr->segnum != -1) {
526                 int     side;
527
528                 if (Search_mode) check_segment(mine_ptr);
529                 else add_edges(mine_ptr);       //add this segments edges to list
530
531                 if (depth != 0) {
532                         for (side=0; side<MAX_SIDES_PER_SEGMENT; side++) {
533                                 if (IS_CHILD(mine_ptr->children[side])) {
534                                         if (mine_ptr->sides[side].wall_num != -1)
535                                                 draw_special_wall(mine_ptr, side);
536                                         draw_mine_sub(mine_ptr->children[side],depth-1);
537                                 }
538                         }
539                 }
540         }
541 }
542
543 void draw_mine_edges(int automap_flag)
544 {
545         int i,type;
546         seg_edge *e;
547
548         for (type=ET_NOTUSED;type>=ET_FACING;type--) {
549                 gr_setcolor(edge_colors[type]);
550                 for (i=0;i<n_used;i++) {
551                         e = &edge_list[used_list[i]];
552                         if (e->type == type)
553                                 if ((!automap_flag) || (e->face_count == 1))
554                                         draw_line(e->v.n.v0,e->v.n.v1);
555                 }
556         }
557 }
558
559 //draws an entire mine
560 void draw_mine(segment *mine_ptr,int depth)
561 {
562         int     i;
563
564         // clear visited list
565         for (i=0; i<=Highest_segment_index; i++)
566                 Been_visited[i] = 0;
567
568         edge_list_size = min(Num_vertices*4,MAX_EDGES);         //make maybe smaller than max
569
570         // clear edge list
571         for (i=0; i<edge_list_size; i++) {
572                 edge_list[i].type = ET_EMPTY;
573                 edge_list[i].face_count = 0;
574                 edge_list[i].backface_count = 0;
575         }
576
577         n_used = 0;
578
579         draw_mine_sub(SEG_PTR_2_NUM(mine_ptr),depth);
580
581         draw_mine_edges(0);
582
583 }
584
585 // -----------------------------------------------------------------------------
586 //      Draw all segments, ignoring connectivity.
587 //      A segment is drawn if its segnum != -1.
588 void draw_mine_all(segment *sp, int automap_flag)
589 {
590         int     s;
591         int     i;
592
593         // clear visited list
594         for (i=0; i<=Highest_segment_index; i++)
595                 Been_visited[i] = 0;
596
597         edge_list_size = min(Num_vertices*4,MAX_EDGES);         //make maybe smaller than max
598
599         // clear edge list
600         for (i=0; i<edge_list_size; i++) {
601                 edge_list[i].type = ET_EMPTY;
602                 edge_list[i].face_count = 0;
603                 edge_list[i].backface_count = 0;
604         }
605
606         n_used = 0;
607
608         for (s=0; s<=Highest_segment_index; s++)
609                 if (sp[s].segnum != -1) {
610                         for (i=0; i<MAX_SIDES_PER_SEGMENT; i++)
611                                 if (sp[s].sides[i].wall_num != -1)
612                                         draw_special_wall(&sp[s], i);
613                         if (Search_mode)
614                                 check_segment(&sp[s]);
615                         else {
616                                 add_edges(&sp[s]);
617                                 draw_seg_objects(&sp[s]);
618                         }
619                 }
620
621         draw_mine_edges(automap_flag);
622
623 }
624
625 void draw_selected_segments(void)
626 {
627         int     s;
628
629         gr_setcolor(SELECT_COLOR);
630         for (s=0; s<N_selected_segs; s++)
631                 if (Segments[Selected_segs[s]].segnum != -1)
632                         draw_segment(&Segments[Selected_segs[s]]);
633 }
634
635 void draw_found_segments(void)
636 {
637         int     s;
638
639         gr_setcolor(FOUND_COLOR);
640         for (s=0; s<N_found_segs; s++)
641                 if (Segments[Found_segs[s]].segnum != -1)
642                         draw_segment(&Segments[Found_segs[s]]);
643 }
644
645 void draw_warning_segments(void)
646 {
647         int     s;
648
649         gr_setcolor(WARNING_COLOR);
650         for (s=0; s<N_warning_segs; s++)
651                 if (Segments[Warning_segs[s]].segnum != -1)
652                         draw_segment(&Segments[Warning_segs[s]]);
653 }
654
655 void draw_group_segments(void)
656 {
657         int     s;
658
659         if (current_group > -1) {
660                 gr_setcolor(GROUP_COLOR);
661                 for (s=0; s<GroupList[current_group].num_segments; s++)
662                         if (Segments[GroupList[current_group].segments[s]].segnum != -1)
663                                 draw_segment(&Segments[GroupList[current_group].segments[s]]);
664                 }
665 }
666
667
668 void draw_special_segments(void)
669 {
670         short seg;
671         ubyte color;
672
673         // Highlight matcens, fuelcens, etc.
674         for (seg=0;seg<=Highest_segment_index;seg++)
675                 if (Segments[seg].segnum != -1)
676                         switch(Segment2s[seg].special)
677                         {
678                         case SEGMENT_IS_FUELCEN:
679                                 color = BM_XRGB( 29, 27, 13 );
680                                 gr_setcolor(color);
681                                 draw_segment(&Segments[seg]);
682                                 break;
683                         case SEGMENT_IS_CONTROLCEN:
684                                 color = BM_XRGB( 29, 0, 0 );
685                                 gr_setcolor(color);
686                                 draw_segment(&Segments[seg]);
687                                 break;
688                         case SEGMENT_IS_ROBOTMAKER:
689                                 color = BM_XRGB( 29, 0, 31 );
690                                 gr_setcolor(color);
691                                 draw_segment(&Segments[seg]);
692                                 break;
693                         }
694 }
695                 
696
697 //find a free vertex. returns the vertex number
698 int alloc_vert()
699 {
700         int vn;
701
702         Assert(Num_vertices < MAX_SEGMENT_VERTICES);
703
704         for (vn=0; (vn < Num_vertices) && Vertex_active[vn]; vn++) ;
705
706         Vertex_active[vn] = 1;
707
708         Num_vertices++;
709
710         return vn;
711 }
712
713 //frees a vertex
714 void free_vert(int vert_num)
715 {
716         Vertex_active[vert_num] = 0;
717         Num_vertices--;
718 }
719
720 // -----------------------------------------------------------------------------
721 void draw_coordinate_axes(void)
722 {
723         int                     i;
724         short                   Axes_verts[16];
725         vms_vector      tvec,xvec,yvec,zvec;
726
727         for (i=0; i<16; i++)
728                 Axes_verts[i] = alloc_vert();
729
730         create_coordinate_axes_from_segment(Cursegp,Axes_verts);
731
732         vm_vec_sub(&xvec,&Vertices[Axes_verts[1]],&Vertices[Axes_verts[0]]);
733         vm_vec_sub(&yvec,&Vertices[Axes_verts[2]],&Vertices[Axes_verts[0]]);
734         vm_vec_sub(&zvec,&Vertices[Axes_verts[3]],&Vertices[Axes_verts[0]]);
735
736         // Create the letter X
737         tvec = xvec;
738         vm_vec_add(&Vertices[Axes_verts[4]],&Vertices[Axes_verts[1]],vm_vec_scale(&tvec,F1_0/16));
739         tvec = yvec;
740         vm_vec_add2(&Vertices[Axes_verts[4]],vm_vec_scale(&tvec,F1_0/8));
741         vm_vec_sub(&Vertices[Axes_verts[6]],&Vertices[Axes_verts[4]],vm_vec_scale(&tvec,F2_0));
742         tvec = xvec;    vm_vec_scale(&tvec,F1_0/8);
743         vm_vec_add(&Vertices[Axes_verts[7]],&Vertices[Axes_verts[4]],&tvec);
744         vm_vec_add(&Vertices[Axes_verts[5]],&Vertices[Axes_verts[6]],&tvec);
745
746         //      Create the letter Y
747         tvec = yvec;
748         vm_vec_add(&Vertices[Axes_verts[11]],&Vertices[Axes_verts[2]],vm_vec_scale(&tvec,F1_0/16));
749         vm_vec_add(&Vertices[Axes_verts[8]],&Vertices[Axes_verts[11]],&tvec);
750         vm_vec_add(&Vertices[Axes_verts[9]],&Vertices[Axes_verts[11]],vm_vec_scale(&tvec,F1_0*2));
751         vm_vec_add(&Vertices[Axes_verts[10]],&Vertices[Axes_verts[11]],&tvec);
752         tvec = xvec;    vm_vec_scale(&tvec,F1_0/16);
753         vm_vec_sub2(&Vertices[Axes_verts[9]],&tvec);
754         vm_vec_add2(&Vertices[Axes_verts[10]],&tvec);
755
756         // Create the letter Z
757         tvec = zvec;
758         vm_vec_add(&Vertices[Axes_verts[12]],&Vertices[Axes_verts[3]],vm_vec_scale(&tvec,F1_0/16));
759         tvec = yvec;
760         vm_vec_add2(&Vertices[Axes_verts[12]],vm_vec_scale(&tvec,F1_0/8));
761         vm_vec_sub(&Vertices[Axes_verts[14]],&Vertices[Axes_verts[12]],vm_vec_scale(&tvec,F2_0));
762         tvec = zvec;    vm_vec_scale(&tvec,F1_0/8);
763         vm_vec_add(&Vertices[Axes_verts[13]],&Vertices[Axes_verts[12]],&tvec);
764         vm_vec_add(&Vertices[Axes_verts[15]],&Vertices[Axes_verts[14]],&tvec);
765
766         rotate_list(16,Axes_verts);
767
768         gr_setcolor(AXIS_COLOR);
769
770         draw_line(Axes_verts[0],Axes_verts[1]);
771         draw_line(Axes_verts[0],Axes_verts[2]);
772         draw_line(Axes_verts[0],Axes_verts[3]);
773
774         // draw the letter X
775         draw_line(Axes_verts[4],Axes_verts[5]);
776         draw_line(Axes_verts[6],Axes_verts[7]);
777
778         // draw the letter Y
779         draw_line(Axes_verts[8],Axes_verts[9]);
780         draw_line(Axes_verts[8],Axes_verts[10]);
781         draw_line(Axes_verts[8],Axes_verts[11]);
782
783         // draw the letter Z
784         draw_line(Axes_verts[12],Axes_verts[13]);
785         draw_line(Axes_verts[13],Axes_verts[14]);
786         draw_line(Axes_verts[14],Axes_verts[15]);
787
788         for (i=0; i<16; i++)
789                 free_vert(Axes_verts[i]);
790 }
791
792 void draw_world(grs_canvas *screen_canvas,editor_view *v,segment *mine_ptr,int depth)
793 {
794         vms_vector viewer_position;
795
796 #if DOUBLE_BUFFER
797         grs_canvas temp_canvas;
798
799 //      mprintf(0, "\n");
800
801 //      if ( screen_canvas == LargeViewBox->canvas ) {
802 //              CurrentBigCanvas ^= 1;
803 //
804 //              gr_set_current_canvas( BigCanvas[CurrentBigCanvas] );
805 //
806 //      } else {
807                 gr_init_sub_canvas(&temp_canvas,canv_offscreen,0,0,
808                         screen_canvas->cv_bitmap.bm_w,screen_canvas->cv_bitmap.bm_h);
809
810                 gr_set_current_canvas(&temp_canvas);
811 //      }
812 #else
813         gr_set_current_canvas(screen_canvas);
814 #endif
815
816         //mprintf(0, "\n");
817
818         ui_mouse_hide();
819
820         //g3_set_points(Segment_points,Vertices);
821
822         viewer_position = v->ev_matrix.fvec;
823         vm_vec_scale(&viewer_position,-v->ev_dist);
824
825         vm_vec_add2(&viewer_position,&Ed_view_target);
826
827         gr_clear_canvas(0);
828         g3_start_frame();
829         g3_set_view_matrix(&viewer_position,&v->ev_matrix,v->ev_zoom);
830
831         render_start_frame();
832
833         gr_setcolor(PLAINSEG_COLOR);
834
835         // Draw all segments or only connected segments.
836         // We might want to draw all segments if we have broken the mine into pieces.
837         if (Draw_all_segments)
838                 draw_mine_all(Segments, Automap_test);
839         else
840                 draw_mine(mine_ptr,depth);
841
842         // Draw the found segments
843         if (!Automap_test) {
844                 draw_warning_segments();
845                 draw_group_segments();
846                 draw_found_segments();
847                 draw_selected_segments();
848                 draw_special_segments();
849
850                 // Highlight group segment and side.
851                 if (current_group > -1)
852                 if (Groupsegp[current_group]) {
853                         gr_setcolor(GROUPSEG_COLOR);
854                         draw_segment(Groupsegp[current_group]);
855
856                         gr_setcolor(GROUPSIDE_COLOR);
857                         draw_seg_side(Groupsegp[current_group],Groupside[current_group]);
858                 }
859
860                 // Highlight marked segment and side.
861                 if (Markedsegp) {
862                         gr_setcolor(MARKEDSEG_COLOR);
863                         draw_segment(Markedsegp);
864
865                         gr_setcolor(MARKEDSIDE_COLOR);
866                         draw_seg_side(Markedsegp,Markedside);
867                 }
868
869                 // Highlight current segment and current side.
870                 gr_setcolor(CURSEG_COLOR);
871                 draw_segment(Cursegp);
872
873                 gr_setcolor(CURSIDE_COLOR);
874                 draw_seg_side(Cursegp,Curside);
875
876                 gr_setcolor(CUREDGE_COLOR);
877                 draw_side_edge(Cursegp,Curside,Curedge);
878
879                 // Draw coordinate axes if we are rendering the large view.
880                 if (Show_axes_flag)
881                         if (screen_canvas == LargeViewBox->canvas)
882                                 draw_coordinate_axes();
883
884                 // Label the window
885                 gr_set_fontcolor((v==current_view)?CRED:CWHITE, -1 );
886                 if ( screen_canvas == LargeViewBox->canvas ) {
887                         gr_ustring( 5, 5, "USER VIEW" );
888                         switch (Large_view_index) {
889                                 case 0: gr_ustring( 85, 5, "-- TOP");   break;
890                                 case 1: gr_ustring( 85, 5, "-- FRONT"); break;
891                                 case 2: gr_ustring( 85, 5, "-- RIGHT"); break;
892                         }                       
893                 } else
894 #if ORTHO_VIEWS
895                  else if ( screen_canvas == TopViewBox->canvas )
896                         gr_ustring( 5, 5, "TOP" );
897                 else if ( screen_canvas == FrontViewBox->canvas )
898                         gr_ustring( 5, 5, "FRONT" );
899                 else if ( screen_canvas == RightViewBox->canvas )
900                         gr_ustring( 5, 5, "RIGHT" );
901 #else
902                         Error("Ortho views have been removed, what gives?\n");
903 #endif
904
905         }
906
907         g3_end_frame();
908
909 #if DOUBLE_BUFFER
910 //      if ( screen_canvas == LargeViewBox->canvas ) {
911 //              if (BigCanvasFirstTime) {
912 //                      BigCanvasFirstTime = 0;
913 //                      gr_set_current_canvas( screen_canvas );
914 //                      gr_ubitmap( 0, 0, &BigCanvas[CurrentBigCanvas]->cv_bitmap );
915 //              } else {
916 //                      gr_vesa_update( &BigCanvas[CurrentBigCanvas]->cv_bitmap, &screen_canvas->cv_bitmap, &BigCanvas[CurrentBigCanvas ^ 1]->cv_bitmap );
917 //              }
918 //      } else {
919                 gr_set_current_canvas( screen_canvas );
920                 gr_ubitmap( 0, 0, &temp_canvas.cv_bitmap );
921 //      }
922
923 #endif
924
925         ui_mouse_show();
926
927 }
928
929 //find the segments that render at a given screen x,y
930 //parms other than x,y are like draw_world
931 //fills in globals N_found_segs & Found_segs
932 void find_segments(short x,short y,grs_canvas *screen_canvas,editor_view *v,segment *mine_ptr,int depth)
933 {
934         vms_vector viewer_position;
935
936 #if DOUBLE_BUFFER
937         grs_canvas temp_canvas;
938
939         gr_init_sub_canvas(&temp_canvas,canv_offscreen,0,0,
940                         screen_canvas->cv_bitmap.bm_w,screen_canvas->cv_bitmap.bm_h);
941
942         gr_set_current_canvas(&temp_canvas);
943 #else
944         gr_set_current_canvas(screen_canvas);
945 #endif
946
947         ui_mouse_hide();
948
949         //g3_set_points(Segment_points,Vertices);
950
951         viewer_position = v->ev_matrix.fvec;
952         vm_vec_scale(&viewer_position,-v->ev_dist);
953
954         vm_vec_add(&viewer_position,&viewer_position,&Ed_view_target);
955
956         g3_start_frame();
957         g3_set_view_matrix(&viewer_position,&v->ev_matrix,v->ev_zoom);
958
959         render_start_frame();
960
961         gr_setcolor(0);
962         gr_pixel(x,y);
963         gr_setcolor(1);
964
965         Search_mode = -1;
966         N_found_segs = 0;
967         Search_x = x; Search_y = y;
968
969         if (Draw_all_segments)
970                 draw_mine_all(Segments, 0);
971         else
972                 draw_mine(mine_ptr,depth);
973
974         g3_end_frame();
975
976         Search_mode = 0;
977
978 }
979
980 void meddraw_init_views( grs_canvas * canvas)
981 {
982         Views[0]->ev_canv = canvas;
983 #if ORTHO_VIEWS
984         Views[1]->ev_canv = TopViewBox->canvas;
985         Views[2]->ev_canv = FrontViewBox->canvas;
986         Views[3]->ev_canv = RightViewBox->canvas;
987 #endif
988 }