3dgfx code, untested
[metatoy] / src / 3dgfx / polytmpl.h
1 #ifdef _MSC_VER
2 #pragma warning (disable: 4101)
3 #endif
4
5 #if !defined(GOURAUD) && !defined(TEXMAP) && !defined(ZBUF)
6 #define NOLERP
7 #endif
8
9 void POLYFILL(struct pvertex *varr)
10 {
11         int i, line, top, bot;
12         struct pvertex *v, *vn, *tab;
13         int32_t x, y0, y1, dx, dy, slope, fx, fy;
14         int start, len;
15         g3d_pixel *fbptr, *pptr, color;
16 #ifdef GOURAUD
17         int32_t lum, dl, lumslope;
18 #endif  /* GOURAUD */
19 #ifdef TEXMAP
20         int32_t tu, tv, du, dv, uslope, vslope;
21         int tx, ty;
22         g3d_pixel texel;
23 #endif
24 #ifdef ZBUF
25         int32_t z, dz, zslope;
26         uint32_t *zptr;
27 #endif
28
29 #if !defined(GOURAUD)
30         /* for flat shading we already know the intensity */
31         color = find_color(varr[0].l, varr[0].l, varr[0].l);
32 #endif
33
34         top = pfill_fb.height;
35         bot = 0;
36
37         for(i=0; i<3; i++) {
38                 /* scan the edge between the current and next vertex */
39                 v = varr + i;
40                 vn = VNEXT(v);
41
42                 if(vn->y == v->y) continue;     /* XXX ??? */
43
44                 if(vn->y >= v->y) {
45                         /* inrementing Y: left side */
46                         tab = left;
47                 } else {
48                         /* decrementing Y: right side, flip vertices to trace bottom->up */
49                         tab = right;
50                         v = vn;
51                         vn = varr + i;
52                 }
53
54                 /* calculate edge slope */
55                 dx = vn->x - v->x;
56                 dy = vn->y - v->y;
57                 slope = (dx << 8) / dy;
58
59 #ifdef GOURAUD
60                 lum = v->l << COLOR_SHIFT;
61                 dl = (vn->l << COLOR_SHIFT) - lum;
62                 lumslope = (dl << 8) / dy;
63 #endif  /* GOURAUD */
64 #ifdef TEXMAP
65                 tu = v->u;
66                 tv = v->v;
67                 du = vn->u - tu;
68                 dv = vn->v - tv;
69                 uslope = (du << 8) / dy;
70                 vslope = (dv << 8) / dy;
71 #endif  /* TEXMAP */
72 #ifdef ZBUF
73                 z = v->z;
74                 dz = vn->z - z;
75                 zslope = (dz << 8) / dy;
76 #endif  /* ZBUF */
77
78                 y0 = (v->y + 0x100) & 0xffffff00;       /* start from the next scanline */
79                 fy = y0 - v->y;                                         /* fractional part before the next scanline */
80                 fx = (fy * slope) >> 8;                         /* X adjust for the step to the next scanline */
81                 x = v->x + fx;                                          /* adjust X */
82                 y1 = vn->y & 0xffffff00;                        /* last scanline of the edge <= vn->y */
83
84                 /* also adjust other interpolated attributes */
85 #ifdef GOURAUD
86                 lum += (fy * lumslope) >> 8;
87 #endif  /* GOURAUD */
88 #ifdef TEXMAP
89 #ifdef FLTUV
90                 tu += uslope * (fy / 256.0f);
91                 tv += vslope * (fy / 256.0f);
92 #else
93                 tu += (fy * uslope) >> 8;
94                 tv += (fy * vslope) >> 8;
95 #endif
96 #endif  /* TEXMAP */
97 #ifdef ZBUF
98                 z += (fy * zslope) >> 8;
99 #endif
100
101                 line = y0 >> 8;
102                 if(line < top) top = line;
103                 if((y1 >> 8) > bot) bot = y1 >> 8;
104
105                 if(line > 0) tab += line;
106
107                 while(line <= (y1 >> 8) && line < pfill_fb.height) {
108                         if(line >= 0) {
109                                 int val = x < 0 ? 0 : x >> 8;
110                                 tab->x = val < pfill_fb.width ? val : pfill_fb.width - 1;
111 #ifdef GOURAUD
112                                 tab->l = lum;
113 #endif  /* GOURAUD */
114 #ifdef TEXMAP
115                                 tab->u = tu;
116                                 tab->v = tv;
117 #endif  /* TEXMAP */
118 #ifdef ZBUF
119                                 tab->z = z;
120 #endif
121                                 tab++;
122                         }
123                         x += slope;
124 #ifdef GOURAUD
125                         lum += lumslope;
126 #endif  /* GOURAUD */
127 #ifdef TEXMAP
128                         tu += uslope;
129                         tv += vslope;
130 #endif  /* TEXMAP */
131 #ifdef ZBUF
132                         z += zslope;
133 #endif  /* ZBUF */
134                         line++;
135                 }
136         }
137
138         if(top < 0) top = 0;
139         if(bot >= pfill_fb.height) bot = pfill_fb.height - 1;
140
141         fbptr = pfill_fb.pixels + top * pfill_fb.width;
142         for(i=top; i<=bot; i++) {
143                 start = left[i].x;
144                 len = right[i].x - start;
145                 /* XXX we probably need more precision in left/right.x */
146
147 #ifndef NOLERP
148                 dx = len == 0 ? 256 : (len << 8);
149 #endif
150
151 #ifdef GOURAUD
152                 lum = left[i].l;
153 #endif  /* GOURAUD */
154 #ifdef TEXMAP
155                 tu = left[i].u;
156                 tv = left[i].v;
157 #endif  /* TEXMAP */
158 #ifdef ZBUF
159                 z = left[i].z;
160                 zptr = pfill_zbuf + i * pfill_fb.width + start;
161 #endif  /* ZBUF */
162
163                 pptr = fbptr + start;
164                 while(len-- > 0) {
165 #if defined(GOURAUD) || defined(TEXMAP)
166                         int inten;
167 #endif
168 #ifdef ZBUF
169                         uint32_t cz = z;
170                         z += pgrad.dzdx;
171
172                         if(cz <= *zptr) {
173                                 *zptr++ = cz;
174                         } else {
175                                 /* ZFAIL: advance all attributes and continue */
176 #ifdef GOURAUD
177                                 lum += pgrad.dldx;
178 #endif  /* GOURAUD */
179 #ifdef TEXMAP
180                                 tu += pgrad.dudx;
181                                 tv += pgrad.dvdx;
182 #endif  /* TEXMAP */
183                                 /* skip pixel */
184                                 pptr++;
185                                 zptr++;
186                                 continue;
187                         }
188 #endif  /* ZBUF */
189
190 #ifdef GOURAUD
191                         /* we upped the color precision to while interpolating the
192                          * edges, now drop the extra bits before packing
193                          */
194                         inten = lum < 0 ? 0 : (lum >> COLOR_SHIFT);
195                         lum += pgrad.dldx;
196 #endif  /* GOURAUD */
197 #ifdef TEXMAP
198                         tx = (tu >> (16 - pfill_tex.xshift)) & pfill_tex.xmask;
199                         ty = (tv >> (16 - pfill_tex.yshift)) & pfill_tex.ymask;
200                         texel = pfill_tex.pixels[(ty << pfill_tex.xshift) + tx];
201
202                         tu += pgrad.dudx;
203                         tv += pgrad.dvdx;
204
205 #ifndef GOURAUD
206                         /* for flat textured, cr,cg,cb would not be initialized */
207                         inten = varr[0].l;
208 #endif  /* !GOURAUD */
209                         /* This is not correct, should be /255, but it's much faster
210                          * to shift by 8 (/256), and won't make a huge difference
211                          */
212                         color = shade_color(texel, inten);
213 #endif  /* TEXMAP */
214
215 #ifdef DEBUG_OVERDRAW
216                         *pptr++ += DEBUG_OVERDRAW;
217 #else
218 #if defined(GOURAUD) || defined(TEXMAP)
219                         if(inten >= 255) inten = 255;
220                         color = find_color(inten, inten, inten);
221 #endif
222                         *pptr++ = color;
223 #endif
224                 }
225                 fbptr += pfill_fb.width;
226         }
227 }
228
229 #undef NOLERP