summaryrefslogtreecommitdiff
path: root/Client/Source/Graphics
diff options
context:
space:
mode:
Diffstat (limited to 'Client/Source/Graphics')
-rw-r--r--Client/Source/Graphics/Color.cpp4
-rw-r--r--Client/Source/Graphics/Color.h48
-rw-r--r--Client/Source/Graphics/CustomVertexLayout.cpp23
-rw-r--r--Client/Source/Graphics/CustomVertexLayout.h33
-rw-r--r--Client/Source/Graphics/DefaultVertexLayout.cpp119
-rw-r--r--Client/Source/Graphics/DefaultVertexLayout.h55
-rw-r--r--Client/Source/Graphics/DeviceDefine.h69
-rw-r--r--Client/Source/Graphics/DynamicMesh.h13
-rw-r--r--Client/Source/Graphics/DynamicVertexBuffer.cpp260
-rw-r--r--Client/Source/Graphics/DynamicVertexBuffer.h54
-rw-r--r--Client/Source/Graphics/FrameBuffer.cpp12
-rw-r--r--Client/Source/Graphics/FrameBuffer.h35
-rw-r--r--Client/Source/Graphics/GPUDataBuffer.cpp207
-rw-r--r--Client/Source/Graphics/GPUDataBuffer.h75
-rw-r--r--Client/Source/Graphics/GfxDevice.cpp169
-rw-r--r--Client/Source/Graphics/GfxDevice.h109
-rw-r--r--Client/Source/Graphics/GlyphAtlas.cpp0
-rw-r--r--Client/Source/Graphics/GlyphAtlas.h6
-rw-r--r--Client/Source/Graphics/ImageData.cpp2
-rw-r--r--Client/Source/Graphics/ImageData.h39
-rw-r--r--Client/Source/Graphics/OpenGL.cpp7
-rw-r--r--Client/Source/Graphics/OpenGL.h41
-rw-r--r--Client/Source/Graphics/Point.cpp0
-rw-r--r--Client/Source/Graphics/Point.h0
-rw-r--r--Client/Source/Graphics/PolyLine.cpp9
-rw-r--r--Client/Source/Graphics/PolyLine.h18
-rw-r--r--Client/Source/Graphics/Primitive.h8
-rw-r--r--Client/Source/Graphics/Quad.cpp62
-rw-r--r--Client/Source/Graphics/Quad.h26
-rw-r--r--Client/Source/Graphics/RenderCommands.cpp9
-rw-r--r--Client/Source/Graphics/RenderCommands.h164
-rw-r--r--Client/Source/Graphics/RenderTexture.cpp0
-rw-r--r--Client/Source/Graphics/RenderTexture.h16
-rw-r--r--Client/Source/Graphics/Shader.cpp154
-rw-r--r--Client/Source/Graphics/Shader.h47
-rw-r--r--Client/Source/Graphics/ShaderCompiler.cpp347
-rw-r--r--Client/Source/Graphics/ShaderCompiler.h55
-rw-r--r--Client/Source/Graphics/Texture.cpp230
-rw-r--r--Client/Source/Graphics/Texture.h94
-rw-r--r--Client/Source/Graphics/VertexAttribute.cpp20
-rw-r--r--Client/Source/Graphics/VertexAttribute.h52
-rw-r--r--Client/Source/Graphics/VertexBuffer.cpp109
-rw-r--r--Client/Source/Graphics/VertexBuffer.h52
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;
+
+};