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