Implement hardware index buffers; some renderer refactoring
Too lazy for detailed comments, read the code
This commit is contained in:
parent
5548b6d65a
commit
a6d0ab565f
24 changed files with 733 additions and 405 deletions
50
src/laser.c
50
src/laser.c
|
@ -13,11 +13,13 @@
|
|||
#include "list.h"
|
||||
#include "stageobjects.h"
|
||||
#include "renderer/api.h"
|
||||
#include "resource/model.h"
|
||||
|
||||
static struct {
|
||||
VertexArray *varr;
|
||||
VertexBuffer *vbuf;
|
||||
ShaderProgram *shader_generic;
|
||||
Model quad_generic;
|
||||
} lasers;
|
||||
|
||||
typedef struct LaserInstancedAttribs {
|
||||
|
@ -54,10 +56,16 @@ void lasers_preload(void) {
|
|||
lasers.varr = r_vertex_array_create();
|
||||
r_vertex_array_set_debug_label(lasers.varr, "Lasers vertex array");
|
||||
r_vertex_array_layout(lasers.varr, sizeof(fmt)/sizeof(VertexAttribFormat), fmt);
|
||||
r_vertex_array_attach_buffer(lasers.varr, r_vertex_buffer_static_models(), 0);
|
||||
r_vertex_array_attach_buffer(lasers.varr, lasers.vbuf, 1);
|
||||
r_vertex_array_attach_vertex_buffer(lasers.varr, r_vertex_buffer_static_models(), 0);
|
||||
r_vertex_array_attach_vertex_buffer(lasers.varr, lasers.vbuf, 1);
|
||||
r_vertex_array_layout(lasers.varr, sizeof(fmt)/sizeof(VertexAttribFormat), fmt);
|
||||
|
||||
lasers.quad_generic.indexed = false;
|
||||
lasers.quad_generic.num_vertices = 4;
|
||||
lasers.quad_generic.offset = 0;
|
||||
lasers.quad_generic.primitive = PRIM_TRIANGLE_STRIP;
|
||||
lasers.quad_generic.vertex_array = lasers.varr;
|
||||
|
||||
lasers.shader_generic = r_shader_get("laser_generic");
|
||||
}
|
||||
|
||||
|
@ -150,6 +158,7 @@ static void draw_laser_curve_specialized(Laser *l) {
|
|||
return;
|
||||
}
|
||||
|
||||
r_shader_ptr(l->shader);
|
||||
r_color(&l->color);
|
||||
r_uniform_sampler("tex", "part/lasercurve");
|
||||
r_uniform_vec2_complex("origin", l->pos);
|
||||
|
@ -158,7 +167,7 @@ static void draw_laser_curve_specialized(Laser *l) {
|
|||
r_uniform_float("width", l->width);
|
||||
r_uniform_float("width_exponent", l->width_exponent);
|
||||
r_uniform_int("span", instances);
|
||||
r_draw(PRIM_TRIANGLE_STRIP, 0, 4, NULL, instances, 0);
|
||||
r_draw_quad_instanced(instances);
|
||||
}
|
||||
|
||||
static void draw_laser_curve_generic(Laser *l) {
|
||||
|
@ -169,6 +178,7 @@ static void draw_laser_curve_generic(Laser *l) {
|
|||
return;
|
||||
}
|
||||
|
||||
r_shader_ptr(lasers.shader_generic);
|
||||
r_color(&l->color);
|
||||
r_uniform_sampler("tex", "part/lasercurve");
|
||||
r_uniform_float("timeshift", timeshift);
|
||||
|
@ -176,46 +186,30 @@ static void draw_laser_curve_generic(Laser *l) {
|
|||
r_uniform_float("width_exponent", l->width_exponent);
|
||||
r_uniform_int("span", instances);
|
||||
|
||||
LaserInstancedAttribs attrs[instances], *aptr = attrs;
|
||||
SDL_RWops *stream = r_vertex_buffer_get_stream(lasers.vbuf);
|
||||
r_vertex_buffer_invalidate(lasers.vbuf);
|
||||
|
||||
for(uint i = 0; i < instances; ++i, ++aptr) {
|
||||
for(uint i = 0; i < instances; ++i) {
|
||||
complex pos = l->prule(l, i * 0.5 + timeshift);
|
||||
complex delta = pos - l->prule(l, i * 0.5 + timeshift - 0.1);
|
||||
|
||||
aptr->pos[0] = creal(pos);
|
||||
aptr->pos[1] = cimag(pos);
|
||||
aptr->delta[0] = creal(delta);
|
||||
aptr->delta[1] = cimag(delta);
|
||||
LaserInstancedAttribs attr;
|
||||
attr.pos[0] = creal(pos);
|
||||
attr.pos[1] = cimag(pos);
|
||||
attr.delta[0] = creal(delta);
|
||||
attr.delta[1] = cimag(delta);
|
||||
SDL_RWwrite(stream, &attr, sizeof(attr), 1);
|
||||
}
|
||||
|
||||
SDL_RWops *stream = r_vertex_buffer_get_stream(lasers.vbuf);
|
||||
SDL_RWseek(stream, 0, RW_SEEK_SET);
|
||||
SDL_RWwrite(stream, &attrs, sizeof(attrs), 1);
|
||||
|
||||
r_draw(PRIM_TRIANGLE_STRIP, 0, 4, NULL, instances, 0);
|
||||
r_draw_model_ptr(&lasers.quad_generic, instances, 0);
|
||||
}
|
||||
|
||||
static void ent_draw_laser(EntityInterface *ent) {
|
||||
Laser *laser = ENT_CAST(ent, Laser);
|
||||
|
||||
if(laser->shader) {
|
||||
// Specialized lasers work with either vertex array,
|
||||
// provided that the static models buffer is attached to it.
|
||||
// We'll only ever draw the first quad, and only care about
|
||||
// attributes 0 and 2 (vec3 position, vec2 uv)
|
||||
|
||||
VertexArray *va = r_vertex_array_current();
|
||||
|
||||
if(va != lasers.varr && va != r_vertex_array_static_models()) {
|
||||
r_vertex_array(lasers.varr);
|
||||
}
|
||||
|
||||
r_shader_ptr(laser->shader);
|
||||
draw_laser_curve_specialized(laser);
|
||||
} else {
|
||||
r_vertex_array(lasers.varr);
|
||||
r_shader_ptr(lasers.shader_generic);
|
||||
draw_laser_curve_generic(laser);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,11 +203,9 @@ static void marisa_laser_renderer_visual(Enemy *renderer, int t, bool render) {
|
|||
Uniform *u_length = r_shader_uniform(shader, "laser_length");
|
||||
Texture *tex0 = get_tex("part/marisa_laser0");
|
||||
Texture *tex1 = get_tex("part/marisa_laser1");
|
||||
VertexArray *varr_saved = r_vertex_array_current();
|
||||
FBPair *fbp_aux = stage_get_fbpair(FBPAIR_FG_AUX);
|
||||
FBPair *fbp_fg = stage_get_fbpair(FBPAIR_FG);
|
||||
|
||||
r_vertex_array(r_vertex_array_static_models());
|
||||
r_shader_ptr(shader);
|
||||
r_uniform_vec4(u_clr0, 0.5, 0.5, 0.5, 0.0);
|
||||
r_uniform_vec4(u_clr1, 0.8, 0.8, 0.8, 0.0);
|
||||
|
@ -265,7 +263,6 @@ static void marisa_laser_renderer_visual(Enemy *renderer, int t, bool render) {
|
|||
}
|
||||
|
||||
r_shader("sprite_default");
|
||||
r_vertex_array(varr_saved);
|
||||
}
|
||||
|
||||
static int marisa_laser_fader(Enemy *e, int t) {
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include "common/state.h"
|
||||
#include "util/glm.h"
|
||||
#include "util/graphics.h"
|
||||
#include "resource/texture.h"
|
||||
#include "resource/sprite.h"
|
||||
|
||||
#define B _r_backend.funcs
|
||||
|
||||
|
@ -377,8 +379,12 @@ UniformType r_uniform_type(Uniform *uniform) {
|
|||
return B.uniform_type(uniform);
|
||||
}
|
||||
|
||||
void r_draw(Primitive prim, uint first, uint count, uint32_t *indices, uint instances, uint base_instance) {
|
||||
B.draw(prim, first, count, indices, instances, base_instance);
|
||||
void r_draw(VertexArray *varr, Primitive prim, uint firstvert, uint count, uint instances, uint base_instance) {
|
||||
B.draw(varr, prim, firstvert, count, instances, base_instance);
|
||||
}
|
||||
|
||||
void r_draw_indexed(VertexArray* varr, Primitive prim, uint firstidx, uint count, uint instances, uint base_instance) {
|
||||
B.draw_indexed(varr, prim, firstidx, count, instances, base_instance);
|
||||
}
|
||||
|
||||
Texture* r_texture_create(const TextureParams *params) {
|
||||
|
@ -520,6 +526,38 @@ SDL_RWops* r_vertex_buffer_get_stream(VertexBuffer *vbuf) {
|
|||
return B.vertex_buffer_get_stream(vbuf);
|
||||
}
|
||||
|
||||
IndexBuffer* r_index_buffer_create(size_t max_elements) {
|
||||
return B.index_buffer_create(max_elements);
|
||||
}
|
||||
|
||||
size_t r_index_buffer_get_capacity(IndexBuffer *ibuf) {
|
||||
return B.index_buffer_get_capacity(ibuf);
|
||||
}
|
||||
|
||||
const char* r_index_buffer_get_debug_label(IndexBuffer *ibuf) {
|
||||
return B.index_buffer_get_debug_label(ibuf);
|
||||
}
|
||||
|
||||
void r_index_buffer_set_debug_label(IndexBuffer *ibuf, const char *label) {
|
||||
B.index_buffer_set_debug_label(ibuf, label);
|
||||
}
|
||||
|
||||
void r_index_buffer_set_offset(IndexBuffer *ibuf, size_t offset) {
|
||||
B.index_buffer_set_offset(ibuf, offset);
|
||||
}
|
||||
|
||||
size_t r_index_buffer_get_offset(IndexBuffer *ibuf) {
|
||||
return B.index_buffer_get_offset(ibuf);
|
||||
}
|
||||
|
||||
void r_index_buffer_add_indices(IndexBuffer *ibuf, uint index_ofs, size_t num_indices, uint indices[num_indices]) {
|
||||
B.index_buffer_add_indices(ibuf, index_ofs, num_indices, indices);
|
||||
}
|
||||
|
||||
void r_index_buffer_destroy(IndexBuffer *ibuf) {
|
||||
B.index_buffer_destroy(ibuf);
|
||||
}
|
||||
|
||||
VertexArray* r_vertex_array_create(void) {
|
||||
return B.vertex_array_create();
|
||||
}
|
||||
|
@ -536,27 +574,26 @@ void r_vertex_array_destroy(VertexArray *varr) {
|
|||
B.vertex_array_destroy(varr);
|
||||
}
|
||||
|
||||
void r_vertex_array_attach_buffer(VertexArray *varr, VertexBuffer *vbuf, uint attachment) {
|
||||
B.vertex_array_attach_buffer(varr, vbuf, attachment);
|
||||
void r_vertex_array_attach_vertex_buffer(VertexArray *varr, VertexBuffer *vbuf, uint attachment) {
|
||||
B.vertex_array_attach_vertex_buffer(varr, vbuf, attachment);
|
||||
}
|
||||
|
||||
VertexBuffer* r_vertex_array_get_attachment(VertexArray *varr, uint attachment) {
|
||||
return B.vertex_array_get_attachment(varr, attachment);
|
||||
VertexBuffer* r_vertex_array_get_vertex_attachment(VertexArray *varr, uint attachment) {
|
||||
return B.vertex_array_get_vertex_attachment(varr, attachment);
|
||||
}
|
||||
|
||||
void r_vertex_array_attach_index_buffer(VertexArray *varr, IndexBuffer *ibuf) {
|
||||
B.vertex_array_attach_index_buffer(varr, ibuf);
|
||||
}
|
||||
|
||||
IndexBuffer* r_vertex_array_get_index_attachment(VertexArray *varr) {
|
||||
return B.vertex_array_get_index_attachment(varr);
|
||||
}
|
||||
|
||||
void r_vertex_array_layout(VertexArray *varr, uint nattribs, VertexAttribFormat attribs[nattribs]) {
|
||||
B.vertex_array_layout(varr, nattribs, attribs);
|
||||
}
|
||||
|
||||
void r_vertex_array(VertexArray *varr) {
|
||||
_r_state_touch_vertex_array();
|
||||
B.vertex_array(varr);
|
||||
}
|
||||
|
||||
VertexArray* r_vertex_array_current(void) {
|
||||
return B.vertex_array_current();
|
||||
}
|
||||
|
||||
void r_vsync(VsyncMode mode) {
|
||||
_r_state_touch_vsync();
|
||||
B.vsync(mode);
|
||||
|
|
|
@ -12,19 +12,18 @@
|
|||
#include "util.h"
|
||||
#include "util/pixmap.h"
|
||||
#include "color.h"
|
||||
#include "resource/resource.h"
|
||||
#include "resource/shader_program.h"
|
||||
#include "resource/texture.h"
|
||||
#include "resource/model.h"
|
||||
#include "resource/sprite.h"
|
||||
#include "common/shader.h"
|
||||
#include "resource/resource.h"
|
||||
|
||||
typedef struct Texture Texture;
|
||||
typedef struct Framebuffer Framebuffer;
|
||||
typedef struct VertexBuffer VertexBuffer;
|
||||
typedef struct VertexArray VertexArray;
|
||||
typedef struct IndexBuffer IndexBuffer;
|
||||
typedef struct ShaderObject ShaderObject;
|
||||
typedef struct ShaderProgram ShaderProgram;
|
||||
typedef struct Sprite Sprite;
|
||||
typedef struct Model Model;
|
||||
|
||||
enum {
|
||||
R_DEBUG_LABEL_SIZE = 128,
|
||||
|
@ -581,7 +580,8 @@ void _r_uniform_sampler_array(const char *uniform, uint offset, uint count, cons
|
|||
) \
|
||||
))(uniform, offset, count, values)
|
||||
|
||||
void r_draw(Primitive prim, uint first, uint count, uint32_t *indices, uint instances, uint base_instance);
|
||||
void r_draw(VertexArray *varr, Primitive prim, uint firstvert, uint count, uint instances, uint base_instance);
|
||||
void r_draw_indexed(VertexArray *varr, Primitive prim, uint firstidx, uint count, uint instances, uint base_instance);
|
||||
|
||||
Texture* r_texture_create(const TextureParams *params) attr_nonnull(1);
|
||||
void r_texture_get_size(Texture *tex, uint mipmap, uint *width, uint *height) attr_nonnull(1);
|
||||
|
@ -620,16 +620,26 @@ void r_vertex_buffer_destroy(VertexBuffer *vbuf) attr_nonnull(1);
|
|||
void r_vertex_buffer_invalidate(VertexBuffer *vbuf) attr_nonnull(1);
|
||||
SDL_RWops* r_vertex_buffer_get_stream(VertexBuffer *vbuf) attr_nonnull(1);
|
||||
|
||||
IndexBuffer* r_index_buffer_create(size_t max_elements);
|
||||
size_t r_index_buffer_get_capacity(IndexBuffer *ibuf) attr_nonnull(1);
|
||||
const char* r_index_buffer_get_debug_label(IndexBuffer *ibuf) attr_nonnull(1);
|
||||
void r_index_buffer_set_debug_label(IndexBuffer *ibuf, const char *label) attr_nonnull(1);
|
||||
void r_index_buffer_set_offset(IndexBuffer *ibuf, size_t offset) attr_nonnull(1);
|
||||
size_t r_index_buffer_get_offset(IndexBuffer *ibuf) attr_nonnull(1);
|
||||
void r_index_buffer_add_indices(IndexBuffer *ibuf, uint index_ofs, size_t num_indices, uint indices[num_indices]) attr_nonnull(1, 4);
|
||||
void r_index_buffer_destroy(IndexBuffer *ibuf) attr_nonnull(1);
|
||||
|
||||
VertexArray* r_vertex_array_create(void);
|
||||
const char* r_vertex_array_get_debug_label(VertexArray *varr) attr_nonnull(1);
|
||||
void r_vertex_array_set_debug_label(VertexArray *varr, const char* label) attr_nonnull(1);
|
||||
void r_vertex_array_destroy(VertexArray *varr) attr_nonnull(1);
|
||||
void r_vertex_array_attach_buffer(VertexArray *varr, VertexBuffer *vbuf, uint attachment) attr_nonnull(1, 2);
|
||||
VertexBuffer* r_vertex_array_get_attachment(VertexArray *varr, uint attachment) attr_nonnull(1);
|
||||
void r_vertex_array_attach_vertex_buffer(VertexArray *varr, VertexBuffer *vbuf, uint attachment) attr_nonnull(1, 2);
|
||||
VertexBuffer* r_vertex_array_get_vertex_attachment(VertexArray *varr, uint attachment) attr_nonnull(1);
|
||||
void r_vertex_array_attach_index_buffer(VertexArray *varr, IndexBuffer *ibuf) attr_nonnull(1);
|
||||
IndexBuffer* r_vertex_array_get_index_attachment(VertexArray *varr) attr_nonnull(1);
|
||||
void r_vertex_array_layout(VertexArray *varr, uint nattribs, VertexAttribFormat attribs[nattribs]) attr_nonnull(1, 3);
|
||||
|
||||
void r_vertex_array(VertexArray *varr) attr_nonnull(1);
|
||||
VertexArray* r_vertex_array_current(void);
|
||||
void r_model_add_static(Model *out_mdl, Primitive prim, size_t num_vertices, GenericModelVertex vertices[num_vertices], uint indices[num_vertices]);
|
||||
|
||||
void r_vsync(VsyncMode mode);
|
||||
VsyncMode r_vsync_current(void);
|
||||
|
@ -664,7 +674,7 @@ void r_state_pop(void);
|
|||
|
||||
void r_draw_quad(void);
|
||||
void r_draw_quad_instanced(uint instances);
|
||||
void r_draw_model_ptr(Model *model) attr_nonnull(1);
|
||||
void r_draw_model_ptr(Model *model, uint instances, uint base_instance) attr_nonnull(1);
|
||||
void r_draw_sprite(const SpriteParams *params) attr_nonnull(1);
|
||||
|
||||
void r_flush_sprites(void);
|
||||
|
@ -774,7 +784,12 @@ void r_clear(ClearBufferFlags flags, const Color *colorval, float depthval) {
|
|||
|
||||
static inline attr_must_inline attr_nonnull(1)
|
||||
void r_draw_model(const char *model) {
|
||||
r_draw_model_ptr(get_resource_data(RES_MODEL, model, RESF_UNSAFE));
|
||||
r_draw_model_ptr(get_resource_data(RES_MODEL, model, RESF_UNSAFE), 0, 0);
|
||||
}
|
||||
|
||||
static inline attr_must_inline attr_nonnull(1)
|
||||
void r_draw_model_instanced(const char *model, uint instances, uint base_instance) {
|
||||
r_draw_model_ptr(get_resource_data(RES_MODEL, model, RESF_UNSAFE), instances, base_instance);
|
||||
}
|
||||
|
||||
static inline attr_must_inline
|
||||
|
|
|
@ -23,7 +23,8 @@ typedef struct RendererFuncs {
|
|||
void (*capabilities)(r_capability_bits_t capbits);
|
||||
r_capability_bits_t (*capabilities_current)(void);
|
||||
|
||||
void (*draw)(Primitive prim, uint first, uint count, uint32_t * indices, uint instances, uint base_instance);
|
||||
void (*draw)(VertexArray *varr, Primitive prim, uint firstvert, uint count, uint instances, uint base_instance);
|
||||
void (*draw_indexed)(VertexArray *varr, Primitive prim, uint firstidx, uint count, uint instances, uint base_instance);
|
||||
|
||||
void (*color4)(float r, float g, float b, float a);
|
||||
const Color* (*color_current)(void);
|
||||
|
@ -90,16 +91,24 @@ typedef struct RendererFuncs {
|
|||
void (*vertex_buffer_invalidate)(VertexBuffer *vbuf);
|
||||
SDL_RWops* (*vertex_buffer_get_stream)(VertexBuffer *vbuf);
|
||||
|
||||
IndexBuffer* (*index_buffer_create)(size_t max_elements);
|
||||
size_t (*index_buffer_get_capacity)(IndexBuffer *ibuf);
|
||||
const char* (*index_buffer_get_debug_label)(IndexBuffer *ibuf);
|
||||
void (*index_buffer_set_debug_label)(IndexBuffer *ibuf, const char *label);
|
||||
void (*index_buffer_set_offset)(IndexBuffer *ibuf, size_t offset);
|
||||
size_t (*index_buffer_get_offset)(IndexBuffer *ibuf);
|
||||
void (*index_buffer_add_indices)(IndexBuffer *ibuf, uint index_ofs, size_t num_indices, uint indices[num_indices]);
|
||||
void (*index_buffer_destroy)(IndexBuffer *ibuf);
|
||||
|
||||
VertexArray* (*vertex_array_create)(void);
|
||||
const char* (*vertex_array_get_debug_label)(VertexArray *varr);
|
||||
void (*vertex_array_set_debug_label)(VertexArray *varr, const char *label);
|
||||
void (*vertex_array_destroy)(VertexArray *varr);
|
||||
void (*vertex_array_layout)(VertexArray *varr, uint nattribs, VertexAttribFormat attribs[nattribs]);
|
||||
void (*vertex_array_attach_buffer)(VertexArray *varr, VertexBuffer *vbuf, uint attachment);
|
||||
VertexBuffer* (*vertex_array_get_attachment)(VertexArray *varr, uint attachment);
|
||||
|
||||
void (*vertex_array)(VertexArray *varr) attr_nonnull(1);
|
||||
VertexArray* (*vertex_array_current)(void);
|
||||
void (*vertex_array_attach_vertex_buffer)(VertexArray *varr, VertexBuffer *vbuf, uint attachment);
|
||||
void (*vertex_array_attach_index_buffer)(VertexArray *varr, IndexBuffer *ibuf);
|
||||
VertexBuffer* (*vertex_array_get_vertex_attachment)(VertexArray *varr, uint attachment);
|
||||
IndexBuffer* (*vertex_array_get_index_attachment)(VertexArray *varr);
|
||||
|
||||
void (*vsync)(VsyncMode mode);
|
||||
VsyncMode (*vsync_current)(void);
|
||||
|
|
|
@ -10,10 +10,13 @@
|
|||
|
||||
#include "models.h"
|
||||
#include "../api.h"
|
||||
#include "resource/model.h"
|
||||
|
||||
static struct {
|
||||
VertexBuffer *vbuf;
|
||||
IndexBuffer *ibuf;
|
||||
VertexArray *varr;
|
||||
Model quad;
|
||||
} _r_models;
|
||||
|
||||
void _r_models_init(void) {
|
||||
|
@ -32,18 +35,21 @@ void _r_models_init(void) {
|
|||
{ { -0.5, 0.5, 0.0 }, { 0, 0, 1 }, { 0, 0 } },
|
||||
};
|
||||
|
||||
_r_models.vbuf = r_vertex_buffer_create(8192 * sizeof(GenericModelVertex), NULL);
|
||||
const size_t max_vertices = 8192;
|
||||
|
||||
_r_models.vbuf = r_vertex_buffer_create(max_vertices * sizeof(GenericModelVertex), NULL);
|
||||
r_vertex_buffer_set_debug_label(_r_models.vbuf, "Static models vertex buffer");
|
||||
|
||||
_r_models.ibuf = r_index_buffer_create(max_vertices);
|
||||
r_index_buffer_set_debug_label(_r_models.ibuf, "Static models index buffer");
|
||||
|
||||
_r_models.varr = r_vertex_array_create();
|
||||
r_vertex_array_set_debug_label(_r_models.varr, "Static models vertex array");
|
||||
r_vertex_array_layout(_r_models.varr, 3, fmt);
|
||||
r_vertex_array_attach_buffer(_r_models.varr, _r_models.vbuf, 0);
|
||||
r_vertex_array_attach_vertex_buffer(_r_models.varr, _r_models.vbuf, 0);
|
||||
r_vertex_array_attach_index_buffer(_r_models.varr, _r_models.ibuf);
|
||||
|
||||
SDL_RWops *stream = r_vertex_buffer_get_stream(_r_models.vbuf);
|
||||
SDL_RWwrite(stream, quad, sizeof(quad), 1);
|
||||
|
||||
r_vertex_array(_r_models.varr);
|
||||
r_model_add_static(&_r_models.quad, PRIM_TRIANGLE_STRIP, 4, quad, NULL);
|
||||
}
|
||||
|
||||
void _r_models_shutdown(void) {
|
||||
|
@ -51,6 +57,26 @@ void _r_models_shutdown(void) {
|
|||
r_vertex_buffer_destroy(_r_models.vbuf);
|
||||
}
|
||||
|
||||
void r_model_add_static(Model *out_mdl, Primitive prim, size_t num_vertices, GenericModelVertex vertices[num_vertices], uint indices[num_vertices]) {
|
||||
out_mdl->vertex_array = _r_models.varr;
|
||||
out_mdl->num_vertices = num_vertices;
|
||||
out_mdl->primitive = prim;
|
||||
|
||||
SDL_RWops *vert_stream = r_vertex_buffer_get_stream(_r_models.vbuf);
|
||||
size_t vert_ofs = SDL_RWtell(vert_stream) / sizeof(GenericModelVertex);
|
||||
|
||||
if(indices != NULL) {
|
||||
out_mdl->offset = r_index_buffer_get_offset(_r_models.ibuf);
|
||||
r_index_buffer_add_indices(_r_models.ibuf, vert_ofs, num_vertices, indices);
|
||||
out_mdl->indexed = true;
|
||||
} else {
|
||||
out_mdl->offset = vert_ofs;
|
||||
out_mdl->indexed = false;
|
||||
}
|
||||
|
||||
SDL_RWwrite(vert_stream, vertices, sizeof(GenericModelVertex), num_vertices);
|
||||
}
|
||||
|
||||
VertexBuffer* r_vertex_buffer_static_models(void) {
|
||||
return _r_models.vbuf;
|
||||
}
|
||||
|
@ -60,22 +86,19 @@ VertexArray* r_vertex_array_static_models(void) {
|
|||
}
|
||||
|
||||
void r_draw_quad(void) {
|
||||
VertexArray *varr_saved = r_vertex_array_current();
|
||||
r_vertex_array(_r_models.varr);
|
||||
r_draw(PRIM_TRIANGLE_STRIP, 0, 4, NULL, 0, 0);
|
||||
r_vertex_array(varr_saved);
|
||||
r_draw_model_ptr(&_r_models.quad, 0, 0);
|
||||
}
|
||||
|
||||
void r_draw_quad_instanced(uint instances) {
|
||||
VertexArray *varr_saved = r_vertex_array_current();
|
||||
r_vertex_array(_r_models.varr);
|
||||
r_draw(PRIM_TRIANGLE_STRIP, 0, 4, NULL, instances, 0);
|
||||
r_vertex_array(varr_saved);
|
||||
r_draw_model_ptr(&_r_models.quad, instances, 0);
|
||||
}
|
||||
|
||||
void r_draw_model_ptr(Model *model) {
|
||||
VertexArray *varr_saved = r_vertex_array_current();
|
||||
r_vertex_array(_r_models.varr);
|
||||
r_draw(PRIM_TRIANGLES, 0, model->icount, model->indices, 0, 0);
|
||||
r_vertex_array(varr_saved);
|
||||
void r_draw_model_ptr(Model *model, uint instances, uint base_instance) {
|
||||
(model->indexed ? r_draw_indexed : r_draw)(
|
||||
model->vertex_array,
|
||||
model->primitive,
|
||||
model->offset, model->num_vertices,
|
||||
instances,
|
||||
base_instance
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "sprite_batch.h"
|
||||
#include "../api.h"
|
||||
#include "util/glm.h"
|
||||
#include "resource/sprite.h"
|
||||
#include "resource/model.h"
|
||||
|
||||
typedef struct SpriteAttribs {
|
||||
mat4 transform;
|
||||
|
@ -43,6 +45,8 @@ static struct SpriteBatchState {
|
|||
uint depth_write_enabled : 1;
|
||||
uint num_pending;
|
||||
|
||||
Model quad;
|
||||
|
||||
struct {
|
||||
uint flushes;
|
||||
uint sprites;
|
||||
|
@ -101,8 +105,14 @@ void _r_sprite_batch_init(void) {
|
|||
_r_sprite_batch.varr = r_vertex_array_create();
|
||||
r_vertex_array_set_debug_label(_r_sprite_batch.varr, "Sprite batch vertex array");
|
||||
r_vertex_array_layout(_r_sprite_batch.varr, sizeof(fmt)/sizeof(*fmt), fmt);
|
||||
r_vertex_array_attach_buffer(_r_sprite_batch.varr, r_vertex_buffer_static_models(), 0);
|
||||
r_vertex_array_attach_buffer(_r_sprite_batch.varr, _r_sprite_batch.vbuf, 1);
|
||||
r_vertex_array_attach_vertex_buffer(_r_sprite_batch.varr, r_vertex_buffer_static_models(), 0);
|
||||
r_vertex_array_attach_vertex_buffer(_r_sprite_batch.varr, _r_sprite_batch.vbuf, 1);
|
||||
|
||||
_r_sprite_batch.quad.indexed = false;
|
||||
_r_sprite_batch.quad.num_vertices = 4;
|
||||
_r_sprite_batch.quad.offset = 0;
|
||||
_r_sprite_batch.quad.primitive = PRIM_TRIANGLE_STRIP;
|
||||
_r_sprite_batch.quad.vertex_array = _r_sprite_batch.varr;
|
||||
}
|
||||
|
||||
void _r_sprite_batch_shutdown(void) {
|
||||
|
@ -140,7 +150,6 @@ void r_flush_sprites(void) {
|
|||
r_mat_push();
|
||||
glm_mat4_copy(_r_sprite_batch.projection, *r_mat_current_ptr(MM_PROJECTION));
|
||||
|
||||
r_vertex_array(_r_sprite_batch.varr);
|
||||
r_shader_ptr(_r_sprite_batch.shader);
|
||||
r_uniform_sampler("tex", _r_sprite_batch.primary_texture);
|
||||
r_uniform_sampler_array("tex_aux[0]", 0, R_NUM_SPRITE_AUX_TEXTURES, _r_sprite_batch.aux_textures);
|
||||
|
@ -153,7 +162,7 @@ void r_flush_sprites(void) {
|
|||
r_cull(_r_sprite_batch.cull_mode);
|
||||
|
||||
if(r_supports(RFEAT_DRAW_INSTANCED_BASE_INSTANCE)) {
|
||||
r_draw(PRIM_TRIANGLE_STRIP, 0, 4, NULL, pending, _r_sprite_batch.base_instance);
|
||||
r_draw_model_ptr(&_r_sprite_batch.quad, pending, _r_sprite_batch.base_instance);
|
||||
_r_sprite_batch.base_instance += pending;
|
||||
|
||||
SDL_RWops *stream = r_vertex_buffer_get_stream(_r_sprite_batch.vbuf);
|
||||
|
@ -165,7 +174,7 @@ void r_flush_sprites(void) {
|
|||
_r_sprite_batch.base_instance = 0;
|
||||
}
|
||||
} else {
|
||||
r_draw(PRIM_TRIANGLE_STRIP, 0, 4, NULL, pending, 0);
|
||||
r_draw_model_ptr(&_r_sprite_batch.quad, pending, 0);
|
||||
r_vertex_buffer_invalidate(_r_sprite_batch.vbuf);
|
||||
}
|
||||
|
||||
|
|
|
@ -89,10 +89,6 @@ void r_state_pop(void) {
|
|||
B.framebuffer(S.framebuffer);
|
||||
}
|
||||
|
||||
RESTORE(RSTATE_VERTEXARRAY) {
|
||||
B.vertex_array(S.varr);
|
||||
}
|
||||
|
||||
RESTORE(RSTATE_VSYNC) {
|
||||
B.vsync(S.vsync);
|
||||
}
|
||||
|
@ -155,12 +151,6 @@ void _r_state_touch_framebuffer(void) {
|
|||
});
|
||||
}
|
||||
|
||||
void _r_state_touch_vertex_array(void) {
|
||||
TAINT(RSTATE_VERTEXARRAY, {
|
||||
S.varr = B.vertex_array_current();
|
||||
});
|
||||
}
|
||||
|
||||
void _r_state_touch_vsync(void) {
|
||||
TAINT(RSTATE_VSYNC, {
|
||||
S.vsync = B.vsync_current();
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
RSTATE(SHADER) \
|
||||
RSTATE(SHADER_UNIFORMS) \
|
||||
RSTATE(RENDERTARGET) \
|
||||
RSTATE(VERTEXARRAY) \
|
||||
RSTATE(VSYNC) \
|
||||
|
||||
typedef enum RendererStateID {
|
||||
|
@ -51,8 +50,6 @@ typedef struct RendererStateRollback {
|
|||
ShaderProgram *shader;
|
||||
// TODO uniforms
|
||||
Framebuffer *framebuffer;
|
||||
// TODO framebuffer viewports, if we actually ever need to modify them at render time
|
||||
VertexArray *varr;
|
||||
VsyncMode vsync;
|
||||
} RendererStateRollback;
|
||||
|
||||
|
@ -65,7 +62,6 @@ void _r_state_touch_depth_func(void);
|
|||
void _r_state_touch_shader(void);
|
||||
void _r_state_touch_uniform(Uniform *uniform);
|
||||
void _r_state_touch_framebuffer(void);
|
||||
void _r_state_touch_vertex_array(void);
|
||||
void _r_state_touch_vsync(void);
|
||||
|
||||
void _r_state_init(void);
|
||||
|
|
132
src/renderer/gl33/common_buffer.c
Normal file
132
src/renderer/gl33/common_buffer.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
|
||||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "common_buffer.h"
|
||||
#include "core.h"
|
||||
|
||||
#define STREAM_CBUF(rw) ((CommonBuffer*)rw)
|
||||
|
||||
static int64_t gl33_buffer_stream_seek(SDL_RWops *rw, int64_t offset, int whence) {
|
||||
CommonBuffer *cbuf = STREAM_CBUF(rw);
|
||||
|
||||
switch(whence) {
|
||||
case RW_SEEK_CUR: {
|
||||
cbuf->offset += offset;
|
||||
break;
|
||||
}
|
||||
|
||||
case RW_SEEK_END: {
|
||||
cbuf->offset = cbuf->size + offset;
|
||||
break;
|
||||
}
|
||||
|
||||
case RW_SEEK_SET: {
|
||||
cbuf->offset = offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(cbuf->offset < cbuf->size);
|
||||
return cbuf->offset;
|
||||
}
|
||||
|
||||
static int64_t gl33_buffer_stream_size(SDL_RWops *rw) {
|
||||
return STREAM_CBUF(rw)->size;
|
||||
}
|
||||
|
||||
static size_t gl33_buffer_stream_write(SDL_RWops *rw, const void *data, size_t size, size_t num) {
|
||||
CommonBuffer *cbuf = STREAM_CBUF(rw);
|
||||
size_t total_size = size * num;
|
||||
assert(cbuf->offset + total_size <= cbuf->size);
|
||||
|
||||
if(total_size > 0) {
|
||||
memcpy(cbuf->cache.buffer + cbuf->offset, data, total_size);
|
||||
cbuf->cache.update_begin = min(cbuf->offset, cbuf->cache.update_begin);
|
||||
cbuf->cache.update_end = max(cbuf->offset + total_size, cbuf->cache.update_end);
|
||||
cbuf->offset += total_size;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static size_t gl33_buffer_stream_read(SDL_RWops *rw, void *data, size_t size, size_t num) {
|
||||
SDL_SetError("Can't read from an OpenGL buffer stream");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gl33_buffer_stream_close(SDL_RWops *rw) {
|
||||
SDL_SetError("Can't close an OpenGL buffer stream");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_RWops* gl33_buffer_get_stream(CommonBuffer *cbuf) {
|
||||
return &cbuf->stream;
|
||||
}
|
||||
|
||||
CommonBuffer* gl33_buffer_create(uint bindidx, size_t capacity, GLenum usage_hint, void *data) {
|
||||
CommonBuffer *cbuf = calloc(1, sizeof(CommonBuffer));
|
||||
cbuf->size = capacity = topow2(capacity);
|
||||
cbuf->cache.buffer = calloc(1, capacity);
|
||||
cbuf->cache.update_begin = capacity;
|
||||
cbuf->bindidx = bindidx;
|
||||
|
||||
glGenBuffers(1, &cbuf->gl_handle);
|
||||
|
||||
GL33_BUFFER_TEMP_BIND(cbuf, {
|
||||
assert(glIsBuffer(cbuf->gl_handle));
|
||||
glBufferData(gl33_bindidx_to_glenum(bindidx), capacity, data, usage_hint);
|
||||
});
|
||||
|
||||
cbuf->stream.type = SDL_RWOPS_UNKNOWN;
|
||||
cbuf->stream.close = gl33_buffer_stream_close;
|
||||
cbuf->stream.read = gl33_buffer_stream_read;
|
||||
cbuf->stream.write = gl33_buffer_stream_write;
|
||||
cbuf->stream.seek = gl33_buffer_stream_seek;
|
||||
cbuf->stream.size = gl33_buffer_stream_size;
|
||||
|
||||
return cbuf;
|
||||
}
|
||||
|
||||
void gl33_buffer_destroy(CommonBuffer *cbuf) {
|
||||
free(cbuf->cache.buffer);
|
||||
gl33_buffer_deleted(cbuf);
|
||||
glDeleteBuffers(1, &cbuf->gl_handle);
|
||||
free(cbuf);
|
||||
}
|
||||
|
||||
void gl33_buffer_invalidate(CommonBuffer *cbuf) {
|
||||
GL33_BUFFER_TEMP_BIND(cbuf, {
|
||||
glBufferData(gl33_bindidx_to_glenum(cbuf->bindidx), cbuf->size, NULL, GL_DYNAMIC_DRAW);
|
||||
});
|
||||
cbuf->offset = 0;
|
||||
}
|
||||
|
||||
void gl33_buffer_flush(CommonBuffer *cbuf) {
|
||||
if(cbuf->cache.update_begin >= cbuf->cache.update_end) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t update_size = cbuf->cache.update_end - cbuf->cache.update_begin;
|
||||
assert(update_size > 0);
|
||||
|
||||
GL33_BUFFER_TEMP_BIND(cbuf, {
|
||||
glBufferSubData(
|
||||
gl33_bindidx_to_glenum(cbuf->bindidx),
|
||||
cbuf->cache.update_begin,
|
||||
update_size,
|
||||
cbuf->cache.buffer + cbuf->cache.update_begin
|
||||
);
|
||||
});
|
||||
|
||||
cbuf->cache.update_begin = cbuf->size;
|
||||
cbuf->cache.update_end = 0;
|
||||
}
|
||||
|
55
src/renderer/gl33/common_buffer.h
Normal file
55
src/renderer/gl33/common_buffer.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "taisei.h"
|
||||
|
||||
#include "opengl.h"
|
||||
#include "../api.h"
|
||||
|
||||
typedef struct CommonBuffer {
|
||||
union {
|
||||
SDL_RWops stream;
|
||||
struct {
|
||||
char padding[offsetof(SDL_RWops, hidden)];
|
||||
|
||||
struct {
|
||||
char *buffer;
|
||||
size_t update_begin;
|
||||
size_t update_end;
|
||||
} cache;
|
||||
|
||||
size_t offset;
|
||||
size_t size;
|
||||
GLuint gl_handle;
|
||||
uint bindidx;
|
||||
char debug_label[R_DEBUG_LABEL_SIZE];
|
||||
};
|
||||
};
|
||||
} CommonBuffer;
|
||||
|
||||
static_assert(
|
||||
offsetof(CommonBuffer, stream) == 0,
|
||||
"stream should be the first member in CommonBuffer for simplicity"
|
||||
);
|
||||
|
||||
CommonBuffer* gl33_buffer_create(uint bindidx, size_t capacity, GLenum usage_hint, void *data);
|
||||
void gl33_buffer_destroy(CommonBuffer *cbuf);
|
||||
void gl33_buffer_invalidate(CommonBuffer *cbuf);
|
||||
SDL_RWops* gl33_buffer_get_stream(CommonBuffer *cbuf);
|
||||
void gl33_buffer_flush(CommonBuffer *cbuf);
|
||||
|
||||
#define GL33_BUFFER_TEMP_BIND(cbuf, code) do { \
|
||||
CommonBuffer *_tempbind_cbuf = (cbuf); \
|
||||
BufferBindingIndex _tempbind_bindidx = _tempbind_cbuf->bindidx; \
|
||||
GLuint _tempbind_buf_saved = gl33_buffer_current(_tempbind_bindidx); \
|
||||
gl33_bind_buffer(_tempbind_bindidx, _tempbind_cbuf->gl_handle); \
|
||||
gl33_sync_buffer(_tempbind_bindidx); \
|
||||
{ code } \
|
||||
gl33_bind_buffer(_tempbind_bindidx, _tempbind_buf_saved); \
|
||||
} while(0)
|
|
@ -17,7 +17,9 @@
|
|||
#include "shader_object.h"
|
||||
#include "shader_program.h"
|
||||
#include "framebuffer.h"
|
||||
#include "common_buffer.h"
|
||||
#include "vertex_buffer.h"
|
||||
#include "index_buffer.h"
|
||||
#include "vertex_array.h"
|
||||
#include "../glcommon/debug.h"
|
||||
#include "../glcommon/vtable.h"
|
||||
|
@ -53,15 +55,10 @@ static struct {
|
|||
Framebuffer *pending;
|
||||
} framebuffer;
|
||||
|
||||
struct {
|
||||
VertexArray *active;
|
||||
VertexArray *pending;
|
||||
} vertex_array;
|
||||
|
||||
struct {
|
||||
GLuint active;
|
||||
GLuint pending;
|
||||
} vbo;
|
||||
} buffer_objects[GL33_NUM_BUFFER_BINDINGS];
|
||||
|
||||
struct {
|
||||
GLuint active;
|
||||
|
@ -109,7 +106,6 @@ static struct {
|
|||
Color color;
|
||||
Color clear_color;
|
||||
float clear_depth;
|
||||
GLuint pbo;
|
||||
r_feature_bits_t features;
|
||||
|
||||
SDL_GLContext *gl_context;
|
||||
|
@ -333,7 +329,7 @@ static void gl33_sync_state(void) {
|
|||
gl33_sync_texunits(true);
|
||||
gl33_sync_framebuffer();
|
||||
gl33_sync_viewport();
|
||||
gl33_sync_vertex_array();
|
||||
gl33_sync_vao();
|
||||
gl33_sync_blend_mode();
|
||||
|
||||
if(R.capabilities.active & r_capability_bit(RCAP_CULL_FACE)) {
|
||||
|
@ -513,23 +509,6 @@ void gl33_sync_texunits(bool prepare_rendering) {
|
|||
}
|
||||
}
|
||||
|
||||
void gl33_sync_vertex_array(void) {
|
||||
R.vertex_array.active = R.vertex_array.pending;
|
||||
|
||||
if(R.vertex_array.active != NULL) {
|
||||
gl33_vertex_array_flush_buffers(R.vertex_array.active);
|
||||
}
|
||||
|
||||
gl33_sync_vao();
|
||||
}
|
||||
|
||||
void gl33_sync_vbo(void) {
|
||||
if(R.vbo.active != R.vbo.pending) {
|
||||
R.vbo.active = R.vbo.pending;
|
||||
glBindBuffer(GL_ARRAY_BUFFER, R.vbo.active);
|
||||
}
|
||||
}
|
||||
|
||||
void gl33_sync_vao(void) {
|
||||
if(R.vao.active != R.vao.pending) {
|
||||
R.vao.active = R.vao.pending;
|
||||
|
@ -537,6 +516,25 @@ void gl33_sync_vao(void) {
|
|||
}
|
||||
}
|
||||
|
||||
GLenum gl33_bindidx_to_glenum(BufferBindingIndex bindidx) {
|
||||
static GLenum map[] = {
|
||||
[GL33_BUFFER_BINDING_ARRAY] = GL_ARRAY_BUFFER,
|
||||
[GL33_BUFFER_BINDING_COPY_WRITE] = GL_COPY_WRITE_BUFFER,
|
||||
[GL33_BUFFER_BINDING_PIXEL_UNPACK] = GL_PIXEL_UNPACK_BUFFER,
|
||||
};
|
||||
|
||||
static_assert(sizeof(map) == sizeof(GLenum) * GL33_NUM_BUFFER_BINDINGS, "Fix the lookup table");
|
||||
assert((uint)bindidx < GL33_NUM_BUFFER_BINDINGS);
|
||||
return map[bindidx];
|
||||
}
|
||||
|
||||
void gl33_sync_buffer(BufferBindingIndex bindidx) {
|
||||
if(R.buffer_objects[bindidx].active != R.buffer_objects[bindidx].pending) {
|
||||
R.buffer_objects[bindidx].active = R.buffer_objects[bindidx].pending;
|
||||
glBindBuffer(gl33_bindidx_to_glenum(bindidx), R.buffer_objects[bindidx].active);
|
||||
}
|
||||
}
|
||||
|
||||
void gl33_sync_cull_face_mode(void) {
|
||||
if(R.cull_face.mode.pending != R.cull_face.mode.active) {
|
||||
GLenum glcull = r_cull_to_gl_cull(R.cull_face.mode.pending);
|
||||
|
@ -656,28 +654,16 @@ uint gl33_bind_texture(Texture *texture, bool for_rendering) {
|
|||
return TU_INDEX(texture->binding_unit);
|
||||
}
|
||||
|
||||
void gl33_bind_vbo(GLuint vbo) {
|
||||
R.vbo.pending = vbo;
|
||||
void gl33_bind_buffer(BufferBindingIndex bindidx, GLuint gl_handle) {
|
||||
R.buffer_objects[bindidx].pending = gl_handle;
|
||||
}
|
||||
|
||||
void gl33_bind_vao(GLuint vao) {
|
||||
R.vao.pending = vao;
|
||||
}
|
||||
|
||||
void gl33_bind_pbo(GLuint pbo) {
|
||||
if(!glext.pixel_buffer_object) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(pbo != R.pbo) {
|
||||
// r_flush_sprites();
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
|
||||
R.pbo = pbo;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint gl33_vbo_current(void) {
|
||||
return R.vbo.pending;
|
||||
GLuint gl33_buffer_current(BufferBindingIndex bindidx) {
|
||||
return R.buffer_objects[bindidx].pending;
|
||||
}
|
||||
|
||||
GLuint gl33_vao_current(void) {
|
||||
|
@ -711,8 +697,12 @@ void gl33_texture_deleted(Texture *tex) {
|
|||
}
|
||||
}
|
||||
|
||||
if(R.pbo == tex->pbo) {
|
||||
R.pbo = 0;
|
||||
if(R.buffer_objects[GL33_BUFFER_BINDING_PIXEL_UNPACK].pending == tex->pbo) {
|
||||
R.buffer_objects[GL33_BUFFER_BINDING_PIXEL_UNPACK].pending = 0;
|
||||
}
|
||||
|
||||
if(R.buffer_objects[GL33_BUFFER_BINDING_PIXEL_UNPACK].active == tex->pbo) {
|
||||
R.buffer_objects[GL33_BUFFER_BINDING_PIXEL_UNPACK].active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -741,26 +731,27 @@ void gl33_shader_deleted(ShaderProgram *prog) {
|
|||
}
|
||||
}
|
||||
|
||||
void gl33_vertex_buffer_deleted(VertexBuffer *vbuf) {
|
||||
if(R.vbo.active == vbuf->gl_handle) {
|
||||
R.vbo.active = 0;
|
||||
void gl33_buffer_deleted(CommonBuffer *cbuf) {
|
||||
if(R.buffer_objects[cbuf->bindidx].active == cbuf->gl_handle) {
|
||||
R.buffer_objects[cbuf->bindidx].active = 0;
|
||||
}
|
||||
|
||||
if(R.vbo.pending == vbuf->gl_handle) {
|
||||
R.vbo.pending = 0;
|
||||
if(R.buffer_objects[cbuf->bindidx].pending == cbuf->gl_handle) {
|
||||
R.buffer_objects[cbuf->bindidx].pending = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void gl33_vertex_buffer_deleted(VertexBuffer *vbuf) {
|
||||
if(R.buffer_objects[GL33_BUFFER_BINDING_ARRAY].active == vbuf->cbuf.gl_handle) {
|
||||
R.buffer_objects[GL33_BUFFER_BINDING_ARRAY].active = 0;
|
||||
}
|
||||
|
||||
if(R.buffer_objects[GL33_BUFFER_BINDING_ARRAY].pending == vbuf->cbuf.gl_handle) {
|
||||
R.buffer_objects[GL33_BUFFER_BINDING_ARRAY].pending = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void gl33_vertex_array_deleted(VertexArray *varr) {
|
||||
if(R.vertex_array.active == varr) {
|
||||
R.vertex_array.active = NULL;
|
||||
}
|
||||
|
||||
if(R.vertex_array.pending == varr) {
|
||||
R.vertex_array.pending = NULL;
|
||||
r_vertex_array(r_vertex_array_static_models());
|
||||
}
|
||||
|
||||
if(R.vao.active == varr->gl_handle) {
|
||||
R.vao.active = 0;
|
||||
}
|
||||
|
@ -862,53 +853,69 @@ static const Color* gl33_color_current(void) {
|
|||
return &R.color;
|
||||
}
|
||||
|
||||
static void gl33_vertex_array(VertexArray *varr) {
|
||||
R.vertex_array.pending = varr;
|
||||
gl33_bind_vao(varr->gl_handle);
|
||||
}
|
||||
|
||||
static VertexArray* gl33_vertex_array_current(void) {
|
||||
return R.vertex_array.pending;
|
||||
}
|
||||
|
||||
static void gl33_draw(Primitive prim, uint first, uint count, uint32_t *indices, uint instances, uint base_instance) {
|
||||
static void gl33_draw(VertexArray *varr, Primitive prim, uint firstvert, uint count, uint instances, uint base_instance) {
|
||||
assert(count > 0);
|
||||
assert((uint)prim < sizeof(prim_to_gl_prim)/sizeof(GLenum));
|
||||
|
||||
r_flush_sprites();
|
||||
|
||||
GLuint gl_prim = prim_to_gl_prim[prim];
|
||||
gl33_sync_state();
|
||||
|
||||
gl33_stats_pre_draw();
|
||||
|
||||
if(indices == NULL) {
|
||||
if(instances) {
|
||||
if(base_instance) {
|
||||
glDrawArraysInstancedBaseInstance(gl_prim, first, count, instances, base_instance);
|
||||
} else {
|
||||
glDrawArraysInstanced(gl_prim, first, count, instances);
|
||||
}
|
||||
} else {
|
||||
glDrawArrays(gl_prim, first, count);
|
||||
}
|
||||
} else {
|
||||
if(instances) {
|
||||
if(base_instance) {
|
||||
glDrawElementsInstancedBaseInstance(gl_prim, count, GL_UNSIGNED_INT, indices, instances, base_instance);
|
||||
} else {
|
||||
glDrawElementsInstanced(gl_prim, count, GL_UNSIGNED_INT, indices, instances);
|
||||
}
|
||||
} else {
|
||||
glDrawElements(gl_prim, count, GL_UNSIGNED_INT, indices);
|
||||
}
|
||||
}
|
||||
|
||||
gl33_stats_post_draw();
|
||||
gl33_stats_pre_draw();
|
||||
r_flush_sprites();
|
||||
GLuint prev_vao = gl33_vao_current();
|
||||
gl33_bind_vao(varr->gl_handle);
|
||||
gl33_sync_state();
|
||||
gl33_vertex_array_flush_buffers(varr);
|
||||
|
||||
if(instances) {
|
||||
if(base_instance) {
|
||||
glDrawArraysInstancedBaseInstance(gl_prim, firstvert, count, instances, base_instance);
|
||||
} else {
|
||||
glDrawArraysInstanced(gl_prim, firstvert, count, instances);
|
||||
}
|
||||
} else {
|
||||
glDrawArrays(gl_prim, firstvert, count);
|
||||
}
|
||||
|
||||
if(R.framebuffer.active) {
|
||||
gl33_framebuffer_taint(R.framebuffer.active);
|
||||
}
|
||||
|
||||
gl33_bind_vao(prev_vao);
|
||||
gl33_stats_post_draw();
|
||||
}
|
||||
|
||||
static void gl33_draw_indexed(VertexArray *varr, Primitive prim, uint firstidx, uint count, uint instances, uint base_instance) {
|
||||
assert(count > 0);
|
||||
assert((uint)prim < sizeof(prim_to_gl_prim)/sizeof(GLenum));
|
||||
assert(varr->index_attachment != NULL);
|
||||
GLuint gl_prim = prim_to_gl_prim[prim];
|
||||
|
||||
gl33_stats_post_draw();
|
||||
gl33_stats_pre_draw();
|
||||
r_flush_sprites();
|
||||
GLuint prev_vao = gl33_vao_current();
|
||||
gl33_bind_vao(varr->gl_handle);
|
||||
gl33_sync_state();
|
||||
gl33_vertex_array_flush_buffers(varr);
|
||||
|
||||
uintptr_t iofs = firstidx * sizeof(gl33_ibo_index_t);
|
||||
|
||||
if(instances) {
|
||||
if(base_instance) {
|
||||
glDrawElementsInstancedBaseInstance(gl_prim, count, GL33_IBO_GL_DATATYPE, (void*)iofs, instances, base_instance);
|
||||
} else {
|
||||
glDrawElementsInstanced(gl_prim, count, GL33_IBO_GL_DATATYPE, (void*)iofs, instances);
|
||||
}
|
||||
} else {
|
||||
glDrawElements(gl_prim, count, GL33_IBO_GL_DATATYPE, (void*)iofs);
|
||||
}
|
||||
|
||||
if(R.framebuffer.active) {
|
||||
gl33_framebuffer_taint(R.framebuffer.active);
|
||||
}
|
||||
|
||||
gl33_bind_vao(prev_vao);
|
||||
gl33_stats_post_draw();
|
||||
}
|
||||
|
||||
static void gl33_framebuffer(Framebuffer *fb) {
|
||||
|
@ -1004,6 +1011,7 @@ RendererBackend _r_backend_gl33 = {
|
|||
.capabilities = gl33_capabilities,
|
||||
.capabilities_current = gl33_capabilities_current,
|
||||
.draw = gl33_draw,
|
||||
.draw_indexed = gl33_draw_indexed,
|
||||
.color4 = gl33_color4,
|
||||
.color_current = gl33_color_current,
|
||||
.blend = gl33_blend,
|
||||
|
@ -1056,15 +1064,23 @@ RendererBackend _r_backend_gl33 = {
|
|||
.vertex_buffer_destroy = gl33_vertex_buffer_destroy,
|
||||
.vertex_buffer_invalidate = gl33_vertex_buffer_invalidate,
|
||||
.vertex_buffer_get_stream = gl33_vertex_buffer_get_stream,
|
||||
.index_buffer_create = gl33_index_buffer_create,
|
||||
.index_buffer_get_capacity = gl33_index_buffer_get_capacity,
|
||||
.index_buffer_get_debug_label = gl33_index_buffer_get_debug_label,
|
||||
.index_buffer_set_debug_label = gl33_index_buffer_set_debug_label,
|
||||
.index_buffer_set_offset = gl33_index_buffer_set_offset,
|
||||
.index_buffer_get_offset = gl33_index_buffer_get_offset,
|
||||
.index_buffer_add_indices = gl33_index_buffer_add_indices,
|
||||
.index_buffer_destroy = gl33_index_buffer_destroy,
|
||||
.vertex_array_destroy = gl33_vertex_array_destroy,
|
||||
.vertex_array_create = gl33_vertex_array_create,
|
||||
.vertex_array_set_debug_label = gl33_vertex_array_set_debug_label,
|
||||
.vertex_array_get_debug_label = gl33_vertex_array_get_debug_label,
|
||||
.vertex_array_layout = gl33_vertex_array_layout,
|
||||
.vertex_array_attach_buffer = gl33_vertex_array_attach_buffer,
|
||||
.vertex_array_get_attachment = gl33_vertex_array_get_attachment,
|
||||
.vertex_array = gl33_vertex_array,
|
||||
.vertex_array_current = gl33_vertex_array_current,
|
||||
.vertex_array_attach_vertex_buffer = gl33_vertex_array_attach_vertex_buffer,
|
||||
.vertex_array_get_vertex_attachment = gl33_vertex_array_get_vertex_attachment,
|
||||
.vertex_array_attach_index_buffer = gl33_vertex_array_attach_index_buffer,
|
||||
.vertex_array_get_index_attachment = gl33_vertex_array_get_index_attachment,
|
||||
.vsync = gl33_vsync,
|
||||
.vsync_current = gl33_vsync_current,
|
||||
.swap = gl33_swap,
|
||||
|
|
|
@ -13,15 +13,30 @@
|
|||
#include "opengl.h"
|
||||
#include "resource/texture.h"
|
||||
#include "../common/backend.h"
|
||||
#include "common_buffer.h"
|
||||
|
||||
typedef struct TextureUnit TextureUnit;
|
||||
|
||||
typedef enum BufferBindingIndex {
|
||||
GL33_BUFFER_BINDING_ARRAY,
|
||||
GL33_BUFFER_BINDING_COPY_WRITE,
|
||||
GL33_BUFFER_BINDING_PIXEL_UNPACK,
|
||||
|
||||
GL33_NUM_BUFFER_BINDINGS
|
||||
} BufferBindingIndex;
|
||||
|
||||
// Internal helper functions
|
||||
|
||||
uint gl33_bind_texture(Texture *texture, bool for_rendering);
|
||||
void gl33_bind_pbo(GLuint pbo);
|
||||
|
||||
void gl33_bind_vao(GLuint vao);
|
||||
void gl33_bind_vbo(GLuint vbo);
|
||||
void gl33_sync_vao(void);
|
||||
GLuint gl33_vao_current(void);
|
||||
|
||||
void gl33_bind_buffer(BufferBindingIndex bindidx, GLuint gl_handle);
|
||||
void gl33_sync_buffer(BufferBindingIndex bindidx);
|
||||
GLuint gl33_buffer_current(BufferBindingIndex bindidx);
|
||||
GLenum gl33_bindidx_to_glenum(BufferBindingIndex bindidx);
|
||||
|
||||
void gl33_set_clear_color(const Color *color);
|
||||
void gl33_set_clear_depth(float depth);
|
||||
|
@ -30,17 +45,12 @@ void gl33_sync_shader(void);
|
|||
void gl33_sync_texunit(TextureUnit *unit, bool prepare_rendering, bool ensure_active) attr_nonnull(1);
|
||||
void gl33_sync_texunits(bool prepare_rendering);
|
||||
void gl33_sync_framebuffer(void);
|
||||
void gl33_sync_vertex_array(void);
|
||||
void gl33_sync_blend_mode(void);
|
||||
void gl33_sync_cull_face_mode(void);
|
||||
void gl33_sync_depth_test_func(void);
|
||||
void gl33_sync_capabilities(void);
|
||||
void gl33_sync_vao(void);
|
||||
void gl33_sync_vbo(void);
|
||||
|
||||
GLuint gl33_vao_current(void);
|
||||
GLuint gl33_vbo_current(void);
|
||||
|
||||
void gl33_buffer_deleted(CommonBuffer *cbuf);
|
||||
void gl33_vertex_buffer_deleted(VertexBuffer *vbuf);
|
||||
void gl33_vertex_array_deleted(VertexArray *varr);
|
||||
void gl33_texture_deleted(Texture *tex);
|
||||
|
|
68
src/renderer/gl33/index_buffer.c
Normal file
68
src/renderer/gl33/index_buffer.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "index_buffer.h"
|
||||
#include "core.h"
|
||||
#include "../glcommon/debug.h"
|
||||
|
||||
IndexBuffer* gl33_index_buffer_create(size_t max_elements) {
|
||||
IndexBuffer *ibuf = (IndexBuffer*)gl33_buffer_create(
|
||||
GL33_BUFFER_BINDING_COPY_WRITE,
|
||||
max_elements * sizeof(gl33_ibo_index_t),
|
||||
GL_STATIC_DRAW,
|
||||
NULL
|
||||
);
|
||||
|
||||
snprintf(ibuf->cbuf.debug_label, sizeof(ibuf->cbuf.debug_label), "IBO #%i", ibuf->cbuf.gl_handle);
|
||||
log_debug("Created IBO %u for %zu elements", ibuf->cbuf.gl_handle, max_elements);
|
||||
return ibuf;
|
||||
}
|
||||
|
||||
size_t gl33_index_buffer_get_capacity(IndexBuffer *ibuf) {
|
||||
return ibuf->cbuf.size / sizeof(gl33_ibo_index_t);
|
||||
}
|
||||
|
||||
const char* gl33_index_buffer_get_debug_label(IndexBuffer *ibuf) {
|
||||
return ibuf->cbuf.debug_label;
|
||||
}
|
||||
|
||||
void gl33_index_buffer_set_debug_label(IndexBuffer *ibuf, const char *label) {
|
||||
glcommon_set_debug_label(ibuf->cbuf.debug_label, "IBO", GL_BUFFER, ibuf->cbuf.gl_handle, label);
|
||||
}
|
||||
|
||||
void gl33_index_buffer_set_offset(IndexBuffer *ibuf, size_t offset) {
|
||||
ibuf->cbuf.offset = offset * sizeof(gl33_ibo_index_t);
|
||||
}
|
||||
|
||||
size_t gl33_index_buffer_get_offset(IndexBuffer *ibuf) {
|
||||
return ibuf->cbuf.offset / sizeof(gl33_ibo_index_t);
|
||||
}
|
||||
|
||||
void gl33_index_buffer_add_indices(IndexBuffer *ibuf, uint index_ofs, size_t num_elements, uint indices[num_elements]) {
|
||||
SDL_RWops *stream = gl33_buffer_get_stream(&ibuf->cbuf);
|
||||
gl33_ibo_index_t data[num_elements];
|
||||
|
||||
for(size_t i = 0; i < num_elements; ++i) {
|
||||
uintmax_t idx = indices[i] + index_ofs;
|
||||
assert(idx <= GL33_IBO_MAX_INDEX);
|
||||
data[i] = idx;
|
||||
}
|
||||
|
||||
SDL_RWwrite(stream, &data, sizeof(gl33_ibo_index_t), num_elements);
|
||||
}
|
||||
|
||||
void gl33_index_buffer_destroy(IndexBuffer *ibuf) {
|
||||
log_debug("Deleted IBO %u", ibuf->cbuf.gl_handle);
|
||||
gl33_buffer_destroy(&ibuf->cbuf);
|
||||
}
|
||||
|
||||
void gl33_index_buffer_flush(IndexBuffer *ibuf) {
|
||||
gl33_buffer_flush(&ibuf->cbuf);
|
||||
}
|
30
src/renderer/gl33/index_buffer.h
Normal file
30
src/renderer/gl33/index_buffer.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT-License
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "taisei.h"
|
||||
|
||||
#include "common_buffer.h"
|
||||
|
||||
typedef struct IndexBuffer {
|
||||
CommonBuffer cbuf;
|
||||
} IndexBuffer;
|
||||
|
||||
typedef GLushort gl33_ibo_index_t;
|
||||
#define GL33_IBO_MAX_INDEX UINT16_MAX
|
||||
#define GL33_IBO_GL_DATATYPE GL_UNSIGNED_SHORT
|
||||
|
||||
IndexBuffer* gl33_index_buffer_create(size_t max_elements);
|
||||
size_t gl33_index_buffer_get_capacity(IndexBuffer *ibuf);
|
||||
const char* gl33_index_buffer_get_debug_label(IndexBuffer *ibuf);
|
||||
void gl33_index_buffer_set_debug_label(IndexBuffer *ibuf, const char *label);
|
||||
void gl33_index_buffer_set_offset(IndexBuffer *ibuf, size_t offset);
|
||||
size_t gl33_index_buffer_get_offset(IndexBuffer *ibuf);
|
||||
void gl33_index_buffer_add_indices(IndexBuffer *ibuf, uint index_ofs, size_t num_indices, uint indices[num_indices]);
|
||||
void gl33_index_buffer_destroy(IndexBuffer *ibuf);
|
||||
void gl33_index_buffer_flush(IndexBuffer *ibuf);
|
|
@ -1,7 +1,9 @@
|
|||
|
||||
r_gl33_src = files(
|
||||
'common_buffer.c',
|
||||
'core.c',
|
||||
'framebuffer.c',
|
||||
'index_buffer.c',
|
||||
'shader_object.c',
|
||||
'shader_program.c',
|
||||
'texture.c',
|
||||
|
|
|
@ -119,11 +119,15 @@ static void gl33_texture_set(Texture *tex, uint mipmap, const Pixmap *image) {
|
|||
GLTextureFormatTuple *fmt = prepare_pixmap(tex, image, &pix);
|
||||
void *image_data = pix.data.untyped;
|
||||
|
||||
GLuint prev_pbo;
|
||||
|
||||
gl33_bind_texture(tex, false);
|
||||
gl33_sync_texunit(tex->binding_unit, false, true);
|
||||
gl33_bind_pbo(tex->pbo);
|
||||
|
||||
if(tex->pbo) {
|
||||
prev_pbo = gl33_buffer_current(GL33_BUFFER_BINDING_PIXEL_UNPACK);
|
||||
gl33_bind_buffer(GL33_BUFFER_BINDING_PIXEL_UNPACK, tex->pbo);
|
||||
gl33_sync_buffer(GL33_BUFFER_BINDING_PIXEL_UNPACK);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER, pixmap_data_size(&pix), image_data, GL_STREAM_DRAW);
|
||||
image_data = NULL;
|
||||
}
|
||||
|
@ -145,7 +149,10 @@ static void gl33_texture_set(Texture *tex, uint mipmap, const Pixmap *image) {
|
|||
|
||||
free(pix.data.untyped);
|
||||
|
||||
gl33_bind_pbo(0);
|
||||
if(tex->pbo) {
|
||||
gl33_bind_buffer(GL33_BUFFER_BINDING_PIXEL_UNPACK, prev_pbo);
|
||||
}
|
||||
|
||||
tex->mipmaps_outdated = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "vertex_array.h"
|
||||
#include "vertex_buffer.h"
|
||||
#include "index_buffer.h"
|
||||
#include "core.h"
|
||||
#include "../glcommon/debug.h"
|
||||
|
||||
|
@ -44,29 +45,40 @@ void gl33_vertex_array_destroy(VertexArray *varr) {
|
|||
free(varr);
|
||||
}
|
||||
|
||||
static void gl33_vertex_array_update_layout(VertexArray *varr, uint attachment, uint old_num_attribs) {
|
||||
static void gl33_vertex_array_update_layout(VertexArray *varr) {
|
||||
GLuint vao_saved = gl33_vao_current();
|
||||
GLuint vbo_saved = gl33_vbo_current();
|
||||
GLuint vbo_saved = gl33_buffer_current(GL33_BUFFER_BINDING_ARRAY);
|
||||
|
||||
gl33_bind_vao(varr->gl_handle);
|
||||
gl33_sync_vao();
|
||||
|
||||
if(varr->layout_dirty_bits & VAO_INDEX_BIT) {
|
||||
gl33_sync_vao();
|
||||
if(varr->index_attachment) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, varr->index_attachment->cbuf.gl_handle);
|
||||
} else {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for(uint i = 0; i < varr->num_attributes; ++i) {
|
||||
VertexAttribFormat *a = varr->attribute_layout + i;
|
||||
assert((uint)a->spec.type < sizeof(va_type_to_gl_type)/sizeof(GLenum));
|
||||
assert(a->attachment < VAO_MAX_BUFFERS);
|
||||
|
||||
if(attachment != UINT_MAX && attachment != a->attachment) {
|
||||
if(!(varr->layout_dirty_bits & (1u << i))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
VertexBuffer *vbuf = r_vertex_array_get_attachment(varr, a->attachment);
|
||||
VertexBuffer *vbuf = varr->attachments[a->attachment];
|
||||
|
||||
if(vbuf == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
gl33_bind_vbo(vbuf->gl_handle);
|
||||
gl33_sync_vbo();
|
||||
gl33_sync_vao();
|
||||
|
||||
gl33_bind_buffer(GL33_BUFFER_BINDING_ARRAY, vbuf->cbuf.gl_handle);
|
||||
gl33_sync_buffer(GL33_BUFFER_BINDING_ARRAY);
|
||||
|
||||
glEnableVertexAttribArray(i);
|
||||
|
||||
|
@ -105,15 +117,21 @@ static void gl33_vertex_array_update_layout(VertexArray *varr, uint attachment,
|
|||
}
|
||||
}
|
||||
|
||||
for(uint i = varr->num_attributes; i < old_num_attribs; ++i) {
|
||||
for(uint i = varr->num_attributes; i < varr->prev_num_attributes; ++i) {
|
||||
gl33_sync_vao();
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
|
||||
gl33_bind_vbo(vbo_saved);
|
||||
gl33_bind_buffer(GL33_BUFFER_BINDING_ARRAY, vbo_saved);
|
||||
gl33_bind_vao(vao_saved);
|
||||
|
||||
varr->prev_num_attributes = varr->num_attributes;
|
||||
varr->layout_dirty_bits = 0;
|
||||
}
|
||||
|
||||
void gl33_vertex_array_attach_buffer(VertexArray *varr, VertexBuffer *vbuf, uint attachment) {
|
||||
void gl33_vertex_array_attach_vertex_buffer(VertexArray *varr, VertexBuffer *vbuf, uint attachment) {
|
||||
assert(attachment < VAO_MAX_BUFFERS);
|
||||
|
||||
// TODO: more efficient way of handling this?
|
||||
if(attachment >= varr->num_attachments) {
|
||||
varr->attachments = realloc(varr->attachments, (attachment + 1) * sizeof(VertexBuffer*));
|
||||
|
@ -121,10 +139,15 @@ void gl33_vertex_array_attach_buffer(VertexArray *varr, VertexBuffer *vbuf, uint
|
|||
}
|
||||
|
||||
varr->attachments[attachment] = vbuf;
|
||||
gl33_vertex_array_update_layout(varr, attachment, varr->num_attributes);
|
||||
varr->layout_dirty_bits |= (1u << attachment);
|
||||
}
|
||||
|
||||
VertexBuffer* gl33_vertex_array_get_attachment(VertexArray *varr, uint attachment) {
|
||||
void gl33_vertex_array_attach_index_buffer(VertexArray *varr, IndexBuffer *ibuf) {
|
||||
varr->index_attachment = ibuf;
|
||||
varr->layout_dirty_bits |= VAO_INDEX_BIT;
|
||||
}
|
||||
|
||||
VertexBuffer* gl33_vertex_array_get_vertex_attachment(VertexArray *varr, uint attachment) {
|
||||
if(varr->num_attachments <= attachment) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -132,16 +155,18 @@ VertexBuffer* gl33_vertex_array_get_attachment(VertexArray *varr, uint attachmen
|
|||
return varr->attachments[attachment];
|
||||
}
|
||||
|
||||
void gl33_vertex_array_layout(VertexArray *varr, uint nattribs, VertexAttribFormat attribs[nattribs]) {
|
||||
uint old_nattribs = varr->num_attributes;
|
||||
IndexBuffer* gl33_vertex_array_get_index_attachment(VertexArray *varr) {
|
||||
return varr->index_attachment;
|
||||
}
|
||||
|
||||
void gl33_vertex_array_layout(VertexArray *varr, uint nattribs, VertexAttribFormat attribs[nattribs]) {
|
||||
if(varr->num_attributes != nattribs) {
|
||||
varr->attribute_layout = realloc(varr->attribute_layout, sizeof(VertexAttribFormat) * nattribs);
|
||||
varr->num_attributes = nattribs;
|
||||
}
|
||||
|
||||
memcpy(varr->attribute_layout, attribs, sizeof(VertexAttribFormat) * nattribs);
|
||||
gl33_vertex_array_update_layout(varr, UINT32_MAX, old_nattribs);
|
||||
varr->layout_dirty_bits |= (1u << nattribs) - 1;
|
||||
}
|
||||
|
||||
const char* gl33_vertex_array_get_debug_label(VertexArray *varr) {
|
||||
|
@ -153,9 +178,17 @@ void gl33_vertex_array_set_debug_label(VertexArray *varr, const char *label) {
|
|||
}
|
||||
|
||||
void gl33_vertex_array_flush_buffers(VertexArray *varr) {
|
||||
if(varr->layout_dirty_bits) {
|
||||
gl33_vertex_array_update_layout(varr);
|
||||
}
|
||||
|
||||
for(uint i = 0; i < varr->num_attachments; ++i) {
|
||||
if(varr->attachments[i] != NULL) {
|
||||
gl33_vertex_buffer_flush(varr->attachments[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(varr->index_attachment != NULL) {
|
||||
gl33_index_buffer_flush(varr->index_attachment);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,12 +12,18 @@
|
|||
#include "../api.h"
|
||||
#include "opengl.h"
|
||||
|
||||
#define VAO_MAX_BUFFERS 31
|
||||
#define VAO_INDEX_BIT (1u << VAO_MAX_BUFFERS)
|
||||
|
||||
struct VertexArray {
|
||||
VertexBuffer **attachments;
|
||||
VertexAttribFormat *attribute_layout;
|
||||
IndexBuffer *index_attachment;
|
||||
GLuint gl_handle;
|
||||
uint num_attachments;
|
||||
uint num_attributes;
|
||||
uint prev_num_attributes;
|
||||
uint layout_dirty_bits;
|
||||
char debug_label[R_DEBUG_LABEL_SIZE];
|
||||
};
|
||||
|
||||
|
@ -25,7 +31,9 @@ VertexArray* gl33_vertex_array_create(void);
|
|||
const char* gl33_vertex_array_get_debug_label(VertexArray *varr);
|
||||
void gl33_vertex_array_set_debug_label(VertexArray *varr, const char *label);
|
||||
void gl33_vertex_array_destroy(VertexArray *varr);
|
||||
void gl33_vertex_array_attach_buffer(VertexArray *varr, VertexBuffer *vbuf, uint attachment);
|
||||
VertexBuffer* gl33_vertex_array_get_attachment(VertexArray *varr, uint attachment);
|
||||
void gl33_vertex_array_attach_vertex_buffer(VertexArray *varr, VertexBuffer *vbuf, uint attachment);
|
||||
void gl33_vertex_array_attach_index_buffer(VertexArray *varr, IndexBuffer *ibuf);
|
||||
VertexBuffer* gl33_vertex_array_get_vertex_attachment(VertexArray *varr, uint attachment);
|
||||
IndexBuffer* gl33_vertex_array_get_index_attachment(VertexArray *varr);
|
||||
void gl33_vertex_array_layout(VertexArray *varr, uint nattribs, VertexAttribFormat attribs[nattribs]);
|
||||
void gl33_vertex_array_flush_buffers(VertexArray *varr);
|
||||
|
|
|
@ -8,140 +8,44 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdalign.h>
|
||||
|
||||
#include "../api.h"
|
||||
#include "vertex_buffer.h"
|
||||
#include "core.h"
|
||||
#include "../glcommon/debug.h"
|
||||
|
||||
#define STREAM_VBUF(rw) ((VertexBuffer*)rw)
|
||||
|
||||
static int64_t gl33_vertex_buffer_stream_seek(SDL_RWops *rw, int64_t offset, int whence) {
|
||||
VertexBuffer *vbuf = STREAM_VBUF(rw);
|
||||
|
||||
switch(whence) {
|
||||
case RW_SEEK_CUR: {
|
||||
vbuf->offset += offset;
|
||||
break;
|
||||
}
|
||||
|
||||
case RW_SEEK_END: {
|
||||
vbuf->offset = vbuf->size + offset;
|
||||
break;
|
||||
}
|
||||
|
||||
case RW_SEEK_SET: {
|
||||
vbuf->offset = offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(vbuf->offset < vbuf->size);
|
||||
return vbuf->offset;
|
||||
}
|
||||
|
||||
static int64_t gl33_vertex_buffer_stream_size(SDL_RWops *rw) {
|
||||
VertexBuffer *vbuf = STREAM_VBUF(rw);
|
||||
return vbuf->size;
|
||||
}
|
||||
|
||||
static size_t gl33_vertex_buffer_stream_write(SDL_RWops *rw, const void *data, size_t size, size_t num) {
|
||||
VertexBuffer *vbuf = STREAM_VBUF(rw);
|
||||
size_t total_size = size * num;
|
||||
assert(vbuf->offset + total_size <= vbuf->size);
|
||||
|
||||
if(total_size > 0) {
|
||||
memcpy(vbuf->cache.buffer + vbuf->offset, data, total_size);
|
||||
vbuf->cache.update_begin = min(vbuf->offset, vbuf->cache.update_begin);
|
||||
vbuf->cache.update_end = max(vbuf->offset + total_size, vbuf->cache.update_end);
|
||||
vbuf->offset += total_size;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static size_t gl33_vertex_buffer_stream_read(SDL_RWops *rw, void *data, size_t size, size_t num) {
|
||||
SDL_SetError("Stream is write-only");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gl33_vertex_buffer_stream_close(SDL_RWops *rw) {
|
||||
SDL_SetError("Can't close a vertex buffer stream");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_RWops* gl33_vertex_buffer_get_stream(VertexBuffer *vbuf) {
|
||||
return &vbuf->stream;
|
||||
}
|
||||
|
||||
VertexBuffer* gl33_vertex_buffer_create(size_t capacity, void *data) {
|
||||
VertexBuffer *vbuf = calloc(1, sizeof(VertexBuffer));
|
||||
vbuf->size = capacity = topow2(capacity);
|
||||
vbuf->cache.buffer = calloc(1, capacity);
|
||||
vbuf->cache.update_begin = capacity;
|
||||
VertexBuffer *vbuf = (VertexBuffer*)gl33_buffer_create(
|
||||
GL33_BUFFER_BINDING_ARRAY,
|
||||
capacity,
|
||||
GL_STATIC_DRAW,
|
||||
data
|
||||
);
|
||||
|
||||
glGenBuffers(1, &vbuf->gl_handle);
|
||||
|
||||
GLuint vbo_saved = gl33_vbo_current();
|
||||
gl33_bind_vbo(vbuf->gl_handle);
|
||||
gl33_sync_vbo();
|
||||
assert(glIsBuffer(vbuf->gl_handle));
|
||||
glBufferData(GL_ARRAY_BUFFER, capacity, data, GL_STATIC_DRAW);
|
||||
gl33_bind_vbo(vbo_saved);
|
||||
|
||||
vbuf->stream.type = SDL_RWOPS_UNKNOWN;
|
||||
vbuf->stream.close = gl33_vertex_buffer_stream_close;
|
||||
vbuf->stream.read = gl33_vertex_buffer_stream_read;
|
||||
vbuf->stream.write = gl33_vertex_buffer_stream_write;
|
||||
vbuf->stream.seek = gl33_vertex_buffer_stream_seek;
|
||||
vbuf->stream.size = gl33_vertex_buffer_stream_size;
|
||||
|
||||
snprintf(vbuf->debug_label, sizeof(vbuf->debug_label), "VBO #%i", vbuf->gl_handle);
|
||||
log_debug("Created VBO %u with %zukb of storage", vbuf->gl_handle, vbuf->size / 1024);
|
||||
snprintf(vbuf->cbuf.debug_label, sizeof(vbuf->cbuf.debug_label), "VBO #%i", vbuf->cbuf.gl_handle);
|
||||
log_debug("Created VBO %u with %zukb of storage", vbuf->cbuf.gl_handle, vbuf->cbuf.size / 1024);
|
||||
return vbuf;
|
||||
}
|
||||
|
||||
void gl33_vertex_buffer_destroy(VertexBuffer *vbuf) {
|
||||
free(vbuf->cache.buffer);
|
||||
gl33_vertex_buffer_deleted(vbuf);
|
||||
glDeleteBuffers(1, &vbuf->gl_handle);
|
||||
log_debug("Deleted VBO %u with %zukb of storage", vbuf->gl_handle, vbuf->size / 1024);
|
||||
free(vbuf);
|
||||
log_debug("Deleted VBO %u with %zukb of storage", vbuf->cbuf.gl_handle, vbuf->cbuf.size / 1024);
|
||||
gl33_buffer_destroy(&vbuf->cbuf);
|
||||
}
|
||||
|
||||
void gl33_vertex_buffer_invalidate(VertexBuffer *vbuf) {
|
||||
GLuint vbo_saved = gl33_vbo_current();
|
||||
gl33_bind_vbo(vbuf->gl_handle);
|
||||
gl33_sync_vbo();
|
||||
glBufferData(GL_ARRAY_BUFFER, vbuf->size, NULL, GL_DYNAMIC_DRAW);
|
||||
gl33_bind_vbo(vbo_saved);
|
||||
vbuf->offset = 0;
|
||||
gl33_buffer_invalidate(&vbuf->cbuf);
|
||||
}
|
||||
|
||||
const char* gl33_vertex_buffer_get_debug_label(VertexBuffer *vbuf) {
|
||||
return vbuf->debug_label;
|
||||
return vbuf->cbuf.debug_label;
|
||||
}
|
||||
|
||||
void gl33_vertex_buffer_set_debug_label(VertexBuffer *vbuf, const char *label) {
|
||||
glcommon_set_debug_label(vbuf->debug_label, "VBO", GL_BUFFER, vbuf->gl_handle, label);
|
||||
glcommon_set_debug_label(vbuf->cbuf.debug_label, "VBO", GL_BUFFER, vbuf->cbuf.gl_handle, label);
|
||||
}
|
||||
|
||||
void gl33_vertex_buffer_flush(VertexBuffer *vbuf) {
|
||||
if(vbuf->cache.update_begin >= vbuf->cache.update_end) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t update_size = vbuf->cache.update_end - vbuf->cache.update_begin;
|
||||
assert(update_size > 0);
|
||||
|
||||
GLuint vbo_saved = gl33_vbo_current();
|
||||
gl33_bind_vbo(vbuf->gl_handle);
|
||||
gl33_sync_vbo();
|
||||
glBufferSubData(GL_ARRAY_BUFFER, vbuf->cache.update_begin, update_size, vbuf->cache.buffer + vbuf->cache.update_begin);
|
||||
gl33_bind_vbo(vbo_saved);
|
||||
|
||||
vbuf->cache.update_begin = vbuf->size;
|
||||
vbuf->cache.update_end = 0;
|
||||
gl33_buffer_flush(&vbuf->cbuf);
|
||||
}
|
||||
|
||||
SDL_RWops* gl33_vertex_buffer_get_stream(VertexBuffer *vbuf) {
|
||||
return gl33_buffer_get_stream(&vbuf->cbuf);
|
||||
}
|
||||
|
|
|
@ -9,34 +9,12 @@
|
|||
#pragma once
|
||||
#include "taisei.h"
|
||||
|
||||
#include "opengl.h"
|
||||
#include <SDL.h>
|
||||
#include "common_buffer.h"
|
||||
|
||||
typedef struct VertexBuffer {
|
||||
union {
|
||||
SDL_RWops stream;
|
||||
struct {
|
||||
char padding[offsetof(SDL_RWops, hidden)];
|
||||
|
||||
struct {
|
||||
char *buffer;
|
||||
size_t update_begin;
|
||||
size_t update_end;
|
||||
} cache;
|
||||
|
||||
size_t offset;
|
||||
size_t size;
|
||||
GLuint gl_handle;
|
||||
char debug_label[R_DEBUG_LABEL_SIZE];
|
||||
};
|
||||
};
|
||||
CommonBuffer cbuf;
|
||||
} VertexBuffer;
|
||||
|
||||
static_assert(
|
||||
offsetof(VertexBuffer, stream) == 0,
|
||||
"stream should be the first member in VertexBuffer for simplicity"
|
||||
);
|
||||
|
||||
VertexBuffer* gl33_vertex_buffer_create(size_t capacity, void *data);
|
||||
const char* gl33_vertex_buffer_get_debug_label(VertexBuffer *vbuf);
|
||||
void gl33_vertex_buffer_set_debug_label(VertexBuffer *vbuf, const char *label);
|
||||
|
|
|
@ -65,7 +65,7 @@ void null_uniform(Uniform *uniform, uint offset, uint count, const void *data) {
|
|||
|
||||
UniformType null_uniform_type(Uniform *uniform) { return UNIFORM_FLOAT; }
|
||||
|
||||
void null_draw(Primitive prim, uint first, uint count, uint32_t *indices, uint instances, uint base_instance) { }
|
||||
void null_draw(VertexArray *varr, Primitive prim, uint first, uint count, uint instances, uint base_instance) { }
|
||||
|
||||
Texture* null_texture_create(const TextureParams *params) {
|
||||
return (void*)&placeholder;
|
||||
|
@ -136,15 +136,24 @@ const char* null_vertex_buffer_get_debug_label(VertexBuffer *vbuf) { return "nul
|
|||
void null_vertex_buffer_destroy(VertexBuffer *vbuf) { }
|
||||
void null_vertex_buffer_invalidate(VertexBuffer *vbuf) { }
|
||||
|
||||
IndexBuffer* null_index_buffer_create(size_t max_elements) { return (void*)&placeholder; }
|
||||
size_t null_index_buffer_get_capacity(IndexBuffer *ibuf) { return UINT32_MAX; }
|
||||
const char* null_index_buffer_get_debug_label(IndexBuffer *ibuf) { return "null index buffer"; }
|
||||
void null_index_buffer_set_debug_label(IndexBuffer *ibuf, const char *label) { }
|
||||
void null_index_buffer_set_offset(IndexBuffer *ibuf, size_t offset) { }
|
||||
size_t null_index_buffer_get_offset(IndexBuffer *ibuf) { return 0; }
|
||||
void null_index_buffer_add_indices(IndexBuffer *ibuf, uint index_ofs, size_t num_elements, uint indices[num_elements]) { }
|
||||
void null_index_buffer_destroy(IndexBuffer *ibuf) { }
|
||||
|
||||
VertexArray* null_vertex_array_create(void) { return (void*)&placeholder; }
|
||||
void null_vertex_array_set_debug_label(VertexArray *varr, const char *label) { }
|
||||
const char* null_vertex_array_get_debug_label(VertexArray *varr) { return "null vertex array"; }
|
||||
void null_vertex_array_destroy(VertexArray *varr) { }
|
||||
void null_vertex_array_attach_buffer(VertexArray *varr, VertexBuffer *vbuf, uint attachment) { }
|
||||
VertexBuffer* null_vertex_array_get_attachment(VertexArray *varr, uint attachment) { return (void*)&placeholder; }
|
||||
void null_vertex_array_attach_vertex_buffer(VertexArray *varr, VertexBuffer *vbuf, uint attachment) { }
|
||||
void null_vertex_array_attach_index_buffer(VertexArray *varr, IndexBuffer *vbuf) { }
|
||||
VertexBuffer* null_vertex_array_get_vertex_attachment(VertexArray *varr, uint attachment) { return (void*)&placeholder; }
|
||||
IndexBuffer* null_vertex_array_get_index_attachment(VertexArray *varr) { return (void*)&placeholder; }
|
||||
void null_vertex_array_layout(VertexArray *varr, uint nattribs, VertexAttribFormat attribs[nattribs]) { }
|
||||
void null_vertex_array(VertexArray *varr) { }
|
||||
VertexArray* null_vertex_array_current(void) { return (void*)&placeholder; }
|
||||
|
||||
void null_clear(ClearBufferFlags flags) { }
|
||||
void null_clear_color4(float r, float g, float b, float a) { }
|
||||
|
@ -168,6 +177,7 @@ RendererBackend _r_backend_null = {
|
|||
.capabilities = null_capabilities,
|
||||
.capabilities_current = null_capabilities_current,
|
||||
.draw = null_draw,
|
||||
.draw_indexed = null_draw,
|
||||
.color4 = null_color4,
|
||||
.color_current = null_color_current,
|
||||
.blend = null_blend,
|
||||
|
@ -220,15 +230,23 @@ RendererBackend _r_backend_null = {
|
|||
.vertex_buffer_destroy = null_vertex_buffer_destroy,
|
||||
.vertex_buffer_invalidate = null_vertex_buffer_invalidate,
|
||||
.vertex_buffer_get_stream = null_vertex_buffer_get_stream,
|
||||
.index_buffer_create = null_index_buffer_create,
|
||||
.index_buffer_get_capacity = null_index_buffer_get_capacity,
|
||||
.index_buffer_get_debug_label = null_index_buffer_get_debug_label,
|
||||
.index_buffer_set_debug_label = null_index_buffer_set_debug_label,
|
||||
.index_buffer_set_offset = null_index_buffer_set_offset,
|
||||
.index_buffer_get_offset = null_index_buffer_get_offset,
|
||||
.index_buffer_add_indices = null_index_buffer_add_indices,
|
||||
.index_buffer_destroy = null_index_buffer_destroy,
|
||||
.vertex_array_create = null_vertex_array_create,
|
||||
.vertex_array_get_debug_label = null_vertex_array_get_debug_label,
|
||||
.vertex_array_set_debug_label = null_vertex_array_set_debug_label,
|
||||
.vertex_array_destroy = null_vertex_array_destroy,
|
||||
.vertex_array_layout = null_vertex_array_layout,
|
||||
.vertex_array_attach_buffer = null_vertex_array_attach_buffer,
|
||||
.vertex_array_get_attachment = null_vertex_array_get_attachment,
|
||||
.vertex_array = null_vertex_array,
|
||||
.vertex_array_current = null_vertex_array_current,
|
||||
.vertex_array_attach_vertex_buffer = null_vertex_array_attach_vertex_buffer,
|
||||
.vertex_array_get_vertex_attachment = null_vertex_array_get_vertex_attachment,
|
||||
.vertex_array_attach_index_buffer = null_vertex_array_attach_index_buffer,
|
||||
.vertex_array_get_index_attachment = null_vertex_array_get_index_attachment,
|
||||
.vsync = null_vsync,
|
||||
.vsync_current = null_vsync_current,
|
||||
.swap = null_swap,
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
#include "resource.h"
|
||||
#include "renderer/api.h"
|
||||
|
||||
// TODO: Rewrite all of this mess, maybe even consider a different format
|
||||
// IQM for instance: http://sauerbraten.org/iqm/
|
||||
|
||||
ResourceHandler model_res_handler = {
|
||||
.type = RES_MODEL,
|
||||
.typename = "model",
|
||||
|
@ -43,21 +46,19 @@ bool check_model_path(const char *path) {
|
|||
}
|
||||
|
||||
typedef struct ModelLoadData {
|
||||
ObjFileData *obj;
|
||||
GenericModelVertex *verts;
|
||||
Model *model;
|
||||
uint *indices;
|
||||
uint icount;
|
||||
} ModelLoadData;
|
||||
|
||||
void* load_model_begin(const char *path, uint flags) {
|
||||
Model *m = malloc(sizeof(Model));
|
||||
ObjFileData *data = malloc(sizeof(ObjFileData));
|
||||
GenericModelVertex *verts;
|
||||
|
||||
parse_obj(path, data);
|
||||
|
||||
m->fverts = data->fverts;
|
||||
m->indices = calloc(data->icount, sizeof(uint));
|
||||
m->icount = data->icount;
|
||||
uint *indices = calloc(data->icount, sizeof(uint));
|
||||
uint icount = data->icount;
|
||||
|
||||
verts = calloc(data->icount, sizeof(GenericModelVertex));
|
||||
|
||||
|
@ -94,21 +95,23 @@ void* load_model_begin(const char *path, uint flags) {
|
|||
memcpy(verts[i].normal, data->normals[ni], sizeof(vec3_noalign));
|
||||
}
|
||||
|
||||
m->indices[i] = i;
|
||||
indices[i] = i;
|
||||
}
|
||||
|
||||
free_obj(data);
|
||||
free(data);
|
||||
|
||||
#undef BADREF
|
||||
|
||||
ModelLoadData *ldata = malloc(sizeof(ModelLoadData));
|
||||
ldata->obj = data;
|
||||
ldata->verts = verts;
|
||||
ldata->model = m;
|
||||
ldata->indices = indices;
|
||||
ldata->icount = icount;
|
||||
|
||||
return ldata;
|
||||
|
||||
fail:
|
||||
free(m->indices);
|
||||
free(m);
|
||||
free(indices);
|
||||
free(verts);
|
||||
free_obj(data);
|
||||
free(data);
|
||||
|
@ -116,33 +119,23 @@ fail:
|
|||
}
|
||||
|
||||
void* load_model_end(void *opaque, const char *path, uint flags) {
|
||||
VertexBuffer *vbuf= r_vertex_buffer_static_models();
|
||||
ModelLoadData *ldata = opaque;
|
||||
|
||||
if(!ldata) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_RWops *stream = r_vertex_buffer_get_stream(vbuf);
|
||||
size_t ioffset = SDL_RWtell(stream);
|
||||
|
||||
for(int i = 0; i < ldata->obj->icount; ++i) {
|
||||
ldata->model->indices[i] += ioffset / sizeof(GenericModelVertex);
|
||||
}
|
||||
|
||||
SDL_RWwrite(stream, ldata->verts, sizeof(GenericModelVertex), ldata->obj->icount);
|
||||
Model *model = calloc(1, sizeof(Model));
|
||||
r_model_add_static(model, PRIM_TRIANGLES, ldata->icount, ldata->verts, ldata->indices);
|
||||
|
||||
free(ldata->verts);
|
||||
free_obj(ldata->obj);
|
||||
free(ldata->obj);
|
||||
Model *m = ldata->model;
|
||||
free(ldata->indices);
|
||||
free(ldata);
|
||||
|
||||
return m;
|
||||
return model;
|
||||
}
|
||||
|
||||
void unload_model(void *model) { // Does not delete elements from the VBO, so doing this at runtime is leaking VBO space
|
||||
free(((Model*)model)->indices);
|
||||
free(model);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "util.h"
|
||||
#include "resource.h"
|
||||
|
||||
#include "renderer/api.h"
|
||||
|
||||
typedef struct ObjFileData {
|
||||
vec3_noalign *xs;
|
||||
int xcount;
|
||||
|
@ -28,11 +30,13 @@ typedef struct ObjFileData {
|
|||
int fverts;
|
||||
} ObjFileData;
|
||||
|
||||
typedef struct Model {
|
||||
uint *indices;
|
||||
int icount;
|
||||
int fverts;
|
||||
} Model;
|
||||
struct Model {
|
||||
VertexArray *vertex_array;
|
||||
size_t num_vertices;
|
||||
size_t offset;
|
||||
Primitive primitive;
|
||||
bool indexed;
|
||||
};
|
||||
|
||||
char* model_path(const char *name);
|
||||
bool check_model_path(const char *path);
|
||||
|
|
Loading…
Reference in a new issue