1 #include "ShaderParser.h" 2 #include <string.h> 3 4 ShaderParser::ShaderParser():ObjectData(SHADER_DATA), 5 m_type(0), 6 m_originalSrc(NULL), 7 m_parsedLines(NULL) { 8 m_infoLog = new GLchar[1]; 9 m_infoLog[0] = '\0'; 10 }; 11 12 ShaderParser::ShaderParser(GLenum type):ObjectData(SHADER_DATA), 13 m_type(type), 14 m_originalSrc(NULL), 15 m_parsedLines(NULL) { 16 17 m_infoLog = new GLchar[1]; 18 m_infoLog[0] = '\0'; 19 }; 20 21 void ShaderParser::setSrc(const Version& ver,GLsizei count,const GLchar** strings,const GLint* length){ 22 for(int i = 0;i<count;i++){ 23 m_src.append(strings[i]); 24 } 25 //store original source 26 if (m_originalSrc) 27 free(m_originalSrc); 28 m_originalSrc = strdup(m_src.c_str()); 29 30 clearParsedSrc(); 31 32 // parseGLSLversion must be called first since #version should be the 33 // first token in the shader source. 34 parseGLSLversion(); 35 parseBuiltinConstants(); 36 /* 37 version 1.30.10 is the first version of GLSL Language containing precision qualifiers 38 if the glsl version is less than 1.30.10 than we will use a shader parser which omits 39 all precision qualifiers from the shader source , otherwise we will use a shader parser 40 which set the default precisions to be the same as the default precisions of GLSL ES 41 */ 42 #if 0 43 if(ver < Version(1,30,10)){ 44 parseOmitPrecision(); 45 } else { 46 parseExtendDefaultPrecision(); 47 } 48 #else 49 //XXX: Until proved otherwise, glsl doesn't know/use those precision macros, so we omit then 50 parseOmitPrecision(); 51 #endif 52 parseLineNumbers(); 53 parseOriginalSrc(); 54 } 55 const GLchar** ShaderParser::parsedLines() { 56 m_parsedLines = (GLchar*)m_parsedSrc.c_str(); 57 return const_cast<const GLchar**> (&m_parsedLines); 58 }; 59 60 const char* ShaderParser::getOriginalSrc(){ 61 return m_originalSrc; 62 } 63 64 void ShaderParser::parseLineNumbers() 65 { 66 m_parsedSrc += "#line 1\n"; 67 } 68 69 void ShaderParser::parseOriginalSrc() { 70 m_parsedSrc+=m_src; 71 } 72 73 void ShaderParser::parseGLSLversion() { 74 75 // 76 // find in shader the #version token if exist. 77 // That token should be the first non-comment or blank token 78 // 79 const char *src = m_src.c_str(); 80 const int minGLSLVersion = 120; 81 int glslVersion = minGLSLVersion; 82 enum { 83 PARSE_NONE, 84 PARSE_IN_C_COMMENT, 85 PARSE_IN_LINE_COMMENT 86 } parseState = PARSE_NONE; 87 const char *c = src; 88 89 while( c && *c != '\0') { 90 if (parseState == PARSE_IN_C_COMMENT) { 91 if (*c == '*' && *(c+1) == '/') { 92 parseState = PARSE_NONE; 93 c += 2; 94 } 95 else c++; 96 } 97 else if (parseState == PARSE_IN_LINE_COMMENT) { 98 if (*c == '\n') { 99 parseState = PARSE_NONE; 100 } 101 c++; 102 } 103 else if (*c == '/' && *(c+1) == '/') { 104 parseState = PARSE_IN_LINE_COMMENT; 105 c += 2; 106 } 107 else if (*c == '/' && *(c+1) == '*') { 108 parseState = PARSE_IN_C_COMMENT; 109 c += 2; 110 } 111 else if (*c == ' ' || *c == '\t' || *c == '\r' || *c == '\n') { 112 c++; 113 } 114 else { 115 // 116 // We have reached the first non-blank character outside 117 // a comment, this must be a #version token or else #version 118 // token does not exist in this shader source. 119 // 120 if (!strncmp(c,"#version",8)) { 121 int ver; 122 if (sscanf(c+8,"%d",&ver) == 1) { 123 // 124 // parsed version string correctly, blank out the 125 // version token from the source, we will add it later at 126 // the begining of the shader. 127 // 128 char *cc = (char *)c; 129 for (int i=0; i<8; i++,cc++) *cc = ' '; 130 while (*cc < '0' || *cc > '9') { *cc = ' '; cc++; } 131 while (*cc >= '0' && *cc <= '9') { *cc = ' '; cc++; } 132 133 // Use the version from the source but only if 134 // it is larger than our minGLSLVersion 135 if (ver > minGLSLVersion) glslVersion = ver; 136 } 137 } 138 139 // 140 // break the loop, no need to go further on the source. 141 break; 142 } 143 } 144 145 // 146 // allow to force GLSL version through environment variable 147 // 148 const char *forceVersion = getenv("GOOGLE_GLES_FORCE_GLSL_VERSION"); 149 if (forceVersion) { 150 int ver; 151 if (sscanf(forceVersion,"%d",&ver) == 1) { 152 glslVersion = ver; 153 } 154 } 155 156 // 157 // if glslVersion is defined, add it to the parsed source 158 // 159 if (glslVersion > 0) { 160 char vstr[16]; 161 sprintf(vstr,"%d",glslVersion); 162 m_parsedSrc += std::string("#version ") + 163 std::string(vstr) + 164 std::string("\n"); 165 } 166 } 167 168 void ShaderParser::parseBuiltinConstants() 169 { 170 m_parsedSrc += 171 "const int _translator_gl_MaxVertexUniformVectors = 256;\n" 172 "const int _translator_gl_MaxFragmentUniformVectors = 256;\n" 173 "const int _translator_gl_MaxVaryingVectors = 15;\n" 174 "#define gl_MaxVertexUniformVectors _translator_gl_MaxVertexUniformVectors\n" 175 "#define gl_MaxFragmentUniformVectors _translator_gl_MaxFragmentUniformVectors\n" 176 "#define gl_MaxVaryingVectors _translator_gl_MaxVaryingVectors\n"; 177 178 } 179 180 void ShaderParser::parseOmitPrecision(){ 181 182 //defines we need to add in order to Omit precisions qualifiers 183 static const GLchar defines[] = { 184 "#define GLES 1\n" 185 "#define lowp \n" 186 "#define mediump \n" 187 "#define highp \n" 188 }; 189 m_parsedSrc+=defines; 190 191 // 192 // parse the source and blank out precision statements 193 // which has the following syntax: 194 // precision {qualifier} {type}; 195 // where {qualifier} is one of lowp,mediump or hightp 196 // type is any valid GLES defined type (we do not check that here!) 197 // NOTE: This is needed in order to workaround driver bug in 198 // Intel/Linux where the compiler does not get statement like 199 // "float;", otherwise we could just define a macro named 200 // precision to be empty. 201 // 202 const char *src = m_src.c_str(); 203 204 enum { 205 PRECISION, 206 QUALIFIER, 207 SEMICOLON 208 } statementState = PRECISION; 209 const char *precision = NULL; 210 const char *delimiter = NULL; 211 212 enum { 213 PARSE_NONE, 214 PARSE_IN_C_COMMENT, 215 PARSE_IN_LINE_COMMENT 216 } parseState = PARSE_NONE; 217 const char *c = src; 218 const char *t = NULL; 219 220 #define IS_DELIMITER(c) ( (c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n' ) 221 #define IS_TOKEN_START(c) ( ((c) >= 'a' && (c) <='z') || ((c) >= 'A' && (c) <= 'Z') ) 222 #define IS_TOKEN_DELIMITER(c) ( IS_DELIMITER(c) || (c) == ';' ) 223 224 while( c && *c != '\0') { 225 if (parseState == PARSE_IN_C_COMMENT) { 226 if (*c == '*' && *(c+1) == '/') { 227 parseState = PARSE_NONE; 228 c += 2; 229 } 230 else c++; 231 } 232 else if (parseState == PARSE_IN_LINE_COMMENT) { 233 if (*c == '\n') { 234 parseState = PARSE_NONE; 235 } 236 c++; 237 } 238 else if (*c == '/' && *(c+1) == '/') { 239 parseState = PARSE_IN_LINE_COMMENT; 240 c += 2; 241 } 242 else if (*c == '/' && *(c+1) == '*') { 243 parseState = PARSE_IN_C_COMMENT; 244 c += 2; 245 } 246 else if (t && IS_TOKEN_DELIMITER(*c)) { 247 int tokenLen = c - t; 248 switch (statementState) { 249 case PRECISION: 250 if (tokenLen == 9 && !strncmp(t,"precision",9)) { 251 statementState = QUALIFIER; 252 precision = t; 253 } 254 break; 255 case QUALIFIER: 256 if ((tokenLen == 4 && !strncmp(t,"lowp",4)) || 257 (tokenLen == 7 && !strncmp(t,"mediump",7)) || 258 (tokenLen == 5 && !strncmp(t,"highp",5))) { 259 statementState = SEMICOLON; 260 } 261 else { 262 statementState = PRECISION; 263 } 264 break; 265 case SEMICOLON: 266 if (*c == ';') { 267 for (char *r = (char *)precision; r<=c ; ++r) { 268 *r = ' '; //blank the character 269 } 270 } 271 statementState = PRECISION; //search for the next precision line 272 break; 273 default: 274 break; 275 } 276 c++; 277 t = NULL; 278 } 279 else if (IS_DELIMITER(*c)) { 280 c++; 281 } 282 else { 283 if (!t && IS_TOKEN_START(*c)) { 284 t = c; 285 } 286 c++; 287 } 288 } 289 } 290 291 void ShaderParser::parseExtendDefaultPrecision(){ 292 293 //the precision lines which we need to add to the shader 294 static const GLchar extend[] = { 295 "#define GLES 1\n" 296 "precision lowp sampler2D;\n" 297 "precision lowp samplerCube;\n" 298 }; 299 300 m_parsedSrc+=extend; 301 } 302 303 void ShaderParser::clearParsedSrc(){ 304 m_parsedSrc.clear(); 305 } 306 307 GLenum ShaderParser::getType() { 308 return m_type; 309 } 310 311 void ShaderParser::setInfoLog(GLchar* infoLog) 312 { 313 delete[] m_infoLog; 314 m_infoLog = infoLog; 315 } 316 317 GLchar* ShaderParser::getInfoLog() 318 { 319 return m_infoLog; 320 } 321 322 ShaderParser::~ShaderParser(){ 323 clearParsedSrc(); 324 if (m_originalSrc) 325 free(m_originalSrc); 326 delete[] m_infoLog; 327 } 328