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