Text archives Help
- From: bigler@sci.utah.edu
- To: manta@sci.utah.edu
- Subject: [MANTA] r1021 - in trunk: Core/Geometry Engine/Display Image Interface SwigInterface doc
- Date: Fri, 28 Apr 2006 12:01:33 -0600 (MDT)
Author: bigler
Date: Fri Apr 28 12:01:31 2006
New Revision: 1021
Added:
trunk/doc/Callbacks.txt
Modified:
trunk/Core/Geometry/AffineTransform.cc
trunk/Engine/Display/SyncDisplay.cc
trunk/Engine/Display/SyncDisplay.h
trunk/Image/NRRDFile.cc
trunk/Interface/Callback.h
trunk/Interface/CallbackHelpers.h
trunk/SwigInterface/manta.i
trunk/SwigInterface/pycallback.cc
trunk/SwigInterface/pycallback.h
trunk/SwigInterface/pycallback.i
trunk/SwigInterface/wxManta.py
Log:
Core/Geometry/AffineTransform.cc
We want static class member functions, not static global functions.
Engine/Display/SyncDisplay.cc
Engine/Display/SyncDisplay.h
Added waitOnFrameReady() that will block instead of returning like
frameReady().
Image/NRRDFile.cc
Steve missed a couple of Image::getRaw -> Image::getRawData
conversions.
Interface/Callback.h
Interface/CallbackHelpers.h
Added a pointer to a more detailed document on how to use Callback
along with a brief explaination.
Added ability to call global and static class member functions.
There is currently only 0Data with 0, 1, 2 Args.
SwigInterface/manta.i
Added AffineTransform, BBox, and Camera class interfaces.
CallbackHelpers.h needs to be included before Callback.h in order to
get the definitions right.
Created macros for assigning IllegalArgument exceptions to specific
functions or groups of functions. Also one for IllegalArgument and
BadPrimitive exceptions.
Added macro to unlock the python Global Interpreter Lock (GIL) when
you call a specific function. This is currently use only for
MantaInterface::addTransaction, but could be use on other functions
in the future.
SwigInterface/pycallback.cc
SwigInterface/pycallback.h
OK, big changes here.
Added PyObjectContainer that is supposed to reference count the
PyObject* inside of it. Currently it doesn't actually decrement the
reference counter, because proxy classes that swig makes don't
delete properly. If in the future you want to decrement the
reference counter, set the DECREMENT_PYTHON_REFERENCE_COUNTER define
in the cc file.
Added static versions of createMantaCallback and callFromC. These
need different names in order to get Callback to work properly (it
doesn't handle overloading at all as far as I can tell).
Now store PyObject*'s as PyObjectContainers, so the reference
counting is all handled for us.
Error checking on the type of the PyObject*'s coming in is now
handled by swig, so we don't have to include ourselves.
Removed fprint debug statements.
Got rid of some dead code.
SwigInterface/pycallback.i
Do type checking on the PyObject*'s being passed in. This will
communicate problems to Python before they get to C, and makes for
cleaner code.
SwigInterface/wxManta.py
Python functions can now be used as Manta::Transactions. See the
example of the camera rotation with the left mouse button.
Use the SyncDisplay display coupled with a thread that checks for
the frameReady state. If a frame is ready, then an event is
generated and the main loop calls the appropiate function
(OnFrameReady) that renders the frame.
There is also the beginnings of a mantaGLCanvas that doesn't do much
currently.
numworkers defaults to 2 instead of 1. Maybe this should get
changed back.
Got rid of temporary print1 function and associated generated
callbacks.
doc/Callbacks.txt
A detailed explaination of how the Callback code works and how to
use it.
Modified: trunk/Core/Geometry/AffineTransform.cc
==============================================================================
--- trunk/Core/Geometry/AffineTransform.cc (original)
+++ trunk/Core/Geometry/AffineTransform.cc Fri Apr 28 12:01:31 2006
@@ -184,30 +184,30 @@
mat[i][3] += translation[i];
}
- static AffineTransform createScale(const Vector& scale)
+ AffineTransform AffineTransform::createScale(const Vector& scale)
{
AffineTransform result;
result.initWithScale(scale);
return result;
}
- static AffineTransform createRotation(const Vector& from,
- const Vector& to)
+ AffineTransform AffineTransform::createRotation(const Vector& from,
+ const Vector& to)
{
AffineTransform result;
result.initWithRotation(from, to);
return result;
}
- static AffineTransform createRotation(const Vector& axis,
- Real angleInRadians)
+ AffineTransform AffineTransform::createRotation(const Vector& axis,
+ Real angleInRadians)
{
AffineTransform result;
result.initWithRotation(axis, angleInRadians);
return result;
}
- static AffineTransform createTranslation(const Vector& translation)
+ AffineTransform AffineTransform::createTranslation(const Vector&
translation)
{
AffineTransform result;
result.initWithTranslation(translation);
Modified: trunk/Engine/Display/SyncDisplay.cc
==============================================================================
--- trunk/Engine/Display/SyncDisplay.cc (original)
+++ trunk/Engine/Display/SyncDisplay.cc Fri Apr 28 12:01:31 2006
@@ -102,6 +102,12 @@
}
void
+SyncDisplay::waitOnFrameReady()
+{
+ _frameready.down();
+}
+
+void
SyncDisplay::renderFrame()
{
// _frameready should already be locked at this point by the
Modified: trunk/Engine/Display/SyncDisplay.h
==============================================================================
--- trunk/Engine/Display/SyncDisplay.h (original)
+++ trunk/Engine/Display/SyncDisplay.h Fri Apr 28 12:01:31 2006
@@ -75,6 +75,7 @@
void setChild(ImageDisplay* child_in);
bool frameReady();
+ void waitOnFrameReady(); // blocks until a frame is ready
void renderFrame();
void doneRendering();
private:
Modified: trunk/Image/NRRDFile.cc
==============================================================================
--- trunk/Image/NRRDFile.cc (original)
+++ trunk/Image/NRRDFile.cc Fri Apr 28 12:01:31 2006
@@ -159,18 +159,14 @@
if (pixel_dimension == 3) {
image = new SimpleImage<RGB8Pixel>( false, width, height );
- dest_ptr = (char *)(
- dynamic_cast<SimpleImage<RGB8Pixel> const *>(
- image)->getRaw( 0 ) );
+ dest_ptr = (char *)(dynamic_cast<SimpleImage<RGB8Pixel> const
*>(image)->getRawData( 0 ) );
}
// RGBA Pixels
else if (pixel_dimension == 4) {
image = new SimpleImage<RGBA8Pixel>( false, width, height );
- dest_ptr = (char *)(
- dynamic_cast<SimpleImage<RGBA8Pixel> const *>(
- image)->getRaw( 0 ) );
+ dest_ptr = (char *)(dynamic_cast<SimpleImage<RGBA8Pixel> const
*>(image)->getRawData( 0 ) );
}
}
Modified: trunk/Interface/Callback.h
==============================================================================
--- trunk/Interface/Callback.h (original)
+++ trunk/Interface/Callback.h Fri Apr 28 12:01:31 2006
@@ -1,4 +1,20 @@
+/*
+ For a detailed explaination of the Callback construct please see:
+
+ doc/Callbacks.txt
+
+ Briefly explained:
+
+ 1. Only void return functions are supported.
+ 2. Data is the call time bound arguments.
+ 3. Arg is the callback creation time bound arguments.
+ 4. Data parameters preceed the Arg parameters of the callback function.
+ 5. If you don't find a create function that match the number of
+ Data and Arg parameters you need, add the create function and
+ corresponding Callback_XData_XArg class.
+ */
+
#ifndef Manta_Interface_Callback_h
#define Manta_Interface_Callback_h
@@ -7,6 +23,31 @@
namespace Manta {
class Callback {
public:
+
+ ////////////////////////////////////////////////////////////
+ // Global functin or static class member functions
+ static
+ CallbackBase_0Data*
+ create(void (*pmf)()) {
+ return new Callback_Static_0Data_0Arg(pmf);
+ }
+
+ template<typename Arg1> static
+ CallbackBase_0Data*
+ create(void (*pmf)(Arg1), Arg1 arg1) {
+ return new Callback_Static_0Data_1Arg<Arg1>(pmf, arg1);
+ }
+
+ template<typename Arg1, typename Arg2> static
+ CallbackBase_0Data*
+ create(void (*pmf)(Arg1, Arg2), Arg1 arg1, Arg2 arg2) {
+ return new Callback_Static_0Data_2Arg<Arg1,Arg2>(pmf, arg1, arg2);
+ }
+
+ ///////////////////////////////////////////////////////////
+ // Class member functions
+
+ // 0 Data callbacks
template<class T> static
CallbackBase_0Data*
create(T* ptr, void (T::*pmf)()) {
Modified: trunk/Interface/CallbackHelpers.h
==============================================================================
--- trunk/Interface/CallbackHelpers.h (original)
+++ trunk/Interface/CallbackHelpers.h Fri Apr 28 12:01:31 2006
@@ -4,6 +4,11 @@
// You should not use these directly - use Callback::create instead
namespace Manta {
+ ////////////////////////////////////////////////////////////
+ // Base classes that can be used by both the static and non-static
+ // Callback classes.
+ //
+
// 0 Data
class CallbackBase_0Data {
public:
@@ -115,11 +120,76 @@
CallbackBase_6Data& operator=(const CallbackBase_6Data&);
};
+
//////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
// These are the actuall implementations with the different number
// of arguments.
+ //////////////////////////////////////////////////////////
+ // Global functin or static class member functions
+ //
+
+ // 0 Data
+ class Callback_Static_0Data_0Arg : public CallbackBase_0Data {
+ public:
+ Callback_Static_0Data_0Arg(void (*pmf)())
+ : pmf(pmf)
+ {
+ }
+ virtual ~Callback_Static_0Data_0Arg()
+ {
+ }
+ virtual void call()
+ {
+ pmf();
+ }
+ private:
+ void (*pmf)();
+ };
+
+ template<typename Arg1>
+ class Callback_Static_0Data_1Arg : public CallbackBase_0Data {
+ public:
+ Callback_Static_0Data_1Arg(void (*pmf)(Arg1), Arg1 arg1)
+ : pmf(pmf), arg1(arg1)
+ {
+ }
+ virtual ~Callback_Static_0Data_1Arg()
+ {
+ }
+ virtual void call()
+ {
+ pmf(arg1);
+ }
+ private:
+ void (*pmf)(Arg1);
+ Arg1 arg1;
+ };
+
+ template<typename Arg1, typename Arg2>
+ class Callback_Static_0Data_2Arg : public CallbackBase_0Data {
+ public:
+ Callback_Static_0Data_2Arg(void (*pmf)(Arg1, Arg2), Arg1 arg1, Arg2 arg2)
+ : pmf(pmf), arg1(arg1), arg2(arg2)
+ {
+ }
+ virtual ~Callback_Static_0Data_2Arg()
+ {
+ }
+ virtual void call()
+ {
+ pmf(arg1, arg2);
+ }
+ private:
+ void (*pmf)(Arg1, Arg2);
+ Arg1 arg1;
+ Arg2 arg2;
+ };
+
+ ///////////////////////////////////////////////////////////
+ // Class member functions
+
// 0 Data
template<class T>
class Callback_0Data_0Arg : public CallbackBase_0Data {
Modified: trunk/SwigInterface/manta.i
==============================================================================
--- trunk/SwigInterface/manta.i (original)
+++ trunk/SwigInterface/manta.i Fri Apr 28 12:01:31 2006
@@ -8,11 +8,15 @@
#include <MantaTypes.h>
#include <Core/Geometry/Vector.h>
#include <Core/Geometry/VectorT.h>
+#include <Core/Geometry/AffineTransform.h>
+#include <Core/Geometry/BBox.h>
%}
%include <MantaTypes.h>
%include <Core/Geometry/Vector.h>
%include <Core/Geometry/VectorT.h>
+%include <Core/Geometry/AffineTransform.h>
+%include <Core/Geometry/BBox.h>
namespace Manta {
%template(VectorT_Real3) VectorT<Manta::Real, 3>;
@@ -30,7 +34,8 @@
%include <Core/Exceptions/IllegalArgument.h>
%include <Core/Exceptions/BadPrimitive.h>
-%exception create {
+%define %manta_IllegalArgument_exception(Function)
+%exception Function {
try {
$action
} catch(Manta::IllegalArgument& e) {
@@ -39,8 +44,10 @@
SWIG_exception(SWIG_RuntimeError, "Unknown exception");
}
}
+%enddef
-%exception {
+%define %manta_IllegalArgument_BadPrimitive_exception(Function)
+%exception Function {
try {
$action
} catch(Manta::IllegalArgument& e) {
@@ -53,15 +60,33 @@
SWIG_exception(SWIG_RuntimeError, "Unknown exception");
}
}
+%enddef
+// This will unlock the Python Global Interpreter Lock (GIL) before
+// calling a potentially blocking function, and then lock it before
+// continuing.
+%define %manta_Release_PythonGIL(Function)
+%exception Function {
+ PyThreadState *_save = PyEval_SaveThread();
+ try {
+ $action
+ PyEval_RestoreThread(_save);
+ } catch(...) {
+ PyEval_RestoreThread(_save);
+ SWIG_exception(SWIG_RuntimeError, "Unknown exception");
+ }
+}
+%enddef
+
+%manta_IllegalArgument_exception(create);
%{
#include <Interface/MantaInterface.h>
#include <Interface/UserInterface.h>
#include <Interface/RenderParameters.h>
#include <Interface/Scene.h>
-#include <Interface/Callback.h>
#include <Interface/CallbackHelpers.h>
+#include <Interface/Callback.h>
#include <SwigInterface/manta.h>
%}
@@ -71,13 +96,16 @@
};
+// This will un
+%manta_Release_PythonGIL(Manta::MantaInterface::addTransaction);
+
%include <Interface/UserInterface.h>
%include <Interface/RenderParameters.h>
%include <Interface/Scene.h>
-%include <Interface/Callback.h>
%include <Interface/CallbackHelpers.h>
+%include <Interface/Callback.h>
%include <Interface/Transaction.h>
%include <Interface/TValue.h>
@@ -176,6 +204,14 @@
}
///////////////////////////////////////////////////////
+// Cameras
+%{
+#include <Interface/Camera.h>
+%}
+
+%include <Interface/Camera.h>
+
+///////////////////////////////////////////////////////
// ImageDisplay
typedef int Window;
@@ -183,11 +219,13 @@
#include <Interface/ImageDisplay.h>
#include <Engine/Display/SyncDisplay.h>
#include <Engine/Display/OpenGLDisplay.h>
+ //#include <Engine/Display/PureOpenGLDisplay.h>
%}
%include <Interface/ImageDisplay.h>
%include <Engine/Display/SyncDisplay.h>
%include <Engine/Display/OpenGLDisplay.h>
+//%include <Engine/Display/PureOpenGLDisplay.h>
Modified: trunk/SwigInterface/pycallback.cc
==============================================================================
--- trunk/SwigInterface/pycallback.cc (original)
+++ trunk/SwigInterface/pycallback.cc Fri Apr 28 12:01:31 2006
@@ -31,56 +31,59 @@
using namespace Manta;
+// #define DECREMENT_PYTHON_REFERENCE_COUNTER 1
+
+PyObjectContainer::PyObjectContainer(PyObject* object_in)
+ : object(object_in)
+{
+ Py_XINCREF(object);
+}
+
+// Copy constructor
+PyObjectContainer::PyObjectContainer(const PyObjectContainer& copy)
+ : object(copy.object)
+{
+ Py_XINCREF(object);
+}
+
+PyObjectContainer::~PyObjectContainer()
+{
+#ifdef DECREMENT_PYTHON_REFERENCE_COUNTER
+ Py_XDECREF(object);
+#endif
+}
+
+void
+PyObjectContainer::set(PyObject* new_object) {
+ Py_XINCREF(new_object);
+#ifdef DECREMENT_PYTHON_REFERENCE_COUNTER
+ Py_XDECREF(object);
+#endif
+ object = new_object;
+}
+
+//////////////////////////////////////////////////////////////
+// PyCallback
PyCallback::PyCallback()
: function(NULL),
args(NULL)
{
- fprintf(stderr, "Constructor called for %p\n", this);
}
PyCallback::PyCallback(PyObject* function, PyObject* args)
: function(function),
args(args)
{
- fprintf(stderr, "Constructor called for %p\n", this);
-
- // Do reference counting
- Py_XINCREF(function);
- Py_XINCREF(args);
-
- //////////////////////////////////////////////
- // We should do some error checking
-
- // Is it callable
- if (!PyCallable_Check(function)) {
- PyErr_SetString(PyExc_TypeError, "first parameter must be callable");
- // Throw an exception....
- return;
- }
-
- // Check the args, but only if something was passed in
- if (args != NULL && !PyTuple_Check(args)) {
- PyErr_SetString(PyExc_TypeError, "argument 2 needs to be a tuple");
- // Throw an exception....
- return;
- }
}
PyCallback::PyCallback(const PyCallback& copy)
: function(copy.function),
args(copy.args)
{
- fprintf(stderr, "Constructor called for %p\n", this);
- // Do reference counting
- Py_XINCREF(function);
- Py_XINCREF(args);
}
-PyCallback::~PyCallback() {
- fprintf(stderr, "Destructor called for %p\n", this);
- // Do reference counting
- Py_XDECREF(function);
- Py_XDECREF(args);
+PyCallback::~PyCallback()
+{
}
PyObject*
@@ -90,30 +93,36 @@
if (new_args == NULL) {
// Use our stored args
- result = PyEval_CallObject(function, args);
+ result = PyEval_CallObject(function(), args());
} else {
- // Use the incoming args
- if (!PyTuple_Check(new_args)) {
- PyErr_SetString(PyExc_TypeError, "argument needs to be a tuple");
- return NULL;
- }
-
- result = PyEval_CallObject(function, new_args);
+ result = PyEval_CallObject(function(), new_args);
}
return result;
}
void
-PyCallback::callFromC()
+PyCallback::callFromC(PyObjectContainer new_args)
+{
+ if (new_args() == NULL)
+ // Use our stored args
+ callFromC2(function, args);
+ else
+ // Use the ones passed in
+ callFromC2(function, new_args);
+}
+
+void
+PyCallback::callFromC2(PyObjectContainer function,
+ PyObjectContainer args)
{
// Get ready to call python code
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
// Call the python function
- PyObject* result = call();
-
+ PyObject* result = PyEval_CallObject(function(), args());
+
// Check the result
if (result == NULL) {
// Something went wrong
@@ -131,87 +140,24 @@
}
CallbackBase_0Data*
-PyCallback::createMantaCallback() {
- return Callback::create(this, &PyCallback::callFromC);
+PyCallback::createMantaCallback(PyObject* new_args) {
+ return Callback::create(this, &PyCallback::callFromC,
+ PyObjectContainer(new_args));
}
-#if 0
-PyObject*
-Manta::create_python_callback(PyObject* self, PyObject* args)
-{
- PyObject* result = NULL;
- PyObject* funct;
- PyObject* funct_args;
-
- int num_args = PyTuple_Size(args);
- if (num_args < 1) {
- PyErr_SetString(PyExc_TypeError, "need at least 1 argument (None
given)");
- return NULL;
- }
-
- funct = PyTuple_GetItem(args, 0);
- if (!PyCallable_Check(funct)) {
- PyErr_SetString(PyExc_TypeError, "first parameter must be callable");
- return NULL;
- }
-
- // Now slice out the arguments
- funct_args = PyTuple_GetSlice(args, 1, num_args);
- PyCallback* cb = new PyCallback(funct, funct_args);
- fprintf(stderr, "cb = %p\n", cb);
-
- result = PyCObject_FromVoidPtr(cb, PyCallback::destroy);
- return result;
+CallbackBase_0Data*
+PyCallback::static_createMantaCallback(PyObject* function,
+ PyObject* args) {
+ return Callback::create(PyCallback::callFromC2,
+ PyObjectContainer(function),
+ PyObjectContainer(args));
}
PyObject*
-Manta::call_python_callback(PyObject* self, PyObject* args)
-{
- PyObject* result;
-
- int num_args = PyTuple_Size(args);
- if (num_args < 1) {
- PyErr_SetString(PyExc_TypeError, "need at least 1 argument (None
given)");
- return NULL;
- }
-
- // Returns a "borrowed reference", so cleanup unneeded
- PyObject* pcb = PyTuple_GetItem(args, 0);
- if (!PyCObject_Check(pcb)) {
- PyErr_SetString(PyExc_TypeError, "first parameter must be Callback");
- return NULL;
- }
- PyCallback* cb = reinterpret_cast<PyCallback*>(PyCObject_AsVoidPtr(pcb));
- // Check to see if we are to use our args or the ones passed in.
- // Returns a "new reference", so cleanup is needed.
- PyObject* new_args = PyTuple_GetSlice(args, 1, num_args);
- if (PyTuple_Size(new_args) > 0) {
- // Use the incoming args
- result = PyEval_CallObject(cb->function, new_args);
- } else {
- // Use our stored args
- result = PyEval_CallObject(cb->function,
- cb->args);
- }
- // Cleanup
- Py_DECREF(new_args);
-
- return result;
-}
-
-static PyMethodDef MyCallbackMethods[] = {
- {"call_callback", Manta::call_python_callback, METH_VARARGS,
- "Call a callable function."},
- {"create_callback", Manta::create_python_callback, METH_VARARGS,
- "Create a callback pointer for later."},
- {NULL, NULL, 0, NULL} /* Sentinel */
-};
-
-PyMODINIT_FUNC
-initmanta_python_callback(void)
+PyCallback::setArgs(PyObject* new_args)
{
- (void) Py_InitModule("manta_python_callback", MyCallbackMethods);
+ args.set(new_args);
+
+ Py_INCREF(Py_None);
+ return Py_None;
}
-
-
-#endif
Modified: trunk/SwigInterface/pycallback.h
==============================================================================
--- trunk/SwigInterface/pycallback.h (original)
+++ trunk/SwigInterface/pycallback.h Fri Apr 28 12:01:31 2006
@@ -36,8 +36,37 @@
namespace Manta {
class CallbackBase_0Data;
-
- struct PyCallback {
+
+ /* This is the thing that is supposed to keep reference counts on
+ our objects. Unfortunately, when a pointer to a swig proxy class
+ is passed in it causes a seg fault when deleted. Since we have
+ no idea what is a swig proxy class and what isn't we will simply
+ have to error on the side of caution and not delete anything.
+ Currently the reference counters are incremented, but not
+ decremented.
+ */
+ class PyObjectContainer {
+ public:
+ PyObjectContainer(PyObject* object_in);
+ // Copy constructor
+ PyObjectContainer(const PyObjectContainer& copy);
+ ~PyObjectContainer();
+
+ PyObject* operator()() { return object; }
+ void set(PyObject* new_object);
+ private:
+ // Don't make "object" public. We need to make sure that things
+ // get reference counted properly.
+ PyObject* object;
+ };
+
+
+ // All the type checking for the "function", "args", and "new_args"
+ // parameters is done for us in SWIG, so you don't need to do it in
+ // the class itself. BTW, don't change the names of these
+ // parameters without making updates to pycallback.i.
+ class PyCallback {
+ public:
PyCallback();
PyCallback(PyObject* function, PyObject* args=0);
PyCallback(const PyCallback& copy);
@@ -50,12 +79,20 @@
// This calls the function and throws exceptions if something went
// bad. You should not call this from swigged code as it will
// lock the interpreter.
- void callFromC();
+ void callFromC(PyObjectContainer new_args);
+ static
+ void callFromC2(PyObjectContainer function,
+ PyObjectContainer args);
- CallbackBase_0Data* createMantaCallback();
+ CallbackBase_0Data* createMantaCallback(PyObject* new_args = 0);
+ static
+ CallbackBase_0Data* static_createMantaCallback(PyObject* function,
+ PyObject* args);
- PyObject* function;
- PyObject* args;
+ PyObject* setArgs(PyObject* new_args);
+ protected:
+ PyObjectContainer function;
+ PyObjectContainer args;
};
Modified: trunk/SwigInterface/pycallback.i
==============================================================================
--- trunk/SwigInterface/pycallback.i (original)
+++ trunk/SwigInterface/pycallback.i Fri Apr 28 12:01:31 2006
@@ -1,11 +1,25 @@
%module pycallback
+%include "exception.i"
+
// This will allow passing of PyObject*'s back and forth between
// python and C, through swig.
%typemap(in) PyObject* {
$1 = $input;
}
+%typemap(check) PyObject* function {
+ if ($1 != 0 && !PyCallable_Check($1)) {
+ SWIG_exception(SWIG_ValueError,"Function argument isn't callable.");
+ }
+}
+
+%typemap(check) PyObject* args, PyObject* new_args {
+ if ($1 != 0 && !PyTuple_Check($1)) {
+ SWIG_exception(SWIG_ValueError,"Argument list isn't a tuple.");
+ }
+}
+
%typemap(out) PyObject* {
$result = $1;
}
@@ -15,3 +29,4 @@
%}
%include <SwigInterface/pycallback.h>
+
Modified: trunk/SwigInterface/wxManta.py
==============================================================================
--- trunk/SwigInterface/wxManta.py (original)
+++ trunk/SwigInterface/wxManta.py Fri Apr 28 12:01:31 2006
@@ -2,13 +2,17 @@
import wx
import sys
+import time
+from wxPython.glcanvas import wxGLCanvas
+import threading
+import math
from manta import *
from pycallback import *
# Number of workers.
-numworkers = 1
+numworkers = 2
# Determine frame resolution.
xres = 512
@@ -51,9 +55,70 @@
scene.getRenderParameters().maxDepth = 5
return scene
-def print1(s1):
- print "1: %s" % s1
+EVT_MANTA_FRAME_READY_ID = wx.NewId()
+class FrameReadyEvent(wx.PyEvent):
+ """Simple event to notify that a frame is ready."""
+ def __init__(self):
+ """Init Frame Ready event."""
+ wx.PyEvent.__init__(self)
+ self.SetEventType(EVT_MANTA_FRAME_READY_ID)
+
+
+class DisplayThread(threading.Thread):
+ """Display Thread that will trigger a display event when the manta
pipeline is ready to display an image."""
+ def __init__(self, notify_window, sync_display):
+ threading.Thread.__init__(self)
+ self.notify_window = notify_window
+ self.sync_display = sync_display
+ self.want_abort = False
+ self.start()
+
+ def run(self):
+ """DisplayThread run function."""
+ print "DisplayThread::run()::start"
+ while(not self.want_abort):
+ if (self.sync_display.frameReady()):
+ wx.PostEvent(self.notify_window, FrameReadyEvent())
+ else:
+ time.sleep(0.00001)
+
+ def abort(self):
+ """abort this thread."""
+ self.want_abort = True
+
+
+
+class mantaGLCanvas(wxGLCanvas):
+ def __init__(self, parent, sync_display):
+ wxGLCanvas.__init__(self, parent, -1)
+# EVT_PAINT(self, self.OnPaint)
+ self.sync_display = sync_display
+ self.init = 0
+ self.Connect(-1,-1, EVT_MANTA_FRAME_READY_ID, OnFrameReady)
+
+ def OnPaint(self, event):
+ # Note that you must always generate a wxPaintDC object,
+ # otherwise certain platforms will not think that you painted
+ # the screen and will call enless refreshes.
+ dc = wxPaintDC(self)
+ self.SetCurrent()
+ if not self.init:
+ self.InitGL()
+ self.init = 1
+ self.OnDraw()
+
+ def OnDraw(self):
+ print "mantaGLCanvas::OnDraw"
+
+ def InitGL(self):
+ print "mantaGLCanvas::InitGL"
+
+ def OnFrameReady(self, event):
+ self.SetCurrent()
+ self.sync_display.renderFrame()
+ self.sync_display.doneRendering()
+ self.SwapBuffers()
class App(wx.App) :
@@ -62,7 +127,7 @@
## OnInit
###########################################################################
def OnInit(self) :
- self.frame = wx.Frame(parent=None, title='Bare', size=wx.Size(xres,
yres) )
+ self.frame = wx.Frame(parent=None, title='Manta', size=wx.Size(xres,
yres) )
self.frame.Show()
#######################################################################
@@ -78,56 +143,145 @@
self.engine.selectRenderer ("raytracer")
self.engine.selectShadowAlgorithm("hard")
+ # Create the camera.
+ camera = self.engine.createCamera("pinhole(-eye 3 3 2 -lookat 0 0
0.3 -up 0 0 1 -fov 60)")
+
# Image display.
use_stereo = False
display = manta_new( OpenGLDisplay( None, self.frame.GetHandle() ) )
- # Create the camera.
- camera = self.engine.createCamera("pinhole(-eye 3 3 2 -lookat 0 0
0.3 -up 0 0 1 -fov 60)")
+ self.sync_display = manta_new(SyncDisplay(vectorStr()))
+ self.sync_display.setChild(display)
+ self.Connect(-1,-1, EVT_MANTA_FRAME_READY_ID, self.OnFrameReady)
+ self.sync_thread = DisplayThread(self, self.sync_display)
+ print "After DisplayThread()"
# Create a display channel.
- self.engine.createChannel( display, camera, use_stereo, xres, yres )
+ self.engine.createChannel( self.sync_display, camera, use_stereo,
xres, yres )
+# self.engine.createChannel( display, camera, use_stereo, xres, yres )
+ print "After createChannel()"
# Basic scene.
self.engine.setScene( createDefaultScenePython() )
self.engine.beginRendering(False)
+ print "After beginRendering()"
#######################################################################
# Setup the UI events.
- self.frame.Bind( wx.EVT_MOTION, self.onMotion )
- self.frame.Bind( wx.EVT_LEFT_DOWN, self.onLeftDown )
-
-
#######################################################################
- # Add a callback
- self.cb = PyCallback(print1, ("hello",))
- self.engine.addTransaction("print1",
manta_new(self.cb.createMantaCallback()))
+ self.frame.Bind( wx.EVT_MOTION, self.OnMotion )
+ self.frame.Bind( wx.EVT_LEFT_DOWN, self.OnLeftDown )
+ self.frame.Bind( wx.EVT_LEFT_UP, self.OnLeftUp )
+ self.frame.Bind( wx.EVT_RIGHT_DOWN, self.OnRightDown )
+ # Keyboard events are ignored for wx.Frame.
+ self.frame.Bind( wx.EVT_KEY_DOWN, self.OnChar )
+
+ ##################################################################
+ # globals
+ self.trackball_radius = 0.8
+ self.mouse_is_down = False
return True
###########################################################################
- ## onExit (called under normal shutdown)
+ ## OnExit (called under normal shutdown)
###########################################################################
def OnExit(self):
print "Exiting the engine"
+ self.sync_thread.abort()
self.engine.finish()
self.engine.blockUntilFinished()
print "Engine exited"
###########################################################################
- ## onMotion
+ ## OnMotion
+
###########################################################################
+ def OnMotion( self, event ):
+ if ( self.mouse_is_down ):
+ self.mouseRotate(event)
+ event.Skip()
+
+
###########################################################################
+ ## OnChar
###########################################################################
- def onMotion( self, event ):
- pos = event.GetPosition()
- print "Motion: %dx%d" % (pos.x, pos.y)
+ def OnChar( self, event ):
+ print "OnChar"
+ key = event.GetKeyCode()
+ if key == 'p':
+ print "Found a 'p'"
+ elif key == 'v':
+ print "Found a 'v'"
+ else:
+ print "Unknown key '%s'" % key
+
event.Skip()
###########################################################################
- ## onLeftDown
+ ## OnChar
+
###########################################################################
+ def OnFrameReady(self, event):
+ self.sync_display.renderFrame()
+ self.sync_display.doneRendering()
+
+
###########################################################################
+ ## OnLeftDown
+
###########################################################################
+ def OnLeftUp( self, event ):
+ self.mouse_is_down = False
+
+
###########################################################################
+ ## OnRightDown
###########################################################################
- def onLeftDown( self, event ):
- # Register the event with Manta
- self.engine.addTransaction("print1",
manta_new(self.cb.createMantaCallback()))
+ def OnRightDown( self, event ):
event.Skip()
+
+
###########################################################################
+ ## OnLeftDown
+
###########################################################################
+ def OnLeftDown( self, event ):
+ # Set this for the motion event
+ self.mouse_is_down = True
+
+ mouse_pos = event.GetPosition()
+ window_size = self.frame.GetSize()
+ # You need to make sure that the results are floating point
+ # instead of integer.
+ xpos = 2.0*mouse_pos.x/window_size.width - 1.0
+ ypos = 1.0 - 2.0*mouse_pos.y/window_size.height
+ self.rotate_from = self.projectToSphere(xpos, ypos,
+ self.trackball_radius)
+ event.Skip()
+
+ def mouseRotate( self, event ):
+ mouse_pos = event.GetPosition()
+ window_size = self.frame.GetSize()
+ xpos = 2.0*mouse_pos.x/window_size.width - 1.0
+ ypos = 1.0 - 2.0*mouse_pos.y/window_size.height
+
+ to = self.projectToSphere(xpos, ypos, self.trackball_radius);
+ trans = AffineTransform()
+ trans.initWithRotation(to, self.rotate_from);
+ self.rotate_from = to;
+
+ channel = 0
+ camera = self.engine.getCamera(channel)
+ cbArgs = ( trans, Camera.LookAt )
+ self.engine.addTransaction("rotate",
+
manta_new(PyCallback.static_createMantaCallback(camera.transform, cbArgs)))
+ self.last_x = mouse_pos.x;
+ self.last_y = mouse_pos.y;
+
+ def projectToSphere(self, x, y, radius):
+ x /= radius
+ y /= radius
+ rad2 = x*x+y*y
+ if ( rad2 > 1 ):
+ rad = math.sqrt(rad2)
+ x /= rad
+ y /= rad
+ return Vector(x,y,0)
+ else:
+ z = math.sqrt(1-rad2)
+ return Vector(x,y,z)
app = App()
Added: trunk/doc/Callbacks.txt
==============================================================================
--- (empty file)
+++ trunk/doc/Callbacks.txt Fri Apr 28 12:01:31 2006
@@ -0,0 +1,112 @@
+Hi, if you are reading this, you are probably wondering what on earth
+all this gunk means and how you are supposed to use it. Well, let me
+explain it as best I can.
+
+At some point you want to make a callback. A callback is simply a
+function you want to call at some future point in time. This function
+can be a global or static class member function (not tied to a
+particular class instance). It can also be a class member function
+tied to a particular instance.
+
+ global:
+ void print(char* string);
+ void do_something();
+
+
+ static class member function:
+ class MyClass {
+ public:
+ static void printType();
+ static void do_XYZ(int x, int y, int z);
+ };
+
+ class member functions tied to a class instance:
+ class MyClass2 {
+ public:
+ void update();
+ void change_X(float new_X);
+ private:
+ float x;
+ };
+
+Manta currently only supports functions that return void. As far as
+arguments are concerned there are two types.
+
+ 1. Arguments bound at callback creation time.
+ 2. Arguments bound at callback call time.
+
+These are referred to as Arg (create time) and Data (call time) in the
+code. The Data arguments are allways proceeded by the Arg arguments.
+
+Let's say you wanted to time how long it takes for a callback to take.
+You can bind the current time it was created when you generate the
+callback and then bind the current time when the callback is called.
+Here's how it would look in code:
+
+ //////////////////////////////////////////////////////////////
+
+ void printTime(double call_time, double creation_time) {
+ printf("It took %g seconds to call printTime\n",
call_time-creation_time);
+ }
+
+ ////////////////////
+ // At creation time
+
+ CallbackBase_1Data<double>* cb = Callback::create(printTime,
+ Time::currentSeconds());
+ // Register the callback with whatever will call it
+ registerCurrentTimeCallback(cb);
+
+ ////////////////////
+ // At call time
+ for(int i = 0; i < timeCallbacks.size(); ++i)
+ timeCallbacks[i]->call(Time::currentSeconds());
+
+ //////////////////////////////////////////////////////////////
+
+If your callback is a static member function, simply use the name of
+the function with the class designator:
+
+ CallbackBase_0Data* cb = Callback::create(MyClass::printType);
+ CallbackBase_0Data* cb = Callback::create(MyClass::do_XYZ, 1, 2, 3);
+
+If you callback is a member function bound to a class instance, you
+must also suply a pointer to the class:
+
+ MyClass2* mc;
+ CallbackBase_0Data* cb = Callback::create(mc, &MyClass2::update);
+ CallbackBase_0Data* cb = Callback::create(mc, &MyClass2::change_X, my_x);
+
+
+You don't always need to create a temporary variable for the callback.
+Often, if you know the type of your base class you can simply place
+the Callback::create in the callback registering function call. This
+is true for MantaInterface's transactions. The callback is a 0Data
+callback meaning there are no call time bound arguments.
+
+ rtrt_inteface->addTransaction("my callback",
+ Callback::create(mc, &MyClass2::update));
+
+This might be a good time to discuss the base classes. The caller
+only needs to know about the call time bound arguments (Data). It
+does not need to know (and nor can it know) about the creation time
+bound arguments (Arg).
+
+There is a different base class for every type of call time bound
+argument. This class is templatized to accommodate any type Data0,
+Data1, Data2, etc. might be. You have to specify the type when
+storing a list of them:
+
+ vector<CallbackBase_2Data<float, int>*> mySpecialCallbacks;
+
+Classes that are templated against the creation time bounded arguments
+(Arg1, Arg2, Arg3, etc.) are derived from the appropiate base class.
+These template types are determined when you call the create function,
+so you don't have to specify them explicitly.
+
+Since you have to write the code for the various combinations of
+number of Data parameters with the number of Arg parameters this can
+cause quite a lot of code. We've defined as many of them as we needed
+for the time being, but you may have to add additional ones as you
+need them.
+
- [MANTA] r1021 - in trunk: Core/Geometry Engine/Display Image Interface SwigInterface doc, bigler, 04/28/2006
Archive powered by MHonArc 2.6.16.