aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/demo.c55
-rw-r--r--src/demo.h44
-rw-r--r--src/main.c94
-rw-r--r--src/makefile3
-rw-r--r--src/ppu/internals.c11
-rw-r--r--src/ppu/internals.h2
-rw-r--r--src/ppu/ppu.c2
-rw-r--r--src/ppu/ppu.h2
-rw-r--r--src/ppusim/mem.c2
-rw-r--r--src/ppusim/pixel.c39
10 files changed, 147 insertions, 107 deletions
diff --git a/src/demo.c b/src/demo.c
new file mode 100644
index 0000000..6248989
--- /dev/null
+++ b/src/demo.c
@@ -0,0 +1,55 @@
+#include <math.h>
+
+#include "demo.h"
+#include "ppu/ppu.h"
+
+#define HH_DEMO_BALL_COUNT 5
+hh_s_ppu_loc_fam_entry g_hh_demo_balls[HH_DEMO_BALL_COUNT];
+
+void hh_demo_setup() {
+ // load sprites
+ hh_ppu_update_sprite(0, HH_DBG_SPRITE_BALL);
+ hh_ppu_update_sprite(1, HH_DBG_SPRITE_CHECKERBOARD);
+
+ // background pattern
+ hh_ppu_update_color(0, 1, (hh_ppu_rgb_color_t) {0x8, 0x8, 0x8});
+ for (unsigned i = 0; i < HH_PPU_BG_CANVAS_TILES_H * HH_PPU_BG_CANVAS_TILES_V; i++) {
+ hh_ppu_update_background(i, (hh_s_ppu_loc_bam_entry) {
+ .horizontal_flip = false,
+ .vertical_flip = false,
+ .palette_index = 0,
+ .tilemap_index = 1,
+ });
+ }
+
+ // cool colors
+ hh_ppu_update_color(1, 1, (hh_ppu_rgb_color_t) {0xf, 0x0, 0xf});
+ hh_ppu_update_color(2, 1, (hh_ppu_rgb_color_t) {0xf, 0xf, 0xf});
+ hh_ppu_update_color(3, 1, (hh_ppu_rgb_color_t) {0xf, 0x0, 0x0});
+ hh_ppu_update_color(4, 1, (hh_ppu_rgb_color_t) {0x0, 0xf, 0xf});
+ hh_ppu_update_color(5, 1, (hh_ppu_rgb_color_t) {0x0, 0x0, 0xf});
+
+ // balls
+ for (unsigned i = 0; i < HH_DEMO_BALL_COUNT; i++) {
+ g_hh_demo_balls[i].horizontal_flip = false;
+ g_hh_demo_balls[i].vertical_flip = false;
+ g_hh_demo_balls[i].palette_index = i+1;
+ g_hh_demo_balls[i].tilemap_index = 0;
+ }
+}
+
+void hh_demo_loop(unsigned long frame) {
+ // set background pattern position
+ hh_ppu_update_aux((hh_s_ppu_loc_aux) {
+ .bg_shift_x = (frame / 2) % HH_PPU_SPRITE_WIDTH,
+ .bg_shift_y = (frame / 8) % HH_PPU_SPRITE_HEIGHT,
+ .fg_fetch = 0,
+ .sysreset = 0,
+ });
+
+ for (unsigned i = 0; i < HH_DEMO_BALL_COUNT; i++) {
+ g_hh_demo_balls[i].position_x = HH_PPU_SCREEN_WIDTH/2 - HH_PPU_SPRITE_WIDTH/2 + (int)(60 * (double)sin((1*(double)frame + 6*(double)i) / 30));
+ g_hh_demo_balls[i].position_y = HH_PPU_SCREEN_HEIGHT/2 - HH_PPU_SPRITE_HEIGHT/2 + (int)(30 * (double)sin((2*(double)frame + 6*(double)i) / 30));
+ hh_ppu_update_foreground(i, g_hh_demo_balls[i]);
+ }
+}
diff --git a/src/demo.h b/src/demo.h
new file mode 100644
index 0000000..89436b5
--- /dev/null
+++ b/src/demo.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "ppu/types.h"
+
+void hh_demo_setup();
+void hh_demo_loop(unsigned long);
+
+static const hh_s_ppu_loc_sprite HH_DBG_SPRITE_BALL = {
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
+ 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0,
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
+};
+
+static const hh_s_ppu_loc_sprite HH_DBG_SPRITE_CHECKERBOARD = {
+ 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
+ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
+ 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0,
+ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0,
+ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0
+};
diff --git a/src/main.c b/src/main.c
index b61f124..f4de225 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,12 +1,8 @@
#include <stdlib.h>
-#include <math.h>
-#ifdef HH_TARGET_DESKTOP
-#include <stdio.h>
-#endif
#include "main.h"
#include "ppu/ppu.h"
-#include "ppu/consts.h"
+#include "demo.h"
bool g_hh_run = true;
@@ -21,97 +17,13 @@ void hh_ppu_vblank_interrupt() {
static unsigned long frame = 0;
frame++;
-#ifdef HH_TARGET_DESKTOP
- // printf("frame %lu\n", frame);
-#endif
-
- unsigned shift = (double) sin((double) frame / 20) * 10 + 10;
- hh_ppu_update_aux((hh_s_ppu_loc_aux) {
- .bg_shift_x = shift,
- .bg_shift_y = 0,
- .fg_fetch = 0,
- .sysreset = 0,
- });
+ hh_demo_loop(frame);
}
void hh_setup() {
hh_ppu_init();
- hh_s_ppu_loc_sprite sprite = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
- 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
- 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
- 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
- 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0,
- 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0,
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0
- };
-
- for (int x = 0; x < HH_PPU_SPRITE_WIDTH; x++) {
- for (int y = 0; y < HH_PPU_SPRITE_HEIGHT; y++) {
- // sprite[y * HH_PPU_SPRITE_WIDTH + x] = (pow(x - 8, 2) + pow(y - 8, 2) < 64) ? 1 : 0;
- uint8_t p = sprite[y * HH_PPU_SPRITE_WIDTH + x];
- printf("%c%c%c", p ? 'X' : ' ', p ? 'X' : ' ', p ? 'X' : ' ');
- }
- printf("\n");
- }
-
- hh_ppu_update_sprite(0, sprite);
-
- // hh_ppu_update_foreground(0, (hh_s_ppu_loc_fam_entry) {
- // .horizontal_flip = false,
- // .vertical_flip = false,
- // .palette_index = 1,
- // .tilemap_index = 0,
- // .position_x = 30,
- // .position_y = 40,
- // });
-
- hh_ppu_update_background(3, (hh_s_ppu_loc_bam_entry) {
- .horizontal_flip = false,
- .vertical_flip = false,
- .palette_index = 1,
- .tilemap_index = 0,
- });
- hh_ppu_update_background(4, (hh_s_ppu_loc_bam_entry) {
- .horizontal_flip = true,
- .vertical_flip = false,
- .palette_index = 2,
- .tilemap_index = 0,
- });
- hh_ppu_update_background(5, (hh_s_ppu_loc_bam_entry) {
- .horizontal_flip = false,
- .vertical_flip = false,
- .palette_index = 3,
- .tilemap_index = 0,
- });
- hh_ppu_update_background(6, (hh_s_ppu_loc_bam_entry) {
- .horizontal_flip = false,
- .vertical_flip = true,
- .palette_index = 4,
- .tilemap_index = 0,
- });
- hh_ppu_update_background(7, (hh_s_ppu_loc_bam_entry) {
- .horizontal_flip = true,
- .vertical_flip = true,
- .palette_index = 5,
- .tilemap_index = 0,
- });
-
- hh_ppu_update_color(1, 1, (hh_ppu_rgb_color_t) {0xf, 0x0, 0xf});
- hh_ppu_update_color(2, 1, (hh_ppu_rgb_color_t) {0xf, 0xf, 0xf});
- hh_ppu_update_color(3, 1, (hh_ppu_rgb_color_t) {0xf, 0x0, 0x0});
- hh_ppu_update_color(4, 1, (hh_ppu_rgb_color_t) {0x0, 0xf, 0xf});
- hh_ppu_update_color(5, 1, (hh_ppu_rgb_color_t) {0x0, 0x0, 0xf});
+ hh_demo_setup();
}
void hh_exit() {
diff --git a/src/makefile b/src/makefile
index 41311eb..83c7df5 100644
--- a/src/makefile
+++ b/src/makefile
@@ -28,7 +28,8 @@ CFLAGS += $(if $(DESKTOP), -DHH_TARGET_DESKTOP, )
LOCAL_SRCS += main.c \
ppu/internals.c \
- ppu/ppu.c
+ ppu/ppu.c \
+ demo.c
CFLAGS += $(SHARED_FLAGS)
LFLAGS += $(SHARED_FLAGS)
diff --git a/src/ppu/internals.c b/src/ppu/internals.c
index 7826ece..e4817f1 100644
--- a/src/ppu/internals.c
+++ b/src/ppu/internals.c
@@ -4,8 +4,9 @@
#include "ppu/internals.h"
bool hh_ppu_vram_valid_address(hh_ppu_addr_t addr) {
+ #warning unimlemented
(void) addr; // compiler bruh
- return true; // TODO
+ return true;
}
void hh_ppu_vram_write(hh_s_ppu_vram_data data) {
@@ -36,7 +37,7 @@ hh_s_ppu_vram_data hh_ppu_2nat_fam(hh_s_ppu_loc_fam_entry e) {
data[0] = HH_RESIZE(e.tilemap_index, 9, 0) << 0 |
HH_RESIZE(e.palette_index, 2, 0) << 10 |
HH_RESIZE(e.position_y, 2, 0) << 13;
- data[1] = HH_RESIZE(e.position_y, 4, 0) << 0 |
+ data[1] = HH_RESIZE(e.position_y, 7, 3) << 0 |
HH_RESIZE(e.position_x, 8, 0) << 5 |
e.vertical_flip << 14 |
e.horizontal_flip << 15;
@@ -64,7 +65,7 @@ hh_s_ppu_vram_data hh_ppu_2nat_aux(hh_s_ppu_loc_aux aux) {
return out;
}
-hh_s_ppu_vram_data hh_ppu_2nat_sprite(hh_ppu_loc_sprite_data_t sprite_data) {
+hh_s_ppu_vram_data hh_ppu_2nat_sprite(const hh_ppu_loc_sprite_data_t sprite_data) {
hh_ppu_data_t* data = malloc(sizeof(hh_ppu_data_t) * HH_PPU_VRAM_TMM_SPRITE_SIZE);
for (unsigned i = 0; i < HH_PPU_SPRITE_WIDTH * HH_PPU_SPRITE_HEIGHT; i++) {
@@ -84,9 +85,9 @@ hh_s_ppu_vram_data hh_ppu_2nat_sprite(hh_ppu_loc_sprite_data_t sprite_data) {
hh_s_ppu_vram_data hh_ppu_2nat_color(hh_ppu_rgb_color_t rgb) {
hh_ppu_data_t* data = malloc(sizeof(hh_ppu_data_t) * HH_PPU_VRAM_PAL_ENTRY_SIZE);
- data[0] = HH_RESIZE(rgb[0], 3, 0) << 0 |
+ data[0] = HH_RESIZE(rgb[0], 3, 0) << 8 |
HH_RESIZE(rgb[1], 3, 0) << 4 |
- HH_RESIZE(rgb[2], 3, 0) << 8;
+ HH_RESIZE(rgb[2], 3, 0) << 0;
hh_s_ppu_vram_data out = {
.data = data,
diff --git a/src/ppu/internals.h b/src/ppu/internals.h
index 6e9dda7..8f50c52 100644
--- a/src/ppu/internals.h
+++ b/src/ppu/internals.h
@@ -25,6 +25,6 @@ void hh_ppu_vram_write(hh_s_ppu_vram_data data);
hh_s_ppu_vram_data hh_ppu_2nat_bam(hh_s_ppu_loc_bam_entry);
hh_s_ppu_vram_data hh_ppu_2nat_fam(hh_s_ppu_loc_fam_entry);
hh_s_ppu_vram_data hh_ppu_2nat_aux(hh_s_ppu_loc_aux);
-hh_s_ppu_vram_data hh_ppu_2nat_sprite(hh_ppu_loc_sprite_data_t);
+hh_s_ppu_vram_data hh_ppu_2nat_sprite(const hh_ppu_loc_sprite_data_t);
hh_s_ppu_vram_data hh_ppu_2nat_color(hh_ppu_rgb_color_t);
diff --git a/src/ppu/ppu.c b/src/ppu/ppu.c
index e2fccb9..5f33c55 100644
--- a/src/ppu/ppu.c
+++ b/src/ppu/ppu.c
@@ -18,7 +18,7 @@ void hh_ppu_update_background(unsigned index, hh_s_ppu_loc_bam_entry e) {
free(s.data);
}
-void hh_ppu_update_sprite(unsigned tilemap_index, hh_s_ppu_loc_sprite sprite) {
+void hh_ppu_update_sprite(unsigned tilemap_index, const hh_s_ppu_loc_sprite sprite) {
hh_s_ppu_vram_data s = hh_ppu_2nat_sprite(sprite);
s.offset = HH_PPU_VRAM_TMM_OFFSET + HH_PPU_VRAM_TMM_SPRITE_SIZE * tilemap_index;
hh_ppu_vram_write(s);
diff --git a/src/ppu/ppu.h b/src/ppu/ppu.h
index 90f964e..cab0e30 100644
--- a/src/ppu/ppu.h
+++ b/src/ppu/ppu.h
@@ -13,7 +13,7 @@ void hh_ppu_update_background(unsigned index, hh_s_ppu_loc_bam_entry e);
/* @brief update aux register */
void hh_ppu_update_aux(hh_s_ppu_loc_aux aux);
/* @brief update single sprite */
-void hh_ppu_update_sprite(unsigned tilemap_index, hh_s_ppu_loc_sprite sprite);
+void hh_ppu_update_sprite(unsigned tilemap_index, const hh_s_ppu_loc_sprite sprite);
/* @brief update entire palette table */
void hh_ppu_update_palette_table(hh_ppu_loc_palette_table_t table);
/* @brief update single palette */
diff --git a/src/ppusim/mem.c b/src/ppusim/mem.c
index 72e01c5..e3f41f5 100644
--- a/src/ppusim/mem.c
+++ b/src/ppusim/mem.c
@@ -8,6 +8,6 @@ hh_ppu_data_t *g_hh_ppusim_vram = NULL;
void hh_ppu_vram_dwrite(hh_ppu_addr_t addr, hh_ppu_data_t data) {
if (!hh_ppu_vram_valid_address(addr)) return;
- printf("ppu[0x%04x] = %04x\n", addr, data);
+ // printf("ppu[0x%04x] = %04x\n", addr, data);
g_hh_ppusim_vram[addr] = data;
}
diff --git a/src/ppusim/pixel.c b/src/ppusim/pixel.c
index 96ee998..2163c10 100644
--- a/src/ppusim/pixel.c
+++ b/src/ppusim/pixel.c
@@ -39,7 +39,7 @@ static uint8_t hh_ppusim_bg_pixel(unsigned x, unsigned y) {
uint8_t cidx = 0;
uint16_t tile_pixel_idx = hh_ppusim_apply_transform(loc_x, loc_y, HH_RESIZE(bam, 14, 14), HH_RESIZE(bam, 13, 13));
uint16_t tile_idx = HH_RESIZE(bam, 9, 0);
- hh_ppu_addr_t ttm_addr = tile_idx + tile_pixel_idx / 5;
+ hh_ppu_addr_t ttm_addr = tile_idx * HH_PPU_VRAM_TMM_SPRITE_SIZE + tile_pixel_idx / 5;
uint8_t word_bit_addr = (tile_pixel_idx % 5) * 3;
hh_ppu_data_t tmm = g_hh_ppusim_vram[HH_PPU_VRAM_TMM_OFFSET + ttm_addr];
cidx |= HH_RESIZE(bam, 12, 10) << 3;
@@ -47,13 +47,40 @@ static uint8_t hh_ppusim_bg_pixel(unsigned x, unsigned y) {
return cidx;
}
+/* @brief get current fg pixel cidx */
+static uint8_t hh_ppusim_fg_pixel(unsigned x, unsigned y) {
+ x += 16;
+ y += 16;
+ uint8_t cidx = 0;
+ for (unsigned i = 0; i < HH_PPU_FG_SPRITE_COUNT; i++) {
+ unsigned fam_offset = i * HH_PPU_VRAM_FAM_ENTRY_SIZE;
+ hh_ppu_data_t* fam = &g_hh_ppusim_vram[HH_PPU_VRAM_FAM_OFFSET + fam_offset];
+ unsigned sprite_y = HH_RESIZE(fam[0], 15, 13) | HH_RESIZE(fam[1], 4, 0) << 3;
+ unsigned sprite_x = HH_RESIZE(fam[1], 13, 5);
+ if (x < sprite_x) continue;
+ if (x >= sprite_x + HH_PPU_SPRITE_WIDTH) continue;
+ if (y < sprite_y) continue;
+ if (y >= sprite_y + HH_PPU_SPRITE_HEIGHT) continue;
+ unsigned loc_x = x - sprite_x;
+ unsigned loc_y = y - sprite_y;
+ uint16_t tile_pixel_idx = hh_ppusim_apply_transform(loc_x, loc_y, HH_RESIZE(fam[1], 15, 15), HH_RESIZE(fam[1], 14, 14));
+ uint16_t tile_idx = HH_RESIZE(fam[0], 9, 0);
+ hh_ppu_addr_t ttm_addr = tile_idx * HH_PPU_VRAM_TMM_SPRITE_SIZE + tile_pixel_idx / 5;
+ uint8_t word_bit_addr = (tile_pixel_idx % 5) * 3;
+ hh_ppu_data_t tmm = g_hh_ppusim_vram[HH_PPU_VRAM_TMM_OFFSET + ttm_addr];
+ unsigned cidx_col = HH_RESIZE(tmm, word_bit_addr+2, word_bit_addr);
+ if (cidx_col == 0) continue;
+ unsigned cidx_pal = HH_RESIZE(fam[0], 12, 10);
+ cidx = (cidx_col << 0) | (cidx_pal << 3);
+ break;
+ }
+ return cidx;
+}
+
void hh_ppusim_pixel(SDL_Renderer* r, unsigned x, unsigned y) {
- // loop through foreground sprites to get highest priority cidx
uint8_t bg_cidx = hh_ppusim_bg_pixel(x, y);
- // check if palette color cidx of foreground is 0
- // lookup color from PAL
- // hh_ppusim_draw
- uint8_t cidx = bg_cidx;
+ uint8_t fg_cidx = hh_ppusim_fg_pixel(x, y);
+ uint8_t cidx = (fg_cidx & HH_MASK(3)) == 0 ? bg_cidx : fg_cidx;
hh_ppu_data_t pal_rgb = g_hh_ppusim_vram[HH_PPU_VRAM_PAL_OFFSET + cidx];
hh_ppu_rgb_color_t rgb = {
HH_RESIZE(pal_rgb, 11, 8),