blob: 8e5696a754b8f2498852633d79d09d26cdda940f [file] [log] [blame]
#include "ShaderParser.h"
#include <string.h>
ShaderParser::ShaderParser():ObjectData(SHADER_DATA),
m_type(0),
m_parsedLines(NULL) {
m_infoLog = new GLchar[1];
m_infoLog[0] = '\0';
};
ShaderParser::ShaderParser(GLenum type):ObjectData(SHADER_DATA),
m_type(type),
m_parsedLines(NULL) {
m_infoLog = new GLchar[1];
m_infoLog[0] = '\0';
};
void ShaderParser::setSrc(const Version& ver,GLsizei count,const GLchar** strings,const GLint* length){
for(int i = 0;i<count;i++){
m_src.append(strings[i]);
}
clearParsedSrc();
// parseGLSLversion must be called first since #version should be the
// first token in the shader source.
parseGLSLversion();
parseBuiltinConstants();
/*
version 1.30.10 is the first version of GLSL Language containing precision qualifiers
if the glsl version is less than 1.30.10 than we will use a shader parser which omits
all precision qualifiers from the shader source , otherwise we will use a shader parser
which set the default precisions to be the same as the default precisions of GLSL ES
*/
#if 0
if(ver < Version(1,30,10)){
parseOmitPrecision();
} else {
parseExtendDefaultPrecision();
}
#else
//XXX: Until proved otherwise, glsl doesn't know/use those precision macros, so we omit then
parseOmitPrecision();
#endif
parseOriginalSrc();
}
const GLchar** ShaderParser::parsedLines() {
m_parsedLines = (GLchar*)m_parsedSrc.c_str();
return const_cast<const GLchar**> (&m_parsedLines);
};
const char* ShaderParser::getOriginalSrc(){
return m_src.c_str();
}
void ShaderParser::parseOriginalSrc() {
m_parsedSrc+=m_src;
}
void ShaderParser::parseGLSLversion() {
//
// find in shader the #version token if exist.
// That token should be the first non-comment or blank token
//
const char *src = m_src.c_str();
const int minGLSLVersion = 120;
int glslVersion = minGLSLVersion;
enum {
PARSE_NONE,
PARSE_IN_C_COMMENT,
PARSE_IN_LINE_COMMENT
} parseState = PARSE_NONE;
const char *c = src;
while( c && *c != '\0') {
if (parseState == PARSE_IN_C_COMMENT) {
if (*c == '*' && *(c+1) == '/') {
parseState = PARSE_NONE;
c += 2;
}
else c++;
}
else if (parseState == PARSE_IN_LINE_COMMENT) {
if (*c == '\n') {
parseState = PARSE_NONE;
}
c++;
}
else if (*c == '/' && *(c+1) == '/') {
parseState = PARSE_IN_LINE_COMMENT;
c += 2;
}
else if (*c == '/' && *(c+1) == '*') {
parseState = PARSE_IN_C_COMMENT;
c += 2;
}
else if (*c == ' ' || *c == '\t' || *c == '\r' || *c == '\n') {
c++;
}
else {
//
// We have reached the first non-blank character outside
// a comment, this must be a #version token or else #version
// token does not exist in this shader source.
//
if (!strncmp(c,"#version",8)) {
int ver;
if (sscanf(c+8,"%d",&ver) == 1) {
//
// parsed version string correctly, blank out the
// version token from the source, we will add it later at
// the begining of the shader.
//
char *cc = (char *)c;
for (int i=0; i<8; i++,cc++) *cc = ' ';
while (*cc < '0' || *cc > '9') { *cc = ' '; cc++; }
while (*cc >= '0' && *cc <= '9') { *cc = ' '; cc++; }
// Use the version from the source but only if
// it is larger than our minGLSLVersion
if (ver > minGLSLVersion) glslVersion = ver;
}
}
//
// break the loop, no need to go further on the source.
break;
}
}
//
// allow to force GLSL version through environment variable
//
const char *forceVersion = getenv("GOOGLE_GLES_FORCE_GLSL_VERSION");
if (forceVersion) {
int ver;
if (sscanf(forceVersion,"%d",&ver) == 1) {
glslVersion = ver;
}
}
//
// if glslVersion is defined, add it to the parsed source
//
if (glslVersion > 0) {
char vstr[16];
sprintf(vstr,"%d",glslVersion);
m_parsedSrc += std::string("#version ") +
std::string(vstr) +
std::string("\n");
}
}
void ShaderParser::parseBuiltinConstants()
{
m_parsedSrc +=
"const int _translator_gl_MaxVertexUniformVectors = 256;\n"
"const int _translator_gl_MaxFragmentUniformVectors = 256;\n"
"const int _translator_gl_MaxVaryingVectors = 15;\n"
"#define gl_MaxVertexUniformVectors _translator_gl_MaxVertexUniformVectors\n"
"#define gl_MaxFragmentUniformVectors _translator_gl_MaxFragmentUniformVectors\n"
"#define gl_MaxVaryingVectors _translator_gl_MaxVaryingVectors\n";
}
void ShaderParser::parseOmitPrecision(){
//defines we need to add in order to Omit precisions qualifiers
static const GLchar defines[] = {
"#define GLES 1\n"
"#define lowp \n"
"#define mediump \n"
"#define highp \n"
"#define precision \n"
};
m_parsedSrc+=defines;
}
void ShaderParser::parseExtendDefaultPrecision(){
//the precision lines which we need to add to the shader
static const GLchar extend[] = {
"#define GLES 1\n"
"precision lowp sampler2D;\n"
"precision lowp samplerCube;\n"
};
m_parsedSrc+=extend;
}
void ShaderParser::clearParsedSrc(){
m_parsedSrc.clear();
}
GLenum ShaderParser::getType() {
return m_type;
}
void ShaderParser::setInfoLog(GLchar* infoLog)
{
delete[] m_infoLog;
m_infoLog = infoLog;
}
GLchar* ShaderParser::getInfoLog()
{
return m_infoLog;
}
ShaderParser::~ShaderParser(){
clearParsedSrc();
delete[] m_infoLog;
}