diff --git a/example/modifier_volume_with_two_volumes.cpp b/example/modifier_volume_with_two_volumes.cpp new file mode 100644 index 0000000..3ed4db4 --- /dev/null +++ b/example/modifier_volume_with_two_volumes.cpp @@ -0,0 +1,264 @@ +#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" + +#include "geometry/plane.hpp" +#include "geometry/cube.hpp" +#include "math/vec3.hpp" +#include "math/vec4.hpp" + +vec3 _transform(const vec3& point, + const uint32_t scale, + const float theta) +{ + float x = point.x; + float y = point.y; + float z = point.z; + float t; + + // object transform + t = z * cos(theta) - x * sin(theta); + x = z * sin(theta) + x * cos(theta); + z = t; + + x *= scale; + y *= scale; + z *= scale; + + // world transform + y += 2.0f; + x *= 0.8; + y *= 0.8; + z *= 0.8; + + // camera transform + z += 4; + + // perspective + x = x / z; + y = y / z; + + // screen space transform + x *= 240.f; + y *= 240.f; + x += 320.f; + y += 240.f; + z = 1 / z; + + return {x, y, z}; +} + +void transform_polygon(ta_parameter_writer& parameter, + const vec3 * vertices, + const face& face, + const float scale, + const vec4& color, + const float theta) +{ + 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::shadow; + + const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater + | isp_tsp_instruction_word::culling_mode::no_culling; + + 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++) { + // world transform + uint32_t vertex_ix = face[i].vertex; + auto& vertex = vertices[vertex_ix]; + auto point = _transform(vertex, scale, theta); + + bool end_of_strip = i == strip_length - 1; + parameter.append() = + vertex_polygon_type_1(polygon_vertex_parameter_control_word(end_of_strip), + point.x, + point.y, + point.z, + color.a, // alpha + color.r, // red + color.g, // green + color.b // blue + ); + } +} + +void transform_modifier_volume(ta_parameter_writer& parameter, + const vec3 * vertices, + const face * faces, + const uint32_t num_faces, + const float scale) +{ + const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume + | para_control::list_type::opaque_modifier_volume + // | group_control::group_en + // | group_control::user_clip::inside_enable + ; + + const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::volume_instruction::normal_polygon + | isp_tsp_instruction_word::culling_mode::no_culling; + + parameter.append() = + global_modifier_volume(parameter_control_word, + isp_tsp_instruction_word); + + for (uint32_t i = 0; i < num_faces; i++) { + // world transform + uint32_t ix_a = faces[i][0].vertex; + uint32_t ix_b = faces[i][1].vertex; + uint32_t ix_c = faces[i][2].vertex; + auto& _a = vertices[ix_a]; + auto& _b = vertices[ix_b]; + auto& _c = vertices[ix_c]; + auto a = _transform(_a, scale, 0.f); + auto b = _transform(_b, scale, 0.f); + auto c = _transform(_c, scale, 0.f); + + if (i == (num_faces - 1)) { + const uint32_t last_parameter_control_word = para_control::para_type::polygon_or_modifier_volume + | para_control::list_type::opaque_modifier_volume + | obj_control::volume::modifier_volume::last_in_volume; + + const uint32_t last_isp_tsp_instruction_word = isp_tsp_instruction_word::volume_instruction::inside_last_polygon + | isp_tsp_instruction_word::culling_mode::no_culling; + + parameter.append() = + global_modifier_volume(last_parameter_control_word, + last_isp_tsp_instruction_word); + + } + + parameter.append() = + vertex_modifier_volume(modifier_volume_vertex_parameter_control_word(), + a.x, a.y, a.z, + b.x, b.y, b.z, + c.x, c.y, c.z); + } +} + +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() +{ + 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::_16x4byte + | ta_alloc_ctrl::o_opb::_16x4byte; + + constexpr struct opb_size opb_size = { .opaque = 16 * 4 + , .opaque_modifier = 16 * 4 + , .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; + + float theta = 0; + + while (true) { + ta_polygon_converter_init(opb_size.total(), + ta_alloc, + 640 / 32, + 480 / 32); + auto parameter = ta_parameter_writer(ta_parameter_buf); + { // plane + vec4 color = {1.0, 0.9, 0.4, 0.2}; + float scale = 2.f; + for (uint32_t i = 0; i < plane::num_faces; i++) { + transform_polygon(parameter, + plane::vertices, + plane::faces[i], + scale, + color, + theta); + } + + /* + for (uint32_t i = 0; i < cube::num_faces; i++) { + transform_polygon(parameter, + cube::vertices, + cube::faces[i], + 1.f, + {1.0f, 0.0f, 1.0f, 0.0f}); + } + */ + } + // end of opaque list + parameter.append() = global_end_of_list(); + + { // cube + float scale = 1.f; + transform_modifier_volume(parameter, + cube::vertices, + cube::faces, + cube::num_faces, + scale); + } + // end of opaque modifier list + parameter.append() = global_end_of_list(); + + ta_polygon_converter_transfer(ta_parameter_buf, parameter.offset); + ta_wait_opaque_modifier_volume_list(); + + core_start_render(frame_ix, num_frames); + + v_sync_in(); + core_wait_end_of_render_video(frame_ix, num_frames); + + constexpr float half_degree = 0.01745329f / 2; + theta += half_degree; + frame_ix += 1; + } +} diff --git a/regs/gen/ta_parameter_format.py b/regs/gen/ta_parameter_format.py new file mode 100644 index 0000000..3da07dd --- /dev/null +++ b/regs/gen/ta_parameter_format.py @@ -0,0 +1,143 @@ +from dataclasses import dataclass +from pprint import pprint +import sys +import csv + +from generate import renderer + +_field_types = { + "parameter_control_word": "uint32_t", + "user_clip_": "uint32_t", + "object_pointer": "uint32_t", + "bounding_box_": "uint32_t", + "isp_tsp_instruction_word": "uint32_t", + "tsp_instruction_word": "uint32_t", + "texture_control_word": "uint32_t", + "data_size_for_sort_dma": "uint32_t", + "next_address_for_sort_dma": "uint32_t", + "face_color_": "float", + "face_offset_color_": "float", + "x": "float", + "y": "float", + "z": "float", + "base_color_": "float", + "base_intensity_": "float", + "u": "float", + "v": "float", + "u_v": "uint32_t", + "base_color": "uint32_t", + "offset_color": "uint32_t", + "offset_color_": "float", + "base_intensity": "float", + "offset_intensity": "float", + "a_": "float", + "b_": "float", + "c_": "float", + "d_": "float", + "a_u_a_v": "uint32_t", + "b_u_b_v": "uint32_t", + "c_u_c_v": "uint32_t", +} + +def get_type(field_name: str): + match = None + match_len = 0 + for name, type in _field_types.items(): + if field_name.startswith(type) and len(name) >= match_len: + match = type + assert match_len != len(name), (name, match) + match_len = len(name) + assert match != None, field_name + return match + +class EndOfInput(Exception): + pass + +def next_row(ix, rows, advance): + if ix >= len(rows): + raise EndOfInput + + if advance: + while rows[ix][0] == "": + ix += 1 + if ix >= len(rows): + raise EndOfInput + row = rows[ix] + ix += 1 + return ix, row + +@dataclass +class FieldDeclaration: + offset: int + name: str + +@dataclass +class StructDeclaration: + name: str + fields: list[FieldDeclaration] + +def parse_type_declaration(ix, rows): + ix, row = next_row(ix, rows, advance=True) + assert len(row) == 2, row + struct_name, empty = row + assert empty == "", row + fields = [] + last_offset = -4 + while True: + ix, row = next_row(ix, rows, advance=False) + if row[0] == "": + assert last_offset + 4 == 32 or last_offset + 4 == 64, last_offset + 4 + return ix, StructDeclaration( + struct_name, + fields + ) + else: + assert len(row) == 2, row + _offset, name = row + offset = int(_offset, 16) + assert offset == last_offset + 4, (hex(offset), hex(last_offset)) + last_offset = offset + fields.append(FieldDeclaration(offset, name)) + +def parse(rows): + ix = 0 + declarations = [] + while True: + try: + ix, declaration = parse_type_declaration(ix, rows) + except EndOfInput: + break + declarations.append(declaration) + + return declarations + +def render_declaration(declaration): + yield f"struct {declaration.name} {{" + for field in declaration.fields: + yield f"" + yield "};" + + +def render_declarations(namespace, declarations): + yield f"namespace {namespace} {{" + for declaration in declarations: + yield from render_declaration(declaration) + yield "" + yield "}" + +def read_input(filename): + with open(filename) as f: + reader = csv.reader(f, delimiter=",", quotechar='"') + rows = [ + [s.strip() for s in row] + for row in reader + ] + return rows + +if __name__ == "__main__": + rows = read_input(sys.argv[1]) + namespace = sys.argv[2] + declarations = parse(rows) + render, out = renderer() + render(render_declarations(namespace, declarations)) + print(out.getvalue()) diff --git a/regs/global_parameter_format.csv b/regs/global_parameter_format.csv new file mode 100644 index 0000000..d13a20e --- /dev/null +++ b/regs/global_parameter_format.csv @@ -0,0 +1,115 @@ +"end_of_list", +"0x00","parameter_control_word" +"0x04", +"0x08", +"0x0c", +"0x10", +"0x14", +"0x18", +"0x1c", +, +"user_tile_clip", +"0x00","parameter_control_word" +"0x04", +"0x08", +"0x0c", +"0x10","user_clip_x_min" +"0x14","user_clip_y_min" +"0x18","user_clip_x_max" +"0x1c","user_clip_y_max" +, +"object_list_set", +"0x00","parameter_control_word" +"0x04","object_pointer" +"0x08", +"0x0c", +"0x10","bounding_box_x_min" +"0x14","bounding_box_y_min" +"0x18","bounding_box_x_max" +"0x1c","bounding_box_y_max" +, +"polygon_type_0", +"0x00","parameter_control_word" +"0x04","isp_tsp_instruction_word" +"0x08","tsp_instruction_word" +"0x0c","texture_control_word" +"0x10", +"0x14", +"0x18","data_size_for_sort_dma" +"0x1c","next_address_for_sort_dma" +, +"polygon_type_1", +"0x00","parameter_control_word" +"0x04","isp_tsp_instruction_word" +"0x08","tsp_instruction_word" +"0x0c","texture_control_word" +"0x10","face_color_alpha" +"0x14","face_color_r" +"0x18","face_color_g" +"0x1c","face_color_b" +, +"polygon_type_2", +"0x00","parameter_control_word" +"0x04","isp_tsp_instruction_word" +"0x08","tsp_instruction_word" +"0x0c","texture_control_word" +"0x10", +"0x14", +"0x18","data_size_for_sort_dma" +"0x1c","next_address_for_sort_dma" +"0x20","face_color_alpha" +"0x24","face_color_r" +"0x28","face_color_g" +"0x2c","face_color_b" +"0x30","face_offset_color_alpha" +"0x34","face_offset_color_r" +"0x38","face_offset_color_g" +"0x3c","face_offset_color_b" +, +"polygon_type_3", +"0x00","parameter_control_word" +"0x04","isp_tsp_instruction_word" +"0x08","tsp_instruction_word_0" +"0x0c","texture_control_word_0" +"0x10","tsp_instruction_word_1" +"0x14","texture_control_word_1" +"0x18","data_size_for_sort_dma" +"0x1c","next_address_for_sort_dma" +, +"polygon_type_4", +"0x00","parameter_control_word" +"0x04","isp_tsp_instruction_word" +"0x08","tsp_instruction_word_0" +"0x0c","texture_control_word_0" +"0x10","tsp_instruction_word_1" +"0x14","texture_control_word_1" +"0x18","data_size_for_sort_dma" +"0x1c","next_address_for_sort_dma" +"0x20","face_color_alpha_0" +"0x24","face_color_r_0" +"0x28","face_color_g_0" +"0x2c","face_color_b_0" +"0x30","face_color_alpha_1" +"0x34","face_color_r_1" +"0x38","face_color_g_1" +"0x3c","face_color_b_1" +, +"sprite", +"0x00","parameter_control_word" +"0x04","isp_tsp_instruction_word" +"0x08","tsp_instruction_word" +"0x0c","texture_control_word" +"0x10","base_color" +"0x14","offset_color" +"0x18","data_size_for_sort_dma" +"0x1c","next_address_for_sort_dma" +, +"modifier_volume", +"0x00","parameter_control_word" +"0x04","isp_tsp_instruction_word" +"0x08", +"0x0c", +"0x10", +"0x14", +"0x18", +"0x1c", diff --git a/regs/vertex_parameter_format.csv b/regs/vertex_parameter_format.csv new file mode 100644 index 0000000..74d31ee --- /dev/null +++ b/regs/vertex_parameter_format.csv @@ -0,0 +1,251 @@ +"polygon_type_0", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10", +"0x14", +"0x18","base_color" +"0x1c", +, +"polygon_type_1", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10","base_color_alpha" +"0x14","base_color_r" +"0x18","base_color_g" +"0x1c","base_color_b" +, +"polygon_type_2", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10", +"0x14", +"0x18","base_intensity" +"0x1c", +, +"polygon_type_3", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10","u" +"0x14","v" +"0x18","base_color" +"0x1c","offset_color" +, +"polygon_type_4", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10","u_v" +"0x14", +"0x18","base_color" +"0x1c","offset_color" +, +"polygon_type_5", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10","u" +"0x14","v" +"0x18", +"0x1c", +"0x20","base_color_alpha" +"0x24","base_color_r" +"0x28","base_color_g" +"0x2c","base_color_b" +"0x30","offset_color_alpha" +"0x34","offset_color_r" +"0x38","offset_color_g" +"0x3c","offset_color_b" +, +"polygon_type_6", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10","u_v" +"0x14", +"0x18", +"0x1c", +"0x20","base_color_alpha" +"0x24","base_color_r" +"0x28","base_color_g" +"0x2c","base_color_b" +"0x30","offset_color_alpha" +"0x34","offset_color_r" +"0x38","offset_color_g" +"0x3c","offset_color_b" +, +"polygon_type_7", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10","u" +"0x14","v" +"0x18","base_intensity" +"0x1c","offset_intensity" +, +"polygon_type_8", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10","u_v" +"0x14", +"0x18","base_intensity" +"0x1c","offset_intensity" +, +"polygon_type_9", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10","base_color_0" +"0x14","base_color_1" +"0x18", +"0x1c", +, +"polygon_type_10", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10","base_intensity_0" +"0x14","base_intensity_1" +"0x18", +"0x1c", +, +"polygon_type_11", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10","u_0" +"0x14","v_0" +"0x18","base_color_0" +"0x1c","offset_color_0" +"0x20","u_1" +"0x24","v_1" +"0x28","base_color_1" +"0x2c","offset_color_1" +"0x30", +"0x34", +"0x38", +"0x3c", +, +"polygon_type_12", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10","u_v_0" +"0x14", +"0x18","base_color_0" +"0x1c","offset_color_0" +"0x20","u_v_1" +"0x24", +"0x28","base_color_1" +"0x2c","offset_color_1" +"0x30", +"0x34", +"0x38", +"0x3c", +, +"polygon_type_13", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10","u_0" +"0x14","v_0" +"0x18","base_intensity_0" +"0x1c","offset_intensity_0" +"0x20","u_1" +"0x24","v_1" +"0x28","base_intensity_1" +"0x2c","offset_intensity_1" +"0x30", +"0x34", +"0x38", +"0x3c", +, +"polygon_type_14", +"0x00","parameter_control_word" +"0x04","x" +"0x08","y" +"0x0c","z" +"0x10","u_v_0" +"0x14", +"0x18","base_intensity_0" +"0x1c","offset_intensity_0" +"0x20","u_v_1" +"0x24", +"0x28","base_intensity_1" +"0x2c","offset_intensity_1" +"0x30", +"0x34", +"0x38", +"0x3c", +, +"sprite_type_0", +"0x00","parameter_control_word" +"0x04","a_x" +"0x08","a_y" +"0x0c","a_z" +"0x10","b_x" +"0x14","b_y" +"0x18","b_z" +"0x1c","c_x" +"0x20","c_y" +"0x24","c_z" +"0x28","d_x" +"0x2c","d_y" +"0x30", +"0x34", +"0x38", +"0x3c", +, +"sprite_type_1", +"0x00","parameter_control_word" +"0x04","a_x" +"0x08","a_y" +"0x0c","a_z" +"0x10","b_x" +"0x14","b_y" +"0x18","b_z" +"0x1c","c_x" +"0x20","c_y" +"0x24","c_z" +"0x28","d_x" +"0x2c","d_y" +"0x30", +"0x34","a_u_a_v" +"0x38","b_u_b_v" +"0x3c","c_u_c_v" +, +"modifier_volume", +"0x00","parameter_control_word" +"0x04","a_x" +"0x08","a_y" +"0x0c","a_z" +"0x10","b_x" +"0x14","b_y" +"0x18","b_z" +"0x1c","c_x" +"0x20","c_y" +"0x24","c_z" +"0x28", +"0x2c", +"0x30", +"0x34", +"0x38", +"0x3c",