THIS FILE IS OBSOLETE This documentation is only pertinent for GTC versions prior to 0.12 GTC versions 0.13 and after have been largely rewritten and the API is COMPLETELY different. === GTC Python Module documentation $Header: /home/gtc/public_html/gtc-cvs/toolchest/doc/gtc-python-module.txt,v 1.6 2000/06/30 18:48:42 loisel Exp $ I've started on the Python bindings for GTC. This is my first go at documenting it. For more information on GTC, please consult the reference manual, which you can find in postscript form here: gtc_source_directory/doc/latex/refman.ps. Please note that the reference manual is automatically generated from the comments in the source code and is really just a starting point for a better documentation that hasn't been written yet. The Python bindings are serving as proving grounds for the usability of the GTC api. They are not set in stone yet, but the basic ideas should remain similar. In case this documentation is out of sync with the actual code, you might want to take a look at the file gtcmodule.c, which contains (at the time of this writing) the entirety of the Python bindings. === Building Just follow the normal build instructions for GTC, the Python bingings are automatically built. To ensure that they are installed some place where python can find them, make sure you make install. If not, you should be able to find libgtcmodule.so in gtc-dir/lib/.libs/libgtcmodule.so. Copy that file to your lib-dynload directory (eg, /usr/lib/python1.5/lib-dynload) or make sure your PYTHONPATH points to it. === My First Python/GTC program from libgtc import * A=rot(1,2,.2,.9) B=invert(A) print A,B,mul(A,B) === Overview of the gtc module GTC provides you with 5 new types. Before going into them, it would be better to introduce matrices. Matrices are 4-tuples of 4-tuples of floats. For instance, this is a matrix: ((1,2,3,4),(2,3,4,5),(3,4,5,6),(11,13,44.5,6)) This corresponds to the matrix usually written like this: [ 1 2 3 11 ] [ 2 3 4 13 ] [ 3 4 5 44.5 ] [ 4 5 6 6 ] Matrices are used to represent orientations, rotations and translations. To get a rotation matrix, you can use the rot() function, to get a translation matrix you can use the xlat() function. To compose matrices (getting the result of applying the various matrices in succession), you can use the mul() function (multiplication). To invert the matrix (to get the inverse transformation), you can use the invert() function. Finally, to get the identity matrix (which corresponds to no rotation or translation), you can use ident(). The module libgtc provides you with a small number of function calls. Function reference ------------------ * Host,Xform,Scene,defaultContext,starsContext,Table are constructors for the new types and will be discussed below. * rot(x,y,z,theta) will give you a matrix that represents a rotation of theta radians about the 3d vector (x,y,z). * xlat(x,y,z) will give you a matrix that represents a translation by a distance x in the X direction, y in the Y direction and z in the Z direction. * ident() will give you an identity matrix, a matrix that does not rotate or translate by any amount. * mul(A,B) will give you a matrix that represents the result of doing the transformation described by B first, then applying that described by A. These two transformation are collapsed into a single matrix which does the same work as B followed by A. * invert(A) returns the inverse of the given matrix A. * typeCode and typeName are tightly coupled with the new node type, which is described below. Node types ---------- There is a new Python type, a Node. You can think of it as a weird Python class. One of its field is "type". It is an integer value representing the specific node type. If you want a nice printable meaningful type name, you can convert that number using typeName(node.type). Or you can use node.typeName instead. Conversely, a type name can be converted to an integer type code using typeCode(node.typeName). ===================================== * Host: These are used to receive connections from clients and communicate with them. Your main loop should consist of fetching events from a host. Constructor: Host(port) will create a new host, listening to the specified port. Methods: get_event() returns the next available event, or None if none. An event is a dictionnary. event["who"] will be a speaker telling you who originated the event. event["type"] will be an integer telling you the event type. I should make some symbolic constants but for now, the event types are: type name extra data 1 KeyPress event["key"] is a number telling you what key was hit 2 KeyRelease event["key"] tells you what key was released 3 NewClient 4 DeadClient 5 Acknowledgement process(float) takes a floating point parameter, the time interval. It will then sleep for that time interval, at the same time processing events from the connected clients, and receiving new connections. A sleep time of zero is also acceptable. Example: host=Host(4000) print host while 1: host.process(0) event=host.get_event() while event != None: print event event=host.get_event() ===================================== * Speaker: These represent a connection to a single client. You get them off hosts, via events. There is no constructor for the speaker type, you will always get your speaker instances via the host event mechanism. Attribute: dead is an integer. If it is zero, everything's fine. If it's one, this client will soon be disconnected; communication with this client is now impossible. You can set the dead flag to one if you want to get rid of players. Methods: req_ack(): requests an acknowledgement message from a player. This will normally result in an event of type Acknowledgement being sent to you by that speaker. end(): finishes a communication packet and sends it off to the speaker in question. Nothing gets sent until you call the end method. camera(matrix): instruct this client to render the scene as it currently is from the point of view specified by the matrix. That is, the camera matrix will be applied to all objects in the universe before they are rendered. Note that this rendered image will not be displayed on the screen unless you also use swapbuffers(). scene(node,table): this sends the current scene to a client. The node parameter is the root node of the scene while the table parameter is the table for the scene (see the table node type). swapbuffers(): this tells the client to display the most recently rendered image (using the camera(matrix) method). remove(scene,cursor): instructs the client to remove the given cursor from the given scene graph. ===================================== * Node: These are the meat of scene graphs. There are several node types. Despite the terminology, all node types are the same Python type; however, they can have different attributes and methods (weeeeird). Attributes supported by all node types -------------------------------------- Note that these are read-only. typeName is a string read-only attribute. It is one of "sceneType", "meshType", "xformType", "textureType", "contextType" or "rectangleType" according to which node type you're dealing with. type: each typeName has a corresponding integer. Sometimes it's more efficient to just use the type integer instead of the typeName string. In addition, you can use the previously mentionned functions typeCode (to convert a type string to a type int) and typeName (to convert a type in to a type string). The node types -------------- Scene: these are used to group many nodes together. They can also specify a "rendering context", a set of rules for rendering nodes. Thus, scene.context is a context type node. Mesh: this is a bunch of textured (maybe) triangles. They're the actual things that wind up on screen. Xform: these contain a matrix and a child node. The matrix gets applied to the child node before the child gets rendered. Texture: You would normally not use these directly, they are used by the mesh nodes. They contain information on the "painting" of the mesh. Context: these are used to modify how the scene is rendered. You will usually want to use the context returned by the defaultContext() constructor, which is adequate for most 3d requirements. However, as an example, I've provided the starsContext(), which is useful when you want to ignore the translation part of matrices. This is good for modelling things that are so far away (like stars) that they appear to stay fixed as you move around. For 2d rendering (eg, for life bars on top of the 3d stuff), you should use a 2d rendering context, which you can get from context2d(). FIXME: context2d() not implemented yet. Rectangle: this is a 2d rectangle, useful for drawing a life bar. This should be used only in a 2d rendering context, which I haven't hooked up yet. Sorry. Constructors: ------------- defaultContext(): This will give you a "context" type node adequate for 3d stuff. starsContext(): similar to defaultContext, but ignores translations. context2d(): this will give you a context appropriate for 2d graphics. Xform(): gives you a transform node (xform is short for transform). Scene(): gives you a scene node. Attributes and methods specific to node types --------------------------------------------- child Xform attribute The child attribute of an xform. A Xform attribute The matrix transform for an xform node. cursor scene attribute (read-only) This gives you a cursor type object for the group of nodes contained in this scene node. The cursor type is a Python type, it's not a node. Its description can be found below. context scene attribute This is the context attached to the current scene. If None, the context of the parent node (if any) is inherited. The root scene node should always have a context. sweep() scene method This will remove all dead children nodes. (See the Cursor type.) add(x) scene method x will get added to the scene. Returns a cursor for the added object. ball mesh attribute (read-only) This returns a tuple describing the origin and radius of a mesh. The tuple is of the form: ((1 2 3) 5) This would describe a mesh centered at (1,2,3) of radius 5. ======================================== * Cursor: these objects come from scenes. If x is a scene node, then you can get a cursor by doing c=x.cursor. This cursor can be used to examine the nodes forming the scene. As such, there is no constructor available for cursors. Attributes: dead: set this to one if you want to have it removed from the scene. scene.sweep() will remove all dead nodes. Otherwise it'll be zero. child: this will tell you what node this cursor currently points to. next: the next node in the scene; this is read-only ======================================= * Table: you'd normally have a bunch of 3d objects, textures and such stored on the disk and you would load them into a table. This gives you a starting number of meshes to play with and build your scenes with. Constructor: Table(directory_name,verbosity): This will load the resources found in the specified directory. Note that you will need to have an index file in that directory, please look at the sample provided with GTC (normally found in the data subdirectory of GTC). The verbosity parameter controls how many messages go to the screen. The higher the verbosity, the more messages you get. At zero, you shouldn't get any messages. Methods: index(int k): This will give you the kth node of the table, counting from zero. size(): this will return the number of items in the table.