mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-18 20:53:50 -04:00
280 lines
9.7 KiB
C++
Executable File
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
|
|
}
|