Load bones, bone indices and weights into model
This commit is contained in:
1 parent
955f606fb5
commit
2e1a604d7b
5 files changed
+145
-74
No files matched your search
@@ -1,6 +1,8 @@
|
|||||||
#ifndef LINEAR_ALG_H
|
#ifndef LINEAR_ALG_H
|
||||||
#define LINEAR_ALG_H
|
#define LINEAR_ALG_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#define PI 3.14159265358979323846264
|
#define PI 3.14159265358979323846264
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -15,6 +17,10 @@ typedef struct {
|
|||||||
vec4_t x, y, z, w;
|
vec4_t x, y, z, w;
|
||||||
} mat4_t;
|
} mat4_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t x, y, z, w;
|
||||||
|
} u16_vec4_t;
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#define MAT4_ID \
|
#define MAT4_ID \
|
||||||
(mat4_t) { \
|
(mat4_t) { \
|
||||||
|
|||||||
@@ -16,9 +16,19 @@ model_t model_init(size_t vertex_count, size_t index_count)
|
|||||||
|
|
||||||
void model_cleanup(model_t *m)
|
void model_cleanup(model_t *m)
|
||||||
{
|
{
|
||||||
free(m->vertices);
|
if (m->vertices != nullptr) {
|
||||||
free(m->indices);
|
free(m->vertices);
|
||||||
m->vertices = nullptr;
|
m->vertices = nullptr;
|
||||||
m->indices = nullptr;
|
m->vertex_count = 0;
|
||||||
m->vertex_count = m->index_count = 0;
|
}
|
||||||
|
if (m->indices != nullptr) {
|
||||||
|
free(m->indices);
|
||||||
|
m->indices = nullptr;
|
||||||
|
m->index_count = 0;
|
||||||
|
}
|
||||||
|
if (m->bones != nullptr) {
|
||||||
|
free(m->bones);
|
||||||
|
m->bones = nullptr;
|
||||||
|
m->bone_count = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -11,13 +11,24 @@ typedef uint16_t index_t;
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
vec3_t position;
|
vec3_t position;
|
||||||
vec3_t normal;
|
vec3_t normal;
|
||||||
|
u16_vec4_t bones;
|
||||||
|
vec4_t weights;
|
||||||
} vertex_t;
|
} vertex_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t parent;
|
||||||
|
vec3_t translation;
|
||||||
|
vec4_t rotation;
|
||||||
|
vec3_t scale;
|
||||||
|
} bone_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
vertex_t *vertices;
|
vertex_t *vertices;
|
||||||
index_t *indices;
|
index_t *indices;
|
||||||
|
bone_t *bones;
|
||||||
size_t vertex_count;
|
size_t vertex_count;
|
||||||
size_t index_count;
|
size_t index_count;
|
||||||
|
size_t bone_count;
|
||||||
} model_t;
|
} model_t;
|
||||||
|
|
||||||
model_t model_init(size_t vertex_count, size_t index_count);
|
model_t model_init(size_t vertex_count, size_t index_count);
|
||||||
|
|||||||
+112
-68
@@ -5,6 +5,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -72,7 +73,7 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t normals;
|
uint32_t normals;
|
||||||
uint32_t positions;
|
uint32_t positions;
|
||||||
uint32_t bones;
|
uint32_t bone_indices;
|
||||||
uint32_t weights;
|
uint32_t weights;
|
||||||
uint32_t indices;
|
uint32_t indices;
|
||||||
} mesh_t;
|
} mesh_t;
|
||||||
@@ -83,22 +84,19 @@ typedef struct {
|
|||||||
uint32_t joint_count;
|
uint32_t joint_count;
|
||||||
} skin_t;
|
} skin_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t parent;
|
|
||||||
vec3_t translation;
|
|
||||||
vec4_t rotation;
|
|
||||||
vec3_t scale;
|
|
||||||
} joint_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t view;
|
uint32_t view;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
|
component_type_t component;
|
||||||
|
accessor_type_t type;
|
||||||
} accessor_t;
|
} accessor_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
accessor_t normals;
|
accessor_t normals;
|
||||||
accessor_t positions;
|
accessor_t positions;
|
||||||
|
accessor_t bone_indices;
|
||||||
|
accessor_t weights;
|
||||||
accessor_t indices;
|
accessor_t indices;
|
||||||
} accessors_t;
|
} accessors_t;
|
||||||
|
|
||||||
@@ -111,6 +109,8 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
view_t normals;
|
view_t normals;
|
||||||
view_t positions;
|
view_t positions;
|
||||||
|
view_t bone_indices;
|
||||||
|
view_t weights;
|
||||||
view_t indices;
|
view_t indices;
|
||||||
} views_t;
|
} views_t;
|
||||||
|
|
||||||
@@ -120,9 +120,13 @@ typedef struct {
|
|||||||
} gltf_info_member_t;
|
} gltf_info_member_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
bone_t *bones;
|
||||||
gltf_info_member_t normals;
|
gltf_info_member_t normals;
|
||||||
gltf_info_member_t positions;
|
gltf_info_member_t positions;
|
||||||
|
gltf_info_member_t bone_indices;
|
||||||
|
gltf_info_member_t weights;
|
||||||
gltf_info_member_t indices;
|
gltf_info_member_t indices;
|
||||||
|
size_t vertex_count, index_count, bone_count;
|
||||||
} gltf_info_t;
|
} gltf_info_t;
|
||||||
|
|
||||||
static void *map_file(const char *path)
|
static void *map_file(const char *path)
|
||||||
@@ -343,6 +347,10 @@ static mesh_t read_mesh_primitives(const uint8_t **p)
|
|||||||
mesh.normals = read_uint(p);
|
mesh.normals = read_uint(p);
|
||||||
} else if (strcmp("POSITION", buffer) == 0) {
|
} else if (strcmp("POSITION", buffer) == 0) {
|
||||||
mesh.positions = read_uint(p);
|
mesh.positions = read_uint(p);
|
||||||
|
} else if (strcmp("JOINTS_0", buffer) == 0) {
|
||||||
|
mesh.bone_indices = read_uint(p);
|
||||||
|
} else if (strcmp("WEIGHTS_0", buffer) == 0) {
|
||||||
|
mesh.weights = read_uint(p);
|
||||||
} else {
|
} else {
|
||||||
skip_value(p);
|
skip_value(p);
|
||||||
}
|
}
|
||||||
@@ -436,7 +444,7 @@ static skin_t read_skins(const uint8_t *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void read_joint_children(
|
static void read_joint_children(
|
||||||
const uint8_t **p, skin_t skin, joint_t joints[MAX_JOINT_COUNT],
|
const uint8_t **p, skin_t skin, bone_t bones[MAX_JOINT_COUNT],
|
||||||
uint32_t parent)
|
uint32_t parent)
|
||||||
{
|
{
|
||||||
assert(**p == '[');
|
assert(**p == '[');
|
||||||
@@ -450,8 +458,8 @@ static void read_joint_children(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert(j < skin.joint_count);
|
assert(j < skin.joint_count);
|
||||||
assert(joints[j].parent == UINT32_MAX);
|
assert(bones[j].parent == UINT32_MAX);
|
||||||
joints[j].parent = parent;
|
bones[j].parent = parent;
|
||||||
|
|
||||||
if (**p == ',')
|
if (**p == ',')
|
||||||
++(*p);
|
++(*p);
|
||||||
@@ -460,12 +468,12 @@ static void read_joint_children(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
read_joints(const uint8_t *p, skin_t skin, joint_t joints[MAX_JOINT_COUNT])
|
read_joints(const uint8_t *p, skin_t skin, bone_t bones[MAX_JOINT_COUNT])
|
||||||
{
|
{
|
||||||
char buffer[MAX_STRING_SIZE];
|
char buffer[MAX_STRING_SIZE];
|
||||||
|
|
||||||
for (uint32_t i = 0; i < skin.joint_count; ++i)
|
for (uint32_t i = 0; i < skin.joint_count; ++i)
|
||||||
joints[i].parent = UINT32_MAX;
|
bones[i].parent = UINT32_MAX;
|
||||||
|
|
||||||
assert(*p == '[');
|
assert(*p == '[');
|
||||||
++p;
|
++p;
|
||||||
@@ -492,13 +500,13 @@ read_joints(const uint8_t *p, skin_t skin, joint_t joints[MAX_JOINT_COUNT])
|
|||||||
++p;
|
++p;
|
||||||
|
|
||||||
if (strcmp("children", buffer) == 0)
|
if (strcmp("children", buffer) == 0)
|
||||||
read_joint_children(&p, skin, joints, j);
|
read_joint_children(&p, skin, bones, j);
|
||||||
else if (strcmp("translation", buffer) == 0)
|
else if (strcmp("translation", buffer) == 0)
|
||||||
joints[j].translation = read_vec3(&p);
|
bones[j].translation = read_vec3(&p);
|
||||||
else if (strcmp("rotation", buffer) == 0)
|
else if (strcmp("rotation", buffer) == 0)
|
||||||
joints[j].rotation = read_vec4(&p);
|
bones[j].rotation = read_vec4(&p);
|
||||||
else if (strcmp("scale", buffer) == 0)
|
else if (strcmp("scale", buffer) == 0)
|
||||||
joints[j].scale = read_vec3(&p);
|
bones[j].scale = read_vec3(&p);
|
||||||
else
|
else
|
||||||
skip_value(&p);
|
skip_value(&p);
|
||||||
|
|
||||||
@@ -512,6 +520,14 @@ read_joints(const uint8_t *p, skin_t skin, joint_t joints[MAX_JOINT_COUNT])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static component_type_t read_component_type(const uint8_t **p)
|
||||||
|
{
|
||||||
|
const uint32_t component = read_uint(p);
|
||||||
|
assert(component >= COMPONENT_TYPE_S8);
|
||||||
|
assert(component <= COMPONENT_TYPE_F32);
|
||||||
|
return (component_type_t)component;
|
||||||
|
}
|
||||||
|
|
||||||
static accessor_type_t read_accessor_type(const uint8_t **p)
|
static accessor_type_t read_accessor_type(const uint8_t **p)
|
||||||
{
|
{
|
||||||
char buffer[MAX_STRING_SIZE];
|
char buffer[MAX_STRING_SIZE];
|
||||||
@@ -528,8 +544,7 @@ static accessor_type_t read_accessor_type(const uint8_t **p)
|
|||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static accessor_t read_accessor(
|
static accessor_t read_accessor(const uint8_t **p)
|
||||||
const uint8_t **p, component_type_t component_type, accessor_type_t type)
|
|
||||||
{
|
{
|
||||||
char buffer[MAX_STRING_SIZE];
|
char buffer[MAX_STRING_SIZE];
|
||||||
accessor_t accessor = {};
|
accessor_t accessor = {};
|
||||||
@@ -549,9 +564,9 @@ static accessor_t read_accessor(
|
|||||||
else if (strcmp("count", buffer) == 0)
|
else if (strcmp("count", buffer) == 0)
|
||||||
accessor.count = read_uint(p);
|
accessor.count = read_uint(p);
|
||||||
else if (strcmp("componentType", buffer) == 0)
|
else if (strcmp("componentType", buffer) == 0)
|
||||||
assert(read_uint(p) == component_type);
|
accessor.component = read_component_type(p);
|
||||||
else if (strcmp("type", buffer) == 0)
|
else if (strcmp("type", buffer) == 0)
|
||||||
assert(read_accessor_type(p) == type);
|
accessor.type = read_accessor_type(p);
|
||||||
else if (strcmp("sparse", buffer) == 0)
|
else if (strcmp("sparse", buffer) == 0)
|
||||||
assert(false); // Sparse accessors are not supported
|
assert(false); // Sparse accessors are not supported
|
||||||
else
|
else
|
||||||
@@ -571,19 +586,18 @@ static accessors_t read_accessors(const uint8_t *p, mesh_t mesh)
|
|||||||
assert(*p == '[');
|
assert(*p == '[');
|
||||||
++p;
|
++p;
|
||||||
for (uint32_t i = 0; *p != ']'; ++i) {
|
for (uint32_t i = 0; *p != ']'; ++i) {
|
||||||
if (i == mesh.normals) {
|
if (i == mesh.normals)
|
||||||
accessors.normals
|
accessors.normals = read_accessor(&p);
|
||||||
= read_accessor(&p, COMPONENT_TYPE_F32, ACCESSOR_TYPE_VEC3);
|
else if (i == mesh.positions)
|
||||||
} else if (i == mesh.positions) {
|
accessors.positions = read_accessor(&p);
|
||||||
accessors.positions
|
else if (i == mesh.bone_indices)
|
||||||
= read_accessor(&p, COMPONENT_TYPE_F32, ACCESSOR_TYPE_VEC3);
|
accessors.bone_indices = read_accessor(&p);
|
||||||
} else if (i == mesh.indices) {
|
else if (i == mesh.weights)
|
||||||
accessors.indices = read_accessor(
|
accessors.weights = read_accessor(&p);
|
||||||
&p, COMPONENT_TYPE_U16, ACCESSOR_TYPE_SCALAR);
|
else if (i == mesh.indices)
|
||||||
} else {
|
accessors.indices = read_accessor(&p);
|
||||||
|
else
|
||||||
skip_value(&p);
|
skip_value(&p);
|
||||||
}
|
|
||||||
|
|
||||||
if (*p == ',')
|
if (*p == ',')
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
@@ -632,6 +646,10 @@ static views_t read_views(const uint8_t *p, accessors_t accessors)
|
|||||||
views.normals = read_view(&p);
|
views.normals = read_view(&p);
|
||||||
else if (i == accessors.positions.view)
|
else if (i == accessors.positions.view)
|
||||||
views.positions = read_view(&p);
|
views.positions = read_view(&p);
|
||||||
|
else if (i == accessors.bone_indices.view)
|
||||||
|
views.bone_indices = read_view(&p);
|
||||||
|
else if (i == accessors.weights.view)
|
||||||
|
views.weights = read_view(&p);
|
||||||
else if (i == accessors.indices.view)
|
else if (i == accessors.indices.view)
|
||||||
views.indices = read_view(&p);
|
views.indices = read_view(&p);
|
||||||
else
|
else
|
||||||
@@ -643,9 +661,23 @@ static views_t read_views(const uint8_t *p, accessors_t accessors)
|
|||||||
|
|
||||||
if (accessors.normals.view == accessors.positions.view)
|
if (accessors.normals.view == accessors.positions.view)
|
||||||
views.positions = views.normals;
|
views.positions = views.normals;
|
||||||
|
|
||||||
|
assert(views.normals.len != 0);
|
||||||
|
assert(views.positions.len != 0);
|
||||||
|
assert(views.bone_indices.len != 0);
|
||||||
|
assert(views.weights.len != 0);
|
||||||
|
assert(views.indices.len != 0);
|
||||||
return views;
|
return views;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gltf_info_member_t info_member(accessor_t accessor, view_t view)
|
||||||
|
{
|
||||||
|
return (gltf_info_member_t) {
|
||||||
|
.len = view.stride == 0 ? view.len : accessor.count * view.stride,
|
||||||
|
.offset = view.offset + accessor.offset,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static gltf_info_t read_json(const uint8_t *json)
|
static gltf_info_t read_json(const uint8_t *json)
|
||||||
{
|
{
|
||||||
char buffer[MAX_STRING_SIZE];
|
char buffer[MAX_STRING_SIZE];
|
||||||
@@ -692,38 +724,60 @@ static gltf_info_t read_json(const uint8_t *json)
|
|||||||
|
|
||||||
const mesh_t mesh = read_meshes(meshes_json);
|
const mesh_t mesh = read_meshes(meshes_json);
|
||||||
const skin_t skin = read_skins(skins_json);
|
const skin_t skin = read_skins(skins_json);
|
||||||
joint_t joints[MAX_JOINT_COUNT] = {};
|
bone_t *bones = calloc(skin.joint_count, sizeof(bone_t));
|
||||||
read_joints(nodes_json, skin, joints);
|
assert(bones != nullptr);
|
||||||
|
read_joints(nodes_json, skin, bones);
|
||||||
|
|
||||||
const accessors_t accessors = read_accessors(accessors_json, mesh);
|
const accessors_t accessors = read_accessors(accessors_json, mesh);
|
||||||
const views_t views = read_views(views_json, accessors);
|
const views_t views = read_views(views_json, accessors);
|
||||||
|
|
||||||
// Assume indices are in their own buffer view
|
// Verify data types
|
||||||
assert(views.indices.stride == 0);
|
assert(
|
||||||
|
accessors.normals.component == COMPONENT_TYPE_F32
|
||||||
|
&& accessors.normals.type == ACCESSOR_TYPE_VEC3);
|
||||||
|
assert(
|
||||||
|
accessors.positions.component == COMPONENT_TYPE_F32
|
||||||
|
&& accessors.positions.type == ACCESSOR_TYPE_VEC3);
|
||||||
|
assert(
|
||||||
|
accessors.bone_indices.component == COMPONENT_TYPE_U16
|
||||||
|
&& accessors.bone_indices.type == ACCESSOR_TYPE_VEC4);
|
||||||
|
assert(
|
||||||
|
accessors.weights.component == COMPONENT_TYPE_F32
|
||||||
|
&& accessors.weights.type == ACCESSOR_TYPE_VEC4);
|
||||||
|
assert(
|
||||||
|
accessors.indices.component == COMPONENT_TYPE_U16
|
||||||
|
&& accessors.indices.type == ACCESSOR_TYPE_SCALAR);
|
||||||
|
|
||||||
|
// Ensure the vertex count is consistent
|
||||||
|
assert(
|
||||||
|
accessors.positions.count == accessors.normals.count
|
||||||
|
&& accessors.positions.count == accessors.bone_indices.count
|
||||||
|
&& accessors.positions.count == accessors.weights.count);
|
||||||
|
|
||||||
return (gltf_info_t) {
|
return (gltf_info_t) {
|
||||||
.normals = {
|
.bones = bones,
|
||||||
.offset = views.normals.offset + accessors.normals.offset,
|
.positions = info_member(accessors.positions, views.positions),
|
||||||
.len = accessors.normals.count * sizeof(vec3_t),
|
.normals = info_member(accessors.normals, views.normals),
|
||||||
},
|
.bone_indices
|
||||||
.positions = {
|
= info_member(accessors.bone_indices, views.bone_indices),
|
||||||
.offset = views.positions.offset + accessors.positions.offset,
|
.weights = info_member(accessors.weights, views.weights),
|
||||||
.len = accessors.positions.count * sizeof(vec3_t),
|
.indices = info_member(accessors.indices, views.indices),
|
||||||
},
|
.vertex_count = accessors.positions.count,
|
||||||
.indices = {
|
.index_count = accessors.indices.count,
|
||||||
.offset = views.indices.offset + accessors.indices.offset,
|
.bone_count = skin.joint_count,
|
||||||
.len = views.indices.len,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void load_vertices(
|
static void load_vertices(
|
||||||
vertex_t *restrict dest, const vec3_t *restrict positions,
|
vertex_t *restrict dest, const vec3_t *restrict positions,
|
||||||
const vec3_t *restrict normals, size_t count)
|
const vec3_t *restrict normals, const u16_vec4_t *restrict bones,
|
||||||
|
const vec4_t *restrict weights, size_t count)
|
||||||
{
|
{
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
dest[i].position = positions[i];
|
dest[i].position = positions[i];
|
||||||
dest[i].normal = normals[i];
|
dest[i].normal = normals[i];
|
||||||
|
dest[i].bones = bones[i];
|
||||||
|
dest[i].weights = weights[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -743,17 +797,6 @@ model_t model_format_glb_read(const char *path)
|
|||||||
offset += sizeof(chunk_hdr_t);
|
offset += sizeof(chunk_hdr_t);
|
||||||
const gltf_info_t info = read_json(file + offset);
|
const gltf_info_t info = read_json(file + offset);
|
||||||
|
|
||||||
// Check glTF info for validity
|
|
||||||
assert(info.positions.len == info.normals.len);
|
|
||||||
assert(info.positions.offset != info.normals.offset);
|
|
||||||
if (info.positions.offset < info.normals.offset) {
|
|
||||||
const uint32_t pos_end = info.positions.offset + info.positions.len;
|
|
||||||
assert(pos_end <= info.normals.offset);
|
|
||||||
} else {
|
|
||||||
const uint32_t norm_end = info.normals.offset + info.normals.len;
|
|
||||||
assert(norm_end <= info.positions.offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read binary chunk header
|
// Read binary chunk header
|
||||||
offset += json_hdr->len;
|
offset += json_hdr->len;
|
||||||
assert(offset != len);
|
assert(offset != len);
|
||||||
@@ -765,13 +808,14 @@ model_t model_format_glb_read(const char *path)
|
|||||||
assert(offset == len);
|
assert(offset == len);
|
||||||
|
|
||||||
// Load data from binary chunk into model
|
// Load data from binary chunk into model
|
||||||
const size_t vertex_count = info.positions.len / sizeof(vec3_t);
|
model_t model = model_init(info.vertex_count, info.index_count);
|
||||||
const size_t index_count = info.indices.len / sizeof(index_t);
|
model.bone_count = info.bone_count;
|
||||||
model_t model = model_init(vertex_count, index_count);
|
model.bones = info.bones;
|
||||||
const vec3_t *positions
|
load_vertices(
|
||||||
= (const vec3_t *)(bin_data + info.positions.offset);
|
model.vertices, (const vec3_t *)(bin_data + info.positions.offset),
|
||||||
const vec3_t *normals = (const vec3_t *)(bin_data + info.normals.offset);
|
(const vec3_t *)(bin_data + info.normals.offset),
|
||||||
load_vertices(model.vertices, positions, normals, vertex_count);
|
(const u16_vec4_t *)(bin_data + info.bone_indices.offset),
|
||||||
|
(const vec4_t *)(bin_data + info.weights.offset), info.vertex_count);
|
||||||
memcpy(model.indices, bin_data + info.indices.offset, info.indices.len);
|
memcpy(model.indices, bin_data + info.indices.offset, info.indices.len);
|
||||||
|
|
||||||
munmap(file, len);
|
munmap(file, len);
|
||||||
|
|||||||
+1
-1
@@ -184,7 +184,7 @@ static vertex_t read_vertex(read_ctx_t *ctx)
|
|||||||
{
|
{
|
||||||
const vec3_t position = read_vec3(ctx);
|
const vec3_t position = read_vec3(ctx);
|
||||||
const vec3_t normal = read_vec3(ctx);
|
const vec3_t normal = read_vec3(ctx);
|
||||||
return (vertex_t) { position, normal };
|
return (vertex_t) { position, normal, {}, {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
model_t model_format_utah_read(const char *path)
|
model_t model_format_utah_read(const char *path)
|
||||||
|
|||||||
Reference in new issue
Block a user