commit d773e368743acee509795c952362f3c837aae881 Author: Zack Buhman Date: Wed Jul 16 12:58:59 2025 -0500 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..206b71c --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.pyc +__pycache__ +.~* +*.BIN +*.bin +*.elf +*.d +*.iso +*.cdi +*.o +*.out +*.gch +*.blend1 +*.scramble +*.FCStd1 \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9366e0f --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +all: src/demo/ballistics.elf + +OPT = -O2 + +MAKEFILE_PATH := $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST))))) +LIB ?= $(MAKEFILE_PATH)/dreamcast +CFLAGS += -I$(MAKEFILE_PATH)/ +CFLAGS += -I$(MAKEFILE_PATH)/src +CFLAGS += -I$(MAKEFILE_PATH)/dreamcast +CFLAGS += -Wno-error=strict-aliasing -fno-strict-aliasing +CARCH = -m4-single -ml + +include dreamcast/base.mk +include dreamcast/common.mk +include dreamcast/headers.mk +include dreamcast/ip.mk + +include demo.mk diff --git a/demo.mk b/demo.mk new file mode 100644 index 0000000..9f17629 --- /dev/null +++ b/demo.mk @@ -0,0 +1,16 @@ +DEMO_OBJ = \ + $(LIB)/holly/core.o \ + $(LIB)/holly/region_array.o \ + $(LIB)/holly/background.o \ + $(LIB)/holly/ta_fifo_polygon_converter.o \ + $(LIB)/holly/framebuffer.o \ + $(LIB)/sh7091/serial.o \ + $(LIB)/sh7091/c_serial.o \ + $(LIB)/maple/maple.o \ + $(LIB)/printf/printf.o \ + $(LIB)/printf/unparse.o \ + $(LIB)/printf/parse.o \ + src/demo/demo.o + +demo.elf: LDSCRIPT = $(LIB)/main.lds +demo.elf: $(START_OBJ) $(DEMO_OBJ) $(LIBGCC) diff --git a/dreamcast b/dreamcast new file mode 120000 index 0000000..c64555a --- /dev/null +++ b/dreamcast @@ -0,0 +1 @@ +../dreamcast \ No newline at end of file diff --git a/src/demo/ballistics.cpp b/src/demo/ballistics.cpp new file mode 100644 index 0000000..aef6e97 --- /dev/null +++ b/src/demo/ballistics.cpp @@ -0,0 +1,99 @@ +#include "physics/particle.hpp" + +namespace demo::ballistic { + + enum struct projectile_type { + NONE, + PISTOL, + ARTILLERY, + FIREBALL, + LASER + }; + + struct projectile + { + physics::particle particle; + projectile_type type; + uint32_t start_time; + + void draw() + { + } + }; + + constexpr int max_projectiles = 32; + projectile projectiles[max_projectiles]; + projectile_type current_projectile_type; + + void init() + { + current_projectile_type = PISTOL; + + for (int i = 0; i < max_projectiles; i++) { + projectiles[i].type = projectile_type::NONE; + } + } + + void fire() + { + projectile * projectile; + + for (int i = 0; i < max_projectiles; i++) { + projectile = &projectiles[i]; + if (projectile->type == UNUSED) + break; + } + + if (i >= max_projectiles) + return; // too many projectiles + + switch (current_projectile_type) { + case projectile_type::PISTOL: + projectile->particle.inverse_mass = 1.0f / 2.0f; + projectile->particle.velocity = vec3(0.0f, 0.0f, 35.0f); + projectile->particle.acceleration = vec3(0.0f, -1.0f, 0.0f); + projectile->particle.damping = 0.99f; + break; + case projectile_type::ARTILLERY: + projectile->particle.inverse_mass = 1.0f / 1.0f; + projectile->particle.velocity = vec3(0.0f, 30.0f, 40.0f); + projectile->particle.acceleration = vec3(0.0f, -20.0f, 0.0f); + projectile->particle.damping = 0.99f; + break; + case projectile_type::FIREBALL: + projectile->particle.inverse_mass = 1.0f / 10.0f; + projectile->particle.velocity = vec3(0.0f, 0.0f, 10.0f); + projectile->particle.acceleration = vec3(0.0f, 0.6f, 0.0f); + projectile->particle.damping = 0.9f; + break; + case projectile_type::LASER: + projectile->particle.inverse_mass = 1.0f / 0.1f; + projectile->particle.velocity = vec3(0.0f, 0.0f, 100.0f); + projectile->particle.acceleration = vec3(0.0f, 0.0f, 0.0f); + projectile->particle.damping = 0.99f; + break; + } + + projectile->particle.position = vec3(0.0f, 1.5f, 0.0f); + //projectile->start_time = FIXME; + projectile->type = current_projectile_type; + //projectile->particle.clear_accumulator(); FIXME + } + + void update() + { + float duration = 1.0f / 60.0f; + + for (int i = 0; i < max_projectiles; i++) { + projectile * projectile = &projectiles[i]; + if (projectile->type == projectile_type::UNUSED) + continue; + + projectile->integrate(duration); + } + } + + void draw() + { + } +} diff --git a/src/demo/demo.cpp b/src/demo/demo.cpp new file mode 100644 index 0000000..65b941d --- /dev/null +++ b/src/demo/demo.cpp @@ -0,0 +1,215 @@ +#include "assert.h" +#include "interrupt.hpp" +//#include "aica/aica.hpp" + +#include "holly/holly.hpp" +#include "holly/ta_bits.hpp" +#include "holly/region_array.hpp" +#include "holly/background.hpp" +#include "holly/core_bits.hpp" +#include "holly/core.hpp" +#include "holly/framebuffer.hpp" +#include "holly/texture_memory_alloc9.hpp" +#include "holly/ta_fifo_texture_memory_transfer.hpp" +#include "holly/ta_fifo_polygon_converter.hpp" + +#include "ta_parameter_presets.hpp" + +#include "printf/printf.h" + +void vbr100() +{ + serial::string("vbr100\n"); + interrupt_exception(); +} + +void vbr400() +{ + serial::string("vbr400\n"); + interrupt_exception(); +} + +static volatile int ta_in_use = 0; +static volatile int core_in_use = 0; +static volatile int next_frame = 0; +static volatile int framebuffer_ix = 0; +static volatile int next_frame_ix = 0; + +static inline void graphics_interrupt(uint32_t istnrm) +{ + if (istnrm & istnrm::v_blank_in) { + system.ISTNRM = istnrm::v_blank_in; + + next_frame = 1; + holly.FB_R_SOF1 = texture_memory_alloc.framebuffer[next_frame_ix].start; + holly.FB_R_SOF2 = texture_memory_alloc.framebuffer[next_frame_ix].start; + } + + if (istnrm & istnrm::end_of_render_tsp) { + system.ISTNRM = istnrm::end_of_render_tsp + | istnrm::end_of_render_isp + | istnrm::end_of_render_video; + + next_frame_ix = framebuffer_ix; + framebuffer_ix += 1; + if (framebuffer_ix >= 3) framebuffer_ix = 0; + + core_in_use = 0; + } + + if (istnrm & istnrm::end_of_transferring_opaque_list) { + system.ISTNRM = istnrm::end_of_transferring_opaque_list; + + core_in_use = 1; + core_start_render2(texture_memory_alloc.region_array.start, + texture_memory_alloc.isp_tsp_parameters.start, + texture_memory_alloc.background[0].start, + texture_memory_alloc.framebuffer[framebuffer_ix].start, + framebuffer::framebuffer.px_width); + + ta_in_use = 0; + } +} + +static bool inside_interrupt = false; + +void vbr600() +{ + assert(inside_interrupt == false); + inside_interrupt = true; + uint32_t sr; + asm volatile ("stc sr,%0" : "=r" (sr)); + sr |= sh::sr::imask(15); + asm volatile ("ldc %0,sr" : : "r" (sr)); + + if (sh7091.CCN.EXPEVT == 0 && sh7091.CCN.INTEVT == 0x320) { // Holly + uint32_t istnrm = system.ISTNRM; + uint32_t isterr = system.ISTERR; + + if (isterr) { + serial::string("isterr: "); + serial::integer(system.ISTERR); + } + + graphics_interrupt(istnrm); + } else if (sh7091.CCN.EXPEVT == 0 && sh7091.CCN.INTEVT == 0x360) { // AICA + //wait(); aica_sound.common.mcire = (1 << 6); // interrupt timer A + + //scene::current_scene->interrupt(); + } else { + serial::string("vbr600\n"); + interrupt_exception(); + } + + sr &= ~sh::sr::imask(15); + asm volatile ("ldc %0,sr" : : "r" (sr)); + inside_interrupt = false; +} + +void draw(ta_parameter_writer& writer) +{ + global_polygon_intensity(writer, {1.0, 0.0, 0.0}); + + quad_type_2(writer, + {10, 10, 1}, + {90, 10, 1}, + {90, 90, 1}, + {10, 90, 1}, + 1.0); + + writer.append() = + ta_global_parameter::end_of_list(para_control::para_type::end_of_list); +} + +void main() +{ + serial::init(0); + + core_init(); + framebuffer::scaler_init(); + + // read + while (spg_status::vsync(holly.SPG_STATUS)); + while (!spg_status::vsync(holly.SPG_STATUS)); + + system.LMMODE0 = 1; // 32-bit address space + system.LMMODE1 = 1; // 32-bit address space + + int length = texture_memory_alloc.framebuffer[2].start; + ta_fifo_texture_memory_transfer::zeroize(&ta_fifo_texture_memory[0 / 4], + length, + 0x00c0bebc); + ta_fifo_texture_memory_transfer::zeroize(&ta_fifo_texture_memory[length / 4], + 720 * 480 * 2, + 0xc5f7c5f7); + + framebuffer::spg_set_mode_640x480_vga(); + framebuffer::init(640, 480, + texture_memory_alloc.framebuffer[0].start); + core_param_init(texture_memory_alloc.region_array.start, + texture_memory_alloc.isp_tsp_parameters.start, + texture_memory_alloc.background[0].start, + framebuffer::framebuffer.px_width); + + holly.SOFTRESET = softreset::pipeline_soft_reset + | softreset::ta_soft_reset; + holly.SOFTRESET = 0; + + uint32_t ta_alloc + = ta_alloc_ctrl::pt_opb::no_list + | ta_alloc_ctrl::tm_opb::no_list + | ta_alloc_ctrl::t_opb::no_list + | ta_alloc_ctrl::om_opb::no_list + | ta_alloc_ctrl::o_opb::_32x4byte; + + struct opb_size opb_size = { + .opaque = 32 * 4, + .opaque_modifier = 0, + .translucent = 0, + .translucent_modifier = 0, + .punch_through = 0 + }; + + + background_parameter2(texture_memory_alloc.background[0].start, + 0x110012); + + region_array_multipass(framebuffer::framebuffer.tile_width(), + framebuffer::framebuffer.tile_height(), + &opb_size, + 1, + texture_memory_alloc.region_array.start, + texture_memory_alloc.object_list.start); + + static uint8_t op_buf[1024 * 1024] __attribute__((aligned(32))); + ta_parameter_writer writer(op_buf, (sizeof (op_buf))); + + interrupt_init(); + + system.IML6NRM = istnrm::end_of_render_tsp + | istnrm::v_blank_in + | istnrm::end_of_transferring_opaque_list; + + while (1) { + writer.offset = 0; + draw(writer); + + while (ta_in_use); + while (core_in_use); + ta_in_use = 1; + ta_polygon_converter_init2(texture_memory_alloc.isp_tsp_parameters.start, + texture_memory_alloc.isp_tsp_parameters.end, + texture_memory_alloc.object_list.start, + texture_memory_alloc.object_list.end, + opb_size.total(), + ta_alloc, + framebuffer::framebuffer.tile_width(), + framebuffer::framebuffer.tile_height()); + + ta_polygon_converter_writeback(writer.buf, writer.offset); + ta_polygon_converter_transfer(writer.buf, writer.offset); + + while (next_frame == 0); + next_frame = 0; + } +} diff --git a/src/demo/framebuffer.cpp b/src/demo/framebuffer.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/demo/graphics.cpp b/src/demo/graphics.cpp new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/demo/graphics.cpp @@ -0,0 +1 @@ + diff --git a/src/physics/particle.cpp b/src/physics/particle.cpp new file mode 100644 index 0000000..3b85cbb --- /dev/null +++ b/src/physics/particle.cpp @@ -0,0 +1,23 @@ +#include "assert.h" +#include "particle.hpp" + +namespace physics { + + void particle::integrate(float duration) + { + assert(duration > 0.0f); + + // linear position + position += velocity * duration; + + // acceleration from force + vec3 acc = acceleration + force_accum * inverse_mass; + + // linear velocity + velocity += acc * duration; + + // drag + velocity *= damping; + } + +} diff --git a/src/physics/particle.hpp b/src/physics/particle.hpp new file mode 100644 index 0000000..7732d8a --- /dev/null +++ b/src/physics/particle.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "math/float_types.hpp" + +namespace physics { + + struct particle + { + vec3 position; + vec3 velocity; + vec3 acceleration; + float damping; + float inverse_mass; + vec3 force_accum; + + void integrate(float duration); + }; + +} diff --git a/src/ta_parameter_presets.hpp b/src/ta_parameter_presets.hpp new file mode 100644 index 0000000..d9cbd2f --- /dev/null +++ b/src/ta_parameter_presets.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include "holly/ta_parameter.hpp" +#include "holly/ta_vertex_parameter.hpp" +#include "holly/ta_global_parameter.hpp" +#include "holly/isp_tsp.hpp" + +#include "math/float_types.hpp" + +static inline void global_polygon_intensity(ta_parameter_writer& writer, + const vec3& color) +{ + const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume + | para_control::list_type::opaque + | obj_control::col_type::intensity_mode_1 + ; + + const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater_or_equal + | isp_tsp_instruction_word::culling_mode::no_culling; + + const uint32_t tsp_instruction_word = tsp_instruction_word::texture_shading_instruction::decal + | tsp_instruction_word::src_alpha_instr::one + | tsp_instruction_word::dst_alpha_instr::zero + | tsp_instruction_word::fog_control::no_fog; + + const uint32_t texture_control_word = 0; + + writer.append() = + ta_global_parameter::polygon_type_1(parameter_control_word, + isp_tsp_instruction_word, + tsp_instruction_word, + texture_control_word, + 1.0f, color.x, color.y, color.z); +} + +static inline void quad_type_2(ta_parameter_writer& writer, + const vec3& ap, + const vec3& bp, + const vec3& cp, + const vec3& dp, + float base_intensity) +{ + writer.append() = + ta_vertex_parameter::polygon_type_2(polygon_vertex_parameter_control_word(false), + ap.x, ap.y, ap.z, + base_intensity); + + writer.append() = + ta_vertex_parameter::polygon_type_2(polygon_vertex_parameter_control_word(false), + bp.x, bp.y, bp.z, + base_intensity); + + writer.append() = + ta_vertex_parameter::polygon_type_2(polygon_vertex_parameter_control_word(false), + dp.x, dp.y, dp.z, + base_intensity); + + writer.append() = + ta_vertex_parameter::polygon_type_2(polygon_vertex_parameter_control_word(true), + cp.x, cp.y, cp.z, + base_intensity); +}