gbasys

annotate src/gfx.c @ 12:a6ddf338a111

line clipping
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 01 Feb 2016 04:41:27 +0200
parents 85f219fcdc82
children
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 }