From f400fe641216efec16e263e4925efcdfd4ea1386 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Fri, 2 Feb 2024 08:18:18 +0800 Subject: [PATCH] example: suzanne_profile: incomplete This has turned in to an experiment related to texture sampling behavior on the Dreamcast. --- europc_mono.data | Bin 0 -> 2688 bytes europc_mono.hpp | 7 + example/example.mk | 14 ++ example/suzanne_profile.cpp | 326 ++++++++++++++++++++++++++++++++++++ font/font_bitmap.cpp | 173 +++++++++++++++++++ font/font_bitmap.hpp | 29 ++++ font/font_draw.cpp | 31 ---- holly/ta_parameter.hpp | 4 +- sperrypc.hpp | 2 + 9 files changed, 554 insertions(+), 32 deletions(-) create mode 100644 europc_mono.data create mode 100644 europc_mono.hpp create mode 100644 example/suzanne_profile.cpp create mode 100644 font/font_bitmap.cpp create mode 100644 font/font_bitmap.hpp delete mode 100644 font/font_draw.cpp diff --git a/europc_mono.data b/europc_mono.data new file mode 100644 index 0000000000000000000000000000000000000000..b9b715d11817912dd75884b198471fd6481a2548 GIT binary patch literal 2688 zcmai0&1%~~5T0OA12xW7P&bD@fk8n8Y?R#l5();VrC=L!3B=eB=g089eGK>eX0)1F zIZbDgcD3`fv)|0@O5|fIWudK<5`y+Njis=C`-gfhwH)wxZ-QePOC!JJr~E+wS-xZ3 zU~U}jJi%^(nNli@oTh4RDsx%O3T@uAX2RC?-}!)+OoHz+TZ>;s-zb^W3cEk!S>@CC zA{Hfh)?cu@3FFQ#*yoFx;RH3Eu4L3I#M!c?aFuSf*WTXFba~6T)>(?RWi>NB&v)AcBe+3k zw^{tI5x-h@PlVW<_NWiGrt70Wx0rjAqUEjwo+eie3o2ORIvS6NQv zyqUZPJzsAFA1nD9c;+|rD~+7F=<3H}z|+R*rmxFF>pk*b)bkqhJYgzizSAo__m=PB zD1T71Cpq@b^_H;m1}`_LrXkiT3N~LODo!2;TQ%a6@^guEZi7e_@~KyJJ&Q-&gXzt% zPNBXuy_Tr|2`}~$mxOTYqn_{i2t0|rQ{tU~%~{dTc_z{kB{2ogNsK=8u*JF*bI(Hp*G0#kMu0F0b&lnRU^Rvc%X;mNd z%ub?dk7_(8=%pYA>3*cIxlNuPtiZhf+?vHG+BA=TYYsElPMwe5tvfI2>yW&fVqTk6 z(rXl*9Gi$sA@RNvoVdh=k<4{ymFwLDfjkb^nl*cUm+}StArUESF<(q7R?JY3yi|ch z-V!)Z(RdpSDOEdf!J?0mNgd#c{Y%CBebRZq?fSTfbhe~_oOn*Syh&|?EBr6}h*FKl GKaIa@PsND< literal 0 HcmV?d00001 diff --git a/europc_mono.hpp b/europc_mono.hpp new file mode 100644 index 0000000..5640718 --- /dev/null +++ b/europc_mono.hpp @@ -0,0 +1,7 @@ +#pragma once + +#include + +extern uint32_t _binary_europc_mono_data_start __asm("_binary_europc_mono_data_start"); +extern uint32_t _binary_europc_mono_data_end __asm("_binary_europc_mono_data_end"); +extern uint32_t _binary_europc_mono_data_size __asm("_binary_europc_mono_data_size"); diff --git a/example/example.mk b/example/example.mk index d9ae056..19e512b 100644 --- a/example/example.mk +++ b/example/example.mk @@ -115,6 +115,20 @@ ICOSPHERE_OBJ = \ example/icosphere.elf: LDSCRIPT = $(LIB)/alt.lds example/icosphere.elf: $(START_OBJ) $(ICOSPHERE_OBJ) +SUZANNE_PROFILE_OBJ = \ + example/suzanne_profile.o \ + vga.o \ + holly/core.o \ + holly/region_array.o \ + holly/background.o \ + holly/ta_fifo_polygon_converter.o \ + font/font_bitmap.o \ + sh7091/serial.o \ + europc_mono.data.o + +example/suzanne_profile.elf: LDSCRIPT = $(LIB)/alt.lds +example/suzanne_profile.elf: $(START_OBJ) $(SUZANNE_PROFILE_OBJ) + WIFFLE_ATTENUATION_OBJ = \ example/wiffle_attenuation.o \ vga.o \ diff --git a/example/suzanne_profile.cpp b/example/suzanne_profile.cpp new file mode 100644 index 0000000..ccd7754 --- /dev/null +++ b/example/suzanne_profile.cpp @@ -0,0 +1,326 @@ +#include + +#include "align.hpp" +#include "vga.hpp" + +#include "holly/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_global_parameter.hpp" +#include "holly/ta_vertex_parameter.hpp" +#include "holly/isp_tsp.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 "geometry/suzanne.hpp" +#include "math/vec4.hpp" + +#include "font/font_bitmap.hpp" +#include "europc_mono.hpp" + +constexpr float half_degree = 0.01745329f / 2; + +#define MODEL suzanne + +vec3 rotate(const vec3& vertex, + const float theta) +{ + float x = vertex.x; + float y = vertex.y; + float z = vertex.z; + float t; + + t = y * cos(theta) - z * sin(theta); + z = y * sin(theta) + z * cos(theta); + y = t; + + float theta2 = 3.14 * sin(theta / 2); + + t = x * cos(theta2) - z * sin(theta2); + z = x * sin(theta2) + z * cos(theta2); + x = t; + + return vec3(x, y, z); +} + +void transform(ta_parameter_writer& parameter, + const uint32_t face_ix, + const float theta, + const vec3 lights[3]) +{ + 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() = + ta_global_parameter::polygon_type_0(parameter_control_word, + isp_tsp_instruction_word, + tsp_instruction_word, + 0, // texture_control_word + 0, // data_size_for_sort_dma + 0 // next_address_for_sort_dma + ); + auto& face = MODEL::faces[face_ix]; + + 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 = MODEL::vertices[vertex_ix]; + auto point = rotate(vertex, theta); + + // lighting transform + uint32_t normal_ix = face[i].normal; + auto& normal = MODEL::normals[normal_ix]; + auto n = rotate(normal, theta); + + vec4 color = {0.2, 0.2, 0.2, 1.0}; + + // intensity calculation + { + auto l = lights[0] - point; + auto n_dot_l = dot(n, l); + if (n_dot_l > 0) { + color.x += 0.6 * n_dot_l / (length(n) * length(l)); + } + } + + { + auto l = lights[1] - point; + auto n_dot_l = dot(n, l); + if (n_dot_l > 0) { + color.y += 0.6 * n_dot_l / (length(n) * length(l)); + } + } + + { + auto l = lights[2] - point; + auto n_dot_l = dot(n, l); + if (n_dot_l > 0) { + color.z += 0.6 * n_dot_l / (length(n) * length(l)); + } + } + + float x = point.x; + float y = point.y; + float z = point.z; + + x *= 10; + y *= 10; + z *= 10; + + // camera transform + z += 20; + + // 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; + + bool end_of_strip = i == strip_length - 1; + parameter.append() = + ta_vertex_parameter::polygon_type_1(polygon_vertex_parameter_control_word(end_of_strip), + x, y, z, + color.w, // alpha + color.x, // r + color.y, // g + color.z // b + ); + } +} + +void transform2(ta_parameter_writer& parameter, + const vec3& pos, + const vec4& color) +{ + 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::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() = + ta_global_parameter::polygon_type_0(parameter_control_word, + isp_tsp_instruction_word, + tsp_instruction_word, + 0, // texture_control_word + 0, // data_size_for_sort_dma + 0 // next_address_for_sort_dma + ); + + constexpr vec3 triangle[] = { + { 0.f, -1.f, 0.f}, + {-1.f, 1.f, 0.f}, + { 1.f, 1.f, 0.f}, + }; + + constexpr uint32_t strip_length = 3; + for (uint32_t i = 0; i < strip_length; i++) { + float x = triangle[i].x; + float y = triangle[i].y; + float z = triangle[i].z; + + x *= 0.2; + y *= 0.2; + z *= 0.2; + + x += pos.x; + y += pos.y; + z += pos.z; + + // camera transform + z += 20; + + // 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; + + bool end_of_strip = i == strip_length - 1; + parameter.append() = + ta_vertex_parameter::polygon_type_1(polygon_vertex_parameter_control_word(end_of_strip), + x, y, z, + color.w, // alpha + color.x, // r + color.y, // g + color.z // b + ); + } +} + +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(); + + auto src = reinterpret_cast(&_binary_europc_mono_data_start); + font_bitmap::inflate(2, // pitch + 9, // width + 14, // height + 16, // texture_width + 16, // texture_height + src); + font_bitmap::palette_data(); + + // 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; + + float theta = 0; + vec3 lights[3] = { + {0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + {0.f, 0.f, 0.f}, + }; + + while (1) { + ta_polygon_converter_init(opb_size.total(), + ta_alloc, + 640 / 32, + 480 / 32); + + float theta2 = 3.14 * 2 * sin(theta / 7); + + lights[0].x = cos(theta) * 15; + lights[0].z = sin(theta) * 15; + + lights[1].x = cos(theta2 + half_degree * 180.f) * 15; + lights[1].z = sin(theta2 + half_degree * 180.f) * 15; + + lights[2].x = cos(theta + half_degree * 360.f) * 15; + lights[2].z = sin(theta + half_degree * 360.f) * 15; + + auto parameter = ta_parameter_writer(ta_parameter_buf); + for (uint32_t i = 0; i < MODEL::num_faces; i++) { + transform(parameter, i, theta, lights); + } + transform2(parameter, lights[0], {1.f, 0.f, 0.f, 1.f}); + transform2(parameter, lights[1], {0.f, 1.f, 0.f, 1.f}); + transform2(parameter, lights[2], {0.f, 0.f, 1.f, 1.f}); + + font_bitmap::transform_string(parameter, + 16, 16, // texture + 9, 14, // glyph + 40, 40, // position + "test", 4); + + parameter.append() = ta_global_parameter::end_of_list(para_control::para_type::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); + theta += half_degree; + frame_ix += 1; + } +} diff --git a/font/font_bitmap.cpp b/font/font_bitmap.cpp new file mode 100644 index 0000000..55d38e5 --- /dev/null +++ b/font/font_bitmap.cpp @@ -0,0 +1,173 @@ +#include + +#include "../holly/holly.hpp" +#include "../holly/core_bits.hpp" +#include "../holly/texture_memory_alloc.hpp" +#include "../holly/isp_tsp.hpp" +#include "../holly/ta_parameter.hpp" +#include "../holly/ta_global_parameter.hpp" +#include "../holly/ta_vertex_parameter.hpp" +#include "../memorymap.hpp" +#include "../twiddle.hpp" + +#include "../sh7091/serial.hpp" + +#include "font_bitmap.hpp" + +namespace font_bitmap { + +static inline void inflate_character(const uint32_t pitch, + const uint32_t width, + const uint32_t height, + const uint32_t texture_width, + const uint32_t texture_height, + const uint8_t * src, + const uint8_t c) +{ + const uint32_t character_index = c - ' '; + const uint32_t offset = pitch * height * character_index; + uint8_t temp[texture_width * texture_height]; + + for (uint32_t y = 0; y < height; y++) { + for (uint32_t x = 0; x < width; x++) { + uint8_t row = src[offset + (y * pitch) + (x / 8)]; + uint8_t px = (row >> (7 - (x % 8))) & 1; + //serial::character((px == 1) ? 'X' : '_'); + uint16_t palette_index = px ? 2 : 1; + temp[y * texture_width + x] = palette_index; + } + for (uint32_t x = width; x < texture_width; x++) { + temp[y * texture_width + x] = 1; + } + //serial::character('\n'); + } + for (uint32_t y = height; y < texture_height; y++) { + for (uint32_t x = 0; x < texture_width; x++) { + temp[y * texture_width + x] = 1; + } + } + + auto mem = reinterpret_cast(texture_memory64); + auto texture = reinterpret_cast(mem->texture); + + const uint32_t texture_offset = texture_width * texture_height * character_index / 2; + twiddle::texture2<4>(&texture[texture_offset / 4], // uint32_t * + temp, + texture_width, + texture_width * texture_height); +} + +void inflate(const uint32_t pitch, + const uint32_t width, + const uint32_t height, + const uint32_t texture_width, + const uint32_t texture_height, + const uint8_t * src) +{ + for (uint8_t ix = 0x20; ix < 0x7f; ix++) { + inflate_character(pitch, + width, + height, + texture_width, + texture_height, + src, + ix); + } +} + +void palette_data() +{ + holly.PAL_RAM_CTRL = pal_ram_ctrl::pixel_format::rgb565; + + holly.PALETTE_RAM[1] = 0x0000; + holly.PALETTE_RAM[2] = 0xffff; +} + +struct quad_vertex { + float x; + float y; + float z; + float u; + float v; +}; + +const struct quad_vertex quad_vertices[4] = { + // [ position ] [ uv coordinates ] + { -0.5f, 0.5f, 0.f, 0.f, 1.f, }, + { -0.5f, -0.5f, 0.f, 0.f, 0.f, }, + { 0.5f, 0.5f, 0.f, 1.f, 1.f, }, + { 0.5f, -0.5f, 0.f, 1.f, 0.f, }, +}; +constexpr uint32_t quad_length = (sizeof (quad_vertices)) / (sizeof (struct quad_vertex)); + +void transform_string(ta_parameter_writer& parameter, + const uint32_t texture_width, + const uint32_t texture_height, + const uint32_t glyph_width, + const uint32_t glyph_height, + const int32_t position_x, + const int32_t position_y, + const char * s, + const uint32_t len + ) +{ + const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume + | para_control::list_type::opaque + | obj_control::col_type::packed_color + | obj_control::texture; + + const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::always + | 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 + | tsp_instruction_word::texture_u_size::from_int(texture_width) + | tsp_instruction_word::texture_v_size::from_int(texture_height); + + for (uint32_t string_ix = 0; string_ix < len; string_ix++) { + const uint32_t texture_address = (offsetof (struct texture_memory_alloc, texture)); + const uint32_t glyph_address = texture_address + texture_width * texture_height * (s[string_ix] - ' ') / 2; + const uint32_t texture_control_word = texture_control_word::pixel_format::_4bpp_palette + | texture_control_word::scan_order::twiddled + | texture_control_word::texture_address(glyph_address / 8); + + parameter.append() = + ta_global_parameter::polygon_type_0(parameter_control_word, + isp_tsp_instruction_word, + tsp_instruction_word, + texture_control_word, + 0, // data_size_for_sort_dma + 0 // next_address_for_sort_dma + ); + + for (uint32_t i = 0; i < quad_length; i++) { + bool end_of_strip = i == quad_length - 1; + + float x = quad_vertices[i].x; + float y = quad_vertices[i].y; + float z = quad_vertices[i].z; + float u = quad_vertices[i].u; + float v = quad_vertices[i].v; + + x *= static_cast(glyph_width * 1); + y *= static_cast(glyph_height * 1); + x += static_cast(position_x + glyph_width * 4 * string_ix); + y += static_cast(position_y); + z = 1.f / (z + 10.f); + + u *= static_cast(glyph_width - 1) / static_cast(texture_width); + v *= static_cast(glyph_height - 1) / static_cast(texture_height); + + parameter.append() = + ta_vertex_parameter::polygon_type_3(polygon_vertex_parameter_control_word(end_of_strip), + x, y, z, + u, v, + 0, // base_color + 0 // offset_color + ); + } + } +} + +} diff --git a/font/font_bitmap.hpp b/font/font_bitmap.hpp new file mode 100644 index 0000000..41d188f --- /dev/null +++ b/font/font_bitmap.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "../holly/ta_parameter.hpp" + +namespace font_bitmap { + +void inflate(const uint32_t pitch, + const uint32_t width, + const uint32_t height, + const uint32_t texture_width, + const uint32_t texture_height, + const uint8_t * src); + +void palette_data(); + +void transform_string(ta_parameter_writer& parameter, + const uint32_t texture_width, + const uint32_t texture_height, + const uint32_t glyph_width, + const uint32_t glyph_height, + const int32_t position_x, + const int32_t position_y, + const char * s, + const uint32_t len + ); + +} diff --git a/font/font_draw.cpp b/font/font_draw.cpp deleted file mode 100644 index a159dbc..0000000 --- a/font/font_draw.cpp +++ /dev/null @@ -1,31 +0,0 @@ - - -uint32_t pixel_data(const uint32_t * dest, const uint8_t * glyph_bitmaps, const uint32_t size) -{ - const uint8_t temp[size]; - - const uint32_t * buf = reinterpret_cast(&glyph_bitmaps[0]); - - copy(table, buf, size); - - return table_address; -} - -uint32_t font_data(const uint32_t * buf, state& state) -{ - constexpr uint32_t font_offset = 0; - constexpr uint32_t glyphs_offset = (sizeof (struct font)); - const uint32_t glyph_bitmaps_offset = (sizeof (struct font)) + (sizeof (struct glyph)) * font->glyph_index; - - auto font = reinterpret_cast(&buf[font_offset / 4]); - auto glyphs = reinterpret_cast(&buf[glyphs_offset / 4]); - auto glyph_bitmaps = &(reinterpret_cast(buf))[glyph_bitmaps_offset]; - - for (uint32_t glyph_ix = 0; glyph_ix < font->glyph_index; glyph_ix++) { - auto& glyph_bitmap = glyphs[glyph_ix].bitmap; - - auto bitmap = &glyph_bitmaps[glyph_bitmap.offset]; - // bitmap.pitch may be zero; bitmap.pitch is a multiple of 8 pixels - SIZE__X(bitmap.pitch) | SIZE__Y(bitmap.rows); - } -} diff --git a/holly/ta_parameter.hpp b/holly/ta_parameter.hpp index a155a2b..e83242c 100644 --- a/holly/ta_parameter.hpp +++ b/holly/ta_parameter.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include @@ -96,7 +98,7 @@ struct ta_parameter_writer { } }; -uint32_t uv_16bit(float u, float v) +constexpr inline uint32_t uv_16bit(float u, float v) { uint32_t * ui = (reinterpret_cast(&u)); uint32_t * vi = (reinterpret_cast(&v)); diff --git a/sperrypc.hpp b/sperrypc.hpp index 346857c..82f31f5 100644 --- a/sperrypc.hpp +++ b/sperrypc.hpp @@ -1,3 +1,5 @@ +#pragma once + #include extern uint32_t _binary_sperrypc_data_start __asm("_binary_sperrypc_data_start");