dxx-rebirth/common/3d/draw.cpp

278 lines
6.4 KiB
C++
Raw Normal View History

2006-03-20 16:43:15 +00:00
/*
* This file is part of the DXX-Rebirth project <http://www.dxx-rebirth.com/>.
* 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
*
*/
#include "dxxerror.h"
2006-03-20 16:43:15 +00:00
#include "3d.h"
#include "globvars.h"
#include "texmap.h"
#include "clipper.h"
#ifndef OGL
#include "gr.h"
#endif
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
tmap_drawer_type tmap_drawer_ptr = draw_tmap;
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
void g3_set_special_render(tmap_drawer_type tmap_drawer)
2006-03-20 16:43:15 +00:00
{
tmap_drawer_ptr = tmap_drawer;
2006-03-20 16:43:15 +00:00
}
#ifndef OGL
//deal with a clipped line
2016-02-12 04:02:28 +00:00
static void must_clip_line(g3s_point *p0,g3s_point *p1,ubyte codes_or,const uint8_t color,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))
; //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);
2016-02-12 04:02:28 +00:00
g3_draw_line(*p0, *p1, color, 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
}
//draws a line. takes two points. returns true if drew
2016-02-12 04:02:28 +00:00
void g3_draw_line(g3s_point &p0, g3s_point &p1, const uint8_t color)
2014-11-16 19:14:51 +00:00
{
temporary_points_t tp;
2016-02-12 04:02:28 +00:00
g3_draw_line(p0, p1, color, tp);
2014-11-16 19:14:51 +00:00
}
2016-02-12 04:02:28 +00:00
void g3_draw_line(g3s_point &p0,g3s_point &p1, const uint8_t color,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)
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
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)
)
2016-02-12 04:02:28 +00:00
return must_clip_line(&p0,&p1,codes_or,color,tp);
2016-02-12 04:02:28 +00:00
gr_line(p0.p3_sx, p0.p3_sy, p1.p3_sx, p1.p3_sy, 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
}
2014-11-16 19:14:51 +00:00
bool do_facing_check(const array<cg3s_point *, 3> &vertlist)
2006-03-20 16:43:15 +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
}
2012-06-30 19:14:06 +00:00
#ifndef OGL
2006-03-20 16:43:15 +00:00
//deal with face that must be clipped
2016-02-12 04:02:28 +00:00
static void must_clip_flat_face(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
if (nv>0 && !(cc.uor&CC_BEHIND) && !cc.uand) {
2015-03-11 02:19:15 +00:00
array<fix, MAX_POINTS_IN_POLY*2> Vertex_list;
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;
}
2016-02-12 04:02:28 +00:00
gr_upoly_tmap(nv, Vertex_list, color);
2006-03-20 16:43:15 +00:00
}
//free temp points
free_points:
;
}
//draw a flat-shaded face.
//returns 1 if off screen, 0 if drew
2016-02-12 04:02:28 +00:00
void _g3_draw_poly(uint_fast32_t nv,cg3s_point *const *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;
auto bufptr = &Vbuf0[0];
2006-03-20 16:43:15 +00:00
for (int i=0;i<nv;i++) {
2006-03-20 16:43:15 +00:00
bufptr[i] = pointlist[i];
cc.uand &= bufptr[i]->p3_codes;
cc.uor |= bufptr[i]->p3_codes;
2006-03-20 16:43:15 +00:00
}
if (cc.uand)
return; //all points off screen
2006-03-20 16:43:15 +00:00
if (cc.uor)
{
2016-02-12 04:02:28 +00:00
must_clip_flat_face(nv,cc,Vbuf0,Vbuf1, color);
return;
}
2006-03-20 16:43:15 +00:00
//now make list of 2d coords (& check for overflow)
2015-03-11 02:19:15 +00:00
array<fix, MAX_POINTS_IN_POLY*2> Vertex_list;
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)
{
2016-02-12 04:02:28 +00:00
must_clip_flat_face(nv,cc,Vbuf0,Vbuf1, color);
return;
}
2006-03-20 16:43:15 +00:00
Vertex_list[i*2] = p->p3_sx;
Vertex_list[i*2+1] = p->p3_sy;
}
2016-02-12 04:02:28 +00:00
gr_upoly_tmap(nv, Vertex_list, color);
//say it drew
2006-03-20 16:43:15 +00:00
}
2014-11-16 19:14:50 +00:00
static void must_clip_tmap_face(int nv,g3s_codes cc,grs_bitmap *bm,polygon_clip_points &Vbuf0, polygon_clip_points &Vbuf1);
2006-03-20 16:43:15 +00:00
//draw a texture-mapped face.
//returns 1 if off screen, 0 if drew
2014-11-16 19:14:51 +00:00
void _g3_draw_tmap(unsigned nv,cg3s_point *const *const pointlist,const g3s_uvl *uvl_list,const g3s_lrgb *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;
auto bufptr = &Vbuf0[0];
2006-03-20 16:43:15 +00:00
for (int i=0;i<nv;i++) {
2006-03-20 16:43:15 +00:00
g3s_point *p;
p = bufptr[i] = pointlist[i];
cc.uand &= p->p3_codes;
cc.uor |= p->p3_codes;
2006-03-20 16:43:15 +00:00
p->p3_u = uvl_list[i].u;
p->p3_v = uvl_list[i].v;
p->p3_l = (light_rgb[i].r+light_rgb[i].g+light_rgb[i].b)/3;
2006-03-20 16:43:15 +00:00
p->p3_flags |= PF_UVS + PF_LS;
}
if (cc.uand)
return; //all points off screen
2006-03-20 16:43:15 +00:00
if (cc.uor)
{
2014-11-16 19:14:50 +00:00
must_clip_tmap_face(nv,cc,&bm,Vbuf0,Vbuf1);
return;
}
2006-03-20 16:43:15 +00:00
//now make list of 2d coords (& check for overflow)
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
return;
2006-03-20 16:43:15 +00:00
}
}
2014-11-30 22:09:18 +00:00
(*tmap_drawer_ptr)(bm,nv,bufptr);
2006-03-20 16:43:15 +00:00
}
2014-11-16 19:14:50 +00:00
static void must_clip_tmap_face(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);
if (nv && !(cc.uor&CC_BEHIND) && !cc.uand) {
2006-03-20 16:43:15 +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;
}
}
2014-11-30 22:09:18 +00:00
(*tmap_drawer_ptr)(*bm,nv,&bufptr[0]);
2006-03-20 16:43:15 +00:00
}
free_points:
;
// Assert(free_point_num==0);
}
//draw a sortof sphere - i.e., the 2d radius is proportional to the 3d
//radius, but not to the distance from the eye
2016-02-12 04:02:28 +00:00
void g3_draw_sphere(g3s_point &pnt,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
2016-02-11 03:25:52 +00:00
fix t;
if (!checkmuldiv(&t, r2, Canv_w2, pnt.p3_z))
return;
2006-03-20 16:43:15 +00:00
#else
2014-11-13 03:22:49 +00:00
if (pnt.p3_z == 0)
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
2016-02-12 04:02:28 +00:00
gr_disk(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
}