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