diff --git a/Makefile b/Makefile index 5d386bf..7068c31 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,8 @@ raytracing/raytracing.elf: raytracing/main-saturn.o raytracing/raytracing.o sh/l vdp2/nbg0.elf: vdp2/nbg0.o res/butterfly.data.o res/butterfly.data.pal.o +vdp2/nbg0_16color.elf: vdp2/nbg0_16color.o res/kirby.data.o res/kirby.data.pal.o + vdp1/polygon.elf: vdp1/polygon.o vdp1/cube.elf: vdp1/cube.o $(LIBGCC) vdp1/normal_sprite.elf: vdp1/normal_sprite.o res/mai00.data.o res/mai.data.pal.o diff --git a/vdp1/cube.cpp b/vdp1/cube.cpp index 7380a22..b045070 100644 --- a/vdp1/cube.cpp +++ b/vdp1/cube.cpp @@ -22,15 +22,15 @@ using vec3 = vec<3, fp16_16>; using mat4x4 = mat<4, 4, fp16_16>; static vec4 vertices[8] = { - {-0.5, -0.5, 0.5, 1.0}, // top left front - { 0.5, -0.5, 0.5, 1.0}, // top right front - { 0.5, 0.5, 0.5, 1.0}, // bottom right front - {-0.5, 0.5, 0.5, 1.0}, // bottom left front + {-1.0, -1.0, 1.0, 1.0}, // top left front + { 1.0, -1.0, 1.0, 1.0}, // top right front + { 1.0, 1.0, 1.0, 1.0}, // bottom right front + {-1.0, 1.0, 1.0, 1.0}, // bottom left front - {-0.5, -0.5, -0.5, 1.0}, // top left back - { 0.5, -0.5, -0.5, 1.0}, // top right back - { 0.5, 0.5, -0.5, 1.0}, // bottom right back - {-0.5, 0.5, -0.5, 1.0}, // bottom left back + {-1.0, -1.0, -1.0, 1.0}, // top left back + { 1.0, -1.0, -1.0, 1.0}, // top right back + { 1.0, 1.0, -1.0, 1.0}, // bottom right back + {-1.0, 1.0, -1.0, 1.0}, // bottom left back }; static uint32_t faces[6][4] = { @@ -47,21 +47,18 @@ struct canvas { fp16_16 height; }; -constexpr struct canvas canvas = { 240, 240 }; +constexpr struct canvas canvas = { 320, 240 }; template vec<3, T> viewport_to_canvas(T x, T y) { - return vec<3, T>(x * canvas.width, y * canvas.height, T(1)); + return vec<3, T>((canvas.width>>1) + x * canvas.height, (canvas.height>>1) - y * canvas.height - T(1), T(1)); } template inline constexpr vec<3, T> project_vertex(vec<4, T> const& v) { - // / (v.z - T(5)) - // / (v.z - T(5)) - return viewport_to_canvas((v.x * T(0.5) + T(2.0/3.0)), - (v.y * T(0.5) + T(0.5))); + return viewport_to_canvas((v.x / v.z), (v.y / v.z)); } constexpr inline uint16_t rgb15(int32_t r, int32_t g, int32_t b) @@ -102,29 +99,35 @@ render() 0, 0, 0, 1, }; - const mat4x4 transform = rotationX * rotationY; + //const mat4x4 transform = rotationX * rotationY; - for (int i = 0; i < 6; i++) { + vec4 transforms[2] = { + {-1.5, 0.0, 7.0, 0.0}, + {1.25, 2, 7.5, 0.0} + }; - const uint32_t * face = faces[i]; + for (vec4& t : transforms) { + for (int i = 0; i < 6; i++) { - vdp1.vram.cmd[ix].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__POLYLINE; - vdp1.vram.cmd[ix].LINK = 0; - vdp1.vram.cmd[ix].PMOD = PMOD__ECD | PMOD__SPD; - vdp1.vram.cmd[ix].COLR = COLR__RGB | colors[i]; + const uint32_t * face = faces[i]; - for (int p = 0; p < 4; p++) { - const vec4& v0 = vertices[face[p]]; + vdp1.vram.cmd[ix].CTRL = CTRL__JP__JUMP_NEXT | CTRL__COMM__POLYLINE; + vdp1.vram.cmd[ix].LINK = 0; + vdp1.vram.cmd[ix].PMOD = PMOD__ECD | PMOD__SPD; + vdp1.vram.cmd[ix].COLR = COLR__RGB | colors[i]; - const vec4 v1 = transform * v0; + for (int p = 0; p < 4; p++) { + const vec4& v0 = vertices[face[p]]; - const vec3& v2 = project_vertex(v1); + const vec4& v1 = v0 + t; - vdp1.vram.cmd[ix].point[p].X = static_cast(v2.x); - vdp1.vram.cmd[ix].point[p].Y = static_cast(v2.y); + const vec3& v2 = project_vertex(v1); + + vdp1.vram.cmd[ix].point[p].X = static_cast(v2.x); + vdp1.vram.cmd[ix].point[p].Y = static_cast(v2.y); + } + ix++; } - - ix++; } vdp1.vram.cmd[ix].CTRL = CTRL__END; diff --git a/vdp2/nbg0_16color.cpp b/vdp2/nbg0_16color.cpp new file mode 100644 index 0000000..80129ca --- /dev/null +++ b/vdp2/nbg0_16color.cpp @@ -0,0 +1,135 @@ +#include + +#include "vdp2.h" +#include "../common/vdp2_func.hpp" + + +extern void * _kirby_data_pal_start __asm("_binary_res_kirby_data_pal_start"); +extern void * _kirby_data_pal_size __asm("_binary_res_kirby_data_pal_size"); + +extern void * _kirby_data_start __asm("_binary_res_kirby_data_start"); +extern void * _kirby_data_size __asm("_binary_res_kirby_data_size"); + +inline constexpr uint16_t rgb15(const uint8_t * buf) +{ + return ((buf[2] >> 3) << 10) // blue + | ((buf[1] >> 3) << 5) // green + | ((buf[0] >> 3) << 0); // red +} + +void palette_data() +{ + const uint32_t buf_size = reinterpret_cast(&_kirby_data_pal_size); + const uint8_t * buf = reinterpret_cast(&_kirby_data_pal_start); + uint32_t buf_ix = 0; + + for (uint32_t i = 0; i < (buf_size / 3); i++) { + vdp2.cram.u16[i] = rgb15(&buf[buf_ix]); + buf_ix += 3; + } +} + +uint32_t cell_data(const uint32_t top) +{ + const uint32_t buf_size = reinterpret_cast(&_kirby_data_size); + const uint8_t * buf = reinterpret_cast(&_kirby_data_start); + + // round to nearest multiple of 32 + const uint32_t table_size = ((buf_size / 2) + 0x20 - 1) & (-0x20); + const uint32_t base_address = top - table_size; // in bytes + + // px is a conversion from 8 bits per index to 4 bits per index + // the value is shifted to its position in a 32-bit big-endian value +#define px(x) (buf[i * 8 + ((x) & 0xf)] << ((7 - ((x) & 0xf)) * 4)) + + for (uint32_t i = 0; i < (buf_size / 8); i++) { + // write an entire row all at once + vdp2.vram.u32[(base_address / 4) + i] = + //vdp2.vram.u32[i] = + px(0) | px(1) | px(2) | px(3) | px(4) | px(5) | px(6) | px(7); + } + +#undef px + + return base_address; +} + +template +void fill(T * buf, T v, int32_t n) noexcept +{ + while (n > 0) { + *buf++ = v; + n -= (sizeof (T)); + } +} + +void main() +{ + v_blank_in(); + + // DISP: Please make sure to change this bit from 0 to 1 during V blank. + vdp2.reg.TVMD = ( TVMD__DISP | TVMD__LSMD__NON_INTERLACE + | TVMD__VRESO__240 | TVMD__HRESO__NORMAL_320); + + + /* set the color mode to 5bits per channel, 1024 colors */ + vdp2.reg.RAMCTL = RAMCTL__CRMD__RGB_5BIT_1024; + + vdp2.reg.VRSIZE = 0; + + /* enable display of NBG0 */ + vdp2.reg.BGON = BGON__N0ON | BGON__N0TPON; + + /* set character format for NBG0 to palettized 16 color + set enable "cell format" for NBG0 + set character size for NBG0 to 1x1 cell */ + vdp2.reg.CHCTLA = CHCTLA__N0CHCN__16_COLOR + | CHCTLA__N0BMEN__CELL_FORMAT + | CHCTLA__N0CHSZ__1x1_CELL; + /* "Note: In color RAM modes 0 and 2, 2048-color becomes 1024-color" */ + + /* plane size */ + vdp2.reg.PLSZ = PLSZ__N0PLSZ__1x1; + + /* map plane offset + 1-word: value of bit 6-0 * 0x2000 + 2-word: value of bit 5-0 * 0x4000 + */ + constexpr int plane_a = 0; + constexpr int plane_a_offset = plane_a * 0x4000; + + constexpr int page_size = 64 * 64 * 2; // N0PNB__1WORD (16-bit) + constexpr int plane_size = page_size * 1; + + vdp2.reg.CYCA0 = 0x0F44F99F; + vdp2.reg.CYCB0 = 0x0F44F99F; + + vdp2.reg.MPOFN = MPOFN__N0MP(0); // bits 8~6 + vdp2.reg.MPABN0 = MPABN0__N0MPB(0) | MPABN0__N0MPA(plane_a); // bits 5~0 + vdp2.reg.MPCDN0 = MPABN0__N0MPD(0) | MPABN0__N0MPC(0); // bits 5~0 + + // zeroize character/cell data from 0 up to plane_a_offset + fill(&vdp2.vram.u32[(0 / 4)], 0, plane_a_offset); + + uint32_t top = (sizeof (union vdp2_vram)); + palette_data(); + uint32_t kirby_address = top = cell_data(top); + uint32_t pattern_name = kirby_address / 32; + + /* use 1-word (16-bit) pattern names */ + //vdp2.reg.PNCN0 = PNCN0__N0PNB__1WORD | PNCN0__N0CNSM | PNCN0__N0SCN((pattern_name >> 10) & 0x1f); + //fill(&vdp2.vram.u16[(plane_a_offset / 4)], pattern_name & 0xfff, plane_size); + + /* use 2-word (32-bit) pattern names */ + vdp2.reg.PNCN0 = PNCN0__N0PNB__2WORD; + fill(&vdp2.vram.u32[(plane_a_offset / 2)], pattern_name, plane_size); + + // both 1-word and 2-word have identical behavior; 2-word is enabled to reduce/focus suspicion. +} + +extern "C" +void start(void) +{ + main(); + while (1) {} +}