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) {
}
#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
@ -817,12 +834,12 @@ reset() {
if (basic_shaders_only) {
_shader_caps._active_vprofile = (int)CG_PROFILE_ARBVP1;
_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 {
_shader_caps._active_vprofile = (int)cgGLGetLatestProfile(CG_GL_VERTEX);
_shader_caps._active_fprofile = (int)cgGLGetLatestProfile(CG_GL_FRAGMENT);
#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
_shader_caps._active_gprofile = (int)0;
#endif
@ -830,7 +847,7 @@ reset() {
_shader_caps._ultimate_vprofile = (int)CG_PROFILE_VP40;
_shader_caps._ultimate_fprofile = (int)CG_PROFILE_FP40;
#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
_shader_caps._ultimate_gprofile = (int)0;
#endif
@ -862,10 +879,12 @@ reset() {
#endif
_shader_caps._supports_glsl = _supports_glsl;
#ifndef OPENGLES_1
#ifndef OPENGLES
if (_supports_glsl) {
_glAttachShader = (PFNGLATTACHSHADERPROC)
get_extension_func(GLPREFIX_QUOTED, "AttachShader");
_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)
get_extension_func(GLPREFIX_QUOTED, "BindAttribLocation");
_glCompileShader = (PFNGLCOMPILESHADERPROC)
get_extension_func(GLPREFIX_QUOTED, "CompileShader");
_glCreateProgram = (PFNGLCREATEPROGRAMPROC)
@ -878,8 +897,16 @@ reset() {
get_extension_func(GLPREFIX_QUOTED, "DeleteShader");
_glDetachShader = (PFNGLDETACHSHADERPROC)
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)
get_extension_func(GLPREFIX_QUOTED, "GetActiveUniform");
_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)
get_extension_func(GLPREFIX_QUOTED, "GetAttribLocation");
_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)
get_extension_func(GLPREFIX_QUOTED, "GetProgramiv");
_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)
@ -912,9 +939,50 @@ reset() {
get_extension_func(GLPREFIX_QUOTED, "UniformMatrix4fv");
_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)
get_extension_func(GLPREFIX_QUOTED, "ValidateProgram");
_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)
get_extension_func(GLPREFIX_QUOTED, "VertexAttribPointer");
}
#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
// In OpenGL ES 2.x, FBO's are supported in the core.
_supports_framebuffer_object = true;
@ -1123,6 +1191,10 @@ reset() {
}
#endif
#ifdef OPENGLES_2
// In OpenGL ES 2.x, this is supported in the core.
_glBlendEquation = glBlendEquation;
#else
_glBlendEquation = NULL;
bool supports_blend_equation = false;
if (is_at_least_gl_version(1, 2)) {
@ -1145,7 +1217,12 @@ reset() {
if (_glBlendEquation == NULL) {
_glBlendEquation = null_glBlendEquation;
}
#endif
#ifdef OPENGLES_2
// In OpenGL ES 2.x, this is supported in the core.
_glBlendColor = glBlendColor;
#else
_glBlendColor = NULL;
bool supports_blend_color = false;
if (is_at_least_gl_version(1, 2)) {
@ -1164,6 +1241,7 @@ reset() {
if (_glBlendColor == NULL) {
_glBlendColor = null_glBlendColor;
}
#endif
#ifdef OPENGLES
_edge_clamp = GL_CLAMP_TO_EDGE;
@ -4051,15 +4129,29 @@ do_issue_shade_model() {
// Description:
////////////////////////////////////////////////////////////////////
void CLP(GraphicsStateGuardian)::
do_issue_shader() {
do_issue_shader(bool state_has_changed) {
#ifndef OPENGLES_1
CLP(ShaderContext) *context = 0;
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) {
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) {
_current_shader_context->unbind(this);
_current_shader = 0;
@ -4076,8 +4168,13 @@ do_issue_shader() {
_current_shader = shader;
_current_shader_context = context;
} else {
// Use the same shader as before, but with new input arguments.
context->issue_parameters(this, Shader::SSD_shaderinputs);
#ifdef OPENGLES_2
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_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();
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
// GLSL shader functions
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 GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);
typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);
typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);
typedef void (APIENTRYP PFNGLDELETESHADERPROC) (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 GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);
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 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 PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
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 // __EDG__
@ -274,7 +280,7 @@ protected:
void do_issue_fog();
void do_issue_depth_offset();
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_texture();
void do_issue_blending();
@ -441,6 +447,9 @@ protected:
PT(Shader) _texture_binding_shader;
CLP(ShaderContext) *_texture_binding_shader_context;
#endif
#ifdef OPENGLES_2
PT(Shader) _default_shader;
#endif
#ifdef SUPPORT_IMMEDIATE_MODE
CLP(ImmediateModeSender) _sender;
@ -581,13 +590,18 @@ public:
#ifndef OPENGLES_1
// GLSL functions
PFNGLATTACHSHADERPROC _glAttachShader;
PFNGLBINDATTRIBLOCATIONPROC _glBindAttribLocation;
PFNGLCOMPILESHADERPROC _glCompileShader;
PFNGLCREATEPROGRAMPROC _glCreateProgram;
PFNGLCREATESHADERPROC _glCreateShader;
PFNGLDELETEPROGRAMPROC _glDeleteProgram;
PFNGLDELETESHADERPROC _glDeleteShader;
PFNGLDETACHSHADERPROC _glDetachShader;
PFNGLDISABLEVERTEXATTRIBARRAYPROC _glDisableVertexAttribArray;
PFNGLENABLEVERTEXATTRIBARRAYPROC _glEnableVertexAttribArray;
PFNGLGETACTIVEATTRIBPROC _glGetActiveAttrib;
PFNGLGETACTIVEUNIFORMPROC _glGetActiveUniform;
PFNGLGETATTRIBLOCATIONPROC _glGetAttribLocation;
PFNGLGETPROGRAMIVPROC _glGetProgramiv;
PFNGLGETPROGRAMINFOLOGPROC _glGetProgramInfoLog;
PFNGLGETSHADERIVPROC _glGetShaderiv;
@ -604,6 +618,7 @@ public:
PFNGLUNIFORM4FVPROC _glUniform4fv;
PFNGLUNIFORMMATRIX4FVPROC _glUniformMatrix4fv;
PFNGLVALIDATEPROGRAMPROC _glValidateProgram;
PFNGLVERTEXATTRIBPOINTERPROC _glVertexAttribPointer;
#endif
GLenum _edge_clamp;

View File

@ -73,9 +73,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
cgGetProfileString(cgGetProgramProfile(_cg_fprogram)) << " " << str << ")\n";
release_resources(gsg);
}
if (glGetError() != GL_NO_ERROR) {
GLCAT.error() << "GL error in ShaderContext constructor\n";
}
gsg->report_my_gl_errors();
if (_cg_gprogram != 0) {
cgGLLoadProgram(_cg_gprogram);
if (GLCAT.is_debug()) {
@ -90,9 +88,7 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
cgGetProfileString(cgGetProgramProfile(_cg_gprogram)) << " " << str << ")\n";
release_resources(gsg);
}
if (glGetError() != GL_NO_ERROR) {
GLCAT.error() << "GL error in ShaderContext constructor\n";
}
gsg->report_my_gl_errors();
}
}
#endif
@ -109,14 +105,13 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
// Analyze the uniforms and put them in _glsl_parameter_map
if (s->_glsl_parameter_map.size() == 0) {
int seqno = 0, texunitno = 0;
int num_uniforms, uniform_maxlength;
gsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_UNIFORMS, &num_uniforms);
gsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniform_maxlength);
for (int i = 0; i < num_uniforms; ++i) {
int param_size;
GLenum param_type;
char* param_name = new char[uniform_maxlength];
gsg->_glGetActiveUniform(_glsl_program, i, uniform_maxlength, NULL, &param_size, &param_type, param_name);
int param_count, param_maxlength, param_size;
GLenum param_type;
gsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_UNIFORMS, &param_count);
gsg->_glGetProgramiv(_glsl_program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &param_maxlength);
char* param_name = new char[param_maxlength];
for (int i = 0; i < param_count; ++i) {
gsg->_glGetActiveUniform(_glsl_program, i, param_maxlength, NULL, &param_size, &param_type, param_name);
GLint p = gsg->_glGetUniformLocation(_glsl_program, param_name);
if (p > -1) {
Shader::ShaderArgId arg_id;
@ -124,6 +119,18 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
arg_id._seqno = seqno++;
s->_glsl_parameter_map.push_back(p);
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") {
Shader::ShaderTexSpec bind;
bind._id = arg_id;
@ -230,10 +237,58 @@ CLP(ShaderContext)(Shader *s, GSG *gsg) : ShaderContext(s) {
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_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";
}
#endif
@ -300,10 +357,18 @@ release_resources(const GSG *gsg) {
// input parameters.
////////////////////////////////////////////////////////////////////
void CLP(ShaderContext)::
bind(GSG *gsg) {
bind(GSG *gsg, bool reissue_parameters) {
_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
if (_cg_context != 0) {
@ -320,13 +385,8 @@ bind(GSG *gsg) {
cg_report_errors();
}
#endif
if (_shader->get_language() == Shader::SL_GLSL && !_shader->get_error_flag()) {
gsg->_glUseProgram(_glsl_program);
}
if (glGetError() != GL_NO_ERROR) {
GLCAT.error() << "GL error in ShaderContext::bind\n";
}
gsg->report_my_gl_errors();
}
////////////////////////////////////////////////////////////////////
@ -353,9 +413,7 @@ unbind(GSG *gsg) {
if (_shader->get_language() == Shader::SL_GLSL) {
gsg->_glUseProgram(0);
}
if (glGetError() != GL_NO_ERROR) {
GLCAT.error() << "GL error in ShaderContext::unbind\n";
}
gsg->report_my_gl_errors();
}
////////////////////////////////////////////////////////////////////
@ -432,9 +490,7 @@ issue_parameters(GSG *gsg, int altered) {
cg_report_errors();
#endif
if (glGetError() != GL_NO_ERROR) {
GLCAT.error() << "GL error in ShaderContext::issue_parameters\n";
}
gsg->report_my_gl_errors();
}
////////////////////////////////////////////////////////////////////
@ -445,22 +501,27 @@ issue_parameters(GSG *gsg, int altered) {
void CLP(ShaderContext)::
disable_shader_vertex_arrays(GSG *gsg) {
_last_gsg = gsg;
#ifdef HAVE_CG
if (_cg_context == 0) {
if (!valid()) {
return;
}
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);
if (_shader->get_language() == Shader::SL_GLSL) {
for (int i=0; i<(int)_shader->_var_spec.size(); i++) {
glDisableVertexAttribArray(i);
}
}
cg_report_errors();
if (glGetError() != GL_NO_ERROR) {
GLCAT.error() << "GL error in ShaderContext::disable_shader_vertex_arrays\n";
#ifdef HAVE_CG
else if (_shader->get_language() == Shader::SL_Cg) {
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
gsg->report_my_gl_errors();
}
////////////////////////////////////////////////////////////////////
@ -479,11 +540,12 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg,
bool force) {
_last_gsg = gsg;
if (prev) prev->disable_shader_vertex_arrays(gsg);
#ifdef HAVE_CG
if (!valid()) {
return true;
}
#ifdef HAVE_CG
cg_report_errors();
#endif
#ifdef SUPPORT_IMMEDIATE_MODE
if (gsg->_use_sender) {
@ -496,8 +558,14 @@ update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg,
int start, stride, num_values;
int nvarying = _shader->_var_spec.size();
for (int i=0; i<nvarying; i++) {
CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
if (p == 0) continue;
#ifdef HAVE_CG
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;
int texslot = _shader->_var_spec[i]._append_uv;
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)) {
return false;
}
cgGLSetParameterPointer(p,
num_values, gsg->get_numeric_type(numeric_type),
stride, client_pointer + start);
cgGLEnableClientState(p);
} else {
if (_shader->get_language() == Shader::SL_GLSL) {
#ifndef OPENGLES_2
glEnableClientState(GL_VERTEX_ARRAY);
#endif
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);
}
#endif
}
}
#ifdef HAVE_CG
cg_report_errors();
if (glGetError() != GL_NO_ERROR) {
GLCAT.error() << "GL error in ShaderContext::update_shader_vertex_arrays\n";
}
#endif // HAVE_CG
#endif
gsg->report_my_gl_errors();
return true;
}
@ -586,9 +672,7 @@ disable_shader_texture_bindings(GSG *gsg) {
cg_report_errors();
#endif
if (glGetError() != GL_NO_ERROR) {
GLCAT.error() << "GL error in ShaderContext::disable_shader_texture_bindings\n";
}
gsg->report_my_gl_errors();
}
////////////////////////////////////////////////////////////////////
@ -694,9 +778,7 @@ update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg) {
cg_report_errors();
#endif
if (glGetError() != GL_NO_ERROR) {
GLCAT.error() << "GL error in ShaderContext::update_shader_texture_bindings\n";
}
gsg->report_my_gl_errors();
}
////////////////////////////////////////////////////////////////////
@ -725,14 +807,16 @@ glsl_report_shader_errors(GSG *gsg, unsigned int shader) {
int length = 0;
int num_chars = 0;
gsg->_glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
gsg->_glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
if (length > 0) {
info_log = (char *) malloc(length);
gsg->_glGetShaderInfoLog(shader, length, &num_chars, info_log);
GLCAT.error(false) << info_log;
free(info_log);
if (strcmp(info_log, "Success.\n") != 0) {
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 num_chars = 0;
gsg->_glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
gsg->_glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
if (length > 0) {
info_log = (char *) malloc(length);
gsg->_glGetProgramInfoLog(program, length, &num_chars, info_log);
GLCAT.error(false) << info_log;
free(info_log);
if (strcmp(info_log, "Success.\n") != 0) {
GLCAT.error(false) << info_log;
}
}
delete[] info_log;
}
////////////////////////////////////////////////////////////////////
@ -762,16 +848,16 @@ glsl_report_program_errors(GSG *gsg, unsigned int program) {
// Description:
////////////////////////////////////////////////////////////////////
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;
switch (type) {
case Shader::ST_VERTEX:
case Shader::ST_vertex:
handle = gsg->_glCreateShader(GL_VERTEX_SHADER);
break;
case Shader::ST_FRAGMENT:
case Shader::ST_fragment:
handle = gsg->_glCreateShader(GL_FRAGMENT_SHADER);
break;
case Shader::ST_GEOMETRY:
case Shader::ST_geometry:
handle = gsg->_glCreateShader(GL_GEOMETRY_SHADER);
break;
default:
@ -780,16 +866,13 @@ glsl_compile_entry_point(GSG *gsg, const char *entry, Shader::ShaderType type) {
if (!handle) {
return 0;
}
// We define our own main() in which we call the right function.
ostringstream str;
str << "void main() { " << entry << "(); };";
const char* sources[2] = {_shader->_text.c_str(), str.str().c_str()};
gsg->_glShaderSource(handle, 2, sources, NULL);
const char* text = _shader->get_text(type).c_str();
gsg->_glShaderSource(handle, 1, &text, NULL);
gsg->_glCompileShader(handle);
int status;
gsg->_glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
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);
gsg->_glDeleteShader(handle);
return 0;
@ -810,38 +893,24 @@ glsl_compile_shader(GSG *gsg) {
_glsl_program = gsg->_glCreateProgram();
if (!_glsl_program) return false;
if (_shader->_text.find("vshader") != -1) {
_glsl_vshader = glsl_compile_entry_point(gsg, "vshader", Shader::ST_VERTEX);
if (!_shader->get_text(Shader::ST_vertex).empty()) {
_glsl_vshader = glsl_compile_entry_point(gsg, Shader::ST_vertex);
if (!_glsl_vshader) return false;
gsg->_glAttachShader(_glsl_program, _glsl_vshader);
} else {
GLCAT.warning() << "Could not locate function 'vshader' in shader text!\n";
}
if (_shader->_text.find("fshader") != -1) {
_glsl_fshader = glsl_compile_entry_point(gsg, "fshader", Shader::ST_FRAGMENT);
if (!_shader->get_text(Shader::ST_fragment).empty()) {
_glsl_fshader = glsl_compile_entry_point(gsg, Shader::ST_fragment);
if (!_glsl_fshader) return false;
gsg->_glAttachShader(_glsl_program, _glsl_fshader);
} else {
GLCAT.warning() << "Could not locate function 'fshader' in shader text!\n";
}
if (_shader->_text.find("gshader") != -1) {
_glsl_gshader = glsl_compile_entry_point(gsg, "gshader", Shader::ST_GEOMETRY);
if (!_shader->get_text(Shader::ST_geometry).empty()) {
_glsl_gshader = glsl_compile_entry_point(gsg, Shader::ST_geometry);
if (!_glsl_gshader) return false;
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.
if (_glsl_vshader != 0) {
glsl_report_shader_errors(gsg, _glsl_vshader);
@ -851,10 +920,17 @@ glsl_compile_shader(GSG *gsg) {
glsl_report_shader_errors(gsg, _glsl_gshader);
}
if (glGetError() != GL_NO_ERROR) {
GLCAT.error() << "Failed to compile shader\n";
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;
}
gsg->report_my_gl_errors();
return true;
}

View File

@ -27,9 +27,9 @@ class CLP(GraphicsStateGuardian);
// Class : GLShaderContext
// Description : xyz
////////////////////////////////////////////////////////////////////
class EXPCL_GL CLP(ShaderContext): public ShaderContext {
public:
friend class CLP(GraphicsStateGuardian);
typedef CLP(GraphicsStateGuardian) GSG;
CLP(ShaderContext)(Shader *s, GSG *gsg);
@ -37,7 +37,7 @@ public:
ALLOC_DELETED_CHAIN(CLP(ShaderContext));
INLINE bool valid(void);
void bind(GSG *gsg);
void bind(GSG *gsg, bool reissue_parameters = true);
void unbind(GSG *gsg);
void issue_parameters(GSG *gsg, int altered);
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_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);
void release_resources(const GSG *gsg);

View File

@ -13,33 +13,68 @@
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: Shader::get_filename
// Access: Public
// Description: Return the Shader's filename.
// Function: Shader::get_filename
// Access: Public
// Description: Return the Shader's filename for the given shader
// type.
////////////////////////////////////////////////////////////////////
INLINE const Filename &Shader::
get_filename() const {
return _filename;
INLINE const Filename Shader::
get_filename(const ShaderType &type) const {
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
// Access: Public
// Description: Return the Shader's text.
// Function: Shader::get_text
// Access: Public
// Description: Return the Shader's text for the given shader type.
////////////////////////////////////////////////////////////////////
INLINE const string &Shader::
get_text() const {
return _text;
INLINE const string Shader::
get_text(const ShaderType &type) const {
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
// Access: Public
// Function: Shader::get_error_flag
// Access: Public
// Description: Returns true if the shader contains a compile-time
// error. This doesn't tell you whether or not the
// shader is supported on the current video card.
////////////////////////////////////////////////////////////////////
INLINE bool Shader::
INLINE const bool Shader::
get_error_flag() const {
return _error_flag;
}

View File

@ -24,8 +24,8 @@
#endif
TypeHandle Shader::_type_handle;
Shader::LoadTable Shader::_load_table;
Shader::MakeTable Shader::_make_table;
Shader::ShaderTable Shader::_load_table;
Shader::ShaderTable Shader::_make_table;
Shader::ShaderCaps Shader::_default_caps;
int Shader::_shaders_generated;
ShaderUtilization Shader::_shader_utilization = SUT_UNSPECIFIED;
@ -37,8 +37,7 @@ ShaderUtilization Shader::_shader_utilization = SUT_UNSPECIFIED;
// of the specified parameter.
////////////////////////////////////////////////////////////////////
void Shader::
cp_report_error(ShaderArgInfo &p, const string &msg)
{
cp_report_error(ShaderArgInfo &p, const string &msg) {
string vstr;
if (p._varying) vstr = "varying ";
else vstr = "uniform ";
@ -62,7 +61,7 @@ cp_report_error(ShaderArgInfo &p, const string &msg)
case SAT_unknown: tstr = "unknown "; break;
}
Filename fn = get_filename();
Filename fn = get_filename(p._id._type);
p._cat->error() << fn << ": " << msg << " (" <<
vstr << dstr << tstr << p._id._name << ")\n";
}
@ -1107,12 +1106,10 @@ cg_release_resources() {
cgDestroyProgram(_cg_fprogram);
_cg_fprogram = 0;
}
// BEGIN CG2 CHANGE
if (_cg_gprogram != 0) {
cgDestroyProgram(_cg_gprogram);
_cg_gprogram = 0;
}
// END CG2 CHANGE
if (_cg_context != 0) {
cgDestroyContext(_cg_context);
_cg_context = 0;
@ -1129,40 +1126,50 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
CGprogram prog;
CGerror err;
const char *compiler_args[100];
const string text;
if (!_text->_separate) {
text = _text->_shared;
}
int nargs = 0;
int active, ultimate;
switch(type)
{
case ST_VERTEX:
switch(type) {
case ST_vertex:
active = caps._active_vprofile;
ultimate = caps._ultimate_vprofile;
if (_text->_separate) {
text = _text._vertex;
}
break;
case ST_FRAGMENT:
case ST_fragment:
active = caps._active_fprofile;
ultimate = caps._ultimate_fprofile;
if (_text->_separate) {
text = _text._fragment;
}
break;
case ST_GEOMETRY:
case ST_geometry:
active = caps._active_gprofile;
ultimate = caps._ultimate_gprofile;
if (_text->_separate) {
text = _text._geometry;
}
break;
};
// END CG2 CHANGE
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++] = "ATI_draw_buffers";
}
compiler_args[nargs] = 0;
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);
err = cgGetError();
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);
err = cgGetError();
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++) {
string line = trim(errlines[i]);
if (line != "") {
gobj_cat.error() << get_filename() << ": " << errlines[i] << "\n";
gobj_cat.error() << get_filename(type) << ": " << errlines[i] << "\n";
}
}
} else {
gobj_cat.error() << get_filename() << ": " << cgGetErrorString(err) << "\n";
gobj_cat.error() << get_filename(type) << ": " << cgGetErrorString(err) << "\n";
}
if (prog != 0) {
cgDestroyProgram(prog);
@ -1209,8 +1216,6 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps, ShaderType typ
bool Shader::
cg_compile_shader(const ShaderCaps &caps) {
// If we already tried compiling for this set of caps, there's no point
// trying again. Just return the results of the previous compile.
if (caps == _cg_last_caps) {
@ -1225,18 +1230,25 @@ cg_compile_shader(const ShaderCaps &caps) {
_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) {
gobj_cat.error() << "could not create a Cg context object.\n";
return false;
}
_cg_vprogram = cg_compile_entry_point("vshader", caps, ST_VERTEX); // CG2 CHANGE
_cg_fprogram = cg_compile_entry_point("fshader", caps, ST_FRAGMENT); // CG2 CHANGE
if (!_text->_separate || !_text._vertex.empty()) {
_cg_vprogram = cg_compile_entry_point("vshader", caps, ST_vertex);
}
if (_text.find("gshader") != -1) {
_cg_gprogram = cg_compile_entry_point("gshader", caps, ST_GEOMETRY);
if (!_text->_separate || !_text._fragment.empty()) {
_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)) {
@ -1317,7 +1329,7 @@ cg_analyze_shader(const ShaderCaps &caps) {
return false;
}
if (!cg_analyze_entry_point(_cg_fprogram, ST_FRAGMENT)) {
if (!cg_analyze_entry_point(_cg_fprogram, ST_fragment)) {
cg_release_resources();
clear_parameters();
return false;
@ -1330,14 +1342,14 @@ cg_analyze_shader(const ShaderCaps &caps) {
return false;
}
if (!cg_analyze_entry_point(_cg_vprogram, ST_VERTEX)) {
if (!cg_analyze_entry_point(_cg_vprogram, ST_vertex)) {
cg_release_resources();
clear_parameters();
return false;
}
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();
clear_parameters();
return false;
@ -1463,15 +1475,15 @@ cg_program_from_shadertype(ShaderType type) {
CGprogram prog = 0;
switch(type) {
case ST_VERTEX:
case ST_vertex:
prog = _cg_vprogram;
break;
case ST_FRAGMENT:
case ST_fragment:
prog = _cg_fprogram;
break;
case ST_GEOMETRY:
case ST_geometry:
prog = _cg_gprogram;
break;
};
@ -1580,7 +1592,7 @@ cg_compile_for(const ShaderCaps &caps,
// Description: Construct a Shader.
////////////////////////////////////////////////////////////////////
Shader::
Shader(const Filename &filename, const string &text, const ShaderLanguage &lang) :
Shader(CPT(ShaderFile) filename, CPT(ShaderFile) text, const ShaderLanguage &lang) :
_filename(filename),
_text(text),
_error_flag(true),
@ -1622,7 +1634,9 @@ Shader(const Filename &filename, const string &text, const ShaderLanguage &lang)
if (_language == SL_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)) {
_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";
#endif
} else if (_language == SL_GLSL) {
// All of the important stuff is done in glShaderContext.
_language = SL_GLSL;
// All of the important stuff is done in glShaderContext,
// 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 {
gobj_cat.error()
<< "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
// Access: Published, Static
// 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::
load(const string &file) {
return load(Filename(file));
load(const Filename &file, const ShaderLanguage &lang) {
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
// Access: Published, Static
// 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.
// Description: This variant of Shader::load loads all shader
// programs separately.
////////////////////////////////////////////////////////////////////
PT(Shader) Shader::
load(const Filename &file) {
LoadTable::const_iterator i = _load_table.find(file);
if (i != _load_table.end()) {
load(const ShaderLanguage &lang, const Filename &vertex, const Filename &fragment, const Filename &geometry) {
PT(ShaderFile) sfile = new ShaderFile(vertex, fragment, geometry);
ShaderTable::const_iterator i = _load_table.find(sfile);
if (i != _load_table.end() && (lang == SL_none || lang == i->second->_language)) {
return i->second;
}
string body;
PT(ShaderFile) sbody = new ShaderFile("", "", "");
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
if (!vfs->read_file(file, body, true)) {
gobj_cat.error() << "Could not read shader file: " << file << "\n";
if (!vertex.empty() && !vfs->read_file(vertex, sbody->_vertex, true)) {
gobj_cat.error() << "Could not read vertex shader file: " << vertex << "\n";
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;
_load_table[file] = result;
_load_table[sfile] = result;
return result;
}
@ -1811,20 +1844,17 @@ load(const Filename &file) {
// Function: Shader::make
// Access: Published, Static
// 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::
make(const string &body) {
MakeTable::const_iterator i = _make_table.find(body);
if (i != _make_table.end()) {
make(const string &body, const ShaderLanguage &lang) {
PT(ShaderFile) sbody = new ShaderFile(body);
ShaderTable::const_iterator i = _make_table.find(sbody);
if (i != _make_table.end() && (lang == SL_none || lang == i->second->_language)) {
return i->second;
}
PT(Shader) result = new Shader("created-shader", body);
_make_table[body] = result;
PT(ShaderFile) sfile = new ShaderFile("created-shader");
PT(Shader) result = new Shader(sfile, sbody, lang);
_make_table[sbody] = result;
if (dump_generated_shaders) {
ostringstream fns;
int index = _shaders_generated ++;
@ -1839,6 +1869,24 @@ make(const string &body) {
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
// Access: Public
@ -1859,10 +1907,11 @@ parse_init() {
////////////////////////////////////////////////////////////////////
void Shader::
parse_line(string &result, bool lt, bool rt) {
int len = _text.size();
nassertv(!_text->_separate);
int len = _text->_shared.size();
int head = _parse;
int tail = head;
while ((tail < len) && (_text[tail] != '\n')) {
while ((tail < len) && (_text->_shared[tail] != '\n')) {
tail++;
}
if (tail < len) {
@ -1871,10 +1920,10 @@ parse_line(string &result, bool lt, bool rt) {
_parse = tail;
}
if (lt) {
while ((head < tail)&&(isspace(_text[head]))) head++;
while ((tail > head)&&(isspace(_text[tail-1]))) tail--;
while ((head < tail)&&(isspace(_text->_shared[head]))) head++;
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::
parse_upto(string &result, string pattern, bool include) {
nassertv(!_text->_separate);
GlobPattern endpat(pattern);
int start = _parse;
int last = _parse;
while (_parse < (int)(_text.size())) {
while (_parse < (int)(_text->_shared.size())) {
string t;
parse_line(t, true, true);
if (endpat.matches(t)) break;
last = _parse;
}
if (include) {
result = _text.substr(start, _parse - start);
result = _text->_shared.substr(start, _parse - start);
} 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::
parse_rest(string &result) {
result = _text.substr(_parse, _text.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;
nassertv(!_text->_separate);
result = _text->_shared.substr(_parse, _text->_shared.size() - _parse);
}
////////////////////////////////////////////////////////////////////
@ -1936,7 +1973,7 @@ parse_lineno() {
////////////////////////////////////////////////////////////////////
bool Shader::
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
// 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
// (or old) ShaderContext. This assumes that the
// GraphicsStateGuardian is the currently active
@ -2010,7 +2047,7 @@ release(PreparedGraphicsObjects *prepared_objects) {
// should use prepare() instead.
//
// 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
// rendered.
////////////////////////////////////////////////////////////////////

View File

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