CSEngine
Loading...
Searching...
No Matches
ShaderUtil.cpp
1//
2// Created by ounols on 19. 4. 30.
3//
4
5#include "ShaderUtil.h"
6#include "../MoreString.h"
7#include "SEnvironmentMgr.h"
8#include "../Settings.h"
9#include "../../PlatformDef.h"
10
11using namespace CSE;
12
13#if defined(__CSE_DESKTOP__)
14std::string ShaderUtil::m_defineVersion = "#version 330 core\n";
15#elif defined(__CSE_ES__)
16std::string ShaderUtil::m_defineVersion = "#version 300 es\n";
17#endif
18
19ShaderUtil::ShaderUtil() = default;
20
21ShaderUtil::~ShaderUtil() = default;
22
24ShaderUtil::CreateProgramHandle(const GLchar* vertexSource, const GLchar* fragmentSource, GLProgramHandle* handle) {
25 if (vertexSource == nullptr || fragmentSource == nullptr) return nullptr;
26 if (handle != nullptr && handle->Program != HANDLE_NULL) return nullptr;
27
28 GLProgramHandle* newHandle = handle;
29 auto program = createProgram(vertexSource, fragmentSource, *newHandle);
30 if (!program) {
31 return nullptr;
32 }
33
34 //Find important variables from shader.
35 auto variables_vert = GetImportantVariables(vertexSource);
36 auto variables_frag = GetImportantVariables(fragmentSource);
37
38 if (newHandle == nullptr)
39 newHandle = new GLProgramHandle();
40 newHandle->SetProgram(program);
41 //Get all variables from shader.
42 newHandle->SetAttributesList(variables_vert, variables_frag);
43 newHandle->SetUniformsList(variables_vert, variables_frag);
44
45 //Binding important variables to engine.
46 BindVariables(newHandle);
47
48 return newHandle;
49}
50
51GLuint
52ShaderUtil::createProgram(const GLchar* vertexSource, const GLchar* fragmentSource, const GLProgramHandle& handle) {
53 GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vertexSource, handle);
54 if (!vertexShader) {
55 return 0;
56 }
57
58 GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource, handle);
59 if (!fragmentShader) {
60 return 0;
61 }
62
63 return createProgram(vertexShader, fragmentShader, handle);
64}
65
66GLuint ShaderUtil::createProgram(GLuint vertexShader, GLuint fragmentShader, const GLProgramHandle& handle) {
67 GLuint program = glCreateProgram();
68
69 if (program) {
70 //쉐이더를 attach 합니다.
71 glAttachShader(program, vertexShader);
72 glAttachShader(program, fragmentShader);
73 glLinkProgram(program);
74
75 GLint linkStatus = GL_FALSE;
76 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
77 if (linkStatus != GL_TRUE) {
78 GLint bufLength = 0;
79 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
80
81 if (bufLength) {
82 auto buf = static_cast<char*>(malloc(bufLength));
83
84 if (buf) {
85 glGetProgramInfoLog(program, bufLength, nullptr, buf);
86 auto errorLog = std::string("[") + handle.GetName() + "] Could not link program:" + buf;
87 SafeLog::Log(errorLog.c_str());
88 free(buf);
89
90 }
91 }
92 glDeleteProgram(program);
93 program = 0;
94
95 }
96 glDetachShader(program, vertexShader);
97 glDetachShader(program, fragmentShader);
98
99 }
100 glDeleteShader(vertexShader);
101 glDeleteShader(fragmentShader);
102
103 return program;
104}
105
106GLuint ShaderUtil::loadShader(GLenum shaderType, const char* pSource, const GLProgramHandle& handle) {
107 GLuint shader = glCreateShader(shaderType);
108 std::string srcString = m_defineVersion
109 + "#define MAX_JOINTS " + std::to_string(Settings::GetMaxJoints()) + '\n'
110 + "#define MAX_LIGHTS " + std::to_string(Settings::GetMaxLights()) + '\n'
111 + pSource;
112 const char* src = srcString.c_str();
113
114 if (shader) {
115 glShaderSource(shader, 1, &src, nullptr);
116 glCompileShader(shader);
117 GLint compiled = 0;
118 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
119
120 if (!compiled) {
121 GLint infoLen = 0;
122 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
123
124 if (infoLen) {
125 auto buf = static_cast<char*>(malloc(infoLen));
126
127 if (buf) {
128 glGetShaderInfoLog(shader, infoLen, nullptr, buf);
129 //LOGE("Could not compile shader %d:\n%s\n", shaderType, buf);
130 auto errorLog = std::string("[") + handle.GetName() + "] Could not compile shader:" + buf;
131 SafeLog::Log(errorLog.c_str());
132 free(buf);
133 }
134 glDeleteShader(shader);
135 shader = 0;
136 }
137 }
138 }
139 return shader;
140}
141
142std::map<std::string, std::string> ShaderUtil::GetImportantVariables(const GLchar* source) {
143 // source를 각 라인별로 나누기 위해 std::stringstream을 사용
144 std::stringstream ss(source);
145 std::string line;
146 std::map<std::string, std::string> variables;
147 std::string type_str;
148
149 // std::stringstream에서 각 라인을 읽음
150 while (std::getline(ss, line)) {
151 // 변수 타입을 포함하는 주석 블록의 시작과 끝 인덱스를 찾음
152 int start_index = line.find("//[");
153 int end_index = line.find("]//");
154
155 if (start_index != std::string::npos && end_index != std::string::npos) {
156 // 시작 인덱스를 3 증가시킴 (주석 블록을 제외한 타입 이름의 시작 인덱스)
157 start_index += 3;
158 // 타입 이름을 추출
159 type_str = line.substr(start_index, end_index - 3);
160 continue;
161 }
162
163 // 타입 이름이 찾아졌으면, 변수 선언을 이 라인에서 찾음
164 if (!type_str.empty()) {
165 // 문장의 끝을 나타내는 세미콜론의 인덱스를 찾음
166 int eoc_index = line.find(';');
167
168 if (eoc_index != std::string::npos) {
169 // 변수 이름의 시작과 끝 인덱스를 찾음
170 int startIndex = line.substr(0, eoc_index).rfind(' ');
171 int endIndex = line.rfind('[');
172 endIndex = endIndex == std::string::npos ? eoc_index : endIndex;
173 auto detail = line.substr(startIndex, endIndex - startIndex);
174
175 // 변수 이름의 공백을 제거하고 맵에 추가
176 detail = trim(detail);
177 variables[type_str] = detail;
178 type_str.clear();
179 }
180 }
181 }
182
183 return variables;
184}
185
187 if (handle == nullptr) return;
188
189 //Attributes
190 auto position = handle->AttributeLocation("att.position");
191 auto normal = handle->AttributeLocation("att.normal");
192 auto jointId = handle->AttributeLocation("att.joint_indices");
193 auto weight = handle->AttributeLocation("att.weight");
194 auto textureCoord = handle->AttributeLocation("att.tex_uv");
195 auto color = handle->AttributeLocation("att.color");
196 //Uniforms
197 auto view = handle->UniformLocation("matrix.view");
198 auto model = handle->UniformLocation("matrix.model");
199 auto cameraPosition = handle->UniformLocation("vec3.camera");
200 auto projection = handle->UniformLocation("matrix.projection");
201 auto projectionInv = handle->UniformLocation("matrix.projection.inv");
202 auto viewInv = handle->UniformLocation("matrix.view.inv");
203 auto skinningMode = handle->UniformLocation("matrix.skinning_mode");
204 auto jointMatrix = handle->UniformLocation("matrix.joint");
205 auto lightPosition = handle->UniformLocation("light.position");
206 auto lightType = handle->UniformLocation("light.type");
207 auto lightRadius = handle->UniformLocation("light.radius");
208 auto lightColor = handle->UniformLocation("light.color");
209 auto lightShadowMap = handle->UniformLocation("light.shadow_map");
210 auto lightMatrix = handle->UniformLocation("light.matrix");
211 auto lightShadowMode = handle->UniformLocation("light.shadow_mode");
212 auto lightSize = handle->UniformLocation("light.size");
213 auto lightIrradiance = handle->UniformLocation("light.irradiance");
214 auto lightPrefilter = handle->UniformLocation("light.prefilter");
215 auto lightBrdf = handle->UniformLocation("light.brdf");
216 auto srcBuffer = handle->UniformLocation("buffer.source");
217 auto srcBufferSize = handle->UniformLocation("buffer.source.size");
218
219 handle->Attributes.Position = position != nullptr ? position->id : HANDLE_NULL;
220 handle->Attributes.Normal = normal != nullptr ? normal->id : HANDLE_NULL;
221 handle->Attributes.JointId = jointId != nullptr ? jointId->id : HANDLE_NULL;
222 handle->Attributes.Weight = weight != nullptr ? weight->id : HANDLE_NULL;
223 handle->Attributes.TextureCoord = textureCoord != nullptr ? textureCoord->id : HANDLE_NULL;
224 handle->Attributes.Color = color != nullptr ? color->id : HANDLE_NULL;
225
226 handle->Uniforms.ViewMatrix = view != nullptr ? view->id : HANDLE_NULL;
227 handle->Uniforms.ModelMatrix = model != nullptr ? model->id : HANDLE_NULL;
228 handle->Uniforms.CameraPosition = cameraPosition != nullptr ? cameraPosition->id : HANDLE_NULL;
229 handle->Uniforms.ProjectionMatrix = projection != nullptr ? projection->id : HANDLE_NULL;
230 handle->Uniforms.ProjectionInvMatrix = projectionInv != nullptr ? projectionInv->id : HANDLE_NULL;
231 handle->Uniforms.ViewInvMatrix = viewInv != nullptr ? viewInv->id : HANDLE_NULL;
232 handle->Uniforms.SkinningMode = skinningMode != nullptr ? skinningMode->id : HANDLE_NULL;
233 handle->Uniforms.JointMatrix = jointMatrix != nullptr ? jointMatrix->id : HANDLE_NULL;
234 handle->Uniforms.LightPosition = lightPosition != nullptr ? lightPosition->id : HANDLE_NULL;
235 handle->Uniforms.LightType = lightType != nullptr ? lightType->id : HANDLE_NULL;
236 handle->Uniforms.LightRadius = lightRadius != nullptr ? lightRadius->id : HANDLE_NULL;
237 handle->Uniforms.LightColor = lightColor != nullptr ? lightColor->id : HANDLE_NULL;
238 handle->Uniforms.LightShadowMap = lightShadowMap != nullptr ? lightShadowMap->id : HANDLE_NULL;
239 handle->Uniforms.LightMatrix = lightMatrix != nullptr ? lightMatrix->id : HANDLE_NULL;
240 handle->Uniforms.LightShadowMode = lightShadowMode != nullptr ? lightShadowMode->id : HANDLE_NULL;
241 handle->Uniforms.LightSize = lightSize != nullptr ? lightSize->id : HANDLE_NULL;
242 handle->Uniforms.LightIrradiance = lightIrradiance != nullptr ? lightIrradiance->id : HANDLE_NULL;
243 handle->Uniforms.LightPrefilter = lightPrefilter != nullptr ? lightPrefilter->id : HANDLE_NULL;
244 handle->Uniforms.LightBrdfLut = lightBrdf != nullptr ? lightBrdf->id : HANDLE_NULL;
245 handle->Uniforms.SourceBuffer = srcBuffer != nullptr ? srcBuffer->id : HANDLE_NULL;
246 handle->Uniforms.SourceBufferSize = srcBufferSize != nullptr ? srcBufferSize->id : HANDLE_NULL;
247}
248
249void ShaderUtil::BindCameraToShader(const GLProgramHandle& handle, const mat4& view, const vec3& cameraPosition,
250 const mat4& projection, const mat4& transform) {
251 if(handle.Uniforms.ViewMatrix >= 0)
252 glUniformMatrix4fv(handle.Uniforms.ViewMatrix, 1, 0, view.Pointer());
253 if(handle.Uniforms.ModelMatrix >= 0)
254 glUniformMatrix4fv(handle.Uniforms.ModelMatrix, 1, 0, transform.Pointer());
255 if(handle.Uniforms.ProjectionMatrix >= 0)
256 glUniformMatrix4fv(handle.Uniforms.ProjectionMatrix, 1, 0, projection.Pointer());
257 if(handle.Uniforms.CameraPosition >= 0)
258 glUniform3fv(handle.Uniforms.CameraPosition, 1, cameraPosition.Pointer());
259
260 if(handle.Uniforms.ProjectionInvMatrix >= 0)
261 glUniformMatrix4fv(handle.Uniforms.ProjectionInvMatrix, 1, 0, mat4::Invert(projection).Pointer());
262 if(handle.Uniforms.ViewInvMatrix >= 0)
263 glUniformMatrix4fv(handle.Uniforms.ViewInvMatrix, 1, 0, mat4::Invert(view).Pointer());
264}
265
266// position(x y z) + normal(x y z) + tex(u v) + weight(x y z) + jointID(id1, id2, id3)
268 int stride = 4 * sizeof(vec3) + sizeof(vec2); //normal + position + uv = (4 * sizeof(vec3) + sizeof(vec2))
269 // 필요한 속성 정의
270 struct Attribute {
271 int id; // 속성 ID
272 size_t offset; // 오프셋
273 int size; // 속성의 개수
274 };
275
276 // 필요한 속성들을 정의
277 const std::vector<Attribute> attributes = {
278 { handle.Attributes.Position, 0, 3 },
279 { handle.Attributes.Normal, sizeof(vec3), 3 },
280 { handle.Attributes.TextureCoord, 2 * sizeof(vec3), 2 },
281 { handle.Attributes.Weight, 2 * sizeof(vec3) + sizeof(vec2), 3 },
282 { handle.Attributes.JointId, 3 * sizeof(vec3) + sizeof(vec2), 3 },
283 };
284
285 // 속성들을 바인딩
286 glBindVertexArray(meshId.m_vertexArray);
287 glBindBuffer(GL_ARRAY_BUFFER, meshId.m_vertexBuffer);
288 for (const auto& attribute: attributes) {
289 if (attribute.id < 0) continue; // 속성이 없을 경우 다음 속성으로
290 glEnableVertexAttribArray(attribute.id);
291 glVertexAttribPointer(attribute.id, attribute.size, GL_FLOAT, GL_FALSE, stride, (GLvoid*) attribute.offset);
292 }
293
294 // 인덱스가 있을 경우 인덱스 버퍼를 바인딩
295 if (meshId.m_indexSize < 0) {
296 glDrawArrays(GL_TRIANGLES, 0, meshId.m_vertexSize);
297 } else {
298 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshId.m_indexBuffer);
299 glDrawElements(GL_TRIANGLES, meshId.m_indexSize * 3, GL_UNSIGNED_SHORT, nullptr);
300 }
301 // 속성들의 바인딩을 해제
302 for (const auto& attribute: attributes) {
303 if (attribute.id < 0) continue; // 속성이 없을 경우 다음 속성으로
304 glDisableVertexAttribArray(attribute.id);
305 }
306 glBindVertexArray(0);
307}
308
309void ShaderUtil::BindAttributeToPlane() {
310 SEnvironmentMgr::RenderPlaneVAO();
311}
312
313void ShaderUtil::BindAttributeToCubeMap() {
314 SEnvironmentMgr::RenderCubeVAO();
315}
316
318 const std::vector<mat4>& jointMatrix) {
319 if (!meshId.m_hasJoint || jointMatrix.empty()) {
320 glUniform1i(handle.Uniforms.SkinningMode, 0);
321 return;
322 }
323
324 std::vector<float> result;
325 result.reserve(jointMatrix.size() * 16);
326 for (const mat4& matrix: jointMatrix) {
327 std::copy(matrix.Pointer(), matrix.Pointer() + 16, std::back_inserter(result));
328 }
329
330 glUniformMatrix4fv(handle.Uniforms.JointMatrix, Settings::GetMaxJoints(), GL_FALSE, &result[0]);
331 glUniform1i(handle.Uniforms.SkinningMode, 1);
332}
static void BindVariables(GLProgramHandle *handle)
Binds variables to the shader.
static GLProgramHandle * CreateProgramHandle(const GLchar *vertexSource, const GLchar *fragmentSource, GLProgramHandle *handle=nullptr)
Creates a program handle.
static void BindAttributeToShader(const GLProgramHandle &handle, const GLMeshID &meshId)
Binds the attributes to the shader.
ShaderUtil()
Constructor for the ShaderUtil class.
static std::map< std::string, std::string > GetImportantVariables(const GLchar *source)
Gets the important variables from the shader source code.
~ShaderUtil()
Destructor for the ShaderUtil class.
static GLuint loadShader(GLenum shaderType, const char *pSource, const GLProgramHandle &handle)
Loads a shader.
static GLuint createProgram(const GLchar *vertexSource, const GLchar *fragmentSource, const GLProgramHandle &handle)
Creates a program.
static void BindSkinningDataToShader(const GLProgramHandle &handle, const GLMeshID &meshId, const std::vector< mat4 > &jointMatrix)
Binds the skinning data to the shader.
static void BindCameraToShader(const GLProgramHandle &handle, const mat4 &camera, const vec3 &cameraPosition, const mat4 &projection, const mat4 &transform)
Binds the camera data to the shader.