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