2006-03-20 16:43:15 +00:00
|
|
|
/*
|
2018-09-02 00:57:29 +00:00
|
|
|
* This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
|
2014-06-12 08:41:03 +00:00
|
|
|
* It is copyright by its individual contributors, as recorded in the
|
|
|
|
* project's Git history. See COPYING.txt at the top level for license
|
|
|
|
* terms and a link to the Git history.
|
|
|
|
*/
|
2006-03-20 16:43:15 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Drawing routines
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2012-07-07 18:35:06 +00:00
|
|
|
#include "dxxerror.h"
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
#include "3d.h"
|
|
|
|
#include "globvars.h"
|
|
|
|
#include "texmap.h"
|
2016-09-24 18:06:11 +00:00
|
|
|
#if !DXX_USE_OGL
|
2021-02-05 12:54:08 +00:00
|
|
|
#include "clipper.h"
|
2015-02-07 05:59:27 +00:00
|
|
|
#include "gr.h"
|
|
|
|
#endif
|
2022-09-24 17:47:52 +00:00
|
|
|
#include "d_enumerate.h"
|
|
|
|
#include "d_zip.h"
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2015-12-13 18:00:49 +00:00
|
|
|
namespace dcx {
|
2015-12-05 22:57:24 +00:00
|
|
|
|
2012-11-18 22:15:54 +00:00
|
|
|
tmap_drawer_type tmap_drawer_ptr = draw_tmap;
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2022-06-05 17:44:52 +00:00
|
|
|
#if DXX_USE_OGL
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
const std::array<GLfloat, 8> build_color_array_from_color_palette_index(const color_palette_index color)
|
|
|
|
{
|
|
|
|
auto &&rgb = PAL2T(color);
|
|
|
|
const GLfloat color_r = rgb.r / 63.0;
|
|
|
|
const GLfloat color_g = rgb.g / 63.0;
|
|
|
|
const GLfloat color_b = rgb.b / 63.0;
|
|
|
|
return {{
|
|
|
|
color_r, color_g, color_b, 1.0,
|
|
|
|
color_r, color_g, color_b, 1.0,
|
|
|
|
}};
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
g3_draw_line_colors::g3_draw_line_colors(const color_palette_index color) :
|
|
|
|
color_array(build_color_array_from_color_palette_index(color))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-03-20 16:43:15 +00:00
|
|
|
//specifies 2d drawing routines to use instead of defaults. Passing
|
|
|
|
//NULL for either or both restores defaults
|
2014-08-08 02:52:35 +00:00
|
|
|
void g3_set_special_render(tmap_drawer_type tmap_drawer)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
2015-01-22 03:34:20 +00:00
|
|
|
tmap_drawer_ptr = tmap_drawer;
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
2022-07-09 13:39:29 +00:00
|
|
|
|
2016-09-24 18:06:11 +00:00
|
|
|
#if !DXX_USE_OGL
|
2022-07-09 13:39:29 +00:00
|
|
|
namespace {
|
|
|
|
|
2006-03-20 16:43:15 +00:00
|
|
|
//deal with a clipped line
|
2022-06-05 17:44:52 +00:00
|
|
|
static void must_clip_line(const g3_draw_line_context &context, g3s_point *p0, g3s_point *p1, const uint8_t codes_or, temporary_points_t &tp)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
|
|
|
if ((p0->p3_flags&PF_TEMP_POINT) || (p1->p3_flags&PF_TEMP_POINT))
|
2015-04-02 02:36:54 +00:00
|
|
|
; //line has already been clipped, so give up
|
2006-03-20 16:43:15 +00:00
|
|
|
else {
|
2014-11-16 19:14:51 +00:00
|
|
|
clip_line(p0,p1,codes_or,tp);
|
2022-06-05 17:44:52 +00:00
|
|
|
g3_draw_line(context, *p0, *p1, tp);
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//free temp points
|
|
|
|
|
|
|
|
if (p0->p3_flags & PF_TEMP_POINT)
|
2014-11-16 19:14:51 +00:00
|
|
|
tp.free_temp_point(p0);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
if (p1->p3_flags & PF_TEMP_POINT)
|
2014-11-16 19:14:51 +00:00
|
|
|
tp.free_temp_point(p1);
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
2022-07-09 13:39:29 +00:00
|
|
|
}
|
|
|
|
|
2006-03-20 16:43:15 +00:00
|
|
|
//draws a line. takes two points. returns true if drew
|
2022-06-05 17:44:52 +00:00
|
|
|
void g3_draw_line(const g3_draw_line_context &context, g3s_point &p0, g3s_point &p1)
|
2014-11-16 19:14:51 +00:00
|
|
|
{
|
|
|
|
temporary_points_t tp;
|
2022-06-05 17:44:52 +00:00
|
|
|
g3_draw_line(context, p0, p1, tp);
|
2014-11-16 19:14:51 +00:00
|
|
|
}
|
|
|
|
|
2022-06-05 17:44:52 +00:00
|
|
|
void g3_draw_line(const g3_draw_line_context &context, g3s_point &p0, g3s_point &p1, temporary_points_t &tp)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
|
|
|
ubyte codes_or;
|
|
|
|
|
2014-11-13 03:19:52 +00:00
|
|
|
if (p0.p3_codes & p1.p3_codes)
|
2015-04-02 02:36:54 +00:00
|
|
|
return;
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2014-11-13 03:19:52 +00:00
|
|
|
codes_or = p0.p3_codes | p1.p3_codes;
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2016-02-12 04:02:28 +00:00
|
|
|
if (
|
|
|
|
(codes_or & CC_BEHIND) ||
|
|
|
|
(static_cast<void>((p0.p3_flags & PF_PROJECTED) || (g3_project_point(p0), 0)), p0.p3_flags & PF_OVERFLOW) ||
|
|
|
|
(static_cast<void>((p1.p3_flags & PF_PROJECTED) || (g3_project_point(p1), 0)), p1.p3_flags & PF_OVERFLOW)
|
|
|
|
)
|
2022-06-05 17:44:52 +00:00
|
|
|
return must_clip_line(context, &p0,&p1, codes_or, tp);
|
|
|
|
gr_line(context.canvas, p0.p3_sx, p0.p3_sy, p1.p3_sx, p1.p3_sy, context.color);
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//returns true if a plane is facing the viewer. takes the unrotated surface
|
|
|
|
//normal of the plane, and a point on it. The normal need not be normalized
|
2014-10-02 03:02:35 +00:00
|
|
|
bool g3_check_normal_facing(const vms_vector &v,const vms_vector &norm)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
2014-10-29 03:24:31 +00:00
|
|
|
return (vm_vec_dot(vm_vec_sub(View_position,v),norm) > 0);
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
2020-05-02 21:18:42 +00:00
|
|
|
bool do_facing_check(const std::array<cg3s_point *, 3> &vertlist)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
2014-08-16 21:54:48 +00:00
|
|
|
//normal not specified, so must compute
|
2006-03-20 16:43:15 +00:00
|
|
|
//get three points (rotated) and compute normal
|
2014-11-02 03:44:27 +00:00
|
|
|
const auto tempv = vm_vec_perp(vertlist[0]->p3_vec,vertlist[1]->p3_vec,vertlist[2]->p3_vec);
|
2014-09-28 21:11:48 +00:00
|
|
|
return (vm_vec_dot(tempv,vertlist[1]->p3_vec) < 0);
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 18:06:11 +00:00
|
|
|
#if !DXX_USE_OGL
|
2022-07-09 13:39:29 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
static void must_clip_tmap_face(grs_canvas &, int nv, g3s_codes cc, grs_bitmap &bm, polygon_clip_points &Vbuf0, polygon_clip_points &Vbuf1);
|
|
|
|
|
2006-03-20 16:43:15 +00:00
|
|
|
//deal with face that must be clipped
|
2017-02-11 21:42:41 +00:00
|
|
|
static void must_clip_flat_face(grs_canvas &canvas, int nv, g3s_codes cc, polygon_clip_points &Vbuf0, polygon_clip_points &Vbuf1, const uint8_t color)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
2014-11-16 19:14:51 +00:00
|
|
|
temporary_points_t tp;
|
|
|
|
auto &bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc,tp);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2012-11-02 17:09:03 +00:00
|
|
|
if (nv>0 && !(cc.uor&CC_BEHIND) && !cc.uand) {
|
2020-05-02 21:18:42 +00:00
|
|
|
std::array<fix, MAX_POINTS_IN_POLY*2> Vertex_list;
|
2014-09-26 02:42:14 +00:00
|
|
|
for (int i=0;i<nv;i++) {
|
2006-03-20 16:43:15 +00:00
|
|
|
g3s_point *p = bufptr[i];
|
|
|
|
|
|
|
|
if (!(p->p3_flags&PF_PROJECTED))
|
2014-11-13 03:21:33 +00:00
|
|
|
g3_project_point(*p);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
if (p->p3_flags&PF_OVERFLOW) {
|
|
|
|
goto free_points;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vertex_list[i*2] = p->p3_sx;
|
|
|
|
Vertex_list[i*2+1] = p->p3_sy;
|
|
|
|
}
|
2017-02-11 21:42:41 +00:00
|
|
|
gr_upoly_tmap(canvas, nv, Vertex_list, color);
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
//free temp points
|
|
|
|
free_points:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
2022-07-09 13:39:29 +00:00
|
|
|
}
|
|
|
|
|
2006-03-20 16:43:15 +00:00
|
|
|
//draw a flat-shaded face.
|
|
|
|
//returns 1 if off screen, 0 if drew
|
2022-09-24 17:47:52 +00:00
|
|
|
void _g3_draw_poly(grs_canvas &canvas, const std::span<cg3s_point *const> pointlist, const uint8_t color)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
|
|
|
g3s_codes cc;
|
|
|
|
|
2014-11-16 19:14:50 +00:00
|
|
|
polygon_clip_points Vbuf0, Vbuf1;
|
2022-09-24 17:47:52 +00:00
|
|
|
auto &bufptr = Vbuf0;
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2022-09-24 17:47:52 +00:00
|
|
|
for (const auto &&[pl, bp] : zip(pointlist, bufptr))
|
|
|
|
{
|
|
|
|
bp = pl;
|
|
|
|
cc.uand &= bp->p3_codes;
|
|
|
|
cc.uor |= bp->p3_codes;
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
2012-11-02 17:09:03 +00:00
|
|
|
if (cc.uand)
|
2015-04-02 02:36:54 +00:00
|
|
|
return; //all points off screen
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2012-11-02 17:09:03 +00:00
|
|
|
if (cc.uor)
|
2015-04-02 02:36:54 +00:00
|
|
|
{
|
2022-09-24 17:47:52 +00:00
|
|
|
must_clip_flat_face(canvas, pointlist.size(), cc, Vbuf0, Vbuf1, color);
|
2015-04-02 02:36:54 +00:00
|
|
|
return;
|
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
//now make list of 2d coords (& check for overflow)
|
2020-05-02 21:18:42 +00:00
|
|
|
std::array<fix, MAX_POINTS_IN_POLY*2> Vertex_list;
|
2022-09-24 17:47:52 +00:00
|
|
|
for (const auto &&[i, pl, p] : enumerate(zip(pointlist, bufptr)))
|
|
|
|
{
|
2006-03-20 16:43:15 +00:00
|
|
|
if (!(p->p3_flags&PF_PROJECTED))
|
2014-11-13 03:21:33 +00:00
|
|
|
g3_project_point(*p);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
if (p->p3_flags&PF_OVERFLOW)
|
2015-04-02 02:36:54 +00:00
|
|
|
{
|
2022-09-24 17:47:52 +00:00
|
|
|
must_clip_flat_face(canvas, pointlist.size(), cc, Vbuf0, Vbuf1, color);
|
2015-04-02 02:36:54 +00:00
|
|
|
return;
|
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
Vertex_list[i*2] = p->p3_sx;
|
|
|
|
Vertex_list[i*2+1] = p->p3_sy;
|
|
|
|
}
|
2022-09-24 17:47:52 +00:00
|
|
|
gr_upoly_tmap(canvas, pointlist.size(), Vertex_list, color);
|
2015-04-02 02:36:54 +00:00
|
|
|
//say it drew
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//draw a texture-mapped face.
|
|
|
|
//returns 1 if off screen, 0 if drew
|
2022-09-24 17:47:52 +00:00
|
|
|
void _g3_draw_tmap(grs_canvas &canvas, const std::span<cg3s_point *const> pointlist, const g3s_uvl *const uvl_list, const g3s_lrgb *const light_rgb, grs_bitmap &bm)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
|
|
|
g3s_codes cc;
|
|
|
|
|
2014-11-16 19:14:50 +00:00
|
|
|
polygon_clip_points Vbuf0, Vbuf1;
|
2022-09-24 17:47:52 +00:00
|
|
|
auto &bufptr = Vbuf0;
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2022-09-24 17:47:52 +00:00
|
|
|
for (auto &&[i, pl, bp] : enumerate(zip(pointlist, bufptr)))
|
|
|
|
{
|
|
|
|
const auto p = bp = pl;
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2012-11-02 17:09:03 +00:00
|
|
|
cc.uand &= p->p3_codes;
|
|
|
|
cc.uor |= p->p3_codes;
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2022-09-24 17:47:52 +00:00
|
|
|
if constexpr (!DXX_USE_OGL)
|
|
|
|
{
|
2006-03-20 16:43:15 +00:00
|
|
|
p->p3_u = uvl_list[i].u;
|
|
|
|
p->p3_v = uvl_list[i].v;
|
2011-04-07 20:32:47 +00:00
|
|
|
p->p3_l = (light_rgb[i].r+light_rgb[i].g+light_rgb[i].b)/3;
|
2022-09-24 17:47:52 +00:00
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
p->p3_flags |= PF_UVS + PF_LS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-11-02 17:09:03 +00:00
|
|
|
if (cc.uand)
|
2014-08-16 17:35:44 +00:00
|
|
|
return; //all points off screen
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2012-11-02 17:09:03 +00:00
|
|
|
if (cc.uor)
|
2014-08-16 17:35:44 +00:00
|
|
|
{
|
2022-09-24 17:47:52 +00:00
|
|
|
must_clip_tmap_face(canvas, pointlist.size(), cc, bm, Vbuf0, Vbuf1);
|
2014-08-16 17:35:44 +00:00
|
|
|
return;
|
|
|
|
}
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
//now make list of 2d coords (& check for overflow)
|
|
|
|
|
2022-09-24 17:47:52 +00:00
|
|
|
for (auto &&p : unchecked_partial_range(bufptr, pointlist.size()))
|
|
|
|
{
|
2006-03-20 16:43:15 +00:00
|
|
|
if (!(p->p3_flags&PF_PROJECTED))
|
2014-11-13 03:21:33 +00:00
|
|
|
g3_project_point(*p);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
if (p->p3_flags&PF_OVERFLOW) {
|
|
|
|
Int3(); //should not overflow after clip
|
2014-08-16 17:35:44 +00:00
|
|
|
return;
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
}
|
2022-09-24 17:47:52 +00:00
|
|
|
(*tmap_drawer_ptr)(canvas, bm, std::span(bufptr).first(pointlist.size()));
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
2022-07-09 13:39:29 +00:00
|
|
|
namespace {
|
|
|
|
|
2017-02-11 21:42:39 +00:00
|
|
|
static void must_clip_tmap_face(grs_canvas &canvas, int nv, g3s_codes cc, grs_bitmap &bm, polygon_clip_points &Vbuf0, polygon_clip_points &Vbuf1)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
2014-11-16 19:14:51 +00:00
|
|
|
temporary_points_t tp;
|
|
|
|
auto &bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc,tp);
|
2012-11-02 17:09:03 +00:00
|
|
|
if (nv && !(cc.uor&CC_BEHIND) && !cc.uand) {
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2014-09-26 02:42:14 +00:00
|
|
|
for (int i=0;i<nv;i++) {
|
2006-03-20 16:43:15 +00:00
|
|
|
g3s_point *p = bufptr[i];
|
|
|
|
|
|
|
|
if (!(p->p3_flags&PF_PROJECTED))
|
2014-11-13 03:21:33 +00:00
|
|
|
g3_project_point(*p);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
|
|
|
if (p->p3_flags&PF_OVERFLOW) {
|
|
|
|
Int3(); //should not overflow after clip
|
|
|
|
goto free_points;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-24 17:47:52 +00:00
|
|
|
(*tmap_drawer_ptr)(canvas, bm, std::span(bufptr).first(nv));
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free_points:
|
|
|
|
;
|
|
|
|
|
|
|
|
// Assert(free_point_num==0);
|
|
|
|
}
|
|
|
|
|
2022-07-09 13:39:29 +00:00
|
|
|
}
|
|
|
|
|
2006-03-20 16:43:15 +00:00
|
|
|
//draw a sortof sphere - i.e., the 2d radius is proportional to the 3d
|
|
|
|
//radius, but not to the distance from the eye
|
2017-08-16 01:54:26 +00:00
|
|
|
void g3_draw_sphere(grs_canvas &canvas, cg3s_point &pnt, const fix rad, const uint8_t color)
|
2006-03-20 16:43:15 +00:00
|
|
|
{
|
2014-11-13 03:22:49 +00:00
|
|
|
if (! (pnt.p3_codes & CC_BEHIND)) {
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2014-11-13 03:22:49 +00:00
|
|
|
if (! (pnt.p3_flags & PF_PROJECTED))
|
|
|
|
g3_project_point(pnt);
|
2006-03-20 16:43:15 +00:00
|
|
|
|
2014-11-13 03:22:49 +00:00
|
|
|
if (! (pnt.p3_codes & PF_OVERFLOW)) {
|
2016-02-11 03:25:52 +00:00
|
|
|
const auto r2 = fixmul(rad, Matrix_scale.x);
|
2006-03-20 16:43:15 +00:00
|
|
|
#ifndef __powerc
|
2022-05-24 02:32:58 +00:00
|
|
|
const auto ot = checkmuldiv(r2, Canv_w2, pnt.p3_z);
|
|
|
|
if (!ot)
|
2015-04-02 02:36:54 +00:00
|
|
|
return;
|
2022-05-24 02:32:58 +00:00
|
|
|
const auto t = *ot;
|
2006-03-20 16:43:15 +00:00
|
|
|
#else
|
2014-11-13 03:22:49 +00:00
|
|
|
if (pnt.p3_z == 0)
|
2015-04-02 02:36:54 +00:00
|
|
|
return;
|
2016-02-11 03:25:52 +00:00
|
|
|
const fix t = fl2f(((f2fl(r2) * fCanv_w2) / f2fl(pnt.p3_z)));
|
2006-03-20 16:43:15 +00:00
|
|
|
#endif
|
2017-02-11 21:42:33 +00:00
|
|
|
gr_disk(canvas, pnt.p3_sx, pnt.p3_sy, t, color);
|
2006-03-20 16:43:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-12-05 22:57:24 +00:00
|
|
|
}
|