Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
/*
2
 * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
3
 * It is copyright by its individual contributors, as recorded in the
4
 * project's Git history.  See COPYING.txt at the top level for license
5
 * terms and a link to the Git history.
6
 */
7
/*
8
 *
9
 * Drawing routines
10
 *
11
 */
12
 
13
 
14
#include "dxxerror.h"
15
 
16
#include "3d.h"
17
#include "globvars.h"
18
#include "texmap.h"
19
#include "clipper.h"
20
#if !DXX_USE_OGL
21
#include "gr.h"
22
#endif
23
 
24
namespace dcx {
25
 
26
tmap_drawer_type tmap_drawer_ptr = draw_tmap;
27
 
28
//specifies 2d drawing routines to use instead of defaults.  Passing
29
//NULL for either or both restores defaults
30
void g3_set_special_render(tmap_drawer_type tmap_drawer)
31
{
32
        tmap_drawer_ptr = tmap_drawer;
33
}
34
#if !DXX_USE_OGL
35
//deal with a clipped line
36
static void must_clip_line(grs_canvas &canvas, g3s_point *p0, g3s_point *p1, const uint8_t codes_or, const uint8_t color, temporary_points_t &tp)
37
{
38
        if ((p0->p3_flags&PF_TEMP_POINT) || (p1->p3_flags&PF_TEMP_POINT))
39
                ;               //line has already been clipped, so give up
40
        else {
41
                clip_line(p0,p1,codes_or,tp);
42
                g3_draw_line(canvas, *p0, *p1, color, tp);
43
        }
44
 
45
        //free temp points
46
 
47
        if (p0->p3_flags & PF_TEMP_POINT)
48
                tp.free_temp_point(p0);
49
 
50
        if (p1->p3_flags & PF_TEMP_POINT)
51
                tp.free_temp_point(p1);
52
}
53
 
54
//draws a line. takes two points.  returns true if drew
55
void g3_draw_line(grs_canvas &canvas, g3s_point &p0, g3s_point &p1, const uint8_t color)
56
{
57
        temporary_points_t tp;
58
        g3_draw_line(canvas, p0, p1, color, tp);
59
}
60
 
61
void g3_draw_line(grs_canvas &canvas, g3s_point &p0, g3s_point &p1, const uint8_t color, temporary_points_t &tp)
62
{
63
        ubyte codes_or;
64
 
65
        if (p0.p3_codes & p1.p3_codes)
66
                return;
67
 
68
        codes_or = p0.p3_codes | p1.p3_codes;
69
 
70
        if (
71
                (codes_or & CC_BEHIND) ||
72
                (static_cast<void>((p0.p3_flags & PF_PROJECTED) || (g3_project_point(p0), 0)), p0.p3_flags & PF_OVERFLOW) ||
73
                (static_cast<void>((p1.p3_flags & PF_PROJECTED) || (g3_project_point(p1), 0)), p1.p3_flags & PF_OVERFLOW)
74
        )
75
                return must_clip_line(canvas, &p0,&p1, codes_or, color, tp);
76
        gr_line(canvas, p0.p3_sx, p0.p3_sy, p1.p3_sx, p1.p3_sy, color);
77
}
78
#endif
79
 
80
//returns true if a plane is facing the viewer. takes the unrotated surface 
81
//normal of the plane, and a point on it.  The normal need not be normalized
82
bool g3_check_normal_facing(const vms_vector &v,const vms_vector &norm)
83
{
84
        return (vm_vec_dot(vm_vec_sub(View_position,v),norm) > 0);
85
}
86
 
87
bool do_facing_check(const std::array<cg3s_point *, 3> &vertlist)
88
{
89
        //normal not specified, so must compute
90
                //get three points (rotated) and compute normal
91
                const auto tempv = vm_vec_perp(vertlist[0]->p3_vec,vertlist[1]->p3_vec,vertlist[2]->p3_vec);
92
                return (vm_vec_dot(tempv,vertlist[1]->p3_vec) < 0);
93
}
94
 
95
#if !DXX_USE_OGL
96
//deal with face that must be clipped
97
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)
98
{
99
        temporary_points_t tp;
100
        auto &bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc,tp);
101
 
102
        if (nv>0 && !(cc.uor&CC_BEHIND) && !cc.uand) {
103
                std::array<fix, MAX_POINTS_IN_POLY*2> Vertex_list;
104
                for (int i=0;i<nv;i++) {
105
                        g3s_point *p = bufptr[i];
106
 
107
                        if (!(p->p3_flags&PF_PROJECTED))
108
                                g3_project_point(*p);
109
 
110
                        if (p->p3_flags&PF_OVERFLOW) {
111
                                goto free_points;
112
                        }
113
 
114
                        Vertex_list[i*2]   = p->p3_sx;
115
                        Vertex_list[i*2+1] = p->p3_sy;
116
                }
117
                gr_upoly_tmap(canvas, nv, Vertex_list, color);
118
        }
119
        //free temp points
120
free_points:
121
        ;
122
}
123
 
124
//draw a flat-shaded face.
125
//returns 1 if off screen, 0 if drew
126
void _g3_draw_poly(grs_canvas &canvas, const uint_fast32_t nv, cg3s_point *const *const pointlist, const uint8_t color)
127
{
128
        g3s_codes cc;
129
 
130
        polygon_clip_points Vbuf0, Vbuf1;
131
        auto bufptr = &Vbuf0[0];
132
 
133
        for (int i=0;i<nv;i++) {
134
 
135
                bufptr[i] = pointlist[i];
136
 
137
                cc.uand &= bufptr[i]->p3_codes;
138
                cc.uor  |= bufptr[i]->p3_codes;
139
        }
140
 
141
        if (cc.uand)
142
                return; //all points off screen
143
 
144
        if (cc.uor)
145
        {
146
                must_clip_flat_face(canvas, nv, cc, Vbuf0, Vbuf1, color);
147
                return;
148
        }
149
 
150
        //now make list of 2d coords (& check for overflow)
151
        std::array<fix, MAX_POINTS_IN_POLY*2> Vertex_list;
152
        for (int i=0;i<nv;i++) {
153
                g3s_point *p = bufptr[i];
154
 
155
                if (!(p->p3_flags&PF_PROJECTED))
156
                        g3_project_point(*p);
157
 
158
                if (p->p3_flags&PF_OVERFLOW)
159
                {
160
                        must_clip_flat_face(canvas, nv, cc, Vbuf0, Vbuf1, color);
161
                        return;
162
                }
163
 
164
                Vertex_list[i*2]   = p->p3_sx;
165
                Vertex_list[i*2+1] = p->p3_sy;
166
        }
167
        gr_upoly_tmap(canvas, nv, Vertex_list, color);
168
        //say it drew
169
}
170
 
171
static void must_clip_tmap_face(grs_canvas &, int nv, g3s_codes cc, grs_bitmap &bm, polygon_clip_points &Vbuf0, polygon_clip_points &Vbuf1);
172
 
173
//draw a texture-mapped face.
174
//returns 1 if off screen, 0 if drew
175
void _g3_draw_tmap(grs_canvas &canvas, const unsigned nv, cg3s_point *const *const pointlist, const g3s_uvl *const uvl_list, const g3s_lrgb *const light_rgb, grs_bitmap &bm)
176
{
177
        g3s_codes cc;
178
 
179
        polygon_clip_points Vbuf0, Vbuf1;
180
        auto bufptr = &Vbuf0[0];
181
 
182
        for (int i=0;i<nv;i++) {
183
                g3s_point *p;
184
 
185
                p = bufptr[i] = pointlist[i];
186
 
187
                cc.uand &= p->p3_codes;
188
                cc.uor  |= p->p3_codes;
189
 
190
#if !DXX_USE_OGL
191
                p->p3_u = uvl_list[i].u;
192
                p->p3_v = uvl_list[i].v;
193
                p->p3_l = (light_rgb[i].r+light_rgb[i].g+light_rgb[i].b)/3;
194
#endif
195
 
196
                p->p3_flags |= PF_UVS + PF_LS;
197
 
198
        }
199
 
200
        if (cc.uand)
201
                return; //all points off screen
202
 
203
        if (cc.uor)
204
        {
205
                must_clip_tmap_face(canvas, nv, cc, bm, Vbuf0, Vbuf1);
206
                return;
207
        }
208
 
209
        //now make list of 2d coords (& check for overflow)
210
 
211
        for (int i=0;i<nv;i++) {
212
                g3s_point *p = bufptr[i];
213
 
214
                if (!(p->p3_flags&PF_PROJECTED))
215
                        g3_project_point(*p);
216
 
217
                if (p->p3_flags&PF_OVERFLOW) {
218
                        Int3();         //should not overflow after clip
219
                        return;
220
                }
221
        }
222
 
223
        (*tmap_drawer_ptr)(canvas, bm, nv, bufptr);
224
}
225
 
226
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)
227
{
228
        temporary_points_t tp;
229
        auto &bufptr = clip_polygon(Vbuf0,Vbuf1,&nv,&cc,tp);
230
        if (nv && !(cc.uor&CC_BEHIND) && !cc.uand) {
231
 
232
                for (int i=0;i<nv;i++) {
233
                        g3s_point *p = bufptr[i];
234
 
235
                        if (!(p->p3_flags&PF_PROJECTED))
236
                                g3_project_point(*p);
237
 
238
                        if (p->p3_flags&PF_OVERFLOW) {
239
                                Int3();         //should not overflow after clip
240
                                goto free_points;
241
                        }
242
                }
243
 
244
                (*tmap_drawer_ptr)(canvas, bm, nv, &bufptr[0]);
245
        }
246
 
247
free_points:
248
        ;
249
 
250
//      Assert(free_point_num==0);
251
}
252
 
253
//draw a sortof sphere - i.e., the 2d radius is proportional to the 3d
254
//radius, but not to the distance from the eye
255
void g3_draw_sphere(grs_canvas &canvas, cg3s_point &pnt, const fix rad, const uint8_t color)
256
{
257
        if (! (pnt.p3_codes & CC_BEHIND)) {
258
 
259
                if (! (pnt.p3_flags & PF_PROJECTED))
260
                        g3_project_point(pnt);
261
 
262
                if (! (pnt.p3_codes & PF_OVERFLOW)) {
263
                        const auto r2 = fixmul(rad, Matrix_scale.x);
264
#ifndef __powerc
265
                        fix t;
266
                        if (!checkmuldiv(&t, r2, Canv_w2, pnt.p3_z))
267
                                return;
268
#else
269
                        if (pnt.p3_z == 0)
270
                                return;
271
                        const fix t = fl2f(((f2fl(r2) * fCanv_w2) / f2fl(pnt.p3_z)));
272
#endif
273
                        gr_disk(canvas, pnt.p3_sx, pnt.p3_sy, t, color);
274
                }
275
        }
276
}
277
#endif
278
 
279
}