Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

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