1#include "opengl_sl.h"
2
3#include <base/detect.h>
4#include <base/io.h>
5#include <base/log.h>
6
7#if defined(BACKEND_AS_OPENGL_ES) || !defined(CONF_BACKEND_OPENGL_ES)
8
9#include <engine/client/backend/glsl_shader_compiler.h>
10#include <engine/graphics.h>
11#include <engine/shared/linereader.h>
12#include <engine/storage.h>
13
14#include <cstdio>
15#include <string>
16#include <vector>
17
18#ifndef BACKEND_AS_OPENGL_ES
19#include <GL/glew.h>
20#else
21#include <GLES3/gl3.h>
22#endif
23
24bool CGLSL::LoadShader(CGLSLCompiler *pCompiler, IStorage *pStorage, const char *pFile, int Type)
25{
26 if(m_IsLoaded)
27 return true;
28
29 CLineReader LineReader;
30 std::vector<std::string> vLines;
31 if(!LineReader.OpenFile(File: pStorage->OpenFile(pFilename: pFile, Flags: IOFLAG_READ, Type: IStorage::TYPE_ALL)))
32 {
33 return false;
34 }
35
36 EBackendType BackendType = pCompiler->m_IsOpenGLES ? BACKEND_TYPE_OPENGL_ES : BACKEND_TYPE_OPENGL;
37 bool IsNewOpenGL = (BackendType == BACKEND_TYPE_OPENGL ? (pCompiler->m_OpenGLVersionMajor >= 4 || (pCompiler->m_OpenGLVersionMajor == 3 && pCompiler->m_OpenGLVersionMinor == 3)) : pCompiler->m_OpenGLVersionMajor >= 3);
38 std::string GLShaderStringPostfix = std::string(" core\r\n");
39 if(BackendType == BACKEND_TYPE_OPENGL_ES)
40 GLShaderStringPostfix = std::string(" es\r\n");
41 //add compiler specific values
42 if(IsNewOpenGL)
43 {
44 vLines.push_back(x: std::string("#version ") + std::string(std::to_string(val: pCompiler->m_OpenGLVersionMajor)) + std::string(std::to_string(val: pCompiler->m_OpenGLVersionMinor)) + std::string(std::to_string(val: pCompiler->m_OpenGLVersionPatch)) + GLShaderStringPostfix);
45 }
46 else
47 {
48 if(pCompiler->m_OpenGLVersionMajor == 3)
49 {
50 if(pCompiler->m_OpenGLVersionMinor == 0)
51 vLines.emplace_back(args: "#version 130 \r\n");
52 if(pCompiler->m_OpenGLVersionMinor == 1)
53 vLines.emplace_back(args: "#version 140 \r\n");
54 if(pCompiler->m_OpenGLVersionMinor == 2)
55 vLines.emplace_back(args: "#version 150 \r\n");
56 }
57 else if(pCompiler->m_OpenGLVersionMajor == 2)
58 {
59 if(pCompiler->m_OpenGLVersionMinor == 0)
60 vLines.emplace_back(args: "#version 110 \r\n");
61 if(pCompiler->m_OpenGLVersionMinor == 1)
62 vLines.emplace_back(args: "#version 120 \r\n");
63 }
64 }
65
66 if(BackendType == BACKEND_TYPE_OPENGL_ES)
67 {
68 if(Type == GL_FRAGMENT_SHADER)
69 {
70 vLines.emplace_back(args: "precision highp float; \r\n");
71 vLines.emplace_back(args: "precision highp sampler2D; \r\n");
72 vLines.emplace_back(args: "precision highp sampler3D; \r\n");
73 vLines.emplace_back(args: "precision highp samplerCube; \r\n");
74 vLines.emplace_back(args: "precision highp samplerCubeShadow; \r\n");
75 vLines.emplace_back(args: "precision highp sampler2DShadow; \r\n");
76 vLines.emplace_back(args: "precision highp sampler2DArray; \r\n");
77 vLines.emplace_back(args: "precision highp sampler2DArrayShadow; \r\n");
78 }
79 }
80
81 for(const CGLSLCompiler::SGLSLCompilerDefine &Define : pCompiler->m_vDefines)
82 {
83 vLines.push_back(x: std::string("#define ") + Define.m_DefineName + std::string(" ") + Define.m_DefineValue + std::string("\r\n"));
84 }
85
86 if(Type == GL_FRAGMENT_SHADER && !IsNewOpenGL && pCompiler->m_OpenGLVersionMajor <= 3 && pCompiler->m_HasTextureArray)
87 {
88 vLines.emplace_back(args: "#extension GL_EXT_texture_array : enable\r\n");
89 }
90
91 while(const char *pReadLine = LineReader.Get())
92 {
93 std::string Line;
94 pCompiler->ParseLine(Line, pReadLine, Type: Type == GL_FRAGMENT_SHADER ? GLSL_SHADER_COMPILER_TYPE_FRAGMENT : GLSL_SHADER_COMPILER_TYPE_VERTEX);
95 Line.append(s: "\r\n");
96 vLines.push_back(x: Line);
97 }
98
99 const char **ShaderCode = new const char *[vLines.size()];
100
101 for(size_t i = 0; i < vLines.size(); ++i)
102 {
103 ShaderCode[i] = vLines[i].c_str();
104 }
105
106 const TWGLuint ShaderId = glCreateShader(Type);
107
108 glShaderSource(ShaderId, vLines.size(), ShaderCode, nullptr);
109 glCompileShader(ShaderId);
110
111 delete[] ShaderCode;
112
113 TWGLint CompilationStatus;
114 glGetShaderiv(ShaderId, GL_COMPILE_STATUS, &CompilationStatus);
115
116 if(CompilationStatus == GL_FALSE)
117 {
118 TWGLint LogLength = 0;
119 glGetShaderiv(ShaderId, GL_INFO_LOG_LENGTH, &LogLength);
120 if(LogLength > 0)
121 {
122 std::string Log(LogLength, '\0');
123 glGetShaderInfoLog(ShaderId, Log.size(), nullptr, &Log.front());
124 if(Log[Log.size() - 2] == '\n')
125 {
126 Log[Log.size() - 2] = '\0';
127 }
128 log_error("gfx/opengl/shader", "Failed to compile shader file '%s'. The compiler returned:\n%s", pFile, Log.c_str());
129 }
130 else
131 {
132 log_error("gfx/opengl/shader", "Failed to compile shader file '%s'. The compiler did not return an error.", pFile);
133 }
134 glDeleteShader(ShaderId);
135 return false;
136 }
137
138 m_Type = Type;
139 m_IsLoaded = true;
140 m_ShaderId = ShaderId;
141 return true;
142}
143
144void CGLSL::DeleteShader()
145{
146 if(!IsLoaded())
147 return;
148 m_IsLoaded = false;
149 glDeleteShader(m_ShaderId);
150}
151
152bool CGLSL::IsLoaded() const
153{
154 return m_IsLoaded;
155}
156
157TWGLuint CGLSL::GetShaderId() const
158{
159 return m_ShaderId;
160}
161
162CGLSL::CGLSL()
163{
164 m_IsLoaded = false;
165}
166
167CGLSL::~CGLSL()
168{
169 DeleteShader();
170}
171
172#endif
173