gs: Wrap OBS Graphics Subsystem in proper C++ classes

This commit is contained in:
Michael Fabian Dirks 2017-09-17 21:55:16 +02:00
parent 52b70ff6de
commit eb1612c6ee
15 changed files with 1313 additions and 133 deletions

View file

@ -30,6 +30,14 @@ SET(obs-stream-effects_HEADERS
"${PROJECT_SOURCE_DIR}/source/filter-shape.h" "${PROJECT_SOURCE_DIR}/source/filter-shape.h"
"${PROJECT_SOURCE_DIR}/source/filter-transform.h" "${PROJECT_SOURCE_DIR}/source/filter-transform.h"
"${PROJECT_SOURCE_DIR}/source/gs-helper.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_BINARY_DIR}/source/version.h"
"${PROJECT_SOURCE_DIR}/source/strings.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-shape.cpp"
"${PROJECT_SOURCE_DIR}/source/filter-transform.cpp" "${PROJECT_SOURCE_DIR}/source/filter-transform.cpp"
"${PROJECT_SOURCE_DIR}/source/gs-helper.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 SET(obs-stream-effects_LOCALE
"${PROJECT_SOURCE_DIR}/data/locale/en-US.ini" "${PROJECT_SOURCE_DIR}/data/locale/en-US.ini"

228
source/gs-effect.cpp Normal file
View file

@ -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 <stdexcept>
extern "C" {
#pragma warning( push )
#pragma warning( disable: 4201 )
#include <libobs/obs.h>
#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::EffectParameter> GS::Effect::GetParameters() {
size_t num = gs_effect_get_num_params(m_effect);
std::vector<GS::EffectParameter> 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<GS::Texture> v) {
if (GetType() != Type::Texture)
throw std::bad_cast();
gs_effect_set_texture(m_param, v->GetObject());
}

100
source/gs-effect.h Normal file
View file

@ -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 <inttypes.h>
#include <memory>
#include <string>
#include <vector>
extern "C" {
#pragma warning( push )
#pragma warning( disable: 4201 )
#include <libobs/graphics/graphics.h>
#include <libobs/graphics/matrix4.h>
#include <libobs/graphics/vec4.h>
#include <libobs/graphics/vec3.h>
#include <libobs/graphics/vec2.h>
#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<GS::Texture> 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<EffectParameter> GetParameters();
EffectParameter GetParameterByName(std::string name);
protected:
gs_effect_t* m_effect;
};
}

View file

@ -18,96 +18,3 @@
*/ */
#include "gs-helper.h" #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;
}
}

View file

@ -19,45 +19,85 @@
#pragma once #pragma once
#include "plugin.h" #include "plugin.h"
extern "C" {
#pragma warning (push)
#pragma warning (disable: 4201)
#include "libobs/graphics/graphics.h"
#pragma warning (pop)
}
#include <vector> #include <vector>
extern "C" {
namespace Helper { #pragma warning (push)
struct Vertex { #pragma warning (disable: 4201)
Vertex(); #include "libobs/graphics/graphics.h"
#pragma warning (pop)
vec3 }
position,
normal,
tangent; gs_effect_param* gs_effect_get_param(gs_effect_t* effect, const char* name) {
vec2 uv[8]; gs_effect_param* p = gs_effect_get_param_by_name(effect, name);
uint32_t if (!p)
color; P_LOG_ERROR("Failed to find parameter %s in effect.", name);
}; return p;
}
class VertexBuffer : public std::vector<Vertex> {
public: bool gs_set_param_int(gs_effect_t* effect, const char* name, int value) {
VertexBuffer(size_t maxVertices); gs_effect_param* p = nullptr;
virtual ~VertexBuffer(); if (nullptr != (p = gs_effect_get_param(effect, name))) {
gs_effect_set_int(p, value);
void set_uv_layers(size_t count); return true;
size_t get_uv_layers(); }
P_LOG_ERROR("Failed to set value %d for parameter %s in"
gs_vertbuffer_t* update(); " effect.", value, name);
return false;
private: }
gs_vb_data *m_vertexData;
gs_vertbuffer_t *m_vertexBuffer; bool gs_set_param_float(gs_effect_t* effect, const char* name, float value) {
std::vector<gs_tvertarray> m_uvArrays; gs_effect_param* p = nullptr;
std::vector<vec3> m_positions, m_normals, m_tangents; if (nullptr != (p = gs_effect_get_param(effect, name))) {
std::vector<uint32_t> m_colors; gs_effect_set_float(p, value);
std::vector<std::vector<vec2>> m_uvs; 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;
} }

65
source/gs-indexbuffer.cpp Normal file
View file

@ -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 <libobs/obs.h>
#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<uint32_t>& 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;
}

46
source/gs-indexbuffer.h Normal file
View file

@ -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 <inttypes.h>
#include <vector>
extern "C" {
#pragma warning( push )
#pragma warning( disable: 4201 )
#include <libobs/graphics/graphics.h>
#pragma warning( pop )
}
namespace GS {
class IndexBuffer : public std::vector<uint32_t> {
public:
IndexBuffer(uint32_t maximumVertices);
IndexBuffer();
IndexBuffer(IndexBuffer& other);
IndexBuffer(std::vector<uint32_t>& other);
virtual ~IndexBuffer();
gs_indexbuffer_t* get();
gs_indexbuffer_t* get(bool refreshGPU);
protected:
gs_indexbuffer_t* m_indexBuffer;
};
}

View file

@ -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 <stdexcept>
extern "C" {
#pragma warning( push )
#pragma warning( disable: 4201 )
#include <libobs/obs.h>
#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;
}

60
source/gs-rendertarget.h Normal file
View file

@ -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 <inttypes.h>
extern "C" {
#pragma warning( push )
#pragma warning( disable: 4201 )
#include <libobs/graphics/graphics.h>
#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;
};
}

207
source/gs-texture.cpp Normal file
View file

@ -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 <stdexcept>
#include <sys/stat.h>
#include <fstream>
extern "C" {
#pragma warning( push )
#pragma warning( disable: 4201 )
#include <libobs/util/platform.h>
#include <libobs/obs.h>
#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;
}

148
source/gs-texture.h Normal file
View file

@ -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 <inttypes.h>
#include <string>
extern "C" {
#pragma warning( push )
#pragma warning( disable: 4201 )
#include <libobs/graphics/graphics.h>
#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();
};
}

20
source/gs-vertex.cpp Normal file
View file

@ -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"

39
source/gs-vertex.h Normal file
View file

@ -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 <inttypes.h>
extern "C" {
#pragma warning( push )
#pragma warning( disable: 4201 )
#include <libobs/graphics/vec3.h>
#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;
};
}

123
source/gs-vertexbuffer.cpp Normal file
View file

@ -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 <stdexcept>
extern "C" {
#pragma warning( push )
#pragma warning( disable: 4201 )
#include <libobs/obs.h>
#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<Vertex>& 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);
}

93
source/gs-vertexbuffer.h Normal file
View file

@ -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 <inttypes.h>
#include <vector>
extern "C" {
#pragma warning( push )
#pragma warning( disable: 4201 )
#include <libobs/graphics/graphics.h>
#pragma warning( pop )
}
namespace GS {
class VertexBuffer : public std::vector<Vertex> {
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<Vertex>& 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<vec3> positions;
std::vector<vec3> normals;
std::vector<vec3> tangents;
std::vector<uint32_t> colors;
std::vector<std::vector<vec4>> uvws;
std::vector<gs_tvertarray> uvwdata;
} m_data;
};
}