From 4bb04a0362008d8c14125c893bdb9213284950cd Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Sat, 30 Dec 2023 10:53:39 +0800 Subject: [PATCH] example: add maple_analog Also adds the incomplete modifier_volume example. This also adds vec2 for UV coordinates, and obj_to_cpp has been modified to parse vertex texture coordinates from obj files. --- Makefile | 28 +-- common.mk | 6 + example/example.mk | 13 + example/maple_analog.cpp | 235 ++++++++++++++++++ example/modifier_volume.cpp | 155 ++++++++++++ geometry/border.hpp | 42 ++++ geometry/border.obj | 29 +++ geometry/circle.hpp | 80 ++++++ geometry/circle.obj | 67 +++++ geometry/cube.hpp | 43 ---- geometry/cube.obj | 57 +++-- geometry/geometry.hpp | 3 + geometry/plane.obj | 15 ++ maple/maple.cpp | 27 -- maple/maple.hpp | 7 +- maple/maple_bus_bits.hpp | 2 + maple/maple_bus_commands.hpp | 161 ++++++------ maple/maple_impl.hpp | 46 ++++ math/vec2.hpp | 147 +++++++++++ math/vec3.hpp | 5 +- math/vec4.hpp | 5 +- qemu.lds | 61 +++++ regs/gen/core_bits.py | 2 + ...aple_commands.py => maple_bus_commands.py} | 8 +- regs/maple_bus_bits.ods | Bin 14517 -> 15789 bytes regs/maple_host_bits.csv | 30 --- regs/maple_host_bits.ods | Bin 14126 -> 0 bytes tools/obj_to_cpp.py | 103 ++++++-- 28 files changed, 1127 insertions(+), 250 deletions(-) create mode 100644 example/maple_analog.cpp create mode 100644 example/modifier_volume.cpp create mode 100644 geometry/border.hpp create mode 100644 geometry/border.obj create mode 100644 geometry/circle.hpp create mode 100644 geometry/circle.obj create mode 100644 geometry/plane.obj create mode 100644 maple/maple_impl.hpp create mode 100644 math/vec2.hpp create mode 100644 qemu.lds rename regs/gen/{maple_commands.py => maple_bus_commands.py} (96%) delete mode 100644 regs/maple_host_bits.csv delete mode 100644 regs/maple_host_bits.ods diff --git a/Makefile b/Makefile index c736c7a..25f67c2 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,8 @@ -all: main.elf +all: include common.mk + +geometry/%.hpp: geometry/%.obj + PYTHONPATH=regs/gen python tools/obj_to_cpp.py $< > $@ + include example/example.mk - -MAIN_OBJ = \ - main.o \ - vga.o \ - rgb.o \ - holly/background.o \ - holly/region_array.o \ - holly/ta_fifo_polygon_converter.o \ - holly/core.o \ - maple/maple.o \ - scene.o \ - macaw.data.o \ - wink.data.o - -serial.elf: LDSCRIPT = $(LIB)/alt.lds -serial.elf: $(START_OBJ) serial_main.o load.o - -main.elf: LDSCRIPT = $(LIB)/main.lds -main.elf: $(START_OBJ) $(MAIN_OBJ) - -test.elf: LDSCRIPT = $(LIB)/alt.lds -test.elf: $(START_OBJ) $(MAIN_OBJ) diff --git a/common.mk b/common.mk index 8bbee2b..afa9463 100644 --- a/common.mk +++ b/common.mk @@ -130,6 +130,12 @@ audio.pcm: %.data.o: %.data $(BUILD_BINARY_O) +maple/maple_bus_commands.hpp: regs/maple_bus_commands.csv regs/gen/maple_bus_commands.py + python regs/gen/maple_bus_commands.py $< > $@ + +maple/maple_bus_bits.hpp: regs/maple_bus_bits.csv regs/gen/core_bits.py + python regs/gen/core_bits.py $< > $@ + clean: find -P \ -regextype posix-egrep \ diff --git a/example/example.mk b/example/example.mk index d6108c0..d0583af 100644 --- a/example/example.mk +++ b/example/example.mk @@ -193,6 +193,19 @@ MAPLE_VIBRATOR_OBJ = \ example/maple_vibrator.elf: LDSCRIPT = $(LIB)/alt.lds example/maple_vibrator.elf: $(START_OBJ) $(MAPLE_VIBRATOR_OBJ) +MAPLE_ANALOG_OBJ = \ + example/maple_analog.o \ + vga.o \ + holly/core.o \ + holly/region_array.o \ + holly/background.o \ + holly/ta_fifo_polygon_converter.o \ + serial.o \ + maple/maple.o + +example/maple_analog.elf: LDSCRIPT = $(LIB)/alt.lds +example/maple_analog.elf: $(START_OBJ) $(MAPLE_ANALOG_OBJ) + SERIAL_TRANSFER_OBJ = \ example/serial_transfer.o \ serial_load.o diff --git a/example/maple_analog.cpp b/example/maple_analog.cpp new file mode 100644 index 0000000..7f78a31 --- /dev/null +++ b/example/maple_analog.cpp @@ -0,0 +1,235 @@ +#include +#include + +#include "align.hpp" + +#include "vga.hpp" +#include "holly.hpp" +#include "holly/core.hpp" +#include "holly/core_bits.hpp" +#include "holly/ta_fifo_polygon_converter.hpp" +#include "holly/ta_parameter.hpp" +#include "holly/ta_bits.hpp" +#include "holly/region_array.hpp" +#include "holly/background.hpp" +#include "holly/texture_memory_alloc.hpp" +#include "memorymap.hpp" +#include "serial.hpp" + +#include "geometry/border.hpp" +#include "geometry/circle.hpp" +#include "math/vec4.hpp" + +#include "maple/maple.hpp" +#include "maple/maple_impl.hpp" +#include "maple/maple_bus_bits.hpp" +#include "maple/maple_bus_commands.hpp" +#include "maple/maple_bus_ft0.hpp" + +uint32_t _command_buf[1024 / 4 + 32]; +uint32_t _receive_buf[1024 / 4 + 32]; + +static ft0::data_transfer::data_format data[4]; + +void do_get_condition(uint32_t * command_buf, + uint32_t * receive_buf) +{ + using command_type = get_condition; + using response_type = data_transfer; + + get_condition::data_fields data_fields = { + .function_type = std::byteswap(function_type::controller) + }; + + maple::init_host_command_all_ports(command_buf, receive_buf, + data_fields); + maple::dma_start(command_buf); + + using command_response_type = struct maple::command_response; + for (uint8_t port = 0; port < 4; port++) { + auto response = reinterpret_cast(receive_buf); + auto& bus_data = response[port].bus_data; + if (bus_data.command_code != response_type::command_code) { + return; + } + auto& data_fields = bus_data.data_fields; + if ((data_fields.function_type & std::byteswap(function_type::controller)) == 0) { + return; + } + + /* + bool a = ft0::data_transfer::digital_button::a(data_fields.data.digital_button); + if (a == 0) { + serial::string("port "); + serial::integer(port); + serial::string(" `a` press "); + serial::integer(a); + } + */ + data[port].analog_axis_3 = data_fields.data.analog_axis_3; + data[port].analog_axis_4 = data_fields.data.analog_axis_4; + } +} + +void transform(ta_parameter_writer& parameter, + const vec3 * vertices, + const face& face, + const vec4& color, + const vec3& position, + const float scale + ) +{ + const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume + | para_control::list_type::opaque + | obj_control::col_type::floating_color + | obj_control::gouraud; + + const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater + | isp_tsp_instruction_word::culling_mode::cull_if_positive; + + const uint32_t tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one + | tsp_instruction_word::dst_alpha_instr::zero + | tsp_instruction_word::fog_control::no_fog; + + parameter.append() = global_polygon_type_0(parameter_control_word, + isp_tsp_instruction_word, + tsp_instruction_word, + 0); + + constexpr uint32_t strip_length = 3; + for (uint32_t i = 0; i < strip_length; i++) { + bool end_of_strip = i == strip_length - 1; + + // world transform + uint32_t vertex_ix = face[i].vertex; + auto& vertex = vertices[vertex_ix]; + auto point = vertex; + + // rotate 90° around the X axis + float x = point.x; + float y = point.z; + float z = point.y; + + // world transform + x *= scale; // world space + y *= scale; // world space + z *= 10; + + // object transform + x += position.x; // object space + y += position.y; // object space + z += position.z; // object space + + // camera transform + z += 1; + //y -= 10; + + // screen space transform + x *= 240.f; + y *= 240.f; + x += 320.f; + y += 240.f; + z = 1 / z; + + parameter.append() = + vertex_polygon_type_1(x, y, z, + color.w, // alpha + color.x, // r + color.y, // g + color.z, // b + end_of_strip); + } +} + +void init_texture_memory(const struct opb_size& opb_size) +{ + auto mem = reinterpret_cast(texture_memory32); + + background_parameter(mem->background, 0xff220000); + + region_array2(mem->region_array, + (offsetof (struct texture_memory_alloc, object_list)), + 640 / 32, // width + 480 / 32, // height + opb_size + ); +} + +uint32_t _ta_parameter_buf[((32 * 8192) + 32) / 4]; + +void main() +{ + uint32_t * command_buf = align_32byte(_command_buf); + uint32_t * receive_buf = align_32byte(_receive_buf); + + vga(); + + // The address of `ta_parameter_buf` must be a multiple of 32 bytes. + // This is mandatory for ch2-dma to the ta fifo polygon converter. + uint32_t * ta_parameter_buf = align_32byte(_ta_parameter_buf); + + constexpr 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::_16x4byte; + + constexpr struct opb_size opb_size = { .opaque = 16 * 4 + , .opaque_modifier = 0 + , .translucent = 0 + , .translucent_modifier = 0 + , .punch_through = 0 + }; + + holly.SOFTRESET = softreset::pipeline_soft_reset + | softreset::ta_soft_reset; + holly.SOFTRESET = 0; + + core_init(); + init_texture_memory(opb_size); + + uint32_t frame_ix = 0; + constexpr uint32_t num_frames = 1; + + while (1) { + do_get_condition(command_buf, receive_buf); + + ta_polygon_converter_init(opb_size.total(), + ta_alloc, + 640 / 32, + 480 / 32); + + float x_pos = static_cast(data[0].analog_axis_3 - 0x80) * (0.5 / 127); + float y_pos = static_cast(data[0].analog_axis_4 - 0x80) * (0.5 / 127); + + auto parameter = ta_parameter_writer(ta_parameter_buf); + for (uint32_t i = 0; i < border::num_faces; i++) { + transform(parameter, + border::vertices, + border::faces[i], + {1.0, 0.0, 0.0, 1.0}, // color + {0.0, 0.0, 0.0}, // position + 0.5f * (1.f / 0.95f) // scale + ); + } + + for (uint32_t i = 0; i < circle::num_faces; i++) { + transform(parameter, + circle::vertices, + circle::faces[i], + {0.0, 1.0, 1.0, 1.0}, // color + {x_pos, y_pos, 0.0}, // position + 0.05f // scale + ); + } + + parameter.append() = global_end_of_list(); + ta_polygon_converter_transfer(ta_parameter_buf, parameter.offset); + ta_wait_opaque_list(); + core_start_render(frame_ix, num_frames); + + v_sync_out(); + core_wait_end_of_render_video(frame_ix, num_frames); + frame_ix += 1; + } +} diff --git a/example/modifier_volume.cpp b/example/modifier_volume.cpp new file mode 100644 index 0000000..f541b2d --- /dev/null +++ b/example/modifier_volume.cpp @@ -0,0 +1,155 @@ +#include + +#include "align.hpp" +#include "vga.hpp" + +#include "holly/texture_memory_alloc.hpp" +#include "holly.hpp" +#include "holly/core.hpp" +#include "holly/core_bits.hpp" +#include "holly/ta_fifo_polygon_converter.hpp" +#include "holly/ta_parameter.hpp" +#include "holly/ta_bits.hpp" +#include "holly/region_array.hpp" +#include "holly/background.hpp" +#include "memorymap.hpp" + +struct vertex { + float x; + float y; + float z; + float u; + float v; + uint32_t color; +}; + +const struct vertex strip_vertices[4] = { + // [ position ] [ uv coordinates ] [color ] + { -0.5f, 0.5f, 0.f, 0.f , 127.f/128.f, 0x00000000}, // the first two base colors in a + { -0.5f, -0.5f, 0.f, 0.f , 0.f , 0x00000000}, // non-Gouraud triangle strip are ignored + { 0.5f, 0.5f, 0.f, 127.f/128.f, 127.f/128.f, 0x00000000}, + { 0.5f, -0.5f, 0.f, 127.f/128.f, 0.f , 0x00000000}, +}; +constexpr uint32_t strip_length = (sizeof (strip_vertices)) / (sizeof (struct vertex)); + +static float theta = 0; +constexpr float half_degree = 0.01745329f / 2.f; + +uint32_t transform(uint32_t * ta_parameter_buf, + const vertex * strip_vertices, + const uint32_t strip_length) +{ + auto parameter = ta_parameter_writer(ta_parameter_buf); + uint32_t texture_address = (offsetof (struct texture_memory_alloc, texture)); + parameter.append() = global_polygon_type_0(texture_address); + + for (uint32_t i = 0; i < strip_length; i++) { + bool end_of_strip = i == strip_length - 1; + + float x = strip_vertices[i].x; + float y = strip_vertices[i].y; + float z = strip_vertices[i].z; + float x1; + + x1 = x * __builtin_cosf(theta) - z * __builtin_sinf(theta); + z = x * __builtin_sinf(theta) + z * __builtin_cosf(theta); + x = x1; + x *= 240.f; + y *= 240.f; + x += 320.f; + y += 240.f; + z = 1.f / (z + 10.f); + + parameter.append() = + vertex_polygon_type_3(x, y, z, + strip_vertices[i].u, + strip_vertices[i].v, + strip_vertices[i].color, + end_of_strip); + } + + parameter.append() = global_end_of_list(); + + return parameter.offset; +} + +void init_texture_memory(const struct opb_size& opb_size) +{ + auto mem = reinterpret_cast(texture_memory32); + + background_parameter(mem->background); + + region_array2(mem->region_array, + (offsetof (struct texture_memory_alloc, object_list)), + 640 / 32, // width + 480 / 32, // height + opb_size + ); +} + +void copy_macaw_texture() +{ + auto src = reinterpret_cast(&_binary_macaw_data_start); + auto size = reinterpret_cast(&_binary_macaw_data_size); + auto mem = reinterpret_cast(texture_memory64); + for (uint32_t px = 0; px < size / 3; px++) { + uint8_t r = src[px * 3 + 0]; + uint8_t g = src[px * 3 + 1]; + uint8_t b = src[px * 3 + 2]; + + uint16_t rgb565 = ((r / 8) << 11) | ((g / 4) << 5) | ((b / 8) << 0); + mem->texture[px] = rgb565; + } +} + +uint32_t _ta_parameter_buf[((32 * (strip_length + 2)) + 32) / 4]; + +void main() +{ + vga(); + copy_macaw_texture(); + + // The address of `ta_parameter_buf` must be a multiple of 32 bytes. + // This is mandatory for ch2-dma to the ta fifo polygon converter. + uint32_t * ta_parameter_buf = align_32byte(_ta_parameter_buf); + + constexpr 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::_16x4byte; + + constexpr struct opb_size opb_size = { .opaque = 16 * 4 + , .opaque_modifier = 0 + , .translucent = 0 + , .translucent_modifier = 0 + , .punch_through = 0 + }; + + constexpr uint32_t tiles = (640 / 32) * (320 / 32); + + holly.SOFTRESET = softreset::pipeline_soft_reset + | softreset::ta_soft_reset; + holly.SOFTRESET = 0; + + core_init(); + init_texture_memory(opb_size); + + uint32_t frame_ix = 0; + constexpr uint32_t num_frames = 1; + + while (true) { + ta_polygon_converter_init(opb_size.total() * tiles, ta_alloc); + uint32_t ta_parameter_size = transform(ta_parameter_buf, strip_vertices, strip_length); + ta_polygon_converter_transfer(ta_parameter_buf, ta_parameter_size); + ta_wait_opaque_list(); + + core_start_render(frame_ix, num_frames); + + v_sync_in(); + core_wait_end_of_render_video(frame_ix, num_frames); + + theta += half_degree; + frame_ix += 1; + } +} diff --git a/geometry/border.hpp b/geometry/border.hpp new file mode 100644 index 0000000..5b4ce2c --- /dev/null +++ b/geometry/border.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include "geometry.hpp" + +namespace border { + constexpr vec3 vertices[] = { + { -1.000000f, 0.000000f, 1.000000f }, + { 1.000000f, 0.000000f, 1.000000f }, + { -1.000000f, 0.000000f, -1.000000f }, + { 1.000000f, 0.000000f, -1.000000f }, + { 0.950000f, 0.000000f, 1.000000f }, + { 0.950000f, 0.000000f, -1.000000f }, + { 0.950000f, 0.000000f, 0.950000f }, + { 0.950000f, 0.000000f, -0.950000f }, + { -0.950000f, 0.000000f, -1.000000f }, + { -0.950000f, 0.000000f, 1.000000f }, + { -0.950000f, 0.000000f, 0.950000f }, + { -0.950000f, 0.000000f, -0.950000f }, + }; + + constexpr vec3 normals[] = { + { -0.000000f, 1.000000f, -0.000000f }, + }; + + constexpr face faces[] = { + {{ 5, 0}, {11, 0}, { 7, 0}}, + {{ 4, 0}, {10, 0}, { 9, 0}}, + {{ 5, 0}, { 8, 0}, {11, 0}}, + {{ 4, 0}, { 6, 0}, {10, 0}}, + {{ 7, 0}, { 3, 0}, { 5, 0}}, + {{ 0, 0}, {10, 0}, {11, 0}}, + {{11, 0}, { 2, 0}, { 0, 0}}, + {{ 1, 0}, { 6, 0}, { 4, 0}}, + {{ 7, 0}, { 6, 0}, { 3, 0}}, + {{ 0, 0}, { 9, 0}, {10, 0}}, + {{11, 0}, { 8, 0}, { 2, 0}}, + {{ 1, 0}, { 3, 0}, { 6, 0}}, + }; + + constexpr uint32_t num_faces = (sizeof (faces)) / (sizeof (face)); + +} diff --git a/geometry/border.obj b/geometry/border.obj new file mode 100644 index 0000000..213a27d --- /dev/null +++ b/geometry/border.obj @@ -0,0 +1,29 @@ +# Blender 3.3.6 +# www.blender.org +o Border +v -1.000000 0.000000 1.000000 +v 1.000000 0.000000 1.000000 +v -1.000000 0.000000 -1.000000 +v 1.000000 0.000000 -1.000000 +v 0.950000 0.000000 1.000000 +v 0.950000 0.000000 -1.000000 +v 0.950000 0.000000 0.950000 +v 0.950000 0.000000 -0.950000 +v -0.950000 0.000000 -1.000000 +v -0.950000 0.000000 1.000000 +v -0.950000 0.000000 0.950000 +v -0.950000 0.000000 -0.950000 +vn -0.0000 1.0000 -0.0000 +s 0 +f 6//1 12//1 8//1 +f 5//1 11//1 10//1 +f 6//1 9//1 12//1 +f 5//1 7//1 11//1 +f 8//1 4//1 6//1 +f 1//1 11//1 12//1 +f 12//1 3//1 1//1 +f 2//1 7//1 5//1 +f 8//1 7//1 4//1 +f 1//1 10//1 11//1 +f 12//1 9//1 3//1 +f 2//1 4//1 7//1 diff --git a/geometry/circle.hpp b/geometry/circle.hpp new file mode 100644 index 0000000..dbe2dea --- /dev/null +++ b/geometry/circle.hpp @@ -0,0 +1,80 @@ +#pragma once + +#include "geometry.hpp" + +namespace circle { + constexpr vec3 vertices[] = { + { 0.000000f, 0.000000f, -1.000000f }, + { -0.195090f, 0.000000f, -0.980785f }, + { -0.382683f, 0.000000f, -0.923880f }, + { -0.555570f, 0.000000f, -0.831470f }, + { -0.707107f, 0.000000f, -0.707107f }, + { -0.831470f, 0.000000f, -0.555570f }, + { -0.923880f, 0.000000f, -0.382683f }, + { -0.980785f, 0.000000f, -0.195090f }, + { -1.000000f, 0.000000f, 0.000000f }, + { -0.980785f, 0.000000f, 0.195090f }, + { -0.923880f, 0.000000f, 0.382683f }, + { -0.831470f, 0.000000f, 0.555570f }, + { -0.707107f, 0.000000f, 0.707107f }, + { -0.555570f, 0.000000f, 0.831470f }, + { -0.382683f, 0.000000f, 0.923880f }, + { -0.195090f, 0.000000f, 0.980785f }, + { 0.000000f, 0.000000f, 1.000000f }, + { 0.195090f, 0.000000f, 0.980785f }, + { 0.382683f, 0.000000f, 0.923880f }, + { 0.555570f, 0.000000f, 0.831470f }, + { 0.707107f, 0.000000f, 0.707107f }, + { 0.831470f, 0.000000f, 0.555570f }, + { 0.923880f, 0.000000f, 0.382683f }, + { 0.980785f, 0.000000f, 0.195090f }, + { 1.000000f, 0.000000f, 0.000000f }, + { 0.980785f, 0.000000f, -0.195090f }, + { 0.923880f, 0.000000f, -0.382683f }, + { 0.831470f, 0.000000f, -0.555570f }, + { 0.707107f, 0.000000f, -0.707107f }, + { 0.555570f, 0.000000f, -0.831470f }, + { 0.382683f, 0.000000f, -0.923880f }, + { 0.195090f, 0.000000f, -0.980785f }, + }; + + constexpr vec3 normals[] = { + { -0.000000f, 1.000000f, -0.000000f }, + }; + + constexpr face faces[] = { + {{31, 0}, { 0, 0}, { 1, 0}}, + {{30, 0}, {31, 0}, { 1, 0}}, + {{20, 0}, {13, 0}, {18, 0}}, + {{ 1, 0}, { 2, 0}, { 3, 0}}, + {{29, 0}, { 1, 0}, { 3, 0}}, + {{28, 0}, {29, 0}, { 3, 0}}, + {{29, 0}, {30, 0}, { 1, 0}}, + {{ 3, 0}, { 4, 0}, { 5, 0}}, + {{27, 0}, { 3, 0}, { 5, 0}}, + {{26, 0}, {27, 0}, { 5, 0}}, + {{26, 0}, { 5, 0}, { 6, 0}}, + {{25, 0}, {26, 0}, { 6, 0}}, + {{25, 0}, { 6, 0}, { 7, 0}}, + {{24, 0}, {25, 0}, { 7, 0}}, + {{24, 0}, { 7, 0}, { 8, 0}}, + {{23, 0}, {24, 0}, { 8, 0}}, + {{23, 0}, { 8, 0}, { 9, 0}}, + {{22, 0}, {23, 0}, { 9, 0}}, + {{22, 0}, { 9, 0}, {10, 0}}, + {{21, 0}, {22, 0}, {10, 0}}, + {{21, 0}, {10, 0}, {11, 0}}, + {{20, 0}, {21, 0}, {11, 0}}, + {{12, 0}, {13, 0}, {11, 0}}, + {{27, 0}, {28, 0}, { 3, 0}}, + {{13, 0}, {20, 0}, {11, 0}}, + {{19, 0}, {20, 0}, {18, 0}}, + {{18, 0}, {13, 0}, {14, 0}}, + {{17, 0}, {18, 0}, {14, 0}}, + {{17, 0}, {14, 0}, {15, 0}}, + {{16, 0}, {17, 0}, {15, 0}}, + }; + + constexpr uint32_t num_faces = (sizeof (faces)) / (sizeof (face)); + +} diff --git a/geometry/circle.obj b/geometry/circle.obj new file mode 100644 index 0000000..a932d98 --- /dev/null +++ b/geometry/circle.obj @@ -0,0 +1,67 @@ +# Blender 3.3.6 +# www.blender.org +o Circle +v 0.000000 0.000000 -1.000000 +v -0.195090 0.000000 -0.980785 +v -0.382683 0.000000 -0.923880 +v -0.555570 0.000000 -0.831470 +v -0.707107 0.000000 -0.707107 +v -0.831470 0.000000 -0.555570 +v -0.923880 0.000000 -0.382683 +v -0.980785 0.000000 -0.195090 +v -1.000000 0.000000 0.000000 +v -0.980785 0.000000 0.195090 +v -0.923880 0.000000 0.382683 +v -0.831470 0.000000 0.555570 +v -0.707107 0.000000 0.707107 +v -0.555570 0.000000 0.831470 +v -0.382683 0.000000 0.923880 +v -0.195090 0.000000 0.980785 +v 0.000000 0.000000 1.000000 +v 0.195090 0.000000 0.980785 +v 0.382683 0.000000 0.923880 +v 0.555570 0.000000 0.831470 +v 0.707107 0.000000 0.707107 +v 0.831470 0.000000 0.555570 +v 0.923880 0.000000 0.382683 +v 0.980785 0.000000 0.195090 +v 1.000000 0.000000 0.000000 +v 0.980785 0.000000 -0.195090 +v 0.923880 0.000000 -0.382683 +v 0.831470 0.000000 -0.555570 +v 0.707107 0.000000 -0.707107 +v 0.555570 0.000000 -0.831470 +v 0.382683 0.000000 -0.923880 +v 0.195090 0.000000 -0.980785 +vn -0.0000 1.0000 -0.0000 +s 0 +f 32//1 1//1 2//1 +f 31//1 32//1 2//1 +f 21//1 14//1 19//1 +f 2//1 3//1 4//1 +f 30//1 2//1 4//1 +f 29//1 30//1 4//1 +f 30//1 31//1 2//1 +f 4//1 5//1 6//1 +f 28//1 4//1 6//1 +f 27//1 28//1 6//1 +f 27//1 6//1 7//1 +f 26//1 27//1 7//1 +f 26//1 7//1 8//1 +f 25//1 26//1 8//1 +f 25//1 8//1 9//1 +f 24//1 25//1 9//1 +f 24//1 9//1 10//1 +f 23//1 24//1 10//1 +f 23//1 10//1 11//1 +f 22//1 23//1 11//1 +f 22//1 11//1 12//1 +f 21//1 22//1 12//1 +f 13//1 14//1 12//1 +f 28//1 29//1 4//1 +f 14//1 21//1 12//1 +f 20//1 21//1 19//1 +f 19//1 14//1 15//1 +f 18//1 19//1 15//1 +f 18//1 15//1 16//1 +f 17//1 18//1 16//1 diff --git a/geometry/cube.hpp b/geometry/cube.hpp index b480325..e69de29 100644 --- a/geometry/cube.hpp +++ b/geometry/cube.hpp @@ -1,43 +0,0 @@ -#pragma once - -#include "geometry.hpp" - -namespace cube { - constexpr vec3 vertices[] = { - { 1.000000f, 1.000000f, -1.000000f }, - { 1.000000f, -1.000000f, -1.000000f }, - { 1.000000f, 1.000000f, 1.000000f }, - { 1.000000f, -1.000000f, 1.000000f }, - { -1.000000f, 1.000000f, -1.000000f }, - { -1.000000f, -1.000000f, -1.000000f }, - { -1.000000f, 1.000000f, 1.000000f }, - { -1.000000f, -1.000000f, 1.000000f }, - }; - - constexpr vec3 normals[] = { - { -0.000000f, 1.000000f, -0.000000f }, - { -0.000000f, -0.000000f, 1.000000f }, - { -1.000000f, -0.000000f, -0.000000f }, - { -0.000000f, -1.000000f, -0.000000f }, - { 1.000000f, -0.000000f, -0.000000f }, - { -0.000000f, -0.000000f, -1.000000f }, - }; - - constexpr face faces[] = { - {{ 4, 0}, { 2, 0}, { 0, 0}}, - {{ 2, 1}, { 7, 1}, { 3, 1}}, - {{ 6, 2}, { 5, 2}, { 7, 2}}, - {{ 1, 3}, { 7, 3}, { 5, 3}}, - {{ 0, 4}, { 3, 4}, { 1, 4}}, - {{ 4, 5}, { 1, 5}, { 5, 5}}, - {{ 4, 0}, { 6, 0}, { 2, 0}}, - {{ 2, 1}, { 6, 1}, { 7, 1}}, - {{ 6, 2}, { 4, 2}, { 5, 2}}, - {{ 1, 3}, { 3, 3}, { 7, 3}}, - {{ 0, 4}, { 2, 4}, { 3, 4}}, - {{ 4, 5}, { 0, 5}, { 1, 5}}, - }; - - constexpr uint32_t num_faces = (sizeof (faces)) / (sizeof (face)); - -} diff --git a/geometry/cube.obj b/geometry/cube.obj index f8e3454..a827254 100644 --- a/geometry/cube.obj +++ b/geometry/cube.obj @@ -1,30 +1,41 @@ # Blender 3.3.6 # www.blender.org o Cube -v 1.000000 1.000000 -1.000000 -v 1.000000 -1.000000 -1.000000 -v 1.000000 1.000000 1.000000 -v 1.000000 -1.000000 1.000000 -v -1.000000 1.000000 -1.000000 -v -1.000000 -1.000000 -1.000000 -v -1.000000 1.000000 1.000000 v -1.000000 -1.000000 1.000000 -vn -0.0000 1.0000 -0.0000 -vn -0.0000 -0.0000 1.0000 +v -1.000000 1.000000 1.000000 +v -1.000000 -1.000000 -1.000000 +v -1.000000 1.000000 -1.000000 +v 1.000000 -1.000000 1.000000 +v 1.000000 1.000000 1.000000 +v 1.000000 -1.000000 -1.000000 +v 1.000000 1.000000 -1.000000 vn -1.0000 -0.0000 -0.0000 -vn -0.0000 -1.0000 -0.0000 -vn 1.0000 -0.0000 -0.0000 vn -0.0000 -0.0000 -1.0000 +vn 1.0000 -0.0000 -0.0000 +vn -0.0000 -0.0000 1.0000 +vn -0.0000 -1.0000 -0.0000 +vn -0.0000 1.0000 -0.0000 +vt 1.000000 0.000000 +vt 1.000000 1.000000 +vt 0.000000 0.000000 +vt 1.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 0.000000 +vt 0.000000 1.000000 +vt 0.000000 0.000000 +vt 1.000000 1.000000 s 0 -f 5//1 3//1 1//1 -f 3//2 8//2 4//2 -f 7//3 6//3 8//3 -f 2//4 8//4 6//4 -f 1//5 4//5 2//5 -f 5//6 2//6 6//6 -f 5//1 7//1 3//1 -f 3//2 7//2 8//2 -f 7//3 5//3 6//3 -f 2//4 4//4 8//4 -f 1//5 3//5 4//5 -f 5//6 1//6 2//6 +f 2/2/1 3/4/1 1/1/1 +f 4/5/2 7/9/2 3/3/2 +f 8/11/3 5/6/3 7/8/3 +f 6/7/4 1/1/4 5/6/4 +f 7/9/5 1/1/5 3/4/5 +f 4/5/6 6/7/6 8/10/6 +f 2/2/1 4/5/1 3/4/1 +f 4/5/2 8/11/2 7/9/2 +f 8/11/3 6/7/3 5/6/3 +f 6/7/4 2/2/4 1/1/4 +f 7/9/5 5/6/5 1/1/5 +f 4/5/6 2/2/6 6/7/6 diff --git a/geometry/geometry.hpp b/geometry/geometry.hpp index a720c02..cf47830 100644 --- a/geometry/geometry.hpp +++ b/geometry/geometry.hpp @@ -2,14 +2,17 @@ #include +#include "math/vec2.hpp" #include "math/vec3.hpp" #include "math/vec4.hpp" +using vec2 = vec<2, float>; using vec3 = vec<3, float>; using vec4 = vec<4, float>; struct vertex__normal { uint16_t vertex; + uint16_t texture; uint16_t normal; }; diff --git a/geometry/plane.obj b/geometry/plane.obj new file mode 100644 index 0000000..6c70187 --- /dev/null +++ b/geometry/plane.obj @@ -0,0 +1,15 @@ +# Blender 3.3.6 +# www.blender.org +o Plane +v -1.000000 0.000000 1.000000 +v 1.000000 0.000000 1.000000 +v -1.000000 0.000000 -1.000000 +v 1.000000 0.000000 -1.000000 +vn -0.0000 1.0000 -0.0000 +vt 0.000000 0.000000 +vt 1.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 1.000000 +s 0 +f 2/2/1 3/3/1 1/1/1 +f 2/2/1 4/4/1 3/3/1 diff --git a/maple/maple.cpp b/maple/maple.cpp index 69536f1..0fbb854 100644 --- a/maple/maple.cpp +++ b/maple/maple.cpp @@ -37,33 +37,6 @@ void init_host_command(uint32_t * command_buf, uint32_t * receive_buf, host_command->bus_data.data_size = data_size / 4; } -void init_host_command_all_ports(uint32_t * buf, uint32_t * receive_buf, - uint8_t command_code, uint32_t command_data_size, uint32_t response_data_size) -{ - const uint32_t command_size = ((sizeof (struct host_command)) + command_data_size); - const uint32_t response_size = align_32byte(((sizeof (struct command_response)) + response_data_size)); - - init_host_command(&buf[(command_size / 4) * 0], &receive_buf[(response_size / 4) * 0], - host_instruction::port_select::a, // destination_port - ap::de::device | ap::port_select::a, command_code, command_data_size, - false); // end_flag - - init_host_command(&buf[(command_size / 4) * 1], &receive_buf[(response_size / 4) * 1], - host_instruction::port_select::b, // destination_port - ap::de::device | ap::port_select::b, command_code, command_data_size, - false); // end_flag - - init_host_command(&buf[(command_size / 4) * 2], &receive_buf[(response_size / 4) * 2], - host_instruction::port_select::c, // destination_port - ap::de::device | ap::port_select::c, command_code, command_data_size, - false); // end_flag - - init_host_command(&buf[(command_size / 4) * 3], &receive_buf[(response_size / 4) * 3], - host_instruction::port_select::d, // destination_port - ap::de::device | ap::port_select::d, command_code, command_data_size, - true); // end_flag -} - void init_device_request(uint32_t * buf, uint32_t * receive_buf, uint32_t destination_port, uint8_t destination_ap) diff --git a/maple/maple.hpp b/maple/maple.hpp index c9e9850..dc2b8ea 100644 --- a/maple/maple.hpp +++ b/maple/maple.hpp @@ -2,6 +2,8 @@ #include +#include "align.hpp" + namespace maple { template @@ -26,16 +28,15 @@ struct command_response { uint8_t data_size; T data_fields; } bus_data; + uint8_t _pad[align_32byte((sizeof (bus_data))) - (sizeof (bus_data))]; }; +static_assert((sizeof (command_response)) == align_32byte((sizeof (command_response)))); void init_host_command(uint32_t * buf, uint32_t * receive_buf, uint32_t destination_port, uint8_t destination_ap, uint8_t command_code, uint8_t data_size, bool end_flag); -void init_host_command_all_ports(uint32_t * buf, uint32_t * receive_buf, - uint8_t command_code, uint32_t command_data_size, uint32_t response_data_size); - void init_device_request(uint32_t * buf, uint32_t * receive_buf, uint32_t destination_port, uint8_t destination_ap); diff --git a/maple/maple_bus_bits.hpp b/maple/maple_bus_bits.hpp index ce4e37d..20df07d 100644 --- a/maple/maple_bus_bits.hpp +++ b/maple/maple_bus_bits.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include "../float_uint32.hpp" diff --git a/maple/maple_bus_commands.hpp b/maple/maple_bus_commands.hpp index a229f80..856663a 100644 --- a/maple/maple_bus_commands.hpp +++ b/maple/maple_bus_commands.hpp @@ -1,3 +1,5 @@ +#pragma once + #include struct device_id { @@ -6,36 +8,40 @@ struct device_id { }; static_assert((sizeof (struct device_id)) == 16); -namespace device_request { - constexpr uint32_t command_code = 0x1; +struct device_request { + static constexpr uint32_t command_code = 0x1; struct data_fields { }; -} +}; -namespace all_status_request { - constexpr uint32_t command_code = 0x2; + +struct all_status_request { + static constexpr uint32_t command_code = 0x2; struct data_fields { }; -} +}; -namespace device_reset { - constexpr uint32_t command_code = 0x3; + +struct device_reset { + static constexpr uint32_t command_code = 0x3; struct data_fields { }; -} +}; -namespace device_kill { - constexpr uint32_t command_code = 0x4; + +struct device_kill { + static constexpr uint32_t command_code = 0x4; struct data_fields { }; -} +}; -namespace device_status { - constexpr uint32_t command_code = 0x5; + +struct device_status { + static constexpr uint32_t command_code = 0x5; struct data_fields { struct device_id device_id; @@ -48,10 +54,11 @@ namespace device_status { }; static_assert((sizeof (struct data_fields)) == 112); -} +}; -namespace device_all_status { - constexpr uint32_t command_code = 0x6; + +struct device_all_status { + static constexpr uint32_t command_code = 0x6; template struct data_fields { @@ -66,39 +73,40 @@ namespace device_all_status { }; static_assert((sizeof (struct data_fields)) == 112); -} +}; -namespace device_reply { - constexpr uint32_t command_code = 0x7; + +struct device_reply { + static constexpr uint32_t command_code = 0x7; struct data_fields { }; -} +}; + +template +struct data_transfer { + static constexpr uint32_t command_code = 0x8; -namespace data_transfer { - constexpr uint32_t command_code = 0x8; - - template struct data_fields { uint32_t function_type; T data; }; - - static_assert((sizeof (struct data_fields)) == 4); -} +}; +static_assert((sizeof (struct data_transfer::data_fields)) == 4); -namespace get_condition { - constexpr uint32_t command_code = 0x9; +struct get_condition { + static constexpr uint32_t command_code = 0x9; struct data_fields { uint32_t function_type; }; static_assert((sizeof (struct data_fields)) == 4); -} +}; -namespace get_media_info { - constexpr uint32_t command_code = 0xa; + +struct get_media_info { + static constexpr uint32_t command_code = 0xa; struct data_fields { uint32_t function_type; @@ -106,10 +114,11 @@ namespace get_media_info { }; static_assert((sizeof (struct data_fields)) == 8); -} +}; -namespace block_read { - constexpr uint32_t command_code = 0xb; + +struct block_read { + static constexpr uint32_t command_code = 0xb; struct data_fields { uint32_t function_type; @@ -119,10 +128,11 @@ namespace block_read { }; static_assert((sizeof (struct data_fields)) == 8); -} +}; -namespace block_write { - constexpr uint32_t command_code = 0xc; + +struct block_write { + static constexpr uint32_t command_code = 0xc; template struct data_fields { @@ -134,10 +144,11 @@ namespace block_write { }; static_assert((sizeof (struct data_fields)) == 8); -} +}; -namespace get_last_error { - constexpr uint32_t command_code = 0xd; + +struct get_last_error { + static constexpr uint32_t command_code = 0xd; struct data_fields { uint32_t function_type; @@ -147,10 +158,11 @@ namespace get_last_error { }; static_assert((sizeof (struct data_fields)) == 8); -} +}; -namespace set_condition { - constexpr uint32_t command_code = 0xe; + +struct set_condition { + static constexpr uint32_t command_code = 0xe; template struct data_fields { @@ -159,10 +171,11 @@ namespace set_condition { }; static_assert((sizeof (struct data_fields)) == 4); -} +}; -namespace ft4_control { - constexpr uint32_t command_code = 0xf; + +struct ft4_control { + static constexpr uint32_t command_code = 0xf; template struct data_fields { @@ -171,10 +184,11 @@ namespace ft4_control { }; static_assert((sizeof (struct data_fields)) == 4); -} +}; -namespace ar_control { - constexpr uint32_t command_code = 0x10; + +struct ar_control { + static constexpr uint32_t command_code = 0x10; template struct data_fields { @@ -183,56 +197,63 @@ namespace ar_control { }; static_assert((sizeof (struct data_fields)) == 4); -} +}; -namespace function_type_unknown { - constexpr uint32_t command_code = 0xfe; + +struct function_type_unknown { + static constexpr uint32_t command_code = 0xfe; struct data_fields { }; -} +}; -namespace command_unknown { - constexpr uint32_t command_code = 0xfd; + +struct command_unknown { + static constexpr uint32_t command_code = 0xfd; struct data_fields { }; -} +}; -namespace transmit_again { - constexpr uint32_t command_code = 0xfc; + +struct transmit_again { + static constexpr uint32_t command_code = 0xfc; struct data_fields { }; -} +}; -namespace file_error { - constexpr uint32_t command_code = 0xfb; + +struct file_error { + static constexpr uint32_t command_code = 0xfb; struct data_fields { uint32_t function_error_code; }; static_assert((sizeof (struct data_fields)) == 4); -} +}; -namespace lcd_error { - constexpr uint32_t command_code = 0xfa; + +struct lcd_error { + static constexpr uint32_t command_code = 0xfa; struct data_fields { uint32_t function_error_code; }; static_assert((sizeof (struct data_fields)) == 4); -} +}; -namespace ar_error { - constexpr uint32_t command_code = 0xf9; + +struct ar_error { + static constexpr uint32_t command_code = 0xf9; struct data_fields { uint32_t function_error_code; }; static_assert((sizeof (struct data_fields)) == 4); -} +}; + diff --git a/maple/maple_impl.hpp b/maple/maple_impl.hpp new file mode 100644 index 0000000..d777bce --- /dev/null +++ b/maple/maple_impl.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +#include "maple/maple.hpp" +#include "maple/maple_bus_commands.hpp" +#include "maple/maple_bus_bits.hpp" + +namespace maple { + +template +void init_host_command_all_ports(uint32_t * command_buf, uint32_t * receive_buf, + const typename C::data_fields& data_fields) +{ + using command_type = maple::host_command; + using response_type = maple::command_response; + + auto host_command = reinterpret_cast(command_buf); + auto response_command = reinterpret_cast(receive_buf); + + init_host_command((uint32_t*)&host_command[0], (uint32_t*)&response_command[0], + host_instruction::port_select::a, // destination_port + ap::de::device | ap::port_select::a, C::command_code, (sizeof (typename C::data_fields)), + false); // end_flag + host_command[0].bus_data.data_fields = data_fields; + + init_host_command((uint32_t*)&host_command[1], (uint32_t*)&response_command[1], + host_instruction::port_select::b, // destination_port + ap::de::device | ap::port_select::b, C::command_code, (sizeof (typename C::data_fields)), + false); // end_flag + host_command[1].bus_data.data_fields = data_fields; + + init_host_command((uint32_t*)&host_command[2], (uint32_t*)&response_command[2], + host_instruction::port_select::c, // destination_port + ap::de::device | ap::port_select::c, C::command_code, (sizeof (typename C::data_fields)), + false); // end_flag + host_command[2].bus_data.data_fields = data_fields; + + init_host_command((uint32_t*)&host_command[3], (uint32_t*)&response_command[3], + host_instruction::port_select::d, // destination_port + ap::de::device | ap::port_select::d, C::command_code, (sizeof (typename C::data_fields)), + true); // end_flag + host_command[3].bus_data.data_fields = data_fields; +} + +} diff --git a/math/vec2.hpp b/math/vec2.hpp new file mode 100644 index 0000000..1197ce2 --- /dev/null +++ b/math/vec2.hpp @@ -0,0 +1,147 @@ +#pragma once + +#include "math.hpp" +#include "vec.hpp" + +// +// vec3 +// + +template +struct vec<2, T> +{ + union { + struct { T x, y; }; + struct { T u, v; }; + }; + + inline constexpr vec(); + inline constexpr vec(T scalar); + inline constexpr vec(T _x, T _y); + + constexpr inline vec<2, T> operator-() const; + inline constexpr T const& operator[](int i) const; + inline constexpr vec<2, T>& operator=(vec<2, T> const& v); + inline constexpr vec<2, T>& operator+=(vec<2, T> const& v); + inline constexpr vec<2, T>& operator-=(vec<2, T> const& v); +}; + +template +inline constexpr vec<2, T>::vec() + : x(0), y(0), z(0) +{} + +template +inline constexpr vec<2, T>::vec(T scalar) + : x(scalar), y(scalar), z(scalar) +{} + +template +inline constexpr vec<2, T>::vec(T _x, T _y) + : x(_x), y(_y) +{} + +template +constexpr inline vec<2, T> vec<2, T>::operator-() const +{ + return vec<2, T>(-x, -y); +} + +template +inline constexpr T const& vec<2, T>::operator[](int i) const +{ + switch(i) + { + default: [[fallthrough]]; + case 0: return x; + case 1: return y; + case 2: return z; + } +} + +template +inline constexpr vec<2, T>& vec<2, T>::operator=(vec<2, T> const& v) +{ + this->x = static_cast(v.x); + this->y = static_cast(v.y); + return *this; +} + +template +inline constexpr vec<2, T>& vec<2, T>::operator+=(vec<2, T> const& v) +{ + *this = *this + vec<2, T>(v); + return *this; +} + +template +inline constexpr vec<2, T>& vec<2, T>::operator-=(vec<2, T> const& v) +{ + *this = *this - vec<2, T>(v); + return *this; +} + +template +inline constexpr vec<2, T> operator+(vec<2, T> const& v1, vec<2, T> const& v2) +{ + return vec<2, T>(v1.x + v2.x, + v1.y + v2.y); +} + +template +inline constexpr vec<2, T> operator-(vec<2, T> const& v1, vec<2, T> const& v2) +{ + return vec<2, T>(v1.x - v2.x, + v1.y - v2.y); +} + +template +inline constexpr vec<2, T> operator*(vec<2, T> const& v1, vec<2, T> const& v2) +{ + return vec<2, T>(v1.x * v2.x, + v1.y * v2.y); +} + +template +inline constexpr vec<2, T> operator*(vec<2, T> const& v1, T const& scalar) +{ + return v1 * vec<2, T>(scalar); +} + +template +inline constexpr vec<2, T> operator/(vec<2, T> const& v1, vec<2, T> const& v2) +{ + return vec<2, T>(v1.x / v2.x, + v1.y / v2.y); +} + +template +inline constexpr vec<2, T> operator/(vec<2, T> const& v1, T const& scalar) +{ + return v1 / vec<2, T>(scalar); +} + +template +inline constexpr T dot(vec<2, T> const& v1, vec<2, T> const& v2) +{ + vec<2, T> tmp(v1 * v2); + return tmp.x + tmp.y; +} + +template +inline constexpr vec<2, T> functor1(T (&func) (T const& x), vec<2, T> const& v) +{ + return vec<2, T>(func(v.x), func(v.y)); +} + +template +inline constexpr vec<2, U> functor1(U (&func) (T const& x), vec<2, T> const& v) +{ + return vec<2, U>(func(v.x), func(v.y)); +} + +template +inline constexpr T length(vec<2, T> const& v) +{ + return sqrt(dot(v, v)); +} diff --git a/math/vec3.hpp b/math/vec3.hpp index 7383cee..434d1c2 100644 --- a/math/vec3.hpp +++ b/math/vec3.hpp @@ -10,7 +10,10 @@ template struct vec<3, T> { - T x, y, z; + union { + struct { T x, y, z; }; + struct { T r, g, b; }; + }; inline constexpr vec(); inline constexpr vec(T scalar); diff --git a/math/vec4.hpp b/math/vec4.hpp index 2ec8b45..4db56d7 100644 --- a/math/vec4.hpp +++ b/math/vec4.hpp @@ -10,7 +10,10 @@ template struct vec<4, T> { - T x, y, z, w; + union { + struct { T x, y, z, w; }; + struct { T r, g, b, a; }; + } inline constexpr vec(); inline constexpr vec(T scalar); diff --git a/qemu.lds b/qemu.lds new file mode 100644 index 0000000..1889748 --- /dev/null +++ b/qemu.lds @@ -0,0 +1,61 @@ +OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") +MEMORY +{ + p1ram : ORIGIN = 0x00000000, LENGTH = 0x7fffffff +} +SECTIONS +{ + . = ORIGIN(p1ram); + + .text ALIGN(4) : SUBALIGN(4) + { + KEEP(*(.text.start)) + *(.text.startup.*) + *(.text.*) + *(.text) + } > p1ram + + .data ALIGN(4) : SUBALIGN(4) + { + *(.data) + *(.data.*) + } > p1ram + + .rodata ALIGN(4) : SUBALIGN(4) + { + *(.rodata) + *(.rodata.*) + } > p1ram + + .ctors ALIGN(4) : SUBALIGN(4) + { + KEEP(*(.ctors)) + KEEP(*(.ctors.*)) + } > p1ram + + .text.p2ram ALIGN(4) : SUBALIGN(4) + { + *(.p2ram) + *(.p2ram.*) + } > p1ram + + .bss ALIGN(4) (NOLOAD) : SUBALIGN(4) + { + *(.bss) + *(.bss.*) + *(COMMON) + } > p1ram + + INCLUDE "debug.lds" +} + +__p1ram_start = ORIGIN(p1ram); +__p1ram_end = ORIGIN(p1ram) + LENGTH(p1ram); + +__bss_link_start = ADDR(.bss); +__bss_link_end = ADDR(.bss) + SIZEOF(.bss); + +__ctors_link_start = ADDR(.ctors); +__ctors_link_end = ADDR(.ctors) + SIZEOF(.ctors); + +INCLUDE "addresses.lds" diff --git a/regs/gen/core_bits.py b/regs/gen/core_bits.py index 5c2949b..f47db48 100644 --- a/regs/gen/core_bits.py +++ b/regs/gen/core_bits.py @@ -216,6 +216,8 @@ def render_registers(registers): yield from render_register(register) def header(): + yield "#pragma once" + yield "" yield "#include " yield "" yield '#include "../float_uint32.hpp"' diff --git a/regs/gen/maple_commands.py b/regs/gen/maple_bus_commands.py similarity index 96% rename from regs/gen/maple_commands.py rename to regs/gen/maple_bus_commands.py index 7b5330e..86ab98a 100644 --- a/regs/gen/maple_commands.py +++ b/regs/gen/maple_bus_commands.py @@ -14,8 +14,8 @@ class CommandNamespace: def command_namespace(namespace: CommandNamespace, data_fields: list[tuple[str, tuple[int, str]]]): - yield f"namespace {namespace.name} {{" - yield f"constexpr uint32_t command_code = {hex(namespace.command_code)};" + yield f"struct {namespace.name} {{" + yield f"static constexpr uint32_t command_code = {hex(namespace.command_code)};" yield "" if namespace.data_size == (0, None): @@ -57,7 +57,7 @@ def command_namespace(namespace: CommandNamespace, else: yield f"static_assert((sizeof (struct data_fields)) == {length});" - yield "}" + yield "};" yield "" def parse_data_size(data_size, base, multiple) -> tuple[int, str]: @@ -155,6 +155,8 @@ def new_aggregator(): return process def headers(): + yield "#pragma once" + yield "" yield "#include " yield "" yield "struct device_id {" diff --git a/regs/maple_bus_bits.ods b/regs/maple_bus_bits.ods index 7c93f534bea43b7ef077229ce2600b370396b55b..c856a5e9d2be95b3312f4ce9fcd396051120c9db 100644 GIT binary patch delta 13454 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 delta 12161 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 DX8NQ6 diff --git a/regs/maple_host_bits.csv b/regs/maple_host_bits.csv deleted file mode 100644 index febbbe6..0000000 --- a/regs/maple_host_bits.csv +++ /dev/null @@ -1,30 +0,0 @@ -"register_name","enum_name","bits","bit_name","value","mask","description" -"host_instruction",,31,"end_flag",1,, -,,,,,, -"host_instruction","port_select","17-16","a",0,, -"host_instruction","port_select","17-16","b",1,, -"host_instruction","port_select","17-16","c",2,, -"host_instruction","port_select","17-16","d",3,, -,,,,,, -"host_instruction","pattern","10-8","normal","0b000",, -"host_instruction","pattern","10-8","light_gun_mode","0b010",, -"host_instruction","pattern","10-8","reset","0b011",, -"host_instruction","pattern","10-8","return_from_light_gun_mode","0b100",, -"host_instruction","pattern","10-8","nop","0b111",, -,,,,,, -"host_instruction",,"7-0","transfer_length",,"0xff", -,,,,,, -"ap","port_select","7-6","a","0b00",, -"ap","port_select","7-6","b","0b01",, -"ap","port_select","7-6","c","0b10",, -"ap","port_select","7-6","d","0b11",, -,,,,,, -"ap","de",5,"device",1,, -"ap","de",5,"expansion_device",0,, -"ap","de",5,"port",0,, -,,,,,, -"ap","lm_bus","4-0","_4","0b10000",, -"ap","lm_bus","4-0","_3","0b01000",, -"ap","lm_bus","4-0","_2","0b00100",, -"ap","lm_bus","4-0","_1","0b00010",, -"ap","lm_bus","4-0","_0","0b00001",, diff --git a/regs/maple_host_bits.ods b/regs/maple_host_bits.ods deleted file mode 100644 index f06e2796faf4ffa3331face35501dd95000460eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14126 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 bo`0~?>Pjf^%o_jz5B{@)8=YF-`>X!}dvB>! diff --git a/tools/obj_to_cpp.py b/tools/obj_to_cpp.py index 490122d..2cb67ab 100644 --- a/tools/obj_to_cpp.py +++ b/tools/obj_to_cpp.py @@ -6,23 +6,26 @@ from generate import renderer with open(sys.argv[1], 'r') as f: lines = f.read().split("\n") -@dataclass +@dataclass(frozen=True) class Vertex: x: float y: float z: float +@dataclass(frozen=True) +class TextureCoordinate: + u: float + v: float + @dataclass -class VertexNormal: +class VertexTextureNormal: vertex: int + texture: int normal: int -Face = tuple[VertexNormal, VertexNormal, VertexNormal] +Face = tuple[VertexTextureNormal, VertexTextureNormal, VertexTextureNormal] name = None -vertices = [] -normals = [] -faces = [] def parse_object(line): h, name = line.split() @@ -35,9 +38,15 @@ def parse_vertex(line): assert len(xyz) == 3 return Vertex(*map(float, xyz)) +def parse_texture_coordinate(line): + h, *uv = line.split() + assert h == 'vt' + assert len(uv) == 2 + return TextureCoordinate(*map(float, uv)) + def maybe_int(i, offset): if i.strip() == "": - return None + assert False else: return int(i) + offset @@ -52,7 +61,7 @@ def parse_face(line): maybe_int(iix, offset=-1) for iix in ix ] - return VertexNormal(vertex_ix, normal_ix) + return VertexTextureNormal(vertex_ix, uv_ix, normal_ix) return tuple(map(parse_ixs, tri)) @@ -70,30 +79,25 @@ def generate_normals(normals): yield "};" yield "" +def generate_texture_coordinates(texture_coordinates): + yield "constexpr vec2 texture[] = {" + for t in texture_coordinates: + yield f"{{ {t.u:9f}f, {t.v:9f}f }}," + yield "};" + yield "" + def generate_faces(faces): yield "constexpr face faces[] = {" for f in faces: - inner = ", ".join(f"{{{vn.vertex:2}, {vn.normal:2}}}" for vn in f) + inner = ", ".join(f"{{{vtn.vertex:3}, {vtn.texture:3}, {vtn.normal:3}}}" for vtn in f) yield f"{{{inner}}}," yield "};" yield "" yield "constexpr uint32_t num_faces = (sizeof (faces)) / (sizeof (face));" yield "" -for line in lines: - if line.startswith('o '): - assert name is None - name = parse_object(line) - elif line.startswith('v '): - vertices.append(parse_vertex(line)) - elif line.startswith('vn '): - normals.append(parse_vertex(line)) - elif line.startswith('f '): - faces.append(parse_face(line)) - else: - pass - -def generate_namespace(): +def generate_namespace(vertices, texture_coordinates, normals, faces): + global name assert name is not None yield "#pragma once" yield "" @@ -102,11 +106,58 @@ def generate_namespace(): yield f"namespace {name} {{" yield from generate_vertices(vertices) + yield from generate_texture_coordinates(texture_coordinates) yield from generate_normals(normals) yield from generate_faces(faces) yield "}" -render, out = renderer() -render(generate_namespace()) -sys.stdout.write(out.getvalue()) +def merge_texture_coordinates(texture_coordinates, faces): + ix = 0 + _texture = dict() + _faces = [] + for face in faces: + for vtn in face: + key = texture_coordinates[vtn.texture] + if key not in _texture: + _texture[key] = ix + ix += 1 + _faces.append(tuple( + VertexTextureNormal(vtn.vertex, + _texture[texture_coordinates[vtn.texture]], + vtn.normal) + for vtn in face + )) + return _texture, _faces + + +def main(): + global name + vertices = [] + texture_coordinates = [] + normals = [] + faces = [] + + for line in lines: + if line.startswith('o '): + assert name is None + name = parse_object(line) + elif line.startswith('v '): + vertices.append(parse_vertex(line)) + elif line.startswith('vn '): + normals.append(parse_vertex(line)) + elif line.startswith('vt '): + texture_coordinates.append(parse_texture_coordinate(line)) + elif line.startswith('f '): + faces.append(parse_face(line)) + else: + pass + + texture_coordinates, faces = merge_texture_coordinates(texture_coordinates, faces) + + render, out = renderer() + render(generate_namespace(vertices, texture_coordinates, normals, faces)) + sys.stdout.write(out.getvalue()) + +if __name__ == '__main__': + main()