examples: add ulala

This commit is contained in:
Zack Buhman 2024-09-11 06:20:44 -05:00
parent e13e4ba987
commit 0fe7105d44
67 changed files with 18336 additions and 1362 deletions

View File

@ -22,6 +22,7 @@ texture.elf: $(DEFAULT) arm9/texture.bin.o
cube.elf: $(DEFAULT) arm9/cube.bin.o
icosphere.elf: $(DEFAULT) arm9/icosphere.bin.o
majora.elf: $(DEFAULT) arm9/majora.bin.o
ulala.elf: $(DEFAULT) arm9/ulala.bin.o
TARGET = arm-none-eabi-
AARCH = -march=armv4t -mlittle-endian
@ -29,4 +30,10 @@ OBJARCH = -O elf32-littlearm -B armv4t
LDSCRIPT = cartridge.lds
include common.mk
%.data.h: %.data
$(BUILD_BINARY_H)
%.data.pal.h: %.data.pal
$(BUILD_BINARY_H)
.PHONY: phony registers

View File

@ -41,11 +41,29 @@ MAJORA_RES = \
../texture/060077E0.data.o \
../texture/06007BE0.data.o \
../texture/06007FE0.data.o
examples/majora.c: $(patsubst %.o,%.h,$(MAJORA_RES))
majora.elf: start.o examples/majora.o ../math/cos_table_fp12.o ../math/cos.o $(MAJORA_RES)
ULALA_RES = \
../model/ulala/eye.data.o \
../model/ulala/ha.data.o \
../model/ulala/p03b_hair.data.o \
../model/ulala/p_face.data.o \
../model/ulala/p_nomal_mix.data.o \
../model/ulala/p_ref_or.data.o \
../model/ulala/u_lb.data.o \
../model/ulala/eye.data.pal.o \
../model/ulala/ha.data.pal.o \
../model/ulala/p03b_hair.data.pal.o \
../model/ulala/p_face.data.pal.o \
../model/ulala/p_nomal_mix.data.pal.o \
../model/ulala/p_ref_or.data.pal.o \
../model/ulala/u_lb.data.pal.o
examples/ulala.c: $(patsubst %.o,%.h,$(ULALA_RES))
ulala.elf: start.o examples/ulala.o ../math/cos_table_fp12.o ../math/cos.o $(ULALA_RES)
CFLAGS += -I../include -I../
include arm9.mk

473
arm9/examples/ulala.c Normal file
View File

@ -0,0 +1,473 @@
#include "io_registers.h"
#include "bits.h"
#include "math/math.h"
#include "model/ulala/eye.data.h"
#include "model/ulala/ha.data.h"
#include "model/ulala/p03b_hair.data.h"
#include "model/ulala/p_face.data.h"
#include "model/ulala/p_nomal_mix.data.h"
#include "model/ulala/p_ref_or.data.h"
#include "model/ulala/u_lb.data.h"
#include "model/ulala/eye.data.pal.h"
#include "model/ulala/ha.data.pal.h"
#include "model/ulala/p03b_hair.data.pal.h"
#include "model/ulala/p_face.data.pal.h"
#include "model/ulala/p_nomal_mix.data.pal.h"
#include "model/ulala/p_ref_or.data.pal.h"
#include "model/ulala/u_lb.data.pal.h"
#include "model/ulala/material.h"
#include "model/ulala/model.h"
void copy_palettes()
{
volatile uint16_t * vram_f = (volatile uint16_t *)(0x06890000);
int palettes = (sizeof (material)) / (sizeof (material[0]));
for (int i = 0; i < palettes; i++) {
int colors = material[i].palette.size / 2;
uint16_t * pal = (uint16_t *)material[i].palette.start;
int offset = material[i].palette.vram_offset;
for (int c = 0; c < colors; c++) {
vram_f[c + offset / 2] = pal[c];
}
}
}
uint32_t teximage_param__t_size(int height)
{
switch (height) {
default:
case 8: return TEXIMAGE_PARAM__t_size__8_texels;
case 16: return TEXIMAGE_PARAM__t_size__16_texels;
case 32: return TEXIMAGE_PARAM__t_size__32_texels;
case 64: return TEXIMAGE_PARAM__t_size__64_texels;
case 128: return TEXIMAGE_PARAM__t_size__128_texels;
case 256: return TEXIMAGE_PARAM__t_size__256_texels;
case 512: return TEXIMAGE_PARAM__t_size__512_texels;
case 1024: return TEXIMAGE_PARAM__t_size__1024_texels;
}
}
uint32_t teximage_param__s_size(int width)
{
switch (width) {
default:
case 8: return TEXIMAGE_PARAM__s_size__8_texels;
case 16: return TEXIMAGE_PARAM__s_size__16_texels;
case 32: return TEXIMAGE_PARAM__s_size__32_texels;
case 64: return TEXIMAGE_PARAM__s_size__64_texels;
case 128: return TEXIMAGE_PARAM__s_size__128_texels;
case 256: return TEXIMAGE_PARAM__s_size__256_texels;
case 512: return TEXIMAGE_PARAM__s_size__512_texels;
case 1024: return TEXIMAGE_PARAM__s_size__1024_texels;
}
}
uint32_t teximage_param__color_palette(int palette_size)
{
switch (palette_size) {
default:
case 4: return TEXIMAGE_PARAM__texture_format__4_color_palette;
case 16: return TEXIMAGE_PARAM__texture_format__16_color_palette;
case 256: return TEXIMAGE_PARAM__texture_format__256_color_palette;
}
}
void copy_pixels()
{
volatile uint16_t * vram_a = (volatile uint16_t *)(0x06800000);
int pixels = (sizeof (material)) / (sizeof (material[0]));
for (int i = 0; i < pixels; i++) {
int size = material[i].pixel.size;
uint16_t * pixel = (uint16_t *)material[i].pixel.start;
int offset = material[i].pixel.vram_offset;
for (int t = 0; t < size / 2; t++) {
vram_a[offset / 2 + t] = pixel[t];
}
}
}
int u_to_s(int n, int dimension)
{
return (n * dimension) >> 10;
}
int v_to_t(int n, int dimension)
{
return ((((1 << 15) - n) * dimension) >> 10);
}
void copy_texture_data()
{
// memory bank allocation
// use VRAM-A for texture pixel data
// use VRAM-E for texture palette data
// temporarily map VRAM-A (128KB) to the arm9 address space:
// 0x06800000 - 0x0681FFFF
io_registers.a.VRAMCNT = 0
| VRAMCNT__vram_a__enable
| VRAMCNT__vram_a__mst(0b00); // arm9
// temporarily map VRAM-F (16KB) to the arm9 address space:
// 0x06890000 - 0x06893FFF
io_registers.a.WVRAMCNT = 0
| WVRAMCNT__vram_f__enable
| WVRAMCNT__vram_f__mst(0b000); // arm9
// at this point, VRAM-A/VRAM-E are not accessible by the 3d engine.
copy_palettes();
copy_pixels();
// map VRAM-A (128KB) to the 3d-engine "texture image slot 0":
// 0x00000 - 0x1ffff (3d engine texture image address space)
io_registers.a.VRAMCNT = 0
| VRAMCNT__vram_a__enable
| VRAMCNT__vram_a__ofs(0) // slot 0
| VRAMCNT__vram_a__mst(0b11); // texture image
// map VRAM-F (16KB) to the 3d-engine "texture palette slot 0":
// 0x0000 - 0x3fff (3d engine texture palette address space)
io_registers.a.WVRAMCNT = 0
| WVRAMCNT__vram_f__enable
| WVRAMCNT__vram_f__ofs(0) // slot 0
| WVRAMCNT__vram_f__mst(0b011); // texture palette
}
void main()
{
// power control
io_registers.a.POWCNT = 0
| POWCNT__lcd_output_destination__a_to_upper__b_to_lower
| POWCNT__geometry_engine__enable
| POWCNT__rendering_engine__enable
| POWCNT__lcd__enable;
// enable bg0 and 3d graphics
io_registers.a.DISPCNT = 0
| DISPCNT__display_mode__graphics_display
| DISPCNT__bg0__enable
| DISPCNT__display_selection_for_bg0__3d_graphics
;
// disable all 3d effects
io_registers.a.DISP3DCNT = 0
| DISP3DCNT__clear_image__disable
| DISP3DCNT__fog_master__disable
| DISP3DCNT__edge_marking__disable
| DISP3DCNT__anti_aliasing__disable
| DISP3DCNT__alpha_blending__disable
| DISP3DCNT__alpha_test__disable
| DISP3DCNT__texture_mapping__enable;
copy_texture_data();
// clear matrix stack status
io_registers.a.GXSTAT |= GXSTAT__matrix_stack_status__overflow_or_underflow;
// load identity matrices
io_registers.a.MTX_MODE = MTX_MODE__matrix_mode__projection;
io_registers.a.MTX_IDENTITY = 0;
// load a symmetric perspective matrix, with aspect ratio correction
io_registers.a.MTX_LOAD_4X4 = (192 << 12) / 256;
io_registers.a.MTX_LOAD_4X4 = 0;
io_registers.a.MTX_LOAD_4X4 = 0;
io_registers.a.MTX_LOAD_4X4 = 0;
io_registers.a.MTX_LOAD_4X4 = 0;
io_registers.a.MTX_LOAD_4X4 = 1 << 12;
io_registers.a.MTX_LOAD_4X4 = 0;
io_registers.a.MTX_LOAD_4X4 = 0;
io_registers.a.MTX_LOAD_4X4 = 0;
io_registers.a.MTX_LOAD_4X4 = 0;
io_registers.a.MTX_LOAD_4X4 = 0;
io_registers.a.MTX_LOAD_4X4 = -(1 << 12);
io_registers.a.MTX_LOAD_4X4 = 0;
io_registers.a.MTX_LOAD_4X4 = 0;
io_registers.a.MTX_LOAD_4X4 = -(1 << 12) >> 4;
io_registers.a.MTX_LOAD_4X4 = 0;
// translate the viewpoint
io_registers.a.MTX_TRANS = 0;
io_registers.a.MTX_TRANS = (int)(1.0 * (float)(1 << 11));
io_registers.a.MTX_TRANS = (int)(-1.0 * (float)(1 << 11));
io_registers.a.MTX_MODE = MTX_MODE__matrix_mode__position;
io_registers.a.MTX_IDENTITY = 0;
io_registers.a.MTX_MODE = MTX_MODE__matrix_mode__position_and_vector;
io_registers.a.MTX_IDENTITY = 0;
io_registers.a.MTX_MODE = MTX_MODE__matrix_mode__texture;
io_registers.a.MTX_IDENTITY = 0;
io_registers.a.MTX_MODE = MTX_MODE__matrix_mode__position_and_vector;
// set the 3d clear color to a dark red
io_registers.a.CLEAR_COLOR = 0
| CLEAR_COLOR__clear_polygon_id(31)
| CLEAR_COLOR__alpha_value(31)
| CLEAR_COLOR__blue(1)
| CLEAR_COLOR__green(1)
| CLEAR_COLOR__red(10);
// set the depth buffer clear value to the maximum value
io_registers.a.CLEAR_DEPTH = CLEAR_DEPTH__value(0x7fff);
// the 3d viewport is the entire display area
io_registers.a.VIEWPORT = 0
| VIEWPORT__y2(191)
| VIEWPORT__x2(255)
| VIEWPORT__y1(0)
| VIEWPORT__x1(0);
// normalized 45° vector
int c = 0.57735 * 512;
// lighting vectors and colors for 3 directional lights
io_registers.a.LIGHT_VECTOR = 0
| LIGHT_VECTOR__light_number(0)
| LIGHT_VECTOR__decimal_z(-c)
| LIGHT_VECTOR__decimal_y(-c)
| LIGHT_VECTOR__decimal_x(-c);
io_registers.a.LIGHT_VECTOR = 0
| LIGHT_VECTOR__light_number(1)
| LIGHT_VECTOR__decimal_z(-c)
| LIGHT_VECTOR__decimal_y(-c)
| LIGHT_VECTOR__decimal_x(c);
io_registers.a.LIGHT_VECTOR = 0
| LIGHT_VECTOR__light_number(2)
| LIGHT_VECTOR__decimal_z(-c)
| LIGHT_VECTOR__decimal_y(c)
| LIGHT_VECTOR__decimal_x(-c);
io_registers.a.LIGHT_COLOR = 0
| LIGHT_COLOR__light_number(0)
| LIGHT_COLOR__blue(31)
| LIGHT_COLOR__green(31)
| LIGHT_COLOR__red(31);
io_registers.a.LIGHT_COLOR = 0
| LIGHT_COLOR__light_number(1)
| LIGHT_COLOR__blue(31)
| LIGHT_COLOR__green(31)
| LIGHT_COLOR__red(31);
io_registers.a.LIGHT_COLOR = 0
| LIGHT_COLOR__light_number(2)
| LIGHT_COLOR__blue(31)
| LIGHT_COLOR__green(31)
| LIGHT_COLOR__red(31);
// integer degrees
int theta = 0;
while (1) {
// calculate sin/cos for 2d rotation; signed fp20.12 result
int cos = cos_fp12(theta);
int sin = sin_fp12(theta);
int cos2 = cos_fp12(-theta >> 1);
int sin2 = sin_fp12(-theta >> 1);
io_registers.a.MTX_MODE = MTX_MODE__matrix_mode__position_and_vector;
// reset position matrix
io_registers.a.MTX_IDENTITY = 0;
io_registers.a.MTX_TRANS = 0;
io_registers.a.MTX_TRANS = (int)(-0.7 * (float)(1 << 12));
io_registers.a.MTX_TRANS = (int)(-0.1 * (float)(1 << 12));
// multiply by a y-axis rotation
io_registers.a.MTX_MULT_3X3 = cos2;
io_registers.a.MTX_MULT_3X3 = 0;
io_registers.a.MTX_MULT_3X3 = sin2;
io_registers.a.MTX_MULT_3X3 = 0;
io_registers.a.MTX_MULT_3X3 = 1 << 12;
io_registers.a.MTX_MULT_3X3 = 0;
io_registers.a.MTX_MULT_3X3 = -sin2;
io_registers.a.MTX_MULT_3X3 = 0;
io_registers.a.MTX_MULT_3X3 = cos2;
/*
// multiply by a z-axis rotation
io_registers.a.MTX_MULT_3X3 = cos;
io_registers.a.MTX_MULT_3X3 = -sin;
io_registers.a.MTX_MULT_3X3 = 0;
io_registers.a.MTX_MULT_3X3 = sin;
io_registers.a.MTX_MULT_3X3 = cos;
io_registers.a.MTX_MULT_3X3 = 0;
io_registers.a.MTX_MULT_3X3 = 0;
io_registers.a.MTX_MULT_3X3 = 0;
io_registers.a.MTX_MULT_3X3 = 1 << 12;
*/
// multiply by a x-axis rotation
/*
io_registers.a.MTX_MULT_3X3 = 1 << 12;
io_registers.a.MTX_MULT_3X3 = 0;
io_registers.a.MTX_MULT_3X3 = 0;
io_registers.a.MTX_MULT_3X3 = 0;
io_registers.a.MTX_MULT_3X3 = cos2;
io_registers.a.MTX_MULT_3X3 = -sin2;
io_registers.a.MTX_MULT_3X3 = 0;
io_registers.a.MTX_MULT_3X3 = sin2;
io_registers.a.MTX_MULT_3X3 = cos2;
*/
// lighting parameters
io_registers.a.DIF_AMB = 0
| DIF_AMB__ambient_blue(3)
| DIF_AMB__ambient_green(3)
| DIF_AMB__ambient_red(3)
| DIF_AMB__diffuse_blue(10)
| DIF_AMB__diffuse_green(10)
| DIF_AMB__diffuse_red(10);
io_registers.a.SPE_EMI = 0
| SPE_EMI__specular_blue(25)
| SPE_EMI__specular_green(25)
| SPE_EMI__specular_red(25);
io_registers.a.COLOR = 0
| COLOR__blue(31)
| COLOR__green(31)
| COLOR__red(31)
;
// the following polygons are fully opaque; backface culling is
// enabled
io_registers.a.POLYGON_ATTR = 0
| POLYGON_ATTR__polygon_id(0)
| POLYGON_ATTR__alpha_value(31)
| POLYGON_ATTR__render_front_surface__enable
| POLYGON_ATTR__render_back_surface__enable
| POLYGON_ATTR__polygon_mode__modulation
| POLYGON_ATTR__light_2__enable
| POLYGON_ATTR__light_1__enable
| POLYGON_ATTR__light_0__enable;
// the following vertices are triangles
io_registers.a.BEGIN_VTXS = BEGIN_VTXS__type__triangle;
struct model * model = &ulala_model;
for (int object_ix = 0; object_ix < model->object_count; object_ix++) {
struct object * obj = model->object[object_ix];
const int num_triangles = obj->triangle_count;
int material_ix = obj->material;
int pixel_offset = material[material_ix].pixel.vram_offset;
int palette_offset = material[material_ix].palette.vram_offset;
int width = material[material_ix].pixel.width;
int height = material[material_ix].pixel.height;
int palette_size = material[material_ix].palette.palette_size;
int shift = palette_size == 4 ? 3 : 4;
io_registers.a.TEXPLTT_BASE = TEXPLTT_BASE__base_address(palette_offset >> shift);
io_registers.a.TEXIMAGE_PARAM = 0
| TEXIMAGE_PARAM__texture_coordinate_transformation_mode__texcoord_source
| teximage_param__color_palette(palette_size)
| TEXIMAGE_PARAM__repeat_t__repeat
| TEXIMAGE_PARAM__repeat_s__repeat
| teximage_param__t_size(height)
| teximage_param__s_size(width)
| TEXIMAGE_PARAM__texture_starting_address(pixel_offset >> 3)
;
for (int i = 0; i < num_triangles; i++) {
// "When texture mapping, the Geometry Engine works faster if you
// issue commands in the following order: TexCoord→Normal→Vertex."
struct vertex_texture * at = &model->texture[obj->triangle[i].a.texture];
io_registers.a.TEXCOORD = 0
| TEXCOORD__t_coordinate(v_to_t(at->v, height))
| TEXCOORD__s_coordinate(u_to_s(at->u, width));
struct vertex_normal * an = &model->normal[obj->triangle[i].a.normal];
io_registers.a.NORMAL = 0
| NORMAL__z_component(an->z)
| NORMAL__y_component(an->y)
| NORMAL__x_component(an->x);
struct vertex_position * a = &model->position[obj->triangle[i].a.position];
io_registers.a.VTX_10 = 0
| VTX_10__z_coordinate(a->z)
| VTX_10__y_coordinate(a->y)
| VTX_10__x_coordinate(a->x);
struct vertex_texture * bt = &model->texture[obj->triangle[i].b.texture];
io_registers.a.TEXCOORD = 0
| TEXCOORD__t_coordinate(v_to_t(bt->v, height))
| TEXCOORD__s_coordinate(u_to_s(bt->u, width));
struct vertex_normal * bn = &model->normal[obj->triangle[i].b.normal];
io_registers.a.NORMAL = 0
| NORMAL__z_component(bn->z)
| NORMAL__y_component(bn->y)
| NORMAL__x_component(bn->x);
struct vertex_position * b = &model->position[obj->triangle[i].b.position];
io_registers.a.VTX_10 = 0
| VTX_10__z_coordinate(b->z)
| VTX_10__y_coordinate(b->y)
| VTX_10__x_coordinate(b->x);
struct vertex_texture * ct = &model->texture[obj->triangle[i].c.texture];
io_registers.a.TEXCOORD = 0
| TEXCOORD__t_coordinate(v_to_t(ct->v, height))
| TEXCOORD__s_coordinate(u_to_s(ct->u, width));
struct vertex_normal * cn = &model->normal[obj->triangle[i].c.normal];
io_registers.a.NORMAL = 0
| NORMAL__z_component(cn->z)
| NORMAL__y_component(cn->y)
| NORMAL__x_component(cn->x);
struct vertex_position * c = &model->position[obj->triangle[i].c.position];
io_registers.a.VTX_10 = 0
| VTX_10__z_coordinate(c->z)
| VTX_10__y_coordinate(c->y)
| VTX_10__x_coordinate(c->x);
}
}
// end of triangles
io_registers.a.END_VTXS = 0;
// wait for the geometry engine
while (io_registers.a.GXSTAT & GXSTAT__geometry_engine_busy);
// wait for the end of the current frame
while (io_registers.a.VCOUNT != 262);
while (io_registers.a.VCOUNT == 262);
// swap buffers
io_registers.a.SWAP_BUFFERS = 0;
// increment theta once per frame
theta += 1;
if (theta >= 360 * 16) {
theta = 0;
}
}
}

View File

@ -0,0 +1,78 @@
import struct
import sys
from PIL import Image
def round_up_palette_size(palette_size):
assert palette_size != 0, (name, palette_size)
if palette_size <= 4:
return 4
elif palette_size <= 16:
return 16
elif palette_size <= 256:
return 256
else:
assert False, palette_size
def pixels_per_byte(palette_size):
if palette_size == 4:
return 4
elif palette_size == 16:
return 2
elif palette_size == 256:
return 1
else:
assert False, palette_size
def pack_one_byte(pixels, index, colors, palette_size):
color_count = len(colors)
num = pixels_per_byte(palette_size)
shift = 8 // num
byte = 0
i = 0
while num > 0:
px, alpha = pixels[index]
if alpha == 0 and color_count < palette_size:
px = color_count
assert px < palette_size
byte |= px << (shift * i)
index += 1
i += 1
num -= 1
return [byte], index
def pack_one_texel(pixels, index, colors, palette_size):
px, alpha = pixels[index]
return
def pack_pixels(pixels, width, height, colors, palette_size):
index = 0
with open(sys.argv[2], 'wb') as f:
while index < (width * height):
byte_list, index = pack_texel(pixels, index, colors, palette_size)
f.write(bytes(byte))
def pack_palette(colors, palette_size):
with open(sys.argv[2], 'wb') as f:
for color in colors:
out = argb1555(255, *color)
f.write(struct.pack('<H', out))
if len(colors) < palette_size:
# transparent color
print('pack transparency at ix', len(colors))
out = argb1555(0, 0, 0, 0)
f.write(struct.pack('<H', out))
with Image.open(sys.argv[1]) as im:
assert im.mode == "P"
width, height = im.size
colors = list(im.palette.colors)
pixels = list(im.convert("PA").getdata())
palette_size = round_up_palette_size(len(colors))
if sys.argv[2].endswith('.data'):
pack_pixels(pixels, width, height, len(colors), palette_size)
elif sys.argv[2].endswith('.pal'):
pack_palette(colors, palette_size)
else:
assert False, sys.argv[2]

72
gen/color_convert.py Normal file
View File

@ -0,0 +1,72 @@
import struct
import sys
from PIL import Image
class color_format:
def gbgr1555(r, g, b, a): # nintendo ds
r5 = (r >> 3) & 31
g6 = (g >> 3) & 31
g6_l = (g >> 2) & 1
b5 = (b >> 3) & 31
return (g6_l << 15) | (b5 << 10) | (g6 << 5) | (r5 << 0)
def argb4444(r, g, b, a):
a4 = (a >> 4) & 15
r4 = (r >> 4) & 15
g4 = (g >> 4) & 15
b4 = (b >> 4) & 15
return (a4 << 12) | (r4 << 8) | (g4 << 4) | (b4 << 0)
def argb1555(r, g, b, a):
a1 = (a >> 7) & 1
r5 = (r >> 3) & 31
g5 = (g >> 3) & 31
b5 = (b >> 3) & 31
return (a1 << 15) | (r5 << 10) | (g5 << 5) | (b5 << 0)
def rgb565(r, g, b, a):
r5 = (r >> 3) & 31
g6 = (g >> 2) & 63
b5 = (b >> 3) & 31
return (r5 << 11) | (g5 << 5) | (b5 << 0)
def from_string(s):
return dict([
("gbgr1555", color_format.gbgr1555),
("argb4444", color_format.argb4444),
("argb1555", color_format.argb1555),
("rgb565", color_format.rgb565),
])[s]
in_file = sys.argv[1]
format = sys.argv[2]
out_file = sys.argv[3]
palette = None
with Image.open(in_file) as im:
width, height = im.size
if not im.palette:
pixels = list(im.convert("RGBA").getdata())
else:
pixels = list(im.convert("P").getdata())
palette = list(im.palette.colors)
has_alpha = False
convert = color_format.from_string(format)
def convert_colors(f, colors):
for color in colors:
value = convert(*color)
f.write(struct.pack("<H", value))
if palette is None:
with open(out_file, 'wb') as f:
convert_colors(f, pixels)
else:
with open(out_file, 'wb') as f:
for pixel in pixels:
f.write(struct.pack("<B", pixel))
with open(out_file + '.pal', 'wb') as f:
convert_colors(f, [(*c, 255) for c in palette])

64
gen/fixed_point.py Normal file
View File

@ -0,0 +1,64 @@
from dataclasses import dataclass
import string
class FixedPointOverflow(Exception):
pass
@dataclass
class FixedPoint:
sign: int
value: int
point: int
def to_fixed_point(fp, integer_bits, fraction_bits):
point = 1 << fraction_bits
value = (fp.value * point) // fp.point
if integer_bits is not None:
integer_point = 1 << integer_bits
integer = value // point
if integer >= integer_point:
raise FixedPointOverflow((integer, integer_point))
return FixedPoint(
fp.sign,
value,
point
)
def to_int(fp):
return fp.sign * fp.value
def to_float(fp):
return fp.sign * fp.value / fp.point
def parse(s):
sign = -1 if s.startswith('-') else 1
s = s.removeprefix('-')
integer, fraction = s.split('.')
assert all(c in string.digits for c in integer), integer
assert all(c in string.digits for c in fraction), fraction
assert len(integer) > 0 and len(fraction) > 0, s
point = 10 ** len(fraction)
value = int(integer) * point + int(fraction)
return FixedPoint(
sign,
value,
point
)
def equal(a, b):
epsilon = 0.00001
return (a - b) < epsilon
def assert_raises(e, f):
try:
f()
except e:
return
raise AssertionError(f"expected {str(e)}")
assert parse("1.234").value == 1234
assert equal(parse("1.234").to_float(), 1.234)
assert parse("1.234").to_fixed_point(16, 16).value == 80871
assert_raises(FixedPointOverflow,
lambda: parse("2.234").to_fixed_point(1, 16))
assert parse("2.234").to_fixed_point(2, 16).value == 146407

35
gen/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

47
gen/parse_material.py Normal file
View File

@ -0,0 +1,47 @@
from dataclasses import dataclass
@dataclass
class NewMtl:
name: str
@dataclass
class MapKd:
name: str
def parse_material_newmtl(args):
name, = args.split()
yield NewMtl(name.replace('-', '_').replace('.', '_'))
def parse_material_mapkd(args):
name, = args.split()
yield MapKd(name)
def parse_mtl_line(line):
prefixes = [
('newmtl ', parse_material_newmtl),
('map_Kd ', parse_material_mapkd),
]
for prefix, parser in prefixes:
if line.startswith(prefix):
args = line.removeprefix(prefix)
yield from parser(args)
def group_by_material(l):
current_material = None
for i in l:
if type(i) is NewMtl:
current_material = i
elif type(i) is MapKd:
assert current_material is not None
yield (current_material, i)
current_material = None
else:
assert False, type(i)
def parse_mtl_file(buf):
return list(group_by_material((
parsed
for line in buf.strip().split('\n')
for parsed in parse_mtl_line(line)
if not line.startswith('#')
)))

155
gen/parse_obj.py Normal file
View File

@ -0,0 +1,155 @@
from collections import defaultdict
from dataclasses import dataclass
import string
from fixed_point import FixedPoint
import fixed_point
@dataclass
class VertexPosition:
x: FixedPoint
y: FixedPoint
z: FixedPoint
@dataclass
class VertexNormal:
x: FixedPoint
y: FixedPoint
z: FixedPoint
@dataclass
class VertexTexture:
u: FixedPoint
v: FixedPoint
@dataclass
class IndexVTN:
vertex_position: int
vertex_texture: int
vertex_normal: int
@dataclass
class Triangle:
a: IndexVTN
b: IndexVTN
c: IndexVTN
@dataclass
class Quadrilateral:
a: IndexVTN
b: IndexVTN
c: IndexVTN
d: IndexVTN
@dataclass
class Object:
name: str
@dataclass
class Material:
lib: str
name: str
@dataclass
class MtlLib:
name: str
def parse_fixed_point_vector(args, n):
split = args.split()
assert len(split) == n, (n, split)
return tuple(map(fixed_point.parse, split))
def parse_vertex_position(args):
coordinates = parse_fixed_point_vector(args, 3)
yield VertexPosition(*coordinates)
def parse_vertex_normal(args):
coordinates = parse_fixed_point_vector(args, 3)
yield VertexNormal(*coordinates)
def parse_vertex_texture(args):
coordinates = parse_fixed_point_vector(args, 2)
yield VertexTexture(*coordinates)
def int_minus_one(s):
n = int(s) - 1
assert n >= 0
return n
def _parse_vertex_indices(args):
indices = args.split('/')
assert len(indices) == 3, indices
return IndexVTN(*map(int_minus_one, indices))
def parse_face(args):
vertices = args.split()
if len(vertices) == 3:
yield Triangle(*map(_parse_vertex_indices, vertices))
elif len(vertices) == 4:
yield Quadrilateral(*map(_parse_vertex_indices, vertices))
else:
assert False, (len(vertices), args)
def safe(s):
return s.replace('-', '_').replace('.', '_').replace(':', '_')
def parse_object(args):
name, = args.split()
yield Object(safe(name))
def parse_material(args):
name, = args.split()
yield Material(None, safe(name))
def parse_mtllib(args):
name, = args.split()
yield MtlLib(name)
def parse_obj_line(line):
prefixes = [
('v ', parse_vertex_position),
('vn ', parse_vertex_normal),
('vt ', parse_vertex_texture),
('f ', parse_face),
('o ', parse_object),
('usemtl ', parse_material),
('mtllib ', parse_mtllib),
]
for prefix, parser in prefixes:
if line.startswith(prefix):
args = line.removeprefix(prefix)
yield from parser(args)
def group_by_type(l):
vertices = defaultdict(list)
current_object = None
faces = defaultdict(lambda: defaultdict(list))
materials = dict()
current_mtllib = None
for i in l:
if type(i) in {VertexPosition, VertexTexture, VertexNormal}:
vertices[type(i)].append(i)
elif type(i) in {Triangle, Quadrilateral}:
assert current_object is not None
faces[current_object.name][type(i)].append(i)
elif type(i) is Material:
assert current_object is not None
assert current_mtllib is not None
i.lib = current_mtllib.name
assert current_object.name not in materials, (current_object.name, materials)
materials[current_object.name] = i
elif type(i) is Object:
current_object = i
elif type(i) is MtlLib:
current_mtllib = i
else:
assert False, type(i)
return dict(vertices), dict((k, dict(v)) for k, v in faces.items()), materials
def parse_obj_file(buf):
return group_by_type((
parsed
for line in buf.strip().split('\n')
for parsed in parse_obj_line(line)
if not line.startswith('#')
))

9
gen/path.py Normal file
View File

@ -0,0 +1,9 @@
from os import path
def texture_path(s):
#return path.join('..', 'texture', s)
return s
def model_path(s):
#return path.join('..', 'model', s)
return s

34
gen/profiles.py Normal file
View File

@ -0,0 +1,34 @@
from dataclasses import dataclass
@dataclass
class Profile:
position: tuple[int, int]
texture: tuple[int, int]
normal: tuple[int, int]
@dataclass
class FixedPointBits:
integer: int
fraction: int
def to_str(self):
return f"{self.integer}.{self.fraction} fixed-point"
@dataclass
class FloatingPoint:
def to_str(self):
return f"floating-point"
profiles = {}
profiles["nds"] = Profile(
position = FixedPointBits(4, 6), # 4.6
normal = FixedPointBits(0, 9), # 0.9
texture = FixedPointBits(1, 14), # 1.14
)
profiles["dreamcast"] = Profile(
position = FloatingPoint(),
normal = FloatingPoint(),
texture = FloatingPoint(),
)

View File

@ -0,0 +1,120 @@
from dataclasses import dataclass
from generate import renderer
from math import log
from path import texture_path
import sys
from PIL import Image
from parse_material import parse_mtl_file
material_filenames = sys.argv[1:]
def render_material_enum(newmtl_mapkd):
yield f"enum material {{"
for newmtl, mapkd in newmtl_mapkd:
yield f"{newmtl.name},";
yield "};"
def render_pixel_descriptor(offset, mapkd, dimensions):
name, _ext = mapkd.name.rsplit('.', maxsplit=1)
pixel_name = f"{name}_data"
width, height = dimensions
yield ".pixel = {"
yield f".start = (uint8_t *)&_binary_{pixel_name}_start,"
yield f".size = (int)&_binary_{pixel_name}_size,"
yield f".vram_offset = {offset.pixel},"
yield f".width = {width},"
yield f".height = {height},"
yield "},"
def render_palette_descriptor(offset, mapkd, palette_size):
name, _ext = mapkd.name.rsplit('.', maxsplit=1)
palette_name = f"{name}_data_pal"
yield ".palette = {"
yield f".start = (uint8_t *)&_binary_{palette_name}_start,"
yield f".size = (int)&_binary_{palette_name}_size,"
yield f".vram_offset = {offset.palette},"
yield f".palette_size = {palette_size},"
yield "},"
@dataclass
class Offset:
pixel: int
palette: int
def round_up_colors(name, colors):
assert colors != 0, (name, colors)
return 256
if colors <= 4:
return 4
if colors <= 16:
return 16
elif colors <= 256:
return 256
else:
assert False, (name, colors)
def image_metadata(mapkd):
path = texture_path(mapkd.name)
with Image.open(path) as im:
dimensions = im.size
colors = len(im.palette.colors)
return dimensions, colors
def round_up_n(x, multiple):
return ((x + multiple - 1) // multiple) * multiple
def bytes_per_pixel(palette_size):
bits_per_pixel = int(log(palette_size)/log(2))
return bits_per_pixel / 8
def render_material(offset, mapkd):
dimensions, colors = image_metadata(mapkd)
palette_size = round_up_colors(mapkd.name, colors)
# pixel descriptor
yield from render_pixel_descriptor(offset, mapkd, dimensions)
pixel_size = bytes_per_pixel(palette_size) * dimensions[0] * dimensions[1]
#pixel_size = 2 * dimensions[0] * dimensions[1]
assert int(pixel_size) == pixel_size
offset.pixel += round_up_n(int(pixel_size), 8)
# palette descriptor
yield from render_palette_descriptor(offset, mapkd, palette_size)
offset.palette += round_up_n(colors * 2, 16)
def render_materials(newmtl_mapkd):
yield "struct material_descriptor material[] = {"
offset = Offset(0, 0)
for newmtl, mapkd in newmtl_mapkd:
yield f"[{newmtl.name}] = {{"
yield from render_material(offset, mapkd)
yield "},"
yield "};"
def render_header():
yield "#pragma once"
yield ""
yield "#include <stdint.h>"
yield ""
yield '#include "model/material.h"'
yield ""
if __name__ == "__main__":
material_filenames = sys.argv[1:]
assert material_filenames
newmtl_mapkd = []
for material_filename in material_filenames:
with open(material_filename) as f:
buf = f.read()
newmtl_mapkd.extend([
(newmtl, mapkd)
for (newmtl, mapkd) in parse_mtl_file(buf)
])
render, out = renderer()
render(render_header())
render(render_material_enum(newmtl_mapkd))
render(render_materials(newmtl_mapkd))
sys.stdout.write(out.getvalue())

160
gen/render_model.py Normal file
View File

@ -0,0 +1,160 @@
from dataclasses import astuple
import sys
from generate import renderer
from parse_obj import parse_obj_file
from parse_obj import VertexPosition
from parse_obj import VertexNormal
from parse_obj import VertexTexture
from parse_obj import Triangle
from parse_obj import Quadrilateral
import profiles
def render_index_vtn(index_vtn):
s = ", ".join(map(str, index_vtn))
yield f"{{{s}}},"
def render_face(face):
yield "{ .v = {"
for index_vtn in astuple(face):
yield from render_index_vtn(index_vtn)
yield "}},"
def render_faces(prefix, name, faces):
yield f"union {name} {prefix}_{name}[] = {{"
for face in faces:
yield from render_face(face)
yield "};"
def render_triangles(prefix, faces):
yield from render_faces(prefix, "triangle", faces)
def render_quadrilateral(prefix, faces):
yield from render_faces(prefix, "quadrilateral", faces)
def xyz(vec):
return (vec.x, vec.y, vec.z)
def uv(vec):
return (vec.u, vec.v)
def render_vertex(profile_item, vertex_tuple):
def _profile_item(profile_item, fp):
if type(profile_item) == profiles.FixedPointBits:
return fp.to_fixed_point(profile_item.integer, profile_item.fraction).to_int()
elif type(profile_item) == profiles.FloatingPoint:
return fp.to_float()
else:
assert False, type(profile_item)
s = ", ".join(
str(_profile_item(profile_item, fp))
for fp in vertex_tuple
)
yield f"{{{s}}},"
def render_vertices(profile_item, prefix, name, vertices):
yield f"// {profile_item.to_str()}"
yield f"vertex_{name} {prefix}_{name}[] = {{"
for vertex in vertices:
yield from render_vertex(profile_item, vertex)
yield "};"
def render_vertex_positions(profile, prefix, vertex_positions):
yield from render_vertices(profile.position,
prefix,
"position",
map(xyz, vertex_positions))
def render_vertex_normals(profile, prefix, vertex_normals):
yield from render_vertices(profile.normal,
prefix,
"normal",
map(xyz, vertex_normals))
def render_vertex_texture(profile, prefix, vertex_textures):
yield from render_vertices(profile.texture,
prefix,
"texture",
map(uv, vertex_textures))
def render_object(prefix, object_name, d, material):
yield f"struct object {prefix}_{object_name} = {{"
triangle_count = len(d[Triangle]) if Triangle in d else 0
quadrilateral_count = len(d[Quadrilateral]) if Quadrilateral in d else 0
if triangle_count > 0:
yield f".triangle = &{prefix}_{object_name}_triangle[0],"
else:
yield f".triangle = NULL,"
if quadrilateral_count > 0:
yield f".quadrilateral = &{prefix}_{object_name}_quadrilateral[0],"
else:
yield f".quadrilateral = NULL,"
yield f".triangle_count = {triangle_count},"
yield f".quadrilateral_count = {quadrilateral_count},"
if material is None:
yield f".material = -1,",
else:
yield f".material = {material.name},"
yield "};"
def render_object_list(prefix, object_names):
yield f"struct object * {prefix}_object_list[] = {{"
for object_name in object_names:
yield f"&{prefix}_{object_name},"
yield "};"
def render_model(prefix, object_count):
yield f"struct model {prefix}_model = {{"
yield f".position = &{prefix}_position[0],"
yield f".texture = &{prefix}_texture[0],"
yield f".normal = &{prefix}_normal[0],"
yield f".object = &{prefix}_object_list[0],"
yield f".object_count = {object_count},"
yield "};"
def render_header():
yield "#pragma once"
yield ""
yield "#include <stddef.h>"
yield ""
yield '#include "../model.h"'
yield ""
obj_filename = sys.argv[1]
prefix = sys.argv[2]
profile_name = sys.argv[3]
profile = profiles.profiles[profile_name]
with open(obj_filename) as f:
buf = f.read()
vertices, faces, materials = parse_obj_file(buf)
render, out = renderer()
render(render_header())
render(render_vertex_positions(profile, prefix, vertices[VertexPosition]))
render(render_vertex_texture(profile, prefix, vertices[VertexTexture]))
render(render_vertex_normals(profile, prefix, vertices[VertexNormal]))
for object_name, d in faces.items():
object_prefix = '_'.join((prefix, object_name))
if Triangle in d:
render(render_triangles(object_prefix, d[Triangle]))
if Quadrilateral in d:
render(render_quadrilateral(object_prefix, d[Quadrilateral]))
render(render_object(prefix, object_name, d, materials.get(object_name)));
render(render_object_list(prefix, faces.keys()))
render(render_model(prefix, len(faces)))
sys.stdout.write(out.getvalue())

View File

@ -1,4 +1,4 @@
all: $(patsubst %.obj,%.h,$(wildcard *.obj))
%.h: %.obj
python render_obj_fixed_point_c_source.py $< $(basename $<) > $@
python ../res/render_obj_fixed_point_c_source.py $< $(basename $<) > $@

View File

@ -1,849 +0,0 @@
#include "model/model.h"
// .6 fixed-point
struct vertex_position majora_position[] = {
{28, 13, -2},
{41, -9, -3},
{17, 4, -2},
{23, 8, 2},
{-24, 8, 2},
{-29, 13, -2},
{-42, -9, -3},
{-18, 4, -2},
{0, 61, -3},
{41, 20, -5},
{0, -13, -7},
{16, 68, -3},
{35, 68, -3},
{49, 52, -3},
{-49, 52, -3},
{-36, 68, -3},
{-17, 68, -3},
{-42, 20, -5},
{-28, 95, 0},
{-16, 63, -1},
{-31, 62, -1},
{-23, 60, 6},
{22, 60, 6},
{30, 62, -1},
{27, 95, 0},
{15, 63, -1},
{64, 20, -1},
{36, 25, -1},
{43, 36, -1},
{39, 30, 3},
{-40, 30, 3},
{-44, 36, -1},
{-65, 20, -1},
{-37, 25, -1},
{-4, -4, -3},
{-25, -20, -3},
{-18, 3, -2},
{-11, -1, 1},
{24, -20, -3},
{17, 3, -2},
{10, -1, 1},
{3, -4, -3},
{-28, 14, -2},
{-54, 3, -2},
{-38, 23, -1},
{-33, 18, 2},
{53, 3, -2},
{37, 23, -1},
{32, 18, 2},
{27, 14, -2},
{0, 61, -3},
{0, 42, 13},
{6, 54, 11},
{15, 29, 17},
{0, 13, 6},
{-16, 29, 17},
{-19, 45, 18},
{0, -13, -7},
{-12, 14, 15},
{-17, 68, -3},
{-13, 61, 7},
{-36, 68, -3},
{-49, 52, -3},
{-37, 48, 14},
{-14, 53, 17},
{-7, 54, 11},
{30, 24, 13},
{41, 20, -5},
{49, 52, -3},
{13, 53, 17},
{18, 45, 18},
{-31, 24, 13},
{-42, 20, -5},
{-24, 14, 7},
{23, 14, 7},
{-27, 60, 11},
{12, 61, 7},
{16, 68, -3},
{26, 60, 11},
{35, 68, -3},
{36, 48, 14},
{11, 14, 15},
};
// .14 fixed-point
struct vertex_texture majora_texture[] = {
{11583, 9984},
{13855, 16384},
{16352, 31},
{12704, 13184},
{0, 31},
{3647, 13184},
{2496, 16384},
{4768, 9984},
{16223, 0},
{16384, 16288},
{3072, 3664},
{256, 11056},
{5439, 16415},
{1679, 15952},
{5456, 16384},
{0, 384},
{672, 16384},
{4096, 1055},
{2111, 0},
{15679, 16384},
{14240, 0},
{16352, 384},
{12256, 1055},
{13631, 16384},
{16384, 0},
{12768, 4768},
{13184, 10591},
{0, 0},
{3167, 10591},
{2720, 16384},
{3584, 4768},
{2399, 16384},
{6880, 11968},
{0, 0},
{4639, 14175},
{11712, 14175},
{16384, 0},
{13951, 16384},
{9472, 11968},
{2399, 16384},
{3968, 8735},
{0, 0},
{3167, 12575},
{13184, 12575},
{16384, 0},
{13951, 16384},
{12383, 8735},
{10944, 13767},
{12256, 16384},
{12256, 11080},
{12263, 5359},
{8623, 8960},
{8192, 12544},
{8647, 5407},
{12263, -17},
{8840, 15552},
{6792, 16415},
{4415, 12712},
{4112, 16440},
{2976, 13160},
{9232, 13943},
{5744, 7960},
{4112, 4903},
{6431, 4712},
{11480, -17},
{6999, 15016},
};
// .9 fixed-point
struct vertex_normal majora_normal[] = {
{-233, -430, -155},
{425, 262, -113},
{107, -155, 476},
{48, -84, 502},
{-108, -155, 476},
{-49, -84, 502},
{-426, 262, -113},
{-426, 262, -113},
{232, -430, -155},
{232, -430, -155},
{48, -84, 502},
{107, -155, 476},
{0, 25, -512},
{0, 25, -512},
{0, 25, -512},
{0, 25, -512},
{0, 25, -512},
{-1, 25, -512},
{-1, 25, -512},
{-1, 25, -512},
{0, 25, -512},
{0, 25, -512},
{0, 25, -512},
{0, 25, -512},
{-1, 25, -512},
{-1, 25, -512},
{-1, 25, -512},
{-1, 25, -512},
{-478, 46, -181},
{-27, 245, 448},
{444, 184, -176},
{-12, 75, 506},
{444, 184, -176},
{26, 245, 448},
{11, 75, 506},
{477, 46, -181},
{26, 245, 448},
{477, 46, -181},
{-445, 184, -176},
{-445, 184, -176},
{11, 75, 506},
{-12, 75, 506},
{-27, 245, 448},
{-478, 46, -181},
{291, 405, -113},
{142, -104, 480},
{-79, -479, -165},
{62, -61, 504},
{-79, -479, -165},
{142, -104, 480},
{-143, -104, 480},
{-63, -61, 504},
{-292, 405, -113},
{-292, 405, -113},
{78, -479, -165},
{-143, -104, 480},
{78, -479, -165},
{142, -104, 480},
{291, 405, -113},
{-475, 155, -112},
{312, -378, -149},
{-80, -177, 473},
{312, -378, -148},
{-37, -96, 501},
{-80, -177, 473},
{36, -96, 501},
{79, -177, 473},
{474, 155, -112},
{-313, -378, -149},
{474, 155, -112},
{79, -177, 473},
{36, -96, 501},
{-313, -378, -148},
{-475, 155, -112},
{-391, 311, -113},
{187, -450, -159},
{-121, -143, 476},
{187, -450, -159},
{-54, -78, 503},
{-121, -143, 476},
{53, -78, 503},
{120, -143, 476},
{390, 311, -113},
{-188, -450, -159},
{390, 311, -113},
{120, -143, 476},
{53, -78, 503},
{-188, -450, -159},
{120, -143, 476},
{-121, -143, 476},
{-54, -78, 503},
{-391, 311, -113},
{-276, 297, 311},
{0, 398, 321},
{0, 75, 506},
{0, -109, 500},
{-48, -49, 507},
{0, 74, 506},
{-26, 46, 509},
{47, -49, 507},
{13, -212, 466},
{0, -355, 369},
{-1, -109, 500},
{157, 391, 290},
{0, 398, 321},
{85, 425, 271},
{-243, 93, 441},
{-211, 346, 312},
{-417, 7, 297},
{275, 297, 311},
{117, 241, 435},
{416, 7, 297},
{283, -182, 385},
{347, -277, 254},
{-118, 241, 435},
{25, 46, 509},
{-252, -339, 290},
{-284, -182, 385},
{-348, -277, 254},
{251, -339, 290},
{347, -278, 254},
{-64, 330, 385},
{85, 425, 271},
{-211, 346, 312},
{-26, 46, 509},
{-417, 7, 297},
{-348, -277, 254},
{-158, 391, 290},
{-86, 425, 271},
{-86, 425, 271},
{63, 330, 385},
{210, 346, 312},
{210, 346, 312},
{242, 93, 441},
{416, 7, 297},
{25, 46, 509},
{-1, 74, 506},
{283, -182, 385},
{347, -277, 254},
{0, -355, 369},
{-348, -278, 254},
{-14, -212, 466},
{0, -109, 500},
{157, 391, 290},
{275, 297, 311},
{117, 241, 435},
{-64, 330, 385},
{-26, 46, 509},
{-243, 93, 441},
{47, -49, 507},
{-252, -339, 290},
{-158, 391, 290},
{-276, 297, 311},
{25, 46, 509},
{63, 330, 385},
{-118, 241, 435},
{-48, -49, 507},
{242, 93, 441},
{-48, -49, 507},
{251, -339, 290},
{117, 241, 435},
{-64, 330, 385},
{-118, 241, 435},
{63, 330, 385},
{-243, 93, 441},
{210, 346, 312},
{63, 330, 385},
{-284, -182, 385},
{416, 7, 297},
{13, -212, 466},
{-14, -212, 466},
};
struct triangle majora_1_triangle[] = {
{
{2, 0, 0},
{0, 1, 1},
{1, 2, 2},
},
{
{3, 3, 3},
{2, 0, 0},
{1, 2, 2},
},
{
{6, 4, 4},
{4, 5, 5},
{5, 6, 6},
},
{
{5, 6, 7},
{7, 7, 8},
{6, 4, 4},
},
{
{7, 7, 9},
{4, 5, 5},
{6, 4, 4},
},
{
{3, 3, 10},
{1, 2, 11},
{0, 1, 1},
},
};
struct object majora_1 = {
.triangle = &majora_1_triangle[0],
.quadrilateral = NULL,
.triangle_count = 6,
.quadrilateral_count = 0,
.material = mtl_06007BE0,
};
struct triangle majora_3_triangle[] = {
{
{10, 8, 12},
{8, 9, 13},
{9, 10, 14},
},
{
{13, 11, 15},
{11, 12, 15},
{12, 13, 16},
},
{
{16, 14, 17},
{14, 11, 17},
{15, 13, 18},
},
{
{14, 11, 19},
{8, 9, 19},
{17, 10, 19},
},
{
{8, 9, 20},
{13, 11, 20},
{9, 10, 20},
},
{
{11, 12, 21},
{13, 11, 22},
{8, 9, 23},
},
{
{14, 11, 24},
{16, 14, 25},
{8, 9, 23},
},
{
{8, 9, 26},
{10, 8, 12},
{17, 10, 27},
},
};
struct object majora_3 = {
.triangle = &majora_3_triangle[0],
.quadrilateral = NULL,
.triangle_count = 8,
.quadrilateral_count = 0,
.material = mtl_06007FE0,
};
struct triangle majora_4_triangle[] = {
{
{20, 15, 28},
{18, 16, 29},
{19, 17, 30},
},
{
{21, 18, 31},
{19, 17, 32},
{18, 16, 29},
},
{
{24, 19, 33},
{22, 20, 34},
{23, 21, 35},
},
{
{24, 19, 36},
{23, 21, 37},
{25, 22, 38},
},
{
{25, 22, 39},
{22, 20, 40},
{24, 19, 36},
},
{
{21, 18, 41},
{18, 16, 42},
{20, 15, 43},
},
{
{28, 23, 44},
{26, 24, 45},
{27, 25, 46},
},
{
{29, 26, 47},
{27, 25, 48},
{26, 24, 49},
},
{
{32, 27, 50},
{30, 28, 51},
{31, 29, 52},
},
{
{31, 29, 53},
{33, 30, 54},
{32, 27, 55},
},
{
{33, 30, 56},
{30, 28, 51},
{32, 27, 50},
},
{
{29, 26, 47},
{26, 24, 57},
{28, 23, 58},
},
};
struct object majora_4 = {
.triangle = &majora_4_triangle[0],
.quadrilateral = NULL,
.triangle_count = 12,
.quadrilateral_count = 0,
.material = mtl_060077E0,
};
struct triangle majora_5_triangle[] = {
{
{36, 31, 59},
{34, 32, 60},
{35, 33, 61},
},
{
{34, 32, 62},
{37, 34, 63},
{35, 33, 64},
},
{
{40, 35, 65},
{38, 36, 66},
{39, 37, 67},
},
{
{41, 38, 68},
{39, 37, 69},
{38, 36, 70},
},
{
{40, 35, 71},
{41, 38, 72},
{38, 36, 66},
},
{
{35, 33, 64},
{37, 34, 63},
{36, 31, 73},
},
};
struct object majora_5 = {
.triangle = &majora_5_triangle[0],
.quadrilateral = NULL,
.triangle_count = 6,
.quadrilateral_count = 0,
.material = mtl_06007DE0,
};
struct triangle majora_6_triangle[] = {
{
{44, 39, 74},
{42, 40, 75},
{43, 41, 76},
},
{
{42, 40, 77},
{45, 42, 78},
{43, 41, 79},
},
{
{48, 43, 80},
{46, 44, 81},
{47, 45, 82},
},
{
{49, 46, 83},
{47, 45, 84},
{46, 44, 85},
},
{
{48, 43, 86},
{49, 46, 87},
{46, 44, 88},
},
{
{43, 41, 89},
{45, 42, 90},
{44, 39, 91},
},
};
struct object majora_6 = {
.triangle = &majora_6_triangle[0],
.quadrilateral = NULL,
.triangle_count = 6,
.quadrilateral_count = 0,
.material = mtl_060079E0,
};
struct triangle majora_7_triangle[] = {
{
{52, 47, 92},
{50, 48, 93},
{51, 49, 94},
},
{
{54, 50, 95},
{53, 51, 96},
{51, 49, 97},
},
{
{56, 52, 98},
{55, 51, 99},
{51, 49, 97},
},
{
{58, 53, 100},
{57, 54, 101},
{54, 50, 102},
},
{
{60, 55, 103},
{50, 48, 104},
{59, 56, 105},
},
{
{63, 57, 106},
{61, 58, 107},
{62, 59, 108},
},
{
{65, 47, 109},
{64, 60, 110},
{51, 49, 97},
},
{
{68, 59, 111},
{66, 61, 112},
{67, 62, 113},
},
{
{69, 60, 114},
{52, 47, 92},
{51, 49, 97},
},
{
{70, 52, 115},
{69, 60, 114},
{51, 49, 97},
},
{
{73, 63, 116},
{71, 61, 117},
{72, 62, 118},
},
{
{74, 63, 119},
{57, 64, 101},
{67, 62, 120},
},
{
{50, 48, 93},
{65, 47, 109},
{51, 49, 97},
},
{
{75, 65, 121},
{59, 56, 122},
{61, 58, 123},
},
{
{64, 60, 110},
{56, 52, 124},
{51, 49, 97},
},
{
{71, 61, 117},
{62, 59, 125},
{72, 62, 126},
},
{
{55, 51, 99},
{54, 50, 95},
{51, 49, 97},
},
{
{50, 48, 104},
{76, 55, 127},
{77, 56, 128},
},
{
{77, 56, 129},
{78, 65, 130},
{79, 58, 131},
},
{
{79, 58, 132},
{80, 57, 133},
{68, 59, 134},
},
{
{53, 51, 96},
{70, 52, 135},
{51, 49, 136},
},
{
{66, 61, 137},
{74, 63, 119},
{67, 62, 138},
},
{
{57, 64, 139},
{73, 63, 116},
{72, 62, 140},
},
{
{57, 54, 101},
{81, 53, 141},
{54, 50, 142},
},
{
{50, 48, 104},
{60, 55, 143},
{65, 47, 144},
},
{
{60, 55, 143},
{64, 60, 145},
{65, 47, 144},
},
{
{75, 65, 146},
{56, 52, 147},
{64, 60, 110},
},
{
{63, 57, 148},
{55, 51, 149},
{56, 52, 124},
},
{
{71, 61, 117},
{58, 53, 100},
{55, 51, 149},
},
{
{73, 63, 150},
{57, 54, 101},
{58, 53, 100},
},
{
{76, 55, 151},
{50, 48, 93},
{52, 47, 152},
},
{
{69, 60, 114},
{76, 55, 151},
{52, 47, 152},
},
{
{70, 52, 153},
{78, 65, 154},
{69, 60, 155},
},
{
{53, 51, 156},
{80, 57, 157},
{70, 52, 115},
},
{
{81, 53, 141},
{66, 61, 137},
{53, 51, 158},
},
{
{57, 54, 101},
{74, 63, 159},
{81, 53, 141},
},
{
{64, 60, 160},
{60, 55, 103},
{75, 65, 161},
},
{
{76, 55, 127},
{69, 60, 162},
{78, 65, 130},
},
{
{59, 56, 105},
{75, 65, 121},
{60, 55, 103},
},
{
{78, 65, 163},
{77, 56, 128},
{76, 55, 127},
},
{
{56, 52, 147},
{75, 65, 146},
{63, 57, 164},
},
{
{61, 58, 123},
{63, 57, 164},
{75, 65, 121},
},
{
{78, 65, 154},
{70, 52, 153},
{80, 57, 133},
},
{
{80, 57, 133},
{79, 58, 165},
{78, 65, 166},
},
{
{55, 51, 149},
{63, 57, 164},
{71, 61, 167},
},
{
{80, 57, 133},
{53, 51, 158},
{66, 61, 137},
},
{
{62, 59, 125},
{71, 61, 167},
{63, 57, 164},
},
{
{66, 61, 112},
{68, 59, 168},
{80, 57, 133},
},
{
{54, 50, 95},
{55, 51, 149},
{58, 53, 169},
},
{
{53, 51, 158},
{54, 50, 95},
{81, 53, 170},
},
{
{58, 53, 100},
{71, 61, 117},
{73, 63, 150},
},
{
{66, 61, 137},
{81, 53, 170},
{74, 63, 159},
},
};
struct object majora_7 = {
.triangle = &majora_7_triangle[0],
.quadrilateral = NULL,
.triangle_count = 52,
.quadrilateral_count = 0,
.material = mtl_060067E0,
};

View File

@ -1,63 +0,0 @@
# Blender 4.1.1 MTL File: 'None'
# www.blender.org
newmtl mtl_060067E0
Ns 95.999992
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd 060067E0.png
newmtl mtl_060077E0
Ns 95.999992
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd 060077E0.png
newmtl mtl_060079E0
Ns 95.999992
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd 060079E0.png
newmtl mtl_06007BE0
Ns 95.999992
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd 06007BE0.png
newmtl mtl_06007DE0
Ns 95.999992
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd 06007DE0.png
newmtl mtl_06007FE0
Ns 95.999992
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd 06007FE0.png

View File

@ -1,430 +0,0 @@
# Blender 4.1.1
# www.blender.org
mtllib majora.mtl
o 1
v 0.451172 0.203125 -0.021484
v 0.652344 -0.129883 -0.038086
v 0.270508 0.073242 -0.027344
v 0.361328 0.135742 0.034180
v -0.361328 0.135742 0.034180
v -0.451172 0.203125 -0.021484
v -0.652344 -0.129883 -0.038086
v -0.270508 0.073242 -0.027344
vn -0.4545 -0.8383 -0.3012
vn 0.8303 0.5125 -0.2191
vn 0.2101 -0.3020 0.9299
vn 0.0955 -0.1626 0.9821
vn -0.2101 -0.3020 0.9299
vn -0.0954 -0.1626 0.9821
vn -0.8303 0.5125 -0.2191
vn -0.8302 0.5125 -0.2191
vn 0.4545 -0.8383 -0.3012
vn 0.4544 -0.8383 -0.3012
vn 0.0954 -0.1626 0.9821
vn 0.2100 -0.3019 0.9299
vt 0.707031 0.609375
vt 0.845703 1.000000
vt 0.998047 0.001953
vt 0.775391 0.804688
vt 0.000000 0.001953
vt 0.222656 0.804688
vt 0.152344 1.000000
vt 0.291016 0.609375
s 0
usemtl mtl_06007BE0
f 3/1/1 1/2/2 2/3/3
f 4/4/4 3/1/1 2/3/3
f 7/5/5 5/6/6 6/7/7
f 6/7/8 8/8/9 7/5/5
f 8/8/10 5/6/6 7/5/5
f 4/4/11 2/3/12 1/2/2
o 3
v 0.000000 0.958008 -0.039062
v 0.643555 0.322266 -0.070312
v 0.000000 -0.203125 -0.096680
v 0.254883 1.076172 -0.033203
v 0.559570 1.070312 -0.033203
v 0.765625 0.813476 -0.045898
v -0.765625 0.813477 -0.045898
v -0.559570 1.070313 -0.033203
v -0.254883 1.076172 -0.033203
v -0.643555 0.322266 -0.070313
vn -0.0000 0.0496 -0.9988
vn 0.0002 0.0494 -0.9988
vn 0.0005 0.0496 -0.9988
vn 0.0007 0.0497 -0.9988
vn 0.0010 0.0501 -0.9987
vn -0.0007 0.0497 -0.9988
vn -0.0010 0.0501 -0.9987
vn -0.0004 0.0495 -0.9988
vn 0.0004 0.0495 -0.9988
vn 0.0006 0.0494 -0.9988
vn 0.0005 0.0493 -0.9988
vn -0.0000 0.0493 -0.9988
vn -0.0005 0.0494 -0.9988
vn -0.0006 0.0494 -0.9988
vn -0.0002 0.0494 -0.9988
vn -0.0005 0.0496 -0.9988
vt 0.990234 0.000000
vt 1.000000 0.994141
vt 0.187500 0.223633
vt 0.015625 0.674805
vt 0.332031 1.001953
vt 0.102539 0.973633
vt 0.333008 1.000000
s 0
usemtl mtl_06007FE0
f 11/9/13 9/10/14 10/11/15
f 14/12/16 12/13/16 13/14/17
f 17/15/18 15/12/18 16/14/19
f 15/12/20 9/10/20 18/11/20
f 9/10/21 14/12/21 10/11/21
f 12/13/22 14/12/23 9/10/24
f 15/12/25 17/15/26 9/10/24
f 9/10/27 11/9/13 18/11/28
o 4
v -0.436523 1.492188 0.012695
v -0.238281 0.990234 -0.011719
v -0.477539 0.968750 -0.013672
v -0.353516 0.951172 0.095703
v 0.353516 0.951172 0.095703
v 0.477539 0.968750 -0.013672
v 0.436524 1.492187 0.012695
v 0.238281 0.990234 -0.011719
v 1.013672 0.322265 -0.015625
v 0.566406 0.394531 -0.011719
v 0.673828 0.570312 -0.002930
v 0.620117 0.479492 0.051758
v -0.620117 0.479492 0.051758
v -0.673828 0.570313 -0.002930
v -1.013672 0.322266 -0.015625
v -0.566406 0.394531 -0.011719
vn -0.9317 0.0907 -0.3517
vn -0.0513 0.4802 0.8757
vn 0.8679 0.3594 -0.3428
vn -0.0218 0.1484 0.9887
vn 0.8680 0.3594 -0.3426
vn 0.0512 0.4802 0.8757
vn 0.0217 0.1483 0.9887
vn 0.9317 0.0907 -0.3516
vn 0.0513 0.4802 0.8757
vn 0.9317 0.0906 -0.3517
vn -0.8680 0.3594 -0.3428
vn -0.8680 0.3595 -0.3426
vn 0.0218 0.1483 0.9887
vn -0.0217 0.1484 0.9887
vn -0.0512 0.4802 0.8757
vn -0.9317 0.0907 -0.3516
vn 0.5699 0.7920 -0.2191
vn 0.2787 -0.2021 0.9389
vn -0.1539 -0.9345 -0.3211
vn 0.1219 -0.1172 0.9856
vn -0.1538 -0.9345 -0.3211
vn 0.2788 -0.2022 0.9388
vn -0.2788 -0.2022 0.9388
vn -0.1219 -0.1172 0.9856
vn -0.5699 0.7920 -0.2190
vn -0.5699 0.7920 -0.2191
vn 0.1538 -0.9345 -0.3211
vn -0.2787 -0.2022 0.9388
vn 0.1539 -0.9345 -0.3211
vn 0.2787 -0.2022 0.9388
vn 0.5698 0.7920 -0.2190
vt 0.000000 0.023438
vt 0.041016 1.000000
vt 0.250000 0.064453
vt 0.128906 0.000000
vt 0.957031 1.000000
vt 0.869141 0.000000
vt 0.998047 0.023438
vt 0.748047 0.064453
vt 0.832031 1.000000
vt 1.000000 0.000000
vt 0.779297 0.291016
vt 0.804688 0.646484
vt 0.000000 0.000000
vt 0.193359 0.646484
vt 0.166016 1.000000
vt 0.218750 0.291016
s 0
usemtl mtl_060077E0
f 21/16/29 19/17/30 20/18/31
f 22/19/32 20/18/33 19/17/30
f 25/20/34 23/21/35 24/22/36
f 25/20/37 24/22/38 26/23/39
f 26/23/40 23/21/41 25/20/37
f 22/19/42 19/17/43 21/16/44
f 29/24/45 27/25/46 28/26/47
f 30/27/48 28/26/49 27/25/50
f 33/28/51 31/29/52 32/30/53
f 32/30/54 34/31/55 33/28/56
f 34/31/57 31/29/52 33/28/51
f 30/27/48 27/25/58 29/24/59
o 5
v -0.060547 -0.047852 -0.033203
v -0.383789 -0.310547 -0.046875
v -0.270508 0.049805 -0.028320
v -0.166016 -0.001953 0.027344
v 0.383789 -0.310547 -0.046875
v 0.270508 0.049805 -0.028320
v 0.166016 -0.001953 0.027344
v 0.060547 -0.047852 -0.033203
vn -0.9276 0.3030 -0.2185
vn 0.6111 -0.7368 -0.2891
vn -0.1552 -0.3452 0.9256
vn 0.6112 -0.7369 -0.2890
vn -0.0709 -0.1856 0.9801
vn -0.1553 -0.3452 0.9256
vn 0.0709 -0.1856 0.9801
vn 0.1553 -0.3452 0.9256
vn 0.9277 0.3029 -0.2185
vn -0.6111 -0.7369 -0.2891
vn 0.9276 0.3029 -0.2185
vn 0.1552 -0.3452 0.9256
vn 0.0709 -0.1857 0.9800
vn -0.6111 -0.7369 -0.2890
vn -0.9277 0.3028 -0.2185
vt 0.146484 1.000000
vt 0.419922 0.730469
vt 0.000000 0.000000
vt 0.283203 0.865234
vt 0.714844 0.865234
vt 1.000000 0.000000
vt 0.851562 1.000000
vt 0.578125 0.730469
s 0
usemtl mtl_06007DE0
f 37/32/60 35/33/61 36/34/62
f 35/33/63 38/35/64 36/34/65
f 41/36/66 39/37/67 40/38/68
f 42/39/69 40/38/70 39/37/71
f 41/36/72 42/39/73 39/37/67
f 36/34/65 38/35/64 37/32/74
o 6
v -0.429688 0.225586 -0.019531
v -0.836914 0.058594 -0.028320
v -0.590820 0.372070 -0.012695
v -0.510742 0.295899 0.042969
v 0.836914 0.058594 -0.028320
v 0.590820 0.372070 -0.012695
v 0.510742 0.295898 0.042969
v 0.429687 0.225586 -0.019531
vn -0.7621 0.6093 -0.2193
vn 0.3665 -0.8775 -0.3094
vn -0.2348 -0.2774 0.9316
vn 0.3666 -0.8775 -0.3093
vn -0.1052 -0.1508 0.9830
vn -0.2347 -0.2774 0.9316
vn 0.1051 -0.1507 0.9830
vn 0.2348 -0.2775 0.9316
vn 0.7621 0.6092 -0.2192
vn -0.3665 -0.8775 -0.3094
vn 0.7621 0.6092 -0.2193
vn 0.2348 -0.2774 0.9316
vn 0.1051 -0.1508 0.9830
vn -0.3665 -0.8775 -0.3093
vn 0.2347 -0.2775 0.9316
vn -0.2348 -0.2775 0.9316
vn -0.1051 -0.1507 0.9830
vn -0.7621 0.6092 -0.2192
vt 0.146484 1.000000
vt 0.242188 0.533203
vt 0.000000 0.000000
vt 0.193359 0.767578
vt 0.804688 0.767578
vt 1.000000 0.000000
vt 0.851562 1.000000
vt 0.755859 0.533203
s 0
usemtl mtl_060079E0
f 45/40/75 43/41/76 44/42/77
f 43/41/78 46/43/79 44/42/80
f 49/44/81 47/45/82 48/46/83
f 50/47/84 48/46/85 47/45/86
f 49/44/87 50/47/88 47/45/89
f 44/42/90 46/43/91 45/40/92
o 7
v 0.000000 0.958008 -0.039062
v 0.000000 0.657227 0.215820
v 0.097656 0.847656 0.176758
v 0.246094 0.464844 0.268555
v 0.000000 0.209961 0.107422
v -0.246094 0.464844 0.268555
v -0.291992 0.710938 0.281250
v 0.000000 -0.203125 -0.096680
v -0.184570 0.228516 0.241211
v -0.254883 1.076172 -0.033203
v -0.191406 0.959961 0.111328
v -0.559570 1.070313 -0.033203
v -0.765625 0.813477 -0.045898
v -0.574219 0.756836 0.222656
v -0.213867 0.839844 0.272461
v -0.097656 0.847656 0.176758
v 0.483398 0.388672 0.204102
v 0.643555 0.322266 -0.070312
v 0.765625 0.813476 -0.045898
v 0.213867 0.839844 0.272461
v 0.291992 0.710937 0.281250
v -0.483398 0.388672 0.204102
v -0.643555 0.322266 -0.070313
v -0.374023 0.221680 0.122070
v 0.374023 0.221680 0.122070
v -0.419922 0.952148 0.172852
v 0.191406 0.959961 0.111328
v 0.254883 1.076172 -0.033203
v 0.419922 0.952148 0.172852
v 0.559570 1.070312 -0.033203
v 0.574219 0.756836 0.222656
v 0.184570 0.228516 0.241211
vn -0.5389 0.5818 0.6091
vn -0.0000 0.7781 0.6282
vn -0.0000 0.1465 0.9892
vn -0.0000 -0.2122 0.9772
vn -0.0919 -0.0941 0.9913
vn -0.0000 0.1464 0.9892
vn -0.0492 0.0905 0.9947
vn 0.0919 -0.0941 0.9913
vn 0.0260 -0.4132 0.9103
vn -0.0000 -0.6929 0.7210
vn -0.0001 -0.2122 0.9772
vn 0.3080 0.7641 0.5669
vn -0.0000 0.7780 0.6282
vn 0.1670 0.8317 0.5295
vn -0.4742 0.1822 0.8614
vn -0.4115 0.6761 0.6113
vn -0.8131 0.0141 0.5819
vn 0.5389 0.5818 0.6091
vn 0.2295 0.4721 0.8511
vn 0.8131 0.0140 0.5819
vn 0.5535 -0.3543 0.7537
vn 0.6778 -0.5410 0.4979
vn -0.2295 0.4721 0.8511
vn 0.0493 0.0905 0.9947
vn -0.4916 -0.6608 0.5671
vn -0.5535 -0.3544 0.7537
vn -0.6778 -0.5410 0.4978
vn 0.4916 -0.6608 0.5671
vn 0.6778 -0.5411 0.4978
vn -0.1243 0.6459 0.7532
vn 0.1669 0.8318 0.5295
vn -0.4114 0.6761 0.6113
vn -0.0493 0.0905 0.9947
vn -0.8131 0.0140 0.5819
vn -0.6778 -0.5410 0.4979
vn -0.3080 0.7641 0.5669
vn -0.1670 0.8317 0.5295
vn -0.1669 0.8318 0.5295
vn 0.1243 0.6459 0.7532
vn 0.4114 0.6761 0.6112
vn 0.4115 0.6761 0.6112
vn 0.4741 0.1822 0.8614
vn 0.8131 0.0141 0.5819
vn 0.0492 0.0905 0.9947
vn -0.0001 0.1464 0.9892
vn 0.5535 -0.3544 0.7537
vn 0.6778 -0.5410 0.4978
vn -0.0000 -0.6930 0.7210
vn -0.6778 -0.5411 0.4978
vn -0.0260 -0.4132 0.9103
vn -0.0000 -0.2121 0.9772
vn 0.3081 0.7640 0.5669
vn 0.5389 0.5819 0.6091
vn 0.2295 0.4722 0.8511
vn -0.1243 0.6458 0.7533
vn -0.0493 0.0906 0.9947
vn -0.4741 0.1821 0.8614
vn 0.0918 -0.0941 0.9913
vn -0.4916 -0.6608 0.5672
vn -0.3081 0.7640 0.5669
vn -0.5389 0.5819 0.6091
vn 0.0493 0.0906 0.9947
vn 0.1243 0.6458 0.7533
vn -0.2295 0.4721 0.8512
vn -0.0918 -0.0940 0.9913
vn 0.4741 0.1821 0.8614
vn -0.0918 -0.0941 0.9913
vn 0.4916 -0.6608 0.5672
vn 0.2294 0.4722 0.8511
vn -0.1243 0.6459 0.7533
vn -0.2294 0.4722 0.8511
vn 0.1242 0.6459 0.7533
vn -0.4741 0.1822 0.8614
vn 0.4114 0.6761 0.6113
vn 0.1243 0.6459 0.7533
vn -0.5535 -0.3543 0.7537
vn 0.8131 0.0140 0.5820
vn 0.0260 -0.4133 0.9102
vn -0.0260 -0.4133 0.9102
vt 0.667969 0.840332
vt 0.748047 1.000000
vt 0.748047 0.676270
vt 0.748535 0.327148
vt 0.526367 0.546875
vt 0.500000 0.765625
vt 0.527832 0.330078
vt 0.748535 -0.000977
vt 0.539551 0.949219
vt 0.414551 1.001953
vt 0.269531 0.775879
vt 0.250977 1.003418
vt 0.181641 0.803223
vt 0.563477 0.851074
vt 0.350586 0.485840
vt 0.250977 0.299316
vt 0.392578 0.287598
vt 0.700684 -0.000977
vt 0.427246 0.916504
s 0
usemtl mtl_060067E0
f 53/48/93 51/49/94 52/50/95
f 55/51/96 54/52/97 52/50/98
f 57/53/99 56/52/100 52/50/98
f 59/54/101 58/55/102 55/51/103
f 61/56/104 51/49/105 60/57/106
f 64/58/107 62/59/108 63/60/109
f 66/48/110 65/61/111 52/50/98
f 69/60/112 67/62/113 68/63/114
f 70/61/115 53/48/93 52/50/98
f 71/53/116 70/61/115 52/50/98
f 74/64/117 72/62/118 73/63/119
f 75/64/120 58/65/102 68/63/121
f 51/49/94 66/48/110 52/50/98
f 76/66/122 60/57/123 62/59/124
f 65/61/111 57/53/125 52/50/98
f 72/62/118 63/60/126 73/63/127
f 56/52/100 55/51/96 52/50/98
f 51/49/105 77/56/128 78/57/129
f 78/57/130 79/66/131 80/59/132
f 80/59/133 81/58/134 69/60/135
f 54/52/97 71/53/136 52/50/137
f 67/62/138 75/64/120 68/63/139
f 58/65/140 74/64/117 73/63/141
f 58/55/102 82/54/142 55/51/143
f 51/49/105 61/56/144 66/48/145
f 61/56/144 65/61/146 66/48/145
f 76/66/147 57/53/148 65/61/111
f 64/58/149 56/52/150 57/53/125
f 72/62/118 59/54/101 56/52/150
f 74/64/151 58/55/102 59/54/101
f 77/56/152 51/49/94 53/48/153
f 70/61/115 77/56/152 53/48/153
f 71/53/154 79/66/155 70/61/156
f 54/52/157 81/58/158 71/53/116
f 82/54/142 67/62/138 54/52/159
f 58/55/102 75/64/160 82/54/142
f 65/61/161 61/56/104 76/66/162
f 77/56/128 70/61/163 79/66/131
f 60/57/106 76/66/122 61/56/104
f 79/66/164 78/57/129 77/56/128
f 57/53/148 76/66/147 64/58/165
f 62/59/124 64/58/165 76/66/122
f 79/66/155 71/53/154 81/58/134
f 81/58/134 80/59/166 79/66/167
f 56/52/150 64/58/165 72/62/168
f 81/58/134 54/52/159 67/62/138
f 63/60/126 72/62/168 64/58/165
f 67/62/113 69/60/169 81/58/134
f 55/51/96 56/52/150 59/54/170
f 54/52/159 55/51/96 82/54/171
f 59/54/101 72/62/118 74/64/151
f 67/62/138 82/54/171 75/64/160

View File

@ -8,17 +8,23 @@ struct index_ptn {
uint16_t normal;
};
struct triangle {
struct index_ptn a;
struct index_ptn b;
struct index_ptn c;
union triangle {
struct {
struct index_ptn a;
struct index_ptn b;
struct index_ptn c;
};
struct index_ptn v[3];
};
struct quadrilateral {
struct index_ptn a;
struct index_ptn b;
struct index_ptn c;
struct index_ptn d;
union quadrilateral {
struct {
struct index_ptn a;
struct index_ptn b;
struct index_ptn c;
struct index_ptn d;
};
struct index_ptn v[4];
};
struct vertex_position { // signed 4.6 fixed point
@ -38,10 +44,23 @@ struct vertex_texture { // s.15 fixed point
int16_t v;
};
typedef struct vertex_position vertex_position;
typedef struct vertex_normal vertex_normal;
typedef struct vertex_texture vertex_texture;
struct object {
struct triangle * triangle;
struct quadrilateral * quadrilateral;
union triangle * triangle;
union quadrilateral * quadrilateral;
int triangle_count;
int quadrilateral_count;
int material;
};
struct model {
vertex_position * position;
vertex_texture * texture;
vertex_normal * normal;
struct object ** object;
int object_count;
};

BIN
model/ulala/eye.data Normal file

Binary file not shown.

5
model/ulala/eye.data.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_eye_data_start __asm("_binary_eye_data_start");
extern uint32_t _binary_eye_data_end __asm("_binary_eye_data_end");
extern uint32_t _binary_eye_data_size __asm("_binary_eye_data_size");

BIN
model/ulala/eye.data.pal Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_eye_data_pal_start __asm("_binary_eye_data_pal_start");
extern uint32_t _binary_eye_data_pal_end __asm("_binary_eye_data_pal_end");
extern uint32_t _binary_eye_data_pal_size __asm("_binary_eye_data_pal_size");

BIN
model/ulala/eye.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
model/ulala/ha.data Normal file

Binary file not shown.

5
model/ulala/ha.data.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_ha_data_start __asm("_binary_ha_data_start");
extern uint32_t _binary_ha_data_end __asm("_binary_ha_data_end");
extern uint32_t _binary_ha_data_size __asm("_binary_ha_data_size");

BIN
model/ulala/ha.data.pal Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_ha_data_pal_start __asm("_binary_ha_data_pal_start");
extern uint32_t _binary_ha_data_pal_end __asm("_binary_ha_data_pal_end");
extern uint32_t _binary_ha_data_pal_size __asm("_binary_ha_data_pal_size");

BIN
model/ulala/ha.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

124
model/ulala/material.h Normal file
View File

@ -0,0 +1,124 @@
#pragma once
#include <stdint.h>
#include "model/material.h"
enum material {
eye,
ha,
p03b_hair,
p_face,
p_nomal_mix,
p_ref_or,
u_lb,
};
struct material_descriptor material[] = {
[eye] = {
.pixel = {
.start = (uint8_t *)&_binary_eye_data_start,
.size = (int)&_binary_eye_data_size,
.vram_offset = 0,
.width = 64,
.height = 64,
},
.palette = {
.start = (uint8_t *)&_binary_eye_data_pal_start,
.size = (int)&_binary_eye_data_pal_size,
.vram_offset = 0,
.palette_size = 256,
},
},
[ha] = {
.pixel = {
.start = (uint8_t *)&_binary_ha_data_start,
.size = (int)&_binary_ha_data_size,
.vram_offset = 4096,
.width = 32,
.height = 32,
},
.palette = {
.start = (uint8_t *)&_binary_ha_data_pal_start,
.size = (int)&_binary_ha_data_pal_size,
.vram_offset = 368,
.palette_size = 256,
},
},
[p03b_hair] = {
.pixel = {
.start = (uint8_t *)&_binary_p03b_hair_data_start,
.size = (int)&_binary_p03b_hair_data_size,
.vram_offset = 5120,
.width = 64,
.height = 64,
},
.palette = {
.start = (uint8_t *)&_binary_p03b_hair_data_pal_start,
.size = (int)&_binary_p03b_hair_data_pal_size,
.vram_offset = 464,
.palette_size = 256,
},
},
[p_face] = {
.pixel = {
.start = (uint8_t *)&_binary_p_face_data_start,
.size = (int)&_binary_p_face_data_size,
.vram_offset = 9216,
.width = 256,
.height = 256,
},
.palette = {
.start = (uint8_t *)&_binary_p_face_data_pal_start,
.size = (int)&_binary_p_face_data_pal_size,
.vram_offset = 560,
.palette_size = 256,
},
},
[p_nomal_mix] = {
.pixel = {
.start = (uint8_t *)&_binary_p_nomal_mix_data_start,
.size = (int)&_binary_p_nomal_mix_data_size,
.vram_offset = 74752,
.width = 128,
.height = 128,
},
.palette = {
.start = (uint8_t *)&_binary_p_nomal_mix_data_pal_start,
.size = (int)&_binary_p_nomal_mix_data_pal_size,
.vram_offset = 1072,
.palette_size = 256,
},
},
[p_ref_or] = {
.pixel = {
.start = (uint8_t *)&_binary_p_ref_or_data_start,
.size = (int)&_binary_p_ref_or_data_size,
.vram_offset = 91136,
.width = 64,
.height = 64,
},
.palette = {
.start = (uint8_t *)&_binary_p_ref_or_data_pal_start,
.size = (int)&_binary_p_ref_or_data_pal_size,
.vram_offset = 1472,
.palette_size = 256,
},
},
[u_lb] = {
.pixel = {
.start = (uint8_t *)&_binary_u_lb_data_start,
.size = (int)&_binary_u_lb_data_size,
.vram_offset = 95232,
.width = 64,
.height = 64,
},
.palette = {
.start = (uint8_t *)&_binary_u_lb_data_pal_start,
.size = (int)&_binary_u_lb_data_pal_size,
.vram_offset = 1488,
.palette_size = 256,
},
},
};

11174
model/ulala/model.h Normal file

File diff suppressed because it is too large Load Diff

BIN
model/ulala/p03b_hair.data Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_p03b_hair_data_start __asm("_binary_p03b_hair_data_start");
extern uint32_t _binary_p03b_hair_data_end __asm("_binary_p03b_hair_data_end");
extern uint32_t _binary_p03b_hair_data_size __asm("_binary_p03b_hair_data_size");

View File

@ -0,0 +1 @@
ÿDÿÄÿÈIÉÍ?M?Í?Ñ_M_Q_Ñ_ÕUYÕÙŸUŸYŸÙŸÝ¿Y¿]¿Ýß]ßaßáÿaÿeÿáÿåfjæê?j?n?ê_j_n_înròŸrŸò

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_p03b_hair_data_pal_start __asm("_binary_p03b_hair_data_pal_start");
extern uint32_t _binary_p03b_hair_data_pal_end __asm("_binary_p03b_hair_data_pal_end");
extern uint32_t _binary_p03b_hair_data_pal_size __asm("_binary_p03b_hair_data_pal_size");

BIN
model/ulala/p03b_hair.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

67
model/ulala/p_face.data Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_p_face_data_start __asm("_binary_p_face_data_start");
extern uint32_t _binary_p_face_data_end __asm("_binary_p_face_data_end");
extern uint32_t _binary_p_face_data_size __asm("_binary_p_face_data_size");

BIN
model/ulala/p_face.data.pal Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_p_face_data_pal_start __asm("_binary_p_face_data_pal_start");
extern uint32_t _binary_p_face_data_pal_end __asm("_binary_p_face_data_pal_end");
extern uint32_t _binary_p_face_data_pal_size __asm("_binary_p_face_data_pal_size");

BIN
model/ulala/p_face.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_p_nomal_mix_data_start __asm("_binary_p_nomal_mix_data_start");
extern uint32_t _binary_p_nomal_mix_data_end __asm("_binary_p_nomal_mix_data_end");
extern uint32_t _binary_p_nomal_mix_data_size __asm("_binary_p_nomal_mix_data_size");

Binary file not shown.

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_p_nomal_mix_data_pal_start __asm("_binary_p_nomal_mix_data_pal_start");
extern uint32_t _binary_p_nomal_mix_data_pal_end __asm("_binary_p_nomal_mix_data_pal_end");
extern uint32_t _binary_p_nomal_mix_data_pal_size __asm("_binary_p_nomal_mix_data_pal_size");

BIN
model/ulala/p_nomal_mix.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

BIN
model/ulala/p_ref_or.data Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_p_ref_or_data_start __asm("_binary_p_ref_or_data_start");
extern uint32_t _binary_p_ref_or_data_end __asm("_binary_p_ref_or_data_end");
extern uint32_t _binary_p_ref_or_data_size __asm("_binary_p_ref_or_data_size");

View File

@ -0,0 +1 @@
{ο½χ��

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_p_ref_or_data_pal_start __asm("_binary_p_ref_or_data_pal_start");
extern uint32_t _binary_p_ref_or_data_pal_end __asm("_binary_p_ref_or_data_pal_end");
extern uint32_t _binary_p_ref_or_data_pal_size __asm("_binary_p_ref_or_data_pal_size");

BIN
model/ulala/p_ref_or.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
model/ulala/player.data.pal Normal file

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 771 B

After

Width:  |  Height:  |  Size: 771 B

BIN
model/ulala/u_lb.data Normal file

Binary file not shown.

5
model/ulala/u_lb.data.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_u_lb_data_start __asm("_binary_u_lb_data_start");
extern uint32_t _binary_u_lb_data_end __asm("_binary_u_lb_data_end");
extern uint32_t _binary_u_lb_data_size __asm("_binary_u_lb_data_size");

View File

@ -0,0 +1 @@
ЭНэ=юСBЦЦ/F/Ц/Ъ0ЪPJPЪPЮQЮpNqNqЮrЮrв�N�R�R�в�в�жГVГждVдZеZдкекѕ^і^іоітcу7c7g8g8чXgYkYыZыZяzo{o{я

View File

@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
extern uint32_t _binary_u_lb_data_pal_start __asm("_binary_u_lb_data_pal_start");
extern uint32_t _binary_u_lb_data_pal_end __asm("_binary_u_lb_data_pal_end");
extern uint32_t _binary_u_lb_data_pal_size __asm("_binary_u_lb_data_pal_size");

BIN
model/ulala/u_lb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

72
model/ulala/ulala.mtl Normal file
View File

@ -0,0 +1,72 @@
# Blender 4.1.1 MTL File: 'None'
# www.blender.org
newmtl eye
Ns 200.000000
Ka 1.000000 1.000000 1.000000
Ks 1.000000 1.000000 1.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 2
map_Kd eye.png
map_d eye.png
newmtl ha
Ns 200.000000
Ka 1.000000 1.000000 1.000000
Ks 1.000000 1.000000 1.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 2
map_Kd ha.png
map_d ha.png
newmtl p03b_hair
Ns 200.000000
Ka 1.000000 1.000000 1.000000
Ks 1.000000 1.000000 1.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 2
map_Kd p03b_hair.png
map_d p03b_hair.png
newmtl p_face
Ns 200.000000
Ka 1.000000 1.000000 1.000000
Ks 1.000000 1.000000 1.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 2
map_Kd p_face.png
map_d p_face.png
newmtl p_nomal_mix
Ns 200.000000
Ka 1.000000 1.000000 1.000000
Ks 1.000000 1.000000 1.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 2
map_Kd p_nomal_mix.png
map_d p_nomal_mix.png
newmtl p_ref_or
Ns 200.000000
Ka 1.000000 1.000000 1.000000
Ks 1.000000 1.000000 1.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 2
map_Kd p_ref_or.png
map_d p_ref_or.png
newmtl u_lb
Ns 200.000000
Ka 1.000000 1.000000 1.000000
Ks 1.000000 1.000000 1.000000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
illum 2
map_Kd u_lb.png
map_d u_lb.png

5484
model/ulala/ulala.obj Normal file

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,7 @@ class MapKd:
def parse_material_newmtl(args):
name, = args.split()
yield NewMtl(name)
yield NewMtl(name.replace('-', '_').replace('.', '_'))
def parse_material_mapkd(args):
name, = args.split()

View File

@ -108,13 +108,16 @@ def parse_face(args):
else:
assert False, (len(vertices), args)
def safe(s):
return s.replace('-', '_').replace('.', '_')
def parse_object(args):
name, = args.split()
yield Object(name)
yield Object(safe(name))
def parse_material(args):
name, = args.split()
yield Material(None, name)
yield Material(None, safe(name))
def parse_mtllib(args):
name, = args.split()
@ -151,7 +154,7 @@ def group_by_type(l):
assert current_object is not None
assert current_mtllib is not None
i.lib = current_mtllib.name
assert current_object.name not in materials
assert current_object.name not in materials, (current_object.name, materials)
materials[current_object.name] = i
elif type(i) is Object:
current_object = i

View File

@ -12,8 +12,8 @@ from parse_obj_fixed_point import Quadrilateral
from parse_material import parse_mtl_file
vertex_position_fraction_bits = 6 # 4.6
vertex_normal_fraction_bits = 9 # s.9
vertex_texture_fraction_bits = 14 # s.15
vertex_normal_fraction_bits = 9 # 0.9
vertex_texture_fraction_bits = 14 # 1.14
def convert_fixed_point(fp, fraction_bits):
point = 2 ** fraction_bits

View File

@ -58,6 +58,8 @@ def image_metadata(mapkd):
path = texture_path(mapkd.name)
with Image.open(path) as im:
dimensions = im.size
if im.palette is None:
print(path)
colors = len(im.palette.colors)
return dimensions, colors

Binary file not shown.