diff --git a/CMakeLists.txt b/CMakeLists.txt index adbd62ef..5ff709bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,14 @@ SET(obs-stream-effects_HEADERS "${PROJECT_SOURCE_DIR}/source/filter-shape.h" "${PROJECT_SOURCE_DIR}/source/filter-transform.h" "${PROJECT_SOURCE_DIR}/source/gs-helper.h" + "${PROJECT_SOURCE_DIR}/source/gs-effect.h" + "${PROJECT_SOURCE_DIR}/source/gs-indexbuffer.h" + "${PROJECT_SOURCE_DIR}/source/gs-mipmapper.h" + "${PROJECT_SOURCE_DIR}/source/gs-rendertarget.h" + "${PROJECT_SOURCE_DIR}/source/gs-texture.h" + "${PROJECT_SOURCE_DIR}/source/gs-vertex.h" + "${PROJECT_SOURCE_DIR}/source/gs-vertexbuffer.h" + "${PROJECT_SOURCE_DIR}/source/gs-mipmapper.h" "${PROJECT_BINARY_DIR}/source/version.h" "${PROJECT_SOURCE_DIR}/source/strings.h" ) @@ -40,6 +48,25 @@ SET(obs-stream-effects_SOURCES "${PROJECT_SOURCE_DIR}/source/filter-shape.cpp" "${PROJECT_SOURCE_DIR}/source/filter-transform.cpp" "${PROJECT_SOURCE_DIR}/source/gs-helper.cpp" + "${PROJECT_SOURCE_DIR}/source/gs-effect.cpp" + "${PROJECT_SOURCE_DIR}/source/gs-indexbuffer.cpp" + "${PROJECT_SOURCE_DIR}/source/gs-mipmapper.cpp" + "${PROJECT_SOURCE_DIR}/source/gs-rendertarget.cpp" + "${PROJECT_SOURCE_DIR}/source/gs-texture.cpp" + "${PROJECT_SOURCE_DIR}/source/gs-vertex.cpp" + "${PROJECT_SOURCE_DIR}/source/gs-vertexbuffer.cpp" + "${PROJECT_SOURCE_DIR}/source/gs-mipmapper.cpp" +) +SET(obs-stream-effects_LOCALE + "${PROJECT_SOURCE_DIR}/data/locale/en-US.ini" +) +SET(obs-stream-effects_EFFECTS + "${PROJECT_SOURCE_DIR}/data/effects/bilateral-blur.effect" + "${PROJECT_SOURCE_DIR}/data/effects/box-blur.effect" + "${PROJECT_SOURCE_DIR}/data/effects/gaussian-blur.effect" + "${PROJECT_SOURCE_DIR}/data/effects/displace.effect" + "${PROJECT_SOURCE_DIR}/data/effects/color-conversion.effect" + "${PROJECT_SOURCE_DIR}/data/effects/mip-mapper.effect" ) SET(obs-stream-effects_LOCALE "${PROJECT_SOURCE_DIR}/data/locale/en-US.ini" diff --git a/source/gs-effect.cpp b/source/gs-effect.cpp new file mode 100644 index 00000000..4c2f9dd5 --- /dev/null +++ b/source/gs-effect.cpp @@ -0,0 +1,228 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "gs-effect.h" +#include +extern "C" { + #pragma warning( push ) + #pragma warning( disable: 4201 ) + #include + #pragma warning( pop ) +} + +GS::Effect::Effect(std::string file) { + obs_enter_graphics(); + char* errorMessage = nullptr; + m_effect = gs_effect_create_from_file(file.c_str(), &errorMessage); + if (!m_effect || errorMessage) { + std::string error(errorMessage); + bfree((void*)errorMessage); + obs_leave_graphics(); + throw std::runtime_error(error); + } + obs_leave_graphics(); +} + +GS::Effect::Effect(std::string code, std::string name) { + obs_enter_graphics(); + char* errorMessage = nullptr; + m_effect = gs_effect_create(code.c_str(), name.c_str(), &errorMessage); + if (!m_effect || errorMessage) { + std::string error(errorMessage); + bfree((void*)errorMessage); + obs_leave_graphics(); + throw std::runtime_error(error); + } + obs_leave_graphics(); +} + +GS::Effect::~Effect() { + obs_enter_graphics(); + gs_effect_destroy(m_effect); + obs_leave_graphics(); +} + +gs_effect_t* GS::Effect::GetObject() { + return m_effect; +} + +std::vector GS::Effect::GetParameters() { + size_t num = gs_effect_get_num_params(m_effect); + std::vector ps; + ps.reserve(num); + for (size_t idx = 0; idx < num; idx++) { + ps.emplace_back(EffectParameter(gs_effect_get_param_by_idx(m_effect, idx))); + } + return ps; +} + +GS::EffectParameter GS::Effect::GetParameterByName(std::string name) { + gs_eparam_t* param = gs_effect_get_param_by_name(m_effect, name.c_str()); + if (!param) + throw std::invalid_argument("parameter with name not found"); + return EffectParameter(param); +} + +GS::EffectParameter::EffectParameter(gs_eparam_t* param) { + if (!param) + throw std::invalid_argument("param is null"); + + m_param = param; + gs_effect_get_param_info(m_param, &m_paramInfo); +} + +GS::EffectParameter::Type GS::EffectParameter::GetType() { + switch (m_paramInfo.type) { + case GS_SHADER_PARAM_BOOL: + return Type::Boolean; + case GS_SHADER_PARAM_FLOAT: + return Type::Float; + case GS_SHADER_PARAM_VEC2: + return Type::Float2; + case GS_SHADER_PARAM_VEC3: + return Type::Float3; + case GS_SHADER_PARAM_VEC4: + return Type::Float4; + case GS_SHADER_PARAM_INT: + return Type::Integer; + case GS_SHADER_PARAM_INT2: + return Type::Integer2; + case GS_SHADER_PARAM_INT3: + return Type::Integer3; + case GS_SHADER_PARAM_INT4: + return Type::Integer4; + case GS_SHADER_PARAM_MATRIX4X4: + return Type::Matrix; + case GS_SHADER_PARAM_TEXTURE: + return Type::Texture; + //case GS_SHADER_PARAM_STRING: + // return Type::String; + default: + case GS_SHADER_PARAM_UNKNOWN: + return Type::Unknown; + } +} + +void GS::EffectParameter::SetBoolean(bool v) { + if (GetType() != Type::Boolean) + throw std::bad_cast(); + gs_effect_set_bool(m_param, v); +} + +void GS::EffectParameter::SetBooleanArray(bool v[], size_t sz) { + if (GetType() != Type::Boolean) + throw std::bad_cast(); + gs_effect_set_val(m_param, v, sz); +} + +void GS::EffectParameter::SetFloat(float_t x) { + if (GetType() != Type::Float) + throw std::bad_cast(); + gs_effect_set_float(m_param, x); +} + +void GS::EffectParameter::SetFloat2(vec2& v) { + if (GetType() != Type::Float2) + throw std::bad_cast(); + gs_effect_set_vec2(m_param, &v); +} + +void GS::EffectParameter::SetFloat2(float_t x, float_t y) { + if (GetType() != Type::Float2) + throw std::bad_cast(); + float_t v[] = { x, y }; + SetFloatArray(v, 2); +} + +void GS::EffectParameter::SetFloat3(vec3& v) { + if (GetType() != Type::Float3) + throw std::bad_cast(); + gs_effect_set_vec3(m_param, &v); +} + +void GS::EffectParameter::SetFloat3(float_t x, float_t y, float_t z) { + if (GetType() != Type::Float3) + throw std::bad_cast(); + float_t v[] = { x, y, z }; + SetFloatArray(v, 3); +} + +void GS::EffectParameter::SetFloat4(vec4& v) { + if (GetType() != Type::Float4) + throw std::bad_cast(); + gs_effect_set_vec4(m_param, &v); +} + +void GS::EffectParameter::SetFloat4(float_t x, float_t y, float_t z, float_t w) { + if (GetType() != Type::Float4) + throw std::bad_cast(); + float_t v[] = { x, y, z, w }; + SetFloatArray(v, 4); +} + +void GS::EffectParameter::SetFloatArray(float_t v[], size_t sz) { + if (GetType() != Type::Float) + throw std::bad_cast(); + gs_effect_set_val(m_param, v, sz); +} + +void GS::EffectParameter::SetInteger(int32_t x) { + if (GetType() != Type::Integer) + throw std::bad_cast(); + gs_effect_set_int(m_param, x); +} + +void GS::EffectParameter::SetInteger2(int32_t x, int32_t y) { + if (GetType() != Type::Integer2) + throw std::bad_cast(); + int32_t v[] = { x, y }; + gs_effect_set_val(m_param, v, 2); +} + +void GS::EffectParameter::SetInteger3(int32_t x, int32_t y, int32_t z) { + if (GetType() != Type::Integer3) + throw std::bad_cast(); + int32_t v[] = { x, y, z }; + gs_effect_set_val(m_param, v, 3); +} + +void GS::EffectParameter::SetInteger4(int32_t x, int32_t y, int32_t z, int32_t w) { + if (GetType() != Type::Integer4) + throw std::bad_cast(); + int32_t v[] = { x, y, z, w }; + gs_effect_set_val(m_param, v, 4); +} + +void GS::EffectParameter::SetIntegerArray(int32_t v[], size_t sz) { + if (GetType() != Type::Integer) + throw std::bad_cast(); + gs_effect_set_val(m_param, v, sz); +} + +void GS::EffectParameter::SetMatrix(matrix4& v) { + if (GetType() != Type::Matrix) + throw std::bad_cast(); + gs_effect_set_matrix4(m_param, &v); +} + +void GS::EffectParameter::SetTexture(std::shared_ptr v) { + if (GetType() != Type::Texture) + throw std::bad_cast(); + gs_effect_set_texture(m_param, v->GetObject()); +} diff --git a/source/gs-effect.h b/source/gs-effect.h new file mode 100644 index 00000000..85412444 --- /dev/null +++ b/source/gs-effect.h @@ -0,0 +1,100 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once +#include "gs-texture.h" +#include +#include +#include +#include +extern "C" { + #pragma warning( push ) + #pragma warning( disable: 4201 ) + #include + #include + #include + #include + #include + #pragma warning( pop ) +} + +namespace GS { + class EffectParameter { + public: + enum class Type : uint8_t { + Unknown, + Boolean, + Float, + Float2, + Float3, + Float4, + Integer, + Integer2, + Integer3, + Integer4, + Matrix, + String, + Texture, + }; + + public: + EffectParameter(gs_eparam_t* param); + + Type GetType(); + + void SetBoolean(bool v); + void SetBooleanArray(bool v[], size_t sz); + void SetFloat(float_t x); + void SetFloat2(vec2& v); + void SetFloat2(float_t x, float_t y); + void SetFloat3(vec3& v); + void SetFloat3(float_t x, float_t y, float_t z); + void SetFloat4(vec4& v); + void SetFloat4(float_t x, float_t y, float_t z, float_t w); + void SetFloatArray(float_t v[], size_t sz); + void SetInteger(int32_t x); + void SetInteger2(int32_t x, int32_t y); + void SetInteger3(int32_t x, int32_t y, int32_t z); + void SetInteger4(int32_t x, int32_t y, int32_t z, int32_t w); + void SetIntegerArray(int32_t v[], size_t sz); + void SetMatrix(matrix4& v); + void SetTexture(std::shared_ptr v); + void SetTextureSampler(); + + private: + gs_eparam_t* m_param; + gs_effect_param_info m_paramInfo; + }; + + class Effect { + public: + Effect(std::string file); + Effect(std::string code, std::string name); + virtual ~Effect(); + + gs_effect_t* GetObject(); + + std::vector GetParameters(); + EffectParameter GetParameterByName(std::string name); + + + protected: + gs_effect_t* m_effect; + }; +} diff --git a/source/gs-helper.cpp b/source/gs-helper.cpp index f2f94136..85cdb112 100644 --- a/source/gs-helper.cpp +++ b/source/gs-helper.cpp @@ -18,96 +18,3 @@ */ #include "gs-helper.h" - -Helper::VertexBuffer::VertexBuffer(size_t maxVertices) { - m_positions.resize(maxVertices); - m_normals.resize(maxVertices); - m_tangents.resize(maxVertices); - m_colors.resize(maxVertices); - m_uvs.resize(8); - m_uvArrays.resize(8); - for (size_t idx = 0; idx < 8; idx++) { - m_uvs[idx].resize(maxVertices); - m_uvArrays[idx].width = 2; - m_uvArrays[idx].array = m_uvs[idx].data(); - } - - m_vertexData = gs_vbdata_create(); - m_vertexData->num = maxVertices; - m_vertexData->points = m_positions.data(); - m_vertexData->normals = m_normals.data(); - m_vertexData->tangents = m_normals.data(); - m_vertexData->colors = m_colors.data(); - m_vertexData->num_tex = m_uvs.size(); - m_vertexData->tvarray = m_uvArrays.data(); - - m_vertexBuffer = gs_vertexbuffer_create(m_vertexData, GS_DYNAMIC); -} - -Helper::VertexBuffer::~VertexBuffer() { - std::memset(m_vertexData, 0, sizeof(gs_vb_data)); - gs_vertexbuffer_destroy(m_vertexBuffer); -} - -void Helper::VertexBuffer::set_uv_layers(size_t count) { - size_t realcount = count > 8 ? 8 : count; - m_uvs.resize(realcount); -} - -size_t Helper::VertexBuffer::get_uv_layers() { - return m_uvs.size(); -} - -gs_vertbuffer_t* Helper::VertexBuffer::update() { - // Update Buffers - size_t verts = this->size(); - m_positions.resize(verts); - m_normals.resize(verts); - m_tangents.resize(verts); - m_colors.resize(verts); - for (size_t layer = 0; layer < m_uvs.size(); layer++) { - m_uvs[layer].resize(verts); - m_uvArrays[layer].width = 2; - m_uvArrays[layer].array = m_uvs[layer].data(); - } - - // Prepare Vertex Data - for (size_t vert = 0; vert < verts; vert++) { - Vertex& v = this->at(vert); - - vec3_copy(&(m_positions.at(vert)), &v.position); - vec3_copy(&(m_normals.at(vert)), &v.normal); - vec3_copy(&(m_tangents.at(vert)), &v.tangent); - m_colors[vert] = v.color; - for (size_t layer = 0; layer < m_uvs.size(); layer++) { - vec2_copy(&m_uvs[layer][vert], &v.uv[layer]); - } - } - - // Upload to GPU - m_vertexData->num = verts; - m_vertexData->points = m_positions.data(); - m_vertexData->normals = m_normals.data(); - m_vertexData->tangents = m_normals.data(); - m_vertexData->colors = m_colors.data(); - m_vertexData->num_tex = m_uvArrays.size(); - m_vertexData->tvarray = m_uvArrays.data(); - gs_vertexbuffer_flush(m_vertexBuffer); - return m_vertexBuffer; -} - -Helper::Vertex::Vertex() { - position.x = - position.y = - position.z = - normal.x = - normal.y = - normal.z = - tangent.x = - tangent.y = - tangent.z = 0; - color = 0; - for (size_t idx = 0; idx < 8; idx++) { - uv[idx].x = uv[idx].y = 0; - } -} diff --git a/source/gs-helper.h b/source/gs-helper.h index a3f74a56..985fea6d 100644 --- a/source/gs-helper.h +++ b/source/gs-helper.h @@ -19,45 +19,85 @@ #pragma once #include "plugin.h" - -extern "C" { -#pragma warning (push) -#pragma warning (disable: 4201) -#include "libobs/graphics/graphics.h" -#pragma warning (pop) -} - #include - -namespace Helper { - struct Vertex { - Vertex(); - - vec3 - position, - normal, - tangent; - vec2 uv[8]; - uint32_t - color; - }; - - class VertexBuffer : public std::vector { - public: - VertexBuffer(size_t maxVertices); - virtual ~VertexBuffer(); - - void set_uv_layers(size_t count); - size_t get_uv_layers(); - - gs_vertbuffer_t* update(); - - private: - gs_vb_data *m_vertexData; - gs_vertbuffer_t *m_vertexBuffer; - std::vector m_uvArrays; - std::vector m_positions, m_normals, m_tangents; - std::vector m_colors; - std::vector> m_uvs; - }; +extern "C" { + #pragma warning (push) + #pragma warning (disable: 4201) + #include "libobs/graphics/graphics.h" + #pragma warning (pop) +} + + +gs_effect_param* gs_effect_get_param(gs_effect_t* effect, const char* name) { + gs_effect_param* p = gs_effect_get_param_by_name(effect, name); + if (!p) + P_LOG_ERROR("Failed to find parameter %s in effect.", name); + return p; +} + +bool gs_set_param_int(gs_effect_t* effect, const char* name, int value) { + gs_effect_param* p = nullptr; + if (nullptr != (p = gs_effect_get_param(effect, name))) { + gs_effect_set_int(p, value); + return true; + } + P_LOG_ERROR("Failed to set value %d for parameter %s in" + " effect.", value, name); + return false; +} + +bool gs_set_param_float(gs_effect_t* effect, const char* name, float value) { + gs_effect_param* p = nullptr; + if (nullptr != (p = gs_effect_get_param(effect, name))) { + gs_effect_set_float(p, value); + return true; + } + P_LOG_ERROR("Failed to set value %f for parameter %s in" + " effect.", value, name); + return false; +} + +bool gs_set_param_float2(gs_effect_t* effect, const char* name, vec2* value) { + gs_effect_param* p = nullptr; + if (nullptr != (p = gs_effect_get_param(effect, name))) { + gs_effect_set_vec2(p, value); + return true; + } + P_LOG_ERROR("Failed to set value {%f,%f} for parameter %s" + " in effect.", value->x, value->y, name); + return false; +} + +bool gs_set_param_float3(gs_effect_t* effect, const char* name, vec3* value) { + gs_effect_param* p = nullptr; + if (nullptr != (p = gs_effect_get_param(effect, name))) { + gs_effect_set_vec3(p, value); + return true; + } + P_LOG_ERROR("Failed to set value {%f,%f,%f} for parameter" + "%s in effect.", value->x, value->y, value->z, name); + return false; +} + +bool gs_set_param_float4(gs_effect_t* effect, const char* name, vec4* value) { + gs_effect_param* p = nullptr; + if (nullptr != (p = gs_effect_get_param(effect, name))) { + gs_effect_set_vec4(p, value); + return true; + } + P_LOG_ERROR("Failed to set value {%f,%f,%f,%f} for" + " parameter %s in effect.", value->x, value->y, value->z, + value->w, name); + return false; +} + +bool gs_set_param_texture(gs_effect_t* effect, const char* name, gs_texture_t* value) { + gs_effect_param* p = nullptr; + if (nullptr != (p = gs_effect_get_param(effect, name))) { + gs_effect_set_texture(p, value); + return true; + } + P_LOG_ERROR("Failed to set texture for" + " parameter %s in effect.", name); + return false; } diff --git a/source/gs-indexbuffer.cpp b/source/gs-indexbuffer.cpp new file mode 100644 index 00000000..3c5169b9 --- /dev/null +++ b/source/gs-indexbuffer.cpp @@ -0,0 +1,65 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "gs-indexbuffer.h" +extern "C" { + #pragma warning( push ) + #pragma warning( disable: 4201 ) + #include + #pragma warning( pop ) +} + +const uint32_t defaultMaximumVertices = 65535u; + +GS::IndexBuffer::IndexBuffer(uint32_t maximumVertices) { + this->reserve(maximumVertices); + + obs_enter_graphics(); + m_indexBuffer = gs_indexbuffer_create(gs_index_type::GS_UNSIGNED_LONG, this->data(), maximumVertices, GS_DYNAMIC); + obs_leave_graphics(); +} + +GS::IndexBuffer::IndexBuffer() : IndexBuffer(defaultMaximumVertices) {} + +GS::IndexBuffer::IndexBuffer(IndexBuffer& other) : IndexBuffer(other.size()) { + std::copy(other.begin(), other.end(), this->end()); +} + +GS::IndexBuffer::IndexBuffer(std::vector& other) : IndexBuffer(other.size()) { + std::copy(other.begin(), other.end(), this->end()); +} + +GS::IndexBuffer::~IndexBuffer() { + obs_enter_graphics(); + gs_indexbuffer_destroy(m_indexBuffer); + obs_leave_graphics(); +} + +gs_indexbuffer_t* GS::IndexBuffer::get() { + return get(true); +} + +gs_indexbuffer_t* GS::IndexBuffer::get(bool refreshGPU) { + if (refreshGPU) { + obs_enter_graphics(); + gs_indexbuffer_flush(m_indexBuffer); + obs_leave_graphics(); + } + return m_indexBuffer; +} diff --git a/source/gs-indexbuffer.h b/source/gs-indexbuffer.h new file mode 100644 index 00000000..5c47adf8 --- /dev/null +++ b/source/gs-indexbuffer.h @@ -0,0 +1,46 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once +#include +#include +extern "C" { + #pragma warning( push ) + #pragma warning( disable: 4201 ) + #include + #pragma warning( pop ) +} + +namespace GS { + class IndexBuffer : public std::vector { + public: + IndexBuffer(uint32_t maximumVertices); + IndexBuffer(); + IndexBuffer(IndexBuffer& other); + IndexBuffer(std::vector& other); + virtual ~IndexBuffer(); + + gs_indexbuffer_t* get(); + + gs_indexbuffer_t* get(bool refreshGPU); + + protected: + gs_indexbuffer_t* m_indexBuffer; + }; +} diff --git a/source/gs-rendertarget.cpp b/source/gs-rendertarget.cpp new file mode 100644 index 00000000..dcaf4fdf --- /dev/null +++ b/source/gs-rendertarget.cpp @@ -0,0 +1,77 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "gs-rendertarget.h" +#include +extern "C" { + #pragma warning( push ) + #pragma warning( disable: 4201 ) + #include + #pragma warning( pop ) +} + +GS::RenderTarget::RenderTarget(gs_color_format colorFormat, gs_zstencil_format zsFormat) { + obs_enter_graphics(); + m_renderTarget = gs_texrender_create(colorFormat, zsFormat); + obs_leave_graphics(); +} + +GS::RenderTarget::~RenderTarget() { + obs_enter_graphics(); + gs_texrender_destroy(m_renderTarget); + obs_leave_graphics(); +} + +GS::RenderTargetOp GS::RenderTarget::Render(uint32_t width, uint32_t height) { + return { this, width, height }; +} + +gs_texture_t* GS::RenderTarget::GetTextureObject() { + obs_enter_graphics(); + return gs_texrender_get_texture(m_renderTarget); + obs_leave_graphics(); +} + +GS::RenderTargetOp::RenderTargetOp(GS::RenderTarget* rt, uint32_t width, uint32_t height) : m_renderTarget(rt) { + if (m_renderTarget == nullptr) + throw std::invalid_argument("rt"); + if (m_renderTarget->m_isBeingRendered) + throw std::logic_error("Can't start rendering to the same render target twice."); + obs_enter_graphics(); + if (!gs_texrender_begin(m_renderTarget->m_renderTarget, width, height)) { + obs_leave_graphics(); + throw std::runtime_error("Failed to begin rendering to render target."); + } + obs_leave_graphics(); + m_renderTarget->m_isBeingRendered = true; +} + +GS::RenderTargetOp::RenderTargetOp(GS::RenderTargetOp&& r) { + this->m_renderTarget = r.m_renderTarget; + r.m_renderTarget = nullptr; +} + +GS::RenderTargetOp::~RenderTargetOp() { + if (m_renderTarget == nullptr) + return; + obs_enter_graphics(); + gs_texrender_end(m_renderTarget->m_renderTarget); + obs_leave_graphics(); + m_renderTarget->m_isBeingRendered = false; +} diff --git a/source/gs-rendertarget.h b/source/gs-rendertarget.h new file mode 100644 index 00000000..ce1c62c3 --- /dev/null +++ b/source/gs-rendertarget.h @@ -0,0 +1,60 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once +#include +extern "C" { + #pragma warning( push ) + #pragma warning( disable: 4201 ) + #include + #pragma warning( pop ) +} + +namespace GS { + class RenderTarget { + friend class RenderTargetOp; + + public: + RenderTarget(gs_color_format colorFormat, gs_zstencil_format zsFormat); + virtual ~RenderTarget(); + + gs_texture_t* GetTextureObject(); + GS::RenderTargetOp Render(uint32_t width, uint32_t height); + + protected: + gs_texrender_t* m_renderTarget; + bool m_isBeingRendered; + }; + + class RenderTargetOp { + public: + RenderTargetOp(GS::RenderTarget* rt, uint32_t width, uint32_t height); + virtual ~RenderTargetOp(); + + // Move Constructor + RenderTargetOp(GS::RenderTargetOp&&); + + // Copy Constructor + RenderTargetOp(const GS::RenderTargetOp&) = delete; + RenderTargetOp& operator=(const GS::RenderTargetOp& r) = delete; + + protected: + GS::RenderTarget* m_renderTarget; + }; +} diff --git a/source/gs-texture.cpp b/source/gs-texture.cpp new file mode 100644 index 00000000..43923166 --- /dev/null +++ b/source/gs-texture.cpp @@ -0,0 +1,207 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "gs-texture.h" +#include +#include +#include +extern "C" { + #pragma warning( push ) + #pragma warning( disable: 4201 ) + #include + #include + #pragma warning( pop ) +} + +GS::Texture::Texture(uint32_t width, uint32_t height, gs_color_format format, uint32_t mip_levels, const uint8_t **mip_data, uint32_t flags) { + if (width == 0) + throw std::logic_error("width must be at least 1"); + if (height == 0) + throw std::logic_error("height must be at least 1"); + if (mip_levels == 0) + throw std::logic_error("mip_levels must be at least 1"); + if (!mip_data) + throw std::logic_error("mip_data is invalid"); + + if (mip_levels > 1 || flags & Flags::BuildMipMaps) { + bool isPOT = (pow(2, (int64_t)floor(log(width) / log(2))) == width) + && (pow(2, (int64_t)floor(log(height) / log(2))) == height); + if (!isPOT) + throw std::logic_error("mip mapping requires power of two dimensions"); + } + + obs_enter_graphics(); + m_texture = gs_texture_create(width, height, format, mip_levels, mip_data, (flags & Flags::Dynamic) ? GS_DYNAMIC : 0 | (flags & Flags::BuildMipMaps) ? GS_BUILD_MIPMAPS : 0); + obs_leave_graphics(); + + if (!m_texture) + throw std::runtime_error("Failed to create texture."); +} + +GS::Texture::Texture(uint32_t width, uint32_t height, uint32_t depth, gs_color_format format, uint32_t mip_levels, const uint8_t **mip_data, uint32_t flags) { + if (width == 0) + throw std::logic_error("width must be at least 1"); + if (height == 0) + throw std::logic_error("height must be at least 1"); + if (depth == 0) + throw std::logic_error("depth must be at least 1"); + if (mip_levels == 0) + throw std::logic_error("mip_levels must be at least 1"); + if (!mip_data) + throw std::logic_error("mip_data is invalid"); + + if (mip_levels > 1 || flags & Flags::BuildMipMaps) { + bool isPOT = (pow(2, (int64_t)floor(log(width) / log(2))) == width) + && (pow(2, (int64_t)floor(log(height) / log(2))) == height) + && (pow(2, (int64_t)floor(log(depth) / log(2))) == depth); + if (!isPOT) + throw std::logic_error("mip mapping requires power of two dimensions"); + } + + obs_enter_graphics(); + m_texture = gs_voltexture_create(width, height, depth, format, mip_levels, mip_data, (flags & Flags::Dynamic) ? GS_DYNAMIC : 0 | (flags & Flags::BuildMipMaps) ? GS_BUILD_MIPMAPS : 0); + obs_leave_graphics(); + + if (!m_texture) + throw std::runtime_error("Failed to create texture."); +} + +GS::Texture::Texture(uint32_t size, gs_color_format format, uint32_t mip_levels, const uint8_t **mip_data, uint32_t flags) { + if (size == 0) + throw std::logic_error("size must be at least 1"); + if (mip_levels == 0) + throw std::logic_error("mip_levels must be at least 1"); + if (!mip_data) + throw std::logic_error("mip_data is invalid"); + + if (mip_levels > 1 || flags & Flags::BuildMipMaps) { + bool isPOT = (pow(2, (int64_t)floor(log(size) / log(2))) == size); + if (!isPOT) + throw std::logic_error("mip mapping requires power of two dimensions"); + } + + obs_enter_graphics(); + m_texture = gs_cubetexture_create(size, format, mip_levels, mip_data, (flags & Flags::Dynamic) ? GS_DYNAMIC : 0 | (flags & Flags::BuildMipMaps) ? GS_BUILD_MIPMAPS : 0); + obs_leave_graphics(); + + if (!m_texture) + throw std::runtime_error("Failed to create texture."); +} + +GS::Texture::Texture(std::string file) { + struct stat st; + if (os_stat(file.c_str(), &st) != 0) + throw std::ios_base::failure(file); + + obs_enter_graphics(); + m_texture = gs_texture_create_from_file(file.c_str()); + obs_leave_graphics(); + + if (!m_texture) + throw std::runtime_error("Failed to load texture."); +} + +GS::Texture::Texture(Texture& other) { + throw std::logic_error("not yet implemented"); + //obs_enter_graphics(); + //switch (gs_get_texture_type(other.m_texture)) { + // case GS_TEXTURE_2D: + // uint32_t width = gs_texture_get_width(other.m_texture); + // uint32_t height = gs_texture_get_height(other.m_texture); + // gs_color_format format = gs_texture_get_color_format(other.m_texture); + // uint32_t mult = 0; + // switch (format) { + // case GS_A8: + // case GS_R8: + // mult = 1; + // break; + // case GS_R16: + // case GS_R16F: + // mult = 2; + // break; + // case GS_RG16F: + // case GS_R32F: + // case GS_BGRA: + // case GS_BGRX: + // case GS_RGBA: + // case GS_R10G10B10A2: + // mult = 4; + // break; + // case GS_RGBA16: + // case GS_RGBA16F: + // case GS_RG32F: + // mult = 8; + // break; + // case GS_RGBA32F: + // mult = 16; + // break; + // case GS_DXT1: + // case GS_DXT3: + // case GS_DXT5: + // mult = 8; + // break; + // } + // uint8_t* buf = new uint8_t[width * height * mult]; + // m_texture = gs_texture_create(width, height, format, + // 1, &buf); + // delete buf; + // break; + // case GS_TEXTURE_3D: + // uint32_t width = gs_voltexture_get_width(other.m_texture); + // uint32_t height = gs_voltexture_get_height(other.m_texture); + // uint32_t depth = gs_voltexture_get_height(other.m_texture); + // gs_color_format format = gs_voltexture_get_color_format(other.m_texture); + // break; + // case GS_TEXTURE_CUBE: + // uint32_t size = gs_cubetexture_get_size(other.m_texture); + // gs_color_format format = gs_cubetexture_get_color_format(other.m_texture); + // gs_copy_texture() + // break; + //} + //obs_leave_graphics(); +} + +GS::Texture::~Texture() { + if (m_texture) { + obs_enter_graphics(); + switch (gs_get_texture_type(m_texture)) { + case GS_TEXTURE_2D: + gs_texture_destroy(m_texture); + break; + case GS_TEXTURE_3D: + gs_voltexture_destroy(m_texture); + break; + case GS_TEXTURE_CUBE: + gs_cubetexture_destroy(m_texture); + break; + } + obs_leave_graphics(); + } + m_texture = nullptr; +} + +void GS::Texture::Load(int unit) { + obs_enter_graphics(); + gs_load_texture(m_texture, unit); + obs_leave_graphics(); +} + +gs_texture_t* GS::Texture::GetObject() { + return m_texture; +} diff --git a/source/gs-texture.h b/source/gs-texture.h new file mode 100644 index 00000000..8e93b781 --- /dev/null +++ b/source/gs-texture.h @@ -0,0 +1,148 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once +#include +#include +extern "C" { + #pragma warning( push ) + #pragma warning( disable: 4201 ) + #include + #pragma warning( pop ) +} + +namespace GS { + class Texture { + public: + enum Type : uint8_t { + Normal, + Volume, + Cube + }; + + enum Flags : uint32_t { + Dynamic, + BuildMipMaps, + }; + + public: + /*! + * \brief Create a new texture from data + * + * + * + * \param width + * \param height + * \param format + * \param mip_levels + * \param mip_data + * \param flags + */ + Texture(uint32_t width, uint32_t height, gs_color_format format, uint32_t mip_levels, const uint8_t **mip_data, uint32_t flags); + + /*! + * \brief Create a new volume texture from data + * + * + * + * \param width + * \param height + * \param depth + * \param format + * \param mip_levels + * \param mip_data + * \param flags + */ + Texture(uint32_t width, uint32_t height, uint32_t depth, gs_color_format format, uint32_t mip_levels, const uint8_t **mip_data, uint32_t flags); + + /*! + * \brief Create a new cube texture from data + * + * + * + * \param size + * \param format + * \param mip_levels + * \param mip_data + * \param flags + */ + Texture(uint32_t size, gs_color_format format, uint32_t mip_levels, const uint8_t **mip_data, uint32_t flags); + + /*! + * \brief Load a texture from a file + * + * Creates a new #GS::Texture from a file located on disk. If the + * file can not be found, accessed or read, a #Plugin::file_not_found_error + * will be thrown. If there is an error reading the file, a + * #Plugin::io_error will be thrown. + * + * \param file File to create the texture from. + */ + Texture(std::string file);// { LoadFromFile(file); } + + /*! + * \brief Copy an existing texture + * + * Create a Texture instance from an existing texture. + * This will not take ownership of the underlying gs_texture_t object. + * + * \param other + * \return + */ + Texture(Texture& other); + + /*! + * \brief Default constructor + */ + Texture() : m_texture(nullptr) {} + + /*! + * \brief Destructor + * + * + * + * \return + */ + virtual ~Texture(); + + /*! + * \brief + * + * + * + * \param unit + * \return void + */ + void Load(int unit); + + /*! + * \brief + * + * + * + * \return gs_texture_t* + */ + gs_texture_t* GetObject(); + + protected: + gs_texture_t* m_texture; + + void DestroyTexture(); + }; +} diff --git a/source/gs-vertex.cpp b/source/gs-vertex.cpp new file mode 100644 index 00000000..69a59c79 --- /dev/null +++ b/source/gs-vertex.cpp @@ -0,0 +1,20 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "gs-vertexbuffer.h" diff --git a/source/gs-vertex.h b/source/gs-vertex.h new file mode 100644 index 00000000..06c2d193 --- /dev/null +++ b/source/gs-vertex.h @@ -0,0 +1,39 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once +#include +extern "C" { + #pragma warning( push ) + #pragma warning( disable: 4201 ) + #include + #pragma warning( pop ) +} + +namespace GS { + const uint32_t MAXIMUM_UVW_LAYERS = 8u; + // ToDo: Optimize for use with GS::VertexBuffer so that it doesn't require in-memory copy. + struct Vertex { + vec3 position; + vec3 normal; + vec3 tangent; + vec4 uv[MAXIMUM_UVW_LAYERS]; + uint32_t color; + }; +} diff --git a/source/gs-vertexbuffer.cpp b/source/gs-vertexbuffer.cpp new file mode 100644 index 00000000..be16adbb --- /dev/null +++ b/source/gs-vertexbuffer.cpp @@ -0,0 +1,123 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "gs-vertexbuffer.h" +#include +extern "C" { + #pragma warning( push ) + #pragma warning( disable: 4201 ) + #include + #pragma warning( pop ) +} + +const uint32_t defaultMaximumVertices = 65535u; + +GS::VertexBuffer::VertexBuffer(uint32_t maximumVertices) { + m_maximumVertices = maximumVertices; + m_uvwLayers = MAXIMUM_UVW_LAYERS; + + // Reserve Space + m_vertexbufferdata.num = m_maximumVertices; + m_data.positions.resize(m_maximumVertices); + m_vertexbufferdata.points = m_data.positions.data(); + m_data.normals.resize(m_maximumVertices); + m_vertexbufferdata.normals = m_data.normals.data(); + m_data.tangents.resize(m_maximumVertices); + m_vertexbufferdata.tangents = m_data.tangents.data(); + m_data.colors.resize(m_maximumVertices); + m_vertexbufferdata.colors = m_data.colors.data(); + m_vertexbufferdata.num_tex = m_uvwLayers; + m_data.uvws.resize(m_uvwLayers); + m_data.uvwdata.resize(m_uvwLayers); + for (uint32_t n = 0; n < m_uvwLayers; n++) { + m_data.uvws[n].resize(m_maximumVertices); + m_data.uvwdata[n].width = 4; + m_data.uvwdata[n].array = m_data.uvws[n].data(); + } + m_vertexbufferdata.tvarray = m_data.uvwdata.data(); + + // Allocate GPU + obs_enter_graphics(); + m_vertexbuffer = gs_vertexbuffer_create(&m_vertexbufferdata, GS_DYNAMIC); + obs_leave_graphics(); + if (!m_vertexbuffer) { + throw std::runtime_error("Failed to create vertex buffer."); + } +} + +GS::VertexBuffer::VertexBuffer(gs_vertbuffer_t* vb) { + m_vertexbuffer = vb; +} + +GS::VertexBuffer::VertexBuffer() : VertexBuffer(defaultMaximumVertices) {} + +GS::VertexBuffer::VertexBuffer(std::vector& other) : VertexBuffer((uint32_t)other.capacity()) { + std::copy(other.begin(), other.end(), this->end()); +} + +GS::VertexBuffer::VertexBuffer(VertexBuffer& other) : VertexBuffer(other.m_maximumVertices) { + std::copy(other.begin(), other.end(), this->end()); +} + +GS::VertexBuffer::~VertexBuffer() { + if (m_vertexbuffer) { + std::memset(&m_vertexbufferdata, 0, sizeof(m_vertexbufferdata)); + obs_enter_graphics(); + gs_vertexbuffer_destroy(m_vertexbuffer); + obs_leave_graphics(); + } + m_vertexbuffer = nullptr; +} + +void GS::VertexBuffer::set_uv_layers(uint32_t layers) { + m_uvwLayers = layers; +} + +uint32_t GS::VertexBuffer::uv_layers() { + return m_uvwLayers; +} + +gs_vertbuffer_t* GS::VertexBuffer::get(bool refreshGPU) { + if (refreshGPU) { + if (size() > m_maximumVertices) + throw std::runtime_error("Too many vertices in Vertex Buffer."); + + for (size_t vertexIdx = 0; vertexIdx < size(); vertexIdx++) { + Vertex& v = this->at(vertexIdx); + vec3_copy(&m_data.positions[vertexIdx], &(v.position)); + vec3_copy(&m_data.normals[vertexIdx], &(v.normal)); + vec3_copy(&m_data.tangents[vertexIdx], &(v.tangent)); + for (size_t texcoordIdx = 0; texcoordIdx < m_uvwLayers; texcoordIdx++) { + vec4_copy(&m_data.uvws[texcoordIdx][vertexIdx], &(v.uv[texcoordIdx])); + } + m_data.colors[vertexIdx] = v.color; + } + m_vertexbufferdata.num = size(); + m_vertexbufferdata.num_tex = m_uvwLayers; + + obs_enter_graphics(); + gs_vertexbuffer_flush(m_vertexbuffer); + obs_leave_graphics(); + } + return m_vertexbuffer; +} + +gs_vertbuffer_t* GS::VertexBuffer::get() { + return get(true); +} diff --git a/source/gs-vertexbuffer.h b/source/gs-vertexbuffer.h new file mode 100644 index 00000000..29eba154 --- /dev/null +++ b/source/gs-vertexbuffer.h @@ -0,0 +1,93 @@ +/* + * Modern effects for a modern Streamer + * Copyright (C) 2017 Michael Fabian Dirks + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once +#include "gs-vertex.h" +#include +#include +extern "C" { + #pragma warning( push ) + #pragma warning( disable: 4201 ) + #include + #pragma warning( pop ) +} + +namespace GS { + class VertexBuffer : public std::vector { + public: + /*! + * \brief Create a Vertex Buffer with specific size + * + * \param maximumVertices Maximum amount of vertices to store. + */ + VertexBuffer(uint32_t maximumVertices); + + /*! + * \brief Create a Vertex Buffer with default size + * This will create a new vertex buffer with the default maximum size. + * + */ + VertexBuffer(); + + /*! + * \brief Create a copy of a Vertex Buffer + * Full Description below + * + * \param other The Vertex Buffer to copy + */ + VertexBuffer(VertexBuffer& other); + + /*! + * \brief Create a Vertex Buffer from a Vertex array + * Full Description below + * + * \param other The Vertex array to use + */ + VertexBuffer(std::vector& other); + + + VertexBuffer(gs_vertbuffer_t* vb); + + virtual ~VertexBuffer(); + + void set_uv_layers(uint32_t layers); + + uint32_t uv_layers(); + + gs_vertbuffer_t* get(); + + gs_vertbuffer_t* get(bool refreshGPU); + + protected: + uint32_t m_maximumVertices; + uint32_t m_uvwLayers; + gs_vb_data m_vertexbufferdata; + gs_vertbuffer_t* m_vertexbuffer; + + // Data Storage + struct { + std::vector positions; + std::vector normals; + std::vector tangents; + std::vector colors; + std::vector> uvws; + std::vector uvwdata; + } m_data; + }; +}