mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 18:03:56 -04:00
More robust Cg support on non-NVIDIA card + automatically enable hardware skinning in Shader Generator
This commit is contained in:
parent
1088cdedc8
commit
ef9908c277
@ -814,17 +814,12 @@ dispatch_compute(int num_groups_x, int num_groups_y, int num_groups_z) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(GeomMunger) GraphicsStateGuardian::
|
||||
get_geom_munger(const RenderState *state, Thread *current_thread) {
|
||||
// We can cast the RenderState to a non-const object because we are
|
||||
// only updating a cache within the RenderState, not really changing
|
||||
// any of its properties.
|
||||
RenderState *nc_state = ((RenderState *)state);
|
||||
|
||||
// Before we even look up the map, see if the _last_mi value points
|
||||
// to this GSG. This is likely because we tend to visit the same
|
||||
// state multiple times during a frame. Also, this might well be
|
||||
// the only GSG in the world anyway.
|
||||
if (!nc_state->_mungers.empty()) {
|
||||
RenderState::Mungers::const_iterator mi = nc_state->_last_mi;
|
||||
if (!state->_mungers.empty()) {
|
||||
RenderState::Mungers::const_iterator mi = state->_last_mi;
|
||||
if (!(*mi).first.was_deleted() && (*mi).first == this) {
|
||||
if ((*mi).second->is_registered()) {
|
||||
return (*mi).second;
|
||||
@ -833,23 +828,23 @@ get_geom_munger(const RenderState *state, Thread *current_thread) {
|
||||
}
|
||||
|
||||
// Nope, we have to look it up in the map.
|
||||
RenderState::Mungers::iterator mi = nc_state->_mungers.find(this);
|
||||
if (mi != nc_state->_mungers.end() && !(*mi).first.was_deleted()) {
|
||||
RenderState::Mungers::iterator mi = state->_mungers.find(this);
|
||||
if (mi != state->_mungers.end() && !(*mi).first.was_deleted()) {
|
||||
if ((*mi).second->is_registered()) {
|
||||
nc_state->_last_mi = mi;
|
||||
state->_last_mi = mi;
|
||||
return (*mi).second;
|
||||
}
|
||||
// This GeomMunger is no longer registered. Remove it from the
|
||||
// map.
|
||||
nc_state->_mungers.erase(mi);
|
||||
state->_mungers.erase(mi);
|
||||
}
|
||||
|
||||
// Nothing in the map; create a new entry.
|
||||
PT(GeomMunger) munger = make_geom_munger(nc_state, current_thread);
|
||||
PT(GeomMunger) munger = make_geom_munger(state, current_thread);
|
||||
nassertr(munger != (GeomMunger *)NULL && munger->is_registered(), munger);
|
||||
|
||||
mi = nc_state->_mungers.insert(RenderState::Mungers::value_type(this, munger)).first;
|
||||
nc_state->_last_mi = mi;
|
||||
mi = state->_mungers.insert(RenderState::Mungers::value_type(this, munger)).first;
|
||||
state->_last_mi = mi;
|
||||
|
||||
return munger;
|
||||
}
|
||||
|
@ -131,7 +131,8 @@ munge_data_impl(const GeomVertexData *data) {
|
||||
}
|
||||
|
||||
GeomVertexAnimationSpec animation = new_data->get_format()->get_animation();
|
||||
if (_shader_skinning) {
|
||||
if (_shader_skinning || (_auto_shader && hardware_animated_vertices &&
|
||||
!basic_shaders_only && animation.get_animation_type() == AT_panda)) {
|
||||
animation.set_hardware(4, true);
|
||||
|
||||
} else if (hardware_animated_vertices &&
|
||||
@ -387,7 +388,17 @@ munge_state_impl(const RenderState *state) {
|
||||
}
|
||||
if (shader_state->_generated_shader == NULL) {
|
||||
// Cache the generated ShaderAttrib on the shader state.
|
||||
shader_state->_generated_shader = shader_generator->synthesize_shader(shader_state);
|
||||
GeomVertexAnimationSpec spec;
|
||||
|
||||
// Currently we overload this flag to request vertex animation
|
||||
// for the shader generator.
|
||||
const ShaderAttrib *sattr;
|
||||
shader_state->get_attrib_def(sattr);
|
||||
if (sattr->get_flag(ShaderAttrib::F_hardware_skinning)) {
|
||||
spec.set_hardware(4, true);
|
||||
}
|
||||
|
||||
shader_state->_generated_shader = shader_generator->synthesize_shader(shader_state, spec);
|
||||
}
|
||||
munged_state = munged_state->set_attrib(shader_state->_generated_shader);
|
||||
}
|
||||
|
@ -41,6 +41,11 @@ CLP(CgShaderContext)::
|
||||
CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext(s) {
|
||||
_glgsg = glgsg;
|
||||
_cg_program = 0;
|
||||
_glsl_program = 0;
|
||||
_has_divisor = false;
|
||||
_color_attrib_index = CA_color;
|
||||
_transform_table_param = 0;
|
||||
_slider_table_param = 0;
|
||||
|
||||
nassertv(s->get_language() == Shader::SL_Cg);
|
||||
|
||||
@ -53,6 +58,21 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
|
||||
return;
|
||||
}
|
||||
|
||||
_transform_table_param = cgGetNamedParameter(_cg_program, "tbl_transforms");
|
||||
if (_transform_table_param) {
|
||||
_transform_table_size = cgGetArraySize(_transform_table_param, 0);
|
||||
}
|
||||
|
||||
_slider_table_param = cgGetNamedParameter(_cg_program, "tbl_sliders");
|
||||
if (_slider_table_param) {
|
||||
_slider_table_size = cgGetArraySize(_slider_table_param, 0);
|
||||
}
|
||||
|
||||
if (GLCAT.is_debug()) {
|
||||
GLCAT.debug()
|
||||
<< "Loading Cg shader " << s->get_filename() << "\n";
|
||||
}
|
||||
|
||||
// Load the program.
|
||||
if (_cg_program == 0) {
|
||||
const char *str = cgGetErrorString(cgGetError());
|
||||
@ -73,6 +93,214 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
|
||||
}
|
||||
}
|
||||
|
||||
if (_cg_program != 0) {
|
||||
if (cgGetProgramProfile(_cg_program) == CG_PROFILE_GLSLC) {
|
||||
_glsl_program = cgGLGetProgramID(_cg_program);
|
||||
|
||||
// Sometimes it fails to link, and Cg fails to propagate the error.
|
||||
GLint link_status;
|
||||
_glgsg->_glGetProgramiv(_glsl_program, GL_LINK_STATUS, &link_status);
|
||||
if (link_status != GL_TRUE) {
|
||||
release_resources();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_cg_program == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't use cgGLSetParameterPointer to set the vertex attributes any
|
||||
// longer, since it is buggy on non-NVIDIA hardware and doesn't allow explicit
|
||||
// control over some parameters. Instead, we have to figure out ourselves how
|
||||
// to map the input varyings to OpenGL vertex attributes.
|
||||
//
|
||||
// We use positive indices to indicate generic vertex attributes, and negative
|
||||
// indices to indicate conventional vertex attributes (ie. glVertexPointer).
|
||||
int nvarying = _shader->_var_spec.size();
|
||||
for (int i = 0; i < nvarying; ++i) {
|
||||
Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
|
||||
CGparameter p = _cg_parameter_map[i];
|
||||
if (p == 0) {
|
||||
bind._id._seqno = CA_unknown;
|
||||
continue;
|
||||
}
|
||||
|
||||
GLint loc = CA_unknown;
|
||||
CGresource res = cgGetParameterResource(p);
|
||||
|
||||
if (cgGetParameterBaseResource(p) == CG_ATTR0) {
|
||||
// The Cg toolkit claims that it is bound to a generic vertex attribute.
|
||||
if (_glsl_program != 0) {
|
||||
// This is where the Cg glslv compiler lies, making the stupid assumption
|
||||
// that we're using an NVIDIA card where generic attributes are aliased
|
||||
// with conventional vertex attributes. Instead, it always uses
|
||||
// conventional attributes in this case. Correct this.
|
||||
int index = cgGetParameterResourceIndex(p);
|
||||
switch (index) {
|
||||
case 0: // gl_Vertex
|
||||
loc = CA_vertex;
|
||||
break;
|
||||
case 2: // gl_Normal
|
||||
loc = CA_normal;
|
||||
break;
|
||||
case 3: // gl_Color
|
||||
loc = CA_color;
|
||||
break;
|
||||
case 4: // gl_SecondaryColor
|
||||
loc = CA_secondary_color;
|
||||
break;
|
||||
case 1: // glWeightPointerARB?
|
||||
case 5: // gl_FogCoord
|
||||
case 6: // PSIZE?
|
||||
case 7: // BLENDINDICES
|
||||
GLCAT.error()
|
||||
<< "Cg varying " << cgGetParameterName(p) << " is bound to "
|
||||
"unrecognized attribute " << index << "\n";
|
||||
loc = CA_unknown;
|
||||
break;
|
||||
default:
|
||||
loc = CA_texcoord + (index - 8);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
loc = cgGetParameterResourceIndex(p);
|
||||
|
||||
if (loc != 0 && bind._id._name == "vtx_position") {
|
||||
// We really have to bind the vertex position to attribute 0, since
|
||||
// OpenGL will hide the model if attribute 0 is not enabled, and we
|
||||
// can only ever be sure that vtx_position is bound.
|
||||
GLCAT.warning()
|
||||
<< "CG varying vtx_position is bound to generic attribute " << loc
|
||||
<< "instead of 0. Use ATTR0 semantic to prevent this.\n";
|
||||
}
|
||||
}
|
||||
|
||||
} else if (res == CG_GLSL_ATTRIB || _glsl_program != 0) {
|
||||
// With cg-glsl-version 130 and higher, no conventional attributes are
|
||||
// used, but it instead uses specially named variables.
|
||||
// A bit of guesswork is involved here; Cg seems to mostly use the
|
||||
// semantics as attribute names in GLSL, with a few exceptions.
|
||||
const char *attribname = NULL;
|
||||
switch (res) {
|
||||
case CG_POSITION0:
|
||||
attribname = "cg_Vertex";
|
||||
break;
|
||||
case CG_NORMAL0:
|
||||
attribname = "NORMAL";
|
||||
break;
|
||||
case CG_COLOR0:
|
||||
case CG_DIFFUSE0:
|
||||
attribname = "COLOR";
|
||||
break;
|
||||
case CG_COLOR1:
|
||||
case CG_SPECULAR0:
|
||||
attribname = "SPECULAR";
|
||||
break;
|
||||
default:
|
||||
// Everything else appears to be named after the semantic string.
|
||||
attribname = cgGetParameterSemantic(p);
|
||||
}
|
||||
loc = _glgsg->_glGetAttribLocation(_glsl_program, attribname);
|
||||
|
||||
if (bind._id._name == "vtx_color") {
|
||||
_color_attrib_index = loc;
|
||||
}
|
||||
|
||||
if (loc == -1) {
|
||||
const char *resource = cgGetParameterResourceName(p);
|
||||
if (!resource) {
|
||||
resource = "unknown";
|
||||
}
|
||||
GLCAT.error()
|
||||
<< "Could not find Cg varying " << cgGetParameterName(p);
|
||||
if (attribname) {
|
||||
GLCAT.error(false) << " : " << attribname;
|
||||
}
|
||||
GLCAT.error(false) << " (" << resource << ") in the compiled GLSL program.\n";
|
||||
|
||||
} else if (loc != 0 && bind._id._name == "vtx_position") {
|
||||
// We really have to bind the vertex position to attribute 0, since
|
||||
// OpenGL will hide the model if attribute 0 is not enabled, and we
|
||||
// can only ever be sure that vtx_position is bound.
|
||||
GLCAT.warning()
|
||||
<< "CG varying vtx_position is bound to generic attribute " << loc
|
||||
<< "instead of 0. Use ATTR0 semantic to prevent this.\n";
|
||||
}
|
||||
|
||||
} else if (cgGetParameterBaseResource(p) == CG_TEXCOORD0) {
|
||||
// A conventional texture coordinate set.
|
||||
loc = CA_texcoord + cgGetParameterResourceIndex(p);
|
||||
|
||||
} else {
|
||||
// Some other conventional vertex attribute.
|
||||
switch (res) {
|
||||
case CG_POSITION0:
|
||||
loc = CA_vertex;
|
||||
break;
|
||||
case CG_NORMAL0:
|
||||
loc = CA_normal;
|
||||
break;
|
||||
case CG_COLOR0:
|
||||
case CG_DIFFUSE0:
|
||||
loc = CA_color;
|
||||
break;
|
||||
case CG_COLOR1:
|
||||
case CG_SPECULAR0:
|
||||
loc = CA_secondary_color;
|
||||
break;
|
||||
default:
|
||||
GLCAT.error()
|
||||
<< "Cg varying " << cgGetParameterName(p);
|
||||
if (cgGetParameterSemantic(p)) {
|
||||
GLCAT.error(false) << " : " << cgGetParameterSemantic(p);
|
||||
}
|
||||
GLCAT.error(false) << " has an unrecognized resource";
|
||||
if (cgGetParameterResourceName(p)) {
|
||||
GLCAT.error(false) << " (" << cgGetParameterResourceName(p) << ")";
|
||||
}
|
||||
GLCAT.error(false) << ".\n";
|
||||
loc = CA_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (GLCAT.is_debug()) {
|
||||
GLCAT.debug()
|
||||
<< "Cg varying " << cgGetParameterName(p);
|
||||
|
||||
const char *semantic = cgGetParameterSemantic(p);
|
||||
if (semantic) {
|
||||
GLCAT.debug(false) << " : " << semantic;
|
||||
}
|
||||
|
||||
if (loc == CA_unknown) {
|
||||
GLCAT.debug(false)
|
||||
<< " is not bound to a vertex attribute\n";
|
||||
|
||||
} else if (loc >= 0) {
|
||||
GLCAT.debug(false)
|
||||
<< " is bound to generic attribute " << loc << "\n";
|
||||
|
||||
} else {
|
||||
const char *resource = cgGetParameterResourceName(p);
|
||||
if (!resource) {
|
||||
resource = "unknown";
|
||||
}
|
||||
GLCAT.debug(false)
|
||||
<< " is bound to a conventional attribute (" << resource << ")\n";
|
||||
}
|
||||
}
|
||||
if (loc == CA_unknown) {
|
||||
// Suggest fix to developer.
|
||||
GLCAT.error() << "Try using a different semantic.\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
// Abuse the seqno field to store the GLSL attribute location.
|
||||
bind._id._seqno = loc;
|
||||
}
|
||||
|
||||
_glgsg->report_my_gl_errors();
|
||||
}
|
||||
|
||||
@ -385,6 +613,58 @@ issue_parameters(int altered) {
|
||||
_glgsg->report_my_gl_errors();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CgGLShaderContext::update_transform_table
|
||||
// Access: Public
|
||||
// Description: Changes the active transform table, used for hardware
|
||||
// skinning.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CLP(CgShaderContext)::
|
||||
update_transform_table(const TransformTable *table) {
|
||||
LMatrix4f *matrices = (LMatrix4f *)alloca(_transform_table_size * 64);
|
||||
|
||||
int i = 0;
|
||||
if (table != NULL) {
|
||||
int num_transforms = min(_transform_table_size, (long)table->get_num_transforms());
|
||||
for (; i < num_transforms; ++i) {
|
||||
#ifdef STDFLOAT_DOUBLE
|
||||
LMatrix4 matrix;
|
||||
table->get_transform(i)->get_matrix(matrix);
|
||||
matrices[i] = LCAST(float, matrix);
|
||||
#else
|
||||
table->get_transform(i)->get_matrix(matrices[i]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
for (; i < _transform_table_size; ++i) {
|
||||
matrices[i] = LMatrix4f::ident_mat();
|
||||
}
|
||||
|
||||
cgGLSetMatrixParameterArrayfc(_transform_table_param, 0,
|
||||
_transform_table_size, (float *)matrices);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CgGLShaderContext::update_slider_table
|
||||
// Access: Public
|
||||
// Description: Changes the active slider table, used for hardware
|
||||
// skinning.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CLP(CgShaderContext)::
|
||||
update_slider_table(const SliderTable *table) {
|
||||
float *sliders = (float *)alloca(_slider_table_size * 4);
|
||||
memset(sliders, 0, _slider_table_size * 4);
|
||||
|
||||
if (table != NULL) {
|
||||
int num_sliders = min(_slider_table_size, (long)table->get_num_sliders());
|
||||
for (int i = 0; i < num_sliders; ++i) {
|
||||
sliders[i] = table->get_slider(i)->get_slider();
|
||||
}
|
||||
}
|
||||
|
||||
cgGLSetParameterArray4f(_slider_table_param, 0, _slider_table_size, sliders);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GLCgShaderContext::disable_shader_vertex_arrays
|
||||
// Access: Public
|
||||
@ -396,27 +676,35 @@ disable_shader_vertex_arrays() {
|
||||
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;
|
||||
for (int i = 0; i < (int)_shader->_var_spec.size(); ++i) {
|
||||
GLint p = _shader->_var_spec[i]._id._seqno;
|
||||
|
||||
if (cgGetParameterBaseResource(p) == CG_ATTR0) {
|
||||
int index = cgGetParameterResourceIndex(p);
|
||||
if (index >= 8) {
|
||||
_glgsg->_glClientActiveTexture(GL_TEXTURE0 + (index - 8));
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
} else if (index == 0) {
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
} else if (index == 2) {
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
|
||||
} else if (index == 3) {
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
if (p >= 0) {
|
||||
_glgsg->_glDisableVertexAttribArray(p);
|
||||
if (_has_divisor) {
|
||||
_glgsg->_glVertexAttribDivisor(p, 0);
|
||||
}
|
||||
} else {
|
||||
cgGLDisableClientState(p);
|
||||
switch (p) {
|
||||
case CA_unknown:
|
||||
break;
|
||||
case CA_vertex:
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
break;
|
||||
case CA_normal:
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
break;
|
||||
case CA_color:
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
break;
|
||||
case CA_secondary_color:
|
||||
glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
|
||||
break;
|
||||
default:
|
||||
_glgsg->_glClientActiveTexture(GL_TEXTURE0 + (p - CA_texcoord));
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -458,12 +746,9 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
|
||||
int start, stride, num_values;
|
||||
int nvarying = _shader->_var_spec.size();
|
||||
for (int i = 0; i < nvarying; ++i) {
|
||||
if (_cg_parameter_map[_shader->_var_spec[i]._id._seqno] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
InternalName *name = _shader->_var_spec[i]._name;
|
||||
int texslot = _shader->_var_spec[i]._append_uv;
|
||||
const Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
|
||||
InternalName *name = bind._name;
|
||||
int texslot = bind._append_uv;
|
||||
if (texslot >= 0 && texslot < _glgsg->_state_texture->get_num_on_stages()) {
|
||||
TextureStage *stage = _glgsg->_state_texture->get_on_stage(texslot);
|
||||
InternalName *texname = stage->get_texcoord_name();
|
||||
@ -474,84 +759,146 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
|
||||
name = name->append(texname->get_basename());
|
||||
}
|
||||
}
|
||||
if (_glgsg->_data_reader->get_array_info(name,
|
||||
array_reader, num_values, numeric_type,
|
||||
start, stride)) {
|
||||
GLint p = bind._id._seqno;
|
||||
|
||||
// Don't apply vertex colors if they are disabled with a ColorAttrib.
|
||||
int num_elements, element_stride, divisor;
|
||||
bool normalized;
|
||||
if ((p != _color_attrib_index || _glgsg->_vertex_colors_enabled) &&
|
||||
_glgsg->_data_reader->get_array_info(name, array_reader,
|
||||
num_values, numeric_type,
|
||||
normalized, start, stride, divisor,
|
||||
num_elements, element_stride)) {
|
||||
const unsigned char *client_pointer;
|
||||
if (!_glgsg->setup_array_data(client_pointer, array_reader, force)) {
|
||||
return false;
|
||||
}
|
||||
client_pointer += start;
|
||||
|
||||
CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
|
||||
// We don't use cgGLSetParameterPointer because it is very buggy and
|
||||
// limited in the options we can set.start
|
||||
GLenum type = _glgsg->get_numeric_type(numeric_type);
|
||||
if (p >= 0) {
|
||||
_glgsg->_glEnableVertexAttribArray(p);
|
||||
|
||||
if (numeric_type == GeomEnums::NT_packed_dabc) {
|
||||
// Yes, this is a thing.
|
||||
num_values = GL_BGRA;
|
||||
}
|
||||
if (bind._integer) {
|
||||
_glgsg->_glVertexAttribIPointer(p, num_values, type,
|
||||
stride, client_pointer);
|
||||
} else if (numeric_type == GeomEnums::NT_packed_dabc) {
|
||||
// GL_BGRA is a special accepted value available since OpenGL 3.2.
|
||||
// It requires us to pass GL_TRUE for normalized.
|
||||
_glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
|
||||
GL_TRUE, stride, client_pointer);
|
||||
} else {
|
||||
_glgsg->_glVertexAttribPointer(p, num_values, type,
|
||||
normalized, stride, client_pointer);
|
||||
}
|
||||
|
||||
// cgGLSetParameterPointer is just stupidly bugged on every level.
|
||||
// Sigh. This seems to work on both NVIDIA and AMD cards now.
|
||||
if (cgGetParameterBaseResource(p) == CG_ATTR0) {
|
||||
int index = cgGetParameterResourceIndex(p);
|
||||
switch (index) {
|
||||
case 0: // gl_Vertex
|
||||
glVertexPointer(num_values, _glgsg->get_numeric_type(numeric_type),
|
||||
stride, client_pointer + start);
|
||||
if (_glgsg->_supports_vertex_attrib_divisor) {
|
||||
_glgsg->_glVertexAttribDivisor(p, divisor);
|
||||
_has_divisor = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
// It's a conventional vertex attribute. Ugh.
|
||||
switch (p) {
|
||||
case CA_unknown:
|
||||
break;
|
||||
|
||||
case CA_vertex:
|
||||
glVertexPointer(num_values, type, stride, client_pointer);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
break;
|
||||
|
||||
case 2: // gl_Normal
|
||||
glNormalPointer(_glgsg->get_numeric_type(numeric_type),
|
||||
stride, client_pointer + start);
|
||||
case CA_normal:
|
||||
glNormalPointer(type, stride, client_pointer);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
break;
|
||||
|
||||
case 3: // gl_Color
|
||||
glColorPointer(num_values, _glgsg->get_numeric_type(numeric_type),
|
||||
stride, client_pointer + start);
|
||||
case CA_color:
|
||||
glColorPointer(num_values, type, stride, client_pointer);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
break;
|
||||
|
||||
case 4: // gl_SecondaryColor
|
||||
//glSecondaryColorPointer(num_values, _glgsg->get_numeric_type(numeric_type),
|
||||
// stride, client_pointer + start);
|
||||
//glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
|
||||
//break;
|
||||
case 5: // gl_FogCoord
|
||||
case 6: // PSIZE?
|
||||
case 7: // BLENDINDICES?
|
||||
case 1: // glWeightPointerARB?
|
||||
GLCAT.error()
|
||||
<< "Unable to bind " << *name << " to "
|
||||
<< cgGetParameterResourceName(p) << "\n";
|
||||
case CA_secondary_color:
|
||||
_glgsg->_glSecondaryColorPointer(num_values, type,
|
||||
stride, client_pointer);
|
||||
glEnableClientState(GL_SECONDARY_COLOR_ARRAY);
|
||||
break;
|
||||
|
||||
default:
|
||||
_glgsg->_glClientActiveTexture(GL_TEXTURE0 + (index - 8));
|
||||
glTexCoordPointer(num_values, _glgsg->get_numeric_type(numeric_type),
|
||||
stride, client_pointer + start);
|
||||
_glgsg->_glClientActiveTexture(GL_TEXTURE0 + (p - CA_texcoord));
|
||||
glTexCoordPointer(num_values, type, stride, client_pointer);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (name == InternalName::get_normal() && num_values == 4) {
|
||||
// In some cases, the normals are aligned to 4 values. We tell
|
||||
// it to use three values exactly, otherwise we get the error:
|
||||
// An unsupported GL extension was required to perform this operation.
|
||||
num_values = 3;
|
||||
}
|
||||
cgGLSetParameterPointer(p, num_values,
|
||||
_glgsg->get_numeric_type(numeric_type),
|
||||
stride, client_pointer + start);
|
||||
cgGLEnableClientState(p);
|
||||
}
|
||||
} else {
|
||||
CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
|
||||
cgGLDisableClientState(p);
|
||||
// There is no vertex column with this name; disable the attribute array.
|
||||
if (p == 0) {
|
||||
//NOTE: if we disable attribute 0 in compatibility profile, the object
|
||||
// will disappear. In GLSL we fix this by forcing the vertex column
|
||||
// to be at 0, but we don't have control over that with Cg. So, we
|
||||
// work around this by just binding something silly to 0.
|
||||
// This breaks flat colors, but it's better than invisible objects?
|
||||
_glgsg->_glEnableVertexAttribArray(0);
|
||||
if (bind._integer) {
|
||||
_glgsg->_glVertexAttribIPointer(0, 4, GL_INT, 0, 0);
|
||||
} else {
|
||||
_glgsg->_glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
}
|
||||
|
||||
} else if (p > 0) {
|
||||
_glgsg->_glDisableVertexAttribArray(p);
|
||||
|
||||
if (p == _color_attrib_index) {
|
||||
#ifdef STDFLOAT_DOUBLE
|
||||
_glgsg->_glVertexAttrib4dv(p, _glgsg->_scene_graph_color.get_data());
|
||||
#else
|
||||
_glgsg->_glVertexAttrib4fv(p, _glgsg->_scene_graph_color.get_data());
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
switch (p) {
|
||||
case CA_unknown:
|
||||
break;
|
||||
case CA_vertex:
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
break;
|
||||
case CA_normal:
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
break;
|
||||
case CA_color:
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
#ifdef STDFLOAT_DOUBLE
|
||||
glColor4dv(_glgsg->_scene_graph_color.get_data());
|
||||
#else
|
||||
glColor4fv(_glgsg->_scene_graph_color.get_data());
|
||||
#endif
|
||||
break;
|
||||
case CA_secondary_color:
|
||||
glDisableClientState(GL_SECONDARY_COLOR_ARRAY);
|
||||
break;
|
||||
default:
|
||||
_glgsg->_glClientActiveTexture(GL_TEXTURE0 + (p - CA_texcoord));
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_transform_table_param) {
|
||||
const TransformTable *table = _glgsg->_data_reader->get_transform_table();
|
||||
update_transform_table(table);
|
||||
}
|
||||
|
||||
if (_slider_table_param) {
|
||||
const SliderTable *table = _glgsg->_data_reader->get_slider_table();
|
||||
update_slider_table(table);
|
||||
}
|
||||
|
||||
cg_report_errors();
|
||||
_glgsg->report_my_gl_errors();
|
||||
|
||||
|
@ -41,6 +41,8 @@ public:
|
||||
void bind(bool reissue_parameters = true);
|
||||
void unbind();
|
||||
void issue_parameters(int altered);
|
||||
void update_transform_table(const TransformTable *table);
|
||||
void update_slider_table(const SliderTable *table);
|
||||
void disable_shader_vertex_arrays();
|
||||
bool update_shader_vertex_arrays(ShaderContext *prev, bool force);
|
||||
void disable_shader_texture_bindings();
|
||||
@ -50,13 +52,32 @@ public:
|
||||
INLINE bool uses_custom_vertex_arrays(void);
|
||||
INLINE bool uses_custom_texture_bindings(void);
|
||||
|
||||
// Special values for location to indicate conventional attrib slots.
|
||||
enum ConventionalAttrib {
|
||||
CA_unknown = -1,
|
||||
CA_vertex = -2,
|
||||
CA_normal = -3,
|
||||
CA_color = -4,
|
||||
CA_secondary_color = -5,
|
||||
CA_texcoord = -32,
|
||||
};
|
||||
|
||||
private:
|
||||
CGprogram _cg_program;
|
||||
GLuint _glsl_program;
|
||||
|
||||
GLint _color_attrib_index;
|
||||
CGparameter _transform_table_param;
|
||||
CGparameter _slider_table_param;
|
||||
long _transform_table_size;
|
||||
long _slider_table_size;
|
||||
|
||||
pvector<CGparameter> _cg_parameter_map;
|
||||
|
||||
CLP(GraphicsStateGuardian) *_glgsg;
|
||||
|
||||
bool _has_divisor;
|
||||
|
||||
void release_resources();
|
||||
|
||||
public:
|
||||
|
@ -599,6 +599,17 @@ reset() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef OPENGLES
|
||||
if (is_at_least_gl_version(1, 4)) {
|
||||
_glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)
|
||||
get_extension_func("glSecondaryColorPointer");
|
||||
|
||||
} else if (has_extension("GL_EXT_secondary_color")) {
|
||||
_glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)
|
||||
get_extension_func("glSecondaryColorPointerEXT");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef OPENGLES_2
|
||||
_supports_vertex_blend = false;
|
||||
#else
|
||||
@ -7121,6 +7132,7 @@ get_extension_func(const char *name) {
|
||||
#endif
|
||||
#ifdef EXPECT_GL_VERSION_1_4
|
||||
{ "glPointParameterfv", (void *)&glPointParameterfv },
|
||||
{ "glSecondaryColorPointer", (void *)&glSecondaryColorPointer },
|
||||
#endif
|
||||
#ifdef EXPECT_GL_VERSION_1_5
|
||||
{ "glBeginQuery", (void *)&glBeginQuery },
|
||||
|
@ -103,6 +103,7 @@ typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) (GLenum target, GLint
|
||||
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
|
||||
typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data);
|
||||
typedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);
|
||||
typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
|
||||
typedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
|
||||
typedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count);
|
||||
typedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);
|
||||
@ -662,6 +663,10 @@ public:
|
||||
bool _explicit_primitive_restart;
|
||||
#endif
|
||||
|
||||
#ifndef OPENGLES
|
||||
PFNGLSECONDARYCOLORPOINTERPROC _glSecondaryColorPointer;
|
||||
#endif
|
||||
|
||||
bool _supports_vertex_blend;
|
||||
PFNGLWEIGHTPOINTERARBPROC _glWeightPointer;
|
||||
PFNGLVERTEXBLENDARBPROC _glVertexBlend;
|
||||
|
@ -49,7 +49,7 @@ get_filename(const ShaderType &type) const {
|
||||
|
||||
} else {
|
||||
// Um, better than nothing?
|
||||
return _filename._vertex;
|
||||
return _filename._fragment;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -553,6 +553,7 @@ cg_recurse_parameters(CGparameter parameter, const ShaderType &type,
|
||||
ShaderArgClass arg_subclass = arg_class;
|
||||
|
||||
CGenum vbl = cgGetParameterVariability(parameter);
|
||||
CGtype base_type = cgGetParameterBaseType(parameter);
|
||||
|
||||
if ((vbl==CG_VARYING)||(vbl==CG_UNIFORM)) {
|
||||
switch (cgGetParameterType(parameter)) {
|
||||
@ -567,16 +568,28 @@ cg_recurse_parameters(CGparameter parameter, const ShaderType &type,
|
||||
|
||||
arg_dim[0] = cgGetArraySize(parameter, 0);
|
||||
|
||||
// Fall through
|
||||
default: {
|
||||
arg_dim[1] = cgGetParameterRows(parameter);
|
||||
arg_dim[2] = cgGetParameterColumns(parameter);
|
||||
|
||||
ShaderArgId id;
|
||||
id._name = cgGetParameterName(parameter);
|
||||
id._type = type;
|
||||
id._seqno = -1;
|
||||
success &= compile_parameter(id, arg_class, arg_subclass, arg_type,
|
||||
arg_dir, (vbl == CG_VARYING), arg_dim, shader_cat.get_safe_ptr()); break;
|
||||
ShaderArgInfo p;
|
||||
p._id._name = cgGetParameterName(parameter);
|
||||
p._id._type = type;
|
||||
p._id._seqno = -1;
|
||||
p._class = arg_class;
|
||||
p._subclass = arg_subclass;
|
||||
p._type = arg_type;
|
||||
p._direction = arg_dir;
|
||||
p._varying = (vbl == CG_VARYING);
|
||||
p._integer = (base_type == CG_UINT || base_type == CG_INT ||
|
||||
base_type == CG_ULONG || base_type == CG_LONG ||
|
||||
base_type == CG_USHORT || base_type == CG_SHORT ||
|
||||
base_type == CG_UCHAR || base_type == CG_CHAR);
|
||||
p._cat = shader_cat.get_safe_ptr();
|
||||
|
||||
success &= compile_parameter(p, arg_dim);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -601,24 +614,7 @@ cg_recurse_parameters(CGparameter parameter, const ShaderType &type,
|
||||
// an error message onto the error messages.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool Shader::
|
||||
compile_parameter(const ShaderArgId &arg_id,
|
||||
const ShaderArgClass &arg_class,
|
||||
const ShaderArgClass &arg_subclass,
|
||||
const ShaderArgType &arg_type,
|
||||
const ShaderArgDir &arg_direction,
|
||||
bool arg_varying,
|
||||
int *arg_dim,
|
||||
NotifyCategory *arg_cat)
|
||||
{
|
||||
ShaderArgInfo p;
|
||||
p._id = arg_id;
|
||||
p._class = arg_class;
|
||||
p._subclass = arg_subclass;
|
||||
p._type = arg_type;
|
||||
p._direction = arg_direction;
|
||||
p._varying = arg_varying;
|
||||
p._cat = arg_cat;
|
||||
|
||||
compile_parameter(ShaderArgInfo &p, int *arg_dim) {
|
||||
if (p._id._name.size() == 0) return true;
|
||||
if (p._id._name[0] == '$') return true;
|
||||
|
||||
@ -650,9 +646,9 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return false;
|
||||
}
|
||||
ShaderVarSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._append_uv = -1;
|
||||
bind._integer = false;
|
||||
bind._integer = p._integer;
|
||||
|
||||
if (pieces.size() == 2) {
|
||||
if (pieces[1] == "position") {
|
||||
@ -685,6 +681,24 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
_var_spec.push_back(bind);
|
||||
return true;
|
||||
}
|
||||
} else if (pieces.size() == 3) {
|
||||
if (pieces[1] == "transform") {
|
||||
if (pieces[2] == "blend") {
|
||||
bind._name = InternalName::get_transform_blend();
|
||||
_var_spec.push_back(bind);
|
||||
return true;
|
||||
}
|
||||
if (pieces[2] == "index") {
|
||||
bind._name = InternalName::get_transform_index();
|
||||
_var_spec.push_back(bind);
|
||||
return true;
|
||||
}
|
||||
if (pieces[2] == "weight") {
|
||||
bind._name = InternalName::get_transform_weight();
|
||||
_var_spec.push_back(bind);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bind._name = InternalName::get_root();
|
||||
@ -793,7 +807,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return false;
|
||||
|
||||
ShaderMatSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._func = SMF_compose;
|
||||
|
||||
int next = 1;
|
||||
@ -856,7 +870,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
if (!cp_errchk_parameter_float(p,16,16)) {
|
||||
return false;
|
||||
}
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_transpose;
|
||||
bind._func = SMF_first;
|
||||
bind._part[0] = SMO_attr_material;
|
||||
@ -867,7 +881,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
if (!cp_errchk_parameter_float(p,3,4)) {
|
||||
return false;
|
||||
}
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_row3;
|
||||
bind._func = SMF_first;
|
||||
bind._part[0] = SMO_attr_color;
|
||||
@ -878,7 +892,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
if (!cp_errchk_parameter_float(p,3,4)) {
|
||||
return false;
|
||||
}
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_row3;
|
||||
bind._func = SMF_first;
|
||||
bind._part[0] = SMO_attr_colorscale;
|
||||
@ -889,7 +903,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
if (!cp_errchk_parameter_float(p,3,4)) {
|
||||
return false;
|
||||
}
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_row3;
|
||||
bind._func = SMF_first;
|
||||
bind._part[0] = SMO_attr_fog;
|
||||
@ -900,7 +914,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
if (!cp_errchk_parameter_float(p,3,4)) {
|
||||
return false;
|
||||
}
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_row3;
|
||||
bind._func = SMF_first;
|
||||
bind._part[0] = SMO_attr_fogcolor;
|
||||
@ -940,7 +954,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return false;
|
||||
}
|
||||
ShaderMatSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_row3;
|
||||
bind._func = SMF_first;
|
||||
bind._part[0] = SMO_alight_x;
|
||||
@ -961,7 +975,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return false;
|
||||
}
|
||||
ShaderMatSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_row3;
|
||||
bind._func = SMF_first;
|
||||
bind._part[0] = SMO_satten_x;
|
||||
@ -981,7 +995,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return false;
|
||||
}
|
||||
ShaderMatSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_transpose;
|
||||
int next = 1;
|
||||
pieces.push_back("");
|
||||
@ -1023,7 +1037,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return false;
|
||||
}
|
||||
ShaderMatSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_whole;
|
||||
bind._func = SMF_first;
|
||||
bind._part[0] = SMO_texmat_x;
|
||||
@ -1044,7 +1058,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return false;
|
||||
}
|
||||
ShaderMatSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_row3;
|
||||
bind._func = SMF_first;
|
||||
bind._part[0] = SMO_plane_x;
|
||||
@ -1065,7 +1079,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return false;
|
||||
}
|
||||
ShaderMatSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_row3;
|
||||
bind._func = SMF_first;
|
||||
bind._part[0] = SMO_clipplane_x;
|
||||
@ -1087,7 +1101,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return false;
|
||||
}
|
||||
ShaderMatSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_row3;
|
||||
bind._func = SMF_first;
|
||||
bind._part[1] = SMO_identity;
|
||||
@ -1136,7 +1150,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return false;
|
||||
}
|
||||
ShaderTexSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._name = 0;
|
||||
bind._stage = atoi(pieces[1].c_str());
|
||||
switch (p._type) {
|
||||
@ -1168,7 +1182,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return false;
|
||||
}
|
||||
ShaderMatSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_row3;
|
||||
bind._func = SMF_first;
|
||||
bind._part[0] = SMO_texpad_x;
|
||||
@ -1188,7 +1202,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return false;
|
||||
}
|
||||
ShaderMatSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._piece = SMP_row3;
|
||||
bind._func = SMF_first;
|
||||
bind._part[0] = SMO_texpix_x;
|
||||
@ -1200,6 +1214,11 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pieces[0] == "tbl") {
|
||||
// Handled elsewhere.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pieces[0] == "l") {
|
||||
// IMPLEMENT THE ERROR CHECKING
|
||||
return true; // Cg handles this automatically.
|
||||
@ -1235,7 +1254,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
return false;
|
||||
|
||||
ShaderPtrSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._arg = kinputname;
|
||||
bind._info = p;
|
||||
bind._dep[0] = SSD_general | SSD_shaderinputs;
|
||||
@ -1253,7 +1272,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
switch (p._type) {
|
||||
case SAT_sampler1d: {
|
||||
ShaderTexSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._name = kinputname;
|
||||
bind._desired_type = Texture::TT_1d_texture;
|
||||
_tex_spec.push_back(bind);
|
||||
@ -1261,7 +1280,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
}
|
||||
case SAT_sampler2d: {
|
||||
ShaderTexSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._name = kinputname;
|
||||
bind._desired_type = Texture::TT_2d_texture;
|
||||
_tex_spec.push_back(bind);
|
||||
@ -1269,7 +1288,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
}
|
||||
case SAT_sampler3d: {
|
||||
ShaderTexSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._name = kinputname;
|
||||
bind._desired_type = Texture::TT_3d_texture;
|
||||
_tex_spec.push_back(bind);
|
||||
@ -1277,7 +1296,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
}
|
||||
case SAT_sampler2dArray: {
|
||||
ShaderTexSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._name = kinputname;
|
||||
bind._desired_type = Texture::TT_2d_texture_array;
|
||||
_tex_spec.push_back(bind);
|
||||
@ -1285,7 +1304,7 @@ compile_parameter(const ShaderArgId &arg_id,
|
||||
}
|
||||
case SAT_samplercube: {
|
||||
ShaderTexSpec bind;
|
||||
bind._id = arg_id;
|
||||
bind._id = p._id;
|
||||
bind._name = kinputname;
|
||||
bind._desired_type = Texture::TT_cube_map;
|
||||
_tex_spec.push_back(bind);
|
||||
@ -1385,7 +1404,8 @@ cg_parameter_type(CGparameter p) {
|
||||
default: return SAT_unknown;
|
||||
}
|
||||
case CG_PARAMETERCLASS_ARRAY: return SAT_unknown;
|
||||
default: return SAT_unknown;
|
||||
default:
|
||||
return SAT_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1531,6 +1551,12 @@ cg_compile_entry_point(const char *entry, const ShaderCaps &caps,
|
||||
if (shader_cat.is_debug()) {
|
||||
shader_cat.debug()
|
||||
<< "Compilation with active profile failed: " << cgGetErrorString(err) << "\n";
|
||||
if (err == CG_COMPILER_ERROR) {
|
||||
const char *listing = cgGetLastListing(context);
|
||||
if (listing != NULL) {
|
||||
shader_cat.debug(false) << listing;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1632,19 +1658,19 @@ cg_compile_shader(const ShaderCaps &caps, CGcontext context) {
|
||||
shader_cat.debug()
|
||||
<< "Cg vertex profile: " << cgGetProfileString((CGprofile)_cg_vprofile) << "\n";
|
||||
vertex_program = cgGetProgramString(_cg_vprogram, CG_COMPILED_PROGRAM);
|
||||
shader_cat.debug() << vertex_program << "\n";
|
||||
shader_cat.spam() << vertex_program << "\n";
|
||||
}
|
||||
if (_cg_fprogram != 0) {
|
||||
shader_cat.debug()
|
||||
<< "Cg fragment profile: " << cgGetProfileString((CGprofile)_cg_fprofile) << "\n";
|
||||
fragment_program = cgGetProgramString(_cg_fprogram, CG_COMPILED_PROGRAM);
|
||||
shader_cat.debug() << fragment_program << "\n";
|
||||
shader_cat.spam() << fragment_program << "\n";
|
||||
}
|
||||
if (_cg_gprogram != 0) {
|
||||
shader_cat.debug()
|
||||
<< "Cg geometry profile: " << cgGetProfileString((CGprofile)_cg_gprofile) << "\n";
|
||||
geometry_program = cgGetProgramString(_cg_gprogram, CG_COMPILED_PROGRAM);
|
||||
shader_cat.debug() << geometry_program << "\n";
|
||||
shader_cat.spam() << geometry_program << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -1745,17 +1771,18 @@ cg_analyze_shader(const ShaderCaps &caps) {
|
||||
}
|
||||
}
|
||||
|
||||
// Assign sequence numbers to all parameters.
|
||||
// Assign sequence numbers to all parameters. GLCgShaderContext relies
|
||||
// on the fact that the varyings start at seqno 0.
|
||||
int seqno = 0;
|
||||
for (int i=0; i<(int)_var_spec.size(); i++) {
|
||||
_var_spec[i]._id._seqno = seqno++;
|
||||
}
|
||||
for (int i=0; i<(int)_mat_spec.size(); i++) {
|
||||
_mat_spec[i]._id._seqno = seqno++;
|
||||
}
|
||||
for (int i=0; i<(int)_tex_spec.size(); i++) {
|
||||
_tex_spec[i]._id._seqno = seqno++;
|
||||
}
|
||||
for (int i=0; i<(int)_var_spec.size(); i++) {
|
||||
_var_spec[i]._id._seqno = seqno++;
|
||||
}
|
||||
|
||||
for (int i=0; i<(int)_ptr_spec.size(); i++) {
|
||||
_ptr_spec[i]._id._seqno = seqno++;
|
||||
@ -1955,7 +1982,7 @@ cg_compile_for(const ShaderCaps &caps, CGcontext context,
|
||||
const char *resource = cgGetParameterResourceName(p);
|
||||
if (resource != NULL) {
|
||||
shader_cat.debug() << "Texture parameter " << id._name
|
||||
<< " is bound to resource " << resource << "\n";
|
||||
<< " is bound to resource " << resource << "\n";
|
||||
}
|
||||
}
|
||||
map[id._seqno] = p;
|
||||
@ -1967,48 +1994,18 @@ cg_compile_for(const ShaderCaps &caps, CGcontext context,
|
||||
|
||||
const char *resource = cgGetParameterResourceName(p);
|
||||
if (shader_cat.is_debug() && resource != NULL) {
|
||||
shader_cat.debug()
|
||||
<< "Varying parameter " << id._name << " is bound to resource "
|
||||
<< cgGetParameterResourceName(p) << "\n";
|
||||
if (cgGetParameterResource(p) == CG_GLSL_ATTRIB) {
|
||||
shader_cat.debug()
|
||||
<< "Varying parameter " << id._name << " is bound to GLSL attribute "
|
||||
<< resource << "\n";
|
||||
} else {
|
||||
shader_cat.debug()
|
||||
<< "Varying parameter " << id._name << " is bound to resource "
|
||||
<< resource << " (" << cgGetParameterResource(p)
|
||||
<< ", index " << cgGetParameterResourceIndex(p) << ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (cgGetParameterBaseResource(p) == CG_UNDEFINED) {
|
||||
// I really don't know what this means, but it happens when I
|
||||
// use the NORMAL0 semantic instead of NORMAL, or POSITION0
|
||||
// instead of POSITION, etc. Not catching this results in a
|
||||
// continuous stream of errors at the renderer side.
|
||||
shader_cat.error()
|
||||
<< "Varying parameter " << id._name;
|
||||
|
||||
const char *semantic = cgGetParameterSemantic(p);
|
||||
if (semantic != NULL) {
|
||||
shader_cat.error(false) << " : " << semantic;
|
||||
}
|
||||
if (resource != NULL) {
|
||||
shader_cat.error(false) << " (bound to resource " << resource << ")";
|
||||
}
|
||||
shader_cat.error(false) << " is invalid!\n";
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Let's try to give the developer a hint...
|
||||
if (semantic != NULL) {
|
||||
if (strcmp(semantic, "POSITION0") == 0) {
|
||||
shader_cat.error() << "Try using the semantic POSITION instead of POSITION0.\n";
|
||||
} else if (strcmp(semantic, "NORMAL0") == 0) {
|
||||
shader_cat.error() << "Try using the semantic NORMAL instead of NORMAL0.\n";
|
||||
} else if (strcmp(semantic, "DIFFUSE0") == 0) {
|
||||
shader_cat.error() << "Try using the semantic DIFFUSE instead of DIFFUSE0.\n";
|
||||
} else if (strcmp(semantic, "SPECULAR0") == 0) {
|
||||
shader_cat.error() << "Try using the semantic SPECULAR instead of SPECULAR0.\n";
|
||||
} else if (strcmp(semantic, "FOGCOORD0") == 0) {
|
||||
shader_cat.error() << "Try using the semantic FOGCOORD instead of FOGCOORD0.\n";
|
||||
} else if (strcmp(semantic, "PSIZE0") == 0) {
|
||||
shader_cat.error() << "Try using the semantic PSIZE instead of PSIZE0.\n";
|
||||
}
|
||||
}
|
||||
#endif // NDEBUG
|
||||
p = 0;
|
||||
}
|
||||
map[id._seqno] = p;
|
||||
}
|
||||
|
||||
@ -2059,9 +2056,9 @@ Shader(ShaderLanguage lang) :
|
||||
_cg_fprofile = CG_PROFILE_UNKNOWN;
|
||||
_cg_gprofile = CG_PROFILE_UNKNOWN;
|
||||
if (_default_caps._ultimate_vprofile == 0 || _default_caps._ultimate_vprofile == CG_PROFILE_UNKNOWN) {
|
||||
_default_caps._active_vprofile = CG_PROFILE_UNKNOWN;
|
||||
_default_caps._active_fprofile = CG_PROFILE_UNKNOWN;
|
||||
_default_caps._active_gprofile = CG_PROFILE_UNKNOWN;
|
||||
_default_caps._active_vprofile = CG_PROFILE_GENERIC;
|
||||
_default_caps._active_fprofile = CG_PROFILE_GENERIC;
|
||||
_default_caps._active_gprofile = CG_PROFILE_GENERIC;
|
||||
_default_caps._ultimate_vprofile = cgGetProfile("glslv");
|
||||
_default_caps._ultimate_fprofile = cgGetProfile("glslf");
|
||||
_default_caps._ultimate_gprofile = cgGetProfile("glslg");
|
||||
|
@ -297,6 +297,7 @@ public:
|
||||
ShaderArgType _type;
|
||||
ShaderArgDir _direction;
|
||||
bool _varying;
|
||||
bool _integer;
|
||||
NotifyCategory *_cat;
|
||||
};
|
||||
|
||||
@ -478,14 +479,7 @@ public:
|
||||
bool &success);
|
||||
#endif
|
||||
|
||||
bool compile_parameter(const ShaderArgId &arg_id,
|
||||
const ShaderArgClass &arg_class,
|
||||
const ShaderArgClass &arg_subclass,
|
||||
const ShaderArgType &arg_type,
|
||||
const ShaderArgDir &arg_direction,
|
||||
bool arg_varying,
|
||||
int *arg_dim,
|
||||
NotifyCategory *arg_cat);
|
||||
bool compile_parameter(ShaderArgInfo &p, int *arg_dim);
|
||||
|
||||
void clear_parameters();
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "colorAttrib.h"
|
||||
#include "texGenAttrib.h"
|
||||
#include "textureAttrib.h"
|
||||
#include "shaderAttrib.h"
|
||||
#include "renderState.h"
|
||||
#include "clockObject.h"
|
||||
#include "cullTraverser.h"
|
||||
@ -128,6 +129,17 @@ munge_geom(GraphicsStateGuardianBase *gsg,
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we have prepared it for skinning via the shader generator,
|
||||
// mark a flag on the state so that the shader generator will do this.
|
||||
// We should probably find a cleaner way to do this.
|
||||
const ShaderAttrib *sattr;
|
||||
if (_state->get_attrib(sattr) && sattr->auto_shader()) {
|
||||
GeomVertexDataPipelineReader data_reader(_munged_data, current_thread);
|
||||
if (data_reader.get_format()->get_animation().get_animation_type() == Geom::AT_hardware) {
|
||||
_state = _state->set_attrib(sattr->set_flag(ShaderAttrib::F_hardware_skinning, true));
|
||||
}
|
||||
}
|
||||
|
||||
StateMunger *state_munger;
|
||||
DCAST_INTO_R(state_munger, munger, false);
|
||||
_state = state_munger->munge_state(_state);
|
||||
|
@ -271,8 +271,8 @@ private:
|
||||
// The code to manage this map lives in
|
||||
// GraphicsStateGuardian::get_geom_munger().
|
||||
typedef pmap<WCPT(GraphicsStateGuardianBase), PT(GeomMunger) > Mungers;
|
||||
Mungers _mungers;
|
||||
Mungers::const_iterator _last_mi;
|
||||
mutable Mungers _mungers;
|
||||
mutable Mungers::const_iterator _last_mi;
|
||||
|
||||
// This is used to mark nodes as we visit them to detect cycles.
|
||||
UpdateSeq _cycle_detect;
|
||||
|
@ -702,6 +702,7 @@ get_auto_shader_attrib_impl(const RenderState *state) const {
|
||||
attrib->_auto_gloss_on = _auto_gloss_on;
|
||||
attrib->_auto_ramp_on = _auto_ramp_on;
|
||||
attrib->_auto_shadow_on = _auto_shadow_on;
|
||||
attrib->_flags = _flags;
|
||||
return return_new(attrib);
|
||||
}
|
||||
|
||||
|
@ -92,19 +92,25 @@ reset_register_allocator() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const char *ShaderGenerator::
|
||||
alloc_vreg() {
|
||||
// The ATTR# input sseem to map to generic vertex attributes in
|
||||
// both arbvp1 and glslv, which behave more consistently.
|
||||
switch (_vtregs_used) {
|
||||
case 0: _vtregs_used += 1; return "TEXCOORD0";
|
||||
case 1: _vtregs_used += 1; return "TEXCOORD1";
|
||||
case 2: _vtregs_used += 1; return "TEXCOORD2";
|
||||
case 3: _vtregs_used += 1; return "TEXCOORD3";
|
||||
case 4: _vtregs_used += 1; return "TEXCOORD4";
|
||||
case 5: _vtregs_used += 1; return "TEXCOORD5";
|
||||
case 6: _vtregs_used += 1; return "TEXCOORD6";
|
||||
case 7: _vtregs_used += 1; return "TEXCOORD7";
|
||||
case 0: _vtregs_used += 1; return "ATTR8";
|
||||
case 1: _vtregs_used += 1; return "ATTR9";
|
||||
case 2: _vtregs_used += 1; return "ATTR10";
|
||||
case 3: _vtregs_used += 1; return "ATTR11";
|
||||
case 4: _vtregs_used += 1; return "ATTR12";
|
||||
case 5: _vtregs_used += 1; return "ATTR13";
|
||||
case 6: _vtregs_used += 1; return "ATTR14";
|
||||
case 7: _vtregs_used += 1; return "ATTR15";
|
||||
}
|
||||
switch (_vcregs_used) {
|
||||
case 0: _vcregs_used += 1; return "COLOR0";
|
||||
case 1: _vcregs_used += 1; return "COLOR1";
|
||||
case 0: _vcregs_used += 1; return "ATTR3";
|
||||
case 1: _vcregs_used += 1; return "ATTR4";
|
||||
case 2: _vcregs_used += 1; return "ATTR5";
|
||||
case 3: _vcregs_used += 1; return "ATTR6";
|
||||
case 4: _vcregs_used += 1; return "ATTR7";
|
||||
case 5: _vcregs_used += 1; return "ATTR1";
|
||||
}
|
||||
// These don't exist in arbvp1, though they're reportedly
|
||||
// supported by other profiles.
|
||||
@ -615,6 +621,7 @@ update_shadow_buffer(NodePath light_np) {
|
||||
// - texmatrix
|
||||
// - 1D/2D/3D textures, cube textures, 2D tex arrays
|
||||
// - linear/exp/exp2 fog
|
||||
// - animation
|
||||
//
|
||||
// Not yet supported:
|
||||
// - dot3_rgb and dot3_rgba combine modes
|
||||
@ -624,7 +631,7 @@ update_shadow_buffer(NodePath light_np) {
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(ShaderAttrib) ShaderGenerator::
|
||||
synthesize_shader(const RenderState *rs) {
|
||||
synthesize_shader(const RenderState *rs, const GeomVertexAnimationSpec &anim) {
|
||||
analyze_renderstate(rs);
|
||||
reset_register_allocator();
|
||||
|
||||
@ -706,7 +713,7 @@ synthesize_shader(const RenderState *rs) {
|
||||
}
|
||||
}
|
||||
if (_vertex_colors) {
|
||||
text << "\t in float4 vtx_color : COLOR0,\n";
|
||||
text << "\t in float4 vtx_color : ATTR3,\n";
|
||||
text << "\t out float4 l_color : COLOR0,\n";
|
||||
}
|
||||
if (_need_world_position || _need_world_normal) {
|
||||
@ -733,7 +740,7 @@ synthesize_shader(const RenderState *rs) {
|
||||
text << "\t out float4 l_eye_normal : " << eye_normal_freg << ",\n";
|
||||
}
|
||||
if (_map_index_height >= 0 || _need_world_normal || _need_eye_normal) {
|
||||
text << "\t in float3 vtx_normal : NORMAL,\n";
|
||||
text << "\t in float3 vtx_normal : ATTR2,\n";
|
||||
}
|
||||
if (_map_index_height >= 0) {
|
||||
text << "\t uniform float4 mspos_view,\n";
|
||||
@ -765,11 +772,50 @@ synthesize_shader(const RenderState *rs) {
|
||||
hpos_freg = alloc_freg();
|
||||
text << "\t out float4 l_hpos : " << hpos_freg << ",\n";
|
||||
}
|
||||
text << "\t float4 vtx_position : POSITION,\n";
|
||||
if (anim.get_animation_type() == GeomEnums::AT_hardware &&
|
||||
anim.get_num_transforms() > 0) {
|
||||
int num_transforms;
|
||||
if (anim.get_indexed_transforms()) {
|
||||
num_transforms = 120;
|
||||
} else {
|
||||
num_transforms = anim.get_num_transforms();
|
||||
}
|
||||
text << "\t uniform float4x4 tbl_transforms[" << num_transforms << "],\n";
|
||||
text << "\t in float4 vtx_transform_weight : ATTR1,\n";
|
||||
if (anim.get_indexed_transforms()) {
|
||||
text << "\t in uint4 vtx_transform_index : ATTR7,\n";
|
||||
}
|
||||
}
|
||||
text << "\t in float4 vtx_position : ATTR0,\n";
|
||||
text << "\t out float4 l_position : POSITION,\n";
|
||||
text << "\t uniform float4x4 mat_modelproj\n";
|
||||
text << ") {\n";
|
||||
|
||||
if (anim.get_animation_type() == GeomEnums::AT_hardware &&
|
||||
anim.get_num_transforms() > 0) {
|
||||
|
||||
if (!anim.get_indexed_transforms()) {
|
||||
text << "\t const uint4 vtx_transform_index = uint4(0, 1, 2, 3);\n";
|
||||
}
|
||||
|
||||
text << "\t float4x4 matrix = tbl_transforms[vtx_transform_index.x] * vtx_transform_weight.x";
|
||||
if (anim.get_num_transforms() > 1) {
|
||||
text << "\n\t + tbl_transforms[vtx_transform_index.y] * vtx_transform_weight.y";
|
||||
}
|
||||
if (anim.get_num_transforms() > 2) {
|
||||
text << "\n\t + tbl_transforms[vtx_transform_index.z] * vtx_transform_weight.z";
|
||||
}
|
||||
if (anim.get_num_transforms() > 3) {
|
||||
text << "\n\t + tbl_transforms[vtx_transform_index.w] * vtx_transform_weight.w";
|
||||
}
|
||||
text << ";\n";
|
||||
|
||||
text << "\t vtx_position = mul(matrix, vtx_position);\n";
|
||||
if (_need_world_normal || _need_eye_normal) {
|
||||
text << "\t vtx_normal = mul((float3x3)matrix, vtx_normal);\n";
|
||||
}
|
||||
}
|
||||
|
||||
text << "\t l_position = mul(mat_modelproj, vtx_position);\n";
|
||||
if (_fog) {
|
||||
text << "\t l_hpos = l_position;\n";
|
||||
|
@ -33,6 +33,7 @@ class DirectionalLight;
|
||||
class PointLight;
|
||||
class Spotlight;
|
||||
class LightAttrib;
|
||||
class GeomVertexAnimationSpec;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : ShaderGenerator
|
||||
@ -71,7 +72,8 @@ class EXPCL_PANDA_PGRAPHNODES ShaderGenerator : public TypedReferenceCount {
|
||||
PUBLISHED:
|
||||
ShaderGenerator(GraphicsStateGuardianBase *gsg, GraphicsOutputBase *host);
|
||||
virtual ~ShaderGenerator();
|
||||
virtual CPT(ShaderAttrib) synthesize_shader(const RenderState *rs);
|
||||
virtual CPT(ShaderAttrib) synthesize_shader(const RenderState *rs,
|
||||
const GeomVertexAnimationSpec &anim);
|
||||
|
||||
protected:
|
||||
CPT(RenderAttrib) create_shader_attrib(const string &txt);
|
||||
|
Loading…
x
Reference in New Issue
Block a user