example: suzanne_profile: incomplete

This has turned in to an experiment related to texture sampling behavior on the
Dreamcast.
This commit is contained in:
Zack Buhman 2024-02-02 08:18:18 +08:00
parent 0381d356bb
commit f400fe6412
9 changed files with 554 additions and 32 deletions

BIN
europc_mono.data Normal file

Binary file not shown.

7
europc_mono.hpp Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include <cstdint>
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");

View File

@ -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 \

326
example/suzanne_profile.cpp Normal file
View File

@ -0,0 +1,326 @@
#include <cstdint>
#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>() =
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>() =
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>() =
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>() =
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<volatile texture_memory_alloc *>(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<const uint8_t *>(&_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>() = 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;
}
}

173
font/font_bitmap.cpp Normal file
View File

@ -0,0 +1,173 @@
#include <cstdint>
#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<volatile texture_memory_alloc *>(texture_memory64);
auto texture = reinterpret_cast<volatile uint32_t *>(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>() =
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<float>(glyph_width * 1);
y *= static_cast<float>(glyph_height * 1);
x += static_cast<float>(position_x + glyph_width * 4 * string_ix);
y += static_cast<float>(position_y);
z = 1.f / (z + 10.f);
u *= static_cast<float>(glyph_width - 1) / static_cast<float>(texture_width);
v *= static_cast<float>(glyph_height - 1) / static_cast<float>(texture_height);
parameter.append<ta_vertex_parameter::polygon_type_3>() =
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
);
}
}
}
}

29
font/font_bitmap.hpp Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <cstdint>
#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
);
}

View File

@ -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<const uint32_t *>(&glyph_bitmaps[0]);
copy<uint32_t>(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<const font *>(&buf[font_offset / 4]);
auto glyphs = reinterpret_cast<const glyph *>(&buf[glyphs_offset / 4]);
auto glyph_bitmaps = &(reinterpret_cast<const uint8_t *>(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);
}
}

View File

@ -1,3 +1,5 @@
#pragma once
#include <cstdint>
#include <cstddef>
@ -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<uint32_t *>(&u));
uint32_t * vi = (reinterpret_cast<uint32_t *>(&v));

View File

@ -1,3 +1,5 @@
#pragma once
#include <cstdint>
extern uint32_t _binary_sperrypc_data_start __asm("_binary_sperrypc_data_start");