panda3d/panda/src/gobj/shader.cxx
2005-09-06 21:33:34 +00:00

280 lines
9.7 KiB
C++
Executable File

// Filename: shader.cxx
// Created by: jyelon (Sep05)
//
////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////
#include "pandabase.h"
#include "shader.h"
TypeHandle Shader::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: Shader::Constructor
// Access: Public
// Description: Construct a Shader.
////////////////////////////////////////////////////////////////////
Shader::
Shader(const string &text, const string &file) {
_text = text;
_file = file;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::Destructor
// Access: Public
// Description: Delete the compiled code, if it exists.
////////////////////////////////////////////////////////////////////
Shader::
~Shader() {
release_all();
}
////////////////////////////////////////////////////////////////////
// Function: Shader::parse_init
// Access: Public
// Description: Set a 'parse pointer' to the beginning of the shader.
////////////////////////////////////////////////////////////////////
void Shader::
parse_init() {
_parse = 0;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::parse_line
// Access: Public
// Description: Parse a line of text. If 'lt' is true, trim blanks
// from the left end of the line. If 'rt' is true, trim
// blanks from the right end (the newline is always
// trimmed).
////////////////////////////////////////////////////////////////////
void Shader::
parse_line(string &result, bool lt, bool rt) {
int len = _text.size();
int head = _parse;
int tail = head;
while ((tail < len) && (_text[tail] != '\n')) tail++;
if (tail < len) {
_parse = tail+1;
} else {
_parse = tail;
}
if (lt) {
while ((head < tail)&&(isspace(_text[head]))) head++;
while ((tail > head)&&(isspace(_text[tail-1]))) tail--;
}
result = _text.substr(head, tail-head);
}
////////////////////////////////////////////////////////////////////
// Function: Shader::parse_upto
// Access: Public
// Description: Parse lines until you read a line that matches the
// specified pattern. Returns all the preceding lines,
// and if the include flag is set, returns the final
// line as well.
////////////////////////////////////////////////////////////////////
void Shader::
parse_upto(string &result, string pattern, bool include) {
GlobPattern endpat(pattern);
int start = _parse;
int last = _parse;
while (_parse < _text.size()) {
string t;
parse_line(t, true, true);
if (endpat.matches(t)) break;
last = _parse;
}
if (include) {
result = _text.substr(start, _parse - start);
} else {
result = _text.substr(start, last - start);
}
}
////////////////////////////////////////////////////////////////////
// Function: Shader::parse_rest
// Access: Public
// Description: Returns the rest of the text from the current
// parse location.
////////////////////////////////////////////////////////////////////
void Shader::
parse_rest(string &result) {
result = _text.substr(_parse, _text.size() - _parse);
}
////////////////////////////////////////////////////////////////////
// Function: Shader::parse_eof
// Access: Public
// Description: Returns true if the parse pointer is at the end of
// the shader.
////////////////////////////////////////////////////////////////////
bool Shader::
parse_eof() {
return (int)_text.size() == _parse;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::arg_index
// Access: Public
// Description: Allocates an integer index to the given
// shader parameter name.
////////////////////////////////////////////////////////////////////
int Shader::
arg_index(const string &id) {
for (int i=0; i<(int)(_args.size()); i++)
if (_args[i] == id)
return i;
_args.push_back(id);
return _args.size() - 1;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::prepare
// Access: Published
// Description: Indicates that the shader should be enqueued to be
// prepared in the indicated prepared_objects at the
// beginning of the next frame. This will ensure the
// texture is already loaded into texture memory if it
// is expected to be rendered soon.
//
// Use this function instead of prepare_now() to preload
// textures from a user interface standpoint.
////////////////////////////////////////////////////////////////////
void Shader::
prepare(PreparedGraphicsObjects *prepared_objects) {
prepared_objects->enqueue_shader(this);
}
////////////////////////////////////////////////////////////////////
// Function: Shader::release
// Access: Published
// Description: Frees the texture context only on the indicated object,
// if it exists there. Returns true if it was released,
// false if it had not been prepared.
////////////////////////////////////////////////////////////////////
bool Shader::
release(PreparedGraphicsObjects *prepared_objects) {
Contexts::iterator ci;
ci = _contexts.find(prepared_objects);
if (ci != _contexts.end()) {
ShaderContext *sc = (*ci).second;
if (sc != (ShaderContext *)NULL) {
prepared_objects->release_shader(sc);
} else {
_contexts.erase(ci);
}
return true;
}
// Maybe it wasn't prepared yet, but it's about to be.
return prepared_objects->dequeue_shader(this);
}
////////////////////////////////////////////////////////////////////
// Function: Shader::prepare_now
// Access: Public
// Description: Creates a context for the texture 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
// rendering context and that it is ready to accept new
// textures. If this is not necessarily the case, you
// should use prepare() instead.
//
// Normally, this is not called directly except by the
// GraphicsStateGuardian; a texture does not need to be
// explicitly prepared by the user before it may be
// rendered.
////////////////////////////////////////////////////////////////////
ShaderContext *Shader::
prepare_now(PreparedGraphicsObjects *prepared_objects,
GraphicsStateGuardianBase *gsg) {
Contexts::const_iterator ci;
ci = _contexts.find(prepared_objects);
if (ci != _contexts.end()) {
return (*ci).second;
}
ShaderContext *tc = prepared_objects->prepare_shader_now(this, gsg);
_contexts[prepared_objects] = tc;
return tc;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::clear_prepared
// Access: Private
// Description: Removes the indicated PreparedGraphicsObjects table
// from the Shader's table, without actually releasing
// the texture. This is intended to be called only from
// PreparedGraphicsObjects::release_texture(); it should
// never be called by user code.
////////////////////////////////////////////////////////////////////
void Shader::
clear_prepared(PreparedGraphicsObjects *prepared_objects) {
Contexts::iterator ci;
ci = _contexts.find(prepared_objects);
if (ci != _contexts.end()) {
_contexts.erase(ci);
} else {
// If this assertion fails, clear_prepared() was given a
// prepared_objects which the texture didn't know about.
nassertv(false);
}
}
////////////////////////////////////////////////////////////////////
// Function: Shader::release_all
// Access: Published
// Description: Frees the context allocated on all objects for which
// the texture has been declared. Returns the number of
// contexts which have been freed.
////////////////////////////////////////////////////////////////////
int Shader::
release_all() {
// We have to traverse a copy of the _contexts list, because the
// PreparedGraphicsObjects object will call clear_prepared() in response
// to each release_texture(), and we don't want to be modifying the
// _contexts list while we're traversing it.
Contexts temp = _contexts;
int num_freed = (int)_contexts.size();
Contexts::const_iterator ci;
for (ci = temp.begin(); ci != temp.end(); ++ci) {
PreparedGraphicsObjects *prepared_objects = (*ci).first;
ShaderContext *sc = (*ci).second;
if (sc != (ShaderContext *)NULL) {
prepared_objects->release_shader(sc);
}
}
// There might still be some outstanding contexts in the map, if
// there were any NULL pointers there. Eliminate them.
_contexts.clear();
return num_freed;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::register_with_read_factory
// Access: Public, Static
// Description: Factory method to generate a Shader object
////////////////////////////////////////////////////////////////////
void Shader::
register_with_read_factory() {
// IMPLEMENT ME
}