shared vbo

main
Brett 2024-01-11 11:49:48 -05:00
parent 4699c02fa6
commit 3e8eea09b5
6 changed files with 25 additions and 372 deletions

View File

@ -1,146 +0,0 @@
/*
* <Short Description>
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_WITH_GRAPHICS_OBJ_LOADER_H
#define BLT_WITH_GRAPHICS_OBJ_LOADER_H
#include "blt/math/vectors.h"
#include "blt/std/hashmap.h"
#include <utility>
#include <vector>
#include <string_view>
namespace blt::gfx
{
typedef blt::vec3f vertex_t;
typedef blt::vec2f uv_t;
typedef blt::vec3f normal_t;
class model_data
{
public:
private:
std::vector<vertex_t> vertices;
std::vector<uv_t> uvs;
std::vector<normal_t> normals;
};
struct face_t
{
std::int32_t vertex, uv, normal;
};
static inline bool operator==(const face_t& f1, const face_t& f2)
{
return f1.vertex == f2.vertex && f1.uv == f2.uv && f1.normal == f2.normal;
}
struct face_hash
{
size_t operator()(const face_t& face) const
{
std::hash<std::int32_t> hasher;
return hasher(face.vertex) ^ hasher(face.uv) ^ hasher(face.normal);
}
};
struct face_eq
{
bool operator()(const face_t& f1, const face_t& f2) const
{
return f1 == f2;
}
};
struct constructed_vertex_t
{
vertex_t vertex;
uv_t uv;
normal_t normal;
};
struct triangle_t
{
std::int32_t v[3];
};
struct quad_t
{
std::int32_t v[4];
};
struct object_data
{
std::string object_name;
std::vector<triangle_t> indices;
};
class obj_objects_t
{
private:
std::vector<constructed_vertex_t> vertex_data_;
std::vector<object_data> objects_;
public:
obj_objects_t(std::vector<constructed_vertex_t>&& vertex_data, std::vector<object_data>&& objects):
vertex_data_(vertex_data), objects_(objects)
{}
inline const std::vector<constructed_vertex_t>& vertex_data()
{
return vertex_data_;
};
inline const std::vector<object_data>& objects()
{
return objects_;
};
};
class char_tokenizer;
class obj_loader
{
private:
std::vector<vertex_t> vertices;
std::vector<uv_t> uvs;
std::vector<normal_t> normals;
// maps between face (constructed vertex) -> vertex indices
HASHMAP<face_t, std::int32_t, face_hash, face_eq> vertex_map;
std::vector<constructed_vertex_t> vertex_data;
object_data current_object;
std::vector<object_data> data;
private:
bool handle_vertex_and_normals(float x, float y, float z, char type);
void parse_vertex_line(char_tokenizer& tokenizer);
void parse_face(char_tokenizer& tokenizer);
void handle_face_vertex(const std::vector<std::string>& face_list, std::int32_t* arr);
public:
obj_objects_t parseFile(std::string_view file);
};
obj_objects_t quick_load(std::string_view file);
}
#endif //BLT_WITH_GRAPHICS_OBJ_LOADER_H

View File

@ -66,7 +66,8 @@ namespace blt::gfx
explicit vbo_t_owner(vbo_t vbo): vbo(vbo) explicit vbo_t_owner(vbo_t vbo): vbo(vbo)
{} {}
vbo_t* operator->(){ vbo_t* operator->()
{
return &vbo; return &vbo;
} }
@ -133,6 +134,7 @@ namespace blt::gfx
vbo_t element; vbo_t element;
void handle_vbo(const vbo_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset); void handle_vbo(const vbo_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset);
public: public:
vertex_array(); vertex_array();
@ -156,6 +158,7 @@ namespace blt::gfx
* @return a shared pointer to the stored vbo. used for chaining VAOs with multiple shared VBOs * @return a shared pointer to the stored vbo. used for chaining VAOs with multiple shared VBOs
*/ */
static_dynamic_array::vbo_type bindVBO(const vbo_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset); static_dynamic_array::vbo_type bindVBO(const vbo_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset);
// same as the other bind method except you provide the shared reference. // same as the other bind method except you provide the shared reference.
void bindVBO(const static_dynamic_array::vbo_type& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset); void bindVBO(const static_dynamic_array::vbo_type& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset);
@ -191,6 +194,11 @@ namespace blt::gfx
glBindVertexArray(0); glBindVertexArray(0);
} }
static inline std::shared_ptr<vbo_t_owner> createSharedVBO(const vbo_t& vbo)
{
return std::make_shared<vbo_t_owner>(vbo);
}
~vertex_array(); ~vertex_array();
}; };

@ -1 +1 @@
Subproject commit 9147a85dc32f06be2a4cfe4e422fdbc52679adc5 Subproject commit 60ec2051d8422716e1d6fb8354c129731106f7ad

View File

@ -1,219 +0,0 @@
/*
* <Short Description>
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <blt/gfx/loader/obj_loader.h>
#include <blt/std/loader.h>
#include <blt/std/string.h>
#include <blt/std/logging.h>
#include <cctype>
#include <charconv>
#include "blt/std/assert.h"
#include "blt/std/utility.h"
namespace blt::gfx
{
class char_tokenizer
{
private:
std::string_view string;
std::size_t current_pos = 0;
public:
explicit char_tokenizer(std::string_view view): string(view)
{}
inline char advance()
{
return string[current_pos++];
}
inline bool has_next(size_t offset = 0)
{
return current_pos + offset < string.size();
}
inline std::string_view read_fully()
{
return blt::string::trim(string.substr(current_pos));
}
};
template<typename T = float>
T get(std::string_view str)
{
T x;
const auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), x);
// probably not needed.
if (ec != std::errc())
{
// int i;
// const auto [ptr2, ec2] = std::from_chars(str.data(), str.data() + str.size(), i);
// if (ec2 == std::errc())
// {
// x = static_cast<float>(i);
// } else
// {
BLT_WARN("Unable to parse string '%s' into number!", std::string(str).c_str());
x = 0;
// }
}
return x;
}
void obj_loader::parse_vertex_line(char_tokenizer& tokenizer)
{
char type = tokenizer.advance();
if (type == 'p')
{
BLT_WARN("Unexpected type '%c' (not supported)", type);
return;
}
auto elements = blt::string::split(std::string(tokenizer.read_fully()), " ");
BLT_ASSERT(elements.size() >= 2 && "Current line doesn't have enough arguments to process!");
float x = get(elements[0]), y = get(elements[1]);
if (elements.size() < 3)
{
if (type == 't')
uvs.push_back(uv_t{x, y});
else
BLT_ERROR("Unable to parse line '%s' type '%c' not recognized for arg count", std::string(tokenizer.read_fully()).c_str(), type);
} else
{
float z = get(elements[2]);
if (!handle_vertex_and_normals(x, y, z, type))
BLT_ERROR("Unable to parse line '%s' type '%c' not recognized", std::string(tokenizer.read_fully()).c_str(), type);
}
}
bool obj_loader::handle_vertex_and_normals(float x, float y, float z, char type)
{
if (std::isspace(type))
{
vertices.push_back(vertex_t{x, y, z});
} else if (type == 'n')
{
normals.push_back(normal_t{x, y, z});
} else
return false;
return true;
}
obj_objects_t quick_load(std::string_view file)
{
return obj_loader().parseFile(file);
}
obj_objects_t obj_loader::parseFile(std::string_view file)
{
auto lines = blt::fs::getLinesFromFile(std::string(file));
for (const auto& line : lines)
{
char_tokenizer token(line);
if (!token.has_next() || token.read_fully().empty())
continue;
switch (token.advance())
{
case '#':
continue;
case 'f':
parse_face(token);
break;
case 'v':
parse_vertex_line(token);
break;
case 'o':
{
if (!current_object.indices.empty())
data.push_back(current_object);
current_object = {};
current_object.object_name = token.read_fully();
break;
}
case 'm':
{
BLT_TRACE("Material '%s' needs to be loaded!", std::string(token.read_fully()).c_str());
break;
}
case 'u':
{
BLT_TRACE("Using material '%s'", std::string(token.read_fully()).c_str());
break;
}
case 's':
BLT_TRACE("Using shading: %s", std::string(token.read_fully()).c_str());
break;
}
}
data.push_back(current_object);
return {std::move(vertex_data), std::move(data)};
}
void obj_loader::parse_face(char_tokenizer& tokenizer)
{
auto faces = blt::string::split(std::string(tokenizer.read_fully()), ' ');
if (faces.size() == 3)
{
triangle_t triangle{};
handle_face_vertex(faces, triangle.v);
current_object.indices.push_back(triangle);
} else if (faces.size() == 4)
{
quad_t quad{};
handle_face_vertex(faces, quad.v);
triangle_t t1{};
triangle_t t2{};
for (int i = 0; i < 3; i++)
t1.v[i] = quad.v[i];
t2.v[0] = quad.v[0];
t2.v[1] = quad.v[2];
t2.v[2] = quad.v[3];
current_object.indices.push_back(t1);
current_object.indices.push_back(t2);
} else
BLT_WARN("Unsupported vertex count! %d", faces.size());
}
void obj_loader::handle_face_vertex(const std::vector<std::string>& face_list, int32_t* arr)
{
for (const auto& pair : blt::enumerate(face_list))
{
auto indices = blt::string::split(pair.second, '/');
BLT_ASSERT(indices.size() == 3 && "Must have vertex, uv, and normal indices!!");
auto vi = get<std::int32_t>(indices[0]);
auto ui = get<std::int32_t>(indices[1]);
auto ni = get<std::int32_t>(indices[2]);
face_t face{vi, ui, ni};
auto loc = vertex_map.find(face);
if (loc == vertex_map.end())
{
auto index = static_cast<std::int32_t>(vertex_data.size());
vertex_data.push_back({vertices[vi], uvs[ui], normals[ni]});
vertex_map.insert({face, index});
arr[pair.first] = index;
} else
{
arr[pair.first] = loc->second;
}
}
}
}

View File

@ -135,7 +135,7 @@ namespace blt::gfx
long offset) long offset)
{ {
handle_vbo(vbo, attribute_number, coordinate_size, type, stride, offset); handle_vbo(vbo, attribute_number, coordinate_size, type, stride, offset);
VBOs[attribute_number] = std::make_shared<vbo_t_owner>(vbo); VBOs[attribute_number] = createSharedVBO(vbo);
return VBOs[attribute_number]; return VBOs[attribute_number];
} }

View File

@ -1,21 +1,19 @@
#include <blt/gfx/window.h> #include <blt/gfx/window.h>
#include <blt/gfx/shader.h>
#include <blt/gfx/state.h> #include <blt/gfx/state.h>
#include <blt/std/logging.h>
#include <imgui.h> #include <imgui.h>
#include "blt/gfx/imgui/IconsFontAwesome5.h" #include "blt/gfx/imgui/IconsFontAwesome5.h"
#include "blt/gfx/renderer/resource_manager.h" #include "blt/gfx/renderer/resource_manager.h"
#include "blt/gfx/renderer/batch_2d_renderer.h" #include "blt/gfx/renderer/batch_2d_renderer.h"
#include "blt/gfx/renderer/camera.h" #include "blt/gfx/renderer/camera.h"
#include <blt/gfx/loader/obj_loader.h> #include <blt/parse/obj_loader.h>
blt::gfx::matrix_state_manager global_matrices; blt::gfx::matrix_state_manager global_matrices;
blt::gfx::resource_manager resources; blt::gfx::resource_manager resources;
blt::gfx::batch_renderer_2d renderer_2d(resources); blt::gfx::batch_renderer_2d renderer_2d(resources);
blt::gfx::first_person_camera camera; blt::gfx::first_person_camera camera;
std::vector<blt::gfx::vertex_array*> vao; std::vector<blt::gfx::vertex_array*> vaos;
float x = 0, y = 0, z = 0; float x = 0, y = 0, z = 0;
float bx = 500, by = 500; float bx = 500, by = 500;
@ -60,11 +58,21 @@ void init()
vbo_t vertices_vbo; vbo_t vertices_vbo;
vertices_vbo.allocate(static_cast<long>(object.vertex_data().size() * sizeof(blt::gfx::constructed_vertex_t)), object.vertex_data().data()); vertices_vbo.allocate(static_cast<long>(object.vertex_data().size() * sizeof(blt::gfx::constructed_vertex_t)), object.vertex_data().data());
auto ptr = vertex_array::createSharedVBO(vertices_vbo);
for (auto obj : object.objects()) for (auto obj : object.objects())
{ {
vbo_t indices_vbo; vbo_t indices_vbo;
indices_vbo.allocate(static_cast<long>(obj.indices.size() * sizeof(blt::gfx::triangle_t)), obj.indices.data()); indices_vbo.allocate(static_cast<long>(obj.indices.size() * sizeof(blt::gfx::triangle_t)), obj.indices.data());
auto* vao = new vertex_array();
vao->bindVBO(ptr, 0, 3, GL_FLOAT, sizeof(float) * (3 + 3 + 2), 0);
vao->bindVBO(ptr, 1, 2, GL_FLOAT, sizeof(float) * (3 + 3 + 2), sizeof(float) * 3);
vao->bindVBO(ptr, 2, 3, GL_FLOAT, sizeof(float) * (3 + 3 + 2), sizeof(float) * (3 + 2));
vao->bindElement(indices_vbo);
vaos.push_back(vao);
} }
global_matrices.create_internals(); global_matrices.create_internals();
@ -98,6 +106,8 @@ int main()
global_matrices.cleanup(); global_matrices.cleanup();
resources.cleanup(); resources.cleanup();
renderer_2d.cleanup(); renderer_2d.cleanup();
for (auto* p : vaos)
delete p;
blt::gfx::cleanup(); blt::gfx::cleanup();
return 0; return 0;
} }