rev |
line source |
nuclear@0
|
1 /*
|
nuclear@7
|
2 gbasys - a gameboy advance hardware abstraction library
|
nuclear@7
|
3 Copyright (C) 2004-2014 John Tsiombikas <nuclear@member.fsf.org>
|
nuclear@0
|
4
|
nuclear@7
|
5 This program is free software: you can redistribute it and/or modify
|
nuclear@0
|
6 it under the terms of the GNU General Public License as published by
|
nuclear@7
|
7 the Free Software Foundation, either version 3 of the License, or
|
nuclear@0
|
8 (at your option) any later version.
|
nuclear@0
|
9
|
nuclear@0
|
10 This program is distributed in the hope that it will be useful,
|
nuclear@0
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nuclear@0
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nuclear@0
|
13 GNU General Public License for more details.
|
nuclear@0
|
14
|
nuclear@0
|
15 You should have received a copy of the GNU General Public License
|
nuclear@7
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
nuclear@0
|
17 */
|
nuclear@1
|
18 #include "config.h"
|
nuclear@0
|
19
|
nuclear@0
|
20 #include <stdlib.h>
|
nuclear@3
|
21 #include <string.h>
|
nuclear@0
|
22 #include "gfx.h"
|
nuclear@0
|
23
|
nuclear@0
|
24 #define FRAME_SEL_BIT 0x10
|
nuclear@0
|
25
|
nuclear@0
|
26 #define H_BLANK_OAM 0x20
|
nuclear@0
|
27 #define OBJ_MAP_2D 0x0
|
nuclear@0
|
28 #define OBJ_MAP_1D 0x40
|
nuclear@0
|
29 #define FORCE_BLANK 0x80
|
nuclear@0
|
30 #define BG0_ENABLE 0x100
|
nuclear@0
|
31 #define BG1_ENABLE 0x200
|
nuclear@0
|
32 #define BG2_ENABLE 0x400
|
nuclear@0
|
33 #define BG3_ENABLE 0x800
|
nuclear@0
|
34
|
nuclear@8
|
35 #define REG_DISPCTL (*(unsigned short*)0x4000000)
|
nuclear@8
|
36 #define REG_VCOUNT (*(unsigned short*)0x4000006)
|
nuclear@8
|
37
|
nuclear@8
|
38 #define REG_BG2PA (*(short*)0x4000020)
|
nuclear@8
|
39 #define REG_BG2PB (*(short*)0x4000022)
|
nuclear@8
|
40 #define REG_BG2PC (*(short*)0x4000024)
|
nuclear@8
|
41 #define REG_BG2PD (*(short*)0x4000026)
|
nuclear@0
|
42
|
nuclear@6
|
43 static unsigned short *paladdr = (void*)0x5000000;
|
nuclear@6
|
44
|
nuclear@0
|
45 static int xres, yres;
|
nuclear@0
|
46 static int sizeof_pixel;
|
nuclear@0
|
47 static int page_flipping;
|
nuclear@0
|
48 static int allocated_back_buffer;
|
nuclear@0
|
49
|
nuclear@0
|
50 static struct pixel_buffer fbuf, bbuf;
|
nuclear@0
|
51 struct pixel_buffer *front_buffer = &fbuf;
|
nuclear@0
|
52 struct pixel_buffer *back_buffer = &bbuf;
|
nuclear@0
|
53
|
nuclear@8
|
54 #define show_page(n) ((n) ? (REG_DISPCTL |= FRAME_SEL_BIT) : (REG_DISPCTL &= ~FRAME_SEL_BIT))
|
nuclear@8
|
55 #define swap_page() (REG_DISPCTL ^= FRAME_SEL_BIT)
|
nuclear@0
|
56
|
nuclear@0
|
57 int set_video_mode(int mode, int double_buffering) {
|
nuclear@0
|
58 if(mode < 3 || mode > 5) return -1;
|
nuclear@0
|
59
|
nuclear@0
|
60 /* mode 5: 160x128, otherwise: 240x160 */
|
nuclear@0
|
61 xres = (mode == 5) ? 160 : 240;
|
nuclear@0
|
62 yres = (mode == 5) ? 128 : 160;
|
nuclear@0
|
63
|
nuclear@0
|
64 sizeof_pixel = (mode == 4) ? 1 : 2;
|
nuclear@0
|
65
|
nuclear@8
|
66 REG_DISPCTL = mode | BG2_ENABLE;
|
nuclear@0
|
67
|
nuclear@0
|
68 show_page(0);
|
nuclear@0
|
69
|
nuclear@0
|
70 if(allocated_back_buffer) {
|
nuclear@0
|
71 free(back_buffer->pixels);
|
nuclear@0
|
72 }
|
nuclear@0
|
73
|
nuclear@0
|
74 front_buffer->pixels = (void*)0x6000000;
|
nuclear@0
|
75 front_buffer->x = back_buffer->x = xres;
|
nuclear@0
|
76 front_buffer->y = back_buffer->y = yres;
|
nuclear@0
|
77 front_buffer->bpp = back_buffer->bpp = sizeof_pixel * 8;
|
nuclear@1
|
78
|
nuclear@0
|
79 if(mode > 3) {
|
nuclear@0
|
80 page_flipping = 1;
|
nuclear@0
|
81 back_buffer->pixels = (void*)0x600a000;
|
nuclear@0
|
82 } else {
|
nuclear@0
|
83 page_flipping = 0;
|
nuclear@0
|
84 if(double_buffering) {
|
nuclear@0
|
85 back_buffer->pixels = malloc(xres * yres * sizeof_pixel);
|
nuclear@0
|
86 }
|
nuclear@0
|
87 }
|
nuclear@0
|
88 }
|
nuclear@0
|
89
|
nuclear@0
|
90 void flip(void) {
|
nuclear@0
|
91 static void *tmp;
|
nuclear@1
|
92
|
nuclear@0
|
93 if(page_flipping) {
|
nuclear@0
|
94 swap_page();
|
nuclear@0
|
95 tmp = front_buffer->pixels;
|
nuclear@0
|
96 front_buffer->pixels = back_buffer->pixels;
|
nuclear@0
|
97 back_buffer->pixels = tmp;
|
nuclear@0
|
98 } else {
|
nuclear@0
|
99 /*dma_copy32(3, front_buffer->pixels, back_buffer->pixels, (xres * yres) >> 1);*/
|
nuclear@0
|
100 dma_copy32(3, front_buffer->pixels, back_buffer->pixels, 19200);
|
nuclear@0
|
101 }
|
nuclear@0
|
102 }
|
nuclear@0
|
103
|
nuclear@0
|
104 /* ------- pixel buffer operations ------- */
|
nuclear@0
|
105
|
nuclear@0
|
106 struct pixel_buffer *create_pixel_buffer(int x, int y, int bpp) {
|
nuclear@0
|
107 struct pixel_buffer *pbuf = malloc(sizeof(struct pixel_buffer));
|
nuclear@0
|
108 if(pbuf) {
|
nuclear@0
|
109 pbuf->pixels = malloc(x * y * bpp / 8);
|
nuclear@0
|
110 pbuf->x = x;
|
nuclear@0
|
111 pbuf->y = y;
|
nuclear@0
|
112 pbuf->bpp = bpp;
|
nuclear@0
|
113 }
|
nuclear@0
|
114 return pbuf;
|
nuclear@0
|
115 }
|
nuclear@0
|
116
|
nuclear@0
|
117 void destroy_pixel_buffer(struct pixel_buffer *pbuf) {
|
nuclear@0
|
118 free(pbuf->pixels);
|
nuclear@0
|
119 free(pbuf);
|
nuclear@0
|
120 }
|
nuclear@0
|
121
|
nuclear@0
|
122 void clear_buffer(struct pixel_buffer *pbuf, unsigned short color) {
|
nuclear@0
|
123 int sz = pbuf->x * pbuf->y;
|
nuclear@0
|
124
|
nuclear@0
|
125 if(pbuf->bpp == 8) {
|
nuclear@0
|
126 color |= color << 8;
|
nuclear@0
|
127 sz >>= 1;
|
nuclear@0
|
128 }
|
nuclear@1
|
129
|
nuclear@0
|
130 dma_fill16(3, pbuf->pixels, color, sz);
|
nuclear@0
|
131 }
|
nuclear@0
|
132
|
nuclear@0
|
133 void copy_buffer(const struct pixel_buffer *src, struct pixel_buffer *dst) {
|
nuclear@0
|
134 int words;
|
nuclear@1
|
135
|
nuclear@0
|
136 if(src->x != dst->x || src->y != dst->y || src->bpp != dst->bpp) return;
|
nuclear@0
|
137
|
nuclear@0
|
138 words = (src->x * src->y) >> (src->bpp == 16 ? 1 : 2);
|
nuclear@0
|
139 dma_copy32(3, dst->pixels, src->pixels, words);
|
nuclear@0
|
140 }
|
nuclear@0
|
141
|
nuclear@3
|
142 #define MIN(a, b) ((a) < (b) ? (a) : (b))
|
nuclear@3
|
143
|
nuclear@3
|
144 void blit(struct pixel_buffer *src, int src_x, int src_y, int src_w, int src_h,
|
nuclear@3
|
145 struct pixel_buffer *dst, int dst_x, int dst_y)
|
nuclear@3
|
146 {
|
nuclear@3
|
147 int i, pixsize, width, height, dstride, sstride;
|
nuclear@3
|
148 unsigned char *dptr, *sptr;
|
nuclear@3
|
149
|
nuclear@3
|
150 if(dst->bpp != src->bpp)
|
nuclear@3
|
151 return;
|
nuclear@3
|
152
|
nuclear@3
|
153 if(src_w <= 0)
|
nuclear@3
|
154 src_w = src->x;
|
nuclear@3
|
155 if(src_h <= 0)
|
nuclear@3
|
156 src_h = src->y;
|
nuclear@3
|
157
|
nuclear@3
|
158 width = MIN(src_w, MIN(src->x - src_x, dst->x - dst_x));
|
nuclear@3
|
159 height = MIN(src_h, MIN(src->y - src_y, dst->y - dst_y));
|
nuclear@3
|
160
|
nuclear@3
|
161 if(width <= 0 || height <= 0)
|
nuclear@3
|
162 return;
|
nuclear@3
|
163
|
nuclear@3
|
164 pixsize = dst->bpp / 8;
|
nuclear@3
|
165 dptr = (unsigned char*)dst->pixels + (dst_y * dst->x + dst_x) * pixsize;
|
nuclear@3
|
166 sptr = (unsigned char*)src->pixels + (src_y * src->x + src_x) * pixsize;
|
nuclear@3
|
167
|
nuclear@3
|
168 dstride = dst->x * pixsize;
|
nuclear@3
|
169 sstride = src->x * pixsize;
|
nuclear@3
|
170
|
nuclear@3
|
171 for(i=0; i<height; i++) {
|
nuclear@3
|
172 memcpy(dptr, sptr, width * pixsize);
|
nuclear@3
|
173 sptr += sstride;
|
nuclear@3
|
174 dptr += dstride;
|
nuclear@3
|
175 }
|
nuclear@3
|
176 }
|
nuclear@3
|
177
|
nuclear@6
|
178 void set_palette(int idx, int r, int g, int b)
|
nuclear@6
|
179 {
|
nuclear@6
|
180 paladdr[idx] = RGB(r, g, b);
|
nuclear@6
|
181 }
|
nuclear@0
|
182
|
nuclear@8
|
183 void set_bg_matrix(int a, int b, int c, int d)
|
nuclear@8
|
184 {
|
nuclear@8
|
185 REG_BG2PA = a;
|
nuclear@8
|
186 REG_BG2PB = b;
|
nuclear@8
|
187 REG_BG2PC = c;
|
nuclear@8
|
188 REG_BG2PD = d;
|
nuclear@8
|
189 }
|
nuclear@8
|
190
|
nuclear@8
|
191 void set_bg_scale(int x, int y)
|
nuclear@8
|
192 {
|
nuclear@8
|
193 set_bg_matrix(x, 0, 0, y);
|
nuclear@8
|
194 }
|
nuclear@8
|
195
|
nuclear@0
|
196 void draw_line(int x1, int y1, int x2, int y2, unsigned short col, struct pixel_buffer *pbuf) {
|
nuclear@0
|
197 int dx, dy, dx2, dy2;
|
nuclear@0
|
198 int x_inc, y_inc;
|
nuclear@0
|
199 int error;
|
nuclear@0
|
200 int i;
|
nuclear@0
|
201 unsigned short *ptr = pbuf->pixels;
|
nuclear@0
|
202
|
nuclear@0
|
203 ptr += y1 * pbuf->x + x1;
|
nuclear@0
|
204 dx = x2 - x1;
|
nuclear@0
|
205 dy = y2 - y1;
|
nuclear@1
|
206
|
nuclear@0
|
207 if(dx >= 0) {
|
nuclear@0
|
208 x_inc = 1;
|
nuclear@0
|
209 } else {
|
nuclear@0
|
210 x_inc = -1;
|
nuclear@0
|
211 dx = -dx;
|
nuclear@0
|
212 }
|
nuclear@1
|
213
|
nuclear@0
|
214 if(dy >= 0) {
|
nuclear@0
|
215 y_inc = pbuf->x;
|
nuclear@0
|
216 } else {
|
nuclear@0
|
217 y_inc = -pbuf->x;
|
nuclear@0
|
218 dy = -dy;
|
nuclear@0
|
219 }
|
nuclear@1
|
220
|
nuclear@0
|
221 dx2 = dx << 1;
|
nuclear@0
|
222 dy2 = dy << 1;
|
nuclear@0
|
223
|
nuclear@0
|
224 if(dx > dy) {
|
nuclear@0
|
225 error = dy2 - dx;
|
nuclear@0
|
226 for(i=0; i<=dx; i++) {
|
nuclear@0
|
227 *ptr = col;
|
nuclear@0
|
228 if(error >= 0) {
|
nuclear@0
|
229 error -= dx2;
|
nuclear@0
|
230 ptr += y_inc;
|
nuclear@0
|
231 }
|
nuclear@0
|
232 error += dy2;
|
nuclear@0
|
233 ptr += x_inc;
|
nuclear@0
|
234 }
|
nuclear@0
|
235 } else {
|
nuclear@0
|
236 error = dx2 - dy;
|
nuclear@0
|
237 for(i=0;i<=dy;i++) {
|
nuclear@0
|
238 *ptr = col;
|
nuclear@0
|
239 if(error >= 0) {
|
nuclear@0
|
240 error -= dy2;
|
nuclear@0
|
241 ptr += x_inc;
|
nuclear@0
|
242 }
|
nuclear@0
|
243 error += dx2;
|
nuclear@0
|
244 ptr += y_inc;
|
nuclear@0
|
245 }
|
nuclear@0
|
246 }
|
nuclear@0
|
247 }
|
nuclear@12
|
248
|
nuclear@12
|
249 enum {
|
nuclear@12
|
250 OUT_L = 1,
|
nuclear@12
|
251 OUT_R = 2,
|
nuclear@12
|
252 OUT_T = 4,
|
nuclear@12
|
253 OUT_B = 8
|
nuclear@12
|
254 };
|
nuclear@12
|
255 static unsigned int outcode(int x, int y, int left, int top, int right, int bot)
|
nuclear@12
|
256 {
|
nuclear@12
|
257 unsigned int res = 0;
|
nuclear@12
|
258 if(x < left) res |= OUT_L;
|
nuclear@12
|
259 if(x > right) res |= OUT_R;
|
nuclear@12
|
260 if(y < top) res |= OUT_T;
|
nuclear@12
|
261 if(y > bot) res |= OUT_B;
|
nuclear@12
|
262 return res;
|
nuclear@12
|
263 }
|
nuclear@12
|
264
|
nuclear@12
|
265 int clip_line(int *x1, int *y1, int *x2, int *y2, int left, int top, int right, int bot)
|
nuclear@12
|
266 {
|
nuclear@12
|
267 int i;
|
nuclear@12
|
268 unsigned int out1, out2;
|
nuclear@12
|
269
|
nuclear@12
|
270 --right;
|
nuclear@12
|
271 --bot;
|
nuclear@12
|
272 out1 = outcode(*x1, *y1, left, top, right, bot);
|
nuclear@12
|
273 out2 = outcode(*x2, *y2, left, top, right, bot);
|
nuclear@12
|
274
|
nuclear@12
|
275 for(;;) {
|
nuclear@12
|
276 int x, y;
|
nuclear@12
|
277 unsigned int outout;
|
nuclear@12
|
278
|
nuclear@12
|
279 if((out1 | out2) == 0)
|
nuclear@12
|
280 return 1; /* both inside */
|
nuclear@12
|
281 if(out1 & out2)
|
nuclear@12
|
282 return 0; /* both outside in the same area */
|
nuclear@12
|
283
|
nuclear@12
|
284 outout = out1 ? out1 : out2;
|
nuclear@12
|
285 if(outout & OUT_T) {
|
nuclear@12
|
286 x = *x1 + (float)(*x2 - *x1) * (float)(top - *y1) / (float)(*y2 - *y1);
|
nuclear@12
|
287 y = top;
|
nuclear@12
|
288 } else if(outout & OUT_B) {
|
nuclear@12
|
289 x = *x1 + (float)(*x2 - *x1) * (float)(bot - *y1) / (float)(*y2 - *y1);
|
nuclear@12
|
290 y = bot;
|
nuclear@12
|
291 } else if(outout & OUT_R) {
|
nuclear@12
|
292 y = *y1 + (float)(*y2 - *y1) * (float)(right - *x1) / (float)(*x2 - *x1);
|
nuclear@12
|
293 x = right;
|
nuclear@12
|
294 } else if(outout & OUT_L) {
|
nuclear@12
|
295 y = *y1 + (float)(*y2 - *y1) * (float)(left - *x1) / (float)(*x2 - *x1);
|
nuclear@12
|
296 x = left;
|
nuclear@12
|
297 }
|
nuclear@12
|
298
|
nuclear@12
|
299 if(out1) {
|
nuclear@12
|
300 *x1 = x;
|
nuclear@12
|
301 *y1 = y;
|
nuclear@12
|
302 out1 = outcode(*x1, *y1, left, top, right, bot);
|
nuclear@12
|
303 } else {
|
nuclear@12
|
304 *x2 = x;
|
nuclear@12
|
305 *y2 = y;
|
nuclear@12
|
306 out2 = outcode(*x2, *y2, left, top, right, bot);
|
nuclear@12
|
307 }
|
nuclear@12
|
308 }
|
nuclear@12
|
309 return 1;
|
nuclear@12
|
310 }
|