Implement Utah teapot model loading
This commit is contained in:
1 parent
f546f27a42
commit
620cf7606b
8 files changed
+303
-48
No files matched your search
@@ -40,6 +40,7 @@ add_executable(demo
|
|||||||
gpu.c
|
gpu.c
|
||||||
linear_alg.c
|
linear_alg.c
|
||||||
main.c
|
main.c
|
||||||
|
model.c
|
||||||
)
|
)
|
||||||
configure_target(demo)
|
configure_target(demo)
|
||||||
target_include_directories(demo PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
|
target_include_directories(demo PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(location = 0) in vec3 frag_colour;
|
layout(location = 0) in vec3 frag_normal;
|
||||||
layout(location = 0) out vec4 out_colour;
|
layout(location = 0) out vec4 out_colour;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
out_colour = vec4(frag_colour, 1.0);
|
out_colour = vec4(frag_normal, 1.0);
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ static void load_buffer(
|
|||||||
vkFreeCommandBuffers(ctx->dev, cmd_pool, 1, &cmd_buf);
|
vkFreeCommandBuffers(ctx->dev, cmd_pool, 1, &cmd_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config)
|
void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config, model_t model)
|
||||||
{
|
{
|
||||||
// Initialise Vulkan instance.
|
// Initialise Vulkan instance.
|
||||||
const VkApplicationInfo app_info = {
|
const VkApplicationInfo app_info = {
|
||||||
@@ -428,7 +428,7 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config)
|
|||||||
.binding = 0,
|
.binding = 0,
|
||||||
.location = 1,
|
.location = 1,
|
||||||
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
||||||
.offset = offsetof(vertex_t, colour),
|
.offset = offsetof(vertex_t, normal),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const VkPipelineVertexInputStateCreateInfo vertex_input_config = {
|
const VkPipelineVertexInputStateCreateInfo vertex_input_config = {
|
||||||
@@ -658,23 +658,24 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config)
|
|||||||
assert(result == VK_SUCCESS);
|
assert(result == VK_SUCCESS);
|
||||||
|
|
||||||
// Set up staging, vertex and index buffers
|
// Set up staging, vertex and index buffers
|
||||||
ctx->index_count = config->index_data_size / sizeof(*config->index_data);
|
const size_t vertex_data_size = model.vertex_count * sizeof(vertex_t);
|
||||||
|
const size_t index_data_size = model.index_count * sizeof(vertex_t);
|
||||||
|
ctx->index_count = model.index_count;
|
||||||
VkBuffer staging_buf;
|
VkBuffer staging_buf;
|
||||||
VkDeviceMemory staging_buf_mem;
|
VkDeviceMemory staging_buf_mem;
|
||||||
const size_t staging_buf_size
|
const size_t staging_buf_size = MAX(vertex_data_size, index_data_size);
|
||||||
= MAX(config->vertex_data_size, config->index_data_size);
|
|
||||||
create_buffer(
|
create_buffer(
|
||||||
ctx, staging_buf_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
ctx, staging_buf_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
&staging_buf, &staging_buf_mem);
|
&staging_buf, &staging_buf_mem);
|
||||||
create_buffer(
|
create_buffer(
|
||||||
ctx, config->vertex_data_size,
|
ctx, vertex_data_size,
|
||||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &ctx->vertex_buf,
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &ctx->vertex_buf,
|
||||||
&ctx->vertex_buf_mem);
|
&ctx->vertex_buf_mem);
|
||||||
create_buffer(
|
create_buffer(
|
||||||
ctx, config->index_data_size,
|
ctx, index_data_size,
|
||||||
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &ctx->index_buf,
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &ctx->index_buf,
|
||||||
&ctx->index_buf_mem);
|
&ctx->index_buf_mem);
|
||||||
@@ -692,11 +693,11 @@ void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config)
|
|||||||
|
|
||||||
// Load vertex and index data
|
// Load vertex and index data
|
||||||
load_buffer(
|
load_buffer(
|
||||||
ctx, ctx->vertex_buf, config->vertex_data, config->vertex_data_size,
|
ctx, ctx->vertex_buf, model.vertices, vertex_data_size, staging_buf,
|
||||||
staging_buf, staging_buf_mem, transient_cmd_pool);
|
staging_buf_mem, transient_cmd_pool);
|
||||||
load_buffer(
|
load_buffer(
|
||||||
ctx, ctx->index_buf, config->index_data, config->index_data_size,
|
ctx, ctx->index_buf, model.indices, index_data_size, staging_buf,
|
||||||
staging_buf, staging_buf_mem, transient_cmd_pool);
|
staging_buf_mem, transient_cmd_pool);
|
||||||
|
|
||||||
// Clean up staging buffer and transient command pool
|
// Clean up staging buffer and transient command pool
|
||||||
vkDestroyCommandPool(ctx->dev, transient_cmd_pool, nullptr);
|
vkDestroyCommandPool(ctx->dev, transient_cmd_pool, nullptr);
|
||||||
|
|||||||
@@ -2,17 +2,13 @@
|
|||||||
#define GPU_H
|
#define GPU_H
|
||||||
|
|
||||||
#include "linear_alg.h"
|
#include "linear_alg.h"
|
||||||
|
#include "model.h"
|
||||||
|
|
||||||
#define GLFW_INCLUDE_VULKAN
|
#define GLFW_INCLUDE_VULKAN
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
#define SWAPCHAIN_IMG_BUFFER_SIZE 4
|
#define SWAPCHAIN_IMG_BUFFER_SIZE 4
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
vec3_t position;
|
|
||||||
vec3_t colour;
|
|
||||||
} vertex_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mat4_t model;
|
mat4_t model;
|
||||||
mat4_t view;
|
mat4_t view;
|
||||||
@@ -53,13 +49,9 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
const char *application_name;
|
const char *application_name;
|
||||||
GLFWwindow *window;
|
GLFWwindow *window;
|
||||||
const vertex_t *vertex_data;
|
|
||||||
size_t vertex_data_size;
|
|
||||||
const uint16_t *index_data;
|
|
||||||
size_t index_data_size;
|
|
||||||
} gpu_config_t;
|
} gpu_config_t;
|
||||||
|
|
||||||
void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config);
|
void gpu_init(gpu_ctx_t *ctx, const gpu_config_t *config, model_t model);
|
||||||
void gpu_cleanup(const gpu_ctx_t *ctx);
|
void gpu_cleanup(const gpu_ctx_t *ctx);
|
||||||
void gpu_render(const gpu_ctx_t *ctx, const mvp_t *mvp);
|
void gpu_render(const gpu_ctx_t *ctx, const mvp_t *mvp);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
|
#include "model.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
@@ -8,17 +9,6 @@
|
|||||||
#define W 800
|
#define W 800
|
||||||
#define H 600
|
#define H 600
|
||||||
|
|
||||||
static const vertex_t vertices[] = {
|
|
||||||
{ { 0.000, 0.612, 0.000 }, { 1, 0, 0 } },
|
|
||||||
{ { -0.500, -0.204, -0.289 }, { 0, 1, 0 } },
|
|
||||||
{ { 0.500, -0.204, -0.289 }, { 0, 0, 1 } },
|
|
||||||
{ { 0.000, -0.204, 0.577 }, { 1, 1, 1 } },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint16_t indices[] = {
|
|
||||||
0, 3, 1, 0, 1, 2, 0, 2, 3, 3, 2, 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AXIS_X,
|
AXIS_X,
|
||||||
AXIS_Y,
|
AXIS_Y,
|
||||||
@@ -54,8 +44,15 @@ key_callback(GLFWwindow *window, int key, int scancode, int action, int mods)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
// Read model from passed path
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "Usage: %s PATH/TO/MODEL\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
model_t model = model_read(argv[1]);
|
||||||
|
|
||||||
// Set up window
|
// Set up window
|
||||||
glfwInit();
|
glfwInit();
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
@@ -70,18 +67,14 @@ int main()
|
|||||||
const gpu_config_t gpu_config = {
|
const gpu_config_t gpu_config = {
|
||||||
.application_name = "Foo",
|
.application_name = "Foo",
|
||||||
.window = window,
|
.window = window,
|
||||||
.vertex_data = vertices,
|
|
||||||
.vertex_data_size = sizeof(vertices),
|
|
||||||
.index_data = indices,
|
|
||||||
.index_data_size = sizeof(indices),
|
|
||||||
};
|
};
|
||||||
gpu_ctx_t gpu;
|
gpu_ctx_t gpu;
|
||||||
gpu_init(&gpu, &gpu_config);
|
gpu_init(&gpu, &gpu_config, model);
|
||||||
|
|
||||||
const vec3_t cam = { 2, 2, -2 };
|
const vec3_t cam = { 0, 4, -4 };
|
||||||
const vec3_t tgt = { 0, 0, 0 };
|
const vec3_t tgt = { 0, 0.5, 0 };
|
||||||
mvp_t mvp = {
|
mvp_t mvp = {
|
||||||
.model = MAT4_SCALE(2),
|
.model = MAT4_SCALE(0.667),
|
||||||
.view = mat4_lookat(cam, tgt, (vec3_t) { 0, 1, 0 }),
|
.view = mat4_lookat(cam, tgt, (vec3_t) { 0, 1, 0 }),
|
||||||
.proj = mat4_perspective((float)W / H, PI / 6, 0.1, 10.0),
|
.proj = mat4_perspective((float)W / H, PI / 6, 0.1, 10.0),
|
||||||
};
|
};
|
||||||
@@ -110,6 +103,7 @@ int main()
|
|||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
gpu_cleanup(&gpu);
|
gpu_cleanup(&gpu);
|
||||||
|
model_cleanup(&model);
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,241 @@
|
|||||||
|
#include "model.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdbit.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 256
|
||||||
|
|
||||||
|
#define FIB_WRAP_COEFF 11400714819323198485LLU
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t *rp;
|
||||||
|
size_t vertex_count;
|
||||||
|
size_t index_count;
|
||||||
|
size_t capacity;
|
||||||
|
size_t buffered;
|
||||||
|
const int fd;
|
||||||
|
uint8_t buffer[BUFFER_SIZE];
|
||||||
|
} read_ctx_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned probe_count;
|
||||||
|
index_t index;
|
||||||
|
bool occupied;
|
||||||
|
} table_node_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
table_node_t *nodes;
|
||||||
|
size_t size;
|
||||||
|
unsigned shift;
|
||||||
|
unsigned max_probe_count;
|
||||||
|
} table_t;
|
||||||
|
|
||||||
|
static uint32_t hash_vertex(vertex_t v)
|
||||||
|
{
|
||||||
|
const uint32_t px = *((uint32_t *)&v.position.x);
|
||||||
|
const uint32_t py = *((uint32_t *)&v.position.y);
|
||||||
|
const uint32_t pz = *((uint32_t *)&v.position.z);
|
||||||
|
const uint32_t nx = *((uint32_t *)&v.normal.x);
|
||||||
|
const uint32_t ny = *((uint32_t *)&v.normal.y);
|
||||||
|
const uint32_t nz = *((uint32_t *)&v.normal.z);
|
||||||
|
return px ^ (py << 1) ^ (pz << 2) ^ (pz << 3) ^ (nx << 4) ^ (ny << 5)
|
||||||
|
^ (nz << 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool vertex_equals(vertex_t v, vertex_t u)
|
||||||
|
{
|
||||||
|
return v.position.x == u.position.x && v.position.y == u.position.y
|
||||||
|
&& v.position.z == u.position.z && v.normal.x == u.normal.x
|
||||||
|
&& v.normal.y == u.normal.y && v.normal.z == u.normal.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned wrap(table_t *table, uint32_t hash)
|
||||||
|
{
|
||||||
|
return (unsigned)((hash * FIB_WRAP_COEFF) >> table->shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool lookup(
|
||||||
|
table_t *table, model_t *model, unsigned base, vertex_t vertex,
|
||||||
|
index_t *index_out)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < table->max_probe_count; ++i) {
|
||||||
|
const unsigned t = (base + i) & (UINT64_MAX >> table->shift);
|
||||||
|
const table_node_t *node = table->nodes + t;
|
||||||
|
if (!node->occupied)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const vertex_t node_vertex = model->vertices[node->index];
|
||||||
|
if (vertex_equals(vertex, node_vertex)) {
|
||||||
|
*index_out = node->index;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insert(table_t *table, unsigned base, index_t index)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < table->size; ++i) {
|
||||||
|
const unsigned t = (base + i) & (UINT64_MAX >> table->shift);
|
||||||
|
table_node_t *node = table->nodes + t;
|
||||||
|
|
||||||
|
if (!node->occupied) {
|
||||||
|
node->occupied = true;
|
||||||
|
node->probe_count = i;
|
||||||
|
node->index = index;
|
||||||
|
if (i > table->max_probe_count)
|
||||||
|
table->max_probe_count = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->probe_count < i) {
|
||||||
|
const unsigned node_probe_count = node->probe_count;
|
||||||
|
node->probe_count = i;
|
||||||
|
i = node_probe_count;
|
||||||
|
const index_t node_index = node->index;
|
||||||
|
node->index = index;
|
||||||
|
index = node_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static index_t handle_vertex(table_t *table, model_t *model, vertex_t vertex)
|
||||||
|
{
|
||||||
|
index_t index;
|
||||||
|
const unsigned base = wrap(table, hash_vertex(vertex));
|
||||||
|
const bool exists = lookup(table, model, base, vertex, &index);
|
||||||
|
if (exists)
|
||||||
|
return index;
|
||||||
|
index = model->vertex_count;
|
||||||
|
model->vertices[model->vertex_count++] = vertex;
|
||||||
|
insert(table, base, index);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t read_byte(read_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->rp >= ctx->buffer + ctx->buffered) {
|
||||||
|
const ssize_t res = read(ctx->fd, ctx->buffer, BUFFER_SIZE);
|
||||||
|
assert(res != -1);
|
||||||
|
ctx->buffered = (size_t)res;
|
||||||
|
ctx->rp = ctx->buffer;
|
||||||
|
}
|
||||||
|
return *ctx->rp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t read_triangle_count(read_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
size_t triangle_count = 0;
|
||||||
|
while (1) {
|
||||||
|
const uint8_t b = read_byte(ctx);
|
||||||
|
if (isdigit(b)) {
|
||||||
|
triangle_count = 10 * triangle_count + b - '0';
|
||||||
|
} else {
|
||||||
|
assert(b == '\n');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return triangle_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float read_float(read_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
bool negative = false;
|
||||||
|
float value = 0, digit_div = 0;
|
||||||
|
while (1) {
|
||||||
|
const uint8_t b = read_byte(ctx);
|
||||||
|
if (b == '-') {
|
||||||
|
assert(value == 0);
|
||||||
|
negative = true;
|
||||||
|
} else if (b == '.') {
|
||||||
|
digit_div = 10;
|
||||||
|
} else if (isdigit(b)) {
|
||||||
|
if (digit_div == 0) {
|
||||||
|
value = 10 * value + (b - '0');
|
||||||
|
} else {
|
||||||
|
value += (float)(b - '0') / digit_div;
|
||||||
|
digit_div *= 10;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(b == ' ' || b == '\n');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (negative ? -1 : 1) * value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static vec3_t read_vec3(read_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
const float x = read_float(ctx);
|
||||||
|
const float y = read_float(ctx);
|
||||||
|
const float z = read_float(ctx);
|
||||||
|
return (vec3_t) { x, y, z };
|
||||||
|
}
|
||||||
|
|
||||||
|
static vertex_t read_vertex(read_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
const vec3_t position = read_vec3(ctx);
|
||||||
|
const vec3_t normal = read_vec3(ctx);
|
||||||
|
return (vertex_t) { position, normal };
|
||||||
|
}
|
||||||
|
|
||||||
|
model_t model_read(const char *path)
|
||||||
|
{
|
||||||
|
read_ctx_t ctx = { .fd = open(path, O_RDONLY), .rp = ctx.buffer };
|
||||||
|
assert(ctx.fd != -1);
|
||||||
|
|
||||||
|
const size_t triangle_count = read_triangle_count(&ctx);
|
||||||
|
const size_t index_count = 3 * triangle_count;
|
||||||
|
|
||||||
|
model_t model = {
|
||||||
|
.indices = malloc(index_count * sizeof(index_t)),
|
||||||
|
.index_count = index_count,
|
||||||
|
.vertices = malloc(index_count * sizeof(vertex_t)),
|
||||||
|
};
|
||||||
|
assert(model.vertices != nullptr);
|
||||||
|
assert(model.indices != nullptr);
|
||||||
|
|
||||||
|
table_t table = { .max_probe_count = 0 };
|
||||||
|
table.size = stdc_bit_ceil((size_t)(1.5 * index_count));
|
||||||
|
table.shift = 64 - stdc_trailing_zeros(table.size);
|
||||||
|
table.nodes = calloc(table.size, sizeof(table_node_t));
|
||||||
|
assert(table.nodes != nullptr);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < index_count; ++i) {
|
||||||
|
const vertex_t vertex = read_vertex(&ctx);
|
||||||
|
index_t index = handle_vertex(&table, &model, vertex);
|
||||||
|
model.indices[i] = index;
|
||||||
|
|
||||||
|
// Skip newline after each triangle
|
||||||
|
if (i % 3 == 2) {
|
||||||
|
const uint8_t b = read_byte(&ctx);
|
||||||
|
assert(b == '\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shrink vertex buffer down to needed size
|
||||||
|
model.vertices
|
||||||
|
= realloc(model.vertices, model.vertex_count * sizeof(vertex_t));
|
||||||
|
assert(model.vertices != nullptr);
|
||||||
|
|
||||||
|
free(table.nodes);
|
||||||
|
close(ctx.fd);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
void model_cleanup(model_t *m)
|
||||||
|
{
|
||||||
|
free(m->vertices);
|
||||||
|
free(m->indices);
|
||||||
|
m->vertices = nullptr;
|
||||||
|
m->indices = nullptr;
|
||||||
|
m->vertex_count = m->index_count = 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef MODEL_H
|
||||||
|
#define MODEL_H
|
||||||
|
|
||||||
|
#include "linear_alg.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef uint16_t index_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vec3_t position;
|
||||||
|
vec3_t normal;
|
||||||
|
} vertex_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vertex_t *vertices;
|
||||||
|
index_t *indices;
|
||||||
|
size_t vertex_count;
|
||||||
|
size_t index_count;
|
||||||
|
} model_t;
|
||||||
|
|
||||||
|
model_t model_read(const char *path);
|
||||||
|
void model_cleanup(model_t *m);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(location = 0) in vec3 pos;
|
layout(location = 0) in vec3 position;
|
||||||
layout(location = 1) in vec3 colour;
|
layout(location = 1) in vec3 normal;
|
||||||
|
|
||||||
layout(location = 0) out vec3 frag_colour;
|
layout(location = 0) out vec3 frag_normal;
|
||||||
|
|
||||||
layout(push_constant) uniform MVP {
|
layout(push_constant) uniform MVP {
|
||||||
mat4 model;
|
mat4 model;
|
||||||
@@ -12,6 +12,6 @@ layout(push_constant) uniform MVP {
|
|||||||
} mvp;
|
} mvp;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = mvp.proj * mvp.view * mvp.model * vec4(pos, 1.0);
|
gl_Position = mvp.proj * mvp.view * mvp.model * vec4(position, 1.0);
|
||||||
frag_colour = colour;
|
frag_normal = normal;
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user