pumpkin_man: use blender.py exporter

This commit is contained in:
Zack Buhman 2025-10-29 13:25:17 -05:00
parent 0e850b4caa
commit 02e191eec0
25 changed files with 731 additions and 79705 deletions

View File

@ -1,7 +1,7 @@
OPT = -O0
CFLAGS += -g
CFLAGS += -Wall -Werror -Wfatal-errors
CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable
CFLAGS += $(shell pkg-config --cflags libdrm)
LDFLAGS += $(shell pkg-config --libs libdrm) -lm

View File

@ -19,17 +19,22 @@
#include "3d_registers_bits.h"
#include "command_processor.h"
#define pumpkin_Material_002 0
#define pumpkin_pumpkin 0
#define pumpkin_belt 0
#include "../model/model.h"
#include "../model/vec.h"
#include "../model/blender_model.h"
#include "../model/pumpkin/pumpkin.h"
#define PI (3.14159274101257324219f)
#define PI_2 (PI * 2.0f)
#define I_PI_2 (1.0f / (PI_2))
struct reloc_indices {
int colorbuffer;
int zbuffer;
int vertexbuffer;
int texturebuffer;
int flush;
};
static inline uint32_t rreg(void * rmmio, uint32_t offset)
{
uint32_t value = *((volatile uint32_t *)(((uintptr_t)rmmio) + offset));
@ -43,7 +48,7 @@ static inline void wreg(void * rmmio, uint32_t offset, uint32_t value)
asm volatile ("" ::: "memory");
}
static void * read_file(const char * filename)
static void * read_file(const char * filename, int * out_size)
{
int fd = open(filename, O_RDONLY);
if (fd == -1) {
@ -74,6 +79,9 @@ static void * read_file(const char * filename)
close(fd);
if (out_size != NULL)
*out_size = size;
return buf;
}
@ -98,7 +106,7 @@ union u32_f32 {
static union u32_f32 ib[16384];
int _3d_clear(int ix)
int _3d_clear(int ix, const struct reloc_indices * reloc_indices)
{
//////////////////////////////////////////////////////////////////////////////
// ZB
@ -118,7 +126,7 @@ int _3d_clear(int ix)
T0V(ZB_DEPTHOFFSET, 0);
T3(_NOP, 0);
ib[ix++].u32 = 1 * 4; // index into relocs array
ib[ix++].u32 = reloc_indices->zbuffer * 4; // index into relocs array
T0V(ZB_DEPTHPITCH
, ZB_DEPTHPITCH__DEPTHPITCH(1600 >> 2)
@ -126,7 +134,7 @@ int _3d_clear(int ix)
| ZB_DEPTHPITCH__DEPTHMICROTILE(1)
);
T3(_NOP, 0);
ib[ix++].u32 = 1 * 4; // index into relocs array
ib[ix++].u32 = reloc_indices->zbuffer * 4; // index into relocs array
//////////////////////////////////////////////////////////////////////////////
// RS
@ -209,35 +217,6 @@ int _3d_clear(int ix)
T0V(VAP_OUT_VTX_FMT_1
, 0x0);
//////////////////////////////////////////////////////////////////////////////
// AOS
//////////////////////////////////////////////////////////////////////////////
T3(_3D_LOAD_VBPNTR, (4 - 1));
ib[ix++].u32 // VAP_VTX_NUM_ARRAYS
= VAP_VTX_NUM_ARRAYS__VTX_NUM_ARRAYS(2)
| VAP_VTX_NUM_ARRAYS__VC_FORCE_PREFETCH(1)
;
ib[ix++].u32 // VAP_VTX_AOS_ATTR01
= VAP_VTX_AOS_ATTR__VTX_AOS_COUNT0(3)
| VAP_VTX_AOS_ATTR__VTX_AOS_STRIDE0(5)
| VAP_VTX_AOS_ATTR__VTX_AOS_COUNT1(2)
| VAP_VTX_AOS_ATTR__VTX_AOS_STRIDE1(5)
;
ib[ix++].u32 // VAP_VTX_AOS_ADDR0
= (4 * 0);
ib[ix++].u32 // VAP_VTX_AOS_ADDR1
= (4 * 3);
// VAP_VTX_AOS_ADDR is an absolute address in VRAM. However, DRM_RADEON_CS
// modifies this to be an offset relative to the GEM buffer handles given via
// NOP:
T3(_NOP, 0);
ib[ix++].u32 = 3 * 4; // index into relocs array for VAP_VTX_AOS_ADDR0
T3(_NOP, 0);
ib[ix++].u32 = 3 * 4; // index into relocs array for VAP_VTX_AOS_ADDR1
//////////////////////////////////////////////////////////////////////////////
// GA_US
//////////////////////////////////////////////////////////////////////////////
@ -278,7 +257,9 @@ int _3d_clear(int ix)
return ix;
}
int _3d_object(int ix, float theta, int vertex_count)
int _3d_object(int ix, const struct reloc_indices * reloc_indices,
float theta,
int vertex_count)
{
//////////////////////////////////////////////////////////////////////////////
// ZB
@ -298,7 +279,7 @@ int _3d_object(int ix, float theta, int vertex_count)
T0V(ZB_DEPTHOFFSET, 0);
T3(_NOP, 0);
ib[ix++].u32 = 1 * 4; // index into relocs array
ib[ix++].u32 = reloc_indices->zbuffer * 4; // index into relocs array
T0V(ZB_DEPTHPITCH
, ZB_DEPTHPITCH__DEPTHPITCH(1600 >> 2)
@ -306,7 +287,7 @@ int _3d_object(int ix, float theta, int vertex_count)
| ZB_DEPTHPITCH__DEPTHMICROTILE(1)
);
T3(_NOP, 0);
ib[ix++].u32 = 1 * 4; // index into relocs array
ib[ix++].u32 = reloc_indices->zbuffer * 4; // index into relocs array
//////////////////////////////////////////////////////////////////////////////
// RS
@ -372,7 +353,7 @@ int _3d_object(int ix, float theta, int vertex_count)
);
T3(_NOP, 0);
ib[ix++].u32 = 2 * 4; // index into relocs array
ib[ix++].u32 = reloc_indices->texturebuffer * 4; // index into relocs array
//////////////////////////////////////////////////////////////////////////////
// VAP_PVS
@ -491,6 +472,35 @@ int _3d_object(int ix, float theta, int vertex_count)
| US_CODE_ADDR__END_ADDR(fragment_shader_instructions - 1)
);
//////////////////////////////////////////////////////////////////////////////
// AOS
//////////////////////////////////////////////////////////////////////////////
T3(_3D_LOAD_VBPNTR, (4 - 1));
ib[ix++].u32 // VAP_VTX_NUM_ARRAYS
= VAP_VTX_NUM_ARRAYS__VTX_NUM_ARRAYS(2)
| VAP_VTX_NUM_ARRAYS__VC_FORCE_PREFETCH(1)
;
ib[ix++].u32 // VAP_VTX_AOS_ATTR01
= VAP_VTX_AOS_ATTR__VTX_AOS_COUNT0(3)
| VAP_VTX_AOS_ATTR__VTX_AOS_STRIDE0(5)
| VAP_VTX_AOS_ATTR__VTX_AOS_COUNT1(2)
| VAP_VTX_AOS_ATTR__VTX_AOS_STRIDE1(5)
;
ib[ix++].u32 // VAP_VTX_AOS_ADDR0
= (4 * 0);
ib[ix++].u32 // VAP_VTX_AOS_ADDR1
= (4 * 3);
// VAP_VTX_AOS_ADDR is an absolute address in VRAM. However, DRM_RADEON_CS
// modifies this to be an offset relative to the GEM buffer handles given via
// NOP:
T3(_NOP, 0);
ib[ix++].u32 = reloc_indices->vertexbuffer * 4; // index into relocs array for VAP_VTX_AOS_ADDR0
T3(_NOP, 0);
ib[ix++].u32 = reloc_indices->vertexbuffer * 4; // index into relocs array for VAP_VTX_AOS_ADDR1
//////////////////////////////////////////////////////////////////////////////
// 3D_DRAW
//////////////////////////////////////////////////////////////////////////////
@ -509,7 +519,7 @@ int _3d_object(int ix, float theta, int vertex_count)
return ix;
}
int indirect_buffer(float theta, int vertex_count)
int indirect_buffer(float theta, int vertex_count, const struct reloc_indices * reloc_indices)
{
int ix = 0;
@ -753,7 +763,7 @@ int indirect_buffer(float theta, int vertex_count)
, 0x00000000 // value replaced by kernel from relocs
);
T3(_NOP, 0);
ib[ix++].u32 = 0 * 4; // index into relocs array
ib[ix++].u32 = reloc_indices->colorbuffer * 4; // index into relocs array
T0V(RB3D_COLORPITCH0
, RB3D_COLORPITCH__COLORPITCH(1600 >> 1)
@ -762,7 +772,7 @@ int indirect_buffer(float theta, int vertex_count)
// The COLORPITCH NOP is ignored/not applied due to
// RADEON_CS_KEEP_TILING_FLAGS, but is still required.
T3(_NOP, 0);
ib[ix++].u32 = 0 * 4; // index into relocs array
ib[ix++].u32 = reloc_indices->colorbuffer * 4; // index into relocs array
//////////////////////////////////////////////////////////////////////////////
// SC
@ -825,8 +835,8 @@ int indirect_buffer(float theta, int vertex_count)
// DRAW
//////////////////////////////////////////////////////////////////////////////
ix = _3d_clear(ix);
ix = _3d_object(ix, theta, vertex_count);
ix = _3d_clear(ix, reloc_indices);
ix = _3d_object(ix, reloc_indices, theta, vertex_count);
//////////////////////////////////////////////////////////////////////////////
// padding
@ -896,31 +906,93 @@ int fill_vertexbuffer(void * ptr, int size)
int ix = 0;
const struct model * model = &pumpkin_model;
const int object_count = (sizeof (objects)) / (sizeof (objects[0]));
for (int object_ix = 0; object_ix < object_count; object_ix++) {
const struct mesh * mesh = objects[object_ix].mesh;
for (int i = 0; i < model->object_count; i++) {
const struct object * object = model->object[i];
for (int j = 0; j < object->triangle_count; j++) {
const union triangle * triangle = &object->triangle[j];
for (int k = 0; k < 3; k++) {
const struct vec3 * p = &model->position[triangle->v[k].position];
const struct vec2 * t = &model->texture[triangle->v[k].texture];
assert(mesh->uv_layers_length == 1);
const vec2 * uvmap = mesh->uv_layers[0];
const vec3 * position = mesh->position;
for (int polygon_ix = 0; polygon_ix < mesh->polygons_length; polygon_ix++) {
assert((ix + 5) < (size / 4));
int uv_ix = polygon_ix * 3;
const struct polygon * polygon = &mesh->polygons[polygon_ix];
const vec3 * ap = &position[polygon->a];
const vec3 * bp = &position[polygon->b];
const vec3 * cp = &position[polygon->c];
const vec2 * at = &uvmap[uv_ix + 0];
const vec2 * bt = &uvmap[uv_ix + 1];
const vec2 * ct = &uvmap[uv_ix + 2];
fptr[ix++] = p->x;
fptr[ix++] = p->y;
fptr[ix++] = p->z;
fptr[ix++] = t->x;
fptr[ix++] = t->y;
}
assert((ix + (5 * 3)) < (size / 4));
fptr[ix++] = ap->x;
fptr[ix++] = ap->y;
fptr[ix++] = ap->z;
fptr[ix++] = at->x;
fptr[ix++] = 1.0f - at->y;
fptr[ix++] = bp->x;
fptr[ix++] = bp->y;
fptr[ix++] = bp->z;
fptr[ix++] = bt->x;
fptr[ix++] = 1.0f - bt->y;
fptr[ix++] = cp->x;
fptr[ix++] = cp->y;
fptr[ix++] = cp->z;
fptr[ix++] = ct->x;
fptr[ix++] = 1.0f - ct->y;
}
}
asm volatile("" ::: "memory");
return ix;
}
static int * load_textures(int fd, int * length_out)
{
int * texture_handles = NULL;
const int materials_length = (sizeof (materials)) / (sizeof (materials[0]));
texture_handles = (int *)calloc((sizeof (int)), materials_length);
char buf[512];
for (int i = 0; i < materials_length; i++) {
assert(strlen(materials[i].name) < 300);
snprintf(buf, (sizeof (buf)), "../model/pumpkin/textures/%s.data", materials[i].name);
int size = 0;
void * file_ptr = read_file(buf, &size);
assert(file_ptr != NULL);
assert(size > 0);
printf("load %s %d\n", buf, size);
assert(materials[i].texture_id < materials_length);
assert(texture_handles[materials[i].texture_id] == 0);
void * buffer_ptr;
int handle = create_colorbuffer(fd, size, &buffer_ptr);
for (int i = 0; i < size / 4; i++) {
((uint32_t *)buffer_ptr)[i] = ((uint32_t *)file_ptr)[i];
}
asm volatile ("" ::: "memory");
free(file_ptr);
munmap(buffer_ptr, size);
texture_handles[materials[i].texture_id] = handle;
}
assert(length_out != NULL);
*length_out = materials_length;
return texture_handles;
}
int main()
{
//////////////////////////////////////////////////////////////////////////////
@ -948,7 +1020,6 @@ int main()
int colorbuffer_handle[2];
int zbuffer_handle;
int texturebuffer_handle;
int vertexbuffer_handle;
int flush_handle;
@ -968,54 +1039,10 @@ int main()
int vertexbuffer_length = fill_vertexbuffer(vertexbuffer_ptr, vertexbuffer_size);
munmap(vertexbuffer_ptr, vertexbuffer_size);
fprintf(stderr, "vertexbuffer length %d\n", vertexbuffer_length);
int vertex_count = vertexbuffer_length / 5;
// texture
{
const int texture_size = 1024 * 1024 * 4;
struct drm_radeon_gem_create args = {
.size = texture_size,
.alignment = 4096,
.handle = 0,
.initial_domain = 4, // RADEON_GEM_DOMAIN_VRAM
.flags = 4
};
ret = drmCommandWriteRead(fd, DRM_RADEON_GEM_CREATE, &args, (sizeof (struct drm_radeon_gem_create)));
if (ret != 0) {
perror("drmCommandWriteRead(DRM_RADEON_GEM_CREATE)");
}
assert(args.handle != 0);
texturebuffer_handle = args.handle;
struct drm_radeon_gem_mmap mmap_args = {
.handle = texturebuffer_handle,
.offset = 0,
.size = texture_size,
};
ret = drmCommandWriteRead(fd, DRM_RADEON_GEM_MMAP, &mmap_args, (sizeof (struct drm_radeon_gem_mmap)));
if (ret != 0) {
perror("drmCommandWriteRead(DRM_RADEON_GEM_MMAP)");
}
void * texturebuffer_ptr = mmap(0, mmap_args.size, PROT_READ|PROT_WRITE, MAP_SHARED,
fd, mmap_args.addr_ptr);
assert(texturebuffer_ptr != MAP_FAILED);
// copy texture
void * texture_buf = read_file("../texture/butterfly_1024x1024_argb8888.data");
assert(texture_buf != NULL);
for (int i = 0; i < texture_size / 4; i++) {
((uint32_t*)texturebuffer_ptr)[i] = ((uint32_t*)texture_buf)[i];
}
asm volatile ("" ::: "memory");
free(texture_buf);
munmap(texturebuffer_ptr, texture_size);
}
int texture_handles_length = 0;
int * texture_handles = load_textures(fd, &texture_handles_length);
// flush
{
@ -1041,45 +1068,59 @@ int main()
0, // RADEON_CS_RING_GFX
};
int ib_dwords = indirect_buffer(0, vertex_count);
int colorbuffer_ix = 0;
float theta = 0;
while (true) {
struct drm_radeon_cs_reloc relocs[] = {
{
.handle = colorbuffer_handle[colorbuffer_ix],
.read_domains = 4, // RADEON_GEM_DOMAIN_VRAM
.write_domain = 4, // RADEON_GEM_DOMAIN_VRAM
.flags = 8,
},
{
int relocs_length = 4 + texture_handles_length;
struct drm_radeon_cs_reloc * relocs = calloc((sizeof (struct drm_radeon_cs_reloc)), relocs_length);
int relocs_size = (sizeof (struct drm_radeon_cs_reloc)) * relocs_length;
const struct reloc_indices reloc_indices = {
.colorbuffer = 0,
.zbuffer = 1,
.vertexbuffer = 2,
.texturebuffer = 3,
.flush = relocs_length - 1,
};
relocs[reloc_indices.zbuffer] = (struct drm_radeon_cs_reloc){
.handle = zbuffer_handle,
.read_domains = 4, // RADEON_GEM_DOMAIN_VRAM
.write_domain = 4, // RADEON_GEM_DOMAIN_VRAM
.flags = 8,
},
{
.handle = texturebuffer_handle,
.read_domains = 4, // RADEON_GEM_DOMAIN_VRAM
.write_domain = 4, // RADEON_GEM_DOMAIN_VRAM
.flags = 8,
},
{
};
relocs[reloc_indices.vertexbuffer] = (struct drm_radeon_cs_reloc){
.handle = vertexbuffer_handle,
.read_domains = 4, // RADEON_GEM_DOMAIN_VRAM
.write_domain = 4, // RADEON_GEM_DOMAIN_VRAM
.flags = 8,
},
{
};
relocs[reloc_indices.flush] = (struct drm_radeon_cs_reloc){
.handle = flush_handle,
.read_domains = 2, // RADEON_GEM_DOMAIN_GTT
.write_domain = 2, // RADEON_GEM_DOMAIN_GTT
.flags = 0,
}
};
for (int i = 0; i < texture_handles_length; i++) {
relocs[reloc_indices.texturebuffer + i] = (struct drm_radeon_cs_reloc){
.handle = texture_handles[i],
.read_domains = 4, // RADEON_GEM_DOMAIN_VRAM
.write_domain = 4, // RADEON_GEM_DOMAIN_VRAM
.flags = 8,
};
}
while (true) {
relocs[reloc_indices.colorbuffer] = (struct drm_radeon_cs_reloc){
.handle = colorbuffer_handle[colorbuffer_ix],
.read_domains = 4, // RADEON_GEM_DOMAIN_VRAM
.write_domain = 4, // RADEON_GEM_DOMAIN_VRAM
.flags = 8,
};
int ib_dwords = indirect_buffer(theta, vertex_count, &reloc_indices);
struct drm_radeon_cs_chunk chunks[3] = {
{
.chunk_id = RADEON_CHUNK_ID_IB,
@ -1088,7 +1129,7 @@ int main()
},
{
.chunk_id = RADEON_CHUNK_ID_RELOCS,
.length_dw = (sizeof (relocs)) / (sizeof (uint32_t)),
.length_dw = relocs_size / (sizeof (uint32_t)),
.chunk_data = (uint64_t)(uintptr_t)relocs,
},
{
@ -1147,9 +1188,6 @@ int main()
// next state
theta += 0.01f;
colorbuffer_ix = (colorbuffer_ix + 1) & 1;
// next indirect buffer
ib_dwords = indirect_buffer(theta, vertex_count);
}
/*

View File

@ -57,12 +57,14 @@ union u32_f32 {
float f32;
};
static union u32_f32 ib[16384];
static union u32_f32 ib[16384 * 20];
int indirect_buffer(int ix,
int width,
int height,
int colorbuffer_reloc_ix,
int texture_width,
int texture_height,
int texturebuffer_reloc_ix,
int shader_ix,
bool intermediate)
@ -479,9 +481,9 @@ int indirect_buffer(int ix,
T0V(TX_ENABLE
, TX_ENABLE__TEX_0_ENABLE__ENABLE);
T0V(TX_FILTER0_0
//, TX_FILTER0__CLAMP_S(2) // clamp to (0.0, 1.0)
//| TX_FILTER0__CLAMP_T(2) // clamp to (0.0, 1.0)
, TX_FILTER0__MAG_FILTER__POINT
, TX_FILTER0__CLAMP_S(2) // clamp to (0.0, 1.0)
| TX_FILTER0__CLAMP_T(2) // clamp to (0.0, 1.0)
| TX_FILTER0__MAG_FILTER__POINT
| TX_FILTER0__MIN_FILTER__POINT
);
T0V(TX_FILTER1_0
@ -489,8 +491,8 @@ int indirect_buffer(int ix,
);
T0V(TX_BORDER_COLOR_0, 0);
T0V(TX_FORMAT0_0
, TX_FORMAT0__TXWIDTH(128 - 1)
| TX_FORMAT0__TXHEIGHT(128 - 1)
, TX_FORMAT0__TXWIDTH(texture_width - 1)
| TX_FORMAT0__TXHEIGHT(texture_height - 1)
);
T0V(TX_FORMAT1_0
@ -563,8 +565,8 @@ int indirect_buffer(int ix,
}
const float fragment_consts[] = {
-1.0f / 128.f, 1.0f / 128.f, -2.0f / 128.f, 2.0f / 128.f,
-3.0f / 128.f, 3.0f / 128.f, 0.0f, 0.0f,
-1.0f / 1024.f, 1.0f / 1024.f, -2.0f / 1024.f, 2.0f / 1024.f,
-3.0f / 1024.f, 3.0f / 1024.f, 0.0f, 0.0f,
0.24609375 + 0.021484375, 0.205078125, 0.1171875, 0.0439453125,
};
int fragment_consts_length = (sizeof (fragment_consts)) / (sizeof (fragment_consts[0]));
@ -689,7 +691,7 @@ int main()
int ret;
int fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
const int texture_size = 128 * 128 * 4;
const int texture_size = 1024 * 1024 * 4;
const int colorbuffer_size = 1600 * 1200 * 4;
int intermediate_handle[2];
int colorbuffer_handle;
@ -705,7 +707,7 @@ int main()
intermediate_handle[1] = create_colorbuffer(fd, texture_size, NULL);
{
void * texture_buf = read_file("../texture/butterfly_128x128_argb8888.data");
void * texture_buf = read_file("../texture/butterfly_1024x1024_argb8888.data");
assert(texture_buf != NULL);
for (int i = 0; i < texture_size / 4; i++) {
((uint32_t*)texturebuffer_ptr)[i] = ((uint32_t*)texture_buf)[i];
@ -774,26 +776,30 @@ int main()
0, // RADEON_CS_RING_GFX
};
int image_dim = 1024;
int ib_dwords = 0;
{
int texturebuffer_reloc_ix = 1;
int colorbuffer_reloc_ix = 2;
int shader_ix = 0;
ib_dwords = indirect_buffer(ib_dwords,
128, 128,
image_dim, image_dim,
colorbuffer_reloc_ix,
image_dim, image_dim,
texturebuffer_reloc_ix,
shader_ix,
true);
}
for (int i = 0; i < 10; i++) {
for (int i = 0; i < 40; i++) {
{
int texturebuffer_reloc_ix = 2;
int colorbuffer_reloc_ix = 3;
int shader_ix = 1;
ib_dwords = indirect_buffer(ib_dwords,
128, 128,
image_dim, image_dim,
colorbuffer_reloc_ix,
image_dim, image_dim,
texturebuffer_reloc_ix,
shader_ix,
true);
@ -803,8 +809,9 @@ int main()
int colorbuffer_reloc_ix = 2;
int shader_ix = 0;
ib_dwords = indirect_buffer(ib_dwords,
128, 128,
image_dim, image_dim,
colorbuffer_reloc_ix,
image_dim, image_dim,
texturebuffer_reloc_ix,
shader_ix,
true);
@ -817,6 +824,7 @@ int main()
ib_dwords = indirect_buffer(ib_dwords,
1600, 1200,
colorbuffer_reloc_ix,
image_dim, image_dim,
texturebuffer_reloc_ix,
shader_ix,
false);

54
model/blender_model.h Normal file
View File

@ -0,0 +1,54 @@
#pragma once
struct polygon {
int a, b, c;
int material_index;
};
struct mesh_material {
const int width;
const int height;
const int texture_id;
};
struct edge {
int a; // vertices index
int b; // vertices index
};
struct edge_polygon {
struct edge edge;
struct {
int a;
int b;
} polygon_index; // polygon indices
};
struct mesh {
const vec3 * position;
const int position_length;
const vec3 * normal;
const int normal_length;
const vec3 * polygon_normal;
const int polygon_normal_length;
const struct polygon * polygons;
const int polygons_length;
const vec2 ** uv_layers;
const int uv_layers_length;
const struct mesh_material * materials;
const int materials_length;
const struct edge_polygon * edge_polygons;
const int edge_polygons_length;
};
struct object {
const struct mesh * mesh;
vec3 scale;
vec4 rotation;
vec3 location;
};
struct material {
const char * name;
const int texture_id;
};

View File

@ -1,15 +1,5 @@
#pragma once
struct vec3 {
float x;
float y;
float z;
};
struct vec2 {
float x;
float y;
};
typedef struct vec3 vertex_position;
typedef struct vec2 vertex_texture;
typedef struct vec3 vertex_normal;

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 KiB

19
model/vec.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
typedef struct vec4 {
float x;
float y;
float z;
float w;
} vec4;
typedef struct vec3 {
float x;
float y;
float z;
} vec3;
typedef struct vec2 {
float x;
float y;
} vec2;

302
tools/blender.py Normal file
View File

@ -0,0 +1,302 @@
import bpy
from os import path
from collections import defaultdict
import bmesh
triangulate_meshes = True
def sprint(*text):
screen = bpy.data.screens['Scripting']
for area in screen.areas:
if area.type != "CONSOLE":
continue
override = {'screen': screen, 'area': area}
with bpy.context.temp_override(**override):
bpy.ops.console.scrollback_append(text=" ".join(map(str, text)))
print = sprint
def render_vec3(v):
return f"{{{v.x:.6f}, {v.y:.6f}, {v.z:.6f}}}"
def render_vec2(v):
return f"{{{v.x:.6f}, {v.y:.6f}}}"
def render_mesh_vertices(f, name, vertices):
f.write(f"static const vec3 {name}_position[] = {{\n")
for vertex in vertices:
f.write(f" {render_vec3(vertex.co)},\n")
f.write("};\n\n")
def render_vertex_normals(f, name, vertices):
f.write(f"static const vec3 {name}_normal[] = {{\n")
for vertex in vertices:
f.write(f" {render_vec3(vertex.normal)},\n")
f.write("};\n\n")
def render_polygon_normals(f, name, polygon_normals):
f.write(f"static const vec3 {name}_polygon_normal[] = {{\n")
for normal in polygon_normals:
f.write(f" {render_vec3(normal.vector)},\n")
f.write("};\n\n")
def sort_by_material(polygons):
return sorted(polygons, key=lambda p: p.material_index)
def render_polygons(f, name, polygons):
f.write(f"static const struct polygon {name}_polygons[] = {{\n")
uv_ix = 0
for i, polygon in enumerate(polygons):
if triangulate_meshes:
assert len(polygon.vertices) == 3
if len(polygon.vertices) not in {3, 4}:
f.write(f" {{-1, -1, -1, -1, -1, -1}}, // {{{s}}}\n")
continue
if triangulate_meshes:
indices = [*polygon.vertices, polygon.material_index]
elif len(polygon.vertices) == 4:
indices = [*polygon.vertices, polygon.material_index, uv_ix]
else:
indices = [*polygon.vertices, -1, polygon.material_index, uv_ix]
uv_ix += len(polygon.vertices)
s = ", ".join(map(str, indices))
f.write(f" {{{s}}},\n")
f.write("};\n\n")
def render_polygon_edge_pairs(f, name, polygons):
by_edge = defaultdict(list)
for i, polygon in enumerate(polygons):
for edge in polygon.edge_keys:
by_edge[frozenset(edge)].append(i)
f.write(f"static const struct edge_polygon {name}_edge_polygons[] = {{\n")
if all(len(p) == 2 for p in by_edge.values()):
for edge, polygons in by_edge.items():
edges = sorted(list(edge))
assert len(edges) == 2, edges
assert len(polygons) == 2, polygons
f.write(f" {{{{{edges[0]}, {edges[1]}}}, {{{polygons[0]}, {polygons[1]}}}}},\n")
else:
f.write("// non-solid polygon\n")
f.write("};\n\n")
def render_uv_map(f, name, name2, uvm):
f.write(f"static const vec2 {name}_{name2}_uvmap[] = {{\n")
for uv in uvm:
s = render_vec2(uv.vector)
f.write(f" {s},\n")
f.write("};\n\n")
def render_location(f, location):
s = render_vec3(location)
f.write(f" .location = {s},\n")
def render_scale(f, scale):
s = render_vec3(scale)
f.write(f" .scale = {s},\n")
def render_rotation_axis_angle(f, r):
r = f"{{{r[1]:.6f}, {r[2]:.6f}, {r[3]:.6f}, {r[0]:.6f}}}"
f.write(f" .rotation = {r}, // rotation_axis_angle (XYZ T)\n")
def render_rotation_quaternion(f, r):
r = f"{{{r[1]:.6f}, {r[2]:.6f}, {r[3]:.6f}, {r[0]:.6f}}}"
f.write(f" .rotation = {r}, // quaternion (XYZW)\n")
def render_mesh(f, name, mesh):
f.write(f"static const vec2 * {name}_uv_layers[] = {{\n")
for layer_name in mesh.uv_layers.keys():
f.write(f" {name}_{translate_name(layer_name)}_uvmap,\n");
f.write( "};\n\n")
f.write(f"static const struct mesh {name} = {{\n")
f.write(f" .position = {name}_position,\n")
f.write(f" .position_length = (sizeof ({name}_position)) / (sizeof ({name}_position[0])),\n")
f.write(f" .normal = {name}_normal,\n")
f.write(f" .normal_length = (sizeof ({name}_normal)) / (sizeof ({name}_normal[0])),\n")
f.write(f" .polygon_normal = {name}_polygon_normal,\n")
f.write(f" .polygon_normal_length = (sizeof ({name}_polygon_normal)) / (sizeof ({name}_polygon_normal[0])),\n")
f.write(f" .polygons = {name}_polygons,\n")
f.write(f" .polygons_length = (sizeof ({name}_polygons)) / (sizeof ({name}_polygons[0])),\n")
f.write(f" .uv_layers = {name}_uv_layers,\n")
f.write(f" .uv_layers_length = (sizeof ({name}_uv_layers)) / (sizeof ({name}_uv_layers[0])),\n")
f.write(f" .materials = {name}_materials,\n")
f.write(f" .materials_length = (sizeof ({name}_materials)) / (sizeof ({name}_materials[0])),\n")
f.write(f" .edge_polygons = {name}_edge_polygons,\n");
f.write(f" .edge_polygons_length = (sizeof ({name}_edge_polygons)) / (sizeof ({name}_edge_polygons[0])),\n")
f.write( "};\n\n")
def translate_name(name):
return name.replace(".", "_").replace("-", "_").replace(" ", "_")
def mesh_objects(collections):
objects = set()
for collection in collections:
if collection.hide_render:
continue
for object in collection.objects:
assert object.name not in objects, object.name
objects.add(object.name)
if object.hide_render:
continue
if object.type == "MESH":
yield object
def mesh_meshes(collections):
mesh_names = set()
for object in mesh_objects(collections):
mesh = object.data
if mesh.name in mesh_names:
continue
mesh_names.add(mesh.name)
if not triangulate_meshes:
yield mesh.name, mesh
else:
# triangulate
tri_mesh = mesh.copy()
bm = bmesh.new()
bm.from_mesh(mesh)
bmesh.ops.triangulate(bm, faces=bm.faces[:])
bm.to_mesh(tri_mesh)
bm.free()
yield mesh.name, tri_mesh
bpy.data.meshes.remove(tri_mesh)
def get_texture(material):
assert material.use_nodes, material.name
for node in material.node_tree.nodes:
if node.type == "TEX_IMAGE":
return node.image
_offset = 0
texture_ids = {}
prefix = "textures_"
def get_texture_id(image):
global _offset
global texture_ids
if image.name in texture_ids:
value = texture_ids[image.name]
return value
value = _offset
texture_ids[image.name] = value
width, height = image.size
#_offset += width * height * 2
_offset += 1
return value
def texture_data_name(name):
name = path.splitext(name)[0]
name = translate_name(name)
return f"{prefix}{name}_data"
def render_mesh_materials(f, name, materials):
f.write(f"static const struct mesh_material {name}_materials[] = {{\n")
print("materials", materials)
for material in materials:
image = get_texture(material)
print("image", image)
if image is not None:
f.write(f" {{ // {material.name} {image.name}\n")
width, height = image.size
texture_id = get_texture_id(image)
f.write(f" .width = {width},\n")
f.write(f" .height = {height},\n")
f.write(f" .texture_id = {texture_id},\n")
f.write(" },\n")
else:
f.write(" {},\n")
f.write("};\n")
def render_materials(f):
f.write("static const struct material materials[] = {\n")
for image_name, texture_id in sorted(texture_ids.items(), key=lambda i: i[1]):
name = texture_data_name(image_name)
f.write(" {\n")
#f.write(f" .start = (void *)&_binary_{name}_start,\n")
#f.write(f" .size = (int)&_binary_{name}_size,\n")
f.write(f" .name = \"{image_name}\",\n")
f.write(f" .texture_id = {texture_id},\n")
f.write(" },\n")
f.write("};\n\n");
def export_meshes(f):
for mesh_name, mesh in mesh_meshes(bpy.data.collections):
#mesh.vertex_normals
#mesh.vertex_colors
#mesh.vertices
#mesh.uv_layers
#mesh.polygons
#mesh.polygon_normals
#mesh.name
mesh_name = "mesh_" + translate_name(mesh_name)
render_mesh_vertices(f, mesh_name, mesh.vertices)
for layer_name, layer in mesh.uv_layers.items():
render_uv_map(f, mesh_name, translate_name(layer_name), layer.uv)
render_vertex_normals(f, mesh_name, mesh.vertices)
render_polygon_normals(f, mesh_name, mesh.polygon_normals)
render_polygons(f, mesh_name, mesh.polygons)
render_polygon_edge_pairs(f, mesh_name, mesh.polygons)
render_mesh_materials(f, mesh_name, mesh.materials)
render_mesh(f, mesh_name, mesh)
#mesh.polygons[0].vertices
# [0, 1, 3, 2]
# v = mesh.vertices[0]
# v.normal
# v.index
def mesh_objects_sorted(objects):
def key(o):
return (o.data.name, o.name)
return sorted(mesh_objects(objects), key=key)
def export_objects(f):
f.write("static const struct object objects[] = {\n")
for object in mesh_objects_sorted(bpy.data.collections):
#object.rotation_mode = 'AXIS_ANGLE'
#object.name
#object.rotation_axis_angle
#object.rotation_euler
#object.location
obj_name = "object_" + translate_name(object.name)
f.write(f" {{ // {obj_name}\n")
obj_mesh_name = "mesh_" + translate_name(object.data.name)
f.write(" ")
f.write(f" .mesh = &{obj_mesh_name},\n")
location, rotation, scale = object.matrix_world.decompose()
f.write(" ")
render_scale(f, scale)
f.write(" ")
render_rotation_quaternion(f, rotation)
f.write(" ")
render_location(f, location)
f.write(" },\n")
f.write("};\n\n")
def export_scene(f):
export_meshes(f)
export_objects(f)
render_materials(f)
home = path.expanduser('~')
with open(path.join(home, "output.h"), "w") as f:
offset = 0
export_scene(f)

9
tools/png_to_data.py Normal file
View File

@ -0,0 +1,9 @@
import sys
from PIL import Image
im = Image.open(sys.argv[1])
im = im.convert("RGBA")
buf = im.tobytes()
with open(sys.argv[2], 'wb') as f:
f.write(buf)