2016-09-13 02:41:43 -04:00
|
|
|
|
2017-04-15 15:42:58 -04:00
|
|
|
// Gawain vertex buffer
|
2016-09-13 02:41:43 -04:00
|
|
|
//
|
|
|
|
|
// This code is part of the Gawain library, with modifications
|
|
|
|
|
// specific to integration with Blender.
|
|
|
|
|
//
|
|
|
|
|
// Copyright 2016 Mike Erwin
|
|
|
|
|
//
|
|
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
|
|
|
|
|
// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
|
|
|
#include "vertex_buffer.h"
|
2016-11-29 00:12:50 -05:00
|
|
|
#include "buffer_id.h"
|
2017-04-15 13:10:14 -04:00
|
|
|
#include "vertex_format_private.h"
|
2016-09-14 16:28:16 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
2016-09-13 02:41:43 -04:00
|
|
|
|
2016-09-15 16:51:10 +02:00
|
|
|
#define KEEP_SINGLE_COPY 1
|
|
|
|
|
|
2017-05-04 21:22:41 +02:00
|
|
|
static unsigned vbo_memory_usage;
|
|
|
|
|
|
2017-02-09 02:28:55 +11:00
|
|
|
VertexBuffer* VertexBuffer_create(void)
|
2016-09-14 16:28:16 +02:00
|
|
|
{
|
|
|
|
|
VertexBuffer* verts = malloc(sizeof(VertexBuffer));
|
2016-09-15 16:51:10 +02:00
|
|
|
VertexBuffer_init(verts);
|
2016-09-14 16:28:16 +02:00
|
|
|
return verts;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 21:45:10 +02:00
|
|
|
VertexBuffer* VertexBuffer_create_with_format(const VertexFormat* format)
|
|
|
|
|
{
|
|
|
|
|
VertexBuffer* verts = VertexBuffer_create();
|
|
|
|
|
VertexFormat_copy(&verts->format, format);
|
|
|
|
|
if (!format->packed)
|
|
|
|
|
VertexFormat_pack(&verts->format);
|
|
|
|
|
return verts;
|
|
|
|
|
|
|
|
|
|
// this function might seem redundant, but there is potential for memory savings here...
|
|
|
|
|
// TODO: implement those memory savings
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 16:51:10 +02:00
|
|
|
void VertexBuffer_init(VertexBuffer* verts)
|
2016-09-14 16:28:16 +02:00
|
|
|
{
|
|
|
|
|
memset(verts, 0, sizeof(VertexBuffer));
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 21:45:10 +02:00
|
|
|
void VertexBuffer_init_with_format(VertexBuffer* verts, const VertexFormat* format)
|
|
|
|
|
{
|
|
|
|
|
VertexBuffer_init(verts);
|
|
|
|
|
VertexFormat_copy(&verts->format, format);
|
|
|
|
|
if (!format->packed)
|
|
|
|
|
VertexFormat_pack(&verts->format);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-23 23:16:54 -04:00
|
|
|
void VertexBuffer_discard(VertexBuffer* verts)
|
|
|
|
|
{
|
2017-05-04 21:22:41 +02:00
|
|
|
if (verts->vbo_id) {
|
2016-11-29 00:12:50 -05:00
|
|
|
buffer_id_free(verts->vbo_id);
|
2017-05-15 12:47:25 -04:00
|
|
|
vbo_memory_usage -= VertexBuffer_size(verts);
|
2017-05-04 21:22:41 +02:00
|
|
|
}
|
2016-11-29 00:12:50 -05:00
|
|
|
#if KEEP_SINGLE_COPY
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
if (verts->data)
|
|
|
|
|
free(verts->data);
|
|
|
|
|
|
2017-05-04 21:22:41 +02:00
|
|
|
|
2016-11-29 00:12:50 -05:00
|
|
|
free(verts);
|
2016-10-23 23:16:54 -04:00
|
|
|
}
|
|
|
|
|
|
2016-09-15 21:45:10 +02:00
|
|
|
unsigned VertexBuffer_size(const VertexBuffer* verts)
|
|
|
|
|
{
|
|
|
|
|
return vertex_buffer_size(&verts->format, verts->vertex_ct);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 16:51:10 +02:00
|
|
|
void VertexBuffer_allocate_data(VertexBuffer* verts, unsigned v_ct)
|
2016-09-14 16:28:16 +02:00
|
|
|
{
|
|
|
|
|
VertexFormat* format = &verts->format;
|
|
|
|
|
if (!format->packed)
|
2016-09-15 21:45:10 +02:00
|
|
|
VertexFormat_pack(format);
|
2016-09-14 16:28:16 +02:00
|
|
|
|
|
|
|
|
verts->vertex_ct = v_ct;
|
|
|
|
|
|
|
|
|
|
// Data initially lives in main memory. Will be transferred to VRAM when we "prime" it.
|
2016-09-15 21:45:10 +02:00
|
|
|
verts->data = malloc(VertexBuffer_size(verts));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VertexBuffer_resize_data(VertexBuffer* verts, unsigned v_ct)
|
|
|
|
|
{
|
|
|
|
|
#if TRUST_NO_ONE
|
|
|
|
|
assert(verts->vertex_ct != v_ct); // allow this?
|
|
|
|
|
assert(verts->data != NULL); // has already been allocated
|
|
|
|
|
assert(verts->vbo_id == 0); // has not been sent to VRAM
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
verts->vertex_ct = v_ct;
|
|
|
|
|
verts->data = realloc(verts->data, VertexBuffer_size(verts));
|
|
|
|
|
// TODO: skip realloc if v_ct < existing vertex count
|
|
|
|
|
// extra space will be reclaimed, and never sent to VRAM (see VertexBuffer_prime)
|
2016-09-14 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
|
2017-04-04 20:45:23 -04:00
|
|
|
void VertexBuffer_set_attrib(VertexBuffer* verts, unsigned a_idx, unsigned v_idx, const void* data)
|
2016-09-14 16:28:16 +02:00
|
|
|
{
|
|
|
|
|
const VertexFormat* format = &verts->format;
|
|
|
|
|
const Attrib* a = format->attribs + a_idx;
|
|
|
|
|
|
|
|
|
|
#if TRUST_NO_ONE
|
|
|
|
|
assert(a_idx < format->attrib_ct);
|
|
|
|
|
assert(v_idx < verts->vertex_ct);
|
|
|
|
|
assert(verts->data != NULL); // data must be in main mem
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
memcpy((GLubyte*)verts->data + a->offset + v_idx * format->stride, data, a->sz);
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-04 20:45:23 -04:00
|
|
|
void VertexBuffer_fill_attrib(VertexBuffer* verts, unsigned a_idx, const void* data)
|
2016-09-14 16:28:16 +02:00
|
|
|
{
|
|
|
|
|
const VertexFormat* format = &verts->format;
|
|
|
|
|
const Attrib* a = format->attribs + a_idx;
|
|
|
|
|
|
|
|
|
|
#if TRUST_NO_ONE
|
|
|
|
|
assert(a_idx < format->attrib_ct);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
const unsigned stride = a->sz; // tightly packed input data
|
|
|
|
|
|
2017-04-04 20:45:23 -04:00
|
|
|
VertexBuffer_fill_attrib_stride(verts, a_idx, stride, data);
|
2016-09-14 16:28:16 +02:00
|
|
|
}
|
|
|
|
|
|
2017-04-04 20:45:23 -04:00
|
|
|
void VertexBuffer_fill_attrib_stride(VertexBuffer* verts, unsigned a_idx, unsigned stride, const void* data)
|
2016-09-14 16:28:16 +02:00
|
|
|
{
|
|
|
|
|
const VertexFormat* format = &verts->format;
|
|
|
|
|
const Attrib* a = format->attribs + a_idx;
|
|
|
|
|
|
|
|
|
|
#if TRUST_NO_ONE
|
|
|
|
|
assert(a_idx < format->attrib_ct);
|
|
|
|
|
assert(verts->data != NULL); // data must be in main mem
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
const unsigned vertex_ct = verts->vertex_ct;
|
|
|
|
|
|
|
|
|
|
if (format->attrib_ct == 1 && stride == format->stride)
|
|
|
|
|
{
|
|
|
|
|
// we can copy it all at once
|
|
|
|
|
memcpy(verts->data, data, vertex_ct * a->sz);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// we must copy it per vertex
|
|
|
|
|
for (unsigned v = 0; v < vertex_ct; ++v)
|
|
|
|
|
memcpy((GLubyte*)verts->data + a->offset + v * format->stride, (const GLubyte*)data + v * stride, a->sz);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-15 16:51:10 +02:00
|
|
|
|
|
|
|
|
static void VertexBuffer_prime(VertexBuffer* verts)
|
|
|
|
|
{
|
|
|
|
|
const VertexFormat* format = &verts->format;
|
|
|
|
|
|
2016-11-29 00:12:50 -05:00
|
|
|
verts->vbo_id = buffer_id_alloc();
|
2016-09-15 16:51:10 +02:00
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
|
|
|
|
|
// fill with delicious data & send to GPU the first time only
|
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, vertex_buffer_size(format, verts->vertex_ct), verts->data, GL_STATIC_DRAW);
|
|
|
|
|
|
2017-05-15 12:47:25 -04:00
|
|
|
vbo_memory_usage += VertexBuffer_size(verts);
|
2017-05-04 21:22:41 +02:00
|
|
|
|
2016-09-15 16:51:10 +02:00
|
|
|
#if KEEP_SINGLE_COPY
|
|
|
|
|
// now that GL has a copy, discard original
|
|
|
|
|
free(verts->data);
|
|
|
|
|
verts->data = NULL;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void VertexBuffer_use(VertexBuffer* verts)
|
|
|
|
|
{
|
|
|
|
|
if (verts->vbo_id)
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id);
|
|
|
|
|
else
|
|
|
|
|
VertexBuffer_prime(verts);
|
|
|
|
|
}
|
2017-05-04 21:22:41 +02:00
|
|
|
|
|
|
|
|
unsigned VertexBuffer_get_memory_usage(void)
|
|
|
|
|
{
|
2017-05-15 13:05:32 -04:00
|
|
|
return vbo_memory_usage;
|
|
|
|
|
}
|