rev |
line source |
nuclear@5
|
1 #include "config.h"
|
nuclear@5
|
2 #include <string.h>
|
nuclear@6
|
3 #include <assert.h>
|
nuclear@5
|
4 #include "polyfill.h"
|
nuclear@5
|
5 #include "fixed.h"
|
nuclear@5
|
6 #include "gbasys.h"
|
nuclear@5
|
7
|
nuclear@9
|
8 #define VNEXT(x, n) (((x) + 1) % (n))
|
nuclear@9
|
9 #define VPREV(x, n) ((x) > 0 ? (x) - 1 : (n) - 1)
|
nuclear@9
|
10
|
nuclear@9
|
11 static void fill_scanline_pal(int y, int x0, int x1, uint8_t color);
|
nuclear@9
|
12 static void fill_scanline_rgb(int y, int x0, int x1, uint16_t color);
|
nuclear@14
|
13 static int winding(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
|
nuclear@5
|
14
|
nuclear@5
|
15 void draw_poly(int num, const pvec3 *verts, uint16_t color)
|
nuclear@5
|
16 {
|
nuclear@5
|
17 int i, topidx = 0, botidx = 0;
|
nuclear@9
|
18 int lidx[2] = {-1, -1}, ridx[2] = {-1, -1};
|
nuclear@5
|
19 int32_t y, topy, boty;
|
nuclear@9
|
20 int32_t ldy = 0, rdy = 0, ldxdy, rdxdy;
|
nuclear@5
|
21 int32_t lx, rx;
|
nuclear@5
|
22 int start, end;
|
nuclear@14
|
23 pvec3 v0, v1;
|
nuclear@14
|
24
|
nuclear@14
|
25 v0.x = verts[1].x - verts[0].x;
|
nuclear@14
|
26 v0.y = verts[1].y - verts[0].y;
|
nuclear@14
|
27
|
nuclear@14
|
28 v1.x = verts[2].x - verts[0].x;
|
nuclear@14
|
29 v1.y = verts[2].y - verts[0].y;
|
nuclear@14
|
30
|
nuclear@14
|
31 if(winding(v0.x, v0.y, v1.x, v1.y) < 0) {
|
nuclear@14
|
32 return; /* backface */
|
nuclear@14
|
33 }
|
nuclear@5
|
34
|
nuclear@5
|
35 topy = boty = verts[0].y;
|
nuclear@5
|
36 for(i=1; i<num; i++) {
|
nuclear@5
|
37 int32_t y = verts[i].y;
|
nuclear@5
|
38 if(y < topy) {
|
nuclear@5
|
39 topy = y;
|
nuclear@5
|
40 topidx = i;
|
nuclear@5
|
41 }
|
nuclear@5
|
42 if(y > boty) {
|
nuclear@5
|
43 boty = y;
|
nuclear@5
|
44 botidx = i;
|
nuclear@5
|
45 }
|
nuclear@5
|
46 }
|
nuclear@5
|
47
|
nuclear@5
|
48 lidx[0] = ridx[0] = topidx;
|
nuclear@9
|
49
|
nuclear@9
|
50 /* find starting left edge */
|
nuclear@9
|
51 lidx[1] = VPREV(lidx[0], num);
|
nuclear@9
|
52 ldy = verts[lidx[1]].y - verts[lidx[0]].y;
|
nuclear@9
|
53
|
nuclear@9
|
54 while(ldy == 0) {
|
nuclear@9
|
55 lidx[0] = lidx[1];
|
nuclear@9
|
56 lidx[1] = VPREV(lidx[1], num);
|
nuclear@9
|
57
|
nuclear@9
|
58 if(lidx[1] == topidx) {
|
nuclear@9
|
59 return; /* degenerate */
|
nuclear@9
|
60 }
|
nuclear@9
|
61
|
nuclear@9
|
62 ldy = verts[lidx[1]].y - verts[lidx[0]].y;
|
nuclear@9
|
63 }
|
nuclear@9
|
64 lx = verts[lidx[0]].x;
|
nuclear@9
|
65 ldxdy = x16div(verts[lidx[1]].x - lx, ldy);
|
nuclear@9
|
66
|
nuclear@9
|
67 /* find starting right edge */
|
nuclear@9
|
68 ridx[1] = VNEXT(ridx[0], num);
|
nuclear@9
|
69 rdy = verts[ridx[1]].y - verts[ridx[0]].y;
|
nuclear@9
|
70
|
nuclear@9
|
71 while(rdy == 0) {
|
nuclear@9
|
72 ridx[0] = ridx[1];
|
nuclear@9
|
73 ridx[1] = VNEXT(ridx[1], num);
|
nuclear@9
|
74
|
nuclear@9
|
75 if(ridx[1] == topidx) {
|
nuclear@9
|
76 return; /* degenerate */
|
nuclear@9
|
77 }
|
nuclear@9
|
78
|
nuclear@9
|
79 rdy = verts[ridx[1]].y - verts[ridx[0]].y;
|
nuclear@9
|
80 }
|
nuclear@9
|
81 rx = verts[ridx[0]].x;
|
nuclear@9
|
82 rdxdy = x16div(verts[ridx[1]].x - rx, rdy);
|
nuclear@9
|
83
|
nuclear@5
|
84 start = topy >> 16;
|
nuclear@5
|
85 end = boty >> 16;
|
nuclear@5
|
86
|
nuclear@6
|
87 if(end >= HEIGHT) end = HEIGHT - 1;
|
nuclear@6
|
88
|
nuclear@5
|
89 y = topy;
|
nuclear@14
|
90 for(i=start; i<=end; i++) {
|
nuclear@9
|
91 short x0, x1;
|
nuclear@5
|
92
|
nuclear@5
|
93 if(y >= verts[lidx[1]].y) {
|
nuclear@9
|
94 lx = verts[lidx[1]].x;
|
nuclear@5
|
95 lidx[0] = lidx[1];
|
nuclear@9
|
96 lidx[1] = VPREV(lidx[1], num);
|
nuclear@5
|
97 ldy = verts[lidx[1]].y - verts[lidx[0]].y;
|
nuclear@5
|
98 if(ldy < 0) {
|
nuclear@5
|
99 break;
|
nuclear@5
|
100 }
|
nuclear@14
|
101 if(ldy) {
|
nuclear@14
|
102 ldxdy = x16div(verts[lidx[1]].x - lx, ldy);
|
nuclear@14
|
103 } else {
|
nuclear@14
|
104 ldxdy = verts[lidx[1]].x - lx;
|
nuclear@14
|
105 }
|
nuclear@5
|
106 }
|
nuclear@5
|
107 if(y >= verts[ridx[1]].y) {
|
nuclear@9
|
108 rx = verts[ridx[1]].x;
|
nuclear@5
|
109 ridx[0] = ridx[1];
|
nuclear@9
|
110 ridx[1] = VNEXT(ridx[1], num);
|
nuclear@5
|
111 rdy = verts[ridx[1]].y - verts[ridx[0]].y;
|
nuclear@5
|
112 if(rdy < 0) {
|
nuclear@5
|
113 break;
|
nuclear@5
|
114 }
|
nuclear@14
|
115 if(rdy) {
|
nuclear@14
|
116 rdxdy = x16div(verts[ridx[1]].x - rx, rdy);
|
nuclear@14
|
117 } else {
|
nuclear@14
|
118 rdxdy = verts[ridx[1]].x - rx;
|
nuclear@14
|
119 }
|
nuclear@5
|
120 }
|
nuclear@5
|
121
|
nuclear@14
|
122 x0 = lx >> 16;
|
nuclear@14
|
123 x1 = rx >> 16;
|
nuclear@9
|
124
|
nuclear@14
|
125 if(i >= 0) {// && x0 < x1) {
|
nuclear@9
|
126 #ifdef PALMODE
|
nuclear@9
|
127 fill_scanline_pal(i, x0, x1, (uint8_t)color);
|
nuclear@9
|
128 #else
|
nuclear@9
|
129 fill_scanline_rgb(i, x0, x1, color);
|
nuclear@9
|
130 #endif
|
nuclear@9
|
131 }
|
nuclear@9
|
132
|
nuclear@5
|
133 lx += ldxdy;
|
nuclear@5
|
134 rx += rdxdy;
|
nuclear@6
|
135 y += 65536;
|
nuclear@5
|
136 }
|
nuclear@5
|
137 }
|
nuclear@5
|
138
|
nuclear@9
|
139
|
nuclear@9
|
140 static void fill_scanline_pal(int y, int x0, int x1, uint8_t color)
|
nuclear@9
|
141 {
|
nuclear@9
|
142 #if 1
|
nuclear@9
|
143 int i, num_pairs, num_pix = x1 - x0;
|
nuclear@9
|
144 uint16_t *pixels = (uint16_t*)back_buffer->pixels + (y * WIDTH + x0) / 2;
|
nuclear@9
|
145 uint16_t colpair = (uint16_t)color | ((uint16_t)color << 8);
|
nuclear@9
|
146
|
nuclear@9
|
147 if(x0 & 1) {
|
nuclear@9
|
148 uint16_t pix = *pixels & 0xff;
|
nuclear@9
|
149 *pixels++ = pix | ((uint16_t)color << 8);
|
nuclear@9
|
150 --num_pix;
|
nuclear@9
|
151 }
|
nuclear@9
|
152
|
nuclear@9
|
153 num_pairs = (num_pix & 0xfffe) / 2;
|
nuclear@9
|
154
|
nuclear@9
|
155 for(i=0; i<num_pairs; i++) {
|
nuclear@9
|
156 *pixels++ = colpair;
|
nuclear@9
|
157 }
|
nuclear@9
|
158
|
nuclear@9
|
159 if(num_pix & 1) {
|
nuclear@9
|
160 uint16_t pix = *pixels & 0xff00;
|
nuclear@9
|
161 *pixels = pix | color;
|
nuclear@9
|
162 }
|
nuclear@9
|
163 #else
|
nuclear@9
|
164 int i;
|
nuclear@9
|
165 uint8_t *pixels = (uint8_t*)back_buffer->pixels + y * WIDTH + x0;
|
nuclear@9
|
166
|
nuclear@9
|
167 for(i=x0; i<x1; i++) {
|
nuclear@9
|
168 *pixels++ = color;
|
nuclear@9
|
169 }
|
nuclear@9
|
170 #endif
|
nuclear@9
|
171 }
|
nuclear@9
|
172
|
nuclear@9
|
173 static void fill_scanline_rgb(int y, int x0, int x1, uint16_t color)
|
nuclear@5
|
174 {
|
nuclear@5
|
175 int i;
|
nuclear@14
|
176 uint16_t *pixels;
|
nuclear@5
|
177
|
nuclear@14
|
178 if(x0 > x1) {
|
nuclear@14
|
179 i = x0;
|
nuclear@14
|
180 x0 = x1;
|
nuclear@14
|
181 x1 = i;
|
nuclear@14
|
182 }
|
nuclear@14
|
183
|
nuclear@14
|
184 if(x0 < 0) x0 = 0;
|
nuclear@14
|
185 if(x1 >= WIDTH - 1) x1 = WIDTH - 1;
|
nuclear@14
|
186
|
nuclear@14
|
187 pixels = (uint16_t*)back_buffer->pixels + y * WIDTH + x0;
|
nuclear@5
|
188 for(i=x0; i<x1; i++) {
|
nuclear@5
|
189 *pixels++ = color;
|
nuclear@5
|
190 }
|
nuclear@5
|
191 }
|
nuclear@8
|
192
|
nuclear@8
|
193
|
nuclear@8
|
194 void draw_point(const pvec3 *v, uint16_t color)
|
nuclear@8
|
195 {
|
nuclear@8
|
196 int x = v->x >> 16;
|
nuclear@8
|
197 int y = v->y >> 16;
|
nuclear@8
|
198 uint16_t *pixels = (uint16_t*)back_buffer->pixels;
|
nuclear@8
|
199
|
nuclear@8
|
200 if(x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) {
|
nuclear@8
|
201 return;
|
nuclear@8
|
202 }
|
nuclear@8
|
203
|
nuclear@9
|
204 #ifdef PALMODE
|
nuclear@9
|
205 pixels += (y * WIDTH + x) / 2;
|
nuclear@9
|
206 if(x & 1) {
|
nuclear@9
|
207 *pixels = (*pixels & 0xff) | (color << 8);
|
nuclear@9
|
208 } else {
|
nuclear@9
|
209 *pixels = (*pixels & 0xff00) | color;
|
nuclear@9
|
210 }
|
nuclear@9
|
211 #else
|
nuclear@8
|
212 pixels[y * WIDTH + x] = color;
|
nuclear@9
|
213 #endif
|
nuclear@8
|
214 }
|
nuclear@14
|
215
|
nuclear@14
|
216 static int winding(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
|
nuclear@14
|
217 {
|
nuclear@14
|
218 return x16mul(x0, y1) - x16mul(y0, x1);
|
nuclear@14
|
219 }
|