fixed 8bit writes to vmem, unaligned data buffers, and started on
authorJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 16 Mar 2021 01:48:35 +0000 (03:48 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 16 Mar 2021 01:48:35 +0000 (03:48 +0200)
sprites

Makefile
src/data.s
src/dma.c [new file with mode: 0644]
src/dma.h [new file with mode: 0644]
src/gbaregs.h
src/gfx.h
src/main.c
src/polyfill.c
src/sprites.c [new file with mode: 0644]
src/sprites.h [new file with mode: 0644]
tools/pngdump/main.c

index 37be9b5..9bb5113 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ $(elf): $(obj)
 
 -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
index b178889..e6fc992 100644 (file)
@@ -2,8 +2,21 @@
 
        .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"
diff --git a/src/dma.c b/src/dma.c
new file mode 100644 (file)
index 0000000..78b516f
--- /dev/null
+++ b/src/dma.c
@@ -0,0 +1,77 @@
+/*
+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;
+}
diff --git a/src/dma.h b/src/dma.h
new file mode 100644 (file)
index 0000000..96b1806
--- /dev/null
+++ b/src/dma.h
@@ -0,0 +1,27 @@
+/*
+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_ */
index 96f024a..762937f 100644 (file)
@@ -41,6 +41,9 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #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)
 
index 6ba6af5..430b980 100644 (file)
--- a/src/gfx.h
+++ b/src/gfx.h
@@ -24,7 +24,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 #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) \
index a519dc0..30d92c2 100644 (file)
@@ -26,6 +26,8 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include "polyfill.h"
 #include "debug.h"
 #include "meshdata.h"
+#include "sprites.h"
+#include "dma.h"
 
 #define MENU_HEIGHT            17
 #define TRACK_HEIGHT   18
@@ -76,7 +78,7 @@ int main(void)
        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;
@@ -94,8 +96,11 @@ int main(void)
                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);
@@ -128,13 +133,11 @@ int main(void)
                        } 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 {
index 11e70fd..856ea5f 100644 (file)
@@ -41,6 +41,7 @@ void polyfill_flat(struct pvertex *varr, int vnum, unsigned char col)
        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;
@@ -92,7 +93,20 @@ void polyfill_flat(struct pvertex *varr, int vnum, unsigned char col)
                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;
        }
@@ -194,6 +208,16 @@ int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax,
        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;
@@ -220,7 +244,7 @@ void draw_line(int x0, int y0, int x1, int y1, unsigned short color)
        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;
@@ -231,7 +255,7 @@ void draw_line(int x0, int y0, int x1, int y1, unsigned short color)
        } else {
                error = dx * 2 - dy;
                for(i=0; i<=dy; i++) {
-                       *fbptr = color;
+                       PUTPIXEL(fbptr);
                        if(error >= 0) {
                                error -= dy * 2;
                                fbptr += x_inc;
diff --git a/src/sprites.c b/src/sprites.c
new file mode 100644 (file)
index 0000000..1986758
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+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);
+}
diff --git a/src/sprites.h b/src/sprites.h
new file mode 100644 (file)
index 0000000..3712aba
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+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_ */
index a2b37fd..908818d 100644 (file)
@@ -84,7 +84,17 @@ int main(int argc, char **argv)
 
        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: