This is another big commit - chief new features are:

* Working OpenGL ES 2.x support. Yay!
 * The shader code now supports separate vertex/fragment/geometry shaders.
 * The GLSL code supports passing vertex attrib arrays.
This commit is contained in:
rdb 2009-07-02 15:01:36 +00:00
parent 44bcbe3de6
commit 66349ecaba
7 changed files with 525 additions and 248 deletions

View File

@ -107,6 +107,23 @@ static void APIENTRY
null_glBlendColor(GLclampf, GLclampf, GLclampf, GLclampf) { null_glBlendColor(GLclampf, GLclampf, GLclampf, GLclampf) {
} }
#ifdef OPENGLES_2
// We have a default shader that will be applied when there
// isn't any shader applied (e.g. if it failed to compile).
// We need this because OpenGL ES 2.x does not have
// a fixed-function pipeline.
// This default shader just outputs a red color, telling
// the user that something went wrong.
CPT(Shader::ShaderFile) default_shader_name = new Shader::ShaderFile("default-shader");
CPT(Shader::ShaderFile) default_shader_body = new Shader::ShaderFile("\
uniform mediump mat4 p3d_ModelViewProjectionMatrix;\
attribute highp vec4 p3d_Vertex;\
void main(void) {\
gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;\ }\n",
"void main(void) {\
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\
}\n");
#endif
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: uchar_bgr_to_rgb // Function: uchar_bgr_to_rgb
@ -817,12 +834,12 @@ reset() {
if (basic_shaders_only) { if (basic_shaders_only) {
_shader_caps._active_vprofile = (int)CG_PROFILE_ARBVP1; _shader_caps._active_vprofile = (int)CG_PROFILE_ARBVP1;
_shader_caps._active_fprofile = (int)CG_PROFILE_ARBFP1; _shader_caps._active_fprofile = (int)CG_PROFILE_ARBFP1;
_shader_caps._active_gprofile = (int)0; // CG2 CHANGE: No geometry shader if only using basic _shader_caps._active_gprofile = (int)0; // No geometry shader if only using basic
} else { } else {
_shader_caps._active_vprofile = (int)cgGLGetLatestProfile(CG_GL_VERTEX); _shader_caps._active_vprofile = (int)cgGLGetLatestProfile(CG_GL_VERTEX);
_shader_caps._active_fprofile = (int)cgGLGetLatestProfile(CG_GL_FRAGMENT); _shader_caps._active_fprofile = (int)cgGLGetLatestProfile(CG_GL_FRAGMENT);
#ifdef CG_CL_GEOMETRY #ifdef CG_CL_GEOMETRY
_shader_caps._active_gprofile = (int)cgGLGetLatestProfile(CG_GL_GEOMETRY); // CG2 CHANGE _shader_caps._active_gprofile = (int)cgGLGetLatestProfile(CG_GL_GEOMETRY);
#else #else
_shader_caps._active_gprofile = (int)0; _shader_caps._active_gprofile = (int)0;
#endif #endif
@ -830,7 +847,7 @@ reset() {
_shader_caps._ultimate_vprofile = (int)CG_PROFILE_VP40; _shader_caps._ultimate_vprofile = (int)CG_PROFILE_VP40;
_shader_caps._ultimate_fprofile = (int)CG_PROFILE_FP40; _shader_caps._ultimate_fprofile = (int)CG_PROFILE_FP40;
#ifdef CG_PROFILE_GPU_CP #ifdef CG_PROFILE_GPU_CP
_shader_caps._ultimate_gprofile = (int)CG_PROFILE_GPU_GP; // CG2 CHANGE _shader_caps._ultimate_gprofile = (int)CG_PROFILE_GPU_GP;
#else #else
_shader_caps._ultimate_gprofile = (int)0; _shader_caps._ultimate_gprofile = (int)0;
#endif #endif
@ -862,10 +879,12 @@ reset() {
#endif #endif
_shader_caps._supports_glsl = _supports_glsl; _shader_caps._supports_glsl = _supports_glsl;
#ifndef OPENGLES_1 #ifndef OPENGLES
if (_supports_glsl) { if (_supports_glsl) {
_glAttachShader = (PFNGLATTACHSHADERPROC) _glAttachShader = (PFNGLATTACHSHADERPROC)
get_extension_func(GLPREFIX_QUOTED, "AttachShader"); get_extension_func(GLPREFIX_QUOTED, "AttachShader");
_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)
get_extension_func(GLPREFIX_QUOTED, "BindAttribLocation");
_glCompileShader = (PFNGLCOMPILESHADERPROC) _glCompileShader = (PFNGLCOMPILESHADERPROC)
get_extension_func(GLPREFIX_QUOTED, "CompileShader"); get_extension_func(GLPREFIX_QUOTED, "CompileShader");
_glCreateProgram = (PFNGLCREATEPROGRAMPROC) _glCreateProgram = (PFNGLCREATEPROGRAMPROC)
@ -878,8 +897,16 @@ reset() {
get_extension_func(GLPREFIX_QUOTED, "DeleteShader"); get_extension_func(GLPREFIX_QUOTED, "DeleteShader");
_glDetachShader = (PFNGLDETACHSHADERPROC) _glDetachShader = (PFNGLDETACHSHADERPROC)
get_extension_func(GLPREFIX_QUOTED, "DetachShader"); get_extension_func(GLPREFIX_QUOTED, "DetachShader");
_glDisableVertexAttribArray (PFNGLDISABLEVERTEXATTRIBARRAYPROC)
get_extension_func(GLPREFIX_QUOTED, "DisableVertexAttribArray");
_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)
get_extension_func(GLPREFIX_QUOTED, "EnableVertexAttribArray");
_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)
get_extension_func(GLPREFIX_QUOTED, "GetActiveAttrib");
_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) _glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)
get_extension_func(GLPREFIX_QUOTED, "GetActiveUniform"); get_extension_func(GLPREFIX_QUOTED, "GetActiveUniform");
_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)
get_extension_func(GLPREFIX_QUOTED, "GetAttribLocation");
_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) _glGetProgramiv = (PFNGLGETPROGRAMIVPROC)
get_extension_func(GLPREFIX_QUOTED, "GetProgramiv"); get_extension_func(GLPREFIX_QUOTED, "GetProgramiv");
_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) _glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)
@ -912,9 +939,50 @@ reset() {
get_extension_func(GLPREFIX_QUOTED, "UniformMatrix4fv"); get_extension_func(GLPREFIX_QUOTED, "UniformMatrix4fv");
_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) _glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)
get_extension_func(GLPREFIX_QUOTED, "ValidateProgram"); get_extension_func(GLPREFIX_QUOTED, "ValidateProgram");
_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)
get_extension_func(GLPREFIX_QUOTED, "VertexAttribPointer");
} }
#endif #endif
#ifdef OPENGLES_2
_glAttachShader = glAttachShader;
_glBindAttribLocation = glBindAttribLocation;
_glCompileShader = glCompileShader;
_glCreateProgram = glCreateProgram;
_glCreateShader = glCreateShader;
_glDeleteProgram = glDeleteProgram;
_glDeleteShader = glDeleteShader;
_glDetachShader = glDetachShader;
_glDisableVertexAttribArray = glDisableVertexAttribArray;
_glEnableVertexAttribArray = glEnableVertexAttribArray;
_glGetActiveAttrib = glGetActiveAttrib;
_glGetActiveUniform = glGetActiveUniform;
_glGetAttribLocation = glGetAttribLocation;
_glGetProgramiv = glGetProgramiv;
_glGetProgramInfoLog = glGetProgramInfoLog;
_glGetShaderiv = glGetShaderiv;
_glGetShaderInfoLog = glGetShaderInfoLog;
_glGetUniformLocation = glGetUniformLocation;
_glLinkProgram = glLinkProgram;
_glShaderSource = glShaderSource;
_glUseProgram = glUseProgram;
_glUniform4f = glUniform4f;
_glUniform1i = glUniform1i;
_glUniform1fv = glUniform1fv;
_glUniform2fv = glUniform2fv;
_glUniform3fv = glUniform3fv;
_glUniform4fv = glUniform4fv;
_glUniformMatrix4fv = glUniformMatrix4fv;
_glValidateProgram = glValidateProgram;
_glVertexAttribPointer = glVertexAttribPointer;
// We need to have a default shader to apply in case
// something didn't happen to have a shader applied, or
// if it failed to compile. This default shader just outputs
// a red color, indicating that something went wrong.
_default_shader = new Shader(default_shader_name, default_shader_body, Shader::SL_GLSL);
#endif
#ifdef OPENGLES_2 #ifdef OPENGLES_2
// In OpenGL ES 2.x, FBO's are supported in the core. // In OpenGL ES 2.x, FBO's are supported in the core.
_supports_framebuffer_object = true; _supports_framebuffer_object = true;
@ -1123,6 +1191,10 @@ reset() {
} }
#endif #endif
#ifdef OPENGLES_2
// In OpenGL ES 2.x, this is supported in the core.
_glBlendEquation = glBlendEquation;
#else
_glBlendEquation = NULL; _glBlendEquation = NULL;
bool supports_blend_equation = false; bool supports_blend_equation = false;
if (is_at_least_gl_version(1, 2)) { if (is_at_least_gl_version(1, 2)) {
@ -1145,7 +1217,12 @@ reset() {
if (_glBlendEquation == NULL) { if (_glBlendEquation == NULL) {
_glBlendEquation = null_glBlendEquation; _glBlendEquation = null_glBlendEquation;
} }
#endif
#ifdef OPENGLES_2
// In OpenGL ES 2.x, this is supported in the core.
_glBlendColor = glBlendColor;
#else
_glBlendColor = NULL; _glBlendColor = NULL;
bool supports_blend_color = false; bool supports_blend_color = false;
if (is_at_least_gl_version(1, 2)) { if (is_at_least_gl_version(1, 2)) {
@ -1164,6 +1241,7 @@ reset() {
if (_glBlendColor == NULL) { if (_glBlendColor == NULL) {
_glBlendColor = null_glBlendColor; _glBlendColor = null_glBlendColor;
} }
#endif
#ifdef OPENGLES #ifdef OPENGLES
_edge_clamp = GL_CLAMP_TO_EDGE; _edge_clamp = GL_CLAMP_TO_EDGE;
@ -4051,15 +4129,29 @@ do_issue_shade_model() {
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void CLP(GraphicsStateGuardian):: void CLP(GraphicsStateGuardian)::
do_issue_shader() { do_issue_shader(bool state_has_changed) {
#ifndef OPENGLES_1 #ifndef OPENGLES_1
CLP(ShaderContext) *context = 0; CLP(ShaderContext) *context = 0;
Shader *shader = (Shader *)(_target_shader->get_shader()); Shader *shader = (Shader *)(_target_shader->get_shader());
#ifdef OPENGLES_2
// If we don't have a shader, apply the default shader.
if (!shader) {
shader = _default_shader;
}
#endif
if (shader) { if (shader) {
context = (CLP(ShaderContext) *)(shader->prepare_now(get_prepared_objects(), this)); context = (CLP(ShaderContext) *)(shader->prepare_now(get_prepared_objects(), this));
} }
#ifdef OPENGLES_2
// If it failed, try applying the default shader.
if (shader != _default_shader && (context == 0 || !context->valid())) {
shader = _default_shader;
context = (CLP(ShaderContext) *)(shader->prepare_now(get_prepared_objects(), this));
}
#endif
if (context == 0 || (context -> valid ( ) == false)) { if (context == 0 || (context->valid() == false)) {
if (_current_shader_context != 0) { if (_current_shader_context != 0) {
_current_shader_context->unbind(this); _current_shader_context->unbind(this);
_current_shader = 0; _current_shader = 0;
@ -4076,8 +4168,13 @@ do_issue_shader() {
_current_shader = shader; _current_shader = shader;
_current_shader_context = context; _current_shader_context = context;
} else { } else {
// Use the same shader as before, but with new input arguments. #ifdef OPENGLES_2
context->issue_parameters(this, Shader::SSD_shaderinputs); context->bind(this, false);
#endif
if (state_has_changed) {
// Use the same shader as before, but with new input arguments.
context->issue_parameters(this, Shader::SSD_shaderinputs);
}
} }
} }
@ -6826,6 +6923,11 @@ set_state_and_transform(const RenderState *target,
_state_shader = _target_shader; _state_shader = _target_shader;
_state_mask.clear_bit(TextureAttrib::get_class_slot()); _state_mask.clear_bit(TextureAttrib::get_class_slot());
} }
#ifdef OPENGLES_2
else { // In the case of OpenGL ES 2.x, we need to glUseShader before we draw anything.
do_issue_shader(false);
}
#endif
int texture_slot = TextureAttrib::get_class_slot(); int texture_slot = TextureAttrib::get_class_slot();
if (_target_rs->get_attrib(texture_slot) != _state_rs->get_attrib(texture_slot) || if (_target_rs->get_attrib(texture_slot) != _state_rs->get_attrib(texture_slot) ||

View File

@ -116,13 +116,18 @@ typedef void (APIENTRYP PFNGLWEIGHTPOINTEROESPROC) (GLint size, GLenum type, GLs
#ifndef OPENGLES_1 #ifndef OPENGLES_1
// GLSL shader functions // GLSL shader functions
typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader); typedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name);
typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader); typedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);
typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void); typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type); typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader); typedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);
typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader); typedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);
typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);
typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
@ -139,6 +144,7 @@ typedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, con
typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);
typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program); typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
#endif #endif
#endif // __EDG__ #endif // __EDG__
@ -274,7 +280,7 @@ protected:
void do_issue_fog(); void do_issue_fog();
void do_issue_depth_offset(); void do_issue_depth_offset();
void do_issue_shade_model(); void do_issue_shade_model();
void do_issue_shader(); void do_issue_shader(bool state_has_changed = false);
void do_issue_material(); void do_issue_material();
void do_issue_texture(); void do_issue_texture();
void do_issue_blending(); void do_issue_blending();
@ -441,6 +447,9 @@ protected:
PT(Shader) _texture_binding_shader; PT(Shader) _texture_binding_shader;
CLP(ShaderContext) *_texture_binding_shader_context; CLP(ShaderContext) *_texture_binding_shader_context;
#endif #endif
#ifdef OPENGLES_2
PT(Shader) _default_shader;
#endif
#ifdef SUPPORT_IMMEDIATE_MODE #ifdef SUPPORT_IMMEDIATE_MODE
CLP(ImmediateModeSender) _sender; CLP(ImmediateModeSender) _sender;
@ -581,13 +590,18 @@ public:
#ifndef OPENGLES_1 #ifndef OPENGLES_1
// GLSL functions // GLSL functions
PFNGLATTACHSHADERPROC _glAttachShader; PFNGLATTACHSHADERPROC _glAttachShader;
PFNGLBINDATTRIBLOCATIONPROC _glBindAttribLocation;
PFNGLCOMPILESHADERPROC _glCompileShader; PFNGLCOMPILESHADERPROC _glCompileShader;
PFNGLCREATEPROGRAMPROC _glCreateProgram; PFNGLCREATEPROGRAMPROC _glCreateProgram;
PFNGLCREATESHADERPROC _glCreateShader; PFNGLCREATESHADERPROC _glCreateShader;
PFNGLDELETEPROGRAMPROC _glDeleteProgram; PFNGLDELETEPROGRAMPROC _glDeleteProgram;
PFNGLDELETESHADERPROC _glDeleteShader; PFNGLDELETESHADERPROC _glDeleteShader;
PFNGLDETACHSHADERPROC _glDetachShader; PFNGLDETACHSHADERPROC _glDetachShader;
PFNGLDISABLEVERTEXATTRIBARRAYPROC _glDisableVertexAttribArray;
PFNGLENABLEVERTEXATTRIBARRAYPROC _glEnableVertexAttribArray;
PFNGLGETACTIVEATTRIBPROC _glGetActiveAttrib;
PFNGLGETACTIVEUNIFORMPROC _glGetActiveUniform; PFNGLGETACTIVEUNIFORMPROC _glGetActiveUniform;
PFNGLGETATTRIBLOCATIONPROC _glGetAttribLocation;
PFNGLGETPROGRAMIVPROC _glGetProgramiv; PFNGLGETPROGRAMIVPROC _glGetProgramiv;
PFNGLGETPROGRAMINFOLOGPROC _glGetProgramInfoLog; PFNGLGETPROGRAMINFOLOGPROC _glGetProgramInfoLog;
PFNGLGETSHADERIVPROC _glGetShaderiv; PFNGLGETSHADERIVPROC _glGetShaderiv;
@ -604,6 +618,7 @@ public:
PFNGLUNIFORM4FVPROC _glUniform4fv; PFNGLUNIFORM4FVPROC _glUniform4fv;
PFNGLUNIFORMMATRIX4FVPROC _glUniformMatrix4fv; PFNGLUNIFORMMATRIX4FVPROC _glUniformMatrix4fv;
PFNGLVALIDATEPROGRAMPROC _glValidateProgram; PFNGLVALIDATEPROGRAMPROC _glValidateProgram;
PFNGLVERTEXATTRIBPOINTERPROC _glVertexAttribPointer;
#endif #endif
GLenum _edge_clamp; GLenum _edge_clamp;

View File

@ -73,9 +73,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
cgGetProfileString(cgGetProgramProfile(_cg_fprogram)) << " " << str << ")\n"; cgGetProfileString(cgGetProgramProfile(_cg_fprogram)) << " " << str << ")\n";
release_resources(gsg); release_resources(gsg);
} }
if (glGetError() != GL_NO_ERROR) { gsg->report_my_gl_errors();
GLCAT.error() << "GL error in ShaderContext constructor\n";
}
if (_cg_gprogram != 0) { if (_cg_gprogram != 0) {
cgGLLoadProgram(_cg_gprogram); cgGLLoadProgram(_cg_gprogram);
if (GLCAT.is_debug()) { if (GLCAT.is_debug()) {
@ -90,9 +88,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
cgGetProfileString(cgGetProgramProfile(_cg_gprogram)) << " " << str << ")\n"; cgGetProfileString(cgGetProgramProfile(_cg_gprogram)) << " " << str << ")\n";
release_resources(gsg); release_resources(gsg);
} }
if (glGetError() != GL_NO_ERROR) { gsg->report_my_gl_errors();
GLCAT.error() << "GL error in ShaderContext constructor\n";
}
} }
} }
#endif #endif
@ -109,14 +105,13 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
// Analyze the uniforms and put them in _glsl_parameter_map // Analyze the uniforms and put them in _glsl_parameter_map
if (s->_glsl_parameter_map.size() == 0) { if (s->_glsl_parameter_map.size() == 0) {
int seqno = 0, texunitno = 0; int seqno = 0, texunitno = 0;
int num_uniforms, uniform_maxlength; int param_count, param_maxlength, param_size;
gsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_UNIFORMS, &num_uniforms); GLenum param_type;
gsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniform_maxlength); gsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_UNIFORMS, &param_count);
for (int i = 0; i < num_uniforms; ++i) { gsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &param_maxlength);
int param_size; char* param_name = new char[param_maxlength];
GLenum param_type; for (int i = 0; i < param_count; ++i) {
char* param_name = new char[uniform_maxlength]; gsg->_glGetActiveUniform(_glsl_program, i, param_maxlength, NULL, &param_size, &param_type, param_name);
gsg->_glGetActiveUniform(_glsl_program, i, uniform_maxlength, NULL, &param_size, &param_type, param_name);
GLint p = gsg->_glGetUniformLocation(_glsl_program, param_name); GLint p = gsg->_glGetUniformLocation(_glsl_program, param_name);
if (p > -1) { if (p > -1) {
Shader::ShaderArgId arg_id; Shader::ShaderArgId arg_id;
@ -124,6 +119,18 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
arg_id._seqno = seqno++; arg_id._seqno = seqno++;
s->_glsl_parameter_map.push_back(p); s->_glsl_parameter_map.push_back(p);
PT(InternalName) inputname = InternalName::make(param_name); PT(InternalName) inputname = InternalName::make(param_name);
if (inputname->get_name() == "p3d_ModelViewProjectionMatrix") {
Shader::ShaderMatSpec bind;
bind._id = arg_id;
bind._piece = Shader::SMP_whole;
bind._func = Shader::SMF_compose;
bind._part[0] = Shader::SMO_model_to_view;
bind._arg[0] = NULL;
bind._part[1] = Shader::SMO_view_to_apiclip;
bind._arg[1] = NULL;
s->_mat_spec.push_back(bind);
continue;
}
if (inputname->get_name().substr(0, 11) == "p3d_Texture") { if (inputname->get_name().substr(0, 11) == "p3d_Texture") {
Shader::ShaderTexSpec bind; Shader::ShaderTexSpec bind;
bind._id = arg_id; bind._id = arg_id;
@ -230,10 +237,58 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
GLCAT.warning() << "Ignoring unrecognized GLSL parameter type!\n"; GLCAT.warning() << "Ignoring unrecognized GLSL parameter type!\n";
} }
} }
delete param_name;
} }
delete[] param_name;
int attrib_idx = 0;
// Now we've processed the uniforms, we'll process the attribs.
gsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_ATTRIBUTES, &param_count);
gsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &param_maxlength);
param_name = new char[param_maxlength];
for (int i = 0; i < param_count; ++i) {
gsg->_glGetActiveAttrib(_glsl_program, i, param_maxlength, NULL, &param_size, &param_type, param_name);
Shader::ShaderVarSpec bind;
Shader::ShaderArgId arg_id;
arg_id._name = param_name;
arg_id._seqno = -1;
PT(InternalName) inputname = InternalName::make(param_name);
bind._append_uv = -1;
if (inputname->get_name() == "p3d_Vertex") {
bind._name = InternalName::get_vertex();
s->_var_spec.push_back(bind);
gsg->_glBindAttribLocation(_glsl_program, i, param_name);
continue;
}
if (inputname->get_name() == "p3d_Normal") {
bind._name = InternalName::get_normal();
s->_var_spec.push_back(bind);
gsg->_glBindAttribLocation(_glsl_program, i, param_name);
continue;
}
if (inputname->get_name() == "p3d_Color") {
bind._name = InternalName::get_color();
s->_var_spec.push_back(bind);
gsg->_glBindAttribLocation(_glsl_program, i, param_name);
continue;
}
}
delete[] param_name;
}
// Finally, re-link the program, or otherwise the glBindAttribLocation
// calls won't have any effect.
gsg->_glLinkProgram(_glsl_program);
int status;
gsg->_glGetProgramiv(_glsl_program, GL_LINK_STATUS, &status);
if (status != GL_TRUE) {
GLCAT.error() << "An error occurred while relinking shader program!\n";
glsl_report_program_errors(gsg, _glsl_program);
s->_error_flag = true;
} }
} }
gsg->report_my_gl_errors();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -263,7 +318,9 @@ release_resources(const GSG *gsg) {
_cg_gprogram = 0; _cg_gprogram = 0;
_cg_parameter_map.clear(); _cg_parameter_map.clear();
} }
if (glGetError() != GL_NO_ERROR) { if (gsg) {
gsg->report_my_gl_errors();
} if (glGetError() != GL_NO_ERROR) {
GLCAT.error() << "GL error in ShaderContext destructor\n"; GLCAT.error() << "GL error in ShaderContext destructor\n";
} }
#endif #endif
@ -300,10 +357,18 @@ release_resources(const GSG *gsg) {
// input parameters. // input parameters.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void CLP(ShaderContext):: void CLP(ShaderContext)::
bind(GSG *gsg) { bind(GSG *gsg, bool reissue_parameters) {
_last_gsg = gsg; _last_gsg = gsg;
// Pass in k-parameters and transform-parameters
issue_parameters(gsg, Shader::SSD_general); // GLSL shaders need to be bound before passing parameters.
if (_shader->get_language() == Shader::SL_GLSL && !_shader->get_error_flag()) {
gsg->_glUseProgram(_glsl_program);
}
if (reissue_parameters) {
// Pass in k-parameters and transform-parameters
issue_parameters(gsg, Shader::SSD_general);
}
#ifdef HAVE_CG #ifdef HAVE_CG
if (_cg_context != 0) { if (_cg_context != 0) {
@ -320,13 +385,8 @@ bind(GSG *gsg) {
cg_report_errors(); cg_report_errors();
} }
#endif #endif
if (_shader->get_language() == Shader::SL_GLSL && !_shader->get_error_flag()) { gsg->report_my_gl_errors();
gsg->_glUseProgram(_glsl_program);
}
if (glGetError() != GL_NO_ERROR) {
GLCAT.error() << "GL error in ShaderContext::bind\n";
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -353,9 +413,7 @@ unbind(GSG *gsg) {
if (_shader->get_language() == Shader::SL_GLSL) { if (_shader->get_language() == Shader::SL_GLSL) {
gsg->_glUseProgram(0); gsg->_glUseProgram(0);
} }
if (glGetError() != GL_NO_ERROR) { gsg->report_my_gl_errors();
GLCAT.error() << "GL error in ShaderContext::unbind\n";
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -432,9 +490,7 @@ issue_parameters(GSG *gsg, int altered) {
cg_report_errors(); cg_report_errors();
#endif #endif
if (glGetError() != GL_NO_ERROR) { gsg->report_my_gl_errors();
GLCAT.error() << "GL error in ShaderContext::issue_parameters\n";
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -445,22 +501,27 @@ issue_parameters(GSG *gsg, int altered) {
void CLP(ShaderContext):: void CLP(ShaderContext)::
disable_shader_vertex_arrays(GSG *gsg) { disable_shader_vertex_arrays(GSG *gsg) {
_last_gsg = gsg; _last_gsg = gsg;
if (!valid()) {
#ifdef HAVE_CG
if (_cg_context == 0) {
return; return;
} }
for (int i=0; i<(int)_shader->_var_spec.size(); i++) { if (_shader->get_language() == Shader::SL_GLSL) {
CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno]; for (int i=0; i<(int)_shader->_var_spec.size(); i++) {
if (p == 0) continue; glDisableVertexAttribArray(i);
cgGLDisableClientState(p); }
} }
cg_report_errors(); #ifdef HAVE_CG
if (glGetError() != GL_NO_ERROR) { else if (_shader->get_language() == Shader::SL_Cg) {
GLCAT.error() << "GL error in ShaderContext::disable_shader_vertex_arrays\n"; for (int i=0; i<(int)_shader->_var_spec.size(); i++) {
CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
if (p == 0) continue;
cgGLDisableClientState(p);
}
cg_report_errors();
} }
#endif #endif
gsg->report_my_gl_errors();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -479,11 +540,12 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg,
bool force) { bool force) {
_last_gsg = gsg; _last_gsg = gsg;
if (prev) prev->disable_shader_vertex_arrays(gsg); if (prev) prev->disable_shader_vertex_arrays(gsg);
#ifdef HAVE_CG
if (!valid()) { if (!valid()) {
return true; return true;
} }
#ifdef HAVE_CG
cg_report_errors(); cg_report_errors();
#endif
#ifdef SUPPORT_IMMEDIATE_MODE #ifdef SUPPORT_IMMEDIATE_MODE
if (gsg->_use_sender) { if (gsg->_use_sender) {
@ -496,8 +558,14 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg,
int start, stride, num_values; int start, stride, num_values;
int nvarying = _shader->_var_spec.size(); int nvarying = _shader->_var_spec.size();
for (int i=0; i<nvarying; i++) { for (int i=0; i<nvarying; i++) {
CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno]; #ifdef HAVE_CG
if (p == 0) continue; if (_shader->get_language() == Shader::SL_Cg) {
if (_cg_parameter_map[_shader->_var_spec[i]._id._seqno] == 0) {
continue;
}
}
#endif
InternalName *name = _shader->_var_spec[i]._name; InternalName *name = _shader->_var_spec[i]._name;
int texslot = _shader->_var_spec[i]._append_uv; int texslot = _shader->_var_spec[i]._append_uv;
if (texslot >= 0 && texslot < gsg->_state_texture->get_num_on_stages()) { if (texslot >= 0 && texslot < gsg->_state_texture->get_num_on_stages()) {
@ -516,21 +584,39 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg,
if (!gsg->setup_array_data(client_pointer, array_reader, force)) { if (!gsg->setup_array_data(client_pointer, array_reader, force)) {
return false; return false;
} }
cgGLSetParameterPointer(p, if (_shader->get_language() == Shader::SL_GLSL) {
num_values, gsg->get_numeric_type(numeric_type), #ifndef OPENGLES_2
stride, client_pointer + start); glEnableClientState(GL_VERTEX_ARRAY);
cgGLEnableClientState(p); #endif
} else { glEnableVertexAttribArray(i);
glVertexAttribPointer(i, num_values, gsg->get_numeric_type(numeric_type),
GL_FALSE, stride, client_pointer + start);
#ifndef OPENGLES_2
glDisableClientState(GL_VERTEX_ARRAY);
#endif
#ifdef HAVE_CG
} else if (_shader->get_language() == Shader::SL_Cg) {
CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
cgGLSetParameterPointer(p,
num_values, gsg->get_numeric_type(numeric_type),
stride, client_pointer + start);
cgGLEnableClientState(p);
#endif
}
}
#ifdef HAVE_CG
else if (_shader->get_language() == Shader::SL_Cg) {
cgGLDisableClientState(p); cgGLDisableClientState(p);
} }
#endif
} }
} }
#ifdef HAVE_CG
cg_report_errors(); cg_report_errors();
if (glGetError() != GL_NO_ERROR) { #endif
GLCAT.error() << "GL error in ShaderContext::update_shader_vertex_arrays\n"; gsg->report_my_gl_errors();
}
#endif // HAVE_CG
return true; return true;
} }
@ -586,9 +672,7 @@ disable_shader_texture_bindings(GSG *gsg) {
cg_report_errors(); cg_report_errors();
#endif #endif
if (glGetError() != GL_NO_ERROR) { gsg->report_my_gl_errors();
GLCAT.error() << "GL error in ShaderContext::disable_shader_texture_bindings\n";
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -694,9 +778,7 @@ update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg) {
cg_report_errors(); cg_report_errors();
#endif #endif
if (glGetError() != GL_NO_ERROR) { gsg->report_my_gl_errors();
GLCAT.error() << "GL error in ShaderContext::update_shader_texture_bindings\n";
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -725,14 +807,16 @@ glsl_report_shader_errors(GSG *gsg, unsigned int shader) {
int length = 0; int length = 0;
int num_chars = 0; int num_chars = 0;
gsg->_glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); gsg->_glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
if (length > 0) { if (length > 0) {
info_log = (char *) malloc(length); info_log = (char *) malloc(length);
gsg->_glGetShaderInfoLog(shader, length, &num_chars, info_log); gsg->_glGetShaderInfoLog(shader, length, &num_chars, info_log);
GLCAT.error(false) << info_log; if (strcmp(info_log, "Success.\n") != 0) {
free(info_log); GLCAT.error(false) << info_log;
}
} }
delete[] info_log;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -746,14 +830,16 @@ glsl_report_program_errors(GSG *gsg, unsigned int program) {
int length = 0; int length = 0;
int num_chars = 0; int num_chars = 0;
gsg->_glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); gsg->_glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
if (length > 0) { if (length > 0) {
info_log = (char *) malloc(length); info_log = (char *) malloc(length);
gsg->_glGetProgramInfoLog(program, length, &num_chars, info_log); gsg->_glGetProgramInfoLog(program, length, &num_chars, info_log);
GLCAT.error(false) << info_log; if (strcmp(info_log, "Success.\n") != 0) {
free(info_log); GLCAT.error(false) << info_log;
}
} }
delete[] info_log;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -762,16 +848,16 @@ glsl_report_program_errors(GSG *gsg, unsigned int program) {
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
unsigned int CLP(ShaderContext):: unsigned int CLP(ShaderContext)::
glsl_compile_entry_point(GSG *gsg, const char *entry, Shader::ShaderType type) { glsl_compile_entry_point(GSG *gsg, Shader::ShaderType type) {
unsigned int handle; unsigned int handle;
switch (type) { switch (type) {
case Shader::ST_VERTEX: case Shader::ST_vertex:
handle = gsg->_glCreateShader(GL_VERTEX_SHADER); handle = gsg->_glCreateShader(GL_VERTEX_SHADER);
break; break;
case Shader::ST_FRAGMENT: case Shader::ST_fragment:
handle = gsg->_glCreateShader(GL_FRAGMENT_SHADER); handle = gsg->_glCreateShader(GL_FRAGMENT_SHADER);
break; break;
case Shader::ST_GEOMETRY: case Shader::ST_geometry:
handle = gsg->_glCreateShader(GL_GEOMETRY_SHADER); handle = gsg->_glCreateShader(GL_GEOMETRY_SHADER);
break; break;
default: default:
@ -780,16 +866,13 @@ glsl_compile_entry_point(GSG *gsg, const char *entry, Shader::ShaderType type) {
if (!handle) { if (!handle) {
return 0; return 0;
} }
// We define our own main() in which we call the right function. const char* text = _shader->get_text(type).c_str();
ostringstream str; gsg->_glShaderSource(handle, 1, &text, NULL);
str << "void main() { " << entry << "(); };";
const char* sources[2] = {_shader->_text.c_str(), str.str().c_str()};
gsg->_glShaderSource(handle, 2, sources, NULL);
gsg->_glCompileShader(handle); gsg->_glCompileShader(handle);
int status; int status;
gsg->_glGetShaderiv(handle, GL_COMPILE_STATUS, &status); gsg->_glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) { if (status != GL_TRUE) {
GLCAT.error() << "An error occurred while compiling " << entry << "!\n"; GLCAT.error() << "An error occurred while compiling shader!\n";
glsl_report_shader_errors(gsg, handle); glsl_report_shader_errors(gsg, handle);
gsg->_glDeleteShader(handle); gsg->_glDeleteShader(handle);
return 0; return 0;
@ -810,38 +893,24 @@ glsl_compile_shader(GSG *gsg) {
_glsl_program = gsg->_glCreateProgram(); _glsl_program = gsg->_glCreateProgram();
if (!_glsl_program) return false; if (!_glsl_program) return false;
if (_shader->_text.find("vshader") != -1) { if (!_shader->get_text(Shader::ST_vertex).empty()) {
_glsl_vshader = glsl_compile_entry_point(gsg, "vshader", Shader::ST_VERTEX); _glsl_vshader = glsl_compile_entry_point(gsg, Shader::ST_vertex);
if (!_glsl_vshader) return false; if (!_glsl_vshader) return false;
gsg->_glAttachShader(_glsl_program, _glsl_vshader); gsg->_glAttachShader(_glsl_program, _glsl_vshader);
} else {
GLCAT.warning() << "Could not locate function 'vshader' in shader text!\n";
} }
if (_shader->_text.find("fshader") != -1) { if (!_shader->get_text(Shader::ST_fragment).empty()) {
_glsl_fshader = glsl_compile_entry_point(gsg, "fshader", Shader::ST_FRAGMENT); _glsl_fshader = glsl_compile_entry_point(gsg, Shader::ST_fragment);
if (!_glsl_fshader) return false; if (!_glsl_fshader) return false;
gsg->_glAttachShader(_glsl_program, _glsl_fshader); gsg->_glAttachShader(_glsl_program, _glsl_fshader);
} else {
GLCAT.warning() << "Could not locate function 'fshader' in shader text!\n";
} }
if (_shader->_text.find("gshader") != -1) { if (!_shader->get_text(Shader::ST_geometry).empty()) {
_glsl_gshader = glsl_compile_entry_point(gsg, "gshader", Shader::ST_GEOMETRY); _glsl_gshader = glsl_compile_entry_point(gsg, Shader::ST_geometry);
if (!_glsl_gshader) return false; if (!_glsl_gshader) return false;
gsg->_glAttachShader(_glsl_program, _glsl_gshader); gsg->_glAttachShader(_glsl_program, _glsl_gshader);
} }
gsg->_glLinkProgram(_glsl_program);
int status;
gsg->_glGetProgramiv(_glsl_program, GL_LINK_STATUS, &status);
if (status != GL_TRUE) {
GLCAT.error() << "An error occurred while linking shader program!\n";
glsl_report_program_errors(gsg, _glsl_program);
return false;
}
// There might be warnings. Only report them for one shader program. // There might be warnings. Only report them for one shader program.
if (_glsl_vshader != 0) { if (_glsl_vshader != 0) {
glsl_report_shader_errors(gsg, _glsl_vshader); glsl_report_shader_errors(gsg, _glsl_vshader);
@ -851,10 +920,17 @@ glsl_compile_shader(GSG *gsg) {
glsl_report_shader_errors(gsg, _glsl_gshader); glsl_report_shader_errors(gsg, _glsl_gshader);
} }
if (glGetError() != GL_NO_ERROR) { gsg->_glLinkProgram(_glsl_program);
GLCAT.error() << "Failed to compile shader\n";
int status;
gsg->_glGetProgramiv(_glsl_program, GL_LINK_STATUS, &status);
if (status != GL_TRUE) {
GLCAT.error() << "An error occurred while linking shader program!\n";
glsl_report_program_errors(gsg, _glsl_program);
return false; return false;
} }
gsg->report_my_gl_errors();
return true; return true;
} }

View File

@ -27,9 +27,9 @@ class CLP(GraphicsStateGuardian);
// Class : GLShaderContext // Class : GLShaderContext
// Description : xyz // Description : xyz
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_GL CLP(ShaderContext): public ShaderContext { class EXPCL_GL CLP(ShaderContext): public ShaderContext {
public: public:
friend class CLP(GraphicsStateGuardian);
typedef CLP(GraphicsStateGuardian) GSG; typedef CLP(GraphicsStateGuardian) GSG;
CLP(ShaderContext)(Shader *s, GSG *gsg); CLP(ShaderContext)(Shader *s, GSG *gsg);
@ -37,7 +37,7 @@ public:
ALLOC_DELETED_CHAIN(CLP(ShaderContext)); ALLOC_DELETED_CHAIN(CLP(ShaderContext));
INLINE bool valid(void); INLINE bool valid(void);
void bind(GSG *gsg); void bind(GSG *gsg, bool reissue_parameters = true);
void unbind(GSG *gsg); void unbind(GSG *gsg);
void issue_parameters(GSG *gsg, int altered); void issue_parameters(GSG *gsg, int altered);
void disable_shader_vertex_arrays(GSG *gsg); void disable_shader_vertex_arrays(GSG *gsg);
@ -76,7 +76,7 @@ private:
void glsl_report_shader_errors(GSG *gsg, unsigned int shader); void glsl_report_shader_errors(GSG *gsg, unsigned int shader);
void glsl_report_program_errors(GSG *gsg, unsigned int program); void glsl_report_program_errors(GSG *gsg, unsigned int program);
unsigned int glsl_compile_entry_point(GSG *gsg, const char *entry, Shader::ShaderType type); unsigned int glsl_compile_entry_point(GSG *gsg, Shader::ShaderType type);
bool glsl_compile_shader(GSG *gsg); bool glsl_compile_shader(GSG *gsg);
void release_resources(const GSG *gsg); void release_resources(const GSG *gsg);

View File

@ -13,33 +13,68 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Shader::get_filename // Function: Shader::get_filename
// Access: Public // Access: Public
// Description: Return the Shader's filename. // Description: Return the Shader's filename for the given shader
// type.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE const Filename &Shader:: INLINE const Filename Shader::
get_filename() const { get_filename(const ShaderType &type) const {
return _filename; if (_filename->_separate) {
nassertr(type != ST_none || !_filename->_shared.empty(), "");
switch (type) {
case ST_vertex:
return _filename->_vertex;
break;
case ST_fragment:
return _filename->_fragment;
break;
case ST_geometry:
return _filename->_geometry;
break;
default:
return _filename->_shared;
}
} else {
return _filename->_shared;
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Shader::get_text // Function: Shader::get_text
// Access: Public // Access: Public
// Description: Return the Shader's text. // Description: Return the Shader's text for the given shader type.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE const string &Shader:: INLINE const string Shader::
get_text() const { get_text(const ShaderType &type) const {
return _text; if (_text->_separate) {
nassertr(type != ST_none || !_text->_shared.empty(), "");
switch (type) {
case ST_vertex:
return _text->_vertex;
break;
case ST_fragment:
return _text->_fragment;
break;
case ST_geometry:
return _text->_geometry;
break;
default:
return _text->_shared;
}
} else {
return _text->_shared;
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Shader::get_error_flag // Function: Shader::get_error_flag
// Access: Public // Access: Public
// Description: Returns true if the shader contains a compile-time // Description: Returns true if the shader contains a compile-time
// error. This doesn't tell you whether or not the // error. This doesn't tell you whether or not the
// shader is supported on the current video card. // shader is supported on the current video card.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE bool Shader:: INLINE const bool Shader::
get_error_flag() const { get_error_flag() const {
return _error_flag; return _error_flag;
} }

View File

@ -24,8 +24,8 @@
#endif #endif
TypeHandle Shader::_type_handle; TypeHandle Shader::_type_handle;
Shader::LoadTable Shader::_load_table; Shader::ShaderTable Shader::_load_table;
Shader::MakeTable Shader::_make_table; Shader::ShaderTable Shader::_make_table;
Shader::ShaderCaps Shader::_default_caps; Shader::ShaderCaps Shader::_default_caps;
int Shader::_shaders_generated; int Shader::_shaders_generated;
ShaderUtilization Shader::_shader_utilization = SUT_UNSPECIFIED; ShaderUtilization Shader::_shader_utilization = SUT_UNSPECIFIED;
@ -37,8 +37,7 @@ ShaderUtilization Shader::_shader_utilization = SUT_UNSPECIFIED;
// of the specified parameter. // of the specified parameter.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void Shader:: void Shader::
cp_report_error(ShaderArgInfo &p, const string &msg) cp_report_error(ShaderArgInfo &p, const string &msg) {
{
string vstr; string vstr;
if (p._varying) vstr = "varying "; if (p._varying) vstr = "varying ";
else vstr = "uniform "; else vstr = "uniform ";
@ -62,7 +61,7 @@ cp_report_error(ShaderArgInfo &p, const string &msg)
case SAT_unknown: tstr = "unknown "; break; case SAT_unknown: tstr = "unknown "; break;
} }
Filename fn = get_filename(); Filename fn = get_filename(p._id._type);
p._cat->error() << fn << ": " << msg << " (" << p._cat->error() << fn << ": " << msg << " (" <<
vstr << dstr << tstr << p._id._name << ")\n"; vstr << dstr << tstr << p._id._name << ")\n";
} }
@ -1107,12 +1106,10 @@ cg_release_resources() {
cgDestroyProgram(_cg_fprogram); cgDestroyProgram(_cg_fprogram);
_cg_fprogram = 0; _cg_fprogram = 0;
} }
// BEGIN CG2 CHANGE
if (_cg_gprogram != 0) { if (_cg_gprogram != 0) {
cgDestroyProgram(_cg_gprogram); cgDestroyProgram(_cg_gprogram);
_cg_gprogram = 0; _cg_gprogram = 0;
} }
// END CG2 CHANGE
if (_cg_context != 0) { if (_cg_context != 0) {
cgDestroyContext(_cg_context); cgDestroyContext(_cg_context);
_cg_context = 0; _cg_context = 0;
@ -1129,40 +1126,50 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
CGprogram prog; CGprogram prog;
CGerror err; CGerror err;
const char *compiler_args[100]; const char *compiler_args[100];
const string text;
if (!_text->_separate) {
text = _text->_shared;
}
int nargs = 0; int nargs = 0;
int active, ultimate; int active, ultimate;
switch(type) switch(type) {
{ case ST_vertex:
case ST_VERTEX:
active = caps._active_vprofile; active = caps._active_vprofile;
ultimate = caps._ultimate_vprofile; ultimate = caps._ultimate_vprofile;
if (_text->_separate) {
text = _text._vertex;
}
break; break;
case ST_FRAGMENT: case ST_fragment:
active = caps._active_fprofile; active = caps._active_fprofile;
ultimate = caps._ultimate_fprofile; ultimate = caps._ultimate_fprofile;
if (_text->_separate) {
text = _text._fragment;
}
break; break;
case ST_GEOMETRY: case ST_geometry:
active = caps._active_gprofile; active = caps._active_gprofile;
ultimate = caps._ultimate_gprofile; ultimate = caps._ultimate_gprofile;
if (_text->_separate) {
text = _text._geometry;
}
break; break;
}; };
// END CG2 CHANGE
cgGetError(); cgGetError();
if (type == ST_FRAGMENT && caps._bug_list.count(SBUG_ati_draw_buffers)) { // CG2 CHANGE if (type == ST_fragment && caps._bug_list.count(SBUG_ati_draw_buffers)) {
compiler_args[nargs++] = "-po"; compiler_args[nargs++] = "-po";
compiler_args[nargs++] = "ATI_draw_buffers"; compiler_args[nargs++] = "ATI_draw_buffers";
} }
compiler_args[nargs] = 0; compiler_args[nargs] = 0;
if ((active != (int)CG_PROFILE_UNKNOWN) && (active != ultimate)) { if ((active != (int)CG_PROFILE_UNKNOWN) && (active != ultimate)) {
prog = cgCreateProgram(_cg_context, CG_SOURCE, _text.c_str(), prog = cgCreateProgram(_cg_context, CG_SOURCE, text.c_str(),
(CGprofile)active, entry, (const char **)compiler_args); (CGprofile)active, entry, (const char **)compiler_args);
err = cgGetError(); err = cgGetError();
if (err == CG_NO_ERROR) { if (err == CG_NO_ERROR) {
@ -1173,7 +1180,7 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
} }
} }
prog = cgCreateProgram(_cg_context, CG_SOURCE, _text.c_str(), prog = cgCreateProgram(_cg_context, CG_SOURCE, text.c_str(),
(CGprofile)ultimate, entry, (const char **)NULL); (CGprofile)ultimate, entry, (const char **)NULL);
err = cgGetError(); err = cgGetError();
if (err == CG_NO_ERROR) { if (err == CG_NO_ERROR) {
@ -1186,11 +1193,11 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
for (int i=0; i<(int)errlines.size(); i++) { for (int i=0; i<(int)errlines.size(); i++) {
string line = trim(errlines[i]); string line = trim(errlines[i]);
if (line != "") { if (line != "") {
gobj_cat.error() << get_filename() << ": " << errlines[i] << "\n"; gobj_cat.error() << get_filename(type) << ": " << errlines[i] << "\n";
} }
} }
} else { } else {
gobj_cat.error() << get_filename() << ": " << cgGetErrorString(err) << "\n"; gobj_cat.error() << get_filename(type) << ": " << cgGetErrorString(err) << "\n";
} }
if (prog != 0) { if (prog != 0) {
cgDestroyProgram(prog); cgDestroyProgram(prog);
@ -1209,8 +1216,6 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
bool Shader:: bool Shader::
cg_compile_shader(const ShaderCaps &caps) { cg_compile_shader(const ShaderCaps &caps) {
// If we already tried compiling for this set of caps, there's no point // If we already tried compiling for this set of caps, there's no point
// trying again. Just return the results of the previous compile. // trying again. Just return the results of the previous compile.
if (caps == _cg_last_caps) { if (caps == _cg_last_caps) {
@ -1225,18 +1230,25 @@ cg_compile_shader(const ShaderCaps &caps) {
_cg_context = cgCreateContext(); _cg_context = cgCreateContext();
gobj_cat.debug() << "Compiling Shader: \n" << _text << "\n"; if (!_text->_separate) {
gobj_cat.debug() << "Compiling Shader: \n" << _text << "\n";
}
if (_cg_context == 0) { if (_cg_context == 0) {
gobj_cat.error() << "could not create a Cg context object.\n"; gobj_cat.error() << "could not create a Cg context object.\n";
return false; return false;
} }
_cg_vprogram = cg_compile_entry_point("vshader", caps, ST_VERTEX); // CG2 CHANGE if (!_text->_separate || !_text._vertex.empty()) {
_cg_fprogram = cg_compile_entry_point("fshader", caps, ST_FRAGMENT); // CG2 CHANGE _cg_vprogram = cg_compile_entry_point("vshader", caps, ST_vertex);
}
if (_text.find("gshader") != -1) { if (!_text->_separate || !_text._fragment.empty()) {
_cg_gprogram = cg_compile_entry_point("gshader", caps, ST_GEOMETRY); _cg_fprogram = cg_compile_entry_point("fshader", caps, ST_fragment);
}
if ((_text->_separate && !_text._geometry.empty()) || (!_text->_separate && _text.find("gshader") != -1)) {
_cg_gprogram = cg_compile_entry_point("gshader", caps, ST_geometry);
} }
if ((_cg_vprogram == 0)||(_cg_fprogram == 0)) { if ((_cg_vprogram == 0)||(_cg_fprogram == 0)) {
@ -1317,7 +1329,7 @@ cg_analyze_shader(const ShaderCaps &caps) {
return false; return false;
} }
if (!cg_analyze_entry_point(_cg_fprogram, ST_FRAGMENT)) { if (!cg_analyze_entry_point(_cg_fprogram, ST_fragment)) {
cg_release_resources(); cg_release_resources();
clear_parameters(); clear_parameters();
return false; return false;
@ -1330,14 +1342,14 @@ cg_analyze_shader(const ShaderCaps &caps) {
return false; return false;
} }
if (!cg_analyze_entry_point(_cg_vprogram, ST_VERTEX)) { if (!cg_analyze_entry_point(_cg_vprogram, ST_vertex)) {
cg_release_resources(); cg_release_resources();
clear_parameters(); clear_parameters();
return false; return false;
} }
if (_cg_gprogram != 0) { if (_cg_gprogram != 0) {
if (!cg_analyze_entry_point(_cg_gprogram, ST_GEOMETRY)) { if (!cg_analyze_entry_point(_cg_gprogram, ST_geometry)) {
cg_release_resources(); cg_release_resources();
clear_parameters(); clear_parameters();
return false; return false;
@ -1463,15 +1475,15 @@ cg_program_from_shadertype(ShaderType type) {
CGprogram prog = 0; CGprogram prog = 0;
switch(type) { switch(type) {
case ST_VERTEX: case ST_vertex:
prog = _cg_vprogram; prog = _cg_vprogram;
break; break;
case ST_FRAGMENT: case ST_fragment:
prog = _cg_fprogram; prog = _cg_fprogram;
break; break;
case ST_GEOMETRY: case ST_geometry:
prog = _cg_gprogram; prog = _cg_gprogram;
break; break;
}; };
@ -1580,7 +1592,7 @@ cg_compile_for(const ShaderCaps &caps,
// Description: Construct a Shader. // Description: Construct a Shader.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
Shader:: Shader::
Shader(const Filename &filename, const string &text, const ShaderLanguage &lang) : Shader(CPT(ShaderFile) filename, CPT(ShaderFile) text, const ShaderLanguage &lang) :
_filename(filename), _filename(filename),
_text(text), _text(text),
_error_flag(true), _error_flag(true),
@ -1622,7 +1634,9 @@ Shader(const Filename &filename, const string &text, const ShaderLanguage &lang)
if (_language == SL_Cg) { if (_language == SL_Cg) {
#ifdef HAVE_CG #ifdef HAVE_CG
cg_get_profile_from_header(_default_caps); if (!_text->_separate) {
cg_get_profile_from_header(_default_caps);
}
if (!cg_analyze_shader(_default_caps)) { if (!cg_analyze_shader(_default_caps)) {
_error_flag = true; _error_flag = true;
@ -1632,8 +1646,13 @@ Shader(const Filename &filename, const string &text, const ShaderLanguage &lang)
<< "Tried to load Cg shader, but no Cg support is enabled.\n"; << "Tried to load Cg shader, but no Cg support is enabled.\n";
#endif #endif
} else if (_language == SL_GLSL) { } else if (_language == SL_GLSL) {
// All of the important stuff is done in glShaderContext. // All of the important stuff is done in glShaderContext,
_language = SL_GLSL; // to avoid gobj getting a dependency on OpenGL.
if (!_text->_separate) {
gobj_cat.error()
<< "GLSL shaders must have separate shader bodies!\n";
_error_flag = true;
}
} else { } else {
gobj_cat.error() gobj_cat.error()
<< "Shader is not in a supported shader-language.\n"; << "Shader is not in a supported shader-language.\n";
@ -1763,47 +1782,61 @@ Shader::
} }
} }
// Removed for now, as the profiles are now taken from the shader source.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Shader::load // Function: Shader::load
// Access: Published, Static // Access: Published, Static
// Description: Loads the shader with the given filename. // Description: Loads the shader with the given filename.
// If the optional vshader or fshader parameters
// are set and non-empty, it will be used to override
// all other profile settings (it even overrides
// the basic-shaders-only flag) and forces the shader
// to use the given profile.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
PT(Shader) Shader:: PT(Shader) Shader::
load(const string &file) { load(const Filename &file, const ShaderLanguage &lang) {
return load(Filename(file)); PT(ShaderFile) sfile = new ShaderFile(file);
ShaderTable::const_iterator i = _load_table.find(sfile);
if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
return i->second;
}
PT(ShaderFile) sbody = new ShaderFile("");
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
if (!vfs->read_file(file, sbody->_shared, true)) {
gobj_cat.error() << "Could not read shader file: " << file << "\n";
return NULL;
}
PT(Shader) result = new Shader(sfile, sbody, lang);
result->_loaded = true;
_load_table[sfile] = result;
return result;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Shader::load // Function: Shader::load
// Access: Published, Static // Access: Published, Static
// Description: Loads the shader with the given filename. // Description: This variant of Shader::load loads all shader
// If the optional vshader or fshader parameters // programs separately.
// are set and non-empty, it will be used to override
// all other profile settings (it even overrides
// the basic-shaders-only flag) and forces the shader
// to use the given profile.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
PT(Shader) Shader:: PT(Shader) Shader::
load(const Filename &file) { load(const ShaderLanguage &lang, const Filename &vertex, const Filename &fragment, const Filename &geometry) {
LoadTable::const_iterator i = _load_table.find(file); PT(ShaderFile) sfile = new ShaderFile(vertex, fragment, geometry);
if (i != _load_table.end()) { ShaderTable::const_iterator i = _load_table.find(sfile);
if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
return i->second; return i->second;
} }
string body; PT(ShaderFile) sbody = new ShaderFile("", "", "");
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr(); VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
if (!vfs->read_file(file, body, true)) { if (!vertex.empty() && !vfs->read_file(vertex, sbody->_vertex, true)) {
gobj_cat.error() << "Could not read shader file: " << file << "\n"; gobj_cat.error() << "Could not read vertex shader file: " << vertex << "\n";
return NULL; return NULL;
} }
PT(Shader) result = new Shader(file, body); if (!fragment.empty() && !vfs->read_file(fragment, sbody->_fragment, true)) {
gobj_cat.error() << "Could not read fragment shader file: " << vertex << "\n";
return NULL;
}
if (!geometry.empty() && !vfs->read_file(geometry, sbody->_geometry, true)) {
gobj_cat.error() << "Could not read geometry shader file: " << vertex << "\n";
return NULL;
}
PT(Shader) result = new Shader(sfile, sbody, lang);
result->_loaded = true; result->_loaded = true;
_load_table[file] = result; _load_table[sfile] = result;
return result; return result;
} }
@ -1811,20 +1844,17 @@ load(const Filename &file) {
// Function: Shader::make // Function: Shader::make
// Access: Published, Static // Access: Published, Static
// Description: Loads the shader, using the string as shader body. // Description: Loads the shader, using the string as shader body.
// If the optional vshader or fshader parameters //////////////////////////////////////////////////////////////////////
// are set and non-empty, it will be used to override
// all other profile settings (it even overrides
// the basic-shaders-only flag) and forces the shader
// to use the given profile.
////////////////////////////////////////////////////////////////////
PT(Shader) Shader:: PT(Shader) Shader::
make(const string &body) { make(const string &body, const ShaderLanguage &lang) {
MakeTable::const_iterator i = _make_table.find(body); PT(ShaderFile) sbody = new ShaderFile(body);
if (i != _make_table.end()) { ShaderTable::const_iterator i = _make_table.find(sbody);
if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
return i->second; return i->second;
} }
PT(Shader) result = new Shader("created-shader", body); PT(ShaderFile) sfile = new ShaderFile("created-shader");
_make_table[body] = result; PT(Shader) result = new Shader(sfile, sbody, lang);
_make_table[sbody] = result;
if (dump_generated_shaders) { if (dump_generated_shaders) {
ostringstream fns; ostringstream fns;
int index = _shaders_generated ++; int index = _shaders_generated ++;
@ -1839,6 +1869,24 @@ make(const string &body) {
return result; return result;
} }
//////////////////////////////////////////////////////////////////////
// Function: Shader::make
// Access: Published, Static
// Description: Loads the shader, using the strings as shader bodies.
//////////////////////////////////////////////////////////////////////
PT(Shader) Shader::
make(const ShaderLanguage &lang, const string &vertex, const string &fragment, const string &geometry) {
PT(ShaderFile) sbody = new ShaderFile(vertex, fragment, geometry);
ShaderTable::const_iterator i = _make_table.find(sbody);
if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
return i->second;
}
PT(ShaderFile) sfile = new ShaderFile("created-shader");
PT(Shader) result = new Shader(sfile, sbody, lang);
_make_table[sbody] = result;
return result;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Shader::parse_init // Function: Shader::parse_init
// Access: Public // Access: Public
@ -1859,10 +1907,11 @@ parse_init() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void Shader:: void Shader::
parse_line(string &result, bool lt, bool rt) { parse_line(string &result, bool lt, bool rt) {
int len = _text.size(); nassertv(!_text->_separate);
int len = _text->_shared.size();
int head = _parse; int head = _parse;
int tail = head; int tail = head;
while ((tail < len) && (_text[tail] != '\n')) { while ((tail < len) && (_text->_shared[tail] != '\n')) {
tail++; tail++;
} }
if (tail < len) { if (tail < len) {
@ -1871,10 +1920,10 @@ parse_line(string &result, bool lt, bool rt) {
_parse = tail; _parse = tail;
} }
if (lt) { if (lt) {
while ((head < tail)&&(isspace(_text[head]))) head++; while ((head < tail)&&(isspace(_text->_shared[head]))) head++;
while ((tail > head)&&(isspace(_text[tail-1]))) tail--; while ((tail > head)&&(isspace(_text->_shared[tail-1]))) tail--;
} }
result = _text.substr(head, tail-head); result = _text->_shared.substr(head, tail-head);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1887,19 +1936,20 @@ parse_line(string &result, bool lt, bool rt) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void Shader:: void Shader::
parse_upto(string &result, string pattern, bool include) { parse_upto(string &result, string pattern, bool include) {
nassertv(!_text->_separate);
GlobPattern endpat(pattern); GlobPattern endpat(pattern);
int start = _parse; int start = _parse;
int last = _parse; int last = _parse;
while (_parse < (int)(_text.size())) { while (_parse < (int)(_text->_shared.size())) {
string t; string t;
parse_line(t, true, true); parse_line(t, true, true);
if (endpat.matches(t)) break; if (endpat.matches(t)) break;
last = _parse; last = _parse;
} }
if (include) { if (include) {
result = _text.substr(start, _parse - start); result = _text->_shared.substr(start, _parse - start);
} else { } else {
result = _text.substr(start, last - start); result = _text->_shared.substr(start, last - start);
} }
} }
@ -1911,21 +1961,8 @@ parse_upto(string &result, string pattern, bool include) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void Shader:: void Shader::
parse_rest(string &result) { parse_rest(string &result) {
result = _text.substr(_parse, _text.size() - _parse); nassertv(!_text->_separate);
} result = _text->_shared.substr(_parse, _text->_shared.size() - _parse);
////////////////////////////////////////////////////////////////////
// Function: Shader::parse_lineno
// Access: Public
// Description: Returns the line number of the current parse pointer.
////////////////////////////////////////////////////////////////////
int Shader::
parse_lineno() {
int result = 1;
for (int i=0; i<_parse; i++) {
if (_text[i] == '\n') result += 1;
}
return result;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1936,7 +1973,7 @@ parse_lineno() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool Shader:: bool Shader::
parse_eof() { parse_eof() {
return (int)_text.size() == _parse; return (int)_text->_shared.size() == _parse;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -2001,7 +2038,7 @@ release(PreparedGraphicsObjects *prepared_objects) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: Shader::prepare_now // Function: Shader::prepare_now
// Access: Published // Access: Published
// Description: Creates a context for the texture on the particular // Description: Creates a context for the shader on the particular
// GSG, if it does not already exist. Returns the new // GSG, if it does not already exist. Returns the new
// (or old) ShaderContext. This assumes that the // (or old) ShaderContext. This assumes that the
// GraphicsStateGuardian is the currently active // GraphicsStateGuardian is the currently active
@ -2010,7 +2047,7 @@ release(PreparedGraphicsObjects *prepared_objects) {
// should use prepare() instead. // should use prepare() instead.
// //
// Normally, this is not called directly except by the // Normally, this is not called directly except by the
// GraphicsStateGuardian; a texture does not need to be // GraphicsStateGuardian; a shader does not need to be
// explicitly prepared by the user before it may be // explicitly prepared by the user before it may be
// rendered. // rendered.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -38,13 +38,27 @@ class EXPCL_PANDA_GOBJ Shader: public TypedReferenceCount {
PUBLISHED: PUBLISHED:
static PT(Shader) load(const Filename &file); enum ShaderLanguage {
static PT(Shader) load(const string &file); SL_none,
static PT(Shader) make(const string &body); SL_Cg,
SL_GLSL
};
enum ShaderType {
ST_none = 0,
ST_vertex,
ST_fragment,
ST_geometry,
};
INLINE const Filename &get_filename() const; static PT(Shader) load(const Filename &file, const ShaderLanguage &lang = SL_none);
INLINE const string &get_text() const; static PT(Shader) make(const string &body, const ShaderLanguage &lang = SL_none);
INLINE bool get_error_flag() const; static PT(Shader) load(const ShaderLanguage &lang, const Filename &vertex, const Filename &fragment, const Filename &geometry = "");
static PT(Shader) make(const ShaderLanguage &lang, const string &vertex, const string &fragment, const string &geometry = "");
INLINE const Filename get_filename(const ShaderType &type = ST_none) const;
INLINE const string get_text(const ShaderType &type = ST_none) const;
INLINE const bool get_error_flag() const;
INLINE const ShaderLanguage get_language() const;
INLINE static ShaderUtilization get_shader_utilization(); INLINE static ShaderUtilization get_shader_utilization();
INLINE static void set_shader_utilization(ShaderUtilization utl); INLINE static void set_shader_utilization(ShaderUtilization utl);
@ -57,14 +71,6 @@ PUBLISHED:
ShaderContext *prepare_now(PreparedGraphicsObjects *prepared_objects, ShaderContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
GraphicsStateGuardianBase *gsg); GraphicsStateGuardianBase *gsg);
enum ShaderLanguage {
SL_none,
SL_Cg,
SL_GLSL
};
INLINE const ShaderLanguage get_language() const;
public: public:
@ -180,12 +186,6 @@ public:
SMF_first, SMF_first,
}; };
enum ShaderType {
ST_VERTEX,
ST_FRAGMENT,
ST_GEOMETRY,
};
struct ShaderArgId { struct ShaderArgId {
string _name; string _name;
ShaderType _type; ShaderType _type;
@ -244,14 +244,27 @@ public:
INLINE ShaderCaps(); INLINE ShaderCaps();
}; };
struct ShaderFile : public ReferenceCount {
ShaderFile(string shared) { _separate = false; _shared = shared; }
ShaderFile(string vertex, string fragment, string geometry = "") {
_separate = true; _vertex = vertex;
_fragment = fragment; _geometry = geometry;
}
bool _separate;
string _shared;
string _vertex;
string _fragment;
string _geometry;
};
private: private:
// These routines help split the shader into sections, // These routines help split the shader into sections,
// for those shader implementations that need to do so. // for those shader implementations that need to do so.
// Don't use them when you use separate shader programs.
void parse_init(); void parse_init();
void parse_line(string &result, bool rt, bool lt); void parse_line(string &result, bool rt, bool lt);
void parse_upto(string &result, string pattern, bool include); void parse_upto(string &result, string pattern, bool include);
void parse_rest(string &result); void parse_rest(string &result);
int parse_lineno();
bool parse_eof(); bool parse_eof();
void cp_report_error(ShaderArgInfo &arg, const string &msg); void cp_report_error(ShaderArgInfo &arg, const string &msg);
@ -330,10 +343,10 @@ public:
pvector <ShaderVarSpec> _var_spec; pvector <ShaderVarSpec> _var_spec;
bool _error_flag; bool _error_flag;
string _text; CPT(ShaderFile) _text;
protected: protected:
Filename _filename; CPT(ShaderFile)_filename;
int _parse; int _parse;
bool _loaded; bool _loaded;
ShaderLanguage _language; ShaderLanguage _language;
@ -342,11 +355,10 @@ public:
static ShaderUtilization _shader_utilization; static ShaderUtilization _shader_utilization;
static int _shaders_generated; static int _shaders_generated;
typedef pmap < Filename , Shader * > LoadTable; typedef pmap < CPT(ShaderFile), Shader * > ShaderTable;
typedef pmap < string , Shader * > MakeTable;
static LoadTable _load_table; static ShaderTable _load_table;
static MakeTable _make_table; static ShaderTable _make_table;
friend class ShaderContext; friend class ShaderContext;
friend class PreparedGraphicsObjects; friend class PreparedGraphicsObjects;
@ -355,10 +367,10 @@ public:
Contexts _contexts; Contexts _contexts;
private: private:
Shader(const Filename &name, const string &text, const ShaderLanguage &lang = SL_none);
void clear_prepared(PreparedGraphicsObjects *prepared_objects); void clear_prepared(PreparedGraphicsObjects *prepared_objects);
public: public:
Shader(CPT(ShaderFile) name, CPT(ShaderFile) text, const ShaderLanguage &lang = SL_none);
static void register_with_read_factory(); static void register_with_read_factory();
~Shader(); ~Shader();