open_toontown_panda3d/panda/src/glstuff/glShaderContext_src.cxx

364 lines
13 KiB
C++
Executable File

// Filename: glShaderContext_src.cxx
// Created by: jyelon (01Sep05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifdef HAVE_CG
#include "Cg/cgGL.h"
#endif
#define DEBUG_GL_SHADER 0
TypeHandle CLP(ShaderContext)::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: GLShaderContext::Constructor
// Access: Public
// Description: xyz
////////////////////////////////////////////////////////////////////
CLP(ShaderContext)::
CLP(ShaderContext)(ShaderExpansion *s, GSG *gsg) : ShaderContext(s) {
#ifdef HAVE_CG
if (s->get_header() == "//Cg") {
// Ask the shader expansion to compile itself for us and
// to give us the resulting Cg program objects.
if (!s->cg_compile_for(gsg->_shader_caps,
_cg_context,
_cg_vprogram,
_cg_fprogram,
_cg_parameter_map)) {
return;
}
// Load the program.
cgGLLoadProgram(_cg_vprogram);
CGerror verror = cgGetError();
if (verror != CG_NO_ERROR) {
const char *str = (const char *)GLP(GetString)(GL_PROGRAM_ERROR_STRING_ARB);
GLCAT.error() << "Could not load Cg vertex program:" << s->get_name() << " (" <<
cgGetProfileString(cgGetProgramProfile(_cg_vprogram)) << " " << str << ")\n";
release_resources();
}
cgGLLoadProgram(_cg_fprogram);
CGerror ferror = cgGetError();
if (ferror != CG_NO_ERROR) {
const char *str = (const char *)GLP(GetString)(GL_PROGRAM_ERROR_STRING_ARB);
GLCAT.error() << "Could not load Cg fragment program:" << s->get_name() << " (" <<
cgGetProfileString(cgGetProgramProfile(_cg_fprogram)) << " " << str << ")\n";
release_resources();
}
}
#endif
}
////////////////////////////////////////////////////////////////////
// Function: GLShaderContext::Destructor
// Access: Public
// Description: xyz
////////////////////////////////////////////////////////////////////
CLP(ShaderContext)::
~CLP(ShaderContext)() {
release_resources();
}
////////////////////////////////////////////////////////////////////
// Function: GLShaderContext::release_resources
// Access: Public
// Description: Should deallocate all system resources (such as
// vertex program handles or Cg contexts).
////////////////////////////////////////////////////////////////////
void CLP(ShaderContext)::
release_resources() {
#ifdef HAVE_CG
if (_cg_context) {
cgDestroyContext(_cg_context);
_cg_context = 0;
_cg_vprogram = 0;
_cg_fprogram = 0;
_cg_parameter_map.clear();
}
#endif
}
////////////////////////////////////////////////////////////////////
// Function: GLShaderContext::bind
// Access: Public
// Description: This function is to be called to enable a new
// shader. It also initializes all of the shader's
// input parameters.
////////////////////////////////////////////////////////////////////
void CLP(ShaderContext)::
bind(GSG *gsg) {
#ifdef HAVE_CG
if (_cg_context != 0) {
// Pass in k-parameters and transform-parameters
issue_parameters(gsg, true);
// Bind the shaders.
cgGLEnableProfile(cgGetProgramProfile(_cg_vprogram));
cgGLBindProgram(_cg_vprogram);
cgGLEnableProfile(cgGetProgramProfile(_cg_fprogram));
cgGLBindProgram(_cg_fprogram);
}
#endif
}
////////////////////////////////////////////////////////////////////
// Function: GLShaderContext::unbind
// Access: Public
// Description: This function disables a currently-bound shader.
////////////////////////////////////////////////////////////////////
void CLP(ShaderContext)::
unbind() {
#ifdef HAVE_CG
if (_cg_context != 0) {
cgGLDisableProfile(cgGetProgramProfile(_cg_vprogram));
cgGLDisableProfile(cgGetProgramProfile(_cg_fprogram));
}
#endif
}
////////////////////////////////////////////////////////////////////
// Function: GLShaderContext::issue_parameters
// Access: Public
// Description: This function gets called whenever the RenderState
// or TransformState has changed, but the ShaderExpansion
// itself has not changed. It loads new values into the
// shader's parameters.
//
// If "altered" is false, that means you promise that
// the parameters for this shader context have already
// been issued once, and that since the last time the
// parameters were issued, no part of the render
// state has changed except the external and internal
// transforms.
////////////////////////////////////////////////////////////////////
void CLP(ShaderContext)::
issue_parameters(GSG *gsg, bool altered) {
#ifdef HAVE_CG
if (_cg_context == 0) {
return;
}
for (int i=0; i<(int)_expansion->_mat_spec.size(); i++) {
if (altered || _expansion->_mat_spec[i]._trans_dependent) {
CGparameter p = _cg_parameter_map[_expansion->_mat_spec[i]._id._seqno];
const LMatrix4f *val = gsg->fetch_specified_value(_expansion->_mat_spec[i], altered);
if (val) {
const float *data = val->get_data();
switch (_expansion->_mat_spec[i]._piece) {
case ShaderExpansion::SMP_whole: cgGLSetMatrixParameterfc(p, data); break;
case ShaderExpansion::SMP_transpose: cgGLSetMatrixParameterfr(p, data); break;
case ShaderExpansion::SMP_row0: cgGLSetParameter4fv(p, data+ 0); break;
case ShaderExpansion::SMP_row1: cgGLSetParameter4fv(p, data+ 4); break;
case ShaderExpansion::SMP_row2: cgGLSetParameter4fv(p, data+ 8); break;
case ShaderExpansion::SMP_row3: cgGLSetParameter4fv(p, data+12); break;
case ShaderExpansion::SMP_col0: cgGLSetParameter4f(p, data[0], data[4], data[ 8], data[12]); break;
case ShaderExpansion::SMP_col1: cgGLSetParameter4f(p, data[1], data[5], data[ 9], data[13]); break;
case ShaderExpansion::SMP_col2: cgGLSetParameter4f(p, data[2], data[6], data[10], data[14]); break;
case ShaderExpansion::SMP_col3: cgGLSetParameter4f(p, data[3], data[7], data[11], data[15]); break;
}
}
}
}
#endif
}
////////////////////////////////////////////////////////////////////
// Function: GLShaderContext::disable_shader_vertex_arrays
// Access: Public
// Description: Disable all the vertex arrays used by this shader.
////////////////////////////////////////////////////////////////////
void CLP(ShaderContext)::
disable_shader_vertex_arrays(GSG *gsg) {
#ifdef HAVE_CG
if (_cg_context == 0) {
return;
}
for (int i=0; i<(int)_expansion->_var_spec.size(); i++) {
CGparameter p = _cg_parameter_map[_expansion->_var_spec[i]._id._seqno];
cgGLDisableClientState(p);
}
#endif
}
////////////////////////////////////////////////////////////////////
// Function: GLShaderContext::update_shader_vertex_arrays
// Access: Public
// Description: Disables all vertex arrays used by the previous
// shader, then enables all the vertex arrays needed
// by this shader. Extracts the relevant vertex array
// data from the gsg.
// The current implementation is inefficient, because
// it may unnecessarily disable arrays then immediately
// reenable them. We may optimize this someday.
////////////////////////////////////////////////////////////////////
bool CLP(ShaderContext)::
update_shader_vertex_arrays(CLP(ShaderContext) *prev, GSG *gsg,
bool force) {
if (prev) prev->disable_shader_vertex_arrays(gsg);
#ifdef HAVE_CG
if (_cg_context == 0) {
return true;
}
#ifdef SUPPORT_IMMEDIATE_MODE
if (gsg->_use_sender) {
GLCAT.error() << "immediate mode shaders not implemented yet\n";
} else
#endif // SUPPORT_IMMEDIATE_MODE
{
const GeomVertexArrayDataHandle *array_reader;
Geom::NumericType numeric_type;
int start, stride, num_values;
int nvarying = _expansion->_var_spec.size();
for (int i=0; i<nvarying; i++) {
CGparameter p = _cg_parameter_map[_expansion->_var_spec[i]._id._seqno];
InternalName *name = _expansion->_var_spec[i]._name;
int texslot = _expansion->_var_spec[i]._append_uv;
if (texslot >= 0) {
const Geom::ActiveTextureStages &active_stages =
gsg->_state._texture->get_on_stages();
if (texslot < (int)active_stages.size()) {
TextureStage *stage = active_stages[texslot];
InternalName *texname = stage->get_texcoord_name();
if (name == InternalName::get_texcoord()) {
name = texname;
} else if (texname != InternalName::get_texcoord()) {
name = name->append(texname->get_basename());
}
}
}
if (gsg->_data_reader->get_array_info(name,
array_reader, num_values, numeric_type,
start, stride)) {
const unsigned char *client_pointer;
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 {
cgGLDisableClientState(p);
}
}
}
#endif // HAVE_CG
return true;
}
////////////////////////////////////////////////////////////////////
// Function: GLShaderContext::disable_shader_texture_bindings
// Access: Public
// Description: Disable all the texture bindings used by this shader.
////////////////////////////////////////////////////////////////////
void CLP(ShaderContext)::
disable_shader_texture_bindings(GSG *gsg) {
#ifdef HAVE_CG
if (_cg_context == 0) {
return;
}
for (int i=0; i<(int)_expansion->_tex_spec.size(); i++) {
CGparameter p = _cg_parameter_map[_expansion->_tex_spec[i]._id._seqno];
int texunit = cgGetParameterResourceIndex(p);
gsg->_glActiveTexture(GL_TEXTURE0 + texunit);
GLP(Disable)(GL_TEXTURE_1D);
GLP(Disable)(GL_TEXTURE_2D);
if (gsg->_supports_3d_texture) {
GLP(Disable)(GL_TEXTURE_3D);
}
if (gsg->_supports_cube_map) {
GLP(Disable)(GL_TEXTURE_CUBE_MAP);
}
// This is probably faster - but maybe not as safe?
// cgGLDisableTextureParameter(p);
}
#endif
}
////////////////////////////////////////////////////////////////////
// Function: GLShaderContext::update_shader_texture_bindings
// Access: Public
// Description: Disables all texture bindings used by the previous
// shader, then enables all the texture bindings needed
// by this shader. Extracts the relevant vertex array
// data from the gsg.
// The current implementation is inefficient, because
// it may unnecessarily disable textures then immediately
// reenable them. We may optimize this someday.
////////////////////////////////////////////////////////////////////
void CLP(ShaderContext)::
update_shader_texture_bindings(CLP(ShaderContext) *prev, GSG *gsg) {
if (prev) prev->disable_shader_texture_bindings(gsg);
#ifdef HAVE_CG
if (_cg_context == 0) {
return;
}
for (int i=0; i<(int)_expansion->_tex_spec.size(); i++) {
CGparameter p = _cg_parameter_map[_expansion->_tex_spec[i]._id._seqno];
Texture *tex = 0;
InternalName *id = _expansion->_tex_spec[i]._name;
if (id != 0) {
const ShaderInput *input = gsg->_target._shader->get_shader_input(id);
tex = input->get_texture();
} else {
if (_expansion->_tex_spec[i]._stage >= gsg->_target._texture->get_num_on_stages()) {
continue;
}
TextureStage *stage = gsg->_target._texture->get_on_stage(_expansion->_tex_spec[i]._stage);
tex = gsg->_target._texture->get_on_texture(stage);
}
if (_expansion->_tex_spec[i]._suffix != 0) {
// The suffix feature is inefficient. It is a temporary hack.
if (tex == 0) {
continue;
}
tex = tex->load_related(_expansion->_tex_spec[i]._suffix);
}
if ((tex == 0) || (tex->get_texture_type() != _expansion->_tex_spec[i]._desired_type)) {
continue;
}
TextureContext *tc = tex->prepare_now(gsg->_prepared_objects, gsg);
if (tc == (TextureContext*)NULL) {
continue;
}
int texunit = cgGetParameterResourceIndex(p);
gsg->_glActiveTexture(GL_TEXTURE0 + texunit);
GLenum target = gsg->get_texture_target(tex->get_texture_type());
if (target == GL_NONE) {
// Unsupported texture mode.
continue;
}
GLP(Enable)(target);
gsg->apply_texture(tc);
}
#endif
}