awasm: new code file format; fixes for (g|t)vars
[awish.git] / src / polymod.c
blob666055093be410cdab80d587f6a0b632cb45e077
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 pangle;
46 static int vertexnum;
49 void polymodInitialize (void) {
50 for (int f = 0; f < 200; ++f) polyScans[f] = -1;
51 polyPointPool = NULL;
52 polyPointPoolSize = 0;
53 polyPointPoolPos = 0;
54 vertexnum = 0;
58 void polymodDeinitialize (void) {
59 if (polyPointPool != NULL) free(polyPointPool);
60 polyPointPool = NULL;
61 polyPointPoolSize = 0;
62 polyPointPoolPos = 0;
63 vertexnum = 0;
67 static inline int allocPolyPoint (int x, int next, int dy) {
68 if (polyPointPoolPos+1 > polyPointPoolSize) {
69 int newsz = polyPointPoolSize+8192;
70 PolyPoint *nn = realloc(polyPointPool, sizeof(PolyPoint)*newsz);
72 if (nn == NULL) fatal("out of memory in polymod");
73 polyPointPool = nn;
74 polyPointPoolSize = newsz;
76 polyPointPool[polyPointPoolPos].x = x;
77 polyPointPool[polyPointPoolPos].next = next;
78 polyPointPool[polyPointPoolPos].dy = dy;
79 polyPointPool[polyPointPoolPos].vertexnum = vertexnum;
80 return polyPointPoolPos++;
84 static inline void insertPoint (int x, int y, int dy) {
85 if (y >= 0 && y < 200) {
86 int n;
88 if ((n = polyScans[y]) != -1) {
89 int p;
91 for (p = -1; n != -1 && x > polyPointPool[n].x; p = n, n = polyPointPool[n].next) ;
92 if (p == -1) {
93 // this is new first point
94 polyScans[y] = allocPolyPoint(x, n, dy);
95 } else {
96 // insert new point after p; n is the next point
97 polyPointPool[p].next = allocPolyPoint(x, n, dy);
99 } else {
100 // first
101 polyScans[y] = allocPolyPoint(x, -1, dy);
108 static inline void rotate (int *x, int *y) {
109 int64_t tx = (int64_t)(*x)*pscale/POLYFIX_BASE;
110 int64_t ty = (int64_t)(*y)*pscale/POLYFIX_BASE;
111 *x = (tx*costab[pangle]-ty*sintab[pangle])/POLYFIX_BASE+pofsx;
112 *y = (tx*sintab[pangle]+ty*costab[pangle])/POLYFIX_BASE+pofsy;
115 #define rotate(x, y) do { \
116 int64_t tx = (int64_t)(x)*pscale/POLYFIX_BASE; \
117 int64_t ty = (int64_t)(y)*pscale/POLYFIX_BASE; \
118 (x) = (tx*costab[pangle]-ty*sintab[pangle])/POLYFIX_BASE+pofsx; \
119 (y) = (tx*sintab[pangle]+ty*costab[pangle])/POLYFIX_BASE+pofsy; \
120 } while (0)
123 static void lineDDA (int x0, int y0, int x1, int y1) {
124 double x, dx;
127 rotate(&x0, &y0);
128 rotate(&x1, &y1);
130 rotate(x0, y0);
131 rotate(x1, y1);
133 if (fdump) fprintf(fdump, "%d: (%d,%d)-(%d,%d)\n", vertexnum, x0, y0, x1, y1);
135 if (y0 == y1) return; // horizontal line
137 //fprintf(stderr, "*(%d,%d)-(%d,%d)\n", x0, y0, x1, y1);
138 if ((y0 < 0 && y1 < 0) || (y0 > 199 && y1 > 199)) return; // out-of-screen lines aren't interesting
140 if (x0 == x1) {
141 // straight vertical line
142 if (y0 < y1) {
143 for (; y0 < y1; ++y0) insertPoint(x0, y0, 1);
144 } else {
145 for (--y0; y0 >= y1; --y0) insertPoint(x0, y0, -1);
147 } else {
148 // draw sloped
149 x = x0;
150 if (y0 < y1) {
151 dx = (double)(x1-x0)/(double)(y1-y0);
152 for (; y0 < y1; ++y0) { insertPoint(x+0.5, y0, 1); x += dx; }
153 } else {
154 dx = (double)(x1-x0)/(double)(y0-y1);
155 for (--y0; y0 >= y1; --y0) { insertPoint(x+0.5, y0, -1); x += dx; }
161 void polymodStart (int ofsx, int ofsy, int scale, int angle) {
162 for (int f = 0; f < 200; ++f) polyScans[f] = -1;
163 polyPointPoolPos = 0;
164 pofsx = ofsx;
165 pofsy = ofsy;
166 pscale = scale;
167 while (angle < 0) angle += 360; // hehe
168 pangle = angle%360;
169 if (polyDump) {
170 fdump = fopen("zdump.txt", "w");
172 vertexnum = -1;
176 void polymodAddPoint (int x, int y) {
177 ++vertexnum;
178 if (vertexnum > 0) {
179 lineDDA(lastX, lastY, x, y);
180 } else {
181 firstX = x;
182 firstY = y;
184 lastX = x;
185 lastY = y;
189 void polymodEnd (void) {
190 if (vertexnum >= 3) {
191 ++vertexnum;
192 lineDDA(lastX, lastY, firstX, firstY);
193 } else {
194 for (int f = 0; f < 200; ++f) polyScans[f] = -1;
199 void polymodFill (SDL_Surface *frame, Uint8 color, Uint8 alpha) {
200 if (fdump) {
201 fprintf(fdump, "=========================\n");
202 for (int y = 0; y < 200; ++y) {
203 int p = polyScans[y], cnt = 0;
205 if (p < 0) continue;
206 fprintf(fdump, "y: %d\n", y);
207 while (p >= 0) {
208 fprintf(fdump, " x: %d (%d) [%d]\n", polyPointPool[p].x, polyPointPool[p].dy, polyPointPool[p].vertexnum);
209 p = polyPointPool[p].next;
210 ++cnt;
212 if (cnt%2) fprintf(fdump, " ***\n");
215 for (int y = 0; y < 200; ++y) {
216 int p = polyScans[y];
218 if (p >= 0) {
219 int wind = polyPointPool[p].dy, x = polyPointPool[p].x;
221 for (p = polyPointPool[p].next; p != -1; p = polyPointPool[p].next) {
222 int ex = polyPointPool[p].x;
224 if (wind != 0) {
225 while (x++ < ex) putPixelA2x(frame, x, y, color, alpha);
226 } else {
227 x = ex;
229 if (polyPointPool[p].dy < 0) putPixelA2x(frame, x, y, color, alpha);
230 wind += polyPointPool[p].dy;
234 if (polyDump) {
235 if (fdump != NULL) fclose(fdump);
236 fdump = NULL;
237 polyDump = 0;