-include $(dep)
-src/data.o: src/data.s data/bg.raw data/bg.pal
+src/data.o: src/data.s data/bg.raw data/bg.pal data/sprites.raw data/sprites.pal
tools/pngdump/pngdump:
$(MAKE) -C tools/pngdump
.globl bgimg_pixels
.globl bgimg_cmap
+ .globl sprites_pixels
+ .globl sprites_cmap
+ .align 1
bgimg_pixels:
.incbin "data/bg.raw"
+
+ .align 1
bgimg_cmap:
.incbin "data/bg.pal"
+
+ .align 1
+sprites_pixels:
+ .incbin "data/sprites.raw"
+
+ .align 1
+sprites_cmap:
+ .incbin "data/sprites.pal"
--- /dev/null
+/*
+gbasys - a gameboy advance hardware abstraction library
+Copyright (C) 2004-2014 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "dma.h"
+
+/* DMA Options */
+#define DMA_ENABLE 0x80000000
+#define DMA_INT_ENABLE 0x40000000
+#define DMA_TIMING_IMMED 0x00000000
+#define DMA_TIMING_VBLANK 0x10000000
+#define DMA_TIMING_HBLANK 0x20000000
+#define DMA_TIMING_DISPSYNC 0x30000000
+#define DMA_16 0x00000000
+#define DMA_32 0x04000000
+#define DMA_REPEAT 0x02000000
+#define DMA_SRC_INC 0x00000000
+#define DMA_SRC_DEC 0x00800000
+#define DMA_SRC_FIX 0x01000000
+#define DMA_DST_INC 0x00000000
+#define DMA_DST_DEC 0x00200000
+#define DMA_DST_FIX1 0x00400000
+#define DMA_DST_RELOAD 0x00600000
+
+/* DMA Register Parts */
+#define DMA_SRC 0
+#define DMA_DST 1
+#define DMA_CTRL 2
+
+static volatile unsigned long *reg_dma[4] = {(void*)0x040000b0, (void*)0x040000bc, (void*)0x040000c8, (void*)0x040000d4 };
+
+/* --- perform a copy of words or halfwords using DMA --- */
+
+void dma_copy32(int channel, void *dst, void *src, int words)
+{
+ reg_dma[channel][DMA_SRC] = (unsigned long)src;
+ reg_dma[channel][DMA_DST] = (unsigned long)dst;
+ reg_dma[channel][DMA_CTRL] = words | DMA_TIMING_IMMED | DMA_32 | DMA_ENABLE;
+}
+
+void dma_copy16(int channel, void *dst, void *src, int halfwords)
+{
+ reg_dma[channel][DMA_SRC] = (unsigned long)src;
+ reg_dma[channel][DMA_DST] = (unsigned long)dst;
+ reg_dma[channel][DMA_CTRL] = halfwords | DMA_TIMING_IMMED | DMA_16 | DMA_ENABLE;
+}
+
+/* --- fill a buffer with an ammount of words and halfwords using DMA --- */
+
+void dma_fill32(int channel, void *dst, unsigned long val, int words)
+{
+ unsigned long valmem = val;
+ reg_dma[channel][DMA_SRC] = (unsigned long)&valmem;
+ reg_dma[channel][DMA_DST] = (unsigned long)dst;
+ reg_dma[channel][DMA_CTRL] = words | DMA_SRC_FIX | DMA_TIMING_IMMED | DMA_32 | DMA_ENABLE;
+}
+
+void dma_fill16(int channel, void *dst, unsigned short val, int halfwords)
+{
+ unsigned short valmem = val;
+ reg_dma[channel][DMA_SRC] = (unsigned long)&valmem;
+ reg_dma[channel][DMA_DST] = (unsigned long)dst;
+ reg_dma[channel][DMA_CTRL] = halfwords | DMA_SRC_FIX | DMA_TIMING_IMMED | DMA_16 | DMA_ENABLE;
+}
--- /dev/null
+/*
+gbasys - a gameboy advance hardware abstraction library
+Copyright (C) 2004-2014 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef _DMA_H_
+#define _DMA_H_
+
+void dma_copy32(int channel, void *dst, void *src, int words);
+void dma_copy16(int channel, void *dst, void *src, int halfwords);
+
+void dma_fill32(int channel, void *dst, unsigned long val, int words);
+void dma_fill16(int channel, void *dst, unsigned short val, int halfwords);
+
+#endif /* _DMA_H_ */
#define CRAM_BG_ADDR 0x5000000
#define CRAM_OBJ_ADDR 0x5000200
+/* OAM table */
+#define OAM_ADDR 0x7000000
+
/* interrupt handler */
#define INTR_VECTOR (*(volatile uint32_t*)0x3007ffc)
#define present(x) \
do { \
- REG_DISPCNT = DISPCNT_BG2 | 4 | ((x) << 4); \
+ REG_DISPCNT = DISPCNT_BG2 | DISPCNT_OBJ | 4 | ((x) << 4); \
} while(0)
#define set_bg_color(idx, r, g, b) \
#include "polyfill.h"
#include "debug.h"
#include "meshdata.h"
+#include "sprites.h"
+#include "dma.h"
#define MENU_HEIGHT 17
#define TRACK_HEIGHT 18
set_intr();
/* mode 4: 240x160 8bpp */
- REG_DISPCNT = DISPCNT_BG2 | 4;
+ REG_DISPCNT = DISPCNT_BG2 | DISPCNT_OBJ | 4;
fbptr[0] = (unsigned char*)VRAM_LFB_FB0_ADDR;
fbptr[1] = (unsigned char*)VRAM_LFB_FB1_ADDR;
r = i / 5 + 6;
*cptr++ = r | (r << 5) | (r << 10);
}
- memcpy(fbptr[0], bgimg_pixels, 240 * 160);
- memcpy(fbptr[1], bgimg_pixels, 240 * 160);
+ dma_copy16(3, fbptr[0], bgimg_pixels, 240 * 160 / 2);
+ dma_copy16(3, fbptr[1], bgimg_pixels, 240 * 160 / 2);
+
+ init_sprites();
+ set_sprite(0, 0, 512, 42, 42, 0, SPR_SZ64);
xgl_init();
xgl_viewport(0, 0, 240, VP_HEIGHT);
} else {
xgl_draw(XGL_LINES, gridaxes + 6, 2); /* -Z */
}
-
if(show_obj == 1) {
xgl_draw(XGL_QUADS, cube, sizeof cube / sizeof *cube);
} else {
xgl_draw(XGL_TRIANGLES, suzanne, sizeof suzanne / sizeof *suzanne);
}
-
if(cam_theta < X_PI) {
xgl_draw(XGL_LINES, gridaxes, 2); /* +X */
} else {
int32_t x, y0, y1, dx, dy, slope, fx, fy;
short *tab, start, len;
unsigned char *fbptr;
+ uint16_t *pptr, pcol = ((uint16_t)col << 8) | (uint16_t)col;
vlast = varr + vnum - 1;
top = fbheight;
len = scantab[1][i] - start;
if(len > 0) {
- memset(fbptr + start, col, len);
+ if(start & 1) {
+ pptr = (uint16_t*)(fbptr + (start & 0xfffe));
+ *pptr = (*pptr & 0xff) | ((uint16_t)col << 8);
+ len--;
+ start++;
+ }
+ pptr = (uint16_t*)(fbptr + start);
+ while(len > 1) {
+ *pptr++ = pcol;
+ len -= 2;
+ }
+ if(len) {
+ *pptr = (*pptr & 0xff00) | col;
+ }
}
fbptr += fbwidth;
}
return 1;
}
+#define PUTPIXEL(ptr) \
+ do { \
+ uint16_t *pptr = (uint16_t*)((uint32_t)ptr & 0xfffffffe); \
+ if((uint32_t)ptr & 1) { \
+ *pptr = (*pptr & 0xff) | (color << 8); \
+ } else { \
+ *pptr = (*pptr & 0xff00) | color; \
+ } \
+ } while(0)
+
void draw_line(int x0, int y0, int x1, int y1, unsigned short color)
{
int i, dx, dy, x_inc, y_inc, error;
if(dx > dy) {
error = dy * 2 - dx;
for(i=0; i<=dx; i++) {
- *fbptr = color;
+ PUTPIXEL(fbptr);
if(error >= 0) {
error -= dx * 2;
fbptr += y_inc;
} else {
error = dx * 2 - dy;
for(i=0; i<=dy; i++) {
- *fbptr = color;
+ PUTPIXEL(fbptr);
if(error >= 0) {
error -= dy * 2;
fbptr += x_inc;
--- /dev/null
+/*
+blender for the Gameboy Advance
+Copyright (C) 2021 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#include <string.h>
+#include "gbaregs.h"
+#include "sprites.h"
+#include "debug.h"
+
+extern unsigned char sprites_pixels[];
+extern struct { unsigned char r, g, b; } sprites_cmap[];
+
+void init_sprites(void)
+{
+ int i, j;
+ uint16_t *cptr;
+ uint16_t *dst, *src;
+
+ /* copy from cartridge to OBJ RAM */
+ dst = (uint16_t*)VRAM_LFB_OBJ_ADDR;
+ src = (uint16_t*)sprites_pixels;
+ for(i=0; i<256; i++) { /* 256 tiles */
+ for(j=0; j<8; j++) {
+ *dst++ = src[j * 64];
+ *dst++ = src[j * 64 + 1];
+ }
+
+ src += 2;
+
+ if((i & 31) == 31) {
+ src += 7 * 128; /* skip to the next row of tiles */
+ }
+ }
+
+
+ /* setup OBJ colormap 0 */
+ cptr = (uint16_t*)CRAM_OBJ_ADDR;
+ for(i=0; i<16; i++) {
+ unsigned char r = sprites_cmap[i].r >> 3;
+ unsigned char g = sprites_cmap[i].g >> 3;
+ unsigned char b = sprites_cmap[i].b >> 3;
+ *cptr++ = r | (g << 5) | (b << 10);
+ }
+}
+
+void set_sprite(uint16_t *oam, int idx, int spr, int x, int y, int pal, unsigned int flags)
+{
+ if(!oam) oam = (uint16_t*)OAM_ADDR;
+
+ oam += idx << 2;
+
+ oam[0] = (y & 0xff) | (flags & 0xff00);
+ oam[1] = (x & 0x1ff) | ((flags >> 8) & 0xfe00);
+ oam[2] = (spr & 0x3ff) | ((flags & 3) << 10) | ((pal & 0xf) << 12);
+}
--- /dev/null
+/*
+blender for the Gameboy Advance
+Copyright (C) 2021 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef SPRITES_H_
+#define SPRITES_H_
+
+#include <stdint.h>
+
+enum {
+ SPR_ROTSCL = 0x0100,
+ SPR_DBLSZ = 0x0200,
+ SPR_BLEND = 0x0400,
+ SPR_OBJWIN = 0x0800,
+ SPR_MOSAIC = 0x1000,
+ SPR_256COL = 0x2000,
+ SPR_HRECT = 0x4000,
+ SPR_VRECT = 0x8000,
+
+ SPR_HFLIP = 0x100000,
+ SPR_VFLIP = 0x200000,
+ SPR_SZ16 = 0x400000,
+ SPR_SZ32 = 0x800000,
+ SPR_SZ64 = 0xc00000
+};
+#define SPR_ROTSCL_PARAM(x) ((unsigned int)(x) << 17)
+#define SPR_PRIO(x) ((unsigned int)(x) & 3)
+
+void init_sprites(void);
+void set_sprite(uint16_t *oam, int idx, int spr, int x, int y, int pal, unsigned int flags);
+
+#endif /* SPRITES_H_ */
switch(mode) {
case 0:
- fwrite(img.pixels, 1, img.scansz * img.height, out);
+ if(img.bpp > 8 || img.cmap_ncolors == 0 || img.cmap_ncolors > 16) {
+ fwrite(img.pixels, 1, img.scansz * img.height, out);
+ } else {
+ /* pack into nibbles */
+ unsigned char *ptr = img.pixels;
+ for(i=0; i<img.width * img.height / 2; i++) {
+ unsigned char pair = (ptr[0] << 4) | ptr[1];
+ fputc(pair, out);
+ ptr += 2;
+ }
+ }
break;
case 1: