1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Adapted from the javascript implementation upon WebGL by kwaters@.
6 
7 #include "shader.h"
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 
12 #include "shadersrc.h"
13 
14 #undef IMPORTGL_API
15 #undef IMPORTGL_FNPTRINIT
16 #include "importgl.h"
17 
18 
19 SHADERLIT sShaderLit;
20 SHADERFLAT sShaderFlat;
21 SHADERFADE sShaderFade;
22 
23 Matrix4x4 sModelView;
24 Matrix4x4 sProjection;
25 
26 
printShaderLog(GLuint shader)27 static void printShaderLog(GLuint shader)
28 {
29     int infoLogSize, infoWritten;
30     char *infoLog;
31     glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogSize);
32     infoLog = malloc(infoLogSize);
33     glGetShaderInfoLog(shader, infoLogSize, &infoWritten, infoLog);
34     fprintf(stderr, "Error: glCompileShader failed: %s\n", infoLog);
35     free(infoLog);
36 }
37 
38 
createShader(const char * src,GLenum shaderType)39 static GLuint createShader(const char *src, GLenum shaderType)
40 {
41     GLint bShaderCompiled;
42     GLuint shader = glCreateShader(shaderType);
43     if (shader == 0)
44         return 0;
45     glShaderSource(shader, 1, &src, NULL);
46     glCompileShader(shader);
47     glGetShaderiv(shader, GL_COMPILE_STATUS, &bShaderCompiled);
48     if (!bShaderCompiled)
49     {
50         printShaderLog(shader);
51         glDeleteShader(shader);
52         return 0;
53     }
54     return shader;
55 }
56 
57 
createProgram(const char * srcVertex,const char * srcFragment)58 static GLuint createProgram(const char *srcVertex, const char * srcFragment)
59 {
60     GLuint program = glCreateProgram();
61     if (program == 0)
62         return 0;
63 
64     GLuint shaderVertex = createShader(srcVertex, GL_VERTEX_SHADER);
65     if (shaderVertex == 0)
66     {
67         glDeleteProgram(program);
68         return 0;
69     }
70     glAttachShader(program, shaderVertex);
71     glDeleteShader(shaderVertex);
72 
73     GLuint shaderFragment = createShader(srcFragment, GL_FRAGMENT_SHADER);
74     if (shaderFragment == 0)
75     {
76         glDeleteProgram(program);
77         return 0;
78     }
79     glAttachShader(program, shaderFragment);
80     glDeleteShader(shaderFragment);
81 
82     glLinkProgram(program);
83     return program;
84 }
85 
86 
computeNormalMatrix(Matrix4x4 m,Matrix3x3 normal)87 static void computeNormalMatrix(Matrix4x4 m, Matrix3x3 normal)
88 {
89     float det = m[0*4+0] * (m[1*4+1] * m[2*4+2] - m[2*4+1] * m[1*4+2]) -
90                 m[0*4+1] * (m[1*4+0] * m[2*4+2] - m[1*4+2] * m[2*4+0]) +
91                 m[0*4+2] * (m[1*4+0] * m[2*4+1] - m[1*4+1] * m[2*4+0]);
92     float invDet = 1.f / det;
93     normal[0*3+0] = invDet * (m[1*4+1] * m[2*4+2] - m[2*4+1] * m[1*4+2]);
94     normal[1*3+0] = invDet * -(m[0*4+1] * m[2*4+2] - m[0*4+2] * m[2*4+1]);
95     normal[2*3+0] = invDet * (m[0*4+1] * m[1*4+2] - m[0*4+2] * m[1*4+1]);
96     normal[0*3+1] = invDet * -(m[1*4+0] * m[2*4+2] - m[1*4+2] * m[2*4+0]);
97     normal[1*3+1] = invDet * (m[0*4+0] * m[2*4+2] - m[0*4+2] * m[2*4+0]);
98     normal[2*3+1] = invDet * -(m[0*4+0] * m[1*4+2] - m[1*4+0] * m[0*4+2]);
99     normal[0*3+2] = invDet * (m[1*4+0] * m[2*4+1] - m[2*4+0] * m[1*4+1]);
100     normal[1*3+2] = invDet * -(m[0*4+0] * m[2*4+1] - m[2*4+0] * m[0*4+1]);
101     normal[2*3+2] = invDet * (m[0*4+0] * m[1*4+1] - m[1*4+0] * m[0*4+1]);
102 }
103 
104 
getLocations()105 static int getLocations()
106 {
107     int rt = 1;
108 #define GET_ATTRIBUTE_LOC(programName, varName) \
109         sShader##programName.varName = \
110         glGetAttribLocation(sShader##programName.program, #varName); \
111         if (sShader##programName.varName == -1) rt = 0
112 #define GET_UNIFORM_LOC(programName, varName) \
113         sShader##programName.varName = \
114         glGetUniformLocation(sShader##programName.program, #varName); \
115         if (sShader##programName.varName == -1) rt = 0
116     GET_ATTRIBUTE_LOC(Lit, pos);
117     GET_ATTRIBUTE_LOC(Lit, normal);
118     GET_ATTRIBUTE_LOC(Lit, colorIn);
119     GET_UNIFORM_LOC(Lit, mvp);
120     GET_UNIFORM_LOC(Lit, normalMatrix);
121     GET_UNIFORM_LOC(Lit, ambient);
122     GET_UNIFORM_LOC(Lit, shininess);
123     GET_UNIFORM_LOC(Lit, light_0_direction);
124     GET_UNIFORM_LOC(Lit, light_0_diffuse);
125     GET_UNIFORM_LOC(Lit, light_0_specular);
126     GET_UNIFORM_LOC(Lit, light_1_direction);
127     GET_UNIFORM_LOC(Lit, light_1_diffuse);
128     GET_UNIFORM_LOC(Lit, light_2_direction);
129     GET_UNIFORM_LOC(Lit, light_2_diffuse);
130 
131     GET_ATTRIBUTE_LOC(Flat, pos);
132     GET_ATTRIBUTE_LOC(Flat, colorIn);
133     GET_UNIFORM_LOC(Flat, mvp);
134 
135     GET_ATTRIBUTE_LOC(Fade, pos);
136     GET_UNIFORM_LOC(Fade, minFade);
137 #undef GET_ATTRIBUTE_LOC
138 #undef GET_UNIFORM_LOC
139     return rt;
140 }
141 
142 
initShaderPrograms()143 int initShaderPrograms()
144 {
145     Matrix4x4_LoadIdentity(sModelView);
146     Matrix4x4_LoadIdentity(sProjection);
147 
148     sShaderFlat.program = createProgram(sFlatVertexSource,
149                                         sFlatFragmentSource);
150     sShaderLit.program = createProgram(sLitVertexSource,
151                                        sFlatFragmentSource);
152     sShaderFade.program = createProgram(sFadeVertexSource,
153                                         sFlatFragmentSource);
154     if (sShaderFlat.program == 0 || sShaderLit.program == 0 ||
155         sShaderFade.program == 0)
156         return 0;
157 
158     return getLocations();
159 }
160 
161 
deInitShaderPrograms()162 void deInitShaderPrograms()
163 {
164     glDeleteProgram(sShaderFlat.program);
165     glDeleteProgram(sShaderLit.program);
166     glDeleteProgram(sShaderFade.program);
167 }
168 
169 
bindShaderProgram(GLuint program)170 void bindShaderProgram(GLuint program)
171 {
172     int loc_mvp = -1;
173     int loc_normalMatrix = -1;
174 
175     glUseProgram(program);
176 
177     if (program == sShaderLit.program)
178     {
179         loc_mvp = sShaderLit.mvp;
180         loc_normalMatrix = sShaderLit.normalMatrix;
181     }
182     else if (program == sShaderFlat.program)
183     {
184         loc_mvp = sShaderFlat.mvp;
185     }
186 
187     if (loc_mvp != -1)
188     {
189         Matrix4x4 mvp;
190         Matrix4x4_Multiply(mvp, sModelView, sProjection);
191         glUniformMatrix4fv(loc_mvp, 1, GL_FALSE, (GLfloat *)mvp);
192     }
193     if (loc_normalMatrix != -1)
194     {
195         Matrix3x3 normalMatrix;
196         computeNormalMatrix(sModelView, normalMatrix);
197         glUniformMatrix3fv(loc_normalMatrix, 1, GL_FALSE,
198                            (GLfloat *)normalMatrix);
199     }
200 }
201 
202