1 // ----------------------------------------------------------------------------
2 // -                        Open3D: www.open3d.org                            -
3 // ----------------------------------------------------------------------------
4 // The MIT License (MIT)
5 //
6 // Copyright (c) 2018 www.open3d.org
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
14 //
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 // IN THE SOFTWARE.
25 // ----------------------------------------------------------------------------
26 
27 #include "ShaderWrapper.h"
28 
29 #include <Core/Geometry/Geometry.h>
30 #include <Core/Utility/Console.h>
31 
32 namespace three{
33 
34 namespace glsl {
35 
Render(const Geometry & geometry,const RenderOption & option,const ViewControl & view)36 bool ShaderWrapper::Render(const Geometry &geometry, const RenderOption &option,
37         const ViewControl &view)
38 {
39     if (compiled_ == false) {
40         Compile();
41     }
42     if (bound_ == false) {
43         BindGeometry(geometry, option, view);
44     }
45     if (compiled_ == false || bound_ == false) {
46         PrintShaderWarning("Something is wrong in compiling or binding.");
47         return false;
48     }
49     return RenderGeometry(geometry, option, view);
50 }
51 
InvalidateGeometry()52 void ShaderWrapper::InvalidateGeometry()
53 {
54     if (bound_) {
55         UnbindGeometry();
56     }
57 }
58 
PrintShaderWarning(const std::string & message) const59 void ShaderWrapper::PrintShaderWarning(const std::string &message) const
60 {
61     PrintWarning("[%s] %s\n", GetShaderName().c_str(), message.c_str());
62 }
63 
CompileShaders(const char * const vertex_shader_code,const char * const geometry_shader_code,const char * const fragment_shader_code)64 bool ShaderWrapper::CompileShaders(
65         const char * const vertex_shader_code,
66         const char * const geometry_shader_code,
67         const char * const fragment_shader_code)
68 {
69     if (compiled_) {
70         return true;
71     }
72 
73     if (vertex_shader_code != NULL) {
74         vertex_shader_ = glCreateShader(GL_VERTEX_SHADER);
75         const GLchar *vertex_shader_code_buffer = vertex_shader_code;
76         glShaderSource(vertex_shader_, 1, &vertex_shader_code_buffer, NULL);
77         glCompileShader(vertex_shader_);
78         if (ValidateShader(vertex_shader_) == false) {
79             return false;
80         }
81     }
82 
83     if (geometry_shader_code != NULL) {
84         geometry_shader_ = glCreateShader(GL_GEOMETRY_SHADER);
85         const GLchar *geometry_shader_code_buffer = geometry_shader_code;
86         glShaderSource(geometry_shader_, 1, &geometry_shader_code_buffer, NULL);
87         glCompileShader(geometry_shader_);
88         if (ValidateShader(geometry_shader_) == false) {
89             return false;
90         }
91     }
92 
93     if (fragment_shader_code != NULL) {
94         fragment_shader_ = glCreateShader(GL_FRAGMENT_SHADER);
95         const GLchar *fragment_shader_code_buffer = fragment_shader_code;
96         glShaderSource(fragment_shader_, 1, &fragment_shader_code_buffer, NULL);
97         glCompileShader(fragment_shader_);
98         if (ValidateShader(fragment_shader_) == false) {
99             return false;
100         }
101     }
102 
103     program_ = glCreateProgram();
104     if (vertex_shader_code != NULL) {
105         glAttachShader(program_, vertex_shader_);
106     }
107     if (geometry_shader_code != NULL) {
108         glAttachShader(program_, geometry_shader_);
109     }
110     if (fragment_shader_code != NULL) {
111         glAttachShader(program_, fragment_shader_);
112     }
113     glLinkProgram(program_);
114     if (ValidateProgram(program_) == false) {
115         return false;
116     }
117 
118     // Mark shader objects as deletable.
119     // They will be released as soon as program is deleted.
120     if (vertex_shader_code != NULL) {
121         glDeleteShader(vertex_shader_);
122     }
123     if (geometry_shader_code != NULL) {
124         glDeleteShader(geometry_shader_);
125     }
126     if (fragment_shader_code != NULL) {
127         glDeleteShader(fragment_shader_);
128     }
129 
130     compiled_ = true;
131     return true;
132 }
133 
ReleaseProgram()134 void ShaderWrapper::ReleaseProgram()
135 {
136     if (compiled_) {
137         glDeleteProgram(program_);
138         compiled_ = false;
139     }
140 }
141 
ValidateShader(GLuint shader_index)142 bool ShaderWrapper::ValidateShader(GLuint shader_index)
143 {
144     GLint result = GL_FALSE;
145     int info_log_length;
146     glGetShaderiv(shader_index, GL_COMPILE_STATUS, &result);
147     if (result == GL_FALSE) {
148         glGetShaderiv(shader_index, GL_INFO_LOG_LENGTH, &info_log_length);
149         if (info_log_length > 0) {
150             std::vector<char> error_message(info_log_length + 1);
151             glGetShaderInfoLog(shader_index, info_log_length, NULL,
152                     &error_message[0]);
153             PrintError("Shader error: %s\n", &error_message[0]);
154         }
155         return false;
156     }
157     return true;
158 }
159 
ValidateProgram(GLuint program_index)160 bool ShaderWrapper::ValidateProgram(GLuint program_index)
161 {
162     GLint result = GL_FALSE;
163     int info_log_length;
164     glGetProgramiv(program_index, GL_LINK_STATUS, &result);
165     if (result == GL_FALSE) {
166         glGetProgramiv(program_index, GL_INFO_LOG_LENGTH, &info_log_length);
167         if (info_log_length > 0) {
168             std::vector<char> error_message(info_log_length + 1);
169             glGetShaderInfoLog(program_index, info_log_length, NULL,
170                     &error_message[0]);
171             PrintError("Shader error: %s\n", &error_message[0]);
172         }
173         return false;
174     }
175     return true;
176 }
177 
178 }    // namespace three::glsl
179 
180 }    // namespace three
181