example/md5: add textures

This commit is contained in:
Zack Buhman 2025-05-13 03:26:47 -05:00
parent 29b7f2b351
commit f72e3da6c1
15 changed files with 680 additions and 33 deletions

View File

@ -47,6 +47,11 @@ using vec3 = vec<3, float>;
using vec4 = vec<4, float>; using vec4 = vec<4, float>;
using mat4x4 = mat<4, 4, float>; using mat4x4 = mat<4, 4, float>;
#include "model/boblamp/guard1_body.data.h"
#include "model/boblamp/guard1_face.data.h"
#include "model/boblamp/guard1_helmet.data.h"
#include "model/boblamp/iron_grill.data.h"
#include "model/boblamp/round_grill.data.h"
#include "md5/md5mesh.h" #include "md5/md5mesh.h"
#include "md5/md5anim.h" #include "md5/md5anim.h"
#include "model/boblamp/boblamp_mesh.h" #include "model/boblamp/boblamp_mesh.h"
@ -241,6 +246,9 @@ void transfer_triangle(ta_parameter_writer& writer,
vec3 ap, vec3 ap,
vec3 bp, vec3 bp,
vec3 cp, vec3 cp,
vec2 at,
vec2 bt,
vec2 ct,
vec3 ac, vec3 ac,
vec3 bc, vec3 bc,
vec3 cc vec3 cc
@ -249,23 +257,29 @@ void transfer_triangle(ta_parameter_writer& writer,
if (ap.z < 0 || bp.z < 0 || cp.z < 0) if (ap.z < 0 || bp.z < 0 || cp.z < 0)
return; return;
writer.append<ta_vertex_parameter::polygon_type_1>() = writer.append<ta_vertex_parameter::polygon_type_5>() =
ta_vertex_parameter::polygon_type_1(polygon_vertex_parameter_control_word(false), ta_vertex_parameter::polygon_type_5(polygon_vertex_parameter_control_word(false),
ap.x, ap.y, ap.z, ap.x, ap.y, ap.z,
at.x, at.y,
1.0, 1.0,
ac.x, ac.y, ac.z); ac.x, ac.y, ac.z,
0, 0, 0, 0);
writer.append<ta_vertex_parameter::polygon_type_1>() = writer.append<ta_vertex_parameter::polygon_type_5>() =
ta_vertex_parameter::polygon_type_1(polygon_vertex_parameter_control_word(false), ta_vertex_parameter::polygon_type_5(polygon_vertex_parameter_control_word(false),
bp.x, bp.y, bp.z, bp.x, bp.y, bp.z,
bt.x, bt.y,
1.0, 1.0,
bc.x, bc.y, bc.z); bc.x, bc.y, bc.z,
0, 0, 0, 0);
writer.append<ta_vertex_parameter::polygon_type_1>() = writer.append<ta_vertex_parameter::polygon_type_5>() =
ta_vertex_parameter::polygon_type_1(polygon_vertex_parameter_control_word(true), ta_vertex_parameter::polygon_type_5(polygon_vertex_parameter_control_word(true),
cp.x, cp.y, cp.z, cp.x, cp.y, cp.z,
ct.x, ct.y,
1.0, 1.0,
cc.x, cc.y, cc.z); cc.x, cc.y, cc.z,
0, 0, 0, 0);
} }
vec4 quaternion_normalize(vec4 q) vec4 quaternion_normalize(vec4 q)
@ -403,7 +417,7 @@ vec3 vertex_weight_color(const md5_mesh_joint * joints,
} }
} }
return {0.0, 0.0, 1.0}; return {1.0, 1.0, 1.0};
} }
static inline vec3 screen_transform(vec3 v) static inline vec3 screen_transform(vec3 v)
@ -469,6 +483,9 @@ void transfer_mesh(ta_parameter_writer& writer,
screen_transform(ap), screen_transform(ap),
screen_transform(bp), screen_transform(bp),
screen_transform(cp), screen_transform(cp),
av->tex,
bv->tex,
cv->tex,
ac * a_diffuse, ac * a_diffuse,
bc * b_diffuse, bc * b_diffuse,
cc * c_diffuse cc * c_diffuse
@ -476,20 +493,29 @@ void transfer_mesh(ta_parameter_writer& writer,
} }
} }
void transfer_scene(ta_parameter_writer& writer, void global_polygon(ta_parameter_writer& writer, const md5_shader * shader)
const mat4x4& screen_trans)
{ {
uint32_t control = para_control::list_type::opaque; uint32_t control = para_control::list_type::opaque
| obj_control::texture;
uint32_t tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one uint32_t tsp_instruction_word = tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero | tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::fog_control::no_fog | tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::texture_shading_instruction::decal; | tsp_instruction_word::texture_shading_instruction::modulate
uint32_t texture_control_word = 0; | tsp_instruction_word::texture_u_size::from_int(shader->width)
| tsp_instruction_word::texture_v_size::from_int(shader->height);
uint32_t texture_address = texture_memory_alloc.texture.start + shader->offset;
uint32_t texture_control_word = texture_control_word::pixel_format::_565
| texture_control_word::scan_order::twiddled
| texture_control_word::texture_address(texture_address / 8);
global_polygon_type_0(writer, global_polygon_type_0(writer,
control, control,
tsp_instruction_word, tsp_instruction_word,
texture_control_word); texture_control_word);
}
void transfer_scene(ta_parameter_writer& writer,
const mat4x4& screen_trans)
{
int frame_ix0 = animation_tick / ticks_per_animation_frame; int frame_ix0 = animation_tick / ticks_per_animation_frame;
int frame_ix1 = frame_ix0 + 1; int frame_ix1 = frame_ix0 + 1;
if (frame_ix1 >= animation_frames) if (frame_ix1 >= animation_frames)
@ -500,8 +526,13 @@ void transfer_scene(ta_parameter_writer& writer,
float lerp = (float)(animation_tick - (frame_ix0 * ticks_per_animation_frame)) * tick_div; float lerp = (float)(animation_tick - (frame_ix0 * ticks_per_animation_frame)) * tick_div;
interpolate_skeleton(anim->num_joints, skeleton0, skeleton1, lerp); interpolate_skeleton(anim->num_joints, skeleton0, skeleton1, lerp);
const md5_shader * last_shader = NULL;
for (int i = 0; i < boblamp_mesh.num_meshes; i++) { for (int i = 0; i < boblamp_mesh.num_meshes; i++) {
transfer_mesh(writer, screen_trans, boblamp_mesh.joints, &boblamp_mesh.meshes[i]); const md5_mesh_mesh * mesh = &boblamp_mesh.meshes[i];
if (last_shader != mesh->shader)
global_polygon(writer, mesh->shader);
transfer_mesh(writer, screen_trans, boblamp_mesh.joints, mesh);
} }
writer.append<ta_global_parameter::end_of_list>() = writer.append<ta_global_parameter::end_of_list>() =
@ -554,6 +585,57 @@ void update_maple(struct md5_mesh * m, struct md5_anim * a)
last_da = da; last_da = da;
} }
void transfer_ta_fifo_texture_memory_32byte(void * dst, const void * src, int length)
{
assert((((int)dst) & 31) == 0);
assert((((int)length) & 31) == 0);
uint32_t out_addr = (uint32_t)dst;
sh7091.CCN.QACR0 = ((reinterpret_cast<uint32_t>(out_addr) >> 24) & 0b11100);
sh7091.CCN.QACR1 = ((reinterpret_cast<uint32_t>(out_addr) >> 24) & 0b11100);
volatile uint32_t * base = &store_queue[(out_addr & 0x03ffffe0) / 4];
const uint32_t * src32 = reinterpret_cast<const uint32_t *>(src);
length = (length + 31) & ~31; // round up to nearest multiple of 32
while (length > 0) {
base[0] = src32[0];
base[1] = src32[1];
base[2] = src32[2];
base[3] = src32[3];
base[4] = src32[4];
base[5] = src32[5];
base[6] = src32[6];
base[7] = src32[7];
asm volatile ("pref @%0"
: // output
: "r" (&base[0]) // input
: "memory");
length -= 32;
base += 8;
src32 += 8;
}
}
void transfer_boblamp_textures()
{
for (uint32_t i = 0; i < (sizeof (boblamp_shaders)) / (sizeof (boblamp_shaders[0])); i++) {
const md5_shader * shader = boblamp_shaders[i];
uint32_t offset = texture_memory_alloc.texture.start + shader->offset;
void * dst = reinterpret_cast<void *>(&ta_fifo_texture_memory[offset / 4]);
transfer_ta_fifo_texture_memory_32byte(dst, shader->start, shader->size);
}
}
void transfer_textures()
{
system.LMMODE0 = 0; // 64-bit address space
system.LMMODE1 = 0; // 64-bit address space
transfer_boblamp_textures();
}
uint8_t __attribute__((aligned(32))) ta_parameter_buf[1024 * 1024]; uint8_t __attribute__((aligned(32))) ta_parameter_buf[1024 * 1024];
int main() int main()
@ -591,6 +673,8 @@ int main()
background_parameter2(texture_memory_alloc.background[0].start, background_parameter2(texture_memory_alloc.background[0].start,
0xff202040); 0xff202040);
transfer_textures();
ta_parameter_writer writer = ta_parameter_writer(ta_parameter_buf, (sizeof (ta_parameter_buf))); ta_parameter_writer writer = ta_parameter_writer(ta_parameter_buf, (sizeof (ta_parameter_buf)));
video_output::set_mode_vga(); video_output::set_mode_vga();
@ -612,7 +696,7 @@ int main()
do_get_condition(); do_get_condition();
update_maple(&boblamp_mesh, &boblamp_anim); update_maple(&boblamp_mesh, &boblamp_anim);
//screen_trans = screen_trans * rotate_z(0.01f); screen_trans = screen_trans * rotate_z(0.003f);
writer.offset = 0; writer.offset = 0;
transfer_scene(writer, screen_trans); transfer_scene(writer, screen_trans);

View File

@ -28,5 +28,5 @@ constexpr texture_memory_alloc texture_memory_alloc = {
.background = {{0x1c2000, 0x1c2020}, .background = {{0x1c2000, 0x1c2020},
{0x5c2000, 0x5c2020}}, {0x5c2000, 0x5c2020}},
// 64-bit addresses // 64-bit addresses
.texture = {0x384040, 0x800000} .texture = {0x384080, 0x800000}
}; };

View File

@ -30,8 +30,16 @@ struct md5_mesh_weight {
const vec3 pos; const vec3 pos;
}; };
struct md5_shader {
const void * start;
const int size;
const int width;
const int height;
const int offset;
};
struct md5_mesh_mesh { struct md5_mesh_mesh {
const char * shader; const md5_shader * shader;
const int num_verts; const int num_verts;
const md5_mesh_vert * verts; const md5_mesh_vert * verts;
const int num_tris; const int num_tris;

View File

@ -2,6 +2,8 @@ from generate import renderer
from math import sqrt from math import sqrt
import sys import sys
import md5mesh import md5mesh
from os import path
from PIL import Image
def vec2(a, b): def vec2(a, b):
return f"{{{a:.6f}, {b:.6f}}}" return f"{{{a:.6f}, {b:.6f}}}"
@ -19,6 +21,13 @@ def unit_quaternion_w(x, y, z):
else: else:
return -sqrt(t) return -sqrt(t)
def sanitize_name(name):
return name.replace("-", "_").replace("/", "_").replace(".", "_")
def shader_to_data_name(shader):
name = path.splitext(shader)[0]
return sanitize_name(name)
def render_md5_mesh_joint(joint): def render_md5_mesh_joint(joint):
yield f'.bone_name = "{joint.bone_name}",' yield f'.bone_name = "{joint.bone_name}",'
yield f".parent_index = {joint.parent_index}," yield f".parent_index = {joint.parent_index},"
@ -48,7 +57,8 @@ def render_md5_mesh_weight(weight):
yield f".pos = {pos}," yield f".pos = {pos},"
def render_md5_mesh_mesh(prefix, i, mesh): def render_md5_mesh_mesh(prefix, i, mesh):
yield f'.shader = "{mesh.shader}",' name = shader_to_data_name(mesh.shader)
yield f'.shader = &{prefix}_{name}, // {mesh.shader}'
yield f".num_verts = {mesh.num_verts}," yield f".num_verts = {mesh.num_verts},"
yield f".verts = {prefix}_{i}_verts," yield f".verts = {prefix}_{i}_verts,"
yield f".num_tris = {mesh.num_tris}," yield f".num_tris = {mesh.num_tris},"
@ -94,12 +104,47 @@ def render_md5_mesh_joints(prefix, joints):
yield "}," yield "},"
yield "};" yield "};"
def render_md5_mesh_meshes(prefix, meshes): offset = None
def render_shader(prefix, dirname, shader):
global offset
name = shader_to_data_name(shader)
dir = sanitize_name(dirname)
filename = path.join(dirname, shader)
with Image.open(filename) as im:
width, height = im.size
yield f"struct md5_shader {prefix}_{name} = {{"
yield f".start = (void *)&_binary_{dir}_{name}_data_start,"
yield f".size = (int)&_binary_{dir}_{name}_data_size,"
yield f".width = {width},"
yield f".height = {height},"
yield f".offset = {offset},"
yield "};"
offset += width * height * 2
def render_md5_mesh_shaders(prefix, dirname, meshes):
global offset
offset = 0
shaders = set(mesh.shader for mesh in meshes)
for shader in shaders:
yield from render_shader(prefix, dirname, shader)
yield f"struct md5_shader * {prefix}_shaders[] = {{"
for shader in shaders:
name = shader_to_data_name(shader)
yield f"&{prefix}_{name},"
yield "};"
def render_md5_mesh_meshes(prefix, dirname, meshes):
for i, mesh in enumerate(meshes): for i, mesh in enumerate(meshes):
yield from render_md5_mesh_verts(prefix, i, mesh.verts) yield from render_md5_mesh_verts(prefix, i, mesh.verts)
yield from render_md5_mesh_tris(prefix, i, mesh.tris) yield from render_md5_mesh_tris(prefix, i, mesh.tris)
yield from render_md5_mesh_weights(prefix, i, mesh.weights) yield from render_md5_mesh_weights(prefix, i, mesh.weights)
yield from render_md5_mesh_shaders(prefix, dirname, meshes)
yield f"struct md5_mesh_mesh {prefix}_meshes[] = {{" yield f"struct md5_mesh_mesh {prefix}_meshes[] = {{"
for i, mesh in enumerate(meshes): for i, mesh in enumerate(meshes):
yield "{" yield "{"
@ -107,23 +152,28 @@ def render_md5_mesh_meshes(prefix, meshes):
yield "}," yield "},"
yield "};" yield "};"
def render_mesh(prefix, m): def render_mesh(prefix, dirname, m):
yield from render_md5_mesh_joints(prefix, m.joints) yield from render_md5_mesh_joints(prefix, m.joints)
yield from render_md5_mesh_meshes(prefix, m.meshes) yield from render_md5_mesh_meshes(prefix, dirname, m.meshes)
yield f"struct md5_mesh {prefix}_mesh = {{" yield f"struct md5_mesh {prefix}_mesh = {{"
yield from render_md5_mesh(prefix, m) yield from render_md5_mesh(prefix, m)
yield "};" yield "};"
def render_all(prefix, m): def render_all(prefix, dirname, m):
yield from render_mesh(prefix, m) yield from render_mesh(prefix, dirname, m)
if __name__ == "__main__": if __name__ == "__main__":
with open(sys.argv[1], 'r') as f: filename = sys.argv[1]
prefix = sys.argv[2]
dirname = path.split(filename)[0]
with open(filename, 'r') as f:
buf = f.read() buf = f.read()
l = [i.strip() for i in buf.split('\n') if i.strip()] l = [i.strip() for i in buf.split('\n') if i.strip()]
m = md5mesh.parse_file(l) m = md5mesh.parse_file(l)
render, out = renderer() render, out = renderer()
render(render_all(sys.argv[2], m)) render(render_all(prefix, dirname, m))
sys.stdout.write(out.getvalue()) sys.stdout.write(out.getvalue())

View File

@ -17759,9 +17759,57 @@ struct md5_mesh_weight boblamp_5_weights[] = {
}, },
}; };
struct md5_shader boblamp_guard1_helmet = {
.start = (void *)&_binary_model_boblamp_guard1_helmet_data_start,
.size = (int)&_binary_model_boblamp_guard1_helmet_data_size,
.width = 256,
.height = 256,
.offset = 0,
};
struct md5_shader boblamp_round_grill = {
.start = (void *)&_binary_model_boblamp_round_grill_data_start,
.size = (int)&_binary_model_boblamp_round_grill_data_size,
.width = 256,
.height = 256,
.offset = 131072,
};
struct md5_shader boblamp_iron_grill = {
.start = (void *)&_binary_model_boblamp_iron_grill_data_start,
.size = (int)&_binary_model_boblamp_iron_grill_data_size,
.width = 256,
.height = 256,
.offset = 262144,
};
struct md5_shader boblamp_guard1_face = {
.start = (void *)&_binary_model_boblamp_guard1_face_data_start,
.size = (int)&_binary_model_boblamp_guard1_face_data_size,
.width = 512,
.height = 256,
.offset = 393216,
};
struct md5_shader boblamp_guard1_body = {
.start = (void *)&_binary_model_boblamp_guard1_body_data_start,
.size = (int)&_binary_model_boblamp_guard1_body_data_size,
.width = 512,
.height = 512,
.offset = 655360,
};
struct md5_shader * boblamp_shaders[] = {
&boblamp_guard1_helmet,
&boblamp_round_grill,
&boblamp_iron_grill,
&boblamp_guard1_face,
&boblamp_guard1_body,
};
struct md5_mesh_mesh boblamp_meshes[] = { struct md5_mesh_mesh boblamp_meshes[] = {
{ {
.shader = "guard1_body.tga", .shader = &boblamp_guard1_body, // guard1_body.tga
.num_verts = 494, .num_verts = 494,
.verts = boblamp_0_verts, .verts = boblamp_0_verts,
.num_tris = 628, .num_tris = 628,
@ -17770,7 +17818,7 @@ struct md5_mesh_mesh boblamp_meshes[] = {
.weights = boblamp_0_weights, .weights = boblamp_0_weights,
}, },
{ {
.shader = "guard1_face.tga", .shader = &boblamp_guard1_face, // guard1_face.tga
.num_verts = 110, .num_verts = 110,
.verts = boblamp_1_verts, .verts = boblamp_1_verts,
.num_tris = 177, .num_tris = 177,
@ -17779,7 +17827,7 @@ struct md5_mesh_mesh boblamp_meshes[] = {
.weights = boblamp_1_weights, .weights = boblamp_1_weights,
}, },
{ {
.shader = "guard1_helmet.tga", .shader = &boblamp_guard1_helmet, // guard1_helmet.tga
.num_verts = 80, .num_verts = 80,
.verts = boblamp_2_verts, .verts = boblamp_2_verts,
.num_tris = 78, .num_tris = 78,
@ -17788,7 +17836,7 @@ struct md5_mesh_mesh boblamp_meshes[] = {
.weights = boblamp_2_weights, .weights = boblamp_2_weights,
}, },
{ {
.shader = "iron_grill.tga", .shader = &boblamp_iron_grill, // iron_grill.tga
.num_verts = 18, .num_verts = 18,
.verts = boblamp_3_verts, .verts = boblamp_3_verts,
.num_tris = 16, .num_tris = 16,
@ -17797,7 +17845,7 @@ struct md5_mesh_mesh boblamp_meshes[] = {
.weights = boblamp_3_weights, .weights = boblamp_3_weights,
}, },
{ {
.shader = "round_grill.tga", .shader = &boblamp_round_grill, // round_grill.tga
.num_verts = 38, .num_verts = 38,
.verts = boblamp_4_verts, .verts = boblamp_4_verts,
.num_tris = 22, .num_tris = 22,
@ -17806,7 +17854,7 @@ struct md5_mesh_mesh boblamp_meshes[] = {
.weights = boblamp_4_weights, .weights = boblamp_4_weights,
}, },
{ {
.shader = "guard1_body.tga", .shader = &boblamp_guard1_body, // guard1_body.tga
.num_verts = 135, .num_verts = 135,
.verts = boblamp_5_verts, .verts = boblamp_5_verts,
.num_tris = 106, .num_tris = 106,

Binary file not shown.

View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t _binary_model_boblamp_guard1_body_data_start __asm("_binary_model_boblamp_guard1_body_data_start");
extern uint32_t _binary_model_boblamp_guard1_body_data_end __asm("_binary_model_boblamp_guard1_body_data_end");
extern uint32_t _binary_model_boblamp_guard1_body_data_size __asm("_binary_model_boblamp_guard1_body_data_size");
#ifdef __cplusplus
}
#endif

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t _binary_model_boblamp_guard1_face_data_start __asm("_binary_model_boblamp_guard1_face_data_start");
extern uint32_t _binary_model_boblamp_guard1_face_data_end __asm("_binary_model_boblamp_guard1_face_data_end");
extern uint32_t _binary_model_boblamp_guard1_face_data_size __asm("_binary_model_boblamp_guard1_face_data_size");
#ifdef __cplusplus
}
#endif

Binary file not shown.

View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t _binary_model_boblamp_guard1_helmet_data_start __asm("_binary_model_boblamp_guard1_helmet_data_start");
extern uint32_t _binary_model_boblamp_guard1_helmet_data_end __asm("_binary_model_boblamp_guard1_helmet_data_end");
extern uint32_t _binary_model_boblamp_guard1_helmet_data_size __asm("_binary_model_boblamp_guard1_helmet_data_size");
#ifdef __cplusplus
}
#endif

Binary file not shown.

View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t _binary_model_boblamp_iron_grill_data_start __asm("_binary_model_boblamp_iron_grill_data_start");
extern uint32_t _binary_model_boblamp_iron_grill_data_end __asm("_binary_model_boblamp_iron_grill_data_end");
extern uint32_t _binary_model_boblamp_iron_grill_data_size __asm("_binary_model_boblamp_iron_grill_data_size");
#ifdef __cplusplus
}
#endif

Binary file not shown.

View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t _binary_model_boblamp_round_grill_data_start __asm("_binary_model_boblamp_round_grill_data_start");
extern uint32_t _binary_model_boblamp_round_grill_data_end __asm("_binary_model_boblamp_round_grill_data_end");
extern uint32_t _binary_model_boblamp_round_grill_data_size __asm("_binary_model_boblamp_round_grill_data_size");
#ifdef __cplusplus
}
#endif