diff --git a/example/cube_vq.cpp b/example/cube_vq.cpp index 6483418..9c58518 100644 --- a/example/cube_vq.cpp +++ b/example/cube_vq.cpp @@ -231,6 +231,6 @@ void main() tile_width, tile_height); transfer_scene(theta); - //theta += degree; + theta += degree; } } diff --git a/example/cube_vq_rectangular.cpp b/example/cube_vq_rectangular.cpp new file mode 100644 index 0000000..a063b53 --- /dev/null +++ b/example/cube_vq_rectangular.cpp @@ -0,0 +1,235 @@ +#include + +#include "holly/isp_tsp.hpp" +#include "holly/ta_parameter.hpp" +#include "holly/ta_global_parameter.hpp" +#include "holly/ta_vertex_parameter.hpp" +#include "holly/ta_bits.hpp" +#include "holly/ta_fifo_polygon_converter.hpp" +#include "holly/holly.hpp" +#include "holly/core_bits.hpp" +#include "holly/core.hpp" +#include "holly/region_array.hpp" +#include "holly/background.hpp" +#include "holly/video_output.hpp" +#include "holly/texture_memory_alloc2.hpp" +#include "sh7091/store_queue.hpp" +#include "sh7091/serial.hpp" + +#include "twiddle.hpp" + +#include "math/vec2.hpp" + +#include "texture/panda/panda_rectangular.vq.h" + +enum material { + Material, +}; + +#include "model/prism.h" + +void transfer_scene(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::intensity_mode_1 + | obj_control::texture + | 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 + | tsp_instruction_word::texture_shading_instruction::modulate + | tsp_instruction_word::texture_u_size::from_int(512) + | tsp_instruction_word::texture_v_size::from_int(256); + + const uint32_t texture_address = texture_memory_alloc::texture.start; + const uint32_t texture_control_word = texture_control_word::vq_compressed + | texture_control_word::pixel_format::_565 + | texture_control_word::scan_order::twiddled + | texture_control_word::texture_address(texture_address / 8); + + for (int j = 0; j < prism_model.object_count; j++) { + *reinterpret_cast(store_queue) = + ta_global_parameter::polygon_type_1(parameter_control_word, + isp_tsp_instruction_word, + tsp_instruction_word, + texture_control_word, // texture_control_word + 1.0, // face color alpha + 1.0, // face color r + 1.0, // face color g + 1.0 // face color b + ); + sq_transfer_32byte(ta_fifo_polygon_converter); + + struct object * object = prism_model.object[j]; + for (int i = 0; i < object->triangle_count; i++) { + for (int k = 0; k < 3; k++) { + int position_ix = object->triangle[i].v[k].position; + float x0 = prism_model.position[position_ix].x; + float y0 = prism_model.position[position_ix].y; + float z0 = prism_model.position[position_ix].z; + + float x1 = x0 * cos(theta) - z0 * sin(theta); + float y1 = y0; + float z1 = x0 * sin(theta) + z0 * cos(theta); + + float x = x1; + float y = y1 * cos(theta) - z1 * sin(theta); + float z = y1 * sin(theta) + z1 * cos(theta); + + z += 2.0; + + x /= z; + y /= z; + + // do rotation + x = x * 240 + 320; + y = y * 240 + 240; + + z = 1/z; + + bool end_of_strip = k == 2; + + int texture_ix = object->triangle[i].v[k].texture; + float u = 1.0 - prism_model.texture[texture_ix].u; + float v = prism_model.texture[texture_ix].v; + + *reinterpret_cast(store_queue) = + ta_vertex_parameter::polygon_type_7(polygon_vertex_parameter_control_word(end_of_strip), + x, y, z, + u, v, + 1.0, // base intensity + 1.0 // offset intensity + ); + sq_transfer_32byte(ta_fifo_polygon_converter); + } + } + } + + *reinterpret_cast(store_queue) = + ta_global_parameter::end_of_list(para_control::para_type::end_of_list); + sq_transfer_32byte(ta_fifo_polygon_converter); +} + +template +inline void copy(T * dst, const T * src, const int32_t n) noexcept +{ + int32_t n_t = n / (sizeof (T)); + while (n_t > 0) { + *dst++ = *src++; + n_t--; + } +} + +void texture_init() +{ + uint32_t offset = texture_memory_alloc::texture.start; + copy(&texture_memory64[offset / 4], + reinterpret_cast(&_binary_texture_panda_panda_rectangular_vq_start), + reinterpret_cast(&_binary_texture_panda_panda_rectangular_vq_size)); +} + +void main() +{ + serial::init(4); + 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 int render_passes = 1; + constexpr struct opb_size opb_size[render_passes] = { + { + .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(); + + video_output::set_mode_vga(); + + constexpr int framebuffer_width = 640; + constexpr int framebuffer_height = 480; + constexpr int tile_width = framebuffer_width / 32; + constexpr int tile_height = framebuffer_height / 32; + + region_array_multipass(tile_width, + tile_height, + opb_size, + render_passes, + texture_memory_alloc::region_array[0].start, + texture_memory_alloc::object_list[0].start); + region_array_multipass(tile_width, + tile_height, + opb_size, + render_passes, + texture_memory_alloc::region_array[1].start, + texture_memory_alloc::object_list[1].start); + + background_parameter2(texture_memory_alloc::background[0].start, + 0xff220033); + background_parameter2(texture_memory_alloc::background[1].start, + 0xff220033); + + texture_init(); + + const float degree = 0.017453292519943295; + float theta = 0; + int ta = -1; + int core = -2; + while (1) { + if (core >= 0) { + // core = 0 ; core = 1 + // ta = 1 ; ta = 0 + core_wait_end_of_render_video(); + while (!spg_status::vsync(holly.SPG_STATUS)); + holly.FB_R_SOF1 = texture_memory_alloc::framebuffer[core].start; + while (spg_status::vsync(holly.SPG_STATUS)); + } + + // core = -2 ; core = 1 ; core = 0 + // ta = -1 ; ta = 0 ; ta = 1 + core += 1; + ta += 1; + if (core > 1) core = 0; + if (ta > 1) ta = 0; + + if (core >= 0) { + // core = 1 ; core = 0 + // ta = 0 ; ta = 1 + ta_wait_opaque_list(); + core_start_render2(texture_memory_alloc::region_array[core].start, + texture_memory_alloc::isp_tsp_parameters[core].start, + texture_memory_alloc::background[core].start, + texture_memory_alloc::framebuffer[core].start, + framebuffer_width); + } + + + // core = -1 ; core = 1 ; core = 0 + // ta = 0 ; ta = 0 ; ta = 1 + ta_polygon_converter_init2(texture_memory_alloc::isp_tsp_parameters[ta].start, + texture_memory_alloc::isp_tsp_parameters[ta].end, + texture_memory_alloc::object_list[ta].start, + texture_memory_alloc::object_list[ta].end, + opb_size[0].total(), + ta_alloc, + tile_width, + tile_height); + transfer_scene(theta); + theta += degree; + } +} diff --git a/example/example.mk b/example/example.mk index ea74607..fcf269d 100644 --- a/example/example.mk +++ b/example/example.mk @@ -582,6 +582,19 @@ CUBE_VQ_OBJ = \ example/cube_vq.elf: LDSCRIPT = $(LIB)/alt.lds example/cube_vq.elf: $(START_OBJ) $(CUBE_VQ_OBJ) +CUBE_VQ_RECTANGULAR_OBJ = \ + example/cube_vq_rectangular.o \ + holly/core.o \ + holly/region_array.o \ + holly/background.o \ + holly/ta_fifo_polygon_converter.o \ + holly/video_output.o \ + sh7091/serial.o \ + texture/panda/panda_rectangular.vq.o + +example/cube_vq_rectangular.elf: LDSCRIPT = $(LIB)/alt.lds +example/cube_vq_rectangular.elf: $(START_OBJ) $(CUBE_VQ_RECTANGULAR_OBJ) + SHEIK_OBJ = \ example/sheik.o \ holly/core.o \ diff --git a/model/prism.h b/model/prism.h new file mode 100644 index 0000000..c4a9774 --- /dev/null +++ b/model/prism.h @@ -0,0 +1,124 @@ +#include + +#include "model.h" + +// floating-point +vertex_position prism_position[] = { + {1.0, 0.5, -0.5}, + {1.0, -0.5, -0.5}, + {1.0, 0.5, 0.5}, + {1.0, -0.5, 0.5}, + {-1.0, 0.5, -0.5}, + {-1.0, -0.5, -0.5}, + {-1.0, 0.5, 0.5}, + {-1.0, -0.5, 0.5}, +}; + +// floating-point +vertex_texture prism_texture[] = { + {0.0, 1.0}, + {1.0, 0.0}, + {1.0, 1.0}, + {0.0, 0.0}, + {1.0, 1.0}, + {0.0, 1.0}, + {0.75, 0.0}, + {0.25, 1.0}, + {0.25, 0.0}, + {0.0, 0.0}, + {0.75, 1.0}, +}; + +// floating-point +vertex_normal prism_normal[] = { + {0.0, 1.0, 0.0}, + {0.0, 0.0, 1.0}, + {-1.0, 0.0, 0.0}, + {0.0, -1.0, 0.0}, + {1.0, 0.0, 0.0}, + {0.0, 0.0, -1.0}, +}; + +union triangle prism_Cube_triangle[] = { + { .v = { + {4, 0, 0}, + {2, 1, 0}, + {0, 2, 0}, + }}, + { .v = { + {2, 3, 1}, + {7, 4, 1}, + {3, 5, 1}, + }}, + { .v = { + {6, 6, 2}, + {5, 7, 2}, + {7, 8, 2}, + }}, + { .v = { + {1, 0, 3}, + {7, 1, 3}, + {5, 2, 3}, + }}, + { .v = { + {0, 6, 4}, + {3, 7, 4}, + {1, 8, 4}, + }}, + { .v = { + {4, 3, 5}, + {1, 4, 5}, + {5, 5, 5}, + }}, + { .v = { + {4, 0, 0}, + {6, 9, 0}, + {2, 1, 0}, + }}, + { .v = { + {2, 3, 1}, + {6, 1, 1}, + {7, 4, 1}, + }}, + { .v = { + {6, 6, 2}, + {4, 10, 2}, + {5, 7, 2}, + }}, + { .v = { + {1, 0, 3}, + {3, 9, 3}, + {7, 1, 3}, + }}, + { .v = { + {0, 6, 4}, + {2, 10, 4}, + {3, 7, 4}, + }}, + { .v = { + {4, 3, 5}, + {0, 1, 5}, + {1, 4, 5}, + }}, +}; + +struct object prism_Cube = { + .triangle = &prism_Cube_triangle[0], + .quadrilateral = NULL, + .triangle_count = 12, + .quadrilateral_count = 0, + .material = Material, +}; + +struct object * prism_object_list[] = { + &prism_Cube, +}; + +struct model prism_model = { + .position = &prism_position[0], + .texture = &prism_texture[0], + .normal = &prism_normal[0], + .object = &prism_object_list[0], + .object_count = 1, +}; + diff --git a/model/prism.mtl b/model/prism.mtl new file mode 100644 index 0000000..4d490e8 --- /dev/null +++ b/model/prism.mtl @@ -0,0 +1,12 @@ +# Blender 4.1.1 MTL File: 'None' +# www.blender.org + +newmtl Material +Ns 250.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 diff --git a/texture/panda/panda.vq b/texture/panda/panda.vq index 0362f18..84bdee0 100644 Binary files a/texture/panda/panda.vq and b/texture/panda/panda.vq differ diff --git a/texture/panda/panda_rectangular.vq b/texture/panda/panda_rectangular.vq new file mode 100644 index 0000000..5602e26 Binary files /dev/null and b/texture/panda/panda_rectangular.vq differ diff --git a/texture/panda/panda_rectangular.vq.h b/texture/panda/panda_rectangular.vq.h new file mode 100644 index 0000000..22d0e39 --- /dev/null +++ b/texture/panda/panda_rectangular.vq.h @@ -0,0 +1,5 @@ +#pragma once +#include +extern uint32_t _binary_texture_panda_panda_rectangular_vq_start __asm("_binary_texture_panda_panda_rectangular_vq_start"); +extern uint32_t _binary_texture_panda_panda_rectangular_vq_end __asm("_binary_texture_panda_panda_rectangular_vq_end"); +extern uint32_t _binary_texture_panda_panda_rectangular_vq_size __asm("_binary_texture_panda_panda_rectangular_vq_size"); diff --git a/twiddle.hpp b/twiddle.hpp index 7c521aa..170c7c9 100644 --- a/twiddle.hpp +++ b/twiddle.hpp @@ -26,37 +26,75 @@ alternately, in verilog syntax: assign t = {x[2], y[2], x[1], y[1], x[0], y[0]}; */ -constexpr inline uint32_t from_xy(uint32_t x, uint32_t y) +constexpr inline int log2(uint32_t n) +{ + switch (n) { + default: + case 8: return 3; + case 16: return 4; + case 32: return 5; + case 64: return 6; + case 128: return 7; + case 256: return 8; + case 512: return 9; + case 1024: return 10; + } +} + +constexpr inline uint32_t from_xy(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { // maximum texture size : 1024x1024 // maximum 1-dimensional index: 0xfffff // bits : 19-0 + // y bits: 0, 2, 4, 6, 8, 10, 12, 14, 16, 18 + // x bits: 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 + + int width_max = log2(width); + int height_max = log2(height); + uint32_t twiddle_ix = 0; - for (int i = 0; i <= (20 / 2); i++) { - twiddle_ix |= ((y >> i) & 1) << (i * 2 + 0); - twiddle_ix |= ((x >> i) & 1) << (i * 2 + 1); + for (int i = 0; i < (20 / 2); i++) { + if (i < width_max && i < height_max) { + twiddle_ix |= ((y >> i) & 1) << (i * 2 + 0); + twiddle_ix |= ((x >> i) & 1) << (i * 2 + 1); + } else if (i < width_max) { + twiddle_ix |= ((x >> i) & 1) << (i + height_max); + } else if (i < height_max) { + twiddle_ix |= ((y >> i) & 1) << (i + width_max); + } else { + break; + } } return twiddle_ix; } -static_assert(from_xy(0b000, 0b000) == 0); -static_assert(from_xy(0b001, 0b000) == 2); -static_assert(from_xy(0b010, 0b000) == 8); -static_assert(from_xy(0b011, 0b000) == 10); -static_assert(from_xy(0b100, 0b000) == 32); -static_assert(from_xy(0b101, 0b000) == 34); -static_assert(from_xy(0b110, 0b000) == 40); -static_assert(from_xy(0b111, 0b000) == 42); +static_assert(from_xy(0b000, 0b000, 8, 8) == 0); +static_assert(from_xy(0b001, 0b000, 8, 8) == 2); +static_assert(from_xy(0b010, 0b000, 8, 8) == 8); +static_assert(from_xy(0b011, 0b000, 8, 8) == 10); +static_assert(from_xy(0b100, 0b000, 8, 8) == 32); +static_assert(from_xy(0b101, 0b000, 8, 8) == 34); +static_assert(from_xy(0b110, 0b000, 8, 8) == 40); +static_assert(from_xy(0b111, 0b000, 8, 8) == 42); -static_assert(from_xy(0b000, 0b001) == 1); -static_assert(from_xy(0b000, 0b010) == 4); -static_assert(from_xy(0b000, 0b011) == 5); -static_assert(from_xy(0b000, 0b100) == 16); -static_assert(from_xy(0b000, 0b101) == 17); -static_assert(from_xy(0b000, 0b110) == 20); -static_assert(from_xy(0b000, 0b111) == 21); +static_assert(from_xy(0b000, 0b001, 8, 8) == 1); +static_assert(from_xy(0b000, 0b010, 8, 8) == 4); +static_assert(from_xy(0b000, 0b011, 8, 8) == 5); +static_assert(from_xy(0b000, 0b100, 8, 8) == 16); +static_assert(from_xy(0b000, 0b101, 8, 8) == 17); +static_assert(from_xy(0b000, 0b110, 8, 8) == 20); +static_assert(from_xy(0b000, 0b111, 8, 8) == 21); + +// 1 0 0 0 +// x bits: 19, 17, 15, 13, 11, 9, 7, 5, 3, 1 +// y bits: 18, 16, 14, 12, 10, 8, 6, 4, 2, 0 +static_assert(from_xy(0b1000, 0b001, 16, 8) == 65); +static_assert(from_xy(0b1010, 0b001, 16, 8) == 73); + +static_assert(from_xy(0b000, 0b1001, 8, 16) == 65); +static_assert(from_xy(0b010, 0b1001, 8, 16) == 73); /* constexpr inline std::array @@ -73,7 +111,6 @@ from_ix(uint32_t curve_ix) return x_y; } -*/ constexpr inline std::tuple from_ix(uint32_t curve_ix) @@ -110,13 +147,14 @@ static_assert(from_ix(16) == xy_type{0b000, 0b100}); static_assert(from_ix(17) == xy_type{0b000, 0b101}); static_assert(from_ix(20) == xy_type{0b000, 0b110}); static_assert(from_ix(21) == xy_type{0b000, 0b111}); +*/ template void texture(volatile T * dst, const T * src, const uint32_t width, const uint32_t height) { for (uint32_t y = 0; y < height; y++) { for (uint32_t x = 0; x < width; x++) { - uint32_t twiddle_ix = from_xy(x, y); + uint32_t twiddle_ix = from_xy(x, y, width, height); T value = src[y * width + x]; dst[twiddle_ix] = value; } @@ -128,7 +166,7 @@ void texture_4bpp(volatile T * dst, const T * src, const uint32_t width, const u { for (uint32_t y = 0; y < height; y++) { for (uint32_t x = 0; x < width; x++) { - uint32_t twiddle_ix = from_xy(x, y); + uint32_t twiddle_ix = from_xy(x, y, width, height); T value = src[y * width + x]; uint32_t shift = (4 * (twiddle_ix & 1)); dst[twiddle_ix / 2] &= ~(0b1111 << shift); @@ -137,6 +175,9 @@ void texture_4bpp(volatile T * dst, const T * src, const uint32_t width, const u } } +/* + the following code is not correct + template void texture2(volatile T * dst, const U * src, const uint32_t src_stride, @@ -206,5 +247,6 @@ void texture3(volatile T * dst, const U * src, } } } +*/ }