dxx-rebirth/similar/editor/meddraw.cpp

933 lines
25 KiB
C++
Raw Normal View History

2006-03-20 17:12:09 +00:00
/*
2014-06-01 17:55:23 +00:00
* Portions of this file are copyright Rebirth contributors and licensed as
* described in COPYING.txt.
* Portions of this file are copyright Parallax Software and licensed
* according to the Parallax license below.
* See COPYING.txt for license details.
2006-03-20 17:12:09 +00:00
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
*/
/*
*
* Med drawing functions.
*
*/
#include <algorithm>
2006-03-20 17:12:09 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "inferno.h"
#include "segment.h"
#include "segpoint.h"
#include "gameseg.h"
#include "gr.h"
#include "ui.h"
#include "editor/editor.h"
2013-03-16 03:10:55 +00:00
#include "editor/esegment.h"
2006-03-20 17:12:09 +00:00
#include "wall.h"
#include "switch.h"
#include "key.h"
#include "mouse.h"
#include "dxxerror.h"
2006-03-20 17:12:09 +00:00
#include "medlisp.h"
#include "u_mem.h"
#include "render.h"
#include "game.h"
#include "kdefs.h"
#include "func.h"
#include "textures.h"
#include "screens.h"
#include "texmap.h"
#include "object.h"
#include "fuelcen.h"
#include "meddraw.h"
2016-12-11 01:56:44 +00:00
#include "d_enumerate.h"
2013-12-21 05:12:38 +00:00
#include "compiler-range_for.h"
#include "segiter.h"
#if DXX_USE_OGL
#include "ogl_init.h"
#endif
using std::min;
2006-03-20 17:12:09 +00:00
// Colors used in editor for indicating various kinds of segments.
#define SELECT_COLOR BM_XRGB( 63/2 , 41/2 , 0/2)
#define FOUND_COLOR BM_XRGB( 0/2 , 30/2 , 45/2)
#define WARNING_COLOR BM_XRGB( 63/2 , 0/2 , 0/2)
#define AXIS_COLOR BM_XRGB( 63/2 , 0/2 , 63/2)
#define PLAINSEG_COLOR BM_XRGB( 45/2 , 45/2 , 45/2)
#define MARKEDSEG_COLOR BM_XRGB( 0/2 , 63/2 , 0/2)
#define MARKEDSIDE_COLOR BM_XRGB( 0/2 , 63/2 , 63/2)
#define CURSEG_COLOR BM_XRGB( 63/2 , 63/2 , 63/2)
#define CURSIDE_COLOR BM_XRGB( 63/2 , 63/2 , 0/2)
#define CUREDGE_COLOR BM_XRGB( 0 , 63/2 , 0 )
#define GROUPSEG_COLOR BM_XRGB( 0/2 , 0/2 , 63/2)
#define GROUPSIDE_COLOR BM_XRGB( 63/2 , 0/2 , 45/2)
#define GROUP_COLOR BM_XRGB( 0/2 , 45/2 , 0/2)
#define ROBOT_COLOR BM_XRGB( 31 , 0 , 0 )
#define PLAYER_COLOR BM_XRGB( 0 , 0 , 31 )
constexpr std::integral_constant<unsigned, MAX_VERTICES * 4> MAX_EDGES{};
2013-06-30 20:59:51 +00:00
static int Search_mode=0; //if true, searching for segments at given x,y
static int Search_x,Search_y;
static int Automap_test=0; // Set to 1 to show wireframe in automap mode.
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:14 +00:00
static void draw_seg_objects(grs_canvas &canvas, const unique_segment &seg)
2006-03-20 17:12:09 +00:00
{
2018-06-24 05:06:14 +00:00
range_for (const auto obj, objects_in(seg, vcobjptridx, vcsegptr))
{
auto sphere_point = g3_rotate_point(obj->pos);
const uint8_t color = (obj->type == OBJ_PLAYER && static_cast<icobjptridx_t::index_type>(obj) > 0)
2016-02-12 04:02:28 +00:00
? BM_XRGB(0, 25, 0)
: (obj == ConsoleObject
? PLAYER_COLOR
: ROBOT_COLOR
);
2018-06-24 05:06:14 +00:00
g3_draw_sphere(canvas, sphere_point, obj->size, color);
2006-03-20 17:12:09 +00:00
}
}
2017-08-26 19:47:51 +00:00
#if DXX_USE_OGL
#define draw_line(C,P0,P1,c) draw_line(P0,P1,c)
2017-08-26 19:47:51 +00:00
#define draw_segment(C,S,c) draw_segment(S,c)
#define draw_listed_segments(C,S,c) draw_listed_segments(S,c)
2017-08-26 19:47:51 +00:00
#endif
static void draw_line(grs_canvas &canvas, const unsigned pnum0, const unsigned pnum1, const uint8_t color)
2006-03-20 17:12:09 +00:00
{
2017-08-26 19:47:51 +00:00
g3_draw_line(canvas, Segment_points[pnum0], Segment_points[pnum1], color);
2006-03-20 17:12:09 +00:00
}
// ----------------------------------------------------------------------------
static void draw_segment(grs_canvas &canvas, const shared_segment &seg, const uint8_t color)
2006-03-20 17:12:09 +00:00
{
if (seg.segnum == segment_none) //this segment doesn't exitst
2006-03-20 17:12:09 +00:00
return;
auto &svp = seg.verts;
2018-12-30 00:43:57 +00:00
auto &Vertices = LevelSharedVertexState.get_vertices();
auto &vcvertptr = Vertices.vcptr;
2018-12-30 00:43:57 +00:00
if (!rotate_list(vcvertptr, svp).uand)
2015-10-18 21:01:18 +00:00
{ //all off screen?
2016-02-12 04:02:28 +00:00
for (unsigned i = 0; i < 4; ++i)
2017-08-26 19:47:51 +00:00
draw_line(canvas, svp[i], svp[i+4], color);
2006-03-20 17:12:09 +00:00
2016-05-21 17:24:51 +00:00
for (unsigned i = 0; i < 3; ++i)
{
2017-08-26 19:47:51 +00:00
draw_line(canvas, svp[i], svp[i+1], color);
draw_line(canvas, svp[i+4], svp[i+4+1], color);
2006-03-20 17:12:09 +00:00
}
2017-08-26 19:47:51 +00:00
draw_line(canvas, svp[0], svp[3], color);
draw_line(canvas, svp[4], svp[3+4], color);
2006-03-20 17:12:09 +00:00
}
}
//for looking for segment under a mouse click
static void check_segment(const vmsegptridx_t seg)
2006-03-20 17:12:09 +00:00
{
2014-08-12 03:01:14 +00:00
auto &svp = seg->verts;
2018-12-30 00:43:57 +00:00
auto &Vertices = LevelSharedVertexState.get_vertices();
auto &vcvertptr = Vertices.vcptr;
2018-12-30 00:43:57 +00:00
if (!rotate_list(vcvertptr, svp).uand)
2015-10-18 21:01:18 +00:00
{ //all off screen?
#if DXX_USE_OGL
g3_end_frame();
#endif
2016-05-21 17:24:51 +00:00
{
2016-02-12 04:02:28 +00:00
uint8_t color = 0;
2017-03-11 19:56:23 +00:00
gr_pixel(grd_curcanv->cv_bitmap, Search_x, Search_y, color); //set our search pixel to color zero
2016-05-21 17:24:51 +00:00
}
#if DXX_USE_OGL
2017-02-11 21:42:34 +00:00
g3_start_frame(*grd_curcanv);
#endif
2016-02-12 04:02:28 +00:00
{
const uint8_t color = 1;
2016-02-12 04:02:28 +00:00
//and render in color one
2006-03-20 17:12:09 +00:00
2015-02-14 22:48:27 +00:00
range_for (auto &fn, Side_to_verts)
{
2014-11-16 19:14:51 +00:00
array<cg3s_point *, 3> vert_list;
2015-02-14 22:48:27 +00:00
vert_list[0] = &Segment_points[seg->verts[fn[0]]];
vert_list[1] = &Segment_points[seg->verts[fn[1]]];
vert_list[2] = &Segment_points[seg->verts[fn[2]]];
2017-02-11 21:42:42 +00:00
g3_check_and_draw_poly(*grd_curcanv, vert_list, color);
2006-03-20 17:12:09 +00:00
2015-02-14 22:48:27 +00:00
vert_list[1] = &Segment_points[seg->verts[fn[2]]];
vert_list[2] = &Segment_points[seg->verts[fn[3]]];
2017-02-11 21:42:42 +00:00
g3_check_and_draw_poly(*grd_curcanv, vert_list, color);
2016-02-12 04:02:28 +00:00
}
2006-03-20 17:12:09 +00:00
}
2014-11-30 22:09:18 +00:00
if (gr_ugpixel(grd_curcanv->cv_bitmap,Search_x,Search_y) == 1)
2006-03-20 17:12:09 +00:00
{
2014-10-02 03:02:34 +00:00
Found_segs.emplace_back(seg);
2006-03-20 17:12:09 +00:00
}
}
}
// ----------------------------------------------------------------------------
2018-12-30 00:43:57 +00:00
static void draw_seg_side(const shared_segment &seg, const unsigned side, const uint8_t color)
2006-03-20 17:12:09 +00:00
{
2018-12-30 00:43:57 +00:00
auto &svp = seg.verts;
auto &Vertices = LevelSharedVertexState.get_vertices();
auto &vcvertptr = Vertices.vcptr;
2018-12-30 00:43:57 +00:00
if (!rotate_list(vcvertptr, svp).uand)
2015-10-18 21:01:18 +00:00
{ //all off screen?
2006-03-20 17:12:09 +00:00
int i;
2016-02-12 04:02:28 +00:00
auto &stv = Side_to_verts[side];
2006-03-20 17:12:09 +00:00
for (i=0;i<3;i++)
2017-08-26 19:47:51 +00:00
draw_line(*grd_curcanv, svp[stv[i]], svp[stv[i+1]], color);
2006-03-20 17:12:09 +00:00
2017-08-26 19:47:51 +00:00
draw_line(*grd_curcanv, svp[stv[i]], svp[stv[0]], color);
2006-03-20 17:12:09 +00:00
}
}
2018-12-30 00:43:57 +00:00
static void draw_side_edge(const shared_segment &seg, const unsigned side, const unsigned edge, const uint8_t color)
2006-03-20 17:12:09 +00:00
{
2018-12-30 00:43:57 +00:00
auto &svp = seg.verts;
auto &Vertices = LevelSharedVertexState.get_vertices();
auto &vcvertptr = Vertices.vcptr;
2018-12-30 00:43:57 +00:00
if (!rotate_list(vcvertptr, svp).uand) //on screen?
2016-02-12 04:02:28 +00:00
{
auto &stv = Side_to_verts[side];
2017-08-26 19:47:51 +00:00
draw_line(*grd_curcanv, svp[stv[edge]], svp[stv[(edge + 1) % 4]], color);
2016-02-12 04:02:28 +00:00
}
2006-03-20 17:12:09 +00:00
}
int Show_triangulations=0;
//edge types - lower number types have precedence
#define ET_FACING 0 //this edge on a facing face
#define ET_NOTFACING 1 //this edge on a non-facing face
#define ET_NOTUSED 2 //no face uses this edge
#define ET_NOTEXTANT 3 //would exist if side were triangulated
#define ET_EMPTY 255 //this entry in array is empty
//colors for those types
//int edge_colors[] = {BM_RGB(45/2,45/2,45/2),
// BM_RGB(45/3,45/3,45/3), //BM_RGB(0,0,45), //
// BM_RGB(45/4,45/4,45/4)}; //BM_RGB(0,45,0)}; //
static
#if defined(DXX_BUILD_DESCENT_I)
const
#endif
2014-08-14 02:34:15 +00:00
array<color_t, 3> edge_colors{{54, 59, 64}};
2006-03-20 17:12:09 +00:00
namespace {
struct seg_edge
{
2006-03-20 17:12:09 +00:00
union {
struct {int v0,v1;} __pack__ n;
2006-03-20 17:12:09 +00:00
long vv;
}v;
ushort type;
ubyte face_count, backface_count;
};
2006-03-20 17:12:09 +00:00
}
2015-08-12 03:11:46 +00:00
static array<seg_edge, MAX_EDGES> edge_list;
static array<int, MAX_EDGES> used_list; //which entries in edge_list have been used
static int n_used;
2006-03-20 17:12:09 +00:00
2016-12-11 01:56:44 +00:00
static unsigned edge_list_size; //set each frame
2006-03-20 17:12:09 +00:00
#define HASH(a,b) ((a*5+b) % edge_list_size)
//define edge numberings
constexpr int edges[] = {
2006-03-20 17:12:09 +00:00
0*8+1, // edge 0
0*8+3, // edge 1
0*8+4, // edge 2
1*8+2, // edge 3
1*8+5, // edge 4
2*8+3, // edge 5
2*8+6, // edge 6
3*8+7, // edge 7
4*8+5, // edge 8
4*8+7, // edge 9
5*8+6, // edge 10
6*8+7, // edge 11
0*8+5, // right cross
0*8+7, // top cross
1*8+3, // front cross
2*8+5, // bottom cross
2*8+7, // left cross
4*8+6, // back cross
//crosses going the other way
1*8+4, // other right cross
3*8+4, // other top cross
0*8+2, // other front cross
1*8+6, // other bottom cross
3*8+6, // other left cross
5*8+7, // other back cross
};
#define N_NORMAL_EDGES 12 //the normal edges of a box
#define N_EXTRA_EDGES 12 //ones created by triangulation
#define N_EDGES_PER_SEGMENT (N_NORMAL_EDGES+N_EXTRA_EDGES)
2014-06-07 15:39:18 +00:00
using std::swap;
2006-03-20 17:12:09 +00:00
//given two vertex numbers on a segment (range 0..7), tell what edge number it is
2013-10-27 22:00:14 +00:00
static int find_edge_num(int v0,int v1)
2006-03-20 17:12:09 +00:00
{
int i;
int vv;
2013-11-28 00:23:50 +00:00
const int *edgep = edges;
2006-03-20 17:12:09 +00:00
if (v0 > v1) swap(v0,v1);
vv = v0*8+v1;
// for (i=0;i<N_EDGES_PER_SEGMENT;i++)
// if (edges[i]==vv) return i;
for (i=N_EDGES_PER_SEGMENT; i; i--)
if (*edgep++ == vv)
return (N_EDGES_PER_SEGMENT-i);
Error("Could not find edge for %d,%d",v0,v1);
2006-03-20 17:12:09 +00:00
//return -1;
}
//finds edge, filling in edge_ptr. if found old edge, returns index, else return -1
2013-10-27 22:00:14 +00:00
static int find_edge(int v0,int v1,seg_edge **edge_ptr)
2006-03-20 17:12:09 +00:00
{
long vv;
int hash,oldhash;
2006-03-20 17:12:09 +00:00
int ret;
vv = (v1<<16) + v0;
oldhash = hash = HASH(v0,v1);
ret = -1;
while (ret==-1) {
if (edge_list[hash].type == ET_EMPTY) ret=0;
else if (edge_list[hash].v.vv == vv) ret=1;
else {
if (++hash==edge_list_size) hash=0;
if (hash==oldhash) Error("Edge list full!");
}
}
*edge_ptr = &edge_list[hash];
if (ret == 0)
return -1;
else
return hash;
}
//adds an edge to the edge list
2013-10-27 22:00:14 +00:00
static void add_edge(int v0,int v1,ubyte type)
2006-03-20 17:12:09 +00:00
{
int found;
seg_edge *e;
if (v0 > v1) swap(v0,v1);
found = find_edge(v0,v1,&e);
if (found == -1) {
e->v.n.v0 = v0;
e->v.n.v1 = v1;
e->type = type;
2015-08-12 03:11:46 +00:00
used_list[n_used] = e - edge_list.begin();
2006-03-20 17:12:09 +00:00
if (type == ET_FACING)
edge_list[used_list[n_used]].face_count++;
else if (type == ET_NOTFACING)
edge_list[used_list[n_used]].backface_count++;
n_used++;
} else {
if (type < e->type)
e->type = type;
if (type == ET_FACING)
edge_list[found].face_count++;
else if (type == ET_NOTFACING)
edge_list[found].backface_count++;
}
}
//adds a segment's edges to the edge list
2018-12-13 02:31:38 +00:00
static void add_edges(const shared_segment &seg)
2006-03-20 17:12:09 +00:00
{
2018-12-13 02:31:38 +00:00
auto &svp = seg.verts;
2018-12-30 00:43:57 +00:00
auto &Vertices = LevelSharedVertexState.get_vertices();
auto &vcvertptr = Vertices.vcptr;
2018-12-30 00:43:57 +00:00
if (!rotate_list(vcvertptr, svp).uand)
2015-10-18 21:01:18 +00:00
{ //all off screen?
2016-12-11 01:56:44 +00:00
int i,fn,vn;
2006-03-20 17:12:09 +00:00
int flag;
ubyte edge_flags[N_EDGES_PER_SEGMENT];
for (i=0;i<N_NORMAL_EDGES;i++) edge_flags[i]=ET_NOTUSED;
for (;i<N_EDGES_PER_SEGMENT;i++) edge_flags[i]=ET_NOTEXTANT;
2018-12-13 02:31:38 +00:00
range_for (auto &&e, enumerate(seg.sides))
2016-12-11 01:56:44 +00:00
{
auto &sidep = e.value;
int num_vertices;
2016-12-11 01:56:44 +00:00
const auto v = create_all_vertex_lists(seg, sidep, e.idx);
const auto &num_faces = v.first;
const auto &vertex_list = v.second;
2006-03-20 17:12:09 +00:00
if (num_faces == 1)
num_vertices = 4;
else
num_vertices = 3;
for (fn=0; fn<num_faces; fn++) {
int en;
//Note: normal check appears to be the wrong way since the normals points in, but we're looking from the outside
2018-12-13 02:31:38 +00:00
if (g3_check_normal_facing(vcvertptr(seg.verts[vertex_list[fn*3]]), sidep.normals[fn]))
2006-03-20 17:12:09 +00:00
flag = ET_NOTFACING;
else
flag = ET_FACING;
auto v0 = &vertex_list[fn*3];
2006-03-20 17:12:09 +00:00
for (vn=0; vn<num_vertices-1; vn++) {
// en = find_edge_num(vertex_list[fn*3 + vn], vertex_list[fn*3 + (vn+1)%num_vertices]);
en = find_edge_num(*v0, *(v0+1));
2014-10-04 15:04:44 +00:00
if (en!=edge_none)
2006-03-20 17:12:09 +00:00
if (flag < edge_flags[en]) edge_flags[en] = flag;
v0++;
}
en = find_edge_num(*v0, vertex_list[fn*3]);
2014-10-04 15:04:44 +00:00
if (en!=edge_none)
2006-03-20 17:12:09 +00:00
if (flag < edge_flags[en]) edge_flags[en] = flag;
}
}
for (i=0; i<N_EDGES_PER_SEGMENT; i++)
if (i<N_NORMAL_EDGES || (edge_flags[i]!=ET_NOTEXTANT && Show_triangulations))
2018-12-13 02:31:38 +00:00
add_edge(seg.verts[edges[i] / 8], seg.verts[edges[i] & 7], edge_flags[i]);
2006-03-20 17:12:09 +00:00
}
}
// ----------------------------------------------------------------------------
2018-12-13 02:31:38 +00:00
static void draw_trigger_side(const shared_segment &seg, const unsigned side, const uint8_t color)
2006-03-20 17:12:09 +00:00
{
2018-12-13 02:31:38 +00:00
auto &svp = seg.verts;
2018-12-30 00:43:57 +00:00
auto &Vertices = LevelSharedVertexState.get_vertices();
auto &vcvertptr = Vertices.vcptr;
2018-12-30 00:43:57 +00:00
if (!rotate_list(vcvertptr, svp).uand)
2015-10-18 21:01:18 +00:00
{ //all off screen?
2006-03-20 17:12:09 +00:00
// Draw diagonals
2016-02-12 04:02:28 +00:00
auto &stv = Side_to_verts[side];
2017-08-26 19:47:51 +00:00
draw_line(*grd_curcanv, svp[stv[0]], svp[stv[2]], color);
2006-03-20 17:12:09 +00:00
}
}
// ----------------------------------------------------------------------------
2018-12-13 02:31:38 +00:00
static void draw_wall_side(const shared_segment &seg, const unsigned side, const uint8_t color)
2006-03-20 17:12:09 +00:00
{
2018-12-13 02:31:38 +00:00
auto &svp = seg.verts;
2018-12-30 00:43:57 +00:00
auto &Vertices = LevelSharedVertexState.get_vertices();
auto &vcvertptr = Vertices.vcptr;
2018-12-30 00:43:57 +00:00
if (!rotate_list(vcvertptr, svp).uand)
2015-10-18 21:01:18 +00:00
{ //all off screen?
2006-03-20 17:12:09 +00:00
// Draw diagonals
2016-02-12 04:02:28 +00:00
auto &stv = Side_to_verts[side];
2017-08-26 19:47:51 +00:00
draw_line(*grd_curcanv, svp[stv[0]], svp[stv[2]], color);
draw_line(*grd_curcanv, svp[stv[1]], svp[stv[3]], color);
2006-03-20 17:12:09 +00:00
}
}
2016-01-26 03:45:07 +00:00
#define WALL_BLASTABLE_COLOR rgb_t{31, 0, 0} // RED
#define WALL_DOOR_COLOR rgb_t{0, 0, 31} // DARK BLUE
#define WALL_DOOR_LOCKED_COLOR rgb_t{0, 0, 63} // BLUE
#define WALL_AUTO_DOOR_COLOR rgb_t{0, 31, 0} // DARK GREEN
#define WALL_AUTO_DOOR_LOCKED_COLOR rgb_t{0, 63, 0} // GREEN
#define WALL_ILLUSION_COLOR rgb_t{63, 0, 63} // PURPLE
2006-03-20 17:12:09 +00:00
#define TRIGGER_COLOR BM_XRGB( 63/2 , 63/2 , 0/2) // YELLOW
// ----------------------------------------------------------------------------------------------------------------
// Draws special walls (for now these are just removable walls.)
2018-12-13 02:31:38 +00:00
static void draw_special_wall(const shared_segment &seg, const unsigned side)
2006-03-20 17:12:09 +00:00
{
2018-12-13 02:31:38 +00:00
auto &w = *vcwallptr(seg.sides[side].wall_num);
const auto get_color = [=]() {
2016-02-12 04:02:28 +00:00
const auto type = w.type;
if (type != WALL_OPEN)
{
2016-02-12 04:02:28 +00:00
const auto flags = w.flags;
if (flags & WALL_DOOR_LOCKED)
return (flags & WALL_DOOR_AUTO) ? WALL_AUTO_DOOR_LOCKED_COLOR : WALL_DOOR_LOCKED_COLOR;
if (flags & WALL_DOOR_AUTO)
return WALL_AUTO_DOOR_COLOR;
if (type == WALL_BLASTABLE)
return WALL_BLASTABLE_COLOR;
if (type == WALL_DOOR)
return WALL_DOOR_COLOR;
if (type == WALL_ILLUSION)
return WALL_ILLUSION_COLOR;
}
2016-01-26 03:45:07 +00:00
return rgb_t{45, 45, 45};
};
const auto color = get_color();
2016-02-12 04:02:28 +00:00
draw_wall_side(seg,side, gr_find_closest_color(color.r, color.g, color.b));
2006-03-20 17:12:09 +00:00
2016-02-12 04:02:28 +00:00
if (w.trigger != trigger_none)
{
2016-02-12 04:02:28 +00:00
draw_trigger_side(seg,side, TRIGGER_COLOR);
2011-09-26 23:31:19 +00:00
}
2006-03-20 17:12:09 +00:00
}
// ----------------------------------------------------------------------------------------------------------------
// Recursively parse mine structure, drawing segments.
static void draw_mine_sub(const vmsegptridx_t segnum,int depth, visited_segment_bitarray_t &visited)
2006-03-20 17:12:09 +00:00
{
2013-12-18 23:38:05 +00:00
if (visited[segnum]) return; // If segment already drawn, return.
visited[segnum] = true; // Say that this segment has been drawn.
2014-10-02 03:02:34 +00:00
auto mine_ptr = segnum;
2006-03-20 17:12:09 +00:00
// If this segment is active, process it, else skip it.
if (mine_ptr->segnum != segment_none) {
2006-03-20 17:12:09 +00:00
int side;
if (Search_mode) check_segment(mine_ptr);
else add_edges(mine_ptr); //add this segments edges to list
if (depth != 0) {
for (side=0; side<MAX_SIDES_PER_SEGMENT; side++) {
const auto child_segnum = mine_ptr->children[side];
if (IS_CHILD(child_segnum))
{
2018-12-13 02:31:38 +00:00
if (mine_ptr->shared_segment::sides[side].wall_num != wall_none)
2006-03-20 17:12:09 +00:00
draw_special_wall(mine_ptr, side);
draw_mine_sub(segnum.absolute_sibling(child_segnum), depth-1, visited);
2006-03-20 17:12:09 +00:00
}
}
}
}
}
2013-10-27 22:00:14 +00:00
static void draw_mine_edges(int automap_flag)
2006-03-20 17:12:09 +00:00
{
int i,type;
seg_edge *e;
for (type=ET_NOTUSED;type>=ET_FACING;type--) {
2016-02-12 04:02:28 +00:00
const auto color = edge_colors[type];
2006-03-20 17:12:09 +00:00
for (i=0;i<n_used;i++) {
e = &edge_list[used_list[i]];
if (e->type == type)
if ((!automap_flag) || (e->face_count == 1))
2017-08-26 19:47:51 +00:00
draw_line(*grd_curcanv, e->v.n.v0, e->v.n.v1, color);
2006-03-20 17:12:09 +00:00
}
}
}
2016-12-11 01:56:44 +00:00
static void clear_edge_list()
{
range_for (auto &i, partial_range(edge_list, edge_list_size))
{
i.type = ET_EMPTY;
i.face_count = 0;
i.backface_count = 0;
}
}
2006-03-20 17:12:09 +00:00
//draws an entire mine
static void draw_mine(const vmsegptridx_t mine_ptr,int depth)
2006-03-20 17:12:09 +00:00
{
2013-12-18 23:38:05 +00:00
visited_segment_bitarray_t visited;
2006-03-20 17:12:09 +00:00
edge_list_size = min(LevelSharedSegmentState.Num_segments * 12, MAX_EDGES.value); //make maybe smaller than max
2006-03-20 17:12:09 +00:00
// clear edge list
2016-12-11 01:56:44 +00:00
clear_edge_list();
2006-03-20 17:12:09 +00:00
n_used = 0;
2014-10-02 03:02:34 +00:00
draw_mine_sub(mine_ptr,depth, visited);
2006-03-20 17:12:09 +00:00
draw_mine_edges(0);
}
// -----------------------------------------------------------------------------
// Draw all segments, ignoring connectivity.
// A segment is drawn if its segnum != -1.
2015-07-13 01:09:36 +00:00
static void draw_mine_all(int automap_flag)
2006-03-20 17:12:09 +00:00
{
edge_list_size = min(LevelSharedSegmentState.Num_segments * 12, MAX_EDGES.value); //make maybe smaller than max
2006-03-20 17:12:09 +00:00
// clear edge list
2016-12-11 01:56:44 +00:00
clear_edge_list();
2006-03-20 17:12:09 +00:00
n_used = 0;
range_for (const auto &&segp, vmsegptridx)
{
if (segp->segnum != segment_none)
{
2018-12-13 02:31:38 +00:00
range_for (auto &&e, enumerate(segp->shared_segment::sides))
2016-12-11 01:56:44 +00:00
if (e.value.wall_num != wall_none)
draw_special_wall(segp, e.idx);
2006-03-20 17:12:09 +00:00
if (Search_mode)
check_segment(segp);
2006-03-20 17:12:09 +00:00
else {
add_edges(segp);
2018-06-24 05:06:14 +00:00
draw_seg_objects(*grd_curcanv, segp);
2006-03-20 17:12:09 +00:00
}
}
}
2006-03-20 17:12:09 +00:00
draw_mine_edges(automap_flag);
}
static void draw_listed_segments(grs_canvas &canvas, count_segment_array_t &s, const uint8_t color)
{
range_for (const auto &ss, s)
{
const auto &&segp = vcsegptr(ss);
if (segp->segnum != segment_none)
draw_segment(canvas, segp, color);
}
}
2013-10-27 22:00:14 +00:00
static void draw_selected_segments(void)
2006-03-20 17:12:09 +00:00
{
draw_listed_segments(*grd_curcanv, Selected_segs, SELECT_COLOR);
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void draw_found_segments(void)
2006-03-20 17:12:09 +00:00
{
draw_listed_segments(*grd_curcanv, Found_segs, FOUND_COLOR);
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void draw_warning_segments(void)
2006-03-20 17:12:09 +00:00
{
draw_listed_segments(*grd_curcanv, Warning_segs, WARNING_COLOR);
2006-03-20 17:12:09 +00:00
}
2013-10-27 22:00:14 +00:00
static void draw_group_segments(void)
2006-03-20 17:12:09 +00:00
{
if (current_group > -1) {
draw_listed_segments(*grd_curcanv, GroupList[current_group].segments, GROUP_COLOR);
2006-03-20 17:12:09 +00:00
}
}
2013-10-27 22:00:14 +00:00
static void draw_special_segments(void)
2006-03-20 17:12:09 +00:00
{
// Highlight matcens, fuelcens, etc.
2016-02-12 04:02:28 +00:00
range_for (const auto &&segp, vcsegptr)
2015-06-13 22:42:18 +00:00
{
if (segp->segnum != segment_none)
{
unsigned r, g, b;
2015-06-13 22:42:18 +00:00
switch(segp->special)
2006-03-20 17:12:09 +00:00
{
case SEGMENT_IS_FUELCEN:
r = 29 * 2, g = 27 * 2, b = 13 * 2;
2006-03-20 17:12:09 +00:00
break;
case SEGMENT_IS_CONTROLCEN:
r = 29 * 2, g = 0, b = 0;
2006-03-20 17:12:09 +00:00
break;
case SEGMENT_IS_ROBOTMAKER:
r = 29 * 2, g = 0, b = 31 * 2;
2006-03-20 17:12:09 +00:00
break;
default:
continue;
2006-03-20 17:12:09 +00:00
}
const auto color = gr_find_closest_color(r, g, b);
2017-08-26 19:47:51 +00:00
draw_segment(*grd_curcanv, segp, color);
}
2015-06-13 22:42:18 +00:00
}
2006-03-20 17:12:09 +00:00
}
//find a free vertex. returns the vertex number
2014-08-08 03:02:24 +00:00
static int alloc_vert()
2006-03-20 17:12:09 +00:00
{
int vn;
const auto Num_vertices = LevelSharedVertexState.Num_vertices;
assert(Num_vertices < MAX_SEGMENT_VERTICES);
2006-03-20 17:12:09 +00:00
for (vn=0; (vn < Num_vertices) && Vertex_active[vn]; vn++) ;
Vertex_active[vn] = 1;
++LevelSharedVertexState.Num_vertices;
2006-03-20 17:12:09 +00:00
return vn;
}
//frees a vertex
2014-08-08 03:02:24 +00:00
static void free_vert(int vert_num)
2006-03-20 17:12:09 +00:00
{
Vertex_active[vert_num] = 0;
--LevelSharedVertexState.Num_vertices;
2006-03-20 17:12:09 +00:00
}
// -----------------------------------------------------------------------------
2013-10-27 22:00:14 +00:00
static void draw_coordinate_axes(void)
2006-03-20 17:12:09 +00:00
{
2017-02-19 19:33:37 +00:00
array<unsigned, 16> Axes_verts;
2014-10-29 03:24:31 +00:00
vms_vector tvec;
2006-03-20 17:12:09 +00:00
2016-12-11 01:56:44 +00:00
range_for (auto &i, Axes_verts)
i = alloc_vert();
2006-03-20 17:12:09 +00:00
create_coordinate_axes_from_segment(Cursegp,Axes_verts);
2018-12-30 00:43:57 +00:00
auto &Vertices = LevelSharedVertexState.get_vertices();
auto &vcvertptr = Vertices.vcptr;
auto &vmvertptr = Vertices.vmptr;
2017-08-11 23:43:54 +00:00
const auto &&av0 = vcvertptr(Axes_verts[0]);
const auto &&av1 = vcvertptr(Axes_verts[1]);
const auto &&av2 = vcvertptr(Axes_verts[2]);
const auto &&av3 = vcvertptr(Axes_verts[3]);
const auto &&av4 = vmvertptr(Axes_verts[4]);
const auto &&av6 = vmvertptr(Axes_verts[6]);
const auto &&av9 = vmvertptr(Axes_verts[9]);
const auto &&av10 = vmvertptr(Axes_verts[10]);
const auto &&av11 = vmvertptr(Axes_verts[11]);
const auto &&av12 = vmvertptr(Axes_verts[12]);
const auto &&av14 = vmvertptr(Axes_verts[14]);
const auto &&xvec = vm_vec_sub(av1, av0);
const auto &&yvec = vm_vec_sub(av2, av0);
const auto &&zvec = vm_vec_sub(av3, av0);
2006-03-20 17:12:09 +00:00
// Create the letter X
tvec = xvec;
2017-08-11 23:43:54 +00:00
vm_vec_add(av4, av1, vm_vec_scale(tvec, F1_0 / 16));
2006-03-20 17:12:09 +00:00
tvec = yvec;
2017-08-11 23:43:54 +00:00
vm_vec_add2(av4, vm_vec_scale(tvec, F1_0 / 8));
vm_vec_sub(av6, av4, vm_vec_scale(tvec, F2_0));
2014-09-28 21:11:05 +00:00
tvec = xvec;
2017-08-11 23:43:54 +00:00
vm_vec_scale(tvec, F1_0 / 8);
vm_vec_add(vmvertptr(Axes_verts[7]), av4, tvec);
vm_vec_add(vmvertptr(Axes_verts[5]), av6, tvec);
2006-03-20 17:12:09 +00:00
// Create the letter Y
tvec = yvec;
2017-08-11 23:43:54 +00:00
vm_vec_add(av11, av2, vm_vec_scale(tvec, F1_0 / 16));
vm_vec_add(vmvertptr(Axes_verts[8]), av11, tvec);
vm_vec_add(av9, av11, vm_vec_scale(tvec, F1_0 * 2));
vm_vec_add(av10, av11, tvec);
2014-09-28 21:11:05 +00:00
tvec = xvec;
2017-08-11 23:43:54 +00:00
vm_vec_scale(tvec, F1_0 / 16);
vm_vec_sub2(av9, tvec);
vm_vec_add2(av10, tvec);
2006-03-20 17:12:09 +00:00
// Create the letter Z
tvec = zvec;
2017-08-11 23:43:54 +00:00
vm_vec_add(av12, av3, vm_vec_scale(tvec, F1_0 / 16));
2006-03-20 17:12:09 +00:00
tvec = yvec;
2017-08-11 23:43:54 +00:00
vm_vec_add2(av12, vm_vec_scale(tvec, F1_0 / 8));
vm_vec_sub(av14, av12, vm_vec_scale(tvec, F2_0));
2014-09-28 21:11:05 +00:00
tvec = zvec;
2017-08-11 23:43:54 +00:00
vm_vec_scale(tvec, F1_0 / 8);
vm_vec_add(vmvertptr(Axes_verts[13]), av12, tvec);
vm_vec_add(vmvertptr(Axes_verts[15]), av14, tvec);
2006-03-20 17:12:09 +00:00
2018-12-30 00:43:57 +00:00
rotate_list(vcvertptr, Axes_verts);
2006-03-20 17:12:09 +00:00
2016-02-12 04:02:28 +00:00
const uint8_t color = AXIS_COLOR;
2006-03-20 17:12:09 +00:00
2017-08-26 19:47:51 +00:00
draw_line(*grd_curcanv, Axes_verts[0], Axes_verts[1], color);
draw_line(*grd_curcanv, Axes_verts[0], Axes_verts[2], color);
draw_line(*grd_curcanv, Axes_verts[0], Axes_verts[3], color);
2006-03-20 17:12:09 +00:00
// draw the letter X
2017-08-26 19:47:51 +00:00
draw_line(*grd_curcanv, Axes_verts[4], Axes_verts[5], color);
draw_line(*grd_curcanv, Axes_verts[6], Axes_verts[7], color);
2006-03-20 17:12:09 +00:00
// draw the letter Y
2017-08-26 19:47:51 +00:00
draw_line(*grd_curcanv, Axes_verts[8], Axes_verts[9], color);
draw_line(*grd_curcanv, Axes_verts[8], Axes_verts[10], color);
draw_line(*grd_curcanv, Axes_verts[8], Axes_verts[11], color);
2006-03-20 17:12:09 +00:00
// draw the letter Z
2017-08-26 19:47:51 +00:00
draw_line(*grd_curcanv, Axes_verts[12], Axes_verts[13], color);
draw_line(*grd_curcanv, Axes_verts[13], Axes_verts[14], color);
draw_line(*grd_curcanv, Axes_verts[14], Axes_verts[15], color);
2006-03-20 17:12:09 +00:00
2016-12-11 01:56:44 +00:00
range_for (auto &i, Axes_verts)
free_vert(i);
2006-03-20 17:12:09 +00:00
}
void draw_world(grs_canvas *screen_canvas,editor_view *v,const vmsegptridx_t mine_ptr,int depth)
2006-03-20 17:12:09 +00:00
{
vms_vector viewer_position;
gr_set_current_canvas(screen_canvas);
viewer_position = v->ev_matrix.fvec;
2014-09-28 21:11:05 +00:00
vm_vec_scale(viewer_position,-v->ev_dist);
2006-03-20 17:12:09 +00:00
2014-09-28 21:43:00 +00:00
vm_vec_add2(viewer_position,Ed_view_target);
2006-03-20 17:12:09 +00:00
2017-01-01 00:45:45 +00:00
gr_clear_canvas(*grd_curcanv, 0);
2017-02-11 21:42:34 +00:00
g3_start_frame(*grd_curcanv);
2014-10-26 22:01:00 +00:00
g3_set_view_matrix(viewer_position,v->ev_matrix,v->ev_zoom);
2006-03-20 17:12:09 +00:00
render_start_frame();
// Draw all segments or only connected segments.
// We might want to draw all segments if we have broken the mine into pieces.
if (Draw_all_segments)
2015-07-13 01:09:36 +00:00
draw_mine_all(Automap_test);
2006-03-20 17:12:09 +00:00
else
draw_mine(mine_ptr,depth);
// Draw the found segments
if (!Automap_test) {
draw_warning_segments();
draw_group_segments();
draw_found_segments();
draw_selected_segments();
draw_special_segments();
// Highlight group segment and side.
if (current_group > -1)
if (Groupsegp[current_group]) {
2017-08-26 19:47:51 +00:00
draw_segment(*grd_curcanv, vcsegptr(Groupsegp[current_group]), GROUPSEG_COLOR);
2016-02-12 04:02:28 +00:00
draw_seg_side(vcsegptr(Groupsegp[current_group]), Groupside[current_group], GROUPSIDE_COLOR);
2006-03-20 17:12:09 +00:00
}
// Highlight marked segment and side.
if (Markedsegp) {
2017-08-26 19:47:51 +00:00
draw_segment(*grd_curcanv, Markedsegp, MARKEDSEG_COLOR);
2016-02-12 04:02:28 +00:00
draw_seg_side(Markedsegp,Markedside, MARKEDSIDE_COLOR);
2006-03-20 17:12:09 +00:00
}
// Highlight current segment and current side.
2017-08-26 19:47:51 +00:00
draw_segment(*grd_curcanv, Cursegp, CURSEG_COLOR);
2006-03-20 17:12:09 +00:00
2016-02-12 04:02:28 +00:00
draw_seg_side(Cursegp,Curside, CURSIDE_COLOR);
2016-02-12 04:02:28 +00:00
draw_side_edge(Cursegp,Curside,Curedge, CUREDGE_COLOR);
2006-03-20 17:12:09 +00:00
// Draw coordinate axes if we are rendering the large view.
if (Show_axes_flag)
2014-09-06 23:55:43 +00:00
if (screen_canvas == LargeViewBox->canvas.get())
2006-03-20 17:12:09 +00:00
draw_coordinate_axes();
// Label the window
2017-02-11 21:42:32 +00:00
gr_set_fontcolor(*grd_curcanv, (v==current_view)?CRED:CWHITE, -1);
2014-09-06 23:55:43 +00:00
if ( screen_canvas == LargeViewBox->canvas.get() ) {
2018-05-19 23:21:42 +00:00
gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 5, 5, "USER VIEW");
2006-03-20 17:12:09 +00:00
switch (Large_view_index) {
2018-05-19 23:21:42 +00:00
case 0: gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 85, 5, "-- TOP"); break;
case 1: gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 85, 5, "-- FRONT"); break;
case 2: gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 85, 5, "-- RIGHT"); break;
2006-03-20 17:12:09 +00:00
}
} else
#if ORTHO_VIEWS
else if ( screen_canvas == TopViewBox->canvas )
2018-05-19 23:21:42 +00:00
gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 5, 5, "TOP");
2006-03-20 17:12:09 +00:00
else if ( screen_canvas == FrontViewBox->canvas )
2018-05-19 23:21:42 +00:00
gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 5, 5, "FRONT");
2006-03-20 17:12:09 +00:00
else if ( screen_canvas == RightViewBox->canvas )
2018-05-19 23:21:42 +00:00
gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 5, 5, "RIGHT");
2006-03-20 17:12:09 +00:00
#else
Error("Ortho views have been removed, what gives?\n");
#endif
}
g3_end_frame();
}
//find the segments that render at a given screen x,y
//parms other than x,y are like draw_world
//fills in globals N_found_segs & Found_segs
void find_segments(short x,short y,grs_canvas *screen_canvas,editor_view *v,const vmsegptridx_t mine_ptr,int depth)
2006-03-20 17:12:09 +00:00
{
vms_vector viewer_position;
gr_set_current_canvas(screen_canvas);
viewer_position = v->ev_matrix.fvec;
2014-09-28 21:11:05 +00:00
vm_vec_scale(viewer_position,-v->ev_dist);
2006-03-20 17:12:09 +00:00
2014-10-30 03:11:06 +00:00
vm_vec_add2(viewer_position,Ed_view_target);
2006-03-20 17:12:09 +00:00
2017-02-11 21:42:34 +00:00
g3_start_frame(*grd_curcanv);
2014-10-26 22:01:00 +00:00
g3_set_view_matrix(viewer_position,v->ev_matrix,v->ev_zoom);
2006-03-20 17:12:09 +00:00
render_start_frame();
#if DXX_USE_OGL
g3_end_frame();
#endif
2016-02-12 04:02:28 +00:00
uint8_t color = 0;
2017-03-11 19:56:23 +00:00
gr_pixel(grd_curcanv->cv_bitmap, x, y, color); //set our search pixel to color zero
#if DXX_USE_OGL
2017-02-11 21:42:34 +00:00
g3_start_frame(*grd_curcanv);
#endif
2006-03-20 17:12:09 +00:00
Search_mode = -1;
Found_segs.clear();
2006-03-20 17:12:09 +00:00
Search_x = x; Search_y = y;
if (Draw_all_segments)
2015-07-13 01:09:36 +00:00
draw_mine_all(0);
2006-03-20 17:12:09 +00:00
else
draw_mine(mine_ptr,depth);
g3_end_frame();
Search_mode = 0;
}
namespace dsx {
2006-03-20 17:12:09 +00:00
void meddraw_init_views( grs_canvas * canvas)
{
#if defined(DXX_BUILD_DESCENT_II)
// sticking these here so the correct D2 colors are used
edge_colors[0] = BM_XRGB(45/2,45/2,45/2);
edge_colors[1] = BM_XRGB(45/3,45/3,45/3); //BM_RGB(0,0,45), //
edge_colors[2] = BM_XRGB(45/4,45/4,45/4); //BM_RGB(0,45,0)}; //
#endif
2006-03-20 17:12:09 +00:00
Views[0]->ev_canv = canvas;
#if ORTHO_VIEWS
Views[1]->ev_canv = TopViewBox->canvas;
Views[2]->ev_canv = FrontViewBox->canvas;
Views[3]->ev_canv = RightViewBox->canvas;
#endif
}
}