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
#include "3d.h"
9
#include "globvars.h"
10
#include "clipper.h"
11
#include "dxxerror.h"
12
 
13
#include "compiler-range_for.h"
14
#include <stdexcept>
15
 
16
namespace dcx {
17
 
18
#if !DXX_USE_OGL
19
temporary_points_t::temporary_points_t() :
20
        free_point_num(0)
21
{
22
        auto p = &temp_points.front();
23
        range_for (auto &f, free_points)
24
                f = p++;
25
}
26
 
27
static g3s_point &get_temp_point(temporary_points_t &t)
28
{
29
        if (t.free_point_num >= t.free_points.size())
30
                throw std::out_of_range("not enough free points");
31
        auto &p = *t.free_points[t.free_point_num++];
32
        p.p3_flags = PF_TEMP_POINT;
33
        return p;
34
}
35
 
36
void temporary_points_t::free_temp_point(g3s_point *p)
37
{
38
        if (!(p->p3_flags & PF_TEMP_POINT))
39
                throw std::invalid_argument("freeing non-temporary point");
40
        if (--free_point_num >= free_points.size())
41
                throw std::out_of_range("too many free points");
42
        free_points[free_point_num] = p;
43
        p->p3_flags &= ~PF_TEMP_POINT;
44
}
45
 
46
//clips an edge against one plane. 
47
static g3s_point &clip_edge(int plane_flag,g3s_point *on_pnt,g3s_point *off_pnt, temporary_points_t &tp)
48
{
49
        fix psx_ratio;
50
        fix a,b,kn,kd;
51
 
52
        //compute clipping value k = (xs-zs) / (xs-xe-zs+ze)
53
        //use x or y as appropriate, and negate x/y value as appropriate
54
 
55
        if (plane_flag & (CC_OFF_RIGHT | CC_OFF_LEFT)) {
56
                a = on_pnt->p3_x;
57
                b = off_pnt->p3_x;
58
        }
59
        else {
60
                a = on_pnt->p3_y;
61
                b = off_pnt->p3_y;
62
        }
63
 
64
        if (plane_flag & (CC_OFF_LEFT | CC_OFF_BOT)) {
65
                a = -a;
66
                b = -b;
67
        }
68
 
69
        kn = a - on_pnt->p3_z;                                          //xs-zs
70
        kd = kn - b + off_pnt->p3_z;                            //xs-zs-xe+ze
71
 
72
        auto &tmp = get_temp_point(tp);
73
 
74
        psx_ratio = fixdiv( kn, kd );
75
        tmp.p3_x = on_pnt->p3_x + fixmul( (off_pnt->p3_x-on_pnt->p3_x), psx_ratio);
76
        tmp.p3_y = on_pnt->p3_y + fixmul( (off_pnt->p3_y-on_pnt->p3_y), psx_ratio);
77
 
78
        if (plane_flag & (CC_OFF_TOP|CC_OFF_BOT))
79
                tmp.p3_z = tmp.p3_y;
80
        else
81
                tmp.p3_z = tmp.p3_x;
82
 
83
        if (plane_flag & (CC_OFF_LEFT|CC_OFF_BOT))
84
                tmp.p3_z = -tmp.p3_z;
85
 
86
        if (on_pnt->p3_flags & PF_UVS) {
87
// PSX_HACK!!!!
88
//              tmp.p3_u = on_pnt->p3_u + fixmuldiv(off_pnt->p3_u-on_pnt->p3_u,kn,kd);
89
//              tmp.p3_v = on_pnt->p3_v + fixmuldiv(off_pnt->p3_v-on_pnt->p3_v,kn,kd);
90
                tmp.p3_u = on_pnt->p3_u + fixmul((off_pnt->p3_u-on_pnt->p3_u), psx_ratio);
91
                tmp.p3_v = on_pnt->p3_v + fixmul((off_pnt->p3_v-on_pnt->p3_v), psx_ratio);
92
 
93
                tmp.p3_flags |= PF_UVS;
94
        }
95
 
96
        if (on_pnt->p3_flags & PF_LS) {
97
// PSX_HACK
98
//              tmp.p3_r = on_pnt->p3_r + fixmuldiv(off_pnt->p3_r-on_pnt->p3_r,kn,kd);
99
//              tmp.p3_g = on_pnt->p3_g + fixmuldiv(off_pnt->p3_g-on_pnt->p3_g,kn,kd);
100
//              tmp.p3_b = on_pnt->p3_b + fixmuldiv(off_pnt->p3_b-on_pnt->p3_b,kn,kd);
101
                tmp.p3_l = on_pnt->p3_l + fixmul((off_pnt->p3_l-on_pnt->p3_l), psx_ratio);
102
                tmp.p3_flags |= PF_LS;
103
        }
104
        g3_code_point(tmp);
105
        return tmp;
106
}
107
 
108
//clips a line to the viewing pyramid.
109
void clip_line(g3s_point *&p0,g3s_point *&p1,const uint_fast8_t codes_or, temporary_points_t &tp)
110
{
111
        //might have these left over
112
        p0->p3_flags &= ~(PF_UVS|PF_LS);
113
        p1->p3_flags &= ~(PF_UVS|PF_LS);
114
 
115
        for (int plane_flag=1;plane_flag<16;plane_flag<<=1)
116
                if (codes_or & plane_flag) {
117
 
118
                        if (p0->p3_codes & plane_flag)
119
                                std::swap(p0, p1);
120
                        const auto old_p1 = std::exchange(p1, &clip_edge(plane_flag,p0,p1,tp));
121
                        if (old_p1->p3_flags & PF_TEMP_POINT)
122
                                tp.free_temp_point(old_p1);
123
                }
124
}
125
 
126
static int clip_plane(int plane_flag,polygon_clip_points &src,polygon_clip_points &dest,int *nv,g3s_codes *cc, temporary_points_t &tp)
127
{
128
        //copy first two verts to end
129
        src[*nv] = src[0];
130
        src[*nv+1] = src[1];
131
 
132
        cc->uand = 0xff; cc->uor = 0;
133
 
134
        uint_fast32_t j = 0;
135
        for (int i=1;i<=*nv;i++) {
136
 
137
                if (src[i]->p3_codes & plane_flag) {                            //cur point off?
138
 
139
                        if (! (src[i-1]->p3_codes & plane_flag)) {      //prev not off?
140
 
141
                                dest[j] = &clip_edge(plane_flag,src[i-1],src[i],tp);
142
                                cc->uor  |= dest[j]->p3_codes;
143
                                cc->uand &= dest[j]->p3_codes;
144
                                ++j;
145
                        }
146
 
147
                        if (! (src[i+1]->p3_codes & plane_flag)) {
148
 
149
                                dest[j] = &clip_edge(plane_flag,src[i+1],src[i],tp);
150
                                cc->uor  |= dest[j]->p3_codes;
151
                                cc->uand &= dest[j]->p3_codes;
152
                                ++j;
153
                        }
154
 
155
                        //see if must free discarded point
156
 
157
                        if (src[i]->p3_flags & PF_TEMP_POINT)
158
                                tp.free_temp_point(src[i]);
159
                }
160
                else {                  //cur not off, copy to dest buffer
161
 
162
                        dest[j++] = src[i];
163
 
164
                        cc->uor  |= src[i]->p3_codes;
165
                        cc->uand &= src[i]->p3_codes;
166
                }
167
        }
168
        return j;
169
}
170
 
171
const polygon_clip_points &clip_polygon(polygon_clip_points &rsrc,polygon_clip_points &rdest,int *nv,g3s_codes *cc, temporary_points_t &tp)
172
{
173
        polygon_clip_points *src = &rsrc, *dest = &rdest;
174
        for (int plane_flag=1;plane_flag<16;plane_flag<<=1)
175
 
176
                if (cc->uor & plane_flag) {
177
 
178
                        *nv = clip_plane(plane_flag,*src,*dest,nv,cc,tp);
179
 
180
                        if (cc->uand)           //clipped away
181
                                return *dest;
182
 
183
                        std::swap(src, dest);
184
                }
185
 
186
        return *src;            //we swapped after we copied
187
}
188
#endif
189
 
190
}