summaryrefslogtreecommitdiff
path: root/Source/modules/asura-core/Graphics/Shader.cpp
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-08-07 21:08:47 +0800
committerchai <chaifix@163.com>2019-08-07 21:08:47 +0800
commit0c391fdbce5a079cf03e483eb6174dd47806163d (patch)
treeb06cd7a9d0ae0d9bb9e82f3dcb786dfce11f8628 /Source/modules/asura-core/Graphics/Shader.cpp
parent9686368e58e25cbd6dc37d686bdd2be3f80486d6 (diff)
*misc
Diffstat (limited to 'Source/modules/asura-core/Graphics/Shader.cpp')
-rw-r--r--Source/modules/asura-core/Graphics/Shader.cpp282
1 files changed, 282 insertions, 0 deletions
diff --git a/Source/modules/asura-core/Graphics/Shader.cpp b/Source/modules/asura-core/Graphics/Shader.cpp
new file mode 100644
index 0000000..329b3f1
--- /dev/null
+++ b/Source/modules/asura-core/Graphics/Shader.cpp
@@ -0,0 +1,282 @@
+#include <asura-base/Exception.h>
+
+#include "GfxDevice.h"
+#include "Shader.h"
+
+using namespace std;
+
+namespace_begin(AsuraEngine)
+namespace_begin(Graphics)
+
+// texture unit
+static uint8 texUnit = 0;
+
+Shader::Shader()
+{
+}
+
+Shader::~Shader()
+{
+ if(m_VertShader) glDeleteShader(m_VertShader);
+ if(m_FragShader) glDeleteShader(m_FragShader);
+ if(m_Program) glDeleteProgram(m_Program);
+}
+
+void Shader::SetActive(Shader* shader)
+{
+ g_Device.SetActiveShader(shader);
+}
+
+Shader* Shader::GetActive()
+{
+ return g_Device.GetActiveShader();
+}
+
+bool Shader::Load(const string& vert, const string& frag)
+{
+ string warnning = "";
+
+ if (!m_Program)
+ {
+ m_Program = glCreateProgram();
+ if (!m_Program)
+ throw Exception("Cannot create OpenGL shader program.");
+ }
+
+ if (!CompileVertexShader(vert, warnning))
+ {
+ throw Exception("Compile vertex shader failed:%s", warnning);
+ }
+
+ if (!CompileFragementShader(frag, warnning))
+ {
+ throw Exception("Compile fragment shader failed:%s", warnning);
+ }
+
+ glAttachShader(m_Program, m_VertShader);
+ glAttachShader(m_Program, m_FragShader);
+
+ glLinkProgram(m_Program);
+ GLint success;
+ glGetProgramiv(m_Program, GL_LINK_STATUS, &success);
+ if (success == GL_FALSE)
+ {
+ warnning = GetProgramWarnings();
+ throw Exception("Link shader program failed:\n%s", warnning.c_str());
+ }
+
+ return true;
+}
+
+bool Shader::CompileVertexShader(const string& vert, string& outError)
+{
+ if (!m_VertShader)
+ {
+ m_VertShader = glCreateShader(GL_VERTEX_SHADER);
+ if (!m_VertShader)
+ {
+ outError = "Cannot create OpenGL Vertex shader.";
+ return false;
+ }
+ }
+
+ const GLchar* source = vert.c_str();
+ GLint success;
+
+ glShaderSource(m_VertShader, 1, &source, NULL);
+ glCompileShader(m_VertShader);
+ glGetShaderiv(m_VertShader, GL_COMPILE_STATUS, &success);
+ if (success == GL_FALSE)
+ {
+ outError = GetShaderWarnings(m_VertShader);
+ return false;
+ }
+
+ return true;
+}
+
+bool Shader::CompileFragementShader(const string& frag, string& outError)
+{
+ if (!m_FragShader)
+ {
+ m_FragShader = glCreateShader(GL_FRAGMENT_SHADER);
+ if (!m_FragShader)
+ {
+ outError = "Cannot create OpenGL fragment shader.";
+ return false;
+ }
+ }
+
+ const GLchar* source = frag.c_str();
+ GLint success;
+
+ source = frag.c_str();
+ glShaderSource(m_FragShader, 1, &source, NULL);
+ glCompileShader(m_FragShader);
+ glGetShaderiv(m_FragShader, GL_COMPILE_STATUS, &success);
+ if (success == GL_FALSE)
+ {
+ outError = GetShaderWarnings(m_FragShader);
+ return false;
+ }
+
+ return true;
+}
+
+void Shader::OnEnable()
+{
+ texUnit = 0;
+}
+
+void Shader::OnDisable()
+{
+ texUnit = 0;
+}
+
+void Shader::OnUsed()
+{
+ texUnit = 0;
+}
+
+uint Shader::GetUniformLocation(const std::string& uniform)
+{
+ GLint loc = glGetUniformLocation(m_Program, uniform.c_str());
+ return loc;
+}
+
+bool Shader::HasUniform(const std::string& uniform)
+{
+ GLint loc = glGetUniformLocation(m_Program, uniform.c_str());
+ return loc != -1;
+}
+
+GLuint Shader::GetGLProgram()
+{
+ return m_Program;
+}
+
+void Shader::SetUniformFloat(uint loc, float value)
+{
+ if(g_Device.GetActiveShader() == this)
+ glUniform1f(loc, value);
+}
+
+bool Shader::SetUniformTexture(uint loc, const Texture& texture)
+{
+ if (g_Device.GetActiveShader() != this)
+ return false;
+
+ g_Device.WipeError();
+ glActiveTexture(GL_TEXTURE0 + texUnit);
+ if (g_Device.HasError())
+ return false;
+ GLint tex = texture.GetGLTexture();
+ glBindTexture(GL_TEXTURE_2D, tex);
+ if (g_Device.HasError())
+ return false;
+ glUniform1i(loc, texUnit);
+ if (g_Device.HasError())
+ return false;
+ ++texUnit;
+}
+
+void Shader::SetUniformVector2(uint loc, const Math::Vector2f& vec2)
+{
+ if (g_Device.GetActiveShader() == this)
+ glUniform2f(loc, vec2.x, vec2.y);
+}
+
+void Shader::SetUniformVector3(uint loc, const Math::Vector3f& vec3)
+{
+ if (g_Device.GetActiveShader() == this)
+ glUniform3f(loc, vec3.x, vec3.y, vec3.z);
+}
+
+void Shader::SetUniformVector4(uint loc, const Math::Vector4f& vec4)
+{
+ if (g_Device.GetActiveShader() == this)
+ glUniform4f(loc, vec4.x, vec4.y, vec4.z, vec4.w);
+}
+
+void Shader::SetUniformMatrix44(uint loc, const Math::Matrix44& mat)
+{
+ if (g_Device.GetActiveShader() == this)
+ glUniformMatrix4fv(loc, 1, GL_FALSE, mat.GetElements());
+}
+
+void Shader::SetUniformColor(uint loc, const Color& color)
+{
+ if (g_Device.GetActiveShader() == this)
+ glUniform4f(loc, color.r, color.g, color.b, color.a);
+}
+
+uint Shader::GetGLTextureUnitCount()
+{
+ GLint maxTextureUnits;
+ glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
+ return (uint)maxTextureUnits;
+}
+
+std::string Shader::GetProgramWarnings()
+{
+ GLint strsize, nullpos;
+ glGetProgramiv(m_Program, GL_INFO_LOG_LENGTH, &strsize);
+
+ if (strsize == 0)
+ return "";
+
+ char *tempstr = new char[strsize];
+
+ memset(tempstr, '\0', strsize);
+ glGetProgramInfoLog(m_Program, strsize, &nullpos, tempstr);
+ tempstr[nullpos] = '\0';
+
+ std::string warnings(tempstr);
+ delete[] tempstr;
+
+ return warnings;
+}
+
+std::string Shader::GetShaderWarnings(GLuint shader)
+{
+ GLint strsize, nullpos;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &strsize);
+
+ if (strsize == 0)
+ return "";
+
+ char *tempstr = new char[strsize];
+
+ memset(tempstr, '\0', strsize);
+ glGetShaderInfoLog(shader, strsize, &nullpos, tempstr);
+ tempstr[nullpos] = '\0';
+
+ std::string warnings(tempstr);
+ delete[] tempstr;
+
+ return warnings;
+}
+
+void Shader::SetAttribute(int loc, VertexBuffer* vbo, uint offseti, uint stridei, bool normalized)
+{
+ GLsizei offset = offseti * vbo->GetDataTypeSize();
+ GLsizei stride = stridei * vbo->GetDataTypeSize();
+ glEnableVertexAttribArray(loc);
+ vbo->Bind();
+ glVertexAttribPointer(loc, 2, vbo->GetDataType(), normalized, stride, (GLvoid*)offset);
+ vbo->UnBind();
+}
+
+int Shader::GetAttributeLocation(const std::string& attribute)
+{
+ int loc = glGetAttribLocation(m_Program, attribute.c_str());
+ return loc;
+}
+
+void Shader::DisableAttribute(int loc)
+{
+ glDisableVertexAttribArray(loc);
+}
+
+namespace_end
+namespace_end \ No newline at end of file