nuclear@0: /* nuclear@7: gbasys - a gameboy advance hardware abstraction library nuclear@7: Copyright (C) 2004-2014 John Tsiombikas nuclear@0: nuclear@7: This program is free software: you can redistribute it and/or modify nuclear@0: it under the terms of the GNU General Public License as published by nuclear@7: the Free Software Foundation, either version 3 of the License, or nuclear@0: (at your option) any later version. nuclear@0: nuclear@0: This program is distributed in the hope that it will be useful, nuclear@0: but WITHOUT ANY WARRANTY; without even the implied warranty of nuclear@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nuclear@0: GNU General Public License for more details. nuclear@0: nuclear@0: You should have received a copy of the GNU General Public License nuclear@7: along with this program. If not, see . nuclear@0: */ nuclear@1: #include "config.h" nuclear@0: nuclear@0: #include nuclear@3: #include nuclear@0: #include "gfx.h" nuclear@0: nuclear@0: #define FRAME_SEL_BIT 0x10 nuclear@0: nuclear@0: #define H_BLANK_OAM 0x20 nuclear@0: #define OBJ_MAP_2D 0x0 nuclear@0: #define OBJ_MAP_1D 0x40 nuclear@0: #define FORCE_BLANK 0x80 nuclear@0: #define BG0_ENABLE 0x100 nuclear@0: #define BG1_ENABLE 0x200 nuclear@0: #define BG2_ENABLE 0x400 nuclear@0: #define BG3_ENABLE 0x800 nuclear@0: nuclear@8: #define REG_DISPCTL (*(unsigned short*)0x4000000) nuclear@8: #define REG_VCOUNT (*(unsigned short*)0x4000006) nuclear@8: nuclear@8: #define REG_BG2PA (*(short*)0x4000020) nuclear@8: #define REG_BG2PB (*(short*)0x4000022) nuclear@8: #define REG_BG2PC (*(short*)0x4000024) nuclear@8: #define REG_BG2PD (*(short*)0x4000026) nuclear@0: nuclear@6: static unsigned short *paladdr = (void*)0x5000000; nuclear@6: nuclear@0: static int xres, yres; nuclear@0: static int sizeof_pixel; nuclear@0: static int page_flipping; nuclear@0: static int allocated_back_buffer; nuclear@0: nuclear@0: static struct pixel_buffer fbuf, bbuf; nuclear@0: struct pixel_buffer *front_buffer = &fbuf; nuclear@0: struct pixel_buffer *back_buffer = &bbuf; nuclear@0: nuclear@8: #define show_page(n) ((n) ? (REG_DISPCTL |= FRAME_SEL_BIT) : (REG_DISPCTL &= ~FRAME_SEL_BIT)) nuclear@8: #define swap_page() (REG_DISPCTL ^= FRAME_SEL_BIT) nuclear@0: nuclear@0: int set_video_mode(int mode, int double_buffering) { nuclear@0: if(mode < 3 || mode > 5) return -1; nuclear@0: nuclear@0: /* mode 5: 160x128, otherwise: 240x160 */ nuclear@0: xres = (mode == 5) ? 160 : 240; nuclear@0: yres = (mode == 5) ? 128 : 160; nuclear@0: nuclear@0: sizeof_pixel = (mode == 4) ? 1 : 2; nuclear@0: nuclear@8: REG_DISPCTL = mode | BG2_ENABLE; nuclear@0: nuclear@0: show_page(0); nuclear@0: nuclear@0: if(allocated_back_buffer) { nuclear@0: free(back_buffer->pixels); nuclear@0: } nuclear@0: nuclear@0: front_buffer->pixels = (void*)0x6000000; nuclear@0: front_buffer->x = back_buffer->x = xres; nuclear@0: front_buffer->y = back_buffer->y = yres; nuclear@0: front_buffer->bpp = back_buffer->bpp = sizeof_pixel * 8; nuclear@1: nuclear@0: if(mode > 3) { nuclear@0: page_flipping = 1; nuclear@0: back_buffer->pixels = (void*)0x600a000; nuclear@0: } else { nuclear@0: page_flipping = 0; nuclear@0: if(double_buffering) { nuclear@0: back_buffer->pixels = malloc(xres * yres * sizeof_pixel); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void flip(void) { nuclear@0: static void *tmp; nuclear@1: nuclear@0: if(page_flipping) { nuclear@0: swap_page(); nuclear@0: tmp = front_buffer->pixels; nuclear@0: front_buffer->pixels = back_buffer->pixels; nuclear@0: back_buffer->pixels = tmp; nuclear@0: } else { nuclear@0: /*dma_copy32(3, front_buffer->pixels, back_buffer->pixels, (xres * yres) >> 1);*/ nuclear@0: dma_copy32(3, front_buffer->pixels, back_buffer->pixels, 19200); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: /* ------- pixel buffer operations ------- */ nuclear@0: nuclear@0: struct pixel_buffer *create_pixel_buffer(int x, int y, int bpp) { nuclear@0: struct pixel_buffer *pbuf = malloc(sizeof(struct pixel_buffer)); nuclear@0: if(pbuf) { nuclear@0: pbuf->pixels = malloc(x * y * bpp / 8); nuclear@0: pbuf->x = x; nuclear@0: pbuf->y = y; nuclear@0: pbuf->bpp = bpp; nuclear@0: } nuclear@0: return pbuf; nuclear@0: } nuclear@0: nuclear@0: void destroy_pixel_buffer(struct pixel_buffer *pbuf) { nuclear@0: free(pbuf->pixels); nuclear@0: free(pbuf); nuclear@0: } nuclear@0: nuclear@0: void clear_buffer(struct pixel_buffer *pbuf, unsigned short color) { nuclear@0: int sz = pbuf->x * pbuf->y; nuclear@0: nuclear@0: if(pbuf->bpp == 8) { nuclear@0: color |= color << 8; nuclear@0: sz >>= 1; nuclear@0: } nuclear@1: nuclear@0: dma_fill16(3, pbuf->pixels, color, sz); nuclear@0: } nuclear@0: nuclear@0: void copy_buffer(const struct pixel_buffer *src, struct pixel_buffer *dst) { nuclear@0: int words; nuclear@1: nuclear@0: if(src->x != dst->x || src->y != dst->y || src->bpp != dst->bpp) return; nuclear@0: nuclear@0: words = (src->x * src->y) >> (src->bpp == 16 ? 1 : 2); nuclear@0: dma_copy32(3, dst->pixels, src->pixels, words); nuclear@0: } nuclear@0: nuclear@3: #define MIN(a, b) ((a) < (b) ? (a) : (b)) nuclear@3: nuclear@3: void blit(struct pixel_buffer *src, int src_x, int src_y, int src_w, int src_h, nuclear@3: struct pixel_buffer *dst, int dst_x, int dst_y) nuclear@3: { nuclear@3: int i, pixsize, width, height, dstride, sstride; nuclear@3: unsigned char *dptr, *sptr; nuclear@3: nuclear@3: if(dst->bpp != src->bpp) nuclear@3: return; nuclear@3: nuclear@3: if(src_w <= 0) nuclear@3: src_w = src->x; nuclear@3: if(src_h <= 0) nuclear@3: src_h = src->y; nuclear@3: nuclear@3: width = MIN(src_w, MIN(src->x - src_x, dst->x - dst_x)); nuclear@3: height = MIN(src_h, MIN(src->y - src_y, dst->y - dst_y)); nuclear@3: nuclear@3: if(width <= 0 || height <= 0) nuclear@3: return; nuclear@3: nuclear@3: pixsize = dst->bpp / 8; nuclear@3: dptr = (unsigned char*)dst->pixels + (dst_y * dst->x + dst_x) * pixsize; nuclear@3: sptr = (unsigned char*)src->pixels + (src_y * src->x + src_x) * pixsize; nuclear@3: nuclear@3: dstride = dst->x * pixsize; nuclear@3: sstride = src->x * pixsize; nuclear@3: nuclear@3: for(i=0; ipixels; nuclear@0: nuclear@0: ptr += y1 * pbuf->x + x1; nuclear@0: dx = x2 - x1; nuclear@0: dy = y2 - y1; nuclear@1: nuclear@0: if(dx >= 0) { nuclear@0: x_inc = 1; nuclear@0: } else { nuclear@0: x_inc = -1; nuclear@0: dx = -dx; nuclear@0: } nuclear@1: nuclear@0: if(dy >= 0) { nuclear@0: y_inc = pbuf->x; nuclear@0: } else { nuclear@0: y_inc = -pbuf->x; nuclear@0: dy = -dy; nuclear@0: } nuclear@1: nuclear@0: dx2 = dx << 1; nuclear@0: dy2 = dy << 1; nuclear@0: nuclear@0: if(dx > dy) { nuclear@0: error = dy2 - dx; nuclear@0: for(i=0; i<=dx; i++) { nuclear@0: *ptr = col; nuclear@0: if(error >= 0) { nuclear@0: error -= dx2; nuclear@0: ptr += y_inc; nuclear@0: } nuclear@0: error += dy2; nuclear@0: ptr += x_inc; nuclear@0: } nuclear@0: } else { nuclear@0: error = dx2 - dy; nuclear@0: for(i=0;i<=dy;i++) { nuclear@0: *ptr = col; nuclear@0: if(error >= 0) { nuclear@0: error -= dy2; nuclear@0: ptr += x_inc; nuclear@0: } nuclear@0: error += dx2; nuclear@0: ptr += y_inc; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@12: nuclear@12: enum { nuclear@12: OUT_L = 1, nuclear@12: OUT_R = 2, nuclear@12: OUT_T = 4, nuclear@12: OUT_B = 8 nuclear@12: }; nuclear@12: static unsigned int outcode(int x, int y, int left, int top, int right, int bot) nuclear@12: { nuclear@12: unsigned int res = 0; nuclear@12: if(x < left) res |= OUT_L; nuclear@12: if(x > right) res |= OUT_R; nuclear@12: if(y < top) res |= OUT_T; nuclear@12: if(y > bot) res |= OUT_B; nuclear@12: return res; nuclear@12: } nuclear@12: nuclear@12: int clip_line(int *x1, int *y1, int *x2, int *y2, int left, int top, int right, int bot) nuclear@12: { nuclear@12: int i; nuclear@12: unsigned int out1, out2; nuclear@12: nuclear@12: --right; nuclear@12: --bot; nuclear@12: out1 = outcode(*x1, *y1, left, top, right, bot); nuclear@12: out2 = outcode(*x2, *y2, left, top, right, bot); nuclear@12: nuclear@12: for(;;) { nuclear@12: int x, y; nuclear@12: unsigned int outout; nuclear@12: nuclear@12: if((out1 | out2) == 0) nuclear@12: return 1; /* both inside */ nuclear@12: if(out1 & out2) nuclear@12: return 0; /* both outside in the same area */ nuclear@12: nuclear@12: outout = out1 ? out1 : out2; nuclear@12: if(outout & OUT_T) { nuclear@12: x = *x1 + (float)(*x2 - *x1) * (float)(top - *y1) / (float)(*y2 - *y1); nuclear@12: y = top; nuclear@12: } else if(outout & OUT_B) { nuclear@12: x = *x1 + (float)(*x2 - *x1) * (float)(bot - *y1) / (float)(*y2 - *y1); nuclear@12: y = bot; nuclear@12: } else if(outout & OUT_R) { nuclear@12: y = *y1 + (float)(*y2 - *y1) * (float)(right - *x1) / (float)(*x2 - *x1); nuclear@12: x = right; nuclear@12: } else if(outout & OUT_L) { nuclear@12: y = *y1 + (float)(*y2 - *y1) * (float)(left - *x1) / (float)(*x2 - *x1); nuclear@12: x = left; nuclear@12: } nuclear@12: nuclear@12: if(out1) { nuclear@12: *x1 = x; nuclear@12: *y1 = y; nuclear@12: out1 = outcode(*x1, *y1, left, top, right, bot); nuclear@12: } else { nuclear@12: *x2 = x; nuclear@12: *y2 = y; nuclear@12: out2 = outcode(*x2, *y2, left, top, right, bot); nuclear@12: } nuclear@12: } nuclear@12: return 1; nuclear@12: }