example: add dragon

This commit is contained in:
Zack Buhman 2025-02-16 19:40:33 -06:00
parent f70603f1ca
commit e389a0c80c
21 changed files with 241002 additions and 1 deletions

View File

@ -16,7 +16,7 @@ SECTIONS
*(.text)
} > p1ram
.data ALIGN(4) :
.data ALIGN(4) : SUBALIGN(32)
{
*(.data)
*(.data.*)

720
example/dragon.cpp Normal file
View File

@ -0,0 +1,720 @@
#include <stdint.h>
#include "holly/background.hpp"
#include "holly/core.hpp"
#include "holly/core_bits.hpp"
#include "holly/holly.hpp"
#include "holly/isp_tsp.hpp"
#include "holly/region_array.hpp"
#include "holly/ta_bits.hpp"
#include "holly/ta_fifo_polygon_converter.hpp"
#include "holly/ta_global_parameter.hpp"
#include "holly/ta_parameter.hpp"
#include "holly/ta_vertex_parameter.hpp"
#include "holly/texture_memory_alloc3.hpp"
#include "holly/video_output.hpp"
#include "sh7091/sh7091.hpp"
#include "sh7091/sh7091_bits.hpp"
#include "sh7091/serial.hpp"
#include "sh7091/vbr.hpp"
#include "systembus.hpp"
#include "systembus_bits.hpp"
#include "memorymap.hpp"
#include "math/vec2.hpp"
#include "math/vec3.hpp"
#include "math/mat4x4.hpp"
using vec2 = vec<2, float>;
using vec3 = vec<3, float>;
using mat4x4 = mat<4, 4, float>;
#include "md2/md2.h"
#include "md2/md2_normals.h"
#include "model/dragon/model.c"
#include "model/dragon/dragon.data.h"
#include "model/dragon/dragon.data.pal.h"
#include "model/dragon/chrome.data.h"
#include "model/dragon/inverse_cube.h"
void vbr100()
{
serial::string("vbr100\n");
serial::string("expevt ");
serial::integer<uint16_t>(sh7091.CCN.EXPEVT);
serial::string("intevt ");
serial::integer<uint16_t>(sh7091.CCN.INTEVT);
serial::string("tra ");
serial::integer<uint16_t>(sh7091.CCN.TRA);
uint32_t spc;
uint32_t ssr;
asm volatile ("stc spc,%0" : "=r" (spc));
asm volatile ("stc ssr,%0" : "=r" (ssr));
serial::string("spc ");
serial::integer(spc);
serial::string("ssr ");
serial::integer(ssr);
while (1);
}
void vbr400()
{
serial::string("vbr400");
serial::string("expevt ");
serial::integer<uint16_t>(sh7091.CCN.EXPEVT);
serial::string("intevt ");
serial::integer<uint16_t>(sh7091.CCN.INTEVT);
serial::string("tra ");
serial::integer<uint16_t>(sh7091.CCN.TRA);
uint32_t spc;
uint32_t ssr;
asm volatile ("stc spc,%0" : "=r" (spc));
asm volatile ("stc ssr,%0" : "=r" (ssr));
serial::string("spc ");
serial::integer(spc);
serial::string("ssr ");
serial::integer(ssr);
while (1);
}
static int render_done = 0;
void vbr600()
{
if (sh7091.CCN.EXPEVT == 0 && sh7091.CCN.INTEVT == 0x320) {
uint32_t istnrm = system.ISTNRM;
uint32_t isterr = system.ISTERR;
if (isterr) {
serial::string("isterr: ");
serial::integer<uint32_t>(system.ISTERR);
}
if (istnrm & istnrm::end_of_render_tsp) {
system.ISTNRM = istnrm::end_of_render_tsp
| istnrm::end_of_render_isp
| istnrm::end_of_render_video;
render_done = 1;
return;
}
}
serial::string("vbr600");
serial::string("expevt ");
serial::integer<uint16_t>(sh7091.CCN.EXPEVT);
serial::string("intevt ");
serial::integer<uint16_t>(sh7091.CCN.INTEVT);
serial::string("tra ");
serial::integer<uint16_t>(sh7091.CCN.TRA);
serial::string("istnrm: ");
serial::integer<uint32_t>(system.ISTNRM);
serial::string("isterr: ");
serial::integer<uint32_t>(system.ISTERR);
uint32_t spc;
uint32_t ssr;
asm volatile ("stc spc,%0" : "=r" (spc));
asm volatile ("stc ssr,%0" : "=r" (ssr));
serial::string("spc ");
serial::integer(spc);
serial::string("ssr ");
serial::integer(ssr);
while (1);
}
void interrupt_init()
{
system.IML2NRM = 0;
system.IML2ERR = 0;
system.IML2EXT = 0;
system.IML4NRM = 0;
system.IML4ERR = 0;
system.IML4EXT = 0;
system.IML6NRM = 0;
system.IML6ERR = 0;
system.IML6EXT = 0;
system.ISTERR = 0xffffffff;
system.ISTNRM = 0xffffffff;
sh7091.CCN.INTEVT = 0;
sh7091.CCN.EXPEVT = 0;
uint32_t vbr = reinterpret_cast<uint32_t>(&__vbr_link_start) - 0x100;
serial::string("vbr ");
serial::integer<uint32_t>(vbr);
serial::string("vbr100 ");
serial::integer<uint32_t>(reinterpret_cast<uint32_t>(&vbr100));
asm volatile ("ldc %0,vbr"
:
: "r" (vbr));
uint32_t sr;
asm volatile ("stc sr,%0"
: "=r" (sr));
serial::string("sr ");
serial::integer<uint32_t>(sr);
sr &= ~sh::sr::bl; // BL
sr &= ~sh::sr::imask(15); // imask
serial::string("sr ");
serial::integer<uint32_t>(sr);
asm volatile ("ldc %0,sr"
:
: "r" (sr));
}
void global_polygon_type_0(ta_parameter_writer& writer, uint32_t texture_address, uint32_t list, uint32_t cull)
{
const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume
| list
| obj_control::col_type::packed_color
| obj_control::texture
;
const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| cull;
const uint32_t tsp_instruction_word = tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::src_alpha_instr::one
| tsp_instruction_word::dst_alpha_instr::zero
| tsp_instruction_word::texture_u_size::from_int(256)
| tsp_instruction_word::texture_v_size::from_int(256)
;
const 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);
writer.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
);
}
void global_polygon_type_0b(ta_parameter_writer& writer, uint32_t texture_address, uint32_t cull)
{
const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume
| para_control::list_type::translucent
| obj_control::col_type::packed_color
| obj_control::texture
;
const uint32_t isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater
| cull;
const uint32_t tsp_instruction_word = tsp_instruction_word::fog_control::no_fog
| tsp_instruction_word::src_alpha_instr::src_alpha
| tsp_instruction_word::dst_alpha_instr::inverse_src_alpha
| tsp_instruction_word::texture_u_size::from_int(64)
| tsp_instruction_word::texture_v_size::from_int(64)
| tsp_instruction_word::use_alpha
| tsp_instruction_word::filter_mode::bilinear_filter
| tsp_instruction_word::texture_shading_instruction::decal_alpha;
const 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);
writer.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
);
}
vec3 screen_transform(const mat4x4& screen, vec3 v)
{
v = screen * v;
float dim = 480 / 2.0 * 8;
return {
v.x / v.z * dim + 640 / 2.0f,
v.y / v.z * dim + 480 / 2.0f,
1 / v.z,
};
}
static inline void render_tri(ta_parameter_writer& writer,
uint32_t base_color,
vec3 ap,
vec3 bp,
vec3 cp,
vec2 at,
vec2 bt,
vec2 ct)
{
writer.append<ta_vertex_parameter::polygon_type_3>() =
ta_vertex_parameter::polygon_type_3(polygon_vertex_parameter_control_word(false),
ap.x, ap.y, ap.z,
at.x, at.y,
base_color,
0); // offset_color
writer.append<ta_vertex_parameter::polygon_type_3>() =
ta_vertex_parameter::polygon_type_3(polygon_vertex_parameter_control_word(false),
bp.x, bp.y, bp.z,
bt.x, bt.y,
base_color,
0); // offset_color
writer.append<ta_vertex_parameter::polygon_type_3>() =
ta_vertex_parameter::polygon_type_3(polygon_vertex_parameter_control_word(true),
cp.x, cp.y, cp.z,
ct.x, ct.y,
base_color,
0); // offset_color
}
static inline void render_quad(ta_parameter_writer& writer,
uint32_t base_color,
vec3 ap,
vec3 bp,
vec3 cp,
vec3 dp,
vec2 at,
vec2 bt,
vec2 ct,
vec2 dt)
{
writer.append<ta_vertex_parameter::polygon_type_3>() =
ta_vertex_parameter::polygon_type_3(polygon_vertex_parameter_control_word(false),
ap.x, ap.y, ap.z,
at.x, at.y,
base_color,
0); // offset_color
writer.append<ta_vertex_parameter::polygon_type_3>() =
ta_vertex_parameter::polygon_type_3(polygon_vertex_parameter_control_word(false),
bp.x, bp.y, bp.z,
bt.x, bt.y,
base_color,
0); // offset_color
writer.append<ta_vertex_parameter::polygon_type_3>() =
ta_vertex_parameter::polygon_type_3(polygon_vertex_parameter_control_word(false),
dp.x, dp.y, dp.z,
dt.x, dt.y,
base_color,
0); // offset_color
writer.append<ta_vertex_parameter::polygon_type_3>() =
ta_vertex_parameter::polygon_type_3(polygon_vertex_parameter_control_word(true),
cp.x, cp.y, cp.z,
ct.x, ct.y,
base_color,
0); // offset_color
}
static inline vec3 frame_vertex_to_vec3(struct md2_frame * frame, int index)
{
return {
((float)frame->verts[index].v[0]) * frame->scale.x + frame->translate.x,
((float)frame->verts[index].v[1]) * frame->scale.y + frame->translate.y,
((float)frame->verts[index].v[2]) * frame->scale.z + frame->translate.z,
};
}
static inline vec2 texture_coordinate_to_vec2(struct md2_texture_coordinate * st, float div, int index)
{
return {
((float)st[index].s) * div,
((float)st[index].t) * div,
};
}
constexpr inline mat4x4 screen_rotation(float theta)
{
//float zt = -0.7853981633974483 + (0.2);
float zt = -0.7853981633974483 + (0.2) + theta * 0.5;
float xt = 0.7853981633974483 * 2.5;
//float xt = 0.7853981633974483 * 3.7;
mat4x4 rx = {
1, 0, 0, 0,
0, cos(xt), -sin(xt), 0,
0, sin(xt), cos(xt), 0,
0, 0, 0, 1,
};
mat4x4 rz = {
cos(zt), -sin(zt), 0, 0,
sin(zt), cos(zt), 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
};
mat4x4 t = {
1, 0, 0, 0,
0, 1, 0, -90,
0, 0, 1, 180,
0, 0, 0, 1,
};
return t * rx * rz;
}
static int animation_tick = 0;
constexpr int animation_frames = 40;
constexpr int ticks_per_animation_frame = 16;
constexpr float tick_div = 1.0f / (float)ticks_per_animation_frame;
void render_dragon(ta_parameter_writer& writer, const mat4x4& model, const mat4x4& screen)
{
int frame_ix0 = animation_tick / ticks_per_animation_frame;
int frame_ix1 = frame_ix0 + 1;
if (frame_ix1 >= animation_frames)
frame_ix1 = 0;
struct md2_frame * frame0 = &dragon_header.frames[frame_ix0];
struct md2_frame * frame1 = &dragon_header.frames[frame_ix1];
float st_div = 1.0f / 256.0f;
uint32_t base_color = 0xff000000;
for (int i = 0; i < dragon_header.num_tris; i++) {
struct md2_triangle * t = &dragon_header.tris[i];
vec3 a0 = frame_vertex_to_vec3(frame0, t->vertex[0]);
vec3 b0 = frame_vertex_to_vec3(frame0, t->vertex[1]);
vec3 c0 = frame_vertex_to_vec3(frame0, t->vertex[2]);
vec3 a1 = frame_vertex_to_vec3(frame1, t->vertex[0]);
vec3 b1 = frame_vertex_to_vec3(frame1, t->vertex[1]);
vec3 c1 = frame_vertex_to_vec3(frame1, t->vertex[2]);
float lerp = (float)(animation_tick - (frame_ix0 * ticks_per_animation_frame)) * tick_div;
vec3 a = model * (a0 + ((a1 - a0) * lerp));
vec3 b = model * (b0 + ((b1 - b0) * lerp));
vec3 c = model * (c0 + ((c1 - c0) * lerp));
vec2 at = texture_coordinate_to_vec2(dragon_header.st, st_div, t->st[0]);
vec2 bt = texture_coordinate_to_vec2(dragon_header.st, st_div, t->st[1]);
vec2 ct = texture_coordinate_to_vec2(dragon_header.st, st_div, t->st[2]);
render_tri(writer,
base_color,
screen_transform(screen, a),
screen_transform(screen, b),
screen_transform(screen, c),
at,
bt,
ct);
}
}
void render_cube(ta_parameter_writer& writer, const mat4x4& screen)
{
float s = 100.f;
float x = -10;
float y = -100;
float z = 0.0f;
const mat4x4 translate = {
1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1,
};
const mat4x4 scale = {
s, 0, 0, 0,
0, s, 0, 0,
0, 0, s, 0,
0, 0, 0, 1,
};
const mat4x4 model = translate * scale;
float x1 = -10;
float y1 = -100;
float z1 = -200.0f;
const mat4x4 translate1 = {
1, 0, 0, x1,
0, 1, 0, y1,
0, 0, 1, z1,
0, 0, 0, 1,
};
const mat4x4 model1 = translate1 * scale;
const struct object * object = inverse_cube_model.object[0];
const uint32_t base_color = 0x40ffffff;
global_polygon_type_0b(writer,
texture_memory_alloc.texture.start + 131072,
isp_tsp_instruction_word::culling_mode::cull_if_positive);
for (int i = 0; i < object->quadrilateral_count; i++) {
const union quadrilateral * quad = &object->quadrilateral[i];
vec3 a = inverse_cube_model.position[quad->a.position];
vec3 b = inverse_cube_model.position[quad->b.position];
vec3 c = inverse_cube_model.position[quad->c.position];
vec3 d = inverse_cube_model.position[quad->d.position];
vec3 ap = model * a;
vec3 bp = model * b;
vec3 cp = model * c;
vec3 dp = model * d;
vec2 at = inverse_cube_model.texture[quad->a.texture];
vec2 bt = inverse_cube_model.texture[quad->b.texture];
vec2 ct = inverse_cube_model.texture[quad->c.texture];
vec2 dt = inverse_cube_model.texture[quad->d.texture];
render_quad(writer,
base_color,
screen_transform(screen, ap),
screen_transform(screen, bp),
screen_transform(screen, cp),
screen_transform(screen, dp),
at * 3.0f,
bt * 3.0f,
ct * 3.0f,
dt * 3.0f);
render_quad(writer,
base_color,
screen_transform(screen, model1 * a),
screen_transform(screen, model1 * b),
screen_transform(screen, model1 * c),
screen_transform(screen, model1 * d),
at * 3.0f,
bt * 3.0f,
ct * 3.0f,
dt * 3.0f);
}
}
void transfer_scene(ta_parameter_writer& writer)
{
const float deg = 0.017453292519943295 / 4;
static float theta = deg;
const mat4x4 screen = screen_rotation(theta);
theta += deg;
// opaque
if (1) {
global_polygon_type_0(writer, texture_memory_alloc.texture.start,
para_control::list_type::opaque,
isp_tsp_instruction_word::culling_mode::cull_if_negative);
float scale = 0.3f;
float translate = -92.8f;
const mat4x4 model = {
scale, 0, 0, 0,
0, scale, 0, 0,
0, 0, scale, translate,
0, 0, 0, 1,
};
render_dragon(writer, model, screen);
}
{
global_polygon_type_0(writer, texture_memory_alloc.texture.start,
para_control::list_type::opaque,
isp_tsp_instruction_word::culling_mode::cull_if_positive);
float scale = 0.3f;
float translate = -107.35f;
const mat4x4 model = {
scale, 0, 0, 0,
0, scale, 0, 0,
0, 0, -scale, translate,
0, 0, 0, 1,
};
render_dragon(writer, model, screen);
}
// end of opaque list
writer.append<ta_global_parameter::end_of_list>() =
ta_global_parameter::end_of_list(para_control::para_type::end_of_list);
render_cube(writer, screen);
// end of translucent list
writer.append<ta_global_parameter::end_of_list>() =
ta_global_parameter::end_of_list(para_control::para_type::end_of_list);
// increment tick
animation_tick += 1;
if (animation_tick >= animation_frames * ticks_per_animation_frame)
animation_tick = 0;
}
void transfer_ta_fifo_texture_memory_32byte(void * dst, void * src, int length)
{
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 & 0x03ffffc0) / 4];
uint32_t * src32 = reinterpret_cast<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_textures()
{
system.LMMODE0 = 0; // 64-bit address space
system.LMMODE1 = 0; // 64-bit address space
{
uint32_t offset = texture_memory_alloc.texture.start;
void * dst = reinterpret_cast<void *>(&ta_fifo_texture_memory[offset / 4]);
void * src = reinterpret_cast<void *>(&_binary_model_dragon_dragon_data_start);
uint32_t size = reinterpret_cast<uint32_t>(&_binary_model_dragon_dragon_data_size);
transfer_ta_fifo_texture_memory_32byte(dst, src, size);
}
{
uint32_t offset = texture_memory_alloc.texture.start + 131072;
void * dst = reinterpret_cast<void *>(&ta_fifo_texture_memory[offset / 4]);
void * src = reinterpret_cast<void *>(&_binary_model_dragon_chrome_data_start);
uint32_t size = reinterpret_cast<uint32_t>(&_binary_model_dragon_chrome_data_size);
transfer_ta_fifo_texture_memory_32byte(dst, src, size);
}
}
void transfer_palette()
{
holly.PAL_RAM_CTRL = pal_ram_ctrl::pixel_format::rgb565;
uint16_t * src = reinterpret_cast<uint16_t *>(&_binary_model_dragon_dragon_data_pal_start);
uint32_t size = reinterpret_cast<uint32_t>(&_binary_model_dragon_dragon_data_pal_size);
for (uint32_t i = 0; i < size / 2; i++) {
holly.PALETTE_RAM[i] = src[i];
}
}
uint8_t __attribute__((aligned(32))) ta_parameter_buf[1024 * 1024];
void main()
{
serial::init(0);
interrupt_init();
constexpr uint32_t ta_alloc = 0
| ta_alloc_ctrl::pt_opb::no_list
| ta_alloc_ctrl::tm_opb::no_list
| ta_alloc_ctrl::t_opb::_16x4byte
| 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 = 16 * 4,
.translucent_modifier = 0,
.punch_through = 0
}
};
holly.SOFTRESET = softreset::pipeline_soft_reset
| softreset::ta_soft_reset;
holly.SOFTRESET = 0;
core_init();
system.IML6NRM = istnrm::end_of_render_tsp;
const int framebuffer_width = 640;
const int framebuffer_height = 480;
const int tile_width = framebuffer_width / 32;
const int tile_height = framebuffer_height / 32;
for (int i = 0; i < 2; i++) {
region_array_multipass(tile_width,
tile_height,
opb_size,
render_passes,
texture_memory_alloc.region_array[i].start,
texture_memory_alloc.object_list[i].start);
background_parameter2(texture_memory_alloc.background[i].start,
0xff202040);
}
int ta = 0;
int core = 0;
ta_parameter_writer writer = ta_parameter_writer(ta_parameter_buf);
transfer_textures();
transfer_palette();
video_output::set_mode_vga();
animation_tick = 0x000004ff;
while (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);
writer.offset = 0;
transfer_scene(writer);
ta_polygon_converter_writeback(writer.buf, writer.offset);
ta_polygon_converter_transfer(writer.buf, writer.offset);
//serial::string("wait opaque_list");
ta_wait_translucent_list();
render_done = 0;
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);
//serial::string("wait render_done");
while (render_done == 0) {
asm volatile ("nop");
};
while (!spg_status::vsync(holly.SPG_STATUS));
holly.FB_R_SOF1 = texture_memory_alloc.framebuffer[ta].start;
while (spg_status::vsync(holly.SPG_STATUS));
}
}

View File

@ -873,3 +873,19 @@ MODIFIER_VOLUME_CUBE_OBJ = \
example/modifier_volume_cube.elf: LDSCRIPT = $(LIB)/main.lds
example/modifier_volume_cube.elf: $(START_OBJ) $(MODIFIER_VOLUME_CUBE_OBJ)
DRAGON_OBJ = \
example/dragon.o \
holly/core.o \
holly/region_array.o \
holly/background.o \
holly/ta_fifo_polygon_converter.o \
holly/video_output.o \
sh7091/serial.o \
model/dragon/dragon.data.o \
model/dragon/dragon.data.pal.o \
model/dragon/chrome.data.o \
$(LIBGCC)
example/dragon.elf: LDSCRIPT = $(LIB)/main.lds
example/dragon.elf: $(START_OBJ) $(DRAGON_OBJ)

80
md2/gen.py Normal file
View File

@ -0,0 +1,80 @@
from generate import renderer
from parse import parse_md2file
import sys
def join(l):
return ", ".join(str(i) for i in l)
def gen_header(prefix, header):
yield f"struct md2_header {prefix}_header = {{"
yield f".skinwidth = {header.skinwidth},"
yield f".skinheight = {header.skinheight},"
yield f".num_vertices = {header.num_vertices},"
yield f".num_st = {header.num_st},"
yield f".num_tris = {header.num_tris},"
yield f".num_frames = {header.num_frames},"
yield f".st = {prefix}_st,"
yield f".tris = {prefix}_triangle,"
yield f".frames = {prefix}_frame,"
yield "};"
def gen_triangles(prefix, triangles):
yield f"struct md2_triangle {prefix}_triangle[] = {{"
for t in triangles:
yield "{"
yield f".vertex = {{{join(t.vertex)}}},"
yield f".st = {{{join(t.st)}}},"
yield "},"
yield "};"
def gen_frames(prefix, frames):
yield f"struct md2_frame {prefix}_frame[] = {{"
for i, f in enumerate(frames):
yield "{"
yield f".scale = {{{join(f.scale)}}},"
yield f".translate = {{{join(f.translate)}}},"
yield f'.name = "{f.name}",'
yield f".verts = {prefix}_verts_{i}"
yield "},"
yield "};"
def gen_frame_vertices(prefix, frames):
for i, f in enumerate(frames):
yield f"struct md2_vertex {prefix}_verts_{i}[] = {{"
for v in f.verts:
yield "{"
yield f".v = {{{join(v.v)}}},"
yield f".normal_index = {v.normal_index},"
yield "},"
yield "};"
def gen_texture_coordinates(prefix, texture_coordinates):
yield f"struct md2_texture_coordinate {prefix}_st[] = {{"
for st in texture_coordinates:
yield f"{{{st.s}, {st.t}}},"
yield "};"
def generate_all(prefix, md2file):
yield from gen_triangles(prefix, md2file.triangles)
yield from gen_frame_vertices(prefix, md2file.frames)
yield from gen_frames(prefix, md2file.frames)
yield from gen_texture_coordinates(prefix, md2file.texture_coordinates)
yield from gen_header(prefix, md2file.header)
with open(sys.argv[1], 'rb') as f:
buf = f.read()
prefix = sys.argv[2]
output_filename = sys.argv[3]
mem = memoryview(buf)
md2file = parse_md2file(mem)
render, out = renderer()
render(generate_all(prefix, md2file))
with open(output_filename, 'w') as f:
f.write(out.getvalue())

35
md2/generate.py Normal file
View File

@ -0,0 +1,35 @@
import io
def should_autonewline(line):
return (
"static_assert" not in line
and "extern" not in line
and (len(line.split()) < 2 or line.split()[1] != '=') # hacky; meh
)
def _render(out, lines):
indent = " "
level = 0
for l in lines:
if l and (l[0] == "}" or l[0] == ")"):
level -= 2
assert level >= 0, out.getvalue()
if len(l) == 0:
out.write("\n")
else:
out.write(indent * level + l + "\n")
if l and (l[-1] == "{" or l[-1] == "("):
level += 2
if level == 0 and l and l[-1] == ";":
if should_autonewline(l):
out.write("\n")
return out
def renderer():
out = io.StringIO()
def render(lines):
return _render(out, lines)
return render, out

40
md2/md2.h Normal file
View File

@ -0,0 +1,40 @@
struct md2_texture_coordinate
{
int16_t s;
int16_t t;
};
struct md2_triangle
{
uint16_t vertex[3];
uint16_t st[3];
};
struct md2_vertex
{
uint8_t v[3]; /* position */
uint8_t normal_index;
};
struct md2_frame
{
vec3 scale; /* scale factor */
vec3 translate; /* translation vector */
char name[16]; /* frame name */
struct md2_vertex * verts; /* list of frame's vertices */
};
struct md2_header
{
int skinwidth; /* texture width */
int skinheight; /* texture height */
int num_vertices; /* number of vertices per frame */
int num_st; /* number of texture coordinates */
int num_tris; /* number of triangles */
int num_frames; /* number of frames */
struct md2_texture_coordinate * st;
struct md2_triangle * tris;
struct md2_frame * frames;
};

166
md2/md2_normals.c Normal file
View File

@ -0,0 +1,166 @@
#include "md2_normals.h"
const vec3 md2_normals[] = {
{ -0.525731f, 0.000000f, 0.850651f },
{ -0.442863f, 0.238856f, 0.864188f },
{ -0.295242f, 0.000000f, 0.955423f },
{ -0.309017f, 0.500000f, 0.809017f },
{ -0.162460f, 0.262866f, 0.951056f },
{ 0.000000f, 0.000000f, 1.000000f },
{ 0.000000f, 0.850651f, 0.525731f },
{ -0.147621f, 0.716567f, 0.681718f },
{ 0.147621f, 0.716567f, 0.681718f },
{ 0.000000f, 0.525731f, 0.850651f },
{ 0.309017f, 0.500000f, 0.809017f },
{ 0.525731f, 0.000000f, 0.850651f },
{ 0.295242f, 0.000000f, 0.955423f },
{ 0.442863f, 0.238856f, 0.864188f },
{ 0.162460f, 0.262866f, 0.951056f },
{ -0.681718f, 0.147621f, 0.716567f },
{ -0.809017f, 0.309017f, 0.500000f },
{ -0.587785f, 0.425325f, 0.688191f },
{ -0.850651f, 0.525731f, 0.000000f },
{ -0.864188f, 0.442863f, 0.238856f },
{ -0.716567f, 0.681718f, 0.147621f },
{ -0.688191f, 0.587785f, 0.425325f },
{ -0.500000f, 0.809017f, 0.309017f },
{ -0.238856f, 0.864188f, 0.442863f },
{ -0.425325f, 0.688191f, 0.587785f },
{ -0.716567f, 0.681718f, -0.147621f },
{ -0.500000f, 0.809017f, -0.309017f },
{ -0.525731f, 0.850651f, 0.000000f },
{ 0.000000f, 0.850651f, -0.525731f },
{ -0.238856f, 0.864188f, -0.442863f },
{ 0.000000f, 0.955423f, -0.295242f },
{ -0.262866f, 0.951056f, -0.162460f },
{ 0.000000f, 1.000000f, 0.000000f },
{ 0.000000f, 0.955423f, 0.295242f },
{ -0.262866f, 0.951056f, 0.162460f },
{ 0.238856f, 0.864188f, 0.442863f },
{ 0.262866f, 0.951056f, 0.162460f },
{ 0.500000f, 0.809017f, 0.309017f },
{ 0.238856f, 0.864188f, -0.442863f },
{ 0.262866f, 0.951056f, -0.162460f },
{ 0.500000f, 0.809017f, -0.309017f },
{ 0.850651f, 0.525731f, 0.000000f },
{ 0.716567f, 0.681718f, 0.147621f },
{ 0.716567f, 0.681718f, -0.147621f },
{ 0.525731f, 0.850651f, 0.000000f },
{ 0.425325f, 0.688191f, 0.587785f },
{ 0.864188f, 0.442863f, 0.238856f },
{ 0.688191f, 0.587785f, 0.425325f },
{ 0.809017f, 0.309017f, 0.500000f },
{ 0.681718f, 0.147621f, 0.716567f },
{ 0.587785f, 0.425325f, 0.688191f },
{ 0.955423f, 0.295242f, 0.000000f },
{ 1.000000f, 0.000000f, 0.000000f },
{ 0.951056f, 0.162460f, 0.262866f },
{ 0.850651f, -0.525731f, 0.000000f },
{ 0.955423f, -0.295242f, 0.000000f },
{ 0.864188f, -0.442863f, 0.238856f },
{ 0.951056f, -0.162460f, 0.262866f },
{ 0.809017f, -0.309017f, 0.500000f },
{ 0.681718f, -0.147621f, 0.716567f },
{ 0.850651f, 0.000000f, 0.525731f },
{ 0.864188f, 0.442863f, -0.238856f },
{ 0.809017f, 0.309017f, -0.500000f },
{ 0.951056f, 0.162460f, -0.262866f },
{ 0.525731f, 0.000000f, -0.850651f },
{ 0.681718f, 0.147621f, -0.716567f },
{ 0.681718f, -0.147621f, -0.716567f },
{ 0.850651f, 0.000000f, -0.525731f },
{ 0.809017f, -0.309017f, -0.500000f },
{ 0.864188f, -0.442863f, -0.238856f },
{ 0.951056f, -0.162460f, -0.262866f },
{ 0.147621f, 0.716567f, -0.681718f },
{ 0.309017f, 0.500000f, -0.809017f },
{ 0.425325f, 0.688191f, -0.587785f },
{ 0.442863f, 0.238856f, -0.864188f },
{ 0.587785f, 0.425325f, -0.688191f },
{ 0.688191f, 0.587785f, -0.425325f },
{ -0.147621f, 0.716567f, -0.681718f },
{ -0.309017f, 0.500000f, -0.809017f },
{ 0.000000f, 0.525731f, -0.850651f },
{ -0.525731f, 0.000000f, -0.850651f },
{ -0.442863f, 0.238856f, -0.864188f },
{ -0.295242f, 0.000000f, -0.955423f },
{ -0.162460f, 0.262866f, -0.951056f },
{ 0.000000f, 0.000000f, -1.000000f },
{ 0.295242f, 0.000000f, -0.955423f },
{ 0.162460f, 0.262866f, -0.951056f },
{ -0.442863f, -0.238856f, -0.864188f },
{ -0.309017f, -0.500000f, -0.809017f },
{ -0.162460f, -0.262866f, -0.951056f },
{ 0.000000f, -0.850651f, -0.525731f },
{ -0.147621f, -0.716567f, -0.681718f },
{ 0.147621f, -0.716567f, -0.681718f },
{ 0.000000f, -0.525731f, -0.850651f },
{ 0.309017f, -0.500000f, -0.809017f },
{ 0.442863f, -0.238856f, -0.864188f },
{ 0.162460f, -0.262866f, -0.951056f },
{ 0.238856f, -0.864188f, -0.442863f },
{ 0.500000f, -0.809017f, -0.309017f },
{ 0.425325f, -0.688191f, -0.587785f },
{ 0.716567f, -0.681718f, -0.147621f },
{ 0.688191f, -0.587785f, -0.425325f },
{ 0.587785f, -0.425325f, -0.688191f },
{ 0.000000f, -0.955423f, -0.295242f },
{ 0.000000f, -1.000000f, 0.000000f },
{ 0.262866f, -0.951056f, -0.162460f },
{ 0.000000f, -0.850651f, 0.525731f },
{ 0.000000f, -0.955423f, 0.295242f },
{ 0.238856f, -0.864188f, 0.442863f },
{ 0.262866f, -0.951056f, 0.162460f },
{ 0.500000f, -0.809017f, 0.309017f },
{ 0.716567f, -0.681718f, 0.147621f },
{ 0.525731f, -0.850651f, 0.000000f },
{ -0.238856f, -0.864188f, -0.442863f },
{ -0.500000f, -0.809017f, -0.309017f },
{ -0.262866f, -0.951056f, -0.162460f },
{ -0.850651f, -0.525731f, 0.000000f },
{ -0.716567f, -0.681718f, -0.147621f },
{ -0.716567f, -0.681718f, 0.147621f },
{ -0.525731f, -0.850651f, 0.000000f },
{ -0.500000f, -0.809017f, 0.309017f },
{ -0.238856f, -0.864188f, 0.442863f },
{ -0.262866f, -0.951056f, 0.162460f },
{ -0.864188f, -0.442863f, 0.238856f },
{ -0.809017f, -0.309017f, 0.500000f },
{ -0.688191f, -0.587785f, 0.425325f },
{ -0.681718f, -0.147621f, 0.716567f },
{ -0.442863f, -0.238856f, 0.864188f },
{ -0.587785f, -0.425325f, 0.688191f },
{ -0.309017f, -0.500000f, 0.809017f },
{ -0.147621f, -0.716567f, 0.681718f },
{ -0.425325f, -0.688191f, 0.587785f },
{ -0.162460f, -0.262866f, 0.951056f },
{ 0.442863f, -0.238856f, 0.864188f },
{ 0.162460f, -0.262866f, 0.951056f },
{ 0.309017f, -0.500000f, 0.809017f },
{ 0.147621f, -0.716567f, 0.681718f },
{ 0.000000f, -0.525731f, 0.850651f },
{ 0.425325f, -0.688191f, 0.587785f },
{ 0.587785f, -0.425325f, 0.688191f },
{ 0.688191f, -0.587785f, 0.425325f },
{ -0.955423f, 0.295242f, 0.000000f },
{ -0.951056f, 0.162460f, 0.262866f },
{ -1.000000f, 0.000000f, 0.000000f },
{ -0.850651f, 0.000000f, 0.525731f },
{ -0.955423f, -0.295242f, 0.000000f },
{ -0.951056f, -0.162460f, 0.262866f },
{ -0.864188f, 0.442863f, -0.238856f },
{ -0.951056f, 0.162460f, -0.262866f },
{ -0.809017f, 0.309017f, -0.500000f },
{ -0.864188f, -0.442863f, -0.238856f },
{ -0.951056f, -0.162460f, -0.262866f },
{ -0.809017f, -0.309017f, -0.500000f },
{ -0.681718f, 0.147621f, -0.716567f },
{ -0.681718f, -0.147621f, -0.716567f },
{ -0.850651f, 0.000000f, -0.525731f },
{ -0.688191f, 0.587785f, -0.425325f },
{ -0.587785f, 0.425325f, -0.688191f },
{ -0.425325f, 0.688191f, -0.587785f },
{ -0.425325f, -0.688191f, -0.587785f },
{ -0.587785f, -0.425325f, -0.688191f },
{ -0.688191f, -0.587785f, -0.425325f }
};

1
md2/md2_normals.h Normal file
View File

@ -0,0 +1 @@
extern const vec3 md2_normals[];

150
md2/parse.py Normal file
View File

@ -0,0 +1,150 @@
import struct
from dataclasses import dataclass
from functools import partial
@dataclass
class MD2Header:
ident: int # magic number: "IDP2"
version: int # version: must be 8
skinwidth: int # texture width
skinheight: int # texture height
framesize: int # size in bytes of a frame
num_skins: int # number of skins
num_vertices: int # number of vertices per frame
num_st: int # number of texture coordinates
num_tris: int # number of triangles
num_glcmds: int # number of opengl commands
num_frames: int # number of frames
offset_skins: int # offset skin data
offset_st: int # offset texture coordinate data
offset_tris: int # offset triangle data
offset_frames: int # offset frame data
offset_glcmds: int # offset OpenGL command data
offset_end: int # offset end of file
@dataclass
class MD2Triangle:
vertex: tuple[int, int, int] # vertex indices of the triangle
st: tuple[int, int, int] # texture coordinate indices
@dataclass
class MD2Vertex:
v: tuple[int, int, int] # position
normal_index: int # normal vector index
@dataclass
class MD2Frame:
scale: tuple[float, float, float]
translate: tuple[float, float, float]
name: str
verts: list[MD2Vertex]
@dataclass
class MD2TextureCoordinate:
s: int
t: int
@dataclass
class MD2File:
header: MD2Header
triangles: list[MD2Triangle]
frames: list[MD2Frame]
texture_coordinates: list[MD2TextureCoordinate]
def parse_header(mem, offset):
size = 17*4
fields = struct.unpack("<" + "i" * 17, mem[offset:offset+size])
header = MD2Header(*fields)
assert header.ident == 0x32504449, header.ident # IDP2
assert header.version == 8, header.version
return offset+size, header
def parse_triangle(mem, offset):
size = 6*2
fields = struct.unpack("<" + "H" * 6, mem[offset:offset+size])
(v1, v2, v3, st1, st2, st3) = fields
return offset+size, MD2Triangle(
(v1, v2, v3),
(st1, st2, st3),
)
def parse_vertex(mem, offset):
size = 4*1
fields = struct.unpack("<" + "B" * 4, mem[offset:offset+size])
v1, v2, v3, normal_index = fields
return offset+size, MD2Vertex(
(v1, v2, v3),
normal_index
)
def parse_multiple(mem, offset, count, parse):
items = []
for i in range(count):
offset, item = parse(mem, offset)
items.append(item)
return offset, items
parse_triangles = partial(parse_multiple, parse=parse_triangle)
parse_vertices = partial(parse_multiple, parse=parse_vertex)
def parse_cstring(l):
cs = []
for b in l:
if b == b'\x00':
break
cs.append(b)
return b"".join(cs)
def parse_frame(mem, offset, num_vertices):
vec_size = 4 * 3
scale = struct.unpack("<fff", mem[offset:offset+vec_size])
offset += vec_size
translate = struct.unpack("<fff", mem[offset:offset+vec_size])
offset += vec_size
name = struct.unpack("<" + "c" * 16, mem[offset:offset+16])
offset += 16
offset, vertices = parse_vertices(mem, offset, num_vertices)
return offset, MD2Frame(
scale,
translate,
parse_cstring(name),
vertices
)
def parse_frames(mem, header):
offset = header.offset_frames
frames = []
for i in range(header.num_frames):
end_of_frame, frame = parse_frame(mem, offset, header.num_vertices)
offset += header.framesize
assert offset == end_of_frame, (offset, end_of_frame)
frames.append(frame)
return offset, frames
def parse_texture_coordinate(mem, offset):
size = 2 * 2
s, t = struct.unpack("<" + "h" * 2, mem[offset:offset+size])
offset += size
return offset, MD2TextureCoordinate(s, t)
parse_texture_coordinates = partial(parse_multiple, parse=parse_texture_coordinate)
def parse_md2file(mem):
_, header = parse_header(mem, 0)
_, triangles = parse_triangles(mem,
header.offset_tris,
header.num_tris)
_, frames = parse_frames(mem, header)
_, texture_coordinates = parse_texture_coordinates(mem,
header.offset_st,
header.num_st)
return MD2File(
header,
triangles,
frames,
texture_coordinates
)

BIN
model/dragon/chrome.data Normal file

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_dragon_chrome_data_start __asm("_binary_model_dragon_chrome_data_start");
extern uint32_t _binary_model_dragon_chrome_data_end __asm("_binary_model_dragon_chrome_data_end");
extern uint32_t _binary_model_dragon_chrome_data_size __asm("_binary_model_dragon_chrome_data_size");
#ifdef __cplusplus
}
#endif

BIN
model/dragon/chrome.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

12
model/dragon/cube.mtl Normal file
View File

@ -0,0 +1,12 @@
# Blender 4.2.1 LTS MTL File: 'None'
# www.blender.org
newmtl Material
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
map_Kd chrome.png

30
model/dragon/cube.obj Normal file
View File

@ -0,0 +1,30 @@
# Blender 4.2.1 LTS
# www.blender.org
mtllib cube.mtl
o Cube
v 1.000000 2.000000 -1.000000
v 1.000000 0.000000 -1.000000
v 1.000000 2.000000 1.000000
v 1.000000 0.000000 1.000000
v -1.000000 2.000000 -1.000000
v -1.000000 0.000000 -1.000000
v -1.000000 2.000000 1.000000
v -1.000000 0.000000 1.000000
vn -0.0000 -1.0000 -0.0000
vn -0.0000 -0.0000 -1.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 1.000000 1.000000
vt 0.000000 1.000000
s 0
usemtl Material
f 1/1/1 3/2/1 7/3/1 5/4/1
f 4/1/2 8/2/2 7/3/2 3/4/2
f 8/1/3 6/2/3 5/3/3 7/4/3
f 6/1/4 8/2/4 4/3/4 2/4/4
f 2/1/5 4/2/5 3/3/5 1/4/5
f 6/1/6 2/2/6 1/3/6 5/4/6

BIN
model/dragon/dragon.data Normal file

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_dragon_dragon_data_start __asm("_binary_model_dragon_dragon_data_start");
extern uint32_t _binary_model_dragon_dragon_data_end __asm("_binary_model_dragon_dragon_data_end");
extern uint32_t _binary_model_dragon_dragon_data_size __asm("_binary_model_dragon_dragon_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_dragon_dragon_data_pal_start __asm("_binary_model_dragon_dragon_data_pal_start");
extern uint32_t _binary_model_dragon_dragon_data_pal_end __asm("_binary_model_dragon_dragon_data_pal_end");
extern uint32_t _binary_model_dragon_dragon_data_pal_size __asm("_binary_model_dragon_dragon_data_pal_size");
#ifdef __cplusplus
}
#endif

BIN
model/dragon/dragon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -0,0 +1,95 @@
#pragma once
#include <stddef.h>
#include "../model.h"
// floating-point
const vertex_position inverse_cube_position[] = {
{1.0, 2.0, -1.0},
{1.0, 0.0, -1.0},
{1.0, 2.0, 1.0},
{1.0, 0.0, 1.0},
{-1.0, 2.0, -1.0},
{-1.0, 0.0, -1.0},
{-1.0, 2.0, 1.0},
{-1.0, 0.0, 1.0},
};
// floating-point
const vertex_texture inverse_cube_texture[] = {
{0.0, 0.0},
{1.0, 0.0},
{1.0, 1.0},
{0.0, 1.0},
};
// floating-point
const vertex_normal inverse_cube_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 quadrilateral inverse_cube_Cube_quadrilateral[] = {
{ .v = {
{0, 0, 0},
{2, 1, 0},
{6, 2, 0},
{4, 3, 0},
}},
{ .v = {
{3, 0, 1},
{7, 1, 1},
{6, 2, 1},
{2, 3, 1},
}},
{ .v = {
{7, 0, 2},
{5, 1, 2},
{4, 2, 2},
{6, 3, 2},
}},
{ .v = {
{5, 0, 3},
{7, 1, 3},
{3, 2, 3},
{1, 3, 3},
}},
{ .v = {
{1, 0, 4},
{3, 1, 4},
{2, 2, 4},
{0, 3, 4},
}},
{ .v = {
{5, 0, 5},
{1, 1, 5},
{0, 2, 5},
{4, 3, 5},
}},
};
const struct object inverse_cube_Cube = {
.triangle = NULL,
.quadrilateral = &inverse_cube_Cube_quadrilateral[0],
.triangle_count = 0,
.quadrilateral_count = 6,
.material = -1,
};
const struct object * inverse_cube_object_list[] = {
&inverse_cube_Cube,
};
const struct model inverse_cube_model = {
.position = &inverse_cube_position[0],
.texture = &inverse_cube_texture[0],
.normal = &inverse_cube_normal[0],
.object = &inverse_cube_object_list[0],
.object_count = 1,
};

239611
model/dragon/model.c Normal file

File diff suppressed because it is too large Load Diff