1 /*
2 * Portions of this file are copyright Rebirth contributors and licensed as
3 * described in COPYING.txt.
4 * Portions of this file are copyright Parallax Software and licensed
5 * according to the Parallax license below.
6 * See COPYING.txt for license details.
7
8 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
9 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
10 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
11 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
12 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
13 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
14 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
15 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
16 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
17 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
18 */
19
20 /*
21 *
22 * Flat shader derived from texture mapper (a little slow)
23 *
24 */
25
26 #include "maths.h"
27 #include "vecmat.h"
28 #include "gr.h"
29 #include "grdef.h"
30 #include "texmap.h"
31 #include "texmapl.h"
32 #include "scanline.h"
33
34 #include "compiler-range_for.h"
35 #include "partial_range.h"
36
37 //#include "tmapext.h"
38
39 #if !DXX_USE_OGL
40 #include "3d.h"
41 #include "dxxerror.h"
42
43 #include "3d.h"
44 #include "dxxerror.h"
45
46 namespace dcx {
47
48 static void gr_upoly_tmap_ylr(grs_canvas &, uint_fast32_t nverts, const int *vert, uint8_t color);
49
50 // -------------------------------------------------------------------------------------
51 // Texture map current scanline.
52 // Uses globals Du_dx and Dv_dx to incrementally compute u,v coordinates
53 // -------------------------------------------------------------------------------------
tmap_scanline_flat(grs_canvas & canvas,int y,fix xleft,fix xright)54 static void tmap_scanline_flat(grs_canvas &canvas, int y, fix xleft, fix xright)
55 {
56 if (xright < xleft)
57 return;
58
59 // setup to call assembler scanline renderer
60
61 fx_y = y;
62 fx_xleft = xleft/F1_0; // (xleft >> 16) != xleft/F1_0 for negative numbers, f2i caused random crashes
63 fx_xright = xright/F1_0;
64
65 if (canvas.cv_fade_level >= GR_FADE_OFF)
66 c_tmap_scanline_flat();
67 else {
68 c_tmap_scanline_shaded(canvas.cv_fade_level);
69 }
70 }
71
72
73 //--unused-- void tmap_scanline_shaded(int y, fix xleft, fix xright)
74 //--unused-- {
75 //--unused-- fix dx;
76 //--unused--
77 //--unused-- dx = xright - xleft;
78 //--unused--
79 //--unused-- // setup to call assembler scanline renderer
80 //--unused--
81 //--unused-- fx_y = y << 16;
82 //--unused-- fx_xleft = xleft;
83 //--unused-- fx_xright = xright;
84 //--unused--
85 //--unused-- asm_tmap_scanline_shaded();
86 //--unused-- }
87
88
89 // -------------------------------------------------------------------------------------
90 // Render a texture map.
91 // Linear in outer loop, linear in inner loop.
92 // -------------------------------------------------------------------------------------
texture_map_flat(grs_canvas & canvas,const g3ds_tmap & t,int color)93 static void texture_map_flat(grs_canvas &canvas, const g3ds_tmap &t, int color)
94 {
95 int vlt,vrt,vlb,vrb; // vertex left top, vertex right top, vertex left bottom, vertex right bottom
96 int topy,boty,dy;
97 fix dx_dy_left,dx_dy_right;
98 int max_y_vertex;
99 fix xleft,xright;
100 fix recip_dy;
101 auto &v3d = t.verts;
102
103 tmap_flat_color = color;
104
105 // Determine top and bottom y coords.
106 compute_y_bounds(t,vlt,vlb,vrt,vrb,max_y_vertex);
107
108 // Set top and bottom (of entire texture map) y coordinates.
109 topy = f2i(v3d[vlt].y2d);
110 boty = f2i(v3d[max_y_vertex].y2d);
111
112 // Set amount to change x coordinate for each advance to next scanline.
113 dy = f2i(t.verts[vlb].y2d) - f2i(t.verts[vlt].y2d);
114 recip_dy = fix_recip(dy);
115
116 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy);
117
118 dy = f2i(t.verts[vrb].y2d) - f2i(t.verts[vrt].y2d);
119 recip_dy = fix_recip(dy);
120
121 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy);
122
123 // Set initial values for x, u, v
124 xleft = v3d[vlt].x2d;
125 xright = v3d[vrt].x2d;
126
127 // scan all rows in texture map from top through first break.
128 // @mk: Should we render the scanline for y==boty? This violates Matt's spec.
129
130 for (int y = topy; y < boty; y++) {
131
132 // See if we have reached the end of the current left edge, and if so, set
133 // new values for dx_dy and x,u,v
134 if (y == f2i(v3d[vlb].y2d)) {
135 // Handle problem of double points. Search until y coord is different. Cannot get
136 // hung in an infinite loop because we know there is a vertex with a lower y coordinate
137 // because in the for loop, we don't scan all spanlines.
138 while (y == f2i(v3d[vlb].y2d)) {
139 vlt = vlb;
140 vlb = prevmod(vlb,t.nv);
141 }
142 dy = f2i(t.verts[vlb].y2d) - f2i(t.verts[vlt].y2d);
143 recip_dy = fix_recip(dy);
144
145 dx_dy_left = compute_dx_dy(t,vlt,vlb, recip_dy);
146
147 xleft = v3d[vlt].x2d;
148 }
149
150 // See if we have reached the end of the current left edge, and if so, set
151 // new values for dx_dy and x. Not necessary to set new values for u,v.
152 if (y == f2i(v3d[vrb].y2d)) {
153 while (y == f2i(v3d[vrb].y2d)) {
154 vrt = vrb;
155 vrb = succmod(vrb,t.nv);
156 }
157
158 dy = f2i(t.verts[vrb].y2d) - f2i(t.verts[vrt].y2d);
159 recip_dy = fix_recip(dy);
160
161 dx_dy_right = compute_dx_dy(t,vrt,vrb, recip_dy);
162
163 xright = v3d[vrt].x2d;
164
165 }
166 tmap_scanline_flat(canvas, y, xleft, xright);
167
168 xleft += dx_dy_left;
169 xright += dx_dy_right;
170
171 }
172 tmap_scanline_flat(canvas, boty, xleft, xright);
173 }
174
175 // -----------------------------------------------------------------------------------------
176 // This is the gr_upoly-like interface to the texture mapper which uses texture-mapper compatible
177 // (ie, avoids cracking) edge/delta computation.
gr_upoly_tmap(grs_canvas & canvas,uint_fast32_t nverts,const std::array<fix,MAX_POINTS_IN_POLY * 2> & vert,const uint8_t color)178 void gr_upoly_tmap(grs_canvas &canvas, uint_fast32_t nverts, const std::array<fix, MAX_POINTS_IN_POLY * 2> &vert, const uint8_t color)
179 {
180 gr_upoly_tmap_ylr(canvas, nverts, vert.data(), color);
181 }
182
183 struct pnt2d {
184 fix x,y;
185 };
186
187 //this takes the same partms as draw_tmap, but draws a flat-shaded polygon
draw_tmap_flat(grs_canvas & canvas,const grs_bitmap & bp,uint_fast32_t nverts,const g3s_point * const * vertbuf)188 void draw_tmap_flat(grs_canvas &canvas, const grs_bitmap &bp, uint_fast32_t nverts, const g3s_point *const *vertbuf)
189 {
190 union {
191 std::array<pnt2d, MAX_TMAP_VERTS> points;
192 std::array<int, MAX_TMAP_VERTS * (sizeof(pnt2d) / sizeof(int))> ipoints;
193 };
194 static_assert(sizeof(points) == sizeof(ipoints), "array size mismatch");
195 fix average_light;
196 Assert(nverts < MAX_TMAP_VERTS);
197 average_light = vertbuf[0]->p3_l;
198 for (int i=1; i<nverts; i++)
199 average_light += vertbuf[i]->p3_l;
200
201 if (nverts == 4)
202 average_light = f2i(average_light * NUM_LIGHTING_LEVELS/4);
203 else
204 average_light = f2i(average_light * NUM_LIGHTING_LEVELS/nverts);
205
206 if (average_light < 0)
207 average_light = 0;
208 else if (average_light > NUM_LIGHTING_LEVELS-1)
209 average_light = NUM_LIGHTING_LEVELS-1;
210
211 const auto color = gr_fade_table[static_cast<gr_fade_level>(average_light)][bp.avg_color];
212
213 for (int i=0;i<nverts;i++) {
214 points[i].x = vertbuf[i]->p3_sx;
215 points[i].y = vertbuf[i]->p3_sy;
216 }
217 gr_upoly_tmap_ylr(canvas, nverts, ipoints.data(), color);
218 }
219
220 // -----------------------------------------------------------------------------------------
221 //This is like gr_upoly_tmap() but instead of drawing, it calls the specified
222 //function with ylr values
gr_upoly_tmap_ylr(grs_canvas & canvas,uint_fast32_t nverts,const int * vert,const uint8_t color)223 static void gr_upoly_tmap_ylr(grs_canvas &canvas, uint_fast32_t nverts, const int *vert, const uint8_t color)
224 {
225 g3ds_tmap my_tmap;
226 my_tmap.nv = nverts;
227
228 range_for (auto &i, partial_range(my_tmap.verts, nverts))
229 {
230 i.x2d = *vert++;
231 i.y2d = *vert++;
232 }
233 texture_map_flat(canvas, my_tmap, color);
234 }
235
236 }
237 #endif //!OGL
238