dos3d
view src/scantmpl.h @ 12:c29a6e024950
merged
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 28 Nov 2011 05:03:22 +0200 |
parents | bce78aaafc68 |
children | 1e9f0b3616fa |
line source
1 /*
2 256-color 3D graphics hack for real-mode DOS.
3 Copyright (C) 2011 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 static void SCAN_EDGE(struct vertex *v0, struct vertex *v1)
19 {
20 int i, start, end;
21 float dx, dy, dfdx;
22 #ifdef INTERP_DEPTH
23 float z, dz, dfdz;
24 #endif
25 #ifdef INTERP_ENERGY
26 float e, de, dfde;
27 #endif
28 #ifdef INTERP_TEX
29 float u, v, du, dv, dfdu, dfdv;
30 #endif
31 float x;
32 struct vertex *edge;
34 dy = v1->pos.y - v0->pos.y;
35 if(dy < 1e-6 && dy > -1e-6) {
36 return;
37 }
39 dx = v1->pos.x - v0->pos.x;
40 dfdx = dx / dy;
42 #ifdef INTERP_DEPTH
43 dz = v1->pos.z - v0->pos.z;
44 dfdz = dz / dy;
45 #endif
46 #ifdef INTERP_ENERGY
47 de = v1->energy - v0->energy;
48 dfde = de / dy;
49 #endif
50 #ifdef INTERP_TEX
51 du = v1->tc.x - v0->tc.x;
52 dv = v1->tc.y - v0->tc.y;
53 dfdu = du / dy;
54 dfdv = dv / dy;
55 #endif
57 if(dy < 0.0) {
58 struct vertex *tmp = v0;
59 v0 = v1;
60 v1 = tmp;
61 edge = (st->ord == MGL_CCW) ? vright : vleft;
62 } else {
63 edge = (st->ord == MGL_CCW) ? vleft : vright;
64 }
66 start = (int)ROUND(v0->pos.y);
67 end = (int)ROUND(v1->pos.y);
69 if(start >= 0) {
71 x = v0->pos.x;
72 #ifdef INTERP_DEPTH
73 z = v0->pos.z;
74 #endif
75 #ifdef INTERP_ENERGY
76 e = v0->energy;
77 #endif
78 #ifdef INTERP_TEX
79 u = v0->tc.x;
80 v = v0->tc.y;
81 #endif
82 } else {
83 float lines = -v0->pos.y;
85 x = v0->pos.x + dfdx * lines;
86 #ifdef INTERP_DEPTH
87 z = v0->pos.z + dfdz * lines;
88 #endif
89 #ifdef INTERP_ENERGY
90 e = v0->energy + dfde * lines;
91 #endif
92 #ifdef INTERP_TEX
93 u = v0->tc.x + dfdu * lines;
94 v = v0->tc.y + dfdv * lines;
95 #endif
96 start = 0;
97 }
99 if(end >= fb->height) {
100 end = fb->height - 1;
101 }
104 for(i=start; i<end; i++) {
105 edge[i].pos.x = x;
106 x += dfdx;
108 edge[i].cidx = v0->cidx;
109 #ifdef INTERP_DEPTH
110 edge[i].pos.z = z;
111 z += dfdz;
112 #endif
114 #ifdef INTERP_ENERGY
115 edge[i].energy = e;
116 e += dfde;
117 #else
118 edge[i].energy = v0->energy;
119 #endif
121 #ifdef INTERP_TEX
122 edge[i].tc.x = u;
123 edge[i].tc.y = v;
124 u += dfdu;
125 v += dfdv;
126 #endif
127 }
128 }
130 static void SCAN_LINE(int y, unsigned char *sline)
131 {
132 int x0, x1, len, tmp, cidx;
133 #if defined(INTERP_DEPTH) || defined(INTERP_ENERGY) || defined(INTERP_TEX)
134 int i;
135 float x, dx;
136 #endif
137 #ifdef INTERP_DEPTH
138 float z, dz, dfdz;
139 #endif
140 #ifdef INTERP_ENERGY
141 float e, de, dfde;
142 #endif
143 #ifdef INTERP_TEX
144 int tx, ty;
145 float u, v, du, dv, dfdu, dfdv;
146 #endif
147 struct vertex *left, *right;
149 x0 = (int)ROUND(vleft[y].pos.x);
150 x1 = (int)ROUND(vright[y].pos.x);
152 if(x1 < x0) {
153 if(st->flags & MGL_CULL_FACE) {
154 return;
155 }
156 tmp = x0;
157 x0 = x1;
158 x1 = tmp;
160 left = vright;
161 right = vleft;
162 } else {
163 left = vleft;
164 right = vright;
165 }
167 if(x1 >= fb->width) {
168 x1 = fb->width - 1;
169 }
171 cidx = left[y].cidx;
172 #if !defined(INTERP_DEPTH) && !defined(INTERP_ENERGY) && !defined(INTERP_TEX)
173 if(x0 < 0) x0 = 0;
174 len = x1 - x0;
175 assert(len >= 0);
176 /* no interpolation at all, just memset the whole scanline */
177 memset(sline + x0, cidx + left[y].energy * st->col_range, len);
178 #else
179 /* otherwise do a loop and interpolate whatever needs interpolating */
180 x = left[y].pos.x;
181 dx = right[y].pos.x - x;
183 if(dx < 0.5 && dx > -0.5) {
184 return;
185 }
187 if(x0 >= 0) {
188 #ifdef INTERP_DEPTH
189 z = left[y].pos.z;
190 dz = right[y].pos.z - z;
191 dfdz = dz / dx;
192 #endif
193 #ifdef INTERP_ENERGY
194 e = left[y].energy;
195 de = right[y].energy - e;
196 dfde = de / dx;
197 #endif
198 #ifdef INTERP_TEX
199 u = left[y].tc.x;
200 v = left[y].tc.y;
201 du = right[y].tc.x - u;
202 dv = right[y].tc.y - v;
203 dfdu = du / dx;
204 dfdv = dv / dx;
205 #endif
206 } else {
207 float dist = -left[y].pos.x;
209 #ifdef INTERP_DEPTH
210 dz = right[y].pos.z - left[y].pos.z;
211 dfdz = dz / dx;
212 z = left[y].pos.z + dfdz * dist;
213 #endif
214 #ifdef INTERP_ENERGY
215 de = right[y].energy - left[y].energy;
216 dfde = de / dx;
217 e = left[y].energy + dfde * dist;
218 #endif
219 #ifdef INTERP_TEX
220 du = right[y].tc.x - left[y].tc.x;
221 dv = right[y].tc.y - left[y].tc.y;
222 dfdu = du / dx;
223 dfdv = dv / dx;
224 u = left[y].tc.x + dfdu * dist;
225 v = left[y].tc.y + dfdv * dist;
226 #endif
227 x0 = 0;
228 }
230 len = x1 - x0;
232 for(i=0; i<len; i++) {
233 int c = cidx;
235 #ifdef INTERP_DEPTH
236 long pix = (sline + x0 + i) - fb->pixels;
237 unsigned short zval = (unsigned short)(z * USHRT_MAX);
238 unsigned short *zptr = fb->zbuf[ZTILE(pix)] + ZTILE_OFFS(pix);
240 if(z < 0.0 || z >= 1.0 || zval > *zptr) {
241 # ifdef INTERP_TEX
242 u += dfdu;
243 v += dfdv;
244 # endif
245 # ifdef INTERP_ENERGY
246 e += dfde;
247 # endif
248 z += dfdz;
249 continue;
250 }
252 *zptr = zval;
253 z += dfdz;
254 #endif
255 #ifdef INTERP_TEX
256 tx = (int)(u * st->tex.width) & st->tex.xmask;
257 ty = (int)(v * st->tex.height) & st->tex.ymask;
258 c = st->tex.pixels[(ty << st->tex.xshift) + tx];
260 u += dfdu;
261 v += dfdv;
262 #endif
263 #ifdef INTERP_ENERGY
264 c += e * st->col_range;
265 e += dfde;
266 #else
267 c += left[y].energy * st->col_range;
268 #endif
269 sline[x0 + i] = c;
270 }
271 #endif /* flat */
272 }