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 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);
44 else
45 {
46 if(pCompiler->m_OpenGLVersionMajor == 3)
47 {
48 if(pCompiler->m_OpenGLVersionMinor == 0)
49 vLines.emplace_back(args: "#version 130 \r\n");
50 if(pCompiler->m_OpenGLVersionMinor == 1)
51 vLines.emplace_back(args: "#version 140 \r\n");
52 if(pCompiler->m_OpenGLVersionMinor == 2)
53 vLines.emplace_back(args: "#version 150 \r\n");
54 }
55 else if(pCompiler->m_OpenGLVersionMajor == 2)
56 {
57 if(pCompiler->m_OpenGLVersionMinor == 0)
58 vLines.emplace_back(args: "#version 110 \r\n");
59 if(pCompiler->m_OpenGLVersionMinor == 1)
60 vLines.emplace_back(args: "#version 120 \r\n");
61 }
62 }
63
64 if(BackendType == BACKEND_TYPE_OPENGL_ES)
65 {
66 if(Type == GL_FRAGMENT_SHADER)
67 {
68 vLines.emplace_back(args: "precision highp float; \r\n");
69 vLines.emplace_back(args: "precision highp sampler2D; \r\n");
70 vLines.emplace_back(args: "precision highp sampler3D; \r\n");
71 vLines.emplace_back(args: "precision highp samplerCube; \r\n");
72 vLines.emplace_back(args: "precision highp samplerCubeShadow; \r\n");
73 vLines.emplace_back(args: "precision highp sampler2DShadow; \r\n");
74 vLines.emplace_back(args: "precision highp sampler2DArray; \r\n");
75 vLines.emplace_back(args: "precision highp sampler2DArrayShadow; \r\n");
76 }
77 }
78
79 for(const CGLSLCompiler::SGLSLCompilerDefine &Define : pCompiler->m_vDefines)
80 {
81 vLines.push_back(x: std::string("#define ") + Define.m_DefineName + std::string(" ") + Define.m_DefineValue + std::string("\r\n"));
82 }
83
84 if(Type == GL_FRAGMENT_SHADER && !IsNewOpenGL && pCompiler->m_OpenGLVersionMajor <= 3 && pCompiler->m_HasTextureArray)
85 {
86 vLines.emplace_back(args: "#extension GL_EXT_texture_array : enable\r\n");
87 }
88
89 while(const char *pReadLine = LineReader.Get())
90 {
91 std::string Line;
92 pCompiler->ParseLine(Line, pReadLine, Type: Type == GL_FRAGMENT_SHADER ? GLSL_SHADER_COMPILER_TYPE_FRAGMENT : GLSL_SHADER_COMPILER_TYPE_VERTEX);
93 Line.append(s: "\r\n");
94 vLines.push_back(x: Line);
95 }
96
97 const char **ShaderCode = new const char *[vLines.size()];
98
99 for(size_t i = 0; i < vLines.size(); ++i)
100 {
101 ShaderCode[i] = vLines[i].c_str();
102 }
103
104 const TWGLuint ShaderId = glCreateShader(Type);
105
106 glShaderSource(ShaderId, vLines.size(), ShaderCode, NULL);
107 glCompileShader(ShaderId);
108
109 delete[] ShaderCode;
110
111 TWGLint CompilationStatus;
112 glGetShaderiv(ShaderId, GL_COMPILE_STATUS, &CompilationStatus);
113
114 if(CompilationStatus == GL_FALSE)
115 {
116 TWGLint LogLength = 0;
117 glGetShaderiv(ShaderId, GL_INFO_LOG_LENGTH, &LogLength);
118 if(LogLength > 0)
119 {
120 std::string Log(LogLength, '\0');
121 glGetShaderInfoLog(ShaderId, Log.size(), nullptr, &Log.front());
122 if(Log[Log.size() - 2] == '\n')
123 {
124 Log[Log.size() - 2] = '\0';
125 }
126 log_error("gfx/opengl/shader", "Failed to compile shader file '%s'. The compiler returned:\n%s", pFile, Log.c_str());
127 }
128 else
129 {
130 log_error("gfx/opengl/shader", "Failed to compile shader file '%s'. The compiler did not return an error.", pFile);
131 }
132 glDeleteShader(ShaderId);
133 return false;
134 }
135
136 m_Type = Type;
137 m_IsLoaded = true;
138 m_ShaderId = ShaderId;
139 return true;
140}
141
142void CGLSL::DeleteShader()
143{
144 if(!IsLoaded())
145 return;
146 m_IsLoaded = false;
147 glDeleteShader(m_ShaderId);
148}
149
150bool CGLSL::IsLoaded() const
151{
152 return m_IsLoaded;
153}
154
155TWGLuint CGLSL::GetShaderId() const
156{
157 return m_ShaderId;
158}
159
160CGLSL::CGLSL()
161{
162 m_IsLoaded = false;
163}
164
165CGLSL::~CGLSL()
166{
167 DeleteShader();
168}
169
170#endif
171