backport cont.
[dosdemo] / src / 3dgfx / polyfill.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <assert.h>
5 #if defined(__WATCOMC__) || defined(_WIN32) || defined(__DJGPP__)
6 #include <malloc.h>
7 #else
8 #include <alloca.h>
9 #endif
10 #include "polyfill.h"
11 #include "gfxutil.h"
12
13 #define FILL_POLY_BITS  0x03
14
15 /* mode bits: 00-wire 01-flat 10-gouraud 11-reserved
16  *     bit 2: texture
17  *     bit 3-4: blend mode: 00-none 01-alpha 10-additive 11-reserved
18  */
19 void (*fillfunc[])(struct pvertex*, int) = {
20         polyfill_wire,
21         polyfill_flat,
22         polyfill_gouraud,
23         0,
24         polyfill_tex_wire,
25         polyfill_tex_flat,
26         polyfill_tex_gouraud,
27         0,
28         polyfill_alpha_wire,
29         polyfill_alpha_flat,
30         polyfill_alpha_gouraud,
31         0,
32         polyfill_alpha_tex_wire,
33         polyfill_alpha_tex_flat,
34         polyfill_alpha_tex_gouraud,
35         0,
36         polyfill_add_wire,
37         polyfill_add_flat,
38         polyfill_add_gouraud,
39         0,
40         polyfill_add_tex_wire,
41         polyfill_add_tex_flat,
42         polyfill_add_tex_gouraud,
43         0, 0, 0, 0, 0, 0, 0, 0, 0
44 };
45
46 struct pimage pfill_fb, pfill_tex;
47
48 #define EDGEPAD 8
49 static struct pvertex *edgebuf, *left, *right;
50 static int edgebuf_size;
51 static int fbheight;
52
53 /*
54 #define CHECKEDGE(x) \
55         do { \
56                 assert(x >= 0); \
57                 assert(x < fbheight); \
58         } while(0)
59 */
60 #define CHECKEDGE(x)
61
62
63 void polyfill_fbheight(int height)
64 {
65         void *tmp;
66         int newsz = (height * 2 + EDGEPAD * 3) * sizeof *edgebuf;
67
68         if(newsz > edgebuf_size) {
69                 free(edgebuf);
70                 if(!(edgebuf = malloc(newsz))) {
71                         fprintf(stderr, "failed to allocate edge table buffer (%d bytes)\n", newsz);
72                         abort();
73                 }
74                 edgebuf_size = newsz;
75
76                 left = edgebuf + EDGEPAD;
77                 right = edgebuf + height + EDGEPAD * 2;
78
79 #ifndef NDEBUG
80                 memset(edgebuf, 0xaa, EDGEPAD * sizeof *edgebuf);
81                 memset(edgebuf + height + EDGEPAD, 0xaa, EDGEPAD * sizeof *edgebuf);
82                 memset(edgebuf + height * 2 + EDGEPAD * 2, 0xaa, EDGEPAD * sizeof *edgebuf);
83 #endif
84         }
85
86         fbheight = height;
87 }
88
89 void polyfill(int mode, struct pvertex *verts, int nverts)
90 {
91 #ifndef NDEBUG
92         if(!fillfunc[mode]) {
93                 fprintf(stderr, "polyfill mode %d not implemented\n", mode);
94                 abort();
95         }
96 #endif
97
98         fillfunc[mode](verts, nverts);
99 }
100
101 void polyfill_wire(struct pvertex *verts, int nverts)
102 {
103         int i, x0, y0, x1, y1;
104         struct pvertex *v = verts;
105         unsigned short color = ((v->r << 8) & 0xf800) |
106                 ((v->g << 3) & 0x7e0) | ((v->b >> 3) & 0x1f);
107
108         for(i=0; i<nverts - 1; i++) {
109                 x0 = v->x >> 8;
110                 y0 = v->y >> 8;
111                 ++v;
112                 x1 = v->x >> 8;
113                 y1 = v->y >> 8;
114                 if(clip_line(&x0, &y0, &x1, &y1, 0, 0, pfill_fb.width, pfill_fb.height)) {
115                         draw_line(x0, y0, x1, y1, color);
116                 }
117         }
118         x0 = verts[0].x >> 8;
119         y0 = verts[0].y >> 8;
120         if(clip_line(&x1, &y1, &x0, &y0, 0, 0, pfill_fb.width, pfill_fb.height)) {
121                 draw_line(x1, y1, x0, y0, color);
122         }
123 }
124
125 void polyfill_tex_wire(struct pvertex *verts, int nverts)
126 {
127         polyfill_wire(verts, nverts);   /* TODO */
128 }
129
130 void polyfill_alpha_wire(struct pvertex *verts, int nverts)
131 {
132         polyfill_wire(verts, nverts);   /* TODO */
133 }
134
135 void polyfill_alpha_tex_wire(struct pvertex *verts, int nverts)
136 {
137         polyfill_wire(verts, nverts);   /* TODO */
138 }
139
140 void polyfill_add_wire(struct pvertex *verts, int nverts)
141 {
142         polyfill_wire(verts, nverts);   /* TODO */
143 }
144
145 void polyfill_add_tex_wire(struct pvertex *verts, int nverts)
146 {
147         polyfill_wire(verts, nverts);   /* TODO */
148 }
149
150 #define NEXTIDX(x) (((x) - 1 + nverts) % nverts)
151 #define PREVIDX(x) (((x) + 1) % nverts)
152
153 /* XXX
154  * When HIGH_QUALITY is defined, the rasterizer calculates slopes for attribute
155  * interpolation on each scanline separately; otherwise the slope for each
156  * attribute would be calculated once for the whole polygon, which is faster,
157  * but produces some slight quantization artifacts, due to the limited precision
158  * of fixed-point calculations.
159  */
160 #define HIGH_QUALITY
161
162 /* extra bits of precision to use when interpolating colors.
163  * try tweaking this if you notice strange quantization artifacts.
164  */
165 #define COLOR_SHIFT     12
166
167
168 #define POLYFILL polyfill_flat
169 #define SCANEDGE scanedge_flat
170 #undef GOURAUD
171 #undef TEXMAP
172 #undef BLEND_ALPHA
173 #undef BLEND_ADD
174 #include "polytmpl.h"
175 #undef POLYFILL
176 #undef SCANEDGE
177
178 #define POLYFILL polyfill_gouraud
179 #define SCANEDGE scanedge_gouraud
180 #define GOURAUD
181 #undef TEXMAP
182 #undef BLEND_ALPHA
183 #undef BLEND_ADD
184 #include "polytmpl.h"
185 #undef POLYFILL
186 #undef SCANEDGE
187
188 #define POLYFILL polyfill_tex_flat
189 #define SCANEDGE scanedge_tex_flat
190 #undef GOURAUD
191 #define TEXMAP
192 #undef BLEND_ALPHA
193 #undef BLEND_ADD
194 #include "polytmpl.h"
195 #undef POLYFILL
196 #undef SCANEDGE
197
198 #define POLYFILL polyfill_tex_gouraud
199 #define SCANEDGE scanedge_tex_gouraud
200 #define GOURAUD
201 #define TEXMAP
202 #undef BLEND_ALPHA
203 #undef BLEND_ADD
204 #include "polytmpl.h"
205 #undef POLYFILL
206 #undef SCANEDGE
207
208 #define POLYFILL polyfill_alpha_flat
209 #define SCANEDGE scanedge_alpha_flat
210 #undef GOURAUD
211 #undef TEXMAP
212 #define BLEND_ALPHA
213 #undef BLEND_ADD
214 #include "polytmpl.h"
215 #undef POLYFILL
216 #undef SCANEDGE
217
218 #define POLYFILL polyfill_alpha_gouraud
219 #define SCANEDGE scanedge_alpha_gouraud
220 #define GOURAUD
221 #undef TEXMAP
222 #define BLEND_ALPHA
223 #undef BLEND_ADD
224 #include "polytmpl.h"
225 #undef POLYFILL
226 #undef SCANEDGE
227
228 #define POLYFILL polyfill_alpha_tex_flat
229 #define SCANEDGE scanedge_alpha_tex_flat
230 #undef GOURAUD
231 #define TEXMAP
232 #define BLEND_ALPHA
233 #undef BLEND_ADD
234 #include "polytmpl.h"
235 #undef POLYFILL
236 #undef SCANEDGE
237
238 #define POLYFILL polyfill_alpha_tex_gouraud
239 #define SCANEDGE scanedge_alpha_tex_gouraud
240 #define GOURAUD
241 #define TEXMAP
242 #define BLEND_ALPHA
243 #undef BLEND_ADD
244 #include "polytmpl.h"
245 #undef POLYFILL
246 #undef SCANEDGE
247
248 #define POLYFILL polyfill_add_flat
249 #define SCANEDGE scanedge_add_flat
250 #undef GOURAUD
251 #undef TEXMAP
252 #undef BLEND_ALPHA
253 #define BLEND_ADD
254 #include "polytmpl.h"
255 #undef POLYFILL
256 #undef SCANEDGE
257
258 #define POLYFILL polyfill_add_gouraud
259 #define SCANEDGE scanedge_add_gouraud
260 #define GOURAUD
261 #undef TEXMAP
262 #undef BLEND_ALPHA
263 #define BLEND_ADD
264 #include "polytmpl.h"
265 #undef POLYFILL
266 #undef SCANEDGE
267
268 #define POLYFILL polyfill_add_tex_flat
269 #define SCANEDGE scanedge_add_tex_flat
270 #undef GOURAUD
271 #define TEXMAP
272 #undef BLEND_ALPHA
273 #define BLEND_ADD
274 #include "polytmpl.h"
275 #undef POLYFILL
276 #undef SCANEDGE
277
278 #define POLYFILL polyfill_add_tex_gouraud
279 #define SCANEDGE scanedge_add_tex_gouraud
280 #define GOURAUD
281 #define TEXMAP
282 #undef BLEND_ALPHA
283 #define BLEND_ADD
284 #include "polytmpl.h"
285 #undef POLYFILL
286 #undef SCANEDGE