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