diff options
Diffstat (limited to 'Client/Source/Graphics')
43 files changed, 2852 insertions, 0 deletions
diff --git a/Client/Source/Graphics/Color.cpp b/Client/Source/Graphics/Color.cpp new file mode 100644 index 0000000..88b1ed8 --- /dev/null +++ b/Client/Source/Graphics/Color.cpp @@ -0,0 +1,4 @@ +#include "Color.h" + +const Color32 Color32::white = Color32(255, 255, 255, 255); + diff --git a/Client/Source/Graphics/Color.h b/Client/Source/Graphics/Color.h new file mode 100644 index 0000000..f7bb937 --- /dev/null +++ b/Client/Source/Graphics/Color.h @@ -0,0 +1,48 @@ +#pragma once + +struct Color +{ + Color(float r = 0, float g = 0, float b = 0, float a = 0) + { + this->r = r; + this->g = g; + this->b = b; + this->a = a; + } + void Set(float r = 0, float g = 0, float b = 0, float a = 0) + { + this->r = r; + this->g = g; + this->b = b; + this->a = a; + } + float r, g, b, a; +}; + +struct Color32 +{ + Color32(unsigned char r = 0, unsigned char g = 0, unsigned char b = 0, unsigned char a = 0) + { + this->r = r; + this->g = g; + this->b = b; + this->a = a; + } + void Set(unsigned char r = 0, unsigned char g = 0, unsigned char b = 0, unsigned char a = 0) + { + this->r = r; + this->g = g; + this->b = b; + this->a = a; + } + + bool operator !=(const Color32& col) + { + return !(r == col.r && g == col.g && b == col.b && a == col.a); + } + + unsigned char r, g, b, a; + + static const Color32 white; +}; + diff --git a/Client/Source/Graphics/CustomVertexLayout.cpp b/Client/Source/Graphics/CustomVertexLayout.cpp new file mode 100644 index 0000000..aa6be9b --- /dev/null +++ b/Client/Source/Graphics/CustomVertexLayout.cpp @@ -0,0 +1,23 @@ +#include "CustomVertexLayout.h" + +namespace VertexLayout +{ + + void SetupCustomVertexLayout(CustomVertexLayout& info) + { + glBindBuffer(GL_ARRAY_BUFFER, info.buffer); + for (int i = 0; i < info.attributes.size(); ++i) + { + VertexAttributeDescriptor& attr = info.attributes[i]; + glEnableVertexAttribArray(i); + int numCompo = attr.componentNum; + GLenum compoType = VertexAttribute::ConvertAttrFormatToGLFormat(attr.componentFormat); + bool normalized = attr.normalize; + uint stride = attr.stride; + const void* pointer = attr.pointer; + + glVertexAttribPointer(i, numCompo, compoType, normalized ? GL_TRUE : GL_FALSE, stride, pointer); + } + } + +} diff --git a/Client/Source/Graphics/CustomVertexLayout.h b/Client/Source/Graphics/CustomVertexLayout.h new file mode 100644 index 0000000..3b54039 --- /dev/null +++ b/Client/Source/Graphics/CustomVertexLayout.h @@ -0,0 +1,33 @@ +#pragma once + +#include <vector> +#include "OpenGL.h" +#include "GPUDataBuffer.h" +#include "VertexAttribute.h" + +struct CustomVertexLayout +{ + GLuint buffer; // 创建时留空 + std::vector<VertexAttributeDescriptor> attributes; + + CustomVertexLayout() + { + int n = buffer; + } + + // 重置pointer(startOffset)为0 + void RestorePointer() + { + for (int i = 0; i < attributes.size(); ++i) + { + attributes[i].pointer = 0; + } + } +}; + +namespace VertexLayout +{ + + extern void SetupCustomVertexLayout(CustomVertexLayout& layout); + +} diff --git a/Client/Source/Graphics/DefaultVertexLayout.cpp b/Client/Source/Graphics/DefaultVertexLayout.cpp new file mode 100644 index 0000000..a468100 --- /dev/null +++ b/Client/Source/Graphics/DefaultVertexLayout.cpp @@ -0,0 +1,119 @@ +#include "DefaultVertexLayout.h" + +namespace VertexLayout +{ + // 默认vertex layout + static const int kVertexAttrSize[VertexAttr_Count] = { + 3 * sizeof(float), // position + 3 * sizeof(float), // normal + 4 * sizeof(float), // tangent + 4 * sizeof(byte), // color + 2 * sizeof(float), // uv + 2 * sizeof(float), // uv2 + 2 * sizeof(float), // uv3 + 2 * sizeof(float), // uv4 + }; + + static const int kVertexAttrDimension[VertexAttr_Count] = { + 3, // position + 3, // normal + 4, // tangent + 4, // color + 2, // uv + 2, // uv2 + 2, // uv3 + 2, // uv4 + }; + + bool IsGLVertexAttrNeedNormalized(uint attr/*, uint format*/) + { + if (attr == VertexAttr_Color) + return true; + /* + if (format == VertexAttrFormat_Color || format == VertexAttrFormat_Byte) + return true; + */ + return false; + } + + uint GetDefaultShaderChannelFormat(uint attr) + { + return attr == VertexAttr_Color ? VertexAttrFormat_Color : VertexAttrFormat_Float; + } + + uint32 GetDefaultVertexAttrSize(int attr) + { + return kVertexAttrSize[attr]; + } + + uint GetDefaultVertexAttrDimension(uint attr) + { + return kVertexAttrDimension[attr]; + } + + uint GetDefaultShaderChannelDimension(uint attr) + { + return attr == VertexAttr_Color ? 4 : GetDefaultVertexAttrDimension(attr); + } + + GLenum GetDefaultVertexAttrcomponentFormat(uint attr) + { + uint componentFormat = GetDefaultShaderChannelFormat(attr); + return VertexAttribute::ConvertAttrFormatToGLFormat(componentFormat); + } + + uint32 GetDynamicChunkStride(uint32 vertexAttrMask) + { + uint32 stride = 0; + for (int i = 0; i < vertexAttrMask; ++i) + { + if (vertexAttrMask & Mask(i)) + stride += VertexLayout::GetDefaultVertexAttrSize(i); + } + return stride; + } + + static uint32 sEnabledArrays = 0; + + void SetupDefaultVertexLayout(const DefaultVertexLayout& info) + { + glBindBuffer(GL_ARRAY_BUFFER, info.buffer); + + for (int attrIdx = 0; attrIdx < VertexAttr_Count; ++attrIdx) + { + if (info.enableMask & Mask(attrIdx)) + { + if (!sEnabledArrays & Mask(attrIdx)) + glEnableVertexAttribArray(attrIdx); + int numCompo = info.attributes[attrIdx].componentNum; + GLenum compoType = VertexLayout::GetDefaultVertexAttrcomponentFormat(attrIdx); + bool normalized = VertexLayout::IsGLVertexAttrNeedNormalized(attrIdx); + uint stride = info.attributes[attrIdx].stride; + const void* pointer = info.attributes[attrIdx].pointer; + + glVertexAttribPointer(attrIdx, numCompo, compoType, normalized ? GL_TRUE : GL_FALSE, stride, pointer); + } + else if (sEnabledArrays & Mask(attrIdx)) + glDisableVertexAttribArray(attrIdx); + } + sEnabledArrays = info.enableMask; + } + + void InvalidateVertexInputCache() + { + sEnabledArrays = 0; + for (int attrIdx = 0; attrIdx < VertexAttr_Count; ++attrIdx) + glDisableVertexAttribArray(attrIdx); + } + + // 索引保存为 unsgined short (GL_UNSIGNED_SHORT) + uint GetDefaultIndexSize() + { + return sizeof(uint16); + } + GLenum GetDefaultIndexFormat() + { + return GL_UNSIGNED_SHORT; + } + +} diff --git a/Client/Source/Graphics/DefaultVertexLayout.h b/Client/Source/Graphics/DefaultVertexLayout.h new file mode 100644 index 0000000..2222ff1 --- /dev/null +++ b/Client/Source/Graphics/DefaultVertexLayout.h @@ -0,0 +1,55 @@ +#pragma once + +#include <vector> + +#include "../Utilities/Type.h" +#include "../Utilities/UtilMacros.h" + +#include "OpenGL.h" +#include "GPUDataBuffer.h" +#include "VertexAttribute.h" + +// 默认的顶点布局,适用于Mesh导入的结果,以保持shader的一致性 +// 如果需要修改布局,比如编辑器UI中,用CustomVertexLayout + +// 默认的顶点属性以及顺序 +enum EVertexAttr +{ + VertexAttr_Position = 0, + VertexAttr_Normal, + VertexAttr_Tangent, + VertexAttr_Color, + VertexAttr_UV, + VertexAttr_UV2, + VertexAttr_UV3, + VertexAttr_UV4, + + VertexAttr_Count +}; + +// GPU侧的默认顶点属性 +struct DefaultVertexLayout +{ + uint32 enableMask; + GLuint buffer; // vbo或者0(pinned memory) + VertexAttributeDescriptor attributes[VertexAttr_Count]; +}; + +namespace VertexLayout +{ + // ibo无论是default还是custom布局都是short + uint GetDefaultIndexSize(); + GLenum GetDefaultIndexFormat(); + + uint32 GetDynamicChunkStride(uint32 vertexAttrMask); + bool IsGLVertexAttrNeedNormalized(uint attr); + uint GetDefaultShaderChannelFormat(uint attr); + uint32 GetDefaultVertexAttrSize(int attr); + uint GetDefaultVertexAttrDimension(uint attr); + uint GetDefaultShaderChannelDimension(uint attr); + GLenum GetDefaultVertexAttrComponentType(uint attr); + + void SetupDefaultVertexLayout(const DefaultVertexLayout& info); + void InvalidateVertexInputCache(); + +} diff --git a/Client/Source/Graphics/DeviceDefine.h b/Client/Source/Graphics/DeviceDefine.h new file mode 100644 index 0000000..db1c138 --- /dev/null +++ b/Client/Source/Graphics/DeviceDefine.h @@ -0,0 +1,69 @@ +#ifndef DEVICE_DEFINE_H +#define DEVICE_DEFINE_H + +enum EDeviceEnable +{ + Enable_DepthTest = 1, + Enable_DepthWrite = 1 << 1, + Enable_StencilTest = 1 << 2, + Enable_StencilWrite = 1 << 3, + Enable_Cull = 1 << 4, + Enable_Blend = 1 << 5, + Enable_AntiAliasing = 1 << 6, +}; + +enum EDepthTest +{ + DepthTest_Greater = 1, + DepthTest_GreaterEqual, + DepthTest_Less, + DepthTest_LessEqual, + DepthTest_Equal, + DepthTest_NotEqual, + DepthTest_Always, +}; + +enum EStencilTest { + StencilTest_Always, + StencilTest_Never, + StencilTest_Less, + StencilTest_Equal, + StencilTest_NotEqual, + StencilTest_LessEqual, + StencilTest_Greater, + StencilTest_GreaterEqual, +}; + +enum EStencilOp { + StencilOp_Keep, + StencilOp_Zero, + StencilOp_Replace, + StencilOp_Incr, + StencilOp_IncrWrap, + StencilOp_Decr, + StencilOp_DecrWrap, + StencilOp_Invert, +}; + +enum EDeviceClear +{ + Clear_DepthBuffer = 1, + Clear_StencilBuffer = 1 << 1, + Clear_ColorBuffer = 1 << 2, +}; + +enum ECullFace +{ + Cull_Front = 1, + Cull_Back = 2, + Cull_None = 3, + Cull_All = 4, +}; + +enum EBlendMode +{ + Blend_Additive = 1, + Blend_Substract = 1, +}; + +#endif
\ No newline at end of file diff --git a/Client/Source/Graphics/DynamicMesh.h b/Client/Source/Graphics/DynamicMesh.h new file mode 100644 index 0000000..94fef4d --- /dev/null +++ b/Client/Source/Graphics/DynamicMesh.h @@ -0,0 +1,13 @@ +#pragma once +#include "../Utilities/StaticInitiator.h" + +// 填充g_SharedVBO的动态mesh +class DynamicMesh +{ +public: + DynamicMesh() {}; + virtual ~DynamicMesh() {}; + + virtual void Draw() = 0; + +}; diff --git a/Client/Source/Graphics/DynamicVertexBuffer.cpp b/Client/Source/Graphics/DynamicVertexBuffer.cpp new file mode 100644 index 0000000..8041e30 --- /dev/null +++ b/Client/Source/Graphics/DynamicVertexBuffer.cpp @@ -0,0 +1,260 @@ +#include "DynamicVertexBuffer.h" +#include "CustomVertexLayout.h" + +DynamicVertexBuffer::DynamicVertexBuffer() +{ +} + +DynamicVertexBuffer::~DynamicVertexBuffer() +{ +} + +//------------------------------------------------------------------------------------------------------------ +// Defualt Vertex Layout + +//GetChunk +//-> ReleaseChunk +//-> DrawChunk + +void DynamicVertexBuffer::GetChunk(uint attrsMask, int maxVerts, int maxIndices, EPrimitive primitive, void **out_vb, void **out_ib) +{ + Assert(out_vb && out_ib); + + uint stride = VertexLayout::GetDynamicChunkStride(attrsMask); // data size of single vertex + GetChunk(stride, maxVerts, VertexLayout::GetDefaultIndexSize(), maxIndices, primitive, out_vb, out_ib); + + // default layout + m_CurAttrMask = attrsMask; + m_CurStride = stride; +} + +void DynamicVertexBuffer::DrawChunk() +{ + DefaultVertexLayout vertexArray; + FillDefaultVertexLayout(vertexArray); + + // bind vertex attributes data + VertexLayout::SetupDefaultVertexLayout(vertexArray); + + const void* indexPtr = m_CurIB ? 0 : (m_CurIBData.empty() ? 0 : &m_CurIBData[0]); + + if (m_CurIB) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_CurIB->GetHandle()); + + GLenum indexFormat = VertexLayout::GetDefaultIndexFormat(); + + switch (m_CurPrimitive) + { + case Primitive_Triangle: + glDrawElements(GL_TRIANGLES, m_CurIndexCount, indexFormat, indexPtr); + break; + case Primitive_Line: + glDrawElements(GL_LINE, m_CurIndexCount, indexFormat, indexPtr); + break; + case Primitive_Point: + glDrawElements(GL_POINT, m_CurIndexCount, indexFormat, indexPtr); + break; + } + + if (m_CurIB) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + // End draw + Clean(); +} + +void DynamicVertexBuffer::FillDefaultVertexLayout(DefaultVertexLayout& dst) +{ + const byte* basepointer = m_CurVB ? 0 : &m_CurVBData[0]; + const GLuint buffer = m_CurVB ? m_CurVB->GetHandle() : 0; + + int attrOffsets[VertexAttr_Count] = { 0 }; + { + uint32 curOffset = 0; + for (uint idx = 0; idx < VertexAttr_Count; ++idx) + { + if (m_CurAttrMask & Mask(idx)) + { + attrOffsets[idx] = curOffset; + curOffset += VertexLayout::GetDefaultVertexAttrSize(idx); + } + } + } + + dst.buffer = buffer; + + for (uint32 attrIdx = 0; attrIdx < VertexAttr_Count; ++attrIdx) + { + if (m_CurAttrMask & Mask(attrIdx)) + { + dst.attributes[attrIdx].pointer = basepointer + attrOffsets[attrIdx]; + dst.attributes[attrIdx].componentFormat = VertexLayout::GetDefaultShaderChannelFormat(attrIdx); + dst.attributes[attrIdx].componentNum = VertexLayout::GetDefaultShaderChannelDimension(attrIdx); + dst.attributes[attrIdx].stride = m_CurStride; + + dst.enableMask |= Mask(attrIdx); + } + } +} + +//------------------------------------------------------------------------------------------------------------ +// Custom Vertex Layout + +// 用buffersize为依据决定用vbo或者pinned memory +void DynamicVertexBuffer::GetChunk(uint sizePerVert, uint sizePerIndex, int maxVerts, int maxIndices, EPrimitive primitive, void **out_vb, void **out_ib) +{ + Assert(out_vb && out_ib); + + m_CurStride = sizePerVert; + uint vbufferSize = sizePerVert * maxVerts; + uint ibufferSize = sizePerIndex * maxIndices; + + const bool mapVertexBuffer = vbufferSize >= kDataBufferThreshold; + const bool mapIndexBuffer = ibufferSize >= kDataBufferThreshold; + + GLenum usage = GL_STREAM_DRAW; + + GPU::DataBuffer* vertexBuffer = mapVertexBuffer ? GPU::ClaimBuffer(vbufferSize, usage) : 0; + GPU::DataBuffer* indexBuffer = mapIndexBuffer ? GPU::ClaimBuffer(ibufferSize, usage) : 0; + + if (vertexBuffer && vertexBuffer->GetSize() < vbufferSize) + vertexBuffer->Restore(vbufferSize, usage); + + if (indexBuffer && indexBuffer->GetSize() < ibufferSize) + indexBuffer->Restore(ibufferSize, usage); + + if (!mapVertexBuffer && m_CurVBData.size() < vbufferSize) + m_CurVBData.resize(vbufferSize); + + if (!mapIndexBuffer && m_CurIBData.size() < ibufferSize) + m_CurIBData.resize(ibufferSize); + + const GLenum access = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT; + + if (vertexBuffer) + *out_vb = vertexBuffer->MapRange(0, vbufferSize, access); + else + *out_vb = &m_CurVBData[0]; + + if (indexBuffer) + *out_ib = indexBuffer->MapRange(0, ibufferSize, access); + else + *out_ib = &m_CurIBData[0]; + + m_CurVB = vertexBuffer; + m_CurIB = indexBuffer; + + m_CurPrimitive = primitive; +} + +void DynamicVertexBuffer::FillCustomVertexLayout(CustomVertexLayout& dst) +{ + const byte* basepointer = m_CurVB ? 0 : &m_CurVBData[0]; + const GLuint buffer = m_CurVB ? m_CurVB->GetHandle() : 0; + + dst.buffer = buffer; + + for (int i = 0; i < dst.attributes.size(); ++i) + { + int offset = dst.attributes[i].startOffset; + dst.attributes[i].pointer = basepointer + offset; + } +} + +void DynamicVertexBuffer::DrawChunk(CustomVertexLayout& layout) +{ + const byte* basepointer = m_CurVB ? 0 : &m_CurVBData[0]; + const GLuint buffer = m_CurVB ? m_CurVB->GetHandle() : 0; + + FillCustomVertexLayout(layout); + + VertexLayout::SetupCustomVertexLayout(layout); + + layout.RestorePointer(); + + const void* indexPtr = m_CurIB ? 0 : (m_CurIBData.empty() ? 0 : &m_CurIBData[0]); + + if (m_CurIB) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_CurIB->GetHandle()); + + GLenum indexFormat = VertexLayout::GetDefaultIndexFormat(); + + switch (m_CurPrimitive) + { + case Primitive_Triangle: + glDrawElements(GL_TRIANGLES, m_CurIndexCount, indexFormat, indexPtr); + break; + case Primitive_Line: + glDrawElements(GL_LINES, m_CurIndexCount, indexFormat, indexPtr); + break; + case Primitive_Point: + glDrawElements(GL_POINTS, m_CurIndexCount, indexFormat, indexPtr); + break; + } + + if (m_CurIB) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + // End draw + Clean(); +} + +//------------------------------------------------------------------------------------------------------------ +// Both Default and Custom Vertex Layout + +void DynamicVertexBuffer::ReleaseChunk(int actualVerts, int actualIndices) +{ + int actualVBufferSize = m_CurStride * actualVerts; + int actualIBufferSize = VertexLayout::GetDefaultIndexSize() * actualIndices; + + const GLenum usage = GL_STREAM_DRAW; + + if (m_CurVB) + { + m_CurVB->FlushMapedRange(0, actualVBufferSize); + m_CurVB->UnMap(); + } + else if (actualVBufferSize >= kDataBufferThreshold) + { + m_CurVB = GPU::ClaimBuffer(actualVBufferSize, usage); + m_CurVB->RestoreWithData(actualVBufferSize, usage, &m_CurVBData[0]); + } + + if (m_CurIB) + { + m_CurIB->FlushMapedRange(0, actualIBufferSize); + m_CurIB->UnMap(); + } + else if (actualIBufferSize >= kDataBufferThreshold) + { + m_CurIB = GPU::ClaimBuffer(0, usage); + m_CurIB->RestoreWithData(0, usage, &m_CurIBData[0]); + } + + m_CurVertexCount = actualVerts; + m_CurIndexCount = actualIndices; +} + +void DynamicVertexBuffer::Clean() +{ + if (m_CurVB) + { + GPU::ReleaseBuffer(m_CurVB); + m_CurVB = 0; + } + + if (m_CurIB) + { + GPU::ReleaseBuffer(m_CurIB); + m_CurIB = 0; + } + + m_CurPrimitive = Primitive_Triangle; + m_CurAttrMask = 0; + m_CurStride = 0; + m_CurVertexCount = 0; + m_CurIndexCount = 0; + + m_CurVBData.clear(); + m_CurIBData.clear(); +} diff --git a/Client/Source/Graphics/DynamicVertexBuffer.h b/Client/Source/Graphics/DynamicVertexBuffer.h new file mode 100644 index 0000000..ad65d80 --- /dev/null +++ b/Client/Source/Graphics/DynamicVertexBuffer.h @@ -0,0 +1,54 @@ +#pragma once +#include <vector> + +#include "../Utilities/UtilMacros.h" + +#include "OpenGL.h" +#include "GPUDataBuffer.h" +#include "DefaultVertexLayout.h" +#include "CustomVertexLayout.h" +#include "Primitive.h" + +// 动态填充的VBO +class DynamicVertexBuffer +{ +public: + DynamicVertexBuffer(); + ~DynamicVertexBuffer(); + + // default layout + void GetChunk(uint attrs, int maxVerts, int maxIndices, EPrimitive primitive, void **out_vb, void **out_ib); + void DrawChunk(); + + // custom layout + void GetChunk(uint sizePerVert, uint sizePerIndex, int maxVerts, int maxIndices, EPrimitive primitive, void **out_vb, void **out_ib); + void DrawChunk(CustomVertexLayout& layout); + + // common + void ReleaseChunk(int actualVerts, int actualIndices); + +private: + + void FillCustomVertexLayout(CustomVertexLayout& dst); + void FillDefaultVertexLayout(DefaultVertexLayout& dst); + + void Clean(); + + // 如果数据大小小于这个限制,用内存数据,而不是glBufferData + static const int kDataBufferThreshold = 1024; + + GPU::DataBuffer *m_CurVB; + GPU::DataBuffer *m_CurIB; + + std::vector<byte> m_CurVBData; + std::vector<uint16> m_CurIBData; + + EPrimitive m_CurPrimitive; + + uint m_CurAttrMask; // default layout only + uint m_CurStride; // default layout only + + uint m_CurVertexCount; + uint m_CurIndexCount; + +};
\ No newline at end of file diff --git a/Client/Source/Graphics/FrameBuffer.cpp b/Client/Source/Graphics/FrameBuffer.cpp new file mode 100644 index 0000000..af4d831 --- /dev/null +++ b/Client/Source/Graphics/FrameBuffer.cpp @@ -0,0 +1,12 @@ +#include "FrameBuffer.h" + +// 有些版本的OpenGL不支持绑定多个RT +bool FrameBuffer::BindRenderTexture(RenderTexture* rt, int location /* = 0 */) +{ + return false; +} + +bool FrameBuffer::Blit(FrameBuffer* target) +{ + return false; +} diff --git a/Client/Source/Graphics/FrameBuffer.h b/Client/Source/Graphics/FrameBuffer.h new file mode 100644 index 0000000..4b9104b --- /dev/null +++ b/Client/Source/Graphics/FrameBuffer.h @@ -0,0 +1,35 @@ +#ifndef FRAME_BUFFER_H +#define FRAME_BUFFER_H + +#include "OpenGL.h" +#include "RenderTexture.h" + +// Fbo,所有绑定的texture和renderbuffer的target都是可读写的GL_FRAMEBUFFER +class FrameBuffer +{ +public: + enum FrameBufferUsage + { + FrameBufferUsage_None = 0, + FrameBufferUsage_Depth = 1, + FrameBufferUsage_Stencil = 2, + FrameBufferUsage_DepthStencil = 3, + }; + + FrameBuffer(FrameBufferUsage usage, int width, int height); + ~FrameBuffer(); + + bool Blit(FrameBuffer* target); + + bool BindRenderTexture(RenderTexture* rt, int location = 0); + + GET(int, Width, m_Width); + GET(int, Height, m_Height); + +private: + int m_Width, m_Height; + FrameBufferUsage m_Usage; + +}; + +#endif
\ No newline at end of file diff --git a/Client/Source/Graphics/GPUDataBuffer.cpp b/Client/Source/Graphics/GPUDataBuffer.cpp new file mode 100644 index 0000000..f5149d9 --- /dev/null +++ b/Client/Source/Graphics/GPUDataBuffer.cpp @@ -0,0 +1,207 @@ +#include <math.h> + +#include "GPUDataBuffer.h" + +namespace GPU +{ + + // 修改buffer数据要绑定到这个目标上,其他情况下用GetHandle()绑定到其他目标 + // GL_COPY_READ_BUFFER + static const GLenum kBufferTarget = GL_COPY_WRITE_BUFFER; + + DataBuffer::DataBuffer() + { + glGenBuffers(1, &m_Handle); + m_Size = 0; + } + + DataBuffer::~DataBuffer() + { + glDeleteBuffers(1, &m_Handle); + } + + void DataBuffer::Restore(int size, GLenum usage) + { + RestoreWithData(size, usage, 0); + } + + void DataBuffer::RestoreWithData(int size, GLenum usage, const void* data) + { + glBindBuffer(kBufferTarget, m_Handle); + glBufferData(kBufferTarget, size, data, usage); + glBindBuffer(kBufferTarget, 0); + m_Size = size; + m_Usage = usage; + } + + // glBufferSubData + // glMapBuffer + // glMapBufferRange (best one) + + void DataBuffer::Upload(int offset, int size, const void* data) + { + glBindBuffer(kBufferTarget, m_Handle); + glBufferSubData(kBufferTarget, offset, size, data); + glBindBuffer(kBufferTarget, 0); + } + + void* DataBuffer::Map(uint32 access) + { + glBindBuffer(kBufferTarget, m_Handle); + void* ptr = glMapBuffer(kBufferTarget, access); + glBindBuffer(kBufferTarget, 0); + return ptr; + } + + void* DataBuffer::MapRange(int offset, int size, uint32 access) + { + glBindBuffer(kBufferTarget, m_Handle); + void* ptr = glMapBufferRange(kBufferTarget, offset, size, access); + glBindBuffer(kBufferTarget, 0); + return ptr; + } + + void DataBuffer::FlushMapedRange(int offset, int size) + { + glBindBuffer(kBufferTarget, m_Handle); + glFlushMappedBufferRange(kBufferTarget, offset, size); + glBindBuffer(kBufferTarget, 0); + } + + void DataBuffer::UnMap() + { + glBindBuffer(kBufferTarget, m_Handle); + glUnmapBuffer(kBufferTarget); + glBindBuffer(kBufferTarget, 0); + } + + void DataBuffer::Orphan() + { + glBindBuffer(kBufferTarget, m_Handle); + glBufferData(kBufferTarget, 0, 0, GL_STREAM_DRAW); + glBindBuffer(kBufferTarget, 0); + } + +//--------------------------------------------------------------------------------------- + + static bool IsBufferPoolCreated = false; + + BufferPool::BufferPool() + :m_LiveBuffers() + { + Assert(!IsBufferPoolCreated); + IsBufferPoolCreated = true; + } + + BufferPool::~BufferPool() + { + } + + static const float kBufferAllocateWeight = 10.0f; //! Default weight for buffer allocation from scratch. + static const float kBufferSizeWeightFactor = 1.f / 8096.f; //!< Weight factor for size difference. + static const float kBufferUsageDiffWeight = 8.f; //!< Weight factor for usage difference. + + static int ComputeBufferWeight(DataBuffer* buffer, int desiredSize, GLenum desiredUsage) + { + const int bufferSize = buffer->GetSize(); + const GLenum bufferUsage = buffer->GetUsage(); + + if (bufferSize == 0) + return kBufferAllocateWeight; + + const int sizeDiff = std::abs(bufferSize - desiredSize); + + return float(sizeDiff)*kBufferSizeWeightFactor + ((bufferUsage != desiredUsage) ? kBufferUsageDiffWeight : 0.f); + } + + DataBuffer* BufferPool::ClaimBuffer(int size, GLenum usage) + { + const float maxWeight = kBufferAllocateWeight; + const int maxCandidates = 5; // Number of potential candidates to consider actually. + + const int sizeClass = GetSizeClass(size); + int numCandidates = 0; // Number of potential candidates considered + int bestBufferNdx = -1; + float bestWeight = std::numeric_limits<float>::infinity(); + + for (int idx = 0; idx < m_LiveBuffers[sizeClass].size(); ++idx) + { + DataBuffer* buffer = m_LiveBuffers[sizeClass][idx]; + const float weight = ComputeBufferWeight(buffer, size, usage); + + if (weight < maxWeight && weight < bestWeight) + { + bestWeight = weight; + bestBufferNdx = idx; + ++numCandidates; + } + + if (numCandidates >= maxCandidates) + break; // Do not try other buffers, sorry. + } + + if (bestBufferNdx >= 0) + { + DataBuffer* selectedBuffer = m_LiveBuffers[sizeClass][bestBufferNdx]; + + if (bestBufferNdx + 1 != m_LiveBuffers[sizeClass].size()) + std::swap(m_LiveBuffers[sizeClass][bestBufferNdx], m_LiveBuffers[sizeClass].back()); + m_LiveBuffers[sizeClass].pop_back(); + + return selectedBuffer; + } + else + return new DataBuffer(); + + } + + void BufferPool::ReleaseBuffer(DataBuffer* buffer) + { + InsertToLive(buffer); + } + + void BufferPool::OnEndFrame() + { + UpdatePendingBuffersArray(); + } + + void BufferPool::UpdatePendingBuffersArray() + { + } + + void BufferPool::InsertToLive(DataBuffer* buffer) + { + const int bufferSize = buffer->GetSize(); + const int sizeClass = GetSizeClass(bufferSize); + + m_LiveBuffers[sizeClass].push_back(buffer); + } + + uint BufferPool::GetSizeClass(uint bufferSize) + { + for (int idx = 0; idx < kSizeClassCount; ++idx) + { + if (bufferSize < GetSizeClassLimit(idx)) + return idx; + } + Assert(false); + return 0; + } + + DataBuffer* ClaimBuffer(int size, GLenum usage) + { + return BufferPool::Instance()->ClaimBuffer(size, usage); + } + + void ReleaseBuffer(DataBuffer* buffer) + { + BufferPool::Instance()->ReleaseBuffer(buffer); + } + + int BufferPool::GetSizeClassLimit(int classNdx) + { + // (0, 2^10] 2^11 2^12 2^13 2^14 2^15 INT_MAX + return classNdx + 1 < kSizeClassCount ? (1 << (classNdx*kSizeClassStepLog2 + kSizeClassBaseLog2)) : INT_MAX; + } + +} diff --git a/Client/Source/Graphics/GPUDataBuffer.h b/Client/Source/Graphics/GPUDataBuffer.h new file mode 100644 index 0000000..3d24514 --- /dev/null +++ b/Client/Source/Graphics/GPUDataBuffer.h @@ -0,0 +1,75 @@ +#ifndef GPU_DATABUFFER_H +#define GPU_DATABUFFER_H + +#include <vector> + +#include "../Utilities/Type.h" +#include "../Utilities/Singleton.h" +#include "../Utilities/UtilMacros.h" +#include "../Utilities/Assert.h" +#include "OpenGL.h" + +namespace GPU +{ + + class DataBuffer + { + public: + DataBuffer(); + ~DataBuffer(); + + void Upload(int offset, int size, const void* data); + void* Map(uint32 access); + void* MapRange(int offset, int size, uint32 access); // 性能最佳 + void FlushMapedRange(int offset, int size); + + void UnMap(); + + void Orphan(); + + void Restore(int size, GLenum usage); + void RestoreWithData(int size, GLenum usage, const void* data); + + GET(int, Size, m_Size); + GET(GLenum, Usage, m_Usage); + GET(GLuint, Handle, m_Handle); + + private: + friend class BufferPool; + + GLuint m_Handle; + int m_Size; + GLenum m_Usage; + }; + + class BufferPool : public Singleton<BufferPool> + { + public: + BufferPool(); + ~BufferPool(); + + DataBuffer* ClaimBuffer(int size, GLenum usage); + void ReleaseBuffer(DataBuffer* buffer); + + void OnEndFrame(); + + private: + static const int kSizeClassBaseLog2 = 10; + static const int kSizeClassStepLog2 = 1; + static const int kSizeClassCount = 7; + + int GetSizeClassLimit(int classNdx); + void UpdatePendingBuffersArray(); + void InsertToLive(DataBuffer* buffer); + uint GetSizeClass(uint bufferSize); + + std::vector<DataBuffer*> m_LiveBuffers[kSizeClassCount]; + + }; + + DataBuffer* ClaimBuffer(int size = 0, GLenum usage = GL_ARRAY_BUFFER); + void ReleaseBuffer(DataBuffer* buffer); + +} + +#endif
\ No newline at end of file diff --git a/Client/Source/Graphics/GfxDevice.cpp b/Client/Source/Graphics/GfxDevice.cpp new file mode 100644 index 0000000..231ee71 --- /dev/null +++ b/Client/Source/Graphics/GfxDevice.cpp @@ -0,0 +1,169 @@ +#include <vector> +#include "GfxDevice.h" +#include "../Math/Math.h" + +static bool deviceInited = false; +// +//static const std::vector<byte> s_AvailableTextureUnitPreset = {0,1,2,3,4,5,6,7}; // 最多支持8个贴图 +//static std::vector<byte> s_TextureUnitBucket = s_AvailableTextureUnitPreset; + +static const int kMaxAvailableTextureUnitCount = 8; // 最多支持8个贴图 +static int s_CurAvailableTextureUnit = 0; + +static int ClaimTextureUnit() +{ + int unit = s_CurAvailableTextureUnit; + s_CurAvailableTextureUnit = (s_CurAvailableTextureUnit + 1) % kMaxAvailableTextureUnitCount; + return unit; +} + +GfxDevice g_GfxDevice; + +GfxDevice::GfxDevice() +{ + Assert(!deviceInited); + deviceInited = true; +} + +GfxDevice::~GfxDevice() +{ +} + +void GfxDevice::Initialize(GfxDeviceSetting setting) +{ +} + +void GfxDevice::Enable(EDeviceEnable enabled) +{ + +} + +void GfxDevice::Disable(EDeviceEnable enabled) +{ + +} + +void GfxDevice::IsEnable(uint flag) +{ + +} + +void GfxDevice::SetDepthTest(EDepthTest testing) +{ + +} + +void GfxDevice::SetCullFace(ECullFace face) +{ + +} + +void GfxDevice::SetStencilMask(byte stencilMask) +{ + +} + +void GfxDevice::SetStencilOp(EStencilOp op) +{ + +} + +void GfxDevice::SetAntiAliasing(int level /*= 0*/) +{ + +} + +void GfxDevice::Clear(int clearFlag) +{ + +} + +void GfxDevice::UseShader(Shader* shader, int idx) +{ + if (shader == NULL) + return; + + GLuint id = shader->GetID(); + if (id == 0) + return; + + glUseProgram(id); + + shader->ExecuteCommand(); + + m_Shader.shader = shader; +} + +void GfxDevice::UnuseShader() +{ + if (m_Shader) + { + m_Shader.shader = NULL; + } + glUseProgram(0); +} + +void GfxDevice::SetUniformVec2(const char* name, Vector2f vec2) +{ + if (!m_Shader) + return; + GLint loc = glGetUniformLocation(m_Shader.GetID(), name); + glUniform2f(loc, vec2.x, vec2.y); +} + +void GfxDevice::SetUniformVec3(const char* name, Vector3f vec3) +{ + if (!m_Shader) + return; + GLint loc = glGetUniformLocation(m_Shader.GetID(), name); + glUniform3f(loc, vec3.x, vec3.y, vec3.z); +} + +void GfxDevice::SetUniformVec4(const char* name, Vector4f vec4) +{ + if (!m_Shader) + return; + GLint loc = glGetUniformLocation(m_Shader.GetID(), name); + glUniform4f(loc, vec4.x, vec4.y, vec4.z, vec4.w); +} + +void GfxDevice::SetUniformMat4(const char* name, Matrix44 mat4) +{ + if (!m_Shader) + return; + GLint loc = glGetUniformLocation(m_Shader.GetID(), name); + glUniformMatrix4fv(loc, 1, GL_TRUE, &mat4.m[0][0]); +} + +void GfxDevice::SetUniformTexture(const char* name, Texture* texture) +{ + int texUnit = ClaimTextureUnit(); + glActiveTexture(GL_TEXTURE0 + texUnit); + glBindTexture(GL_TEXTURE_2D, texture->GetGpuID()); + + GLint loc = glGetUniformLocation(m_Shader.GetID(), name); + glUniform1i(loc, texUnit); +} + +void GfxDevice::BeginFrame() +{ + m_IsInsideFrame = true; + +} + +void GfxDevice::EndFrame() +{ + //GPU::BufferPool::Instance()->OnEndFrame(); + + m_IsInsideFrame = false; +} + +void GfxDevice::PresentFrame() +{ +// swap buffers +} + +bool GfxDevice::IsInsideFrame() +{ + return m_IsInsideFrame; +} diff --git a/Client/Source/Graphics/GfxDevice.h b/Client/Source/Graphics/GfxDevice.h new file mode 100644 index 0000000..d81d574 --- /dev/null +++ b/Client/Source/Graphics/GfxDevice.h @@ -0,0 +1,109 @@ +#ifndef DEVICE_H +#define DEVICE_H +#include "../Math/Math.h" + +#include "../Utilities/Type.h" +#include "../Utilities/Assert.h" +#include "../Graphics/Shader.h" +#include "../Math/Vector2.hpp" +#include "../Math/Vector3.hpp" +#include "../Math/Vector4.hpp" +#include "../Math/Matrix44.h" + +#include "Shader.h" +#include "Texture.h" +#include "DeviceDefine.h" +#include "VertexBuffer.h" +#include "DynamicVertexBuffer.h" +#include "Color.h" + +struct GfxDeviceSetting +{ + ETextureFilterMode filterMode; // 默认的贴图过滤模式 + ETextureWrapMode wrapMode; // 默认的贴图平铺模式 +}; + +// 当前绑定的shader +struct ShaderState +{ + Shader* shader; + operator bool() + { + return shader != NULL; + } + GLuint GetID() { + if (shader == nullptr) + return 0; + GLint id = shader->GetID(); + return id; + } +}; + +// 对渲染相关API的封装 +class GfxDevice +{ +public: + GfxDevice(); + ~GfxDevice(); + + void Initialize(GfxDeviceSetting setting); + + void Enable(EDeviceEnable enabled); + void Disable(EDeviceEnable enabled); + void IsEnable(uint flag); + + void SetDepthTest(EDepthTest testing); + void SetCullFace(ECullFace face); + void SetStencilMask(byte stencilMask); + void SetStencilOp(EStencilOp op); + + void SetAntiAliasing(int level = 0); + + void Clear(int clearFlag); + + void UseShader(Shader* shader, int idx); + void UnuseShader(); + void SetUniformVec2(const char* name, Vector2f vec2); + void SetUniformVec3(const char* name, Vector3f vec3); + void SetUniformVec4(const char* name, Vector4f vec4); + void SetUniformMat4(const char* name, Matrix44 mat4); + void SetUniformTexture(const char* name, Texture* texture); + + void BeginFrame(); + void EndFrame(); + void PresentFrame(); + + bool IsInsideFrame(); + + DynamicVertexBuffer* GetSharedVBO() { return &m_DynamicVBO; } + + GET_SET(Color, ClearColor, m_ClearColor); + GET_SET(ETextureFilterMode, DefaultFilterMode, m_DefaultFilterMode); + GET_SET(ETextureWrapMode, DefaultWrapMode, m_DefaultWrapMode); + +private: + bool m_IsInsideFrame; + + // 渲染状态 + uint m_EnableFlag; + Color m_ClearColor; + EDepthTest m_DepthTest; + EStencilTest m_StencilTest; + EStencilOp m_StencilOp; + byte m_StencilMask; + + ShaderState m_Shader; // 当前绑定的shader + + // 贴图默认设置 + ETextureFilterMode m_DefaultFilterMode; + ETextureWrapMode m_DefaultWrapMode; + + DynamicVertexBuffer m_DynamicVBO; // 共享的VBO,用来做立即渲染 + +}; + +extern GfxDevice g_GfxDevice; + +#define g_SharedVBO (*g_GfxDevice.GetSharedVBO()) + +#endif
\ No newline at end of file diff --git a/Client/Source/Graphics/GlyphAtlas.cpp b/Client/Source/Graphics/GlyphAtlas.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Client/Source/Graphics/GlyphAtlas.cpp diff --git a/Client/Source/Graphics/GlyphAtlas.h b/Client/Source/Graphics/GlyphAtlas.h new file mode 100644 index 0000000..b0ab858 --- /dev/null +++ b/Client/Source/Graphics/GlyphAtlas.h @@ -0,0 +1,6 @@ +#ifndef TEXT_ATLAS_H +#define TEXT_ATLAS_H + + + +#endif
\ No newline at end of file diff --git a/Client/Source/Graphics/ImageData.cpp b/Client/Source/Graphics/ImageData.cpp new file mode 100644 index 0000000..8e2e4bf --- /dev/null +++ b/Client/Source/Graphics/ImageData.cpp @@ -0,0 +1,2 @@ +#include "ImageData.h" + diff --git a/Client/Source/Graphics/ImageData.h b/Client/Source/Graphics/ImageData.h new file mode 100644 index 0000000..9ebc738 --- /dev/null +++ b/Client/Source/Graphics/ImageData.h @@ -0,0 +1,39 @@ +#ifndef IMAGE_DATA_H +#define IMAGE_DATA_H + +#include <vector> + +enum EPixelFormat +{ + PixelFormat_RGBA, + PixelFormat_RGB, + PixelFormat_R, + PixelFormat_RG, + PixelFormat_BGR, + PixelFormat_BGRA +}; + +enum EPixelElementType +{ + PixelType_UNSIGNED_BYTE, + PixelType_UNSIGNED_INT, + PixelType_BYTE, + PixelType_INT, + PixelType_FLOAT, +}; + +// 图片像素数据 +class ImageData +{ +public: + ImageData() + { + } + + void* pixels; // 像素数据,格式和类型参考 http://docs.gl/gl3/glTexImage2D pixel data的format和type + EPixelFormat format; + EPixelElementType type; + int width, height; +}; + +#endif
\ No newline at end of file diff --git a/Client/Source/Graphics/OpenGL.cpp b/Client/Source/Graphics/OpenGL.cpp new file mode 100644 index 0000000..9ed2e50 --- /dev/null +++ b/Client/Source/Graphics/OpenGL.cpp @@ -0,0 +1,7 @@ +#include "OpenGL.h" + +#pragma comment(lib, "opengl32.lib") + +std::string g_sharedGLErrorMsg = ""; + + diff --git a/Client/Source/Graphics/OpenGL.h b/Client/Source/Graphics/OpenGL.h new file mode 100644 index 0000000..d93fb5a --- /dev/null +++ b/Client/Source/Graphics/OpenGL.h @@ -0,0 +1,41 @@ +#ifndef OPENGL_H +#define OPENGL_H + +#include "glad/glad.h" +#include <string> +#include <exception> + +//http://docs.gl/gl3/glClear + +#define CheckGLError(action)\ +if(true){ \ + GLenum error; \ + while ((error = glGetError()) != GL_NO_ERROR) { \ + action \ + } \ +} + +#define WipeGLError() \ +if(true){\ + GLenum error; \ + while ((error = glGetError()) != GL_NO_ERROR) { \ + throw GLException(error); \ + } \ +} + +extern std::string g_sharedGLErrorMsg; + +class GLException : public std::exception +{ +public: + GLException(const char* what) + : std::exception(what) + {} + GLException(int glError) + { + g_sharedGLErrorMsg = std::to_string(glError); + std::exception(g_sharedGLErrorMsg.c_str()); + } +}; + +#endif
\ No newline at end of file diff --git a/Client/Source/Graphics/Point.cpp b/Client/Source/Graphics/Point.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Client/Source/Graphics/Point.cpp diff --git a/Client/Source/Graphics/Point.h b/Client/Source/Graphics/Point.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Client/Source/Graphics/Point.h diff --git a/Client/Source/Graphics/PolyLine.cpp b/Client/Source/Graphics/PolyLine.cpp new file mode 100644 index 0000000..911b3e5 --- /dev/null +++ b/Client/Source/Graphics/PolyLine.cpp @@ -0,0 +1,9 @@ +#include "PolyLine.h" +#include "Color.h" +#include "../Math/Math.h" + +struct PolyLineVBOLayout +{ + Vector3f position; + Color32 color; +}; diff --git a/Client/Source/Graphics/PolyLine.h b/Client/Source/Graphics/PolyLine.h new file mode 100644 index 0000000..816d18e --- /dev/null +++ b/Client/Source/Graphics/PolyLine.h @@ -0,0 +1,18 @@ +#ifndef POLY_LINE_H +#define POLY_LINE_H + +#include "../Math/Vector3.hpp" + +class PolyLine +{ +public: + PolyLine(); + ~PolyLine(); + + void Draw(); + +private: + +}; + +#endif
\ No newline at end of file diff --git a/Client/Source/Graphics/Primitive.h b/Client/Source/Graphics/Primitive.h new file mode 100644 index 0000000..6636221 --- /dev/null +++ b/Client/Source/Graphics/Primitive.h @@ -0,0 +1,8 @@ +#pragma once + +enum EPrimitive +{ + Primitive_Triangle = 1, + Primitive_Line = 2, + Primitive_Point = 3, +}; diff --git a/Client/Source/Graphics/Quad.cpp b/Client/Source/Graphics/Quad.cpp new file mode 100644 index 0000000..40c896d --- /dev/null +++ b/Client/Source/Graphics/Quad.cpp @@ -0,0 +1,62 @@ +#include "../Graphics/GfxDevice.h" +#include "../Math/Math.h" +#include "../Math/Math.h" + +#include "Quad.h" + +struct QuadVBOLayout +{ + Vector3f position; + Vector2f uv; +}; + +static CustomVertexLayout layout; + +InitializeStaticVariables([]() { + VertexAttributeDescriptor POSITION = VertexAttributeDescriptor(0, 3, VertexAttrFormat_Float, sizeof(QuadVBOLayout)); + VertexAttributeDescriptor UV = VertexAttributeDescriptor(sizeof(Vector3f), 2, VertexAttrFormat_Float, sizeof(QuadVBOLayout)); + + layout.attributes.push_back(POSITION); + layout.attributes.push_back(UV); +}); + +void Quad::Draw() +{ + const int nVerts = 4; + const int nIndices = 6; + + float pos[] = { + m_Left, m_Bottom, 0, // left-bottom + m_Right, m_Bottom, 0, // right-bottom + m_Right, m_Top, 0, // right-top + m_Left, m_Top, 0, // top-left + }; + float uv[] = { + 0, 0, + 1, 0, + 1, 1, + 0, 1, + }; + int indices[] = { + 0, 1, 3, // right-top + 1, 2, 3, // left-bottom + }; + + uint8* vb; + uint16* ib; + + g_SharedVBO.GetChunk(sizeof(QuadVBOLayout), sizeof(uint16), 4, 6, Primitive_Triangle, (void**)&vb, (void**)&ib); + + QuadVBOLayout* dst = (QuadVBOLayout*)vb; + for (int i = 0; i < nVerts; ++i) + { + dst[i].position.Set(pos[3 * i], pos[3 * i + 1], pos[3 * i + 2]); + dst[i].uv.Set(uv[2 * i], uv[2 * i + 1]); + } + + for (int i = 0; i < nIndices; ++i) + ib[i] = indices[i]; + + g_SharedVBO.ReleaseChunk(4, 6); + g_SharedVBO.DrawChunk(layout); +} diff --git a/Client/Source/Graphics/Quad.h b/Client/Source/Graphics/Quad.h new file mode 100644 index 0000000..ee6c5be --- /dev/null +++ b/Client/Source/Graphics/Quad.h @@ -0,0 +1,26 @@ +#ifndef QUAD_H +#define QUAD_H + +#include "../Utilities/UtilMacros.h" +#include "DynamicMesh.h" + +class Quad : public DynamicMesh +{ +public: + Quad(float l, float r, float t, float b); + + void Set(float l, float r, float t, float b); + + GET_SET(float, Left, m_Left); + GET_SET(float, Right, m_Right); + GET_SET(float, Top, m_Top); + GET_SET(float, Bottom, m_Bottom); + + void Draw() override; + +private: + float m_Left, m_Right, m_Top, m_Bottom; + +}; + +#endif
\ No newline at end of file diff --git a/Client/Source/Graphics/RenderCommands.cpp b/Client/Source/Graphics/RenderCommands.cpp new file mode 100644 index 0000000..336bf20 --- /dev/null +++ b/Client/Source/Graphics/RenderCommands.cpp @@ -0,0 +1,9 @@ +#include "RenderCommands.h" + +void ReleaseRenderCommandGroup(RenderCommandGroup& group) +{ + for (int i = 0; i < group.size(); ++i) + { + delete group[i]; + } +} diff --git a/Client/Source/Graphics/RenderCommands.h b/Client/Source/Graphics/RenderCommands.h new file mode 100644 index 0000000..f66b4e2 --- /dev/null +++ b/Client/Source/Graphics/RenderCommands.h @@ -0,0 +1,164 @@ +锘#pragma once +#include "OpenGL.h" +#include <vector> + +struct RenderCommand +{ + virtual void Execute() = 0; +}; + +typedef std::vector<RenderCommand*> RenderCommandGroup; +void ReleaseRenderCommandGroup(RenderCommandGroup& group); + +// Cull Off|Front|Back|Both +struct Cmd_Cull : RenderCommand +{ + enum ECullFace { + Cull_Disable, + Cull_Front, + Cull_Back, + Cull_Both, + }; + + ECullFace cull; + + void Execute() override + { + if (cull == ECullFace::Cull_Disable) + { + glDisable(GL_CULL_FACE); + return; + } + glEnable(GL_CULL_FACE); + switch (cull) + { + case ECullFace::Cull_Front: glCullFace(GL_FRONT); break; + case ECullFace::Cull_Back: glCullFace(GL_BACK); break; + case ECullFace::Cull_Both: glCullFace(GL_FRONT_AND_BACK); break; + } + } +}; + +// Blend Off +// Blend <srcFac> <dstFac> +struct Cmd_Blend : RenderCommand +{ + enum EBlend + { + Blend_Zero, // 0 + Blend_One, // 1 + Blend_Src_Color, // 婧愰鑹插悜閲廋炉source + Blend_One_Minus_Src_Color, // 1鈭扖炉source + Blend_Dst_Color, // 鐩爣棰滆壊鍚戦噺C炉destination + Blend_One_Minus_Dst_Color, // 1鈭扖炉destination + Blend_Src_Alpha, // C炉source鐨刟lpha鍊 + Blend_One_Minus_Src_Alpha, // 1鈭 C炉source鐨刟lpha鍊 + Blend_Dst_Alpha, // C炉destination鐨刟lpha鍊 + Blend_One_Minus_Dst_Alpha, // 1鈭 C炉destination鐨刟lpha鍊 + Blend_Constant_Color, // 甯搁鑹插悜閲廋炉constant + Blend_One_Minus_Constant_Color, // 1鈭扖炉constant + Blend_Constant_Alpha, // C炉constant鐨刟lpha鍊 + Blend_One_Minus_Constant_Alpha, // 1鈭 C炉constant鐨刟lpha鍊 + }; + + bool enable; + EBlend srcFac; + EBlend dstFac; + + void Execute() override + { + if (!enable) + glDisable(GL_BLEND); + glEnable(GL_BLEND); + glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); + GLenum src, dst; + switch (srcFac) + { + case EBlend::Blend_Zero: src = GL_ZERO; break; + case EBlend::Blend_One: src = GL_ONE; break; + case EBlend::Blend_Src_Color: src = GL_SRC_COLOR; break; + case EBlend::Blend_One_Minus_Src_Color: src = GL_ONE_MINUS_SRC_COLOR; break; + case EBlend::Blend_Dst_Color: src = GL_DST_COLOR; break; + case EBlend::Blend_One_Minus_Dst_Color: src = GL_ONE_MINUS_DST_COLOR; break; + case EBlend::Blend_Src_Alpha: src = GL_SRC_ALPHA; break; + case EBlend::Blend_One_Minus_Src_Alpha: src = GL_ONE_MINUS_SRC_ALPHA; break; + case EBlend::Blend_Dst_Alpha: src = GL_DST_ALPHA; break; + case EBlend::Blend_One_Minus_Dst_Alpha: src = GL_ONE_MINUS_DST_ALPHA; break; + case EBlend::Blend_Constant_Color: src = GL_CONSTANT_COLOR; break; + case EBlend::Blend_One_Minus_Constant_Color: src = GL_ONE_MINUS_CONSTANT_COLOR; break; + case EBlend::Blend_Constant_Alpha: src = GL_CONSTANT_ALPHA; break; + case EBlend::Blend_One_Minus_Constant_Alpha: src = GL_ONE_MINUS_CONSTANT_ALPHA; break; + } + switch (dstFac) + { + case EBlend::Blend_Zero: dst = GL_ZERO; break; + case EBlend::Blend_One: dst = GL_ONE; break; + case EBlend::Blend_Src_Color: dst = GL_SRC_COLOR; break; + case EBlend::Blend_One_Minus_Src_Color: dst = GL_ONE_MINUS_SRC_COLOR; break; + case EBlend::Blend_Dst_Color: dst = GL_DST_COLOR; break; + case EBlend::Blend_One_Minus_Dst_Color: dst = GL_ONE_MINUS_DST_COLOR; break; + case EBlend::Blend_Src_Alpha: dst = GL_SRC_ALPHA; break; + case EBlend::Blend_One_Minus_Src_Alpha: dst = GL_ONE_MINUS_SRC_ALPHA; break; + case EBlend::Blend_Dst_Alpha: dst = GL_DST_ALPHA; break; + case EBlend::Blend_One_Minus_Dst_Alpha: dst = GL_ONE_MINUS_DST_ALPHA; break; + case EBlend::Blend_Constant_Color: dst = GL_CONSTANT_COLOR; break; + case EBlend::Blend_One_Minus_Constant_Color: dst = GL_ONE_MINUS_CONSTANT_COLOR; break; + case EBlend::Blend_Constant_Alpha: dst = GL_CONSTANT_ALPHA; break; + case EBlend::Blend_One_Minus_Constant_Alpha: dst = GL_ONE_MINUS_CONSTANT_ALPHA; break; + } + glBlendFunc(src, dst); + } +}; + +// DepthTest Off|<func> +struct Cmd_DepthTest : RenderCommand +{ + enum EDepthTest + { + DepthTest_Off, // 涓嶈繘琛屾繁搴︽祴璇 + DepthTest_Always, // 姘歌繙閫氳繃娴嬭瘯 + DepthTest_Never, // 姘歌繙涓嶉氳繃娴嬭瘯 + DepthTest_Less, // 鍦ㄧ墖娈垫繁搴﹀煎皬浜庣紦鍐插尯鐨勬繁搴︽椂閫氳繃娴嬭瘯 + DepthTest_Equal, // 鍦ㄧ墖娈垫繁搴﹀肩瓑浜庣紦鍐插尯鐨勬繁搴︽椂閫氳繃娴嬭瘯 + DepthTest_Lequal, // 鍦ㄧ墖娈垫繁搴﹀煎皬浜庣瓑浜庣紦鍐插尯鐨勬繁搴︽椂閫氳繃娴嬭瘯 + DepthTest_Greater, // 鍦ㄧ墖娈垫繁搴﹀煎ぇ浜庣紦鍐插尯鐨勬繁搴︽椂閫氳繃娴嬭瘯 + DepthTest_Notequal, // 鍦ㄧ墖娈垫繁搴﹀间笉绛変簬缂撳啿鍖虹殑娣卞害鏃堕氳繃娴嬭瘯 + DepthTest_Gequal, // 鍦ㄧ墖娈垫繁搴﹀煎ぇ浜庣瓑浜庣紦鍐插尯鐨勬繁搴︽椂閫氳繃娴嬭瘯 + }; + + EDepthTest test; + + void Execute() override + { + if (test == EDepthTest::DepthTest_Off) + { + glDisable(GL_DEPTH_TEST); + return; + } + glEnable(GL_DEPTH_TEST); + switch (test) + { + case EDepthTest::DepthTest_Always: glDepthFunc(GL_ALWAYS); break; + case EDepthTest::DepthTest_Never: glDepthFunc(GL_NEVER); break; + case EDepthTest::DepthTest_Less: glDepthFunc(GL_LESS); break; + case EDepthTest::DepthTest_Equal: glDepthFunc(GL_EQUAL); break; + case EDepthTest::DepthTest_Lequal: glDepthFunc(GL_LEQUAL); break; + case EDepthTest::DepthTest_Greater: glDepthFunc(GL_GREATER); break; + case EDepthTest::DepthTest_Notequal: glDepthFunc(GL_NOTEQUAL); break; + case EDepthTest::DepthTest_Gequal: glDepthFunc(GL_GEQUAL); break; + } + } +}; + +// DepthWrite Off|On +struct Cmd_DepthWrite : RenderCommand +{ + bool write; + void Execute() override + { + if(write) + glDepthMask(GL_TRUE); + else + glDepthMask(GL_FALSE); + } +}; diff --git a/Client/Source/Graphics/RenderTexture.cpp b/Client/Source/Graphics/RenderTexture.cpp new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Client/Source/Graphics/RenderTexture.cpp diff --git a/Client/Source/Graphics/RenderTexture.h b/Client/Source/Graphics/RenderTexture.h new file mode 100644 index 0000000..a501f50 --- /dev/null +++ b/Client/Source/Graphics/RenderTexture.h @@ -0,0 +1,16 @@ +#ifndef RENDER_TEXTURE_H +#define RENDER_TEXTURE_H + +#include "Texture.h" + +// 离屏渲染 +class RenderTexture : public Texture +{ +public: + RenderTexture(ETextureFormat format); + +}; + +RenderTexture* CreateRenderTexture(int width, int height, ETextureFormat format); + +#endif
\ No newline at end of file diff --git a/Client/Source/Graphics/Shader.cpp b/Client/Source/Graphics/Shader.cpp new file mode 100644 index 0000000..899578b --- /dev/null +++ b/Client/Source/Graphics/Shader.cpp @@ -0,0 +1,154 @@ +#include <exception> + +#include "../Debug/log.h" +#include "Shader.h" +#include "OpenGL.h" +#include "ShaderCompiler.h" + +using namespace std; + +std::string shaderError = ""; +void checkCompileshaderErrorors(GLuint shader, std::string type) +{ + GLint success; + GLchar infoLog[1024]; + if (type != "PROGRAM") + { + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(shader, 1024, NULL, infoLog); + shaderError = "ERROR::SHADER_COMPILATION_ERROR of type: " + type + "\n" + infoLog; + } + } + else + { + glGetProgramiv(shader, GL_LINK_STATUS, &success); + if (!success) + { + glGetProgramInfoLog(shader, 1024, NULL, infoLog); + shaderError = "ERROR::SHADER_COMPILATION_ERROR of type: " + type + "\n" + infoLog; + } + } + if (!success) + { + throw ShaderCompileExecption(shaderError.c_str()); + } +} + +Shader::Shader() +{ +} + +Shader::Shader(std::string& glsllShader) +{ + // stl的string会在大小超过阈值的情况下在栈里分配,并用RAII保证释放 + std::string vsh ; + std::string fsh ; + try + { + GLSLCompiler::Compile(glsllShader, vsh, fsh, m_Commands); + } + catch (GLSLCompileException& e) + { + ReleaseRenderCommandGroup(m_Commands); + throw ShaderCompileExecption(e.what()); + } + CompileProgram(vsh.c_str(), fsh.c_str()); +} + +Shader::Shader(const char* vert, const char* frag) +{ + CompileProgram(vert, frag); +} + +void Shader::CompileProgram(const char* vert, const char* frag, bool keepSrc) +{ + const char* vertCode = vert; + const char* fragCode = frag; + // vertex shader + m_VertID = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(m_VertID, 1, &vertCode, NULL);//为了支持中文注释,长度传NULL + glCompileShader(m_VertID); + checkCompileshaderErrorors(m_VertID, "VERTEX"); + // fragment Shader + m_FragID = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(m_FragID, 1, &fragCode, NULL); + glCompileShader(m_FragID); + checkCompileshaderErrorors(m_FragID, "FRAGMENT"); + // create program + m_ProgramID = glCreateProgram(); + glAttachShader(m_ProgramID, m_VertID); + glAttachShader(m_ProgramID, m_FragID); + glLinkProgram(m_ProgramID); + checkCompileshaderErrorors(m_ProgramID, "PROGRAM"); +} + +Shader::~Shader() +{ + glDeleteProgram(m_ProgramID); + glDeleteShader(m_VertID); + glDeleteShader(m_FragID); +} + +void Shader::ReCompile(std::string& vert, std::string frag) +{ + const char* vertCode = vert.c_str(); + const char* fragCode = frag.c_str(); + // vertex shader + glShaderSource(m_VertID, 1, &vertCode, NULL); + glCompileShader(m_VertID); + checkCompileshaderErrorors(m_VertID, "VERTEX"); + // fragment Shader + glShaderSource(m_FragID, 1, &fragCode, NULL); + glCompileShader(m_FragID); + checkCompileshaderErrorors(m_FragID, "FRAGMENT"); + // create program + glAttachShader(m_ProgramID, m_VertID); + glAttachShader(m_ProgramID, m_FragID); + glLinkProgram(m_ProgramID); + checkCompileshaderErrorors(m_FragID, "PROGRAM"); +} + +void Shader::ReCompileVert(std::string& vert) +{ + glDeleteShader(m_VertID); + const char* vertCode = vert.c_str(); + // vertex shader + glShaderSource(m_VertID, 1, &vertCode, NULL); + glCompileShader(m_VertID); + checkCompileshaderErrorors(m_VertID, "VERTEX"); + // create program + glAttachShader(m_ProgramID, m_VertID); + glAttachShader(m_ProgramID, m_FragID); + glLinkProgram(m_ProgramID); + checkCompileshaderErrorors(m_FragID, "PROGRAM"); +} + +void Shader::ReCompileFrag(std::string frag) +{ + glDeleteShader(m_FragID); + const char* fragCode = frag.c_str(); + // fragment Shader + glShaderSource(m_FragID, 1, &fragCode, NULL); + glCompileShader(m_FragID); + checkCompileshaderErrorors(m_FragID, "FRAGMENT"); + // create program + glAttachShader(m_ProgramID, m_VertID); + glAttachShader(m_ProgramID, m_FragID); + glLinkProgram(m_ProgramID); + checkCompileshaderErrorors(m_FragID, "PROGRAM"); +} + +bool Shader::IsValid() +{ + return m_ProgramID != 0; +} + +void Shader::ExecuteCommand() +{ + for (int i = 0; i < m_Commands.size(); ++i) + { + m_Commands[i]->Execute(); + } +}
\ No newline at end of file diff --git a/Client/Source/Graphics/Shader.h b/Client/Source/Graphics/Shader.h new file mode 100644 index 0000000..8d5fc0e --- /dev/null +++ b/Client/Source/Graphics/Shader.h @@ -0,0 +1,47 @@ +#pragma once +#include <string> +#include <exception> +#include "OpenGL.h" +#include "../Utilities/UtilMacros.h" +#include "../Utilities/Assert.h" +#include "../Debug/Log.h" +#include "RenderCommands.h" + +// 着色器程序 +class Shader +{ +public: + Shader()/*throw(ShaderCompileExecption)*/; + Shader(std::string& glsllShader)/*throw(ShaderCompileExecption)*/; + Shader(const char* vert, const char* frag)/*throw(ShaderCompileExecption)*/; + ~Shader(); + + void ReCompile(std::string& vert, std::string frag)/*throw(ShaderCompileExecption)*/; + void ReCompileVert(std::string& vert)/*throw(ShaderCompileExecption)*/; + void ReCompileFrag(std::string frag)/*throw(ShaderCompileExecption)*/; + + bool IsValid(); + + void ExecuteCommand(); + + GET(GLint, ID, m_ProgramID); + +private: + void CompileProgram(const char* vert, const char* frag, bool keepSrc = false); + + RenderCommandGroup m_Commands; // 渲染前的状态设置 + + GLint m_ProgramID; + GLint m_FragID; + GLint m_VertID; + +}; + +class ShaderCompileExecption : public std::exception +{ +public: + ShaderCompileExecption(const char* what) + : std::exception(what) + { + } +}; diff --git a/Client/Source/Graphics/ShaderCompiler.cpp b/Client/Source/Graphics/ShaderCompiler.cpp new file mode 100644 index 0000000..362b28e --- /dev/null +++ b/Client/Source/Graphics/ShaderCompiler.cpp @@ -0,0 +1,347 @@ +#include "ShaderCompiler.h" +#include <sstream> +#include <algorithm> + +using namespace std; + +static const char* VSH_BEGIN = "VSH_BEGIN"; +static const char* VSH_END = "VSH_END"; +static const char* FSH_BEGIN = "FSH_BEGIN"; +static const char* FSH_END = "FSH_END"; +static const char* CMD_BEGIN = "CMD_BEGIN"; +static const char* CMD_END = "CMD_END"; + +std::string s_CompileError = ""; + +// GLSL分为四部分 +// * CMD_BEGIN 和 CMD_END 之间的命令 +// * VERTEX_SHADER_BEGIN 和 VERTEX_SHADER_END之间的顶点着色器 +// * FRAGMENT_SHADER_BEGIN 和 FRAGMENT_SHADER_END之间的片段着色器 +// * 三者之外的公共部分 +void GLSLCompiler::Compile(std::string& src, std::string& vsh, std::string& fsh, RenderCommandGroup& group)/*throw GLSLCompileException*/ +{ +#define CheckLabel(label) {\ + int pos = src.find(label);\ + if(pos == string::npos || !IsLabelActive(src, label)) {\ + s_CompileError = std::string("Compile Shader Error: No ") + #label + " label";\ + throw GLSLCompileException(s_CompileError.c_str());\ + }} + + CheckLabel(VSH_BEGIN); + CheckLabel(VSH_END); + CheckLabel(FSH_BEGIN); + CheckLabel(FSH_END); + + vsh = GetContent(src, VSH_BEGIN, VSH_END); + fsh = GetContent(src, FSH_BEGIN, FSH_END); + + bool hasCmd = IsLabelActive(src, CMD_BEGIN) && IsLabelActive(src, CMD_END); + if (hasCmd) + { + string cmd = GetContent(src, CMD_BEGIN, CMD_END); + if (cmd.size() > 0) + { + ParseCmd(cmd, group); + } + else + { + hasCmd = false; + } + } + + string common; + common = TrimContent(src, VSH_BEGIN, VSH_END); + common = TrimContent(common, FSH_BEGIN, FSH_END); + if (hasCmd) + common = TrimContent(common, CMD_BEGIN, CMD_END); + + vsh = common + vsh; + fsh = common + fsh; +} + +std::string GLSLCompiler::GetContent(std::string& src, const char* from, const char* to) +{ + int begin = src.find(from); + int end = src.find(to); + if (begin == string::npos || end == string::npos) + { + return ""; + } + std::string content = src.substr(begin + strlen(from), end - begin - strlen(from)); + return content; +} + +std::string GLSLCompiler::TrimContent(std::string& src, const char* from, const char* to) +{ + int begin = src.find(from); + int end = src.find(to); + string result = src.erase(begin, end + strlen(to) - begin); + return result; +} + +bool GLSLCompiler::IsLabelActive(std::string& src, const char* label) +{ + int pos = src.find(label); + if (pos == string::npos) + return false; + for (int i = pos - 1; i >= 0; --i) + { + int second = i; + int first = i - 1; + if (first < 0) + break; + if (src[second] == '\n' || src[first] == '\r') + break; + if (src[first] == '/' && src[second] == '/') + return false; + } + return true; +} + +bool GLSLCompiler::IsCommandActive(std::string& src, const char* label) +{ + int pos = src.find(label); + if (pos == string::npos) + return false; + for (int i = pos - 1; i >= 0; --i) + { + int second = i; + int first = i - 1; + if (first < 0) + break; + if (src[second] == '\n' || src[first] == '\r') + break; + if (src[first] == '/' && src[second] == '/') + return false; + } + return true; +} + +void GLSLCompiler::ParseCmd(std::string& cmds, RenderCommandGroup& group) +{ + istringstream ss = istringstream(cmds); + string line; + while (getline(ss, line)) + { + if(line.find('\r') != string::npos) + line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); + if (IsLineCommentd(line)) + continue; + int cb, ce; // cmd begin, end + if (!FindCmdPos(line, &cb, &ce)) + continue; + string cmdName = line.substr(cb, ce - cb + 1); + string cmdValue = line.substr(ce + 1, line.size() - ce - 1); + if (cmdName == "Cull") CommandCull(cmdValue, group); + else if (cmdName == "Blend") CommandBlend(cmdValue, group); + else if (cmdName == "DepthTest") CommandDepthTest(cmdValue, group); + else if (cmdName == "DepthWrite") CommandDepthWrite(cmdValue, group); + else + { + s_CompileError = string("Unknown command " + cmdName); + throw GLSLCompileException(s_CompileError.c_str()); + } + } +} + +#define IsSeperator(c) (c == ' ' || c == '\r' || c == '\n' || c == /*tab*/9) + +// 找到行内的第一个单词,作为命令名 +bool GLSLCompiler::FindCmdPos(std::string& line, int* start, int* end) +{ + for (int i = 0; i < line.size(); ++i) + { + if (IsSeperator(line[i])) + continue; + *start = i; + for (int j = i + 1; j < line.size(); ++j) + { + if (IsSeperator(line[j])) + { + *end = j - 1; + return true; + } + } + } + return false; +} + +bool GLSLCompiler::IsLineCommentd(std::string& line) +{ + for (int i = 0; i < line.size(); ++i) + { + if (IsSeperator(line[i])) + continue; + int first = i; + int second = i + 1; + if (second == line.size()) + return false; + if (line[first] == '/' && line[second] == '/') + return true; + return false; + } + return false; +} + +#define MAX_PARAM 2 + +void GLSLCompiler::CommandCull(std::string& p, RenderCommandGroup& group) +{ + std::string params[1]; + GetParams("Cull", p, params, 1); + + Cmd_Cull* pCull = new Cmd_Cull(); + Cmd_Cull& cull = *pCull; + if (params[0] == "Off") cull.cull = Cmd_Cull::Cull_Disable; + else if (params[0] == "Front") cull.cull = Cmd_Cull::Cull_Front; + else if (params[0] == "Back") cull.cull = Cmd_Cull::Cull_Back; + else if (params[0] == "Both") cull.cull = Cmd_Cull::Cull_Both; + else + { + delete pCull; + s_CompileError = string("Compile Shader Error: Invalid parameter of Cull: " + params[0]); + throw GLSLCompileException(s_CompileError.c_str()); + } + group.push_back(pCull); +} + +void GLSLCompiler::CommandBlend(std::string& p, RenderCommandGroup& group) +{ + std::string params[2]; + GetParams("Blend", p, params, 2); + + Cmd_Blend* pblend = new Cmd_Blend(); + Cmd_Blend& blend = *pblend; + if (params[0] == "Off") + { + blend.enable = false; + group.push_back(pblend); + return; + } + + blend.enable = true; + + if (params[0] == "Zero") blend.srcFac = Cmd_Blend::Blend_Zero; + else if (params[0] == "One") blend.srcFac = Cmd_Blend::Blend_One; + else if (params[0] == "SrcColor") blend.srcFac = Cmd_Blend::Blend_Src_Color; + else if (params[0] == "OneMinusSrcColor") blend.srcFac = Cmd_Blend::Blend_One_Minus_Src_Color; + else if (params[0] == "DstColor") blend.srcFac = Cmd_Blend::Blend_Dst_Color; + else if (params[0] == "OneMinusDstColor") blend.srcFac = Cmd_Blend::Blend_One_Minus_Dst_Color; + else if (params[0] == "SrcAlpha") blend.srcFac = Cmd_Blend::Blend_Src_Alpha; + else if (params[0] == "OneMinusSrcAlpha") blend.srcFac = Cmd_Blend::Blend_One_Minus_Src_Alpha; + else if (params[0] == "DstAlpha") blend.srcFac = Cmd_Blend::Blend_Dst_Alpha; + else if (params[0] == "OneMinusDstAlpha") blend.srcFac = Cmd_Blend::Blend_One_Minus_Dst_Alpha; + else if (params[0] == "ConstantColor") blend.srcFac = Cmd_Blend::Blend_Constant_Color; + else if (params[0] == "OneMinusConstantColor") blend.srcFac = Cmd_Blend::Blend_One_Minus_Constant_Color; + else if (params[0] == "ConstantAlpha") blend.srcFac = Cmd_Blend::Blend_Constant_Alpha; + else if (params[0] == "OneMinusConstantAlpha") blend.srcFac = Cmd_Blend::Blend_One_Minus_Constant_Alpha; + else + { + delete pblend; + s_CompileError = string("Compile Shader Error: Invalid parameter of Blend: " + params[0]); + throw GLSLCompileException(s_CompileError.c_str()); + } + + if (params[1] == "Zero") blend.dstFac = Cmd_Blend::Blend_Zero; + else if (params[1] == "One") blend.dstFac = Cmd_Blend::Blend_One; + else if (params[1] == "SrcColor") blend.dstFac = Cmd_Blend::Blend_Src_Color; + else if (params[1] == "OneMinusSrcColor") blend.dstFac = Cmd_Blend::Blend_One_Minus_Src_Color; + else if (params[1] == "DstColor") blend.dstFac = Cmd_Blend::Blend_Dst_Color; + else if (params[1] == "OneMinusDstColor") blend.dstFac = Cmd_Blend::Blend_One_Minus_Dst_Color; + else if (params[1] == "SrcAlpha") blend.dstFac = Cmd_Blend::Blend_Src_Alpha; + else if (params[1] == "OneMinusSrcAlpha") blend.dstFac = Cmd_Blend::Blend_One_Minus_Src_Alpha; + else if (params[1] == "DstAlpha") blend.dstFac = Cmd_Blend::Blend_Dst_Alpha; + else if (params[1] == "OneMinusDstAlpha") blend.dstFac = Cmd_Blend::Blend_One_Minus_Dst_Alpha; + else if (params[1] == "ConstantColor") blend.dstFac = Cmd_Blend::Blend_Constant_Color; + else if (params[1] == "OneMinusConstantColor") blend.dstFac = Cmd_Blend::Blend_One_Minus_Constant_Color; + else if (params[1] == "ConstantAlpha") blend.dstFac = Cmd_Blend::Blend_Constant_Alpha; + else if (params[1] == "OneMinusConstantAlpha") blend.dstFac = Cmd_Blend::Blend_One_Minus_Constant_Alpha; + else + { + delete pblend; + s_CompileError = string("Compile Shader Error: Invalid parameter of Blend: " + params[1]); + throw GLSLCompileException(s_CompileError.c_str()); + } + + group.push_back(pblend); +} + +void GLSLCompiler::CommandDepthTest(std::string& p, RenderCommandGroup& group) +{ + std::string params[1]; + GetParams("DepthTest", p, params, 1); + + Cmd_DepthTest* pTest = new Cmd_DepthTest(); + Cmd_DepthTest& test = *pTest; + if (params[0] == "Off") test.test = Cmd_DepthTest::DepthTest_Off; + else if (params[0] == "Always") test.test = Cmd_DepthTest::DepthTest_Always; + else if (params[0] == "Never") test.test = Cmd_DepthTest::DepthTest_Never; + else if (params[0] == "Less") test.test = Cmd_DepthTest::DepthTest_Less; + else if (params[0] == "Equal") test.test = Cmd_DepthTest::DepthTest_Equal; + else if (params[0] == "LEqual") test.test = Cmd_DepthTest::DepthTest_Lequal; + else if (params[0] == "Greater") test.test = Cmd_DepthTest::DepthTest_Greater; + else if (params[0] == "NotEqual") test.test = Cmd_DepthTest::DepthTest_Notequal; + else if (params[0] == "GEqual") test.test = Cmd_DepthTest::DepthTest_Gequal; + else + { + delete pTest; + s_CompileError = string("Compile Shader Error: Invalid parameter of DepthTest: " + params[0]); + throw GLSLCompileException(s_CompileError.c_str()); + } + group.push_back(pTest); +} + +void GLSLCompiler::CommandDepthWrite(std::string& p, RenderCommandGroup& group) +{ + std::string params[1]; + GetParams("DepthWrite", p, params, 1); + + Cmd_DepthWrite* pwrite = new Cmd_DepthWrite(); + Cmd_DepthWrite& write = *pwrite; + if (params[0] == "Off") write.write = false; + else if (params[0] == "On") write.write = true; + else + { + delete pwrite; + s_CompileError = string("Compile Shader Error: Invalid parameter of DepthWrite: " + params[0]); + throw GLSLCompileException(s_CompileError.c_str()); + } + group.push_back(pwrite); +} + +void GLSLCompiler::GetParams(const char* cmdName, std::string& params, std::string* out, int n) +{ + int index = 0; + for (int i = 0; i < params.size(); ++i) + { + if (IsSeperator(params[i])) + continue; + int j = i + 1; + for (; j < params.size(); ++j) + { + if (j == params.size() - 1) + { + if (index >= n) + { + s_CompileError = string("Compile Shader Error: Invalid parameter count of ") + cmdName +" : " + params; + throw GLSLCompileException(s_CompileError.c_str()); + } + if(!IsSeperator(params[j])) + out[index++] = params.substr(i, j - i + 1); + else + out[index++] = params.substr(i, j - i); + return; + } + if (!IsSeperator(params[j])) + continue; + if (index >= n) + { + s_CompileError = string("Compile Shader Error: Invalid parameter count of ") + cmdName + " : " + params; + throw GLSLCompileException(s_CompileError.c_str()); + } + out[index++] = params.substr(i, j - i); + break; + } + i = j; + } +} diff --git a/Client/Source/Graphics/ShaderCompiler.h b/Client/Source/Graphics/ShaderCompiler.h new file mode 100644 index 0000000..f374567 --- /dev/null +++ b/Client/Source/Graphics/ShaderCompiler.h @@ -0,0 +1,55 @@ +#pragma once + +#include <exception> +#include <string> +#include "../Threading/Mutex.h" +#include "../Threading/Job.h" +#include "../Graphics/RenderCommands.h" + +// 编译GLSL(GameLab Shader) + +// in: .glsl path +// out: vsh & fsh +class CompileGLSLJob : public Job +{ + +}; + +// in: glsl shader +// out: vsh & fsh +class CompileGLSLShaderJob : public Job +{ + +}; + +class GLSLCompileException : public std::exception +{ +public: + GLSLCompileException(const char* what) + : std::exception(what) + { + } + +}; + +class GLSLCompiler +{ +public: + static void Compile(std::string& src, std::string& vsh, std::string& fsh, RenderCommandGroup& cmd)/*throw GLSLCompileException*/; + +private: + static std::string GetContent(std::string& src, const char* from, const char* to); + static std::string TrimContent(std::string& src, const char* from, const char* to); + static bool IsLabelActive(std::string& src, const char* label); + + static void ParseCmd(std::string& cmd, RenderCommandGroup& group); + static bool IsCommandActive(std::string& src, const char* label); + static bool FindCmdPos(std::string& line, int* start, int* end); + static bool IsLineCommentd(std::string& line); + static void CommandCull(std::string& params, RenderCommandGroup& group); + static void CommandBlend(std::string& params, RenderCommandGroup& group); + static void CommandDepthTest(std::string& params, RenderCommandGroup& group); + static void CommandDepthWrite(std::string& params, RenderCommandGroup& group); + static void GetParams(const char* cmdName, std::string& params, std::string* out, int n); + +}; diff --git a/Client/Source/Graphics/Texture.cpp b/Client/Source/Graphics/Texture.cpp new file mode 100644 index 0000000..79dd5ea --- /dev/null +++ b/Client/Source/Graphics/Texture.cpp @@ -0,0 +1,230 @@ +#include "../Math/Math.h" + +#include "ImageData.h" +#include "Texture.h" + +Texture::Texture(TextureSetting setting, ImageData* imgData) +{ + Init(setting, imgData); + // force not keep imgData + m_KeepPixelData = false; +} + +void Texture::Init(TextureSetting setting, ImageData* imgData) +{ + m_Width = imgData->width; + m_Height = imgData->height; + m_Type = setting.type; + m_Format = setting.format; + m_WrapMode = setting.wrapMode; + m_FilterMode = setting.filterMode; + m_KeepPixelData = setting.keepImageData; + + glGenTextures(1, &m_GPUID); + glBindTexture(GL_TEXTURE_2D, m_GPUID); + + CheckGLError( + glDeleteTextures(1, &m_GPUID); + glBindTexture(GL_TEXTURE_2D, 0); + throw TextureException(error); + ); + + switch (m_WrapMode) { + case ETextureWrapMode::Clamp: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + break; + case ETextureWrapMode::Repeat: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + break; + case ETextureWrapMode::Mirror: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); + break; + default: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + break; + } + + CheckGLError( + glDeleteTextures(1, &m_GPUID); + glBindTexture(GL_TEXTURE_2D, 0); + throw TextureException(error); + ); + + switch (m_FilterMode) { + case ETextureFilterMode::Linear: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + case ETextureFilterMode::Nearest: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + default: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + } + + GLint srcFormat = GL_RGB; + switch (imgData->format) + { + case PixelFormat_R: srcFormat = GL_RED; break; + case PixelFormat_RGB: srcFormat = GL_RGB; break; + case PixelFormat_RGBA: srcFormat = GL_RGBA; break; + default: Assert(false); + } + GLint srcType = GL_UNSIGNED_BYTE; + switch (imgData->type) + { + case PixelType_UNSIGNED_BYTE: srcType = GL_UNSIGNED_BYTE; break; + default: Assert(false); + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imgData->width, imgData->height, 0, srcFormat, srcType, imgData->pixels); + + CheckGLError( + glDeleteTextures(1, &m_GPUID); + glBindTexture(GL_TEXTURE_2D, 0); + throw TextureException(error); + ); +} + +Texture::Texture(TextureSetting setting, int w, int h) +{ + m_KeepPixelData = false; + + m_Width = w; + m_Height = h; + m_Type = setting.type; + m_Format = setting.format; + m_WrapMode = setting.wrapMode; + m_FilterMode = setting.filterMode; + m_KeepPixelData = setting.keepImageData; + + WipeGLError(); + + glGenTextures(1, &m_GPUID); + glBindTexture(GL_TEXTURE_2D, m_GPUID); + + CheckGLError( + glDeleteTextures(1, &m_GPUID); + glBindTexture(GL_TEXTURE_2D, 0); + throw TextureException(error); + ); + + switch (m_WrapMode) { + case ETextureWrapMode::Clamp: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + break; + case ETextureWrapMode::Repeat: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + break; + case ETextureWrapMode::Mirror: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); + break; + default: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + break; + } + + CheckGLError( + glDeleteTextures(1, &m_GPUID); + glBindTexture(GL_TEXTURE_2D, 0); + throw TextureException(error); + ); + + switch (m_FilterMode) { + case ETextureFilterMode::Linear: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + case ETextureFilterMode::Nearest: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + default: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + } + GLenum internalFormat = GL_RGB; + if (m_Format == ETextureFormat::R8) + { + internalFormat = GL_RED; + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + } + + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + + CheckGLError( + glDeleteTextures(1, &m_GPUID); + glBindTexture(GL_TEXTURE_2D, 0); + throw TextureException(error); + ); + + glBindTexture(GL_TEXTURE_2D, 0); +} + +Texture::~Texture() +{ + glDeleteTextures(1, &m_GPUID); +} + +void Texture::UpdateSubImage(Rect rect, int format, int type, const void* data) +{ + glBindTexture(GL_TEXTURE_2D, m_GPUID); + + CheckGLError( + glBindTexture(GL_TEXTURE_2D, 0); + throw TextureException(error); + ); + + int alignment = 4; + if (m_Format == ETextureFormat::R8) + { + alignment = 1; + } + + GLenum fmt = GL_RED; + switch (format) + { + case EPixelFormat::PixelFormat_BGR: fmt = GL_BGR; break; + case EPixelFormat::PixelFormat_BGRA:fmt = GL_BGRA; break; + case EPixelFormat::PixelFormat_R: fmt = GL_RED; break; + case EPixelFormat::PixelFormat_RG: fmt = GL_RG; break; + case EPixelFormat::PixelFormat_RGB: fmt = GL_RGB; break; + case EPixelFormat::PixelFormat_RGBA: fmt = GL_RGBA; break; + } + GLenum t = GL_UNSIGNED_BYTE; + switch (type) + { + case EPixelElementType::PixelType_UNSIGNED_BYTE: t = GL_UNSIGNED_BYTE; break; + case EPixelElementType::PixelType_UNSIGNED_INT: t = GL_UNSIGNED_INT; break; + case EPixelElementType::PixelType_BYTE: t = GL_BYTE; break; + case EPixelElementType::PixelType_INT: t = GL_INT; break; + case EPixelElementType::PixelType_FLOAT: t = GL_FLOAT; break; + } + + glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); + + glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x, rect.y, rect.width, rect.height, fmt, t, data); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + + CheckGLError( + glBindTexture(GL_TEXTURE_2D, 0); + throw TextureException(error); + ); + + glBindTexture(GL_TEXTURE_2D, 0); +}
\ No newline at end of file diff --git a/Client/Source/Graphics/Texture.h b/Client/Source/Graphics/Texture.h new file mode 100644 index 0000000..cf423e1 --- /dev/null +++ b/Client/Source/Graphics/Texture.h @@ -0,0 +1,94 @@ +#pragma once +#include <exception> +#include <string> + +#include "../Math/Math.h" +#include "../Utilities/UtilMacros.h" +#include "../Utilities/Assert.h" + +#include "OpenGL.h" + +class ImageData; + +enum ETextureType +{ + TEX_2D, + TEX_CUBE, +}; + +enum ETextureFormat +{ + RGBA32, + RGB24, + RGB16, + R8, + A8, +}; + +enum ETextureWrapMode +{ + Clamp, + Repeat, + Mirror, +}; + +enum ETextureFilterMode +{ + Nearest, + Linear, +}; + +// GPU侧的导入设置 +struct TextureSetting +{ + bool keepImageData; // 是否保存图片数据 + int type; // 图片类型 + int format; // 内部格式 + int wrapMode; // 包围 + int filterMode; // 滤波 +}; + +class TextureException : public std::exception +{ +public: + TextureException(const char* what) + : std::exception(what) + {} + TextureException(int glError) + { + g_sharedGLErrorMsg = std::to_string(glError); + std::exception(g_sharedGLErrorMsg.c_str()); + } +}; + +class Texture +{ +public: + Texture(TextureSetting setting, int width, int height)/*throw TextureException*/; // 空贴图 + Texture(TextureSetting setting, ImageData* imgData)/*throw TextureException*/; + ~Texture(); + + void UpdateSubImage(Rect rect, int format, int type, const void* data); + + GET(int, Width, m_Width); + GET(int, Height, m_Height); + + GET(GLuint, GpuID, m_GPUID); + +private: + void Init(TextureSetting setting, ImageData* imgData); + + //------------------------------------------------------------------------------ + + GLuint m_GPUID; + + int m_Width, m_Height; + + int m_Type; + int m_Format; + int m_FilterMode; + int m_WrapMode; + + bool m_KeepPixelData; // 是否保存图像像素数据,默认导入后不保存 + +};
\ No newline at end of file diff --git a/Client/Source/Graphics/VertexAttribute.cpp b/Client/Source/Graphics/VertexAttribute.cpp new file mode 100644 index 0000000..e5f2ea7 --- /dev/null +++ b/Client/Source/Graphics/VertexAttribute.cpp @@ -0,0 +1,20 @@ +#include "VertexAttribute.h" + +namespace VertexAttribute +{ + + // map VertexAttrFormat to OpenGL type + static GLenum kGLVertexAttrFormat[VertexAttrFormat_Count] = { + GL_FLOAT, // VertexAttrFormat_Float + GL_HALF_FLOAT, // VertexAttrFormat_Float16 + GL_UNSIGNED_BYTE, // VertexAttrFormat_Color + GL_BYTE, // VertexAttrFormat_Byte + GL_UNSIGNED_BYTE, // VertexAttrFormat_Unsigned_Byte + }; + + GLenum ConvertAttrFormatToGLFormat(uint fmt) + { + return kGLVertexAttrFormat[fmt]; + } + +}
\ No newline at end of file diff --git a/Client/Source/Graphics/VertexAttribute.h b/Client/Source/Graphics/VertexAttribute.h new file mode 100644 index 0000000..8f7bc82 --- /dev/null +++ b/Client/Source/Graphics/VertexAttribute.h @@ -0,0 +1,52 @@ +#pragma once + +#include <vector> + +#include "../Utilities/UtilMacros.h" + +#include "OpenGL.h" +#include "GPUDataBuffer.h" + +// component format +enum VertexAttrFormat +{ + VertexAttrFormat_Float = 0, // position\normal\tangent\uv\uv2\uv3\uv4 + VertexAttrFormat_Float16, + VertexAttrFormat_Color, // color + VertexAttrFormat_Byte, + VertexAttrFormat_Unsigned_Byte, + + VertexAttrFormat_Count +}; + +struct VertexAttributeDescriptor +{ + //union { + const void* pointer; // 内存地址,刚创建时留空 + int startOffset; // 显存中相对VBO的偏移值 + //}; + uint componentNum; // 向量维度1,2,3,4 + uint componentFormat; // 每个分量的类型 + uint16 stride; // 间隔 + bool normalize; // 是否归一化,只用于CustomVertexLayout + + // for default vertex layout + VertexAttributeDescriptor() {} + // for custom vertex layout + VertexAttributeDescriptor(int startOff, uint num, uint fmt, uint16 strd, bool normalized = false) + { + startOffset = startOff; + componentNum = num; + componentFormat = fmt; + stride = strd; + normalize = normalized; + } + +}; + +namespace VertexAttribute +{ + + extern GLenum ConvertAttrFormatToGLFormat(uint fmt); + +} diff --git a/Client/Source/Graphics/VertexBuffer.cpp b/Client/Source/Graphics/VertexBuffer.cpp new file mode 100644 index 0000000..d95bf58 --- /dev/null +++ b/Client/Source/Graphics/VertexBuffer.cpp @@ -0,0 +1,109 @@ +#include "VertexBuffer.h" + +VertexBuffer::VertexBuffer(int vbSize, int ibSize, VertexBufferType type) +{ + m_VB = GPU::ClaimBuffer(vbSize, GL_STATIC_DRAW); + m_IB = GPU::ClaimBuffer(ibSize, GL_STATIC_DRAW); +} + +VertexBuffer::~VertexBuffer() +{ + GPU::ReleaseBuffer(m_VB); + GPU::ReleaseBuffer(m_IB); +} +// GetChunk +// <fill> +// FlushChunk +// DrawChunk +void VertexBuffer::GetChunk(uint sizePerVert, uint sizePerIndex, int maxVerts, int maxIndices, EPrimitive primitive, void **out_vb, void **out_ib) +{ + m_SizePerVertex = sizePerVert; + + uint vbufferSize = sizePerVert * maxVerts; + uint ibufferSize = sizePerIndex * maxIndices; + + GLenum usage = GL_STATIC_DRAW; + m_VB->Restore(vbufferSize, usage); + m_IB->Restore(ibufferSize, usage); + + const GLenum access = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_FLUSH_EXPLICIT_BIT; + + *out_vb = m_VB->MapRange(0, vbufferSize, access); + *out_ib = m_IB->MapRange(0, ibufferSize, access); + + m_Primitive = primitive; + + WipeGLError(); +} + +void VertexBuffer::FlushChunk(int actualVerts, int actualIndices) +{ + int actualVBufferSize = m_SizePerVertex * actualVerts; + int actualIBufferSize = VertexLayout::GetDefaultIndexSize() * actualIndices; + + m_CurIndexCount = actualIndices; + + m_VB->FlushMapedRange(0, actualVBufferSize); + m_IB->FlushMapedRange(0, actualIBufferSize); + + m_VB->UnMap(); + m_IB->UnMap(); + + WipeGLError(); +} + +void VertexBuffer::Draw(CustomVertexLayout& layout) +{ + const byte* basepointer = 0; + const GLuint buffer = m_VB->GetHandle(); + + FillCustomVertexLayout(layout); + + VertexLayout::SetupCustomVertexLayout(layout); + + layout.RestorePointer(); + + const void* indexPtr = 0; + + CheckGLError( + throw GLException(error); + ); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IB->GetHandle()); + + CheckGLError( + throw GLException(error); + ); + GLenum indexFormat = VertexLayout::GetDefaultIndexFormat(); + + switch (m_Primitive) + { + case Primitive_Triangle: + glDrawElements(GL_TRIANGLES, m_CurIndexCount, indexFormat, indexPtr); + break; + case Primitive_Line: + glDrawElements(GL_LINE, m_CurIndexCount, indexFormat, indexPtr); + break; + case Primitive_Point: + glDrawElements(GL_POINT, m_CurIndexCount, indexFormat, indexPtr); + break; + } + + CheckGLError( + throw GLException(error); + ); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +void VertexBuffer::FillCustomVertexLayout(CustomVertexLayout& dst) +{ + const byte* basepointer = 0; + const GLuint buffer = m_VB->GetHandle(); + + dst.buffer = buffer; + + for (int i = 0; i < dst.attributes.size(); ++i) + { + int offset = dst.attributes[i].startOffset; + dst.attributes[i].pointer = basepointer + offset; + } +}
\ No newline at end of file diff --git a/Client/Source/Graphics/VertexBuffer.h b/Client/Source/Graphics/VertexBuffer.h new file mode 100644 index 0000000..b907337 --- /dev/null +++ b/Client/Source/Graphics/VertexBuffer.h @@ -0,0 +1,52 @@ +#pragma once + +#include <vector> + +#include "../Utilities/UtilMacros.h" + +#include "OpenGL.h" +#include "GPUDataBuffer.h" +#include "DefaultVertexLayout.h" +#include "CustomVertexLayout.h" +#include "Primitive.h" + +// 实际使用过程中,通常是一个VBO和一个IBO一起,submesh对应的是IBO中的不同的段,而不是不同的IBO + +class VertexBuffer +{ +public: + enum VertexBufferType + { + VertexBufferType_Static, // device + VertexBufferType_Stream, // pinned (best performance) + VertexBufferType_Dynamic,// device + }; + + VertexBuffer(int vbSize, int ibSize, VertexBufferType type); + ~VertexBuffer(); + + // 填充数据 + void GetChunk(uint sizePerVert, uint sizePerIndex, int maxVerts, int maxIndices, EPrimitive primitive, void **out_vb, void **out_ib); + // 提交数据 + void FlushChunk(int actualVerts, int actualIndices); + + GET(GPU::DataBuffer*, VB, m_VB); + GET(GPU::DataBuffer*, IB, m_IB); + + void Draw(CustomVertexLayout& layout); + +private: + void FillCustomVertexLayout(CustomVertexLayout& dst); + + VertexBufferType m_Type; + + GPU::DataBuffer* m_VB; + GPU::DataBuffer* m_IB; + + int m_SizePerVertex; + + int m_CurIndexCount; + + EPrimitive m_Primitive; + +}; |