Python updates:

Added scene module
This commit is contained in:
2004-06-07 11:03:12 +00:00
parent b468bf726c
commit c16444e624
14 changed files with 386 additions and 79 deletions

View File

@@ -53,8 +53,17 @@ PyObject* listvalue_mapping_subscript(PyObject* list,PyObject* pyindex)
return (PyObject*) item;
}
Py_Error(PyExc_IndexError, "Python ListIndex out of range");
Py_Return;
if (PyInt_Check(pyindex))
{
int index = PyInt_AsLong(pyindex);
return listvalue_buffer_item(list, index);
}
PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */
STR_String index_str(PyString_AsString(pyindex_str));
PyErr_Format(PyExc_KeyError, "'%s' not in list", index_str.Ptr());
Py_DECREF(pyindex_str);
return NULL;
}
@@ -189,7 +198,7 @@ PyTypeObject CListValue::Type = {
__repr, /*tp_repr*/
0, /*tp_as_number*/
&listvalue_as_sequence, /*tp_as_sequence*/
0, /*tp_as_mapping*/
&instance_as_mapping, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call */
};

View File

@@ -82,6 +82,38 @@ inline void Py_Fatal(char *M) {
else \
return rvalue
/**
* These macros are helpfull when embedding Python routines. The second
* macro is one that also requires a documentation string
*/
#define KX_PYMETHOD(class_name, method_name) \
PyObject* Py##method_name(PyObject* self, PyObject* args, PyObject* kwds); \
static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \
return ((class_name*) self)->Py##method_name(self, args, kwds); \
}; \
#define KX_PYMETHOD_DOC(class_name, method_name) \
PyObject* Py##method_name(PyObject* self, PyObject* args, PyObject* kwds); \
static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \
return ((class_name*) self)->Py##method_name(self, args, kwds); \
}; \
static char method_name##_doc[]; \
/* The line above should remain empty */
/**
* Method table macro (with doc)
*/
#define KX_PYMETHODTABLE(class_name, method_name) \
{#method_name , (PyCFunction) class_name::sPy##method_name, METH_VARARGS, class_name::method_name##_doc}
/**
* Function implementation macro
*/
#define KX_PYMETHODDEF_DOC(class_name, method_name, doc_string) \
char class_name::method_name##_doc[] = doc_string; \
PyObject* class_name::Py##method_name(PyObject* self, PyObject* args, PyObject* kwds)
/*------------------------------
* PyObjectPlus

View File

@@ -182,37 +182,6 @@ public:
//
//
/**
* These macros are helpfull when embedding Python routines. The second
* macro is one that also requires a documentation string
*/
#define KX_PYMETHOD(class_name, method_name) \
PyObject* Py##method_name(PyObject* self, PyObject* args, PyObject* kwds); \
static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \
return ((class_name*) self)->Py##method_name(self, args, kwds); \
}; \
#define KX_PYMETHOD_DOC(class_name, method_name) \
PyObject* Py##method_name(PyObject* self, PyObject* args, PyObject* kwds); \
static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \
return ((class_name*) self)->Py##method_name(self, args, kwds); \
}; \
static char method_name##_doc[]; \
/* The line above should remain empty */
/**
* Method table macro (with doc)
*/
#define KX_PYMETHODTABLE(class_name, method_name) \
{#method_name , (PyCFunction) class_name::sPy##method_name, METH_VARARGS, class_name::method_name##_doc}
/**
* Function implementation macro
*/
#define KX_PYMETHODDEF_DOC(class_name, method_name, doc_string) \
char class_name::method_name##_doc[] = doc_string; \
PyObject* class_name::Py##method_name(PyObject* self, PyObject* args, PyObject* kwds)
#ifndef NO_EXP_PYTHON_EMBEDDING

View File

@@ -42,7 +42,7 @@ struct SCA_DebugProp
STR_String m_name;
};
class SCA_IScene
class SCA_IScene
{
std::vector<SCA_DebugProp*> m_debugList;
public:

View File

@@ -515,14 +515,14 @@ KX_PYMETHODDEF_DOC(KX_Camera, sphereInsideFrustum,
MT_Point3 centre = MT_Point3FromPyList(pycentre);
if (PyErr_Occurred())
{
PyErr_SetString(PyExc_TypeError, "Expected list for argument centre.");
PyErr_SetString(PyExc_TypeError, "sphereInsideFrustum: Expected list for argument centre.");
Py_Return;
}
return PyInt_FromLong(SphereInsideFrustum(centre, radius)); /* new ref */
}
PyErr_SetString(PyExc_TypeError, "Expected arguments: (centre, radius)");
PyErr_SetString(PyExc_TypeError, "sphereInsideFrustum: Expected arguments: (centre, radius)");
Py_Return;
}
@@ -558,8 +558,8 @@ KX_PYMETHODDEF_DOC(KX_Camera, boxInsideFrustum,
unsigned int num_points = PySequence_Size(pybox);
if (num_points != 8)
{
PyErr_Format(PyExc_TypeError, "Expected eight (8) points, got %d", num_points);
Py_Return;
PyErr_Format(PyExc_TypeError, "boxInsideFrustum: Expected eight (8) points, got %d", num_points);
return NULL;
}
MT_Point3 box[8];
@@ -569,17 +569,14 @@ KX_PYMETHODDEF_DOC(KX_Camera, boxInsideFrustum,
box[p] = MT_Point3FromPyList(item);
Py_DECREF(item);
if (PyErr_Occurred())
{
Py_Return;
}
return NULL;
}
return PyInt_FromLong(BoxInsideFrustum(box)); /* new ref */
}
PyErr_SetString(PyExc_TypeError, "Expected argument: list of points.");
Py_Return;
PyErr_SetString(PyExc_TypeError, "boxInsideFrustum: Expected argument: list of points.");
return NULL;
}
KX_PYMETHODDEF_DOC(KX_Camera, pointInsideFrustum,
@@ -603,13 +600,13 @@ KX_PYMETHODDEF_DOC(KX_Camera, pointInsideFrustum,
{
MT_Point3 point = MT_Point3FromPyList(pypoint);
if (PyErr_Occurred())
Py_Return;
return NULL;
return PyInt_FromLong(PointInsideFrustum(point)); /* new ref */
}
PyErr_SetString(PyExc_TypeError, "Expected point argument.");
Py_Return;
PyErr_SetString(PyExc_TypeError, "pointInsideFrustum: Expected point argument.");
return NULL;
}
KX_PYMETHODDEF_DOC(KX_Camera, getCameraToWorld,
@@ -686,14 +683,12 @@ KX_PYMETHODDEF_DOC(KX_Camera, setProjectionMatrix,
{
MT_Matrix4x4 mat = MT_Matrix4x4FromPyObject(pymat);
if (PyErr_Occurred())
{
Py_Return;
}
return NULL;
SetProjectionMatrix(mat);
Py_Return;
}
PyErr_SetString(PyExc_TypeError, "Expected 4x4 list as matrix argument.");
Py_Return;
PyErr_SetString(PyExc_TypeError, "setProjectionMatrix: Expected 4x4 list as matrix argument.");
return NULL;
}

View File

@@ -160,7 +160,7 @@ static PyObject* gPyGetSpectrum(PyObject* self,
static void gPyStartDSP(PyObject* self,
static PyObject* gPyStartDSP(PyObject* self,
PyObject* args,
PyObject* kwds)
{
@@ -172,13 +172,15 @@ static void gPyStartDSP(PyObject* self,
{
audiodevice->StartUsingDSP();
usedsp = true;
Py_Return;
}
}
return NULL;
}
static void gPyStopDSP(PyObject* self,
static PyObject* gPyStopDSP(PyObject* self,
PyObject* args,
PyObject* kwds)
{
@@ -190,16 +192,32 @@ static void gPyStopDSP(PyObject* self,
{
audiodevice->StopUsingDSP();
usedsp = false;
Py_Return;
}
}
return NULL;
}
static STR_String gPyGetCurrentScene_doc =
"getCurrentScene()\n"
"Gets a reference to the current scene.\n";
static PyObject* gPyGetCurrentScene(PyObject* self,
PyObject* args,
PyObject* kwds)
{
Py_INCREF(gp_KetsjiScene);
return (PyObject*) gp_KetsjiScene;
}
static struct PyMethodDef game_methods[] = {
{"getCurrentController",
(PyCFunction) SCA_PythonController::sPyGetCurrentController,
METH_VARARGS, SCA_PythonController::sPyGetCurrentController__doc__},
{"getCurrentScene", (PyCFunction) gPyGetCurrentScene,
METH_VARARGS, gPyGetCurrentScene_doc.Ptr()},
{"addActiveActuator",(PyCFunction) SCA_PythonController::sPyAddActiveActuator,
METH_VARARGS, SCA_PythonController::sPyAddActiveActuator__doc__},
{"getRandomFloat",(PyCFunction) gPyGetRandomFloat,

View File

@@ -84,6 +84,7 @@ PyParentObject KX_SCA_ReplaceMeshActuator::Parents[] = {
PyMethodDef KX_SCA_ReplaceMeshActuator::Methods[] = {
{"setMesh", (PyCFunction) KX_SCA_ReplaceMeshActuator::sPySetMesh, METH_VARARGS, SetMesh_doc},
KX_PYMETHODTABLE(KX_SCA_ReplaceMeshActuator, getMesh),
{NULL,NULL} //Sentinel
};
@@ -123,7 +124,13 @@ PyObject* KX_SCA_ReplaceMeshActuator::PySetMesh(PyObject* self,
return NULL;
}
KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, getMesh,
"getMesh() -> string\n"
"Returns the name of the mesh to be substituted.\n"
)
{
return PyString_FromString(const_cast<char *>(m_mesh->GetName().ReadPtr()));
}
/* ------------------------------------------------------------------------- */
/* Native functions */

View File

@@ -82,6 +82,7 @@ class KX_SCA_ReplaceMeshActuator : public SCA_IActuator
/* 1. setMesh */
KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,SetMesh);
KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,getMesh);
};

View File

@@ -102,7 +102,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
class NG_NetworkDeviceInterface *ndi,
class SND_IAudioDevice* adi,
const STR_String& sceneName):
PyObjectPlus(&KX_Scene::Type),
m_keyboardmgr(NULL),
m_mousemgr(NULL),
m_physicsEnvironment(0),
@@ -155,6 +155,8 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
m_canvasDesignWidth = 0;
m_canvasDesignHeight = 0;
m_attrlist = PyDict_New(); /* new ref */
}
@@ -202,6 +204,8 @@ KX_Scene::~KX_Scene()
{
delete m_bucketmanager;
}
Py_DECREF(m_attrlist);
}
@@ -1115,3 +1119,105 @@ void KX_Scene::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* physEnv)
return;
}
}
//----------------------------------------------------------------------------
//Python
PyMethodDef KX_Scene::Methods[] = {
KX_PYMETHODTABLE(KX_Scene, getLightList),
KX_PYMETHODTABLE(KX_Scene, getObjectList),
KX_PYMETHODTABLE(KX_Scene, getName),
{NULL,NULL} //Sentinel
};
PyTypeObject KX_Scene::Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"KX_Scene",
sizeof(KX_Scene),
0,
PyDestructor,
0,
__getattr,
__setattr,
0, //&MyPyCompare,
__repr,
0, //&cvalue_as_number,
0,
0,
0,
0, 0, 0, 0, 0, 0
};
PyParentObject KX_Scene::Parents[] = {
&KX_Scene::Type,
&CValue::Type,
NULL
};
PyObject* KX_Scene::_getattr(const STR_String& attr)
{
if (attr == "name")
return PyString_FromString(GetName());
if (attr == "active_camera")
{
KX_Camera *camera = GetActiveCamera();
camera->AddRef();
return (PyObject*) camera;
}
if (attr == "suspended")
return PyInt_FromLong(m_suspend);
if (attr == "activity_culling")
return PyInt_FromLong(m_activity_culling);
if (attr == "activity_culling_radius")
return PyFloat_FromDouble(m_activity_box_radius);
PyObject* value = PyDict_GetItemString(m_attrlist, const_cast<char *>(attr.ReadPtr()));
if (value)
{
Py_INCREF(value);
return value;
}
_getattr_up(PyObjectPlus);
}
int KX_Scene::_setattr(const STR_String &attr, PyObject *pyvalue)
{
if (!PyDict_SetItemString(m_attrlist, const_cast<char *>(attr.ReadPtr()), pyvalue))
return 0;
return PyObjectPlus::_setattr(attr, pyvalue);
}
KX_PYMETHODDEF_DOC(KX_Scene, getLightList,
"getLightList() -> list [KX_Light]\n"
"Returns a list of all lights in the scene.\n"
)
{
m_lightlist->AddRef();
return (PyObject*) m_lightlist;
}
KX_PYMETHODDEF_DOC(KX_Scene, getObjectList,
"getObjectList() -> list [KX_GameObject]\n"
"Returns a list of all game objects in the scene.\n"
)
{
m_objectlist->AddRef();
return (PyObject*) m_objectlist;
}
KX_PYMETHODDEF_DOC(KX_Scene, getName,
"getName() -> string\n"
"Returns the name of the scene.\n"
)
{
return PyString_FromString(GetName());
}

View File

@@ -49,6 +49,8 @@
#include "RAS_FramingManager.h"
#include "RAS_Rect.h"
#include "PyObjectPlus.h"
/**
* @section Forward declarations
*/
@@ -86,9 +88,9 @@ class SG_IObject;
* The KX_Scene holds all data for an independent scene. It relates
* KX_Objects to the specific objects in the modules.
* */
class KX_Scene : public SCA_IScene
class KX_Scene : public SCA_IScene, public PyObjectPlus
{
//Py_Header;
Py_Header;
protected:
RAS_BucketManager* m_bucketmanager;
CListValue* m_tempObjectList;
@@ -245,6 +247,11 @@ protected:
void MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty);
void MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible);
/**
* This stores anything from python
*/
PyObject* m_attrlist;
public:
KX_Scene(class SCA_IInputDevice* keyboarddevice,
@@ -486,25 +493,25 @@ public:
*/
void SetNodeTree(SG_Tree* root);
#if 0
KX_PYMETHOD_DOC(KX_Scene, GetLightList);
KX_PYMETHOD_DOC(KX_Scene, GetObjectList);
KX_PYMETHOD_DOC(KX_Scene, GetName);
KX_PYMETHOD_DOC(KX_Scene, getLightList);
KX_PYMETHOD_DOC(KX_Scene, getObjectList);
KX_PYMETHOD_DOC(KX_Scene, getName);
/*
KX_PYMETHOD_DOC(KX_Scene, getActiveCamera);
KX_PYMETHOD_DOC(KX_Scene, getActiveCamera);
KX_PYMETHOD_DOC(KX_Scene, findCamera);
KX_PYMETHOD_DOC(KX_Scene, GetActiveCamera);
KX_PYMETHOD_DOC(KX_Scene, SetActiveCamera);
KX_PYMETHOD_DOC(KX_Scene, FindCamera);
KX_PYMETHOD_DOC(KX_Scene, getGravity);
KX_PYMETHOD_DOC(KX_Scene, SetGravity);
KX_PYMETHOD_DOC(KX_Scene, setActivityCulling);
KX_PYMETHOD_DOC(KX_Scene, setActivityCullingRadius);
KX_PYMETHOD_DOC(KX_Scene, SetActivityCulling);
KX_PYMETHOD_DOC(KX_Scene, SetActivityCullingRadius);
KX_PYMETHOD_DOC(KX_Scene, SetSceneViewport);
KX_PYMETHOD_DOC(KX_Scene, GetSceneViewport);
KX_PYMETHOD_DOC(KX_Scene, setSceneViewport);
KX_PYMETHOD_DOC(KX_Scene, setSceneViewport);
*/
virtual PyObject* _getattr(const STR_String& attr); /* name, active_camera, gravity, suspended, viewport, framing, activity_culling, activity_culling_radius */
#endif
virtual int KX_Scene::_setattr(const STR_String &attr, PyObject *pyvalue);
};
typedef std::vector<KX_Scene*> KX_SceneList;

View File

@@ -86,6 +86,12 @@ def getCurrentController():
@rtype: L{SCA_PythonController}
"""
def getCurrentScene():
"""
Gets the current Scene.
@rtype: L{KX_Scene}
"""
def addActiveActuator(actuator, activate):
"""
Activates the given actuator.
@@ -118,3 +124,4 @@ def stopDSP():
Only the fmod sound driver supports this.
DSP can be computationally expensive.
"""

View File

@@ -6,16 +6,56 @@ class KX_MeshProxy:
A mesh object.
You can only change the vertex properties of a mesh object, not the mesh topology.
To use mesh objects effectively, you should know a bit about how the game engine handles them.
1. Mesh Objects are converted from Blender at scene load.
2. The Converter groups polygons by Material. This means they can be sent to the
renderer efficiently. A material holds:
1. The texture.
2. The Blender material.
3. The Tile properties
4. The face properties - (From the "Texture Face" panel)
5. Transparency & z sorting
6. Light layer
7. Polygon shape (triangle/quad)
8. Game Object
3. Verticies will be split by face if necessary. Verticies can only be shared between
faces if:
1. They are at the same position
2. UV coordinates are the same
3. Their normals are the same (both polygons are "Set Smooth")
4. They are the same colour
For example: a cube has 24 verticies: 6 faces with 4 verticies per face.
The correct method of iterating over every L{KX_VertexProxy} in a game object::
import GameLogic
co = GameLogic.getcurrentController()
obj = co.getOwner()
m_i = 0
mesh = obj.getMesh(m_i) # There can be more than one mesh...
while mesh != None:
for mat in range(mesh.getNumMaterials()):
for v_index in range(mesh.getVertexArrayLength(mat)):
vertex = mesh.getVertex(mat, v_index)
# Do something with vertex here...
# ... eg: colour the vertex red.
vertex.colour = [1.0, 0.0, 0.0, 1.0]
m_i += 1
mesh = obj.getMesh(m_i)
"""
def GetNumMaterials():
def getNumMaterials():
"""
Gets the number of materials associated with this object.
@rtype: integer
"""
def GetMaterialName(matid):
def getMaterialName(matid):
"""
Gets the name of the specified material.
@@ -24,7 +64,7 @@ class KX_MeshProxy:
@rtype: string
@return: the attached material name.
"""
def GetTextureName(matid):
def getTextureName(matid):
"""
Gets the name of the specified material's texture.
@@ -33,7 +73,7 @@ class KX_MeshProxy:
@rtype: string
@return: the attached material's texture name.
"""
def GetVertexArrayLength(matid):
def getVertexArrayLength(matid):
"""
Gets the length of the vertex array associated with the specified material.
@@ -44,7 +84,7 @@ class KX_MeshProxy:
@rtype: integer
@return: the number of verticies in the vertex array.
"""
def GetVertex(matid, index):
def getVertex(matid, index):
"""
Gets the specified vertex from the mesh object.

View File

@@ -6,13 +6,55 @@ class KX_SCA_ReplaceMeshActuator(SCA_IActuator):
"""
Edit Object actuator, in Replace Mesh mode.
Example::
# Level-of-detail
# Switch a game object's mesh based on its depth in the camera view.
# +----------+ +-----------+ +-------------------------------------+
# | Always +-----+ Python +-----+ Edit Object (Replace Mesh) LOD.Mesh |
# +----------+ +-----------+ +-------------------------------------+
import GameLogic
# List detail meshes here
# Mesh (name, near, far)
# Meshes overlap so that they don't 'pop' when on the edge of the distance.
meshes = ((".Hi", 0.0, -20.0),
(".Med", -15.0, -50.0),
(".Lo", -40.0, -100.0)
)
co = GameLogic.getCurrentController()
obj = co.getOwner()
act = co.getActuator("LOD." + obj.getName())
cam = GameLogic.getCurrentScene().active_camera
def Depth(pos, plane):
return pos[0]*plane[0] + pos[1]*plane[1] + pos[2]*plane[2] + plane[3]
# Depth is negative and decreasing further from the camera
depth = Depth(obj.position, cam.world_to_camera[2])
newmesh = None
curmesh = None
# Find the lowest detail mesh for depth
for mesh in meshes:
if depth < mesh[1] and depth > mesh[2]:
newmesh = mesh
if "ME" + obj.getName() + mesh[0] == act.getMesh():
curmesh = mesh
if newmesh != None and "ME" + obj.getName() + newmesh[0] != act.getMesh():
# The mesh is a different mesh - switch it.
# Check the current mesh is not a better fit.
if curmesh == None or curmesh[1] < depth or curmesh[2] > depth:
act.setMesh(obj.getName() + newmesh[0])
GameLogic.addActiveActuator(act, True)
@warning: Replace mesh actuators will be ignored if at game start, the
named mesh doesn't exist.
This will generate a warning in the console:
C{ERROR: GameObject I{OBName} ReplaceMeshActuator I{ActuatorName} without object}
"""
def setMesh(name):
"""
@@ -20,4 +62,10 @@ class KX_SCA_ReplaceMeshActuator(SCA_IActuator):
@type name: string
"""
def getMesh():
"""
Returns the name of the mesh that will replace the current one.
@rtype: string
"""

View File

@@ -0,0 +1,68 @@
# $Id$
# Documentation for KX_Scene.py
class KX_Scene:
"""
Scene.
The activity culling stuff is supposed to disable logic bricks when their owner gets too far
from the active camera. It was taken from some code lurking at the back of KX_Scene - who knows
what it does!
Example::
import GameLogic
# get the scene
scene = GameLogic.getCurrentScene()
# print all the objects in the scene
for obj in scene.getObjectList():
print obj.getName()
# get an object named 'Cube'
obj = scene.getObjectList()["OBCube"]
# get the first object in the scene.
obj = scene.getObjectList()[0]
Example::
# Get the depth of an object in the camera view.
import GameLogic
obj = GameLogic.getCurrentController().getOwner()
cam = GameLogic.getCurrentScene().active_camera
# Depth is negative and decreasing further from the camera
depth = obj.position[0]*cam.world_to_camera[2][0] + obj.position[1]*cam.world_to_camera[2][1] + obj.position[2]*cam.world_to_camera[2][2] + cam.world_to_camera[2][3]
@ivar name: The scene's name
@type name: string
@ivar active_camera: The current active camera
@type active_camera: L{KX_Camera}
@ivar suspended: True if the scene is suspended.
@type suspended: boolean
@ivar activity_culling: True if the scene is activity culling
@type activity_culling: boolean
@ivar activity_culling_radius: The distance outside which to do activity culling. Measured in manhattan distance.
@type activity_culling_radius: float
"""
def getLightList():
"""
Returns the list of lights in the scene.
@rtype: list [L{KX_Light}]
"""
def getObjectList():
"""
Returns the list of objects in the scene.
@rtype: list [L{KX_GameObject}]
"""
def getName():
"""
Returns the name of the scene.
@rtype: string
"""