- fix vertex array object binding bug

- add shader program
- fix that alpha color was stored in red channel in Color4
- fix buffer upload bug
This commit is contained in:
Magnus Norddahl 2019-08-12 08:33:40 +02:00
parent fd37c455d2
commit 2eaf323ad0
15 changed files with 331 additions and 42 deletions

View file

@ -6,6 +6,7 @@ using System.Threading.Tasks;
namespace CodeImp.DoomBuilder.Rendering
{
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 4)]
public struct Matrix
{
public float M11, M12, M13, M14;
@ -189,7 +190,7 @@ namespace CodeImp.DoomBuilder.Rendering
result.M11 = xScale;
result.M22 = yScale;
result.M33 = zfar / (znear - zfar);
result.M43 = -znear * zfar / (znear - zfar);
result.M43 = -2.0f * znear * zfar / (znear - zfar);
result.M34 = 1.0f;
return result;
}
@ -203,7 +204,7 @@ namespace CodeImp.DoomBuilder.Rendering
result.M11 = xScale;
result.M22 = yScale;
result.M33 = zfar / (znear - zfar);
result.M43 = znear * zfar / (znear - zfar);
result.M43 = 2.0f * znear * zfar / (znear - zfar);
result.M34 = -1.0f;
return result;
}

View file

@ -125,19 +125,19 @@ namespace CodeImp.DoomBuilder.Rendering
// To ColorValue
public Color4 ToColorValue()
{
return new Color4(a * BYTE_TO_FLOAT,
r * BYTE_TO_FLOAT,
return new Color4(r * BYTE_TO_FLOAT,
g * BYTE_TO_FLOAT,
b * BYTE_TO_FLOAT);
b * BYTE_TO_FLOAT,
a * BYTE_TO_FLOAT);
}
// To ColorValue
public Color4 ToColorValue(float withalpha)
{
return new Color4(withalpha,
r * BYTE_TO_FLOAT,
return new Color4(r * BYTE_TO_FLOAT,
g * BYTE_TO_FLOAT,
b * BYTE_TO_FLOAT);
b * BYTE_TO_FLOAT,
withalpha);
}
// This returns a new PixelColor with adjusted alpha

View file

@ -72,11 +72,6 @@ namespace CodeImp.DoomBuilder.Rendering
RenderDevice_SetAlphaBlendEnable(Handle, value);
}
public void SetAlphaRef(int value)
{
RenderDevice_SetAlphaRef(Handle, value);
}
public void SetAlphaTestEnable(bool value)
{
RenderDevice_SetAlphaTestEnable(Handle, value);
@ -232,7 +227,6 @@ namespace CodeImp.DoomBuilder.Rendering
{
// Setup renderstates
SetAlphaBlendEnable(false);
SetAlphaRef(0x0000007E);
SetAlphaTestEnable(false);
SetCullMode(Cull.None);
SetDestinationBlend(Blend.InverseSourceAlpha);
@ -276,9 +270,6 @@ namespace CodeImp.DoomBuilder.Rendering
[DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void RenderDevice_SetAlphaBlendEnable(IntPtr handle, bool value);
[DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void RenderDevice_SetAlphaRef(IntPtr handle, int value);
[DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void RenderDevice_SetAlphaTestEnable(IntPtr handle, bool value);

View file

@ -207,6 +207,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="RenderDevice.cpp" />
<ClCompile Include="Shader.cpp" />
<ClCompile Include="Texture.cpp" />
<ClCompile Include="VertexBuffer.cpp" />
<ClCompile Include="VertexDeclaration.cpp" />
@ -218,6 +219,7 @@
<ClInclude Include="OpenGLContext.h" />
<ClInclude Include="Precomp.h" />
<ClInclude Include="RenderDevice.h" />
<ClInclude Include="Shader.h" />
<ClInclude Include="Texture.h" />
<ClInclude Include="VertexBuffer.h" />
<ClInclude Include="VertexDeclaration.h" />

View file

@ -10,6 +10,8 @@
<Filter>gl_load</Filter>
</ClCompile>
<ClCompile Include="OpenGLContext.cpp" />
<ClCompile Include="Precomp.cpp" />
<ClCompile Include="Shader.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="IndexBuffer.h" />
@ -24,6 +26,8 @@
<Filter>gl_load</Filter>
</ClInclude>
<ClInclude Include="OpenGLContext.h" />
<ClInclude Include="Precomp.h" />
<ClInclude Include="Shader.h" />
</ItemGroup>
<ItemGroup>
<None Include="exports.def" />

View file

@ -13,7 +13,7 @@ IndexBuffer::~IndexBuffer()
void IndexBuffer::SetBufferData(const void* data, int64_t size)
{
if (size > 0 && size < (int64_t)mData.size())
if (size > 0 && size <= (int64_t)mData.size())
memcpy(mData.data(), data, size);
}

View file

@ -111,6 +111,20 @@ void OpenGLContext::SwapBuffers()
End();
}
int OpenGLContext::GetWidth() const
{
RECT box = { 0 };
GetClientRect(window, &box);
return box.right;
}
int OpenGLContext::GetHeight() const
{
RECT box = { 0 };
GetClientRect(window, &box);
return box.bottom;
}
/////////////////////////////////////////////////////////////////////////////
OpenGLCreationHelper::OpenGLCreationHelper(HWND window) : window(window)

View file

@ -10,6 +10,9 @@ public:
void End();
void SwapBuffers();
int GetWidth() const;
int GetHeight() const;
explicit operator bool() const { return context != 0; }
private:

View file

@ -3,6 +3,7 @@
#include <cstdint>
#include <vector>
#include <map>
#include <memory>
#include <Windows.h>
#include "gl_load/gl_system.h"

View file

@ -5,8 +5,64 @@
#include "IndexBuffer.h"
#include "VertexDeclaration.h"
#include "Texture.h"
#include "Shader.h"
#include <stdexcept>
const char* mainVertexShader = R"(
#version 150
in vec4 AttrPosition;
in vec4 AttrColor;
in vec2 AttrUV;
in vec3 AttrNormal;
out vec4 Color;
out vec2 UV;
out vec3 Normal;
uniform mat4 World;
uniform mat4 View;
uniform mat4 Projection;
void main()
{
Color = AttrColor;
UV = AttrUV;
Normal = AttrNormal;
gl_Position = Projection * View * World * AttrPosition;
}
)";
const char* mainFragmentShader = R"(
#version 150
in vec4 Color;
in vec2 UV;
in vec3 Normal;
out vec4 FragColor;
void main()
{
FragColor = vec4(UV, 1.0, 1.0);
}
)";
RenderDevice::RenderDevice(HWND hwnd) : Context(hwnd)
{
if (Context)
{
Context.Begin();
mShader = std::make_unique<Shader>();
if (!mShader->Compile(mainVertexShader, mainFragmentShader))
{
throw std::runtime_error(mShader->GetErrors());
}
Context.End();
}
}
RenderDevice::~RenderDevice()
{
}
@ -24,34 +80,44 @@ void RenderDevice::SetIndexBuffer(IndexBuffer* buffer)
void RenderDevice::SetAlphaBlendEnable(bool value)
{
}
void RenderDevice::SetAlphaRef(int value)
{
mAlphaBlend = value;
mNeedApply = true;
}
void RenderDevice::SetAlphaTestEnable(bool value)
{
mAlphaTest = value;
mNeedApply = true;
}
void RenderDevice::SetCullMode(Cull mode)
{
mCullMode = mode;
mNeedApply = true;
}
void RenderDevice::SetBlendOperation(BlendOperation op)
{
mBlendOperation = op;
mNeedApply = true;
}
void RenderDevice::SetSourceBlend(Blend blend)
{
mSourceBlend = blend;
mNeedApply = true;
}
void RenderDevice::SetDestinationBlend(Blend blend)
{
mDestinationBlend = blend;
mNeedApply = true;
}
void RenderDevice::SetFillMode(FillMode mode)
{
mFillMode = mode;
mNeedApply = true;
}
void RenderDevice::SetFogEnable(bool value)
@ -80,10 +146,14 @@ void RenderDevice::SetTextureFactor(int factor)
void RenderDevice::SetZEnable(bool value)
{
mDepthTest = value;
mNeedApply = true;
}
void RenderDevice::SetZWriteEnable(bool value)
{
mDepthWrite = value;
mNeedApply = true;
}
void RenderDevice::SetTransform(TransformState state, float* matrix)
@ -128,12 +198,12 @@ void RenderDevice::StartRendering(bool clear, int backcolor, Texture* target, bo
{
glClearColor(RPART(backcolor) / 255.0f, GPART(backcolor) / 255.0f, BPART(backcolor) / 255.0f, APART(backcolor) / 255.0f);
glClearDepthf(1.0f);
glClear(GL_COLOR | GL_DEPTH);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
else if (clear)
{
glClearColor(RPART(backcolor) / 255.0f, GPART(backcolor) / 255.0f, BPART(backcolor) / 255.0f, APART(backcolor) / 255.0f);
glClear(GL_COLOR);
glClear(GL_COLOR_BUFFER_BIT);
}
Context.End();
}
@ -155,16 +225,80 @@ void RenderDevice::CopyTexture(Texture* src, Texture* dst, CubeMapFace face)
{
}
void RenderDevice::CheckError()
{
GLenum error = glGetError();
if (error != GL_NO_ERROR)
throw std::runtime_error("OpenGL error!");
}
void RenderDevice::ApplyChanges()
{
ApplyShader();
ApplyVertexBuffers();
ApplyIndexBuffer();
ApplyMatrices();
ApplyTextures();
ApplyRasterizerState();
ApplyBlendState();
ApplyDepthState();
CheckError();
mNeedApply = false;
}
void RenderDevice::ApplyShader()
{
glUseProgram(mShader->GetProgram());
}
void RenderDevice::ApplyRasterizerState()
{
if (mCullMode == Cull::None)
{
glDisable(GL_CULL_FACE);
}
else
{
glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);
}
GLenum fillMode2GL[] = { GL_FILL, GL_LINE };
glPolygonMode(GL_FRONT_AND_BACK, fillMode2GL[(int)mFillMode]);
}
void RenderDevice::ApplyBlendState()
{
if (mAlphaBlend)
{
static const GLenum blendOp2GL[] = { GL_FUNC_ADD, GL_FUNC_REVERSE_SUBTRACT };
static const GLenum blendFunc2GL[] = { GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE, GL_CONSTANT_COLOR };
glEnable(GL_BLEND);
glBlendEquation(blendOp2GL[(int)mBlendOperation]);
glBlendFunc(blendFunc2GL[(int)mSourceBlend], blendFunc2GL[(int)mDestinationBlend]);
}
else
{
glDisable(GL_BLEND);
}
}
void RenderDevice::ApplyDepthState()
{
if (mDepthTest)
{
glEnable(GL_DEPTH_TEST);
glDepthMask(mDepthWrite ? GL_TRUE : GL_FALSE);
}
else
{
glDisable(GL_DEPTH_TEST);
}
}
void RenderDevice::ApplyIndexBuffer()
{
if (mIndexBuffer)
@ -180,11 +314,17 @@ void RenderDevice::ApplyIndexBuffer()
void RenderDevice::ApplyVertexBuffers()
{
static const int typeSize[] = { 2, 3, 4 };
static const int type[] = { GL_FLOAT, GL_FLOAT, GL_UNSIGNED_BYTE };
static const int type[] = { GL_FLOAT, GL_FLOAT, GL_BGRA };
static const int typeNormalized[] = { GL_FALSE, GL_FALSE, GL_TRUE };
if (mVertexDeclaration)
{
if (!mVAO)
{
glGenVertexArrays(1, &mVAO);
glBindVertexArray(mVAO);
}
for (size_t i = 0; i < mVertexDeclaration->Elements.size(); i++)
{
const auto& element = mVertexDeclaration->Elements[i];
@ -193,11 +333,12 @@ void RenderDevice::ApplyVertexBuffers()
if (vertBinding.Buffer)
{
GLuint vertexbuffer = vertBinding.Buffer->GetBuffer();
glEnableVertexAttribArray(location);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glEnableVertexAttribArray(location);
glVertexAttribPointer(location, typeSize[(int)element.Type], type[(int)element.Type], typeNormalized[(int)element.Type], vertBinding.Stride, (const void*)(element.Offset + (ptrdiff_t)vertBinding.Offset));
mEnabledVertexAttributes[location] = 2;
break;
}
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
@ -207,7 +348,7 @@ void RenderDevice::ApplyVertexBuffers()
{
if (mEnabledVertexAttributes[i] == 2)
{
mEnabledVertexAttributes[i]--;
mEnabledVertexAttributes[i] = 1;
}
else if (mEnabledVertexAttributes[i] == 1)
{
@ -219,10 +360,10 @@ void RenderDevice::ApplyVertexBuffers()
void RenderDevice::ApplyMatrices()
{
for (size_t i = 0; i < NumTransforms; i++)
for (size_t i = 0; i < (size_t)TransformState::NumTransforms; i++)
{
auto& binding = mTransforms[i];
glUniformMatrix4fv((GLuint)i, 1, GL_FALSE, binding.Values);
glUniformMatrix4fv(mShader->TransformLocations[i], 1, GL_FALSE, binding.Values);
}
}
@ -244,6 +385,7 @@ void RenderDevice::ApplyTextures()
void RenderDevice::ApplyRenderTarget(Texture* target, bool usedepthbuffer)
{
glViewport(0, 0, Context.GetWidth(), Context.GetHeight());
}
/////////////////////////////////////////////////////////////////////////////
@ -282,11 +424,6 @@ void RenderDevice_SetAlphaBlendEnable(RenderDevice* device, bool value)
device->SetAlphaBlendEnable(value);
}
void RenderDevice_SetAlphaRef(RenderDevice* device, int value)
{
device->SetAlphaRef(value);
}
void RenderDevice_SetAlphaTestEnable(RenderDevice* device, bool value)
{
device->SetAlphaTestEnable(value);

View file

@ -6,13 +6,14 @@ class VertexBuffer;
class IndexBuffer;
class VertexDeclaration;
class Texture;
class Shader;
enum class CubeMapFace;
enum class Cull : int { None, Counterclockwise };
enum class Blend : int { InverseSourceAlpha, SourceAlpha, One, BlendFactor };
enum class BlendOperation : int { Add, ReverseSubtract };
enum class FillMode : int { Solid, Wireframe };
enum class TransformState : int { World, View, Projection };
enum class TransformState : int { World, View, Projection, NumTransforms };
enum class TextureAddress : int { Wrap, Clamp };
enum class ShaderFlags : int { None, Debug };
enum class PrimitiveType : int { LineList, TriangleList, TriangleStrip };
@ -22,11 +23,11 @@ class RenderDevice
{
public:
RenderDevice(HWND hwnd);
~RenderDevice();
void SetVertexBuffer(int index, VertexBuffer* buffer, long offset, long stride);
void SetIndexBuffer(IndexBuffer* buffer);
void SetAlphaBlendEnable(bool value);
void SetAlphaRef(int value);
void SetAlphaTestEnable(bool value);
void SetCullMode(Cull mode);
void SetBlendOperation(BlendOperation op);
@ -55,10 +56,16 @@ public:
void ApplyChanges();
void ApplyVertexBuffers();
void ApplyIndexBuffer();
void ApplyShader();
void ApplyMatrices();
void ApplyTextures();
void ApplyRasterizerState();
void ApplyBlendState();
void ApplyDepthState();
void ApplyRenderTarget(Texture* target, bool usedepthbuffer);
void CheckError();
OpenGLContext Context;
struct VertexBinding
@ -87,12 +94,31 @@ public:
TextureAddress AddressW = TextureAddress::Wrap;
};
enum { NumTransforms = 3, NumSlots = 16 };
Mat4f mTransforms[NumTransforms];
enum { NumSlots = 16 };
Mat4f mTransforms[(int)TransformState::NumTransforms];
VertexDeclaration *mVertexDeclaration = nullptr;
GLuint mVAO = 0;
int mEnabledVertexAttributes[NumSlots] = { 0 };
VertexBinding mVertexBindings[NumSlots];
SamplerState mSamplerStates[NumSlots];
IndexBuffer* mIndexBuffer = nullptr;
std::unique_ptr<Shader> mShader;
Cull mCullMode = Cull::None;
FillMode mFillMode = FillMode::Solid;
bool mAlphaTest = false;
bool mAlphaBlend = false;
BlendOperation mBlendOperation = BlendOperation::Add;
Blend mSourceBlend = Blend::SourceAlpha;
Blend mDestinationBlend = Blend::InverseSourceAlpha;
bool mDepthTest = false;
bool mDepthWrite = false;
bool mNeedApply = true;
};

83
Source/Native/Shader.cpp Normal file
View file

@ -0,0 +1,83 @@
#include "Precomp.h"
#include "Shader.h"
#include "VertexDeclaration.h"
#include "RenderDevice.h"
#include <stdexcept>
Shader::Shader()
{
}
Shader::~Shader()
{
// To do: move to delete list
}
bool Shader::Compile(const std::string& vertexShader, const std::string& fragmentShader)
{
mVertexShader = CompileShader(vertexShader, GL_VERTEX_SHADER);
if (!mVertexShader)
return false;
mFragmentShader = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);
if (!mFragmentShader)
return false;
mProgram = glCreateProgram();
glAttachShader(mProgram, mVertexShader);
glAttachShader(mProgram, mFragmentShader);
glBindAttribLocation(mProgram, (GLuint)DeclarationUsage::Position, "AttrPosition");
glBindAttribLocation(mProgram, (GLuint)DeclarationUsage::Color, "AttrColor");
glBindAttribLocation(mProgram, (GLuint)DeclarationUsage::TextureCoordinate, "AttrUV");
glBindAttribLocation(mProgram, (GLuint)DeclarationUsage::Normal, "AttrNormal");
glLinkProgram(mProgram);
GLint status = 0;
glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
if (status != GL_TRUE)
{
GLsizei length = 0;
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &length);
std::vector<GLchar> errors(length + (size_t)1);
glGetProgramInfoLog(mProgram, (GLsizei)errors.size(), &length, errors.data());
mErrors = { errors.begin(), errors.begin() + length };
glDeleteProgram(mProgram);
glDeleteShader(mVertexShader);
glDeleteShader(mFragmentShader);
mProgram = 0;
mVertexShader = 0;
mFragmentShader = 0;
return false;
}
TransformLocations[(int)TransformState::World] = glGetUniformLocation(mProgram, "World");
TransformLocations[(int)TransformState::View] = glGetUniformLocation(mProgram, "View");
TransformLocations[(int)TransformState::Projection] = glGetUniformLocation(mProgram, "Projection");
return mProgram;
}
GLuint Shader::CompileShader(const std::string& code, GLenum type)
{
GLuint shader = glCreateShader(type);
const GLchar* sources[] = { (GLchar*)code.data() };
const GLint lengths[] = { (GLint)code.size() };
glShaderSource(shader, 1, sources, lengths);
glCompileShader(shader);
GLint status = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE)
{
GLsizei length = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
std::vector<GLchar> errors(length + (size_t)1);
glGetShaderInfoLog(shader, (GLsizei)errors.size(), &length, errors.data());
mErrors = { errors.begin(), errors.begin() + length };
glDeleteShader(shader);
return 0;
}
return shader;
}

29
Source/Native/Shader.h Normal file
View file

@ -0,0 +1,29 @@
#pragma once
#include <string>
#include "RenderDevice.h"
class Shader
{
public:
Shader();
~Shader();
bool Compile(const std::string& vertexShader, const std::string& fragmentShader);
const char* GetErrors() const { return mErrors.c_str(); }
GLuint GetProgram() const { return mProgram; }
GLuint TransformLocations[(int)TransformState::NumTransforms] = { 0 };
private:
GLuint CompileShader(const std::string& code, GLenum type);
GLuint mProgram = 0;
GLuint mVertexShader = 0;
GLuint mFragmentShader = 0;
std::string mErrors;
Shader(const Shader&) = delete;
Shader& operator=(const Shader&) = delete;
};

View file

@ -13,13 +13,13 @@ VertexBuffer::~VertexBuffer()
void VertexBuffer::SetBufferData(const void* data, int64_t size)
{
if (size > 0 && size < (int64_t)mData.size())
if (size > 0 && size <= (int64_t)mData.size())
memcpy(mData.data(), data, size);
}
void VertexBuffer::SetBufferSubdata(int64_t destOffset, const void* data, int64_t size)
{
if (destOffset >= 0 && size > 0 && size < (int64_t)mData.size() - destOffset)
if (destOffset >= 0 && size > 0 && size <= (int64_t)mData.size() - destOffset)
memcpy(mData.data() + destOffset, data, size);
}
@ -30,7 +30,6 @@ GLuint VertexBuffer::GetBuffer()
glGenBuffers(1, &mBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mBuffer);
glBufferData(GL_ARRAY_BUFFER, mData.size(), mData.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
return mBuffer;
}

View file

@ -6,7 +6,6 @@ EXPORTS
RenderDevice_SetVertexBuffer
RenderDevice_SetIndexBuffer
RenderDevice_SetAlphaBlendEnable
RenderDevice_SetAlphaRef
RenderDevice_SetAlphaTestEnable
RenderDevice_SetCullMode
RenderDevice_SetBlendOperation