DarkRadiant Script Reference: Difference between revisions

From The DarkMod Wiki
Jump to navigationJump to search
Line 134: Line 134:
Note: the brush interface is rather thin at the moment, expect the function set to grow over time.
Note: the brush interface is rather thin at the moment, expect the function set to grow over time.
==== PatchNode ====
==== PatchNode ====
* ''no special methods at the moment''
* <tt>setDims(unsigned width, unsigned height)</tt> sets the new patch dimensions.
* <tt>unsigned getWidth()</tt> returns the patch width (number of columns).
* <tt>unsigned getHeight()</tt> returns the patch height (number of rows).
* <tt>PatchControl ctrlAt(unsigned row, unsigned col)</tt> returns the PatchControl structure for row (h) and col (w). See below for a PatchControl description.
* <tt>string getShader()</tt> Returns the shader name for this patch.
* <tt>setShader(string newShaderName)</tt> Sets the shader name for this patch.
* <tt>insertColumns(unsigned colIndex)</tt> Inserts two columns before and after the column with index <colIndex>.
* <tt>insertRows(unsigned rowIndex)</tt> Inserts two rows before and after the row with index <rowIndex>.
* <tt>removePoints(bool columns, unsigned index)</tt> Removes columns or rows right before and after the col/row with the given index, reducing the according dimension by 2.
* <tt>appendPoints(bool columns, bool beginning)</tt> Appends two rows or columns at the beginning or the end.
* <tt>bool isValid()</tt> Check if the patch has invalid control points or width/height are zero
* <tt>bool isDegenerate()</tt> Check whether all control vertices are in the same 3D spot (with minimal tolerance)
* <tt>bool subdivionsFixed()</tt> Gets whether this patch is a patchDef3 (fixed tesselation)
* <tt>Subdivisions getSubdivisions()</tt> Returns the x,y subdivision values (for tesselation), see Subdivision for a further description of the return value
* <tt>setFixedSubdivisions(bool isFixed, Subdivisions divisions)</tt> Sets the subdivision of this patch: ''isFixed'': TRUE, if this patch should be a patchDef3 (fixed tesselation), ''divisions'': a two-component vector containing the desired subdivisions.
* <tt>controlPointsChanged()</tt> Updates the patch tesselation matrix, call this everytime you're done with your PatchControl changes.
 
===== PatchControl =====
A PatchControl is a structure containing information about a patch vertex. It has the following members:
* <tt>vertex</tt> This is a vector holding the 3D coordinates of this control point, see Vector3.
* <tt>texcoord</tt> This is a vector holding the 2D texture coordinates of this control point, see Vector2.
 
===== Subdivisions =====
This is a two-component vector holding two unsigned integers, defining the number of horizontal/vertical tesselations for this patch.
* <tt>x</tt> The number of horizontal subdivisions, e.g. ''patch.getSubdivisions().x()''
* <tt>y</tt> The number of vertical subdivisions, e.g. ''patch.getSubdivisions().y()''


==== EntityNode ====
==== EntityNode ====

Revision as of 13:18, 12 November 2009

DarkRadiant is offering a Python script interface which provides access to the most important functions, such as the Virtual File System, the Shader System and the Scenegraph. A complete reference of all available classes can be found later in this article.

Entering Script Code

Script code can be brought to execution by either entering it in the ad-hoc scripting window (in the group dialog) or by saving it in a .py file in the install/scripts/ folder and running it by entering the command "RunScript yourfile.py" in the command console. Python files are loaded and interpreted each time the runscript command occurs, so it's easy to tweak your code and test it in DarkRadiant right after you hit the save button.

Classes and Methods

DarkRadiant's "internal C++ code is organised into various modules. Each module provides a set of functions, for instance: the GlobalMaterialManager object provides methods to acquire information about all available shaders; the GlobalBrushCreator can be called whenever a new brush should be instanced. The script interface is following the same route and exposes most of these modules to scripting. The following should give you an overview of all the module objects available for your scripts. Examples are given whenever possible.

GlobalSceneGraph

When a map is loaded, the SceneGraph is populated with so-called SceneNodes. Each node represents an object in the map, be it a brush, a patch, an entity or a model (technically, a model is attached as child to a single entity). Each scenegraph has one single root, which can be access through the GlobalSceneGraph module.

  • SceneNode root() Returns the reference to the root node of the global scenegraph. This can return an empty "NULL" node if no map is loaded at invocation time.

SceneNode

A SceneNode provides a set of methods to gain information about its type, its position, etc. A SceneNode is a general object, its actual type can be BrushNode, PatchNode, EntityNode or ModelNode. Each SceneNode can act as parent (or container) to one or many SceneNodes, but each SceneNode can only have one parent at a time. The methods of a general SceneNode are as follows:

  • isNull() Returns true if this node is "empty", i.e. it is the NULL node. Calling methods on a NULL node doesn't have any effect.
  • addToContainer(SceneNode newContainer) Adds this node as child to the given container.
  • removeFromParent() Removes this node from any parent container. If this node has no parent, nothing happens.
  • AABB getWorldAABB() Returns the bounding box (absolute coordinates) of this node. This includes the bounding boxes of all child nodes as well.
  • SceneNode getParent() Returns the parent of this node. If this node doesn't have a parent, a NULL node is returned.
  • string getNodeType() Returns the type string of this node, i.e. "Brush", "Patch", etc.
  • traverse(SceneNodeVisitor visitor) Traverses this Node and all its children using the given Visitor object. See the tutorial about scenegraph traversal for more information.
  • setSelected(bool isSelected) Sets the selection status of this node, i.e. setSelected(1) will select this node. Not all nodes are selectable (ModelNodes, for example).
  • invertSelected() Inverts the selection status of this node, i.e. if it is selected before this call, it will be deselected. Not all nodes are selectable.
  • bool isSelected() Returns the selection status of this node. A return value true means that this node is selected.

SceneGraph Traversal

It's possible to iterate over a given node's children which happens in a distinct way. In order to do that, a "SceneNodeVisitor" object is needed which is (as the name states) "visiting" each node along the route.

A node traversal works like this: first, the node itself is visited (depth 0), then all its children (depth 1). At each node the visitor will visit all the children first, before it continues to visit the "sibling" nodes.

This is a working code example where a visitor will traverse the entire scenegraph (i.e. a whole map):

# This is the visitor object
class SceneWalker(SceneNodeVisitor) :
 	def pre(self, node):
		# Print the type string of each visited node
		print(node.getNodeType())
		return 1

# Instantiate a new walker object
walker = SceneWalker()
GlobalSceneGraph.root().traverse(walker)

Let's say we have a simple scenegraph containing a root node. The root node has two entity nodes as children. The first entity (which is usually the worldspawn) is parent of two brush nodes, the second entity has no children (could be a light). When this scenegraph is traversed (starting from the root), the visitor will produce the following output:

entity
primitive
primitive
entity

Looking closely at this route, it is obvious that Entity 1's children are traversed before Entity 2, which is important. The visitor will always try to gain more "depth" before continuing to traverse on the same depth. It is possible to prevent traversal of a node's children: the visitor just needs to return false (0) when visiting a certain node. Let's say you don't want to traverse the worldspawn brushes, because you're interested in entities only:

# This visitor will NOT traverse children of entities
class EntityWalker(SceneNodeVisitor) :
 	def pre(self, node):
		# Check whether we have an entity
		if node.isEntity():
			# ...
			# do something with this entity
			# ...
			return 0 # return false: don't traverse entities
		else:
			return 1 # not an entity, return true to traverse children

# Instantiate a new entity walker object
walker = EntityWalker()
GlobalSceneGraph.root().traverse(walker)

The output will be something like this:

entity
entity

You might wonder why the visit function is called pre. There is indeed a post function, which can be added to the visitor object, optionally. When the post function is defined, it will be invoked after the walker has finished traversing a node's children. This is an example:

# This visitor has both pre and post functions defined
class SceneWalker(SceneNodeVisitor) :
	def pre(self, node):
		# Print the type string of each visited node
		print('Pre: ' + node.getNodeType())
		return 1
	def post(self, node):
		# Print the type string of each visited node
		print('Post: ' + node.getNodeType())

# Instantiate a new walker object
walker = SceneWalker()
GlobalSceneGraph.root().traverse(walker)

Using this walker, the output will be something like this:

Pre: entity
Pre: primitive
Post: primitive
Pre: primitive
Post: primitive
Post: entity
Pre: entity
Post: entity

As obvious, the visitor visited the first entity (pre), then its children are traversed, and finally the entity is visited once more (post), before the walker proceeds to the next entity. Note: the post method doesn't need to return anything, unlike the pre method. Most of the time you don't need to define a post method, but it might prove to be useful sometimes.

Special SceneNode Types

A SceneNode is just a general object. For some purposes it might be enough to have a SceneNode in your hands, but sometimes you'll want to know the actual node type, whether it is a brush, a patch, an entity or a model. Each SceneNode has a couple of is*() and get*() methods, like isBrush() and getBrush(). You can use the is*() methods to check whether a node is of a specific type, and the get*() methods to convert a SceneNode to a special node type. An example:

if node.isBrush():
	print('Node is a brush!')
else:
	print('Node is not a brush.')

If you want actually do something with a brush, more than just confirming its type, you'll want to go with this code:

brush = node.getBrush()
if not brush.isNull():
	# We've successfully converted the SceneNode into a BrushNode
	print('Found a brush with ' + str(brush.getNumFaces()) + ' faces')
else:
	print('Node is not a brush')

The above code attempts to convert an existing node to a BrushNode. This will succeed only if the node is actually of the correct type, otherwise a NULL node will be returned, which is what the code above checks. If the brush object is not the NULL node, the cast succeeded and we have a valid brushnode in our hands.

There exist analogous methods for entities, models and patches, they are called:

  • isEntity()
  • EntityNode getEntity()
  • isPatch()
  • PatchNode getPatch()
  • isModel()
  • ModelNode getModel()

Each node type provides some special methods, additionally to the ones that come with a SceneNode. A BrushNode has all the methods of a SceneNode, plus a few more.

BrushNode

  • int getNumFaces() Returns the number of faces of this brush.

Note: the brush interface is rather thin at the moment, expect the function set to grow over time.

PatchNode

  • setDims(unsigned width, unsigned height) sets the new patch dimensions.
  • unsigned getWidth() returns the patch width (number of columns).
  • unsigned getHeight() returns the patch height (number of rows).
  • PatchControl ctrlAt(unsigned row, unsigned col) returns the PatchControl structure for row (h) and col (w). See below for a PatchControl description.
  • string getShader() Returns the shader name for this patch.
  • setShader(string newShaderName) Sets the shader name for this patch.
  • insertColumns(unsigned colIndex) Inserts two columns before and after the column with index <colIndex>.
  • insertRows(unsigned rowIndex) Inserts two rows before and after the row with index <rowIndex>.
  • removePoints(bool columns, unsigned index) Removes columns or rows right before and after the col/row with the given index, reducing the according dimension by 2.
  • appendPoints(bool columns, bool beginning) Appends two rows or columns at the beginning or the end.
  • bool isValid() Check if the patch has invalid control points or width/height are zero
  • bool isDegenerate() Check whether all control vertices are in the same 3D spot (with minimal tolerance)
  • bool subdivionsFixed() Gets whether this patch is a patchDef3 (fixed tesselation)
  • Subdivisions getSubdivisions() Returns the x,y subdivision values (for tesselation), see Subdivision for a further description of the return value
  • setFixedSubdivisions(bool isFixed, Subdivisions divisions) Sets the subdivision of this patch: isFixed: TRUE, if this patch should be a patchDef3 (fixed tesselation), divisions: a two-component vector containing the desired subdivisions.
  • controlPointsChanged() Updates the patch tesselation matrix, call this everytime you're done with your PatchControl changes.
PatchControl

A PatchControl is a structure containing information about a patch vertex. It has the following members:

  • vertex This is a vector holding the 3D coordinates of this control point, see Vector3.
  • texcoord This is a vector holding the 2D texture coordinates of this control point, see Vector2.
Subdivisions

This is a two-component vector holding two unsigned integers, defining the number of horizontal/vertical tesselations for this patch.

  • x The number of horizontal subdivisions, e.g. patch.getSubdivisions().x()
  • y The number of vertical subdivisions, e.g. patch.getSubdivisions().y()

EntityNode

  • string getKeyValue(string key) Returns the value of the given entity key (=spawnarg).
  • setKeyValue(string key, string value) Sets the value of the named key, i.e. setKeyValue('health', '100').
  • forEachKeyValue(EntityVisitor visitor) Iterates over all spawnargs of this entity. This requires an EntityVisitor object, which will visit all spawnargs (see below).
  • bool isInherited(string key) Returns true (1) when the given key is an inherited one.
  • EntityClass getEntityClass() Returns the reference to the EntityClass (the object representing the entityDef) of this entity.
  • EntityKeyValuePairs getKeyValuePairs(string prefix) Returns a list of all spawnargs on this entity matching the given prefix. This does not include inherited keyvalues.
EntityVisitor

An EntityVisitor object can be used to traverse the list of spawnargs on a given entity. Such an object just needs to implement a single visit function, see this example:

# This is the prototype of an EntityVisitor object
class MyEntityVisitor(EntityVisitor) :
	def visit(self, key, value):
		print('Worldspawn has spawnarg: ' + key + ' = ' + value)

worldspawn = GlobalMap.getWorldSpawn()
if not worldspawn.isNull():
	ev = MyEntityVisitor()

	# Cast the node onto an entity
	worldspawnent = worldspawn.getEntity()

	worldspawnent.forEachKeyValue(ev)

ModelNode

Entity Classes

GlobalEntityClassManager

The global entity class manager provides methods to retrieve existing entity classes. It also holds all the model definitions, which carry information about meshes and animations.

  • EntityClass findClass(string classname) Finds an entity class by name. If the class with the given name doesn't exist, a NULL object is returned.
  • forEach(EntityClassVisitor visitor) Iterates over all existing entity classes, using the given visitor object.
  • ModelDef findModel(string modelDefName) Returns the model def with the given name. If it doesn't exist, the returned ModelDef is empty, including its name.

EntityClassVisitor

An EntityClassVisitor can be used to iterate over all existing entityDefs. It just needs a single function definition named visit:

  • visit(EntityClass eclass) Is called for each known EntityClass.

This code example can be used as template when writing scripts for entityclasses; it shows how to print the "editor_usage" spawnarg of each entityDef:

# Test implementing a eclass visitor interface
class TestVisitor(EntityClassVisitor) :
	def visit(self, eclass):
		print eclass.getAttribute('editor_usage').value

eclassVisitor = TestVisitor()
GlobalEntityClassManager.forEach(eclassVisitor)

EntityClass

An EntityClass represents what modders know as entityDef. An entityDef represents a collection of spawnargs, pre-defining a certain entity type. Its interface is pretty simple:

  • isNull Returns true if this entityclass is a NULL object, i.e. is empty. This is usually the case if an nonexisting eclass was requested from the GlobalEntityClassManager.
  • EntityClassAttribute getAttribute(string key) Returns the named attribute (spawnarg) of this entityclass. The returned attribute can be empty if the key is not defined.

EntityClassAttribute

An EntityClassAttribute represents a spawnarg on a given entityDef. It contains not only the key and the value, but also additional information about its type and (possibly) a description.

  • name Returns the name of this attribute (i.e. the key), for example: "spawnclass".
  • value Returns the value of this attribute.
  • type Returns the type string of this attribute - this can be "string", "bool", "sound", "float", etc.
  • description Returns the description, as provided by an "editor_*" spawnarg.
  • inherited Returns TRUE if this attribute has been inherited from a parent entityDef.

ModelDef

A ModelDef represents a model {} block as defined in the .def files of the game. A ModelDef primarily contains information about meshes and animations.

  • name The name of this modelDef.
  • mesh The value of the "mesh" property, usually pointing to an .md5mesh file in TDM.
  • skin The skin property. This is empty if no skin is used by this model.
  • parent The parent def this modelDef is inheriting from.
  • anims The list of anims. This basically is a key => value map, which can be iterated over like shown in the following code snippet.
# Try to find the modeldef of the builder forger
modelDef = GlobalEntityClassManager.findModel('builderforger')
print('ModelDef mesh for builderforger = ' + modelDef.mesh)

# Iterate over all the animations for this modelDef
for anim in modelDef.anims:
	print(anim.key())
	print(' = ')
	print(anim.data())
	print()

GlobalCommandSystem

The global command system can be used to execute DarkRadiant commands, as entered manually in the console.

  • execute(string command) Executes the given string command.
  • addStatement(string statementName, string str) Adds the given <str> as new statement with the given name.
  • removeCommand Removes the command with the given name from the command system.

Example:

# Test the commandsystem (this stretches the texture of the selection by 10%)
GlobalCommandSystem.execute('texscale "0 0.1"')

GlobalFileSystem

This global object allows the client to browse the so-called Virtual File System, which lists both the contents of the mod folders ("base", "darkmod", etc.) as well as the contents of the PK4 files in them.

  • forEachFile(string baseDir, string extension, FileVisitor visitor, int depth) Traverses the virtual filesystem, taking "baseDir" as starting point (e.g. "models/"), using "extension" to filter the visiited files and the given "visitor" to visit each file. The depth parameter can be used to restrict the traversal to a maximum folder depth.
  • string findFile(string relativeFilename) Returns the absolute filename for the given relative filename.
  • string findRoot(string absFilename) Returns the filesystem root for the given absolute filename, basically converting it to a relative filename.
  • string readTextFile(string relativeFilename) Returns the full text contents of the given filename.
  • int getFileCount(string filename) Returns the number of files in the VFS matching the given filename.

FileVisitor

A FileVisitor is needed to traverse the GlobalFileSystem using its forEachFile() method. The visitor just needs to provide a single "visit" method, which is called for each matching file.

  • visit(string filename) Is called by forEachFile() for each matching filename.

GlobalGameManager

The GlobalGameManager object knows about all the available games. DarkRadiant supports a number of different "games", with each being defined in its own .game file in the install/ folder.

  • string getModPath() Returns the current mod path, e.g. C:\Games\Doom3\darkmod, or ~/.doom3/darkmod.
  • Game currentGame() Returns the active game object.
  • StringVector getVFSSearchPaths Returns a list of strings with the current search path, i.e. the search priorities. Topmost folder are searched first. The list can be iterated using Python's "for .. in .." construct.

Game

  • string getKeyValue(string key) Returns a key value as defined in the .game file for this game object. E.g. "basegame" will return "base" for the Doom 3 game.

GlobalGrid

The GlobalGrid object can be used to set the grid size of the current viewports.

  • int getGridPower() Returns the currently active grid size in powers of two. The value is in the range [-3 .. 8], with -3 mapping to 0.125 and 8 mapping to 256.
  • setGridSize(int gridsize) Set the current grid size to the given power of two. The value must be in the range [-3 .. 8], with -3 referring to 0.125 and 8 referring to 256.
  • float getGridSize()Returns the currently active grid size in absolute units (e.g. 0.125 .. 256)
  • gridDown() Decreases the grid size (stops at 0.125)
  • gridUp() Increases the grid size (stops at 256)

GlobalMap

The GlobalMap object represents the currently loaded map. Its interface is quite thin at the moment:

  • SceneNode getWorldSpawn() Returns the worldspawn of the currently loaded map. This can be a NULL node if no map is active or no worldspawn has been created yet.

Math Objects

The most important math objects as used by the internal C++ code are exposed to scripting. This includes the most widely used three-component vector "Vector3" as well as the axis aligned bounding box object AABB, among others.

Vector2

A Vector2 is a two-component floating point vector.

  • x Returns a reference to the first component x of this vector.
  • y Returns a reference to the second component y of this vector.
  • float getLength() Returns the length of this vector.
  • float getLengthSquared() Returns the squared length (x^2 + y^2)
  • float dot(Vector2 other) Returns the result of the inner product of this Vector2 with a second Vector2.
  • Vector2 crossProduct(Vector2 other) Returns the resulting vector of the cross product of this Vector2 with one another.

Vector3

A Vector3 is a three-component floating point vector.

  • x Returns a reference to the first component x of this vector.
  • y Returns a reference to the second component y of this vector.
  • z Returns a reference to the third component z of this vector.
  • float getLength() Returns the length of this vector.
  • float getLengthSquared() Returns the squared length (x^2 + y^2 + z^2)
  • float dot(Vector3 other) Returns the result of the inner product of this Vector3 with a second Vector3.
  • Vector3 crossProduct(Vector3 other) Returns the resulting vector of the cross product of this Vector3 with one another.
  • Vector3 getNormalised() Returns a normalised copy of this vector, leaves this vector untouched.
  • normalise() Normalises this vector. After this call, this vector is a unit vector.
  • Vector3 getInversed() Returns an inversed copy of this vector, with the components <1/x 1/y 1/z>.
  • float angle(Vector3 other) Returns the angle between this vector and the "other" Vector3.
  • float max() Returns the maximum absolute value of all three components.
  • float min() Returns the minimum absolute value of all three components.
  • bool isParallel(Vector3 other) Returns true (1) if this vector is parallel to the "other" vector.

Vector4 / Quaternion

A Vector4 is a four-component floating-point Vector, also used to represent Quaternions. Both Quaternion and Vector4 are valid object types and implement the same interface.

  • x Returns a reference to the first component x of this vector.
  • y Returns a reference to the second component y of this vector.
  • z Returns a reference to the third component z of this vector.
  • w Returns a reference to the fourth component w of this vector.
  • float dot(Vector4 other) Returns the result of the inner product of this Vector4 with a second Vector4.
  • Vector3 getProjected() Projects this Vector4 into three dimensional space, by dividing the first three components by w and returning the resulting Vector3.

Vector Arithmetics

All Vector objects support the most important operators, each compatible with a Vector of the same type.

  • +
  • -
  • +=
  • -=
  • < (lesser than, only supported by Vector2 and Vector3)

AABB

AABB is an abbreviation of "Axis-Aligned Bounding Box". An AABB can be seen as rectangular box, providing an outer bound of the object it contains. Each two planes of an AABB are parallel to one of the orthogonal xy, yz and xz planes.

  • AABB() Constructs an empty bounding box, which is invalid until its origin and extents are set to something valid.
  • AABB(Vector3 origin, Vector3 extents) Constructs a valid bounding box, using the given origin and extents.
  • Vector3 origin This property can be used to access the center Vector3 of this bounding box.
  • extents This property provides access to the symmetrical extents (the Vector3 pointing from the center to one corner)
  • bool isValid() Returns true (1) if this AABB is valid.
  • float getRadius() Returns the radius of this bounding box, i.e. the length of the "extents" vector.
  • includePoint(Vector3 other) Modifies this bounding box to include the given point, extending it when necessary.
  • includeAABB(AABB other) Modifies this bounding box to include the given AABB, extending it when necessary.

GlobalRadiant

The "Radiant" module plays a slightly different role for scripting than it does for the "internal" C++ code. Here, it provides some "convenience" methods.

  • EntityNodefindEntityByClassname(string name) Returns the first matching entity with the given classname in the current scenegraph. Returns a NULL node if nothing is found.

Example:

worldspawn = Radiant.findEntityByClassname("worldspawn")
worldspawn.setKeyValue('test', 'success')
print('Worldspawn edited')

GlobalSelectionSystem

The GlobalSelectionSystem object is the one managing the current selection. It provides methods to globally change selection states and to iterate over the existing selection.

  • SelectionInfo getSelectionInfo() Returns the reference to the internal counters of the selectionsystem, which can be used to check how many objects of which type are currently selected.
  • foreachSelected(SelectionVisitor visitor) Visits the current selection using the given Visitor object (not counting components).
  • foreachSelectedComponent(SelectionVisitor visitor) Visits the current component selection using the given Visitor object.
  • setSelectedAll(bool selected) Sets the selection status of all objects in the scenegraph (not counting components like Vertices and Edges).
  • setSelectedAllComponents(bool selected) Sets the selection status of all components in the scenegraph (Vertices, Edges, Faces).
  • SceneNode ultimateSelected() Returns a reference to the last selected object. Will throw an exception if called with an empty selection, so check first using getSelectionInfo().
  • SceneNode penultimateSelected() Returns a reference to the penultimate selected object. Will throw an exception if called with less than two objects selected, so check first using getSelectionInfo().

SelectionInfo

This is the object returned by GlobalSelectionSystem.getSelectionInfo(). It provides just a few counters which can be used to inspect the currently selected object.

  • int totalCount The total number of selected objects, including components.
  • int patchCount The number of selected patches.
  • int brushCount The number of selected brushes.
  • int entityCount The number of selected entities.
  • int componentCount The number of selected components (Faces, Edges, Vertices).

GlobalMaterialManager

This object holds all the shaders as parsed from the material (.mtr) files in the materials/ folders. Use this to retrieve a given material object and get information about them.

  • foreachShader(ShaderVisitor visitor) Visit each known shader with the given visitor object.
  • Shader getMaterialForName(string name) Returns the shader object for the given name. Returns a NULL object if nothing is found (isNull() will return true).

ShaderVisitor

A ShaderVisitor is needed for the GlobalMaterialManager.foreachShader() method to iterate over known materials.

  • visit(Shader s) Is invoked by the foreachShader() routine for each shader, passing the object along.

This example script will print all materials and the files they're defined in:

# This is the shader visitor object we will use to traverse the materials
class TestShaderVisitor(ShaderVisitor) :
	def visit(self, shader):
		if not shader.isNull():
			print('Found shader: ' + shader.getName() + ' defined in ' + shader.getShaderFileName())

shadervisitor = TestShaderVisitor()
GlobalMaterialManager.foreachShader(shadervisitor)

Shader

The shader object wraps around a known material, holding information about the shader stages and other things.

  • bool isNull() Returns true (1) if this a NULL material.
  • string getName() Returns the full name of this shader, e.g. "textures/darkmod/stone/brick/blocks_mixedsize01"
  • string getShaderFileName() Returns the filename this shader is defined in (e.g. "materials/tdm_stone_brick.mtr")
  • string getDescription() Returns the description string as parsed from the material.
  • bool isVisible() Returns true if this shader is visible, i.e. not currently filtered.
  • bool isAmbientLight() Returns true (1) if this is an ambient light material.
  • bool isBlendLight() Returns true (1) if this is a blend light material.
  • bool isFogLight() Returns true (1) if this is a fog light material.