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