1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "Shader.h"
17
18 #include <chrono>
19 #include <thread>
20
21 #include "AndroidOut.h"
22 #include "Model.h"
23 #include "Utility.h"
24 using namespace std::chrono_literals;
25
loadShader(const std::string & vertexSource,const std::string & fragmentSource,const std::string & positionAttributeName,const std::string & uvAttributeName,const std::string & projectionMatrixUniformName)26 Shader *Shader::loadShader(const std::string &vertexSource, const std::string &fragmentSource,
27 const std::string &positionAttributeName,
28 const std::string &uvAttributeName,
29 const std::string &projectionMatrixUniformName) {
30 Shader *shader = nullptr;
31
32 GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vertexSource);
33 if (!vertexShader) {
34 return nullptr;
35 }
36
37 GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentSource);
38 if (!fragmentShader) {
39 glDeleteShader(vertexShader);
40 return nullptr;
41 }
42
43 GLuint program = glCreateProgram();
44 if (program) {
45 aout << "Program created!" << std::endl;
46 glAttachShader(program, vertexShader);
47 glAttachShader(program, fragmentShader);
48
49 glLinkProgram(program);
50 GLint linkStatus = GL_FALSE;
51 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
52 if (linkStatus != GL_TRUE) {
53 GLint logLength = 0;
54 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
55
56 // If we fail to link the shader program, log the result for debugging
57 if (logLength) {
58 GLchar *log = new GLchar[logLength];
59 glGetProgramInfoLog(program, logLength, nullptr, log);
60 aout << "Failed to link program with:\n" << log << std::endl;
61 delete[] log;
62 }
63
64 glDeleteProgram(program);
65 } else {
66 // Get the attribute and uniform locations by name. You may also choose to hardcode
67 // indices with layout= in your shader, but it is not done in this sample
68 GLint positionAttribute = glGetAttribLocation(program, positionAttributeName.c_str());
69 GLint uvAttribute = glGetAttribLocation(program, uvAttributeName.c_str());
70 GLint projectionMatrixUniform =
71 glGetUniformLocation(program, projectionMatrixUniformName.c_str());
72
73 // Only create a new shader if all the attributes are found.
74 if (positionAttribute != -1 && uvAttribute != -1 && projectionMatrixUniform != -1) {
75 shader = new Shader(program, positionAttribute, uvAttribute,
76 projectionMatrixUniform);
77 } else {
78 glDeleteProgram(program);
79 }
80 }
81 }
82
83 // The shaders are no longer needed once the program is linked. Release their memory.
84 glDeleteShader(vertexShader);
85 glDeleteShader(fragmentShader);
86
87 return shader;
88 }
89
loadShader(GLenum shaderType,const std::string & shaderSource)90 GLuint Shader::loadShader(GLenum shaderType, const std::string &shaderSource) {
91 Utility::assertGlError();
92 GLuint shader = glCreateShader(shaderType);
93 if (shader) {
94 auto *shaderRawString = (GLchar *)shaderSource.c_str();
95 GLint shaderLength = shaderSource.length();
96 glShaderSource(shader, 1, &shaderRawString, &shaderLength);
97 glCompileShader(shader);
98
99 GLint shaderCompiled = 0;
100 glGetShaderiv(shader, GL_COMPILE_STATUS, &shaderCompiled);
101
102 // If the shader doesn't compile, log the result to the terminal for debugging
103 if (!shaderCompiled) {
104 GLint infoLength = 0;
105 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength);
106
107 if (infoLength) {
108 auto *infoLog = new GLchar[infoLength];
109 glGetShaderInfoLog(shader, infoLength, nullptr, infoLog);
110 aout << "Failed to compile with:\n" << infoLog << std::endl;
111 delete[] infoLog;
112 }
113
114 glDeleteShader(shader);
115 shader = 0;
116 }
117 }
118 return shader;
119 }
120
activate() const121 void Shader::activate() const {
122 glUseProgram(program_);
123 }
124
deactivate() const125 void Shader::deactivate() const {
126 glUseProgram(0);
127 }
128
drawModel(const Model & model) const129 void Shader::drawModel(const Model &model) const {
130 // The position attribute is 3 floats
131 glVertexAttribPointer(position_, // attrib
132 3, // elements
133 GL_FLOAT, // of type float
134 GL_FALSE, // don't normalize
135 sizeof(Vertex), // stride is Vertex bytes
136 model.getVertexData() // pull from the start of the vertex data
137 );
138 glEnableVertexAttribArray(position_);
139
140 // The uv attribute is 2 floats
141 glVertexAttribPointer(uv_, // attrib
142 2, // elements
143 GL_FLOAT, // of type float
144 GL_FALSE, // don't normalize
145 sizeof(Vertex), // stride is Vertex bytes
146 ((uint8_t *)model.getVertexData()) +
147 sizeof(Vector3) // offset Vector3 from the start
148 );
149 glEnableVertexAttribArray(uv_);
150
151 // Setup the texture
152 glActiveTexture(GL_TEXTURE0);
153 glBindTexture(GL_TEXTURE_2D, model.getTexture().getTextureID());
154
155 // Draw as indexed triangles
156 glDrawElements(GL_TRIANGLES, model.getIndexCount(), GL_UNSIGNED_SHORT, model.getIndexData());
157
158 glDisableVertexAttribArray(uv_);
159 glDisableVertexAttribArray(position_);
160 }
161
setProjectionMatrix(float * projectionMatrix) const162 void Shader::setProjectionMatrix(float *projectionMatrix) const {
163 glUniformMatrix4fv(projectionMatrix_, 1, false, projectionMatrix);
164 }