removed costab
[awish.git] / src / polymod.c
blob3c96b117b831014a992435124d42ccf3fc0e4ea2
1 /*
2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation, either version 3 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 #include "polymod.h"
17 #include <stdint.h>
19 #include "video.h"
20 #include "gameglobals.h"
22 #include "sincostab.c"
25 int polyDump = 0;
26 static FILE *fdump = NULL;
29 typedef struct PolyPoint {
30 int vertexnum;
31 int dy;
32 int next; // -1: none
33 int x;
34 } PolyPoint;
37 static int polyPointPoolSize = 0;
38 static int polyPointPoolPos = 0;
39 static PolyPoint *polyPointPool = NULL;
40 static int polyScans[200]; // index of the first point of each scan; -1: none
41 static int firstX, firstY;
42 static int lastX, lastY;
43 static int pofsx, pofsy;
44 static int pscale;
45 static int pangles;
46 static int panglec;
47 static int vertexnum;
50 void polymodInitialize (void) {
51 for (int f = 0; f < 200; ++f) polyScans[f] = -1;
52 polyPointPool = NULL;
53 polyPointPoolSize = 0;
54 polyPointPoolPos = 0;
55 vertexnum = 0;
59 void polymodDeinitialize (void) {
60 if (polyPointPool != NULL) free(polyPointPool);
61 polyPointPool = NULL;
62 polyPointPoolSize = 0;
63 polyPointPoolPos = 0;
64 vertexnum = 0;
68 static inline int allocPolyPoint (int x, int next, int dy) {
69 if (polyPointPoolPos+1 > polyPointPoolSize) {
70 int newsz = polyPointPoolSize+8192;
71 PolyPoint *nn = realloc(polyPointPool, sizeof(PolyPoint)*newsz);
73 if (nn == NULL) fatal("out of memory in polymod");
74 polyPointPool = nn;
75 polyPointPoolSize = newsz;
77 polyPointPool[polyPointPoolPos].x = x;
78 polyPointPool[polyPointPoolPos].next = next;
79 polyPointPool[polyPointPoolPos].dy = dy;
80 polyPointPool[polyPointPoolPos].vertexnum = vertexnum;
81 return polyPointPoolPos++;
85 static inline void insertPoint (int x, int y, int dy) {
86 if (y >= 0 && y < 200) {
87 int n;
89 if ((n = polyScans[y]) != -1) {
90 int p;
92 for (p = -1; n != -1 && x > polyPointPool[n].x; p = n, n = polyPointPool[n].next) ;
93 if (p == -1) {
94 // this is new first point
95 polyScans[y] = allocPolyPoint(x, n, dy);
96 } else {
97 // insert new point after p; n is the next point
98 polyPointPool[p].next = allocPolyPoint(x, n, dy);
100 } else {
101 // first
102 polyScans[y] = allocPolyPoint(x, -1, dy);
109 static inline void rotate (int *x, int *y) {
110 int64_t tx = (int64_t)(*x)*pscale/POLYFIX_BASE;
111 int64_t ty = (int64_t)(*y)*pscale/POLYFIX_BASE;
112 *x = (tx*costab[pangle]-ty*sintab[pangle])/POLYFIX_BASE+pofsx;
113 *y = (tx*sintab[pangle]+ty*costab[pangle])/POLYFIX_BASE+pofsy;
117 #define rotate(x, y) do { \
118 int64_t tx = (int64_t)(x)*pscale/POLYFIX_BASE; \
119 int64_t ty = (int64_t)(y)*pscale/POLYFIX_BASE; \
120 (x) = (tx*costab[pangle]-ty*sintab[pangle])/POLYFIX_BASE+pofsx; \
121 (y) = (tx*sintab[pangle]+ty*costab[pangle])/POLYFIX_BASE+pofsy; \
122 } while (0)
124 #define rotate(x, y) do { \
125 int64_t tx = (int64_t)(x)*pscale/POLYFIX_BASE; \
126 int64_t ty = (int64_t)(y)*pscale/POLYFIX_BASE; \
127 (x) = (tx*sintab[panglec]-ty*sintab[pangles])/POLYFIX_BASE+pofsx; \
128 (y) = (tx*sintab[pangles]+ty*sintab[panglec])/POLYFIX_BASE+pofsy; \
129 } while (0)
132 static void lineDDA (int x0, int y0, int x1, int y1) {
133 double x, dx;
136 rotate(&x0, &y0);
137 rotate(&x1, &y1);
139 rotate(x0, y0);
140 rotate(x1, y1);
142 if (fdump) fprintf(fdump, "%d: (%d,%d)-(%d,%d)\n", vertexnum, x0, y0, x1, y1);
144 if (y0 == y1) return; // horizontal line
146 //fprintf(stderr, "*(%d,%d)-(%d,%d)\n", x0, y0, x1, y1);
147 if ((y0 < 0 && y1 < 0) || (y0 > 199 && y1 > 199)) return; // out-of-screen lines aren't interesting
149 if (x0 == x1) {
150 // straight vertical line
151 if (y0 < y1) {
152 for (; y0 < y1; ++y0) insertPoint(x0, y0, 1);
153 } else {
154 for (--y0; y0 >= y1; --y0) insertPoint(x0, y0, -1);
156 } else {
157 // draw sloped
158 x = x0;
159 if (y0 < y1) {
160 dx = (double)(x1-x0)/(double)(y1-y0);
161 for (; y0 < y1; ++y0) { insertPoint(x+0.5, y0, 1); x += dx; }
162 } else {
163 dx = (double)(x1-x0)/(double)(y0-y1);
164 for (--y0; y0 >= y1; --y0) { insertPoint(x+0.5, y0, -1); x += dx; }
170 void polymodStart (int ofsx, int ofsy, int scale, int angle) {
171 for (int f = 0; f < 200; ++f) polyScans[f] = -1;
172 polyPointPoolPos = 0;
173 pofsx = ofsx;
174 pofsy = ofsy;
175 pscale = scale;
176 angle %= 360; if (angle < 0) angle += 360;
177 pangles = angle;
178 panglec = (angle+90)%360;
179 if (polyDump) {
180 fdump = fopen("zdump.txt", "w");
182 vertexnum = 0;
186 void polymodAddPoint (int x, int y) {
187 if (vertexnum > 0) {
188 lineDDA(lastX, lastY, x, y);
189 } else {
190 firstX = x;
191 firstY = y;
193 lastX = x;
194 lastY = y;
195 ++vertexnum;
199 void polymodEnd (void) {
200 if (vertexnum >= 3) {
201 lineDDA(lastX, lastY, firstX, firstY);
202 } else {
203 for (int f = 0; f < 200; ++f) polyScans[f] = -1;
208 static void drawLine (SDL_Surface *frame, int x0, int y0, int x1, int y1, Uint8 color, Uint8 alpha) {
209 int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
210 int dy = -abs(y1-y0), sy = y0<y1 ? 1 : -1;
211 int err = dx+dy, e2; /* error value e_xy */
212 for (;;) {
213 //if (x0 == x1 && y0 == y1) break; // break first, so last point is not drawn
214 putPixelA2x(frame, x0, y0, color, alpha);
215 if (x0 == x1 && y0 == y1) break;
216 e2 = 2*err;
217 if (e2 >= dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
218 if (e2 <= dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
223 void polymodFill (SDL_Surface *frame, Uint8 color, Uint8 alpha) {
224 //fprintf(stderr, "vertexnum=%d\n", vertexnum);
225 if (vertexnum < 1) return;
226 if (fdump) {
227 fprintf(fdump, "=========================\n");
228 for (int y = 0; y < 200; ++y) {
229 int p = polyScans[y], cnt = 0;
231 if (p < 0) continue;
232 fprintf(fdump, "y: %d\n", y);
233 while (p >= 0) {
234 fprintf(fdump, " x: %d (%d) [%d]\n", polyPointPool[p].x, polyPointPool[p].dy, polyPointPool[p].vertexnum);
235 p = polyPointPool[p].next;
236 ++cnt;
238 if (cnt%2) fprintf(fdump, " ***\n");
242 if (vertexnum == 1) {
243 rotate(firstX, firstY);
244 putPixelA2x(frame, firstX, firstY, color, alpha);
245 return;
248 if (vertexnum == 2) {
249 rotate(firstX, firstY);
250 rotate(lastX, lastY);
251 //fprintf(stderr, "(%d,%d)-(%d,%d)\n", firstX, firstY, lastX, lastY);
252 drawLine(frame, firstX, firstY, lastX, lastY, color, alpha);
253 return;
256 for (int y = 0; y < 200; ++y) {
257 int p = polyScans[y];
259 if (p >= 0) {
260 int wind = polyPointPool[p].dy, x = polyPointPool[p].x;
262 for (p = polyPointPool[p].next; p != -1; p = polyPointPool[p].next) {
263 int ex = polyPointPool[p].x;
265 if (wind != 0) {
266 while (x++ < ex) putPixelA2x(frame, x, y, color, alpha);
267 } else {
268 x = ex;
270 if (polyPointPool[p].dy < 0) putPixelA2x(frame, x, y, color, alpha);
271 wind += polyPointPool[p].dy;
275 if (polyDump) {
276 if (fdump != NULL) fclose(fdump);
277 fdump = NULL;
278 polyDump = 0;
283 // returns next ofsx
284 static int polymodStrokes (const signed char *data, int len, SDL_Surface *frame, int ofsx, int ofsy, int scale, int angle, Uint8 color, Uint8 alpha) {
285 int res = data[2];
286 int pendown = 0;
287 // skip dimensions
288 //fprintf(stderr, "len=%d\n", len);
289 len /= 2;
290 data += 3;
291 --len;
292 while (len-- > 0) {
293 if (data[0] == -128 && data[1] == -128) {
295 if (pendown) {
296 polymodStart(ofsx, ofsy, scale, angle);
297 polymodAddPoint(data[-2], data[-1]);
298 polymodEnd();
299 polymodFill(frame, color, alpha);
302 pendown = 0;
303 } else {
304 if (pendown) {
305 //fprintf(stderr, " %d: (%d,%d)-(%d,%d)\n", len, data[-2], data[-1], data[0], data[1]);
306 polymodStart(ofsx, ofsy, scale, angle);
307 polymodAddPoint(data[-2], data[-1]);
308 polymodAddPoint(data[0], data[1]);
309 polymodEnd();
310 polymodFill(frame, color, alpha);
311 } else {
312 pendown = 1;
315 data += 2;
318 if (pendown) {
319 polymodStart(ofsx, ofsy, scale, angle);
320 polymodAddPoint(data[-2], data[-1]);
321 polymodEnd();
322 polymodFill(frame, color, alpha);
325 return res;
329 #include "hfont.c"
331 int polymodChar (SDL_Surface *frame, int ch, int ofsx, int ofsy, int scale, int angle, Uint8 color, Uint8 alpha) {
332 if (ch < ' ' || ch > 127) return 0;
333 return polymodStrokes(hfData+hfInfo[ch-32], hfInfo[ch-31]-hfInfo[ch-32], frame, ofsx, ofsy, scale, angle, color, alpha);
337 void polymodStr (SDL_Surface *frame, const char *str, int ofsx, int ofsy, int scale, int angle, Uint8 color, Uint8 alpha) {
338 while (*str) {
339 int w, x0, y0;
341 w = polymodChar(frame, *str++, ofsx, ofsy, scale, angle, color, alpha);
342 x0 = w;
343 y0 = 0;
344 pofsx = pofsy = 0;
345 rotate(x0, y0);
346 ofsx += x0;
347 ofsy += y0;