Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[MANTA] r1110 - in trunk: Core/Geometry Engine/Display Model/Lights SwigInterface


Chronological Thread 
  • From: bigler@sci.utah.edu
  • To: manta@sci.utah.edu
  • Subject: [MANTA] r1110 - in trunk: Core/Geometry Engine/Display Model/Lights SwigInterface
  • Date: Fri, 9 Jun 2006 12:44:08 -0600 (MDT)

Author: bigler
Date: Fri Jun  9 12:44:07 2006
New Revision: 1110

Added:
   trunk/SwigInterface/FloatSpin.py
Modified:
   trunk/Core/Geometry/Vector.h
   trunk/Engine/Display/OpenGLDisplay.h
   trunk/Model/Lights/HeadLight.h
   trunk/Model/Lights/PointLight.h
   trunk/SwigInterface/CMakeLists.txt
   trunk/SwigInterface/manta.i
   trunk/SwigInterface/wxManta.py
Log:

Core/Geometry/Vector.h

  Added swig version of set element.
  
Engine/Display/OpenGLDisplay.h

  Swig was getting confused with the MaybeSet sub class, so I just
  ifdefed it out.

Model/Lights/HeadLight.h
Model/Lights/PointLight.h

  Added get and set accessors.

SwigInterface/CMakeLists.txt

  Copy FloatSpin.py over to where _manta was built.
  
SwigInterface/FloatSpin.py

  wxPython extension for floating point spinners.

SwigInterface/manta.i

  Rearange things to allow Light to be extended to have asPointLight
  and asHeadLight casting functions.

SwigInterface/wxManta.py

  Added LightFrame window that allows us to edit the light locations
  and colors.


Modified: trunk/Core/Geometry/Vector.h
==============================================================================
--- trunk/Core/Geometry/Vector.h        (original)
+++ trunk/Core/Geometry/Vector.h        Fri Jun  9 12:44:07 2006
@@ -111,6 +111,9 @@
       Real& __getitem__( int i ) {
         return self->operator[](i);
       }
+      void __setitem__(int i,Real val) {
+        self->operator[](i) = val;
+      }
     }
 #endif
     // One might be tempted to add an "operator &" function, but

Modified: trunk/Engine/Display/OpenGLDisplay.h
==============================================================================
--- trunk/Engine/Display/OpenGLDisplay.h        (original)
+++ trunk/Engine/Display/OpenGLDisplay.h        Fri Jun  9 12:44:07 2006
@@ -49,6 +49,7 @@
     PureOpenGLDisplay* ogl;
     bool verbose;
 
+#ifndef SWIG
     // Handy little class to test whether a variable has been set.
     // This assumes that you only want to use the value if you called
     // set.
@@ -70,6 +71,7 @@
     };
     MaybeSet<bool> single_buffered;
     MaybeSet<bool> use_buffersubdata;
+#endif
 
     bool displayFrameRate;
 

Modified: trunk/Model/Lights/HeadLight.h
==============================================================================
--- trunk/Model/Lights/HeadLight.h      (original)
+++ trunk/Model/Lights/HeadLight.h      Fri Jun  9 12:44:07 2006
@@ -9,16 +9,21 @@
 namespace Manta {
   class HeadLight : public Light {
   public:
-    HeadLight(const Real offset_, const Color &color_) : offset( offset_ ), 
color( color_ ) {  };
+    HeadLight(const Real offset_, const Color &color_)
+      : offset( offset_ ), color( color_ )
+    {  };
 
     virtual void preprocess(const PreprocessContext&) { /* Does Nothing. */ 
};
     virtual void computeLight(RayPacket& destRays,
                               const RenderContext &context,
                               RayPacket& sourceRays) const;
 
+    Real getOffset() const { return offset; };
     void setOffset( Real offset_ ) { offset = offset_; };
-    Real getOffset() { return offset; };
 
+    Color getColor() const { return color; }
+    void setColor(const Color& new_c) { color = new_c; }
+    
   private:
     Real  offset;
     Color color;

Modified: trunk/Model/Lights/PointLight.h
==============================================================================
--- trunk/Model/Lights/PointLight.h     (original)
+++ trunk/Model/Lights/PointLight.h     Fri Jun  9 12:44:07 2006
@@ -16,6 +16,14 @@
 
     virtual void computeLight(RayPacket& rays, const RenderContext &context,
                               RayPacket& source) const;
+
+    // Accessors
+    Vector getPosition() const { return position; }
+    void setPosition(const Vector& new_p) { position = new_p; }
+
+    Color getColor() const { return color; }
+    void setColor(const Color& new_c) { color = new_c; }
+    
   private:
     Vector position;
     Color color;

Modified: trunk/SwigInterface/CMakeLists.txt
==============================================================================
--- trunk/SwigInterface/CMakeLists.txt  (original)
+++ trunk/SwigInterface/CMakeLists.txt  Fri Jun  9 12:44:07 2006
@@ -45,6 +45,17 @@
   pycallback.i pycallback.cc pycallback.h)
 SWIG_LINK_LIBRARIES(pycallback ${PYTHON_LIBRARIES})
 
+
+# Copy the manta.py swig compiled object to the lib directory.
+ADD_CUSTOM_COMMAND(
+   TARGET _manta
+   POST_BUILD
+   COMMAND      ${CMAKE_COMMAND}
+   ARGS -E copy ${CMAKE_CURRENT_SOURCE_DIR}/FloatSpin.py
+                ${PROJECT_BINARY_DIR}/lib/FloatSpin.py
+   COMMENT "Copying FloatSpin.py to ${PROJECT_BINARY_DIR}/lib/FloatSpin.py"
+                )
+
 ############################################################
 # Load a scene from a python script.
 SET(SCENE_PYTHON 0 CACHE BOOL "Load a scene from a python script..")

Added: trunk/SwigInterface/FloatSpin.py
==============================================================================
--- (empty file)
+++ trunk/SwigInterface/FloatSpin.py    Fri Jun  9 12:44:07 2006
@@ -0,0 +1,1305 @@
+# 
--------------------------------------------------------------------------- #
+# FLOATSPIN Control wxPython IMPLEMENTATION
+# Python Code By:
+#
+# Andrea Gavana, @ 16 Nov 2005
+# Latest Revision: 16 Nov 2005, 21.50 CET
+#
+#
+# TODO List/Caveats
+#
+# 1. Ay Idea?
+#
+# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
+# Write To Me At:
+#
+# andrea.gavana@agip.it
+# andrea_gavan@tin.it
+#
+# Or, Obviously, To The wxPython Mailing List!!!
+#
+#
+# End Of Comments
+# 
--------------------------------------------------------------------------- #
+
+
+"""
+Description:
+
+FloatSpin Implements A Floating Point SpinCtrl. It Is Built Using A Custom
+wx.PyControl, Composed By A wx.TextCtrl And A wx.SpinButton. In Order To
+Correctly Handle Floating Points Numbers Without Rounding Errors Or Non-Exact
+Floating Point Representations, FloatSpin Uses The Great FixedPoint Class
+From Tim Peters.
+
+What You Can Do:
+
+- Set The Number Of Representative Digits For Your Floating Point Numbers;
+- Set The Floating Point Format (%f, %F, %e, %E, %g, %G);
+- Set The Increment Of Every EVT_FLOATSPIN Event;
+- Set Minimum, Maximum Values For FloatSpin As Well As Its Range;
+- Change Font And Colour For The Underline wx.TextCtrl.
+
+
+Events Catched:
+
+FloatSpin Catched 3 Different Types Of Events:
+
+1) Spin Events: Events Generated By Spinning Up/Down The SpinButton;
+2) Char Events: Playing With Up/Down Arrows Of The Keyboard Increase/Decrease
+   The Value Of FloatSpin;
+3) Mouse Wheel Event: Using The Wheel Will Change The Value Of FloatSpin.
+
+In Addition, There Are Some Other Functionalities:
+
+It Remembers The Initial Value As A Default Value, Call SetToDefaultValue, Or
+Press <ESC> To Return To It
+
+Shift + Arrow = 2 * Increment        (Or Shift + Mouse Wheel)
+Ctrl  + Arrow = 10 * Increment       (Or Ctrl + Mouse Wheel)
+Alt   + Arrow = 100 * Increment       (Or Alt + Mouse Wheel)
+
+Combinations Of Shift, Ctrl, Alt Increment The FloatSpin Value By The Product
+Of The Factors;
+
+PgUp & PgDn = 10 * Increment * The Product Of The Shift, Ctrl, Alt Factors;
+
+<SPACE> Sets The Control's Value To It's Last Valid State.
+
+
+Usage:
+
+FloatSpin Construction Can Be Summarized As Follows:
+
+FloatSpin.__init__(self, parent, id, pos=wx.DefaultPosition,
+                   size=wx.DefaultSize, style=0, value=0.0, min=0.0, 
max=100.0,
+                   increment=1.0, digits=-1, extrastyle=FS_LEFT,
+                   name="FloatSpin")
+
+Where:
+
+- value: Is The Current Value For FloatSpin;
+- min: The Minimum Value;
+- max: The Maximum Value;
+- increment: The Increment For Every EVT_FLOATSPIN Events;
+- digits: Number Of Representative Digits For Your Floating Point Numbers;
+- extrastyle: One Of The Following:
+  a) FS_LEFT: Align Underline wx.TextCtrl Left;
+  b) FS_RIGHT: Align Underline wx.TextCtrl Right;
+  c) FS_CENTER: Align Underline wx.TextCtrl Center;
+  Plus The Possibility To Use FS_READONLY, That Makes The Underline 
wx.TextCtrl
+  Read-Only (No Edits Possible).
+
+See FloatSpin __init__() Method For The Definition Of Non Standard (Non
+wxPython) Parameters.
+
+FloatSpin Control Is Freeware And Distributed Under The wxPython License. 
+
+Latest Revision: Andrea Gavana @ 16 Nov 2005, 21.50 CET
+
+"""
+
+
+#----------------------------------------------------------------------
+# Beginning Of FLOATSPIN wxPython Code
+#----------------------------------------------------------------------
+
+import wx
+
+# Set The Styles For The Underline wx.TextCtrl
+FS_READONLY = 1
+FS_LEFT = 2
+FS_CENTRE = 4
+FS_RIGHT = 8
+
+# Define The FloatSpin Event
+wxEVT_FLOATSPIN = wx.NewEventType()
+
+#-----------------------------------#
+#        FloatSpinEvent
+#-----------------------------------#
+
+EVT_FLOATSPIN = wx.PyEventBinder(wxEVT_FLOATSPIN, 1)
+
+# 
---------------------------------------------------------------------------- #
+# Class FloatSpinEvent
+# 
---------------------------------------------------------------------------- #
+
+class FloatSpinEvent(wx.PyCommandEvent):
+    """ This Event Will Be Sent When A EVT_FLOATSPIN Event Is Mapped In The 
Parent. """
+    
+    def __init__(self, eventType, id=1, nSel=-1, nOldSel=-1):
+        """ Default Class Constructor. """
+        
+        wx.PyCommandEvent.__init__(self, eventType, id)
+        self._eventType = eventType
+
+
+    def SetPosition(self, pos):
+        """ Sets Event Position. """
+        
+        self._position = pos
+        
+
+    def GetPosition(self):
+        """ Returns Event Position. """
+        
+        return self._position
+
+
+#----------------------------------------------------------------------------
+# FloatTextCtrl
+#----------------------------------------------------------------------------
+
+
+class FloatTextCtrl(wx.TextCtrl):
+
+    def __init__(self, parent, id=wx.ID_ANY, value="", 
pos=wx.DefaultPosition,
+                 size=wx.DefaultSize, style=wx.TE_NOHIDESEL | 
wx.TE_PROCESS_ENTER,
+                 validator=wx.DefaultValidator,
+                 name=wx.TextCtrlNameStr):
+        """
+        Default Class Constructor.
+        Used Internally. Do Not Call Directly This Class In Your Code!
+        """
+        
+        wx.TextCtrl.__init__(self, parent, id, value, pos, size, style, 
validator, name)
+        
+        self._parent = parent
+        self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
+        self.Bind(wx.EVT_CHAR, self.OnChar)
+        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
+
+
+    def OnDestroy(self, event):
+        """ Tries To Correctly Handle The Control Destruction Under MSW. """
+        
+        if self._parent:
+            self._parent._textctrl = None
+            self._parent = None
+
+
+    def OnChar(self, event):
+        """ Handles The wx.EVT_CHAR Event By Passing It To FloatSpin. """
+
+        if self._parent:
+            self._parent.OnChar(event)
+
+
+    def OnKillFocus(self, event):
+        """ Synchronize The wx.SpinButton And The wx.TextCtrl When Focus Is 
Lost. """
+
+        if self._parent:
+            self._parent.SyncSpinToText(True)
+            
+        event.Skip()
+
+
+#----------------------------------------------------------------------------
 #
+# FloatSpin
+# This Is The Main Class Implementation
+# 
---------------------------------------------------------------------------- #
+
+class FloatSpin(wx.PyControl):
+
+    def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
+                 size=(95,-1), style=0, value=0.0, min=0.0, max=100.0,
+                 increment=1.0, digits=-1, extrastyle=FS_LEFT,
+                 name="FloatSpin"):
+        """
+        Default Class Constructor. Non-Default Parameters Are:
+        
+        - value: Is The Current Value For FloatSpin;
+        - min: The Minimum Value;
+        - max: The Maximum Value;
+        - increment: The Increment For Every EVT_FLOATSPIN Events;
+        - digits: Number Of Representative Digits For Your Floating Point 
Numbers;
+        - extrastyle: One Of The Following:
+          a) FS_LEFT: Align Underline wx.TextCtrl Left;
+          b) FS_RIGHT: Align Underline wx.TextCtrl Right;
+          c) FS_CENTER: Align Underline wx.TextCtrl Center;
+          Plus The Possibility To Use FS_READONLY, That Makes The Underline 
wx.TextCtrl
+          Read-Only (No Edits Possible).
+          
+        """
+        
+        wx.PyControl.__init__(self, parent, id, pos, size, 
style|wx.NO_BORDER|
+                              wx.NO_FULL_REPAINT_ON_RESIZE | 
wx.CLIP_CHILDREN,
+                              wx.DefaultValidator, name)
+
+        self._min = FixedPoint(str(min), 20)
+        self._max = FixedPoint(str(max), 20)
+
+        if (min <= max):
+            if value < min:
+                value = min
+            elif value > max:
+                value = max
+        
+            
+        self._value = FixedPoint(str(value), 20)
+        self._defaultvalue = self._value
+        self._increment = FixedPoint(str(increment), 20)
+        self._spinmodifier = FixedPoint(str(1.0), 20)
+        self._digits = digits
+        self._snapticks = False
+        self._spinbutton = None
+        self._textctrl = None
+        self._spinctrl_bestsize = wx.Size(-999, -999)
+
+        self.SetLabel(name)
+        self.SetBackgroundColour(parent.GetBackgroundColour())
+        self.SetForegroundColour(parent.GetForegroundColour())
+
+        width = size[0]
+        height = size[1]
+        best_size = self.DoGetBestSize()
+        
+        if width == -1:
+            width = best_size.GetWidth()
+        if height == -1:
+            height = best_size.GetHeight()
+
+        self.SetBestSize((width, height))
+        
+        self._validkeycode = [43, 45, 46, 69, 101, 127, 314]
+        self._validkeycode.extend(range(48, 58))
+        self._validkeycode.extend([wx.WXK_RETURN, wx.WXK_TAB, wx.WXK_BACK,
+                                   wx.WXK_LEFT, wx.WXK_RIGHT])
+       
+        self._spinbutton = wx.SpinButton(self, wx.ID_ANY, wx.DefaultPosition,
+                                         size=(-1, height),
+                                         style=wx.SP_ARROW_KEYS | 
wx.SP_VERTICAL |
+                                         wx.SP_WRAP)
+
+        txtstyle = wx.TE_NOHIDESEL | wx.TE_PROCESS_ENTER
+        
+        if extrastyle & FS_RIGHT:
+            txtstyle = txtstyle | wx.TE_RIGHT
+        elif extrastyle & FS_CENTRE:
+            txtstyle = txtstyle | wx.TE_CENTER
+
+        if extrastyle & FS_READONLY:
+            txtstyle = txtstyle | wx.TE_READONLY
+        
+        self._textctrl = FloatTextCtrl(self, wx.ID_ANY, str(self._value),
+                                       wx.DefaultPosition,
+                                       
(width-self._spinbutton.GetSize().GetWidth(), height),
+                                       txtstyle)
+
+        self._mainsizer = wx.BoxSizer(wx.HORIZONTAL)
+        self._mainsizer.Add(self._textctrl, 0)
+        self._mainsizer.Add(self._spinbutton, 0)
+        self.SetSizer(self._mainsizer)
+        self._mainsizer.Layout()
+
+        self.SetFormat()    
+        self.SetDigits(digits)
+        
+        # set the value here without generating an event
+
+        strs = ("%100." + str(self._digits) + 
self._textformat[1])%self._value
+        
+        strs = strs.strip()
+        strs = self.ReplaceDoubleZero(strs)
+        
+        self._textctrl.SetValue(strs)
+
+        self.Bind(wx.EVT_SPIN_UP, self.OnSpinUp)
+        self.Bind(wx.EVT_SPIN_DOWN, self.OnSpinDown)
+        self.Bind(wx.EVT_TEXT_ENTER, self.OnTextEnter)
+        self.Bind(wx.EVT_SET_FOCUS, self.OnFocus)
+        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
+        self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
+        self._spinbutton.Bind(wx.EVT_LEFT_DOWN, self.OnSpinMouseDown)
+        
+
+    def OnDestroy(self, event):
+        """ Tries To Correctly Handle The Control Destruction Under MSW. """
+        
+        # Null This Since MSW Sends KILL_FOCUS On Deletion 
+        if self._textctrl: 
+            self._textctrl._parent = None
+            self._textctrl.Destroy()
+            self._textctrl = None
+        
+        self._spinbutton.Destroy()
+        self._spinbutton = None
+
+
+    def DoGetBestSize(self):
+        """ Calculates The Best Size For FloatSpin. """
+   
+        if self._spinctrl_bestsize.x == -999:
+            
+            spin = wx.SpinCtrl(self, -1)
+            self._spinctrl_bestsize = spin.GetBestSize()
+            
+            # oops something went wrong, set to reasonable value
+            if self._spinctrl_bestsize.GetWidth() < 20:
+                self._spinctrl_bestsize.SetWidth(95)
+            if self._spinctrl_bestsize.GetHeight() < 10:
+                self._spinctrl_bestsize.SetHeight(22)
+
+            spin.Destroy()
+
+        return self._spinctrl_bestsize
+
+
+    def DoSendEvent(self):
+        """ Send The Event To The Parent. """
+
+        event = wx.CommandEvent(wx.wxEVT_COMMAND_SPINCTRL_UPDATED, 
self.GetId())
+        event.SetEventObject(self)
+        event.SetInt(int(self._value + 0.5))
+        
+        if self._textctrl:
+            event.SetString(self._textctrl.GetValue())
+
+        self.GetEventHandler().ProcessEvent(event)
+
+        eventOut = FloatSpinEvent(wxEVT_FLOATSPIN, self.GetId())
+        eventOut.SetPosition(int(self._value + 0.5))
+        eventOut.SetEventObject(self)
+        self.GetEventHandler().ProcessEvent(eventOut)
+
+
+    def OnSpinMouseDown(self, event):
+
+        modifier = FixedPoint(str(1.0), 20)
+        if event.m_shiftDown:
+            modifier = modifier*2.0
+        if event.m_controlDown:
+            modifier = modifier*10.0
+        if event.m_altDown:
+            modifier = modifier*100.0
+
+        self._spinmodifier = modifier
+        
+        event.Skip()
+        
+
+    def OnSpinUp(self, event):
+        """ Handles The wx.EVT_SPIN_UP For FloatSpin. """
+
+        if self._textctrl and self._textctrl.IsModified(): 
+            self.SyncSpinToText(False)
+  
+        if self.InRange(self._value + self._increment*self._spinmodifier):
+        
+            self._value = self._value + self._increment*self._spinmodifier
+            self.SetValue(self._value)
+            self.DoSendEvent()
+    
+
+    def OnSpinDown(self, event):
+        """ Handles The wx.EVT_SPIN_DOWN For FloatSpin. """
+        
+        if self._textctrl and self._textctrl.IsModified(): 
+            self.SyncSpinToText(False)
+        
+        if self.InRange(self._value - self._increment*self._spinmodifier):
+        
+            self._value = self._value - self._increment*self._spinmodifier
+            self.SetValue(self._value)
+            self.DoSendEvent()
+    
+
+    def OnTextEnter(self, event):
+        """ Handles The wx.EVT_TEXT_ENTER For The Underline wx.TextCtrl. """
+
+        self.SyncSpinToText(True)
+        event.Skip()
+
+
+    def OnChar(self, event):
+        """ Handles The wx.EVT_CHAR For The Underline wx.TextCtrl. """
+
+        modifier = FixedPoint(str(1.0), 20)
+        if event.m_shiftDown:
+            modifier = modifier*2.0
+        if event.m_controlDown:
+            modifier = modifier*10.0
+        if event.m_altDown:
+            modifier = modifier*100.0
+
+        keycode = event.GetKeyCode()
+
+        if keycode == wx.WXK_UP:
+        
+            if self._textctrl and self._textctrl.IsModified():
+                self.SyncSpinToText(False)
+
+            self.SetValue(self._value + self._increment*modifier)
+            self.DoSendEvent()
+        
+        elif keycode == wx.WXK_DOWN:
+        
+            if self._textctrl and self._textctrl.IsModified():
+                self.SyncSpinToText(False)
+                
+            self.SetValue(self._value - self._increment*modifier)
+            self.DoSendEvent()
+        
+        elif keycode == wx.WXK_PRIOR:
+
+            if self._textctrl and self._textctrl.IsModified():
+                self.SyncSpinToText(False)
+
+            self.SetValue(self._value + 10.0*self._increment*modifier)
+            self.DoSendEvent()
+            
+        elif keycode == wx.WXK_NEXT:
+
+            if self._textctrl and self._textctrl.IsModified():
+                self.SyncSpinToText(False)
+
+            self.SetValue(self._value - 10.0*self._increment*modifier)
+            self.DoSendEvent()
+                    
+        elif keycode == wx.WXK_SPACE:
+        
+            self.SetValue(self._value)
+            event.Skip(False)
+
+        elif keycode == wx.WXK_ESCAPE:
+        
+            self.SetToDefaultValue()
+            self.DoSendEvent()
+        
+        elif keycode == wx.WXK_TAB:
+        
+            new_event = wx.NavigationKeyEvent()
+            new_event.SetEventObject(self.GetParent())
+            new_event.SetDirection(not event.ShiftDown())
+            # CTRL-TAB changes the (parent) window, i.e. switch notebook page
+            new_event.SetWindowChange(event.ControlDown())
+            new_event.SetCurrentFocus(self)
+            self.GetParent().GetEventHandler().ProcessEvent(new_event)
+
+        else:
+            if keycode not in self._validkeycode:
+                return
+            
+            event.Skip()
+    
+
+    def OnMouseWheel(self, event):
+        """ Handles The wx.EVT_MOUSEWHEEL For FloatSpin. """
+
+        modifier = FixedPoint(str(1.0), 20)
+        if event.m_shiftDown:
+            modifier = modifier*2.0
+        if event.m_controlDown:
+            modifier = modifier*10.0
+        if event.m_altDown:
+            modifier = modifier*100.0
+
+        if self._textctrl and self._textctrl.IsModified():
+            self.SyncSpinToText(False)
+
+        if event.GetWheelRotation() > 0:
+            self.SetValue(self._value + self._increment*modifier)
+            self.DoSendEvent()
+
+        else:
+
+            self.SetValue(self._value - self._increment*modifier)
+            self.DoSendEvent()
+            
+
+    def ReplaceDoubleZero(self, strs):
+        """ Replaces The (Somewhat) Python Ugly '+e000' With +e00. """
+
+        if self._textformat not in ["%g", "%e", "%E", "%G"]:
+            return strs
+
+        if strs.find("e+00") >= 0:
+            strs = strs.replace("e+00", "e+0")
+        elif strs.find("e-00") >= 0:
+            strs = strs.replace("e-00", "e-0")
+        elif strs.find("E+00") >= 0:
+            strs = strs.replace("E+00", "E+0")
+        elif strs.find("E-00") >= 0:
+            strs = strs.replace("E-00", "E-0")
+
+        return strs
+    
+
+    def SetValue(self, value):
+        """ Sets The FloatSpin Value. """
+
+        if not self._textctrl or not self.InRange(value):
+            return
+
+        if self._snapticks and self._increment != 0.0:
+        
+            finite, snap_value = self.IsFinite(value)
+
+            if not finite: # FIXME What To Do About A Failure?
+    
+                if (snap_value - floor(snap_value) < ceil(snap_value) - 
snap_value):
+                    value = self._defaultvalue + 
floor(snap_value)*self._increment
+                else:
+                    value = self._defaultvalue + 
ceil(snap_value)*self._increment
+
+        strs = ("%100." + str(self._digits) + self._textformat[1])%value
+        strs = strs.strip()
+        strs = self.ReplaceDoubleZero(strs)
+
+        if value != self._value or strs != self._textctrl.GetValue():
+        
+            self._textctrl.SetValue(strs)
+            self._textctrl.DiscardEdits()
+            self._value = value
+
+
+    def GetValue(self):
+        """ Returns The FloatSpin Value. """
+        
+        return self._value
+
+
+    def SetRange(self, min_val, max_val):
+        """
+        Set The Allowed Range, If max_val < min_val Then No Range And All
+        Values Are Allowed.
+        """
+        
+        self._min = FixedPoint(str(min_val), 20)
+        self._max = FixedPoint(str(max_val), 20)
+
+        if self.HasRange():
+            if self._value > self._max:
+                self.SetValue(self._max)
+            elif self._value < self._min:
+                self.SetValue(self._min)
+    
+
+    def SetIncrement(self, increment):
+        """ Sets The Increment For Every EVT_FLOATSPIN Event. """
+
+        if increment < 1./10.0**self._digits:
+            raise "\nERROR: Increment Should Be Greater Or Equal To 
1/(10**digits)."
+        
+        self._increment = FixedPoint(str(increment), 20)
+        self.SetValue(self._value)
+
+    
+    def GetIncrement(self):
+        """ Returns The Increment For Every EVT_FLOATSPIN Event. """
+
+        return self._increment
+    
+
+    def SetDigits(self, digits=-1):
+        """
+        Sets The Number Of Digits To Show. If digits < 0, FloatSpin Tries To
+        Calculate The Best Number Of Digits Based On Input __init__ Values.
+        """
+        
+        if digits < 0:
+            incr = str(self._increment)
+            if incr.find(".") < 0:
+                digits = 0
+            else:
+                digits = len(incr[incr.find(".")+1:])
+                
+        self._digits = digits
+        
+        self.SetValue(self._value)
+
+
+    def GetDigits(self):
+        """ Returns The Number Of Digits Shown. """
+
+        return self._digits
+    
+
+    def SetFormat(self, fmt="%f"):
+        """ Set The String Format To Use. """
+        
+        if fmt not in ["%f", "%g", "%e", "%E", "%F", "%G"]:
+            raise '\nERROR: Bad Float Number Format: ' + repr(fmt) + '. It 
Should Be ' \
+                  'One Of "%f", "%g", "%e", "%E", "%F", "%G"'
+
+        self._textformat = fmt
+
+        if self._digits < 0:
+            self.SetDigits()
+            
+        self.SetValue(self._value)
+        
+
+    def GetFormat(self):
+        """ Returns The String Format In Use. """
+
+        return self._textformat
+    
+
+    def SetDefaultValue(self, defaultvalue):
+        """ Sets The FloatSpin Default Value. """
+
+        if self.InRange(defaultvalue):        
+            self._defaultvalue = FixedPoint(str(defaultvalue), 20)
+
+
+    def GetDefaultValue(self):
+        """ Returns The FloatSpin Default Value. """
+
+        return self._defaultvalue
+
+
+    def IsDefaultValue(self):
+        """ Returns Whether The Current Value Is The Default Value Or Not. 
"""
+        
+        return self._value == self._defaultvalue
+    
+
+    def SetToDefaultValue(self):
+        """ Sets FloatSpin Value To Its Default Value. """
+
+        self.SetValue(self._defaultvalue)        
+
+
+    def SetSnapToTicks(self, forceticks=True):
+        """
+        Force The Value To Always Be Divisible By The Increment. Initially 
False.
+        This Uses The Default Value As The Basis, You Will Get Strange 
Results
+        For Very Large Differences Between The Current Value And Default 
Value
+        When The Increment Is Very Small.
+        """
+
+        if self._snapticks != forceticks:
+        
+            self._snapticks = forceticks
+            self.SetValue(self._value)
+
+
+    def GetSnapToTicks(self):
+        """ Returns Whether The Snap To Ticks Option Is Active Or Not. """
+        
+        return self._snapticks        
+    
+
+    def OnFocus(self, event):
+        """ Handles The wx.EVT_SET_FOCUS Event For FloatSpin. """
+
+        if self._textctrl:
+            self._textctrl.SetFocus()
+
+        event.Skip()
+
+
+    def OnKillFocus(self, event):
+        """ Handles The wx.EVT_KILL_FOCUS Event For FloatSpin. """
+        
+        self.SyncSpinToText(True)
+        event.Skip()
+
+
+    def SyncSpinToText(self, send_event=True, force_valid=True):
+        """ Synchronize The Underline wx.TextCtrl With wx.SpinButton. """
+        
+        if not self._textctrl:
+            return
+
+        curr = self._textctrl.GetValue()
+        curr = curr.strip()
+        
+        if curr:
+            try:
+                curro = float(curr)
+                curr = FixedPoint(curr, 20)
+            except:
+                self.SetValue(self._value)
+                return
+            
+            if force_valid or not self.HasRange() or self.InRange(curr):
+            
+                if force_valid and self.HasRange():
+                
+                    if curr > self.GetMax():
+                        curr = self.GetMax()
+                    elif curr < self.GetMin(): 
+                        curr = self.GetMin()
+                
+                if self._value != curr:
+                    self.SetValue(curr)
+                    
+                    if send_event:
+                        self.DoSendEvent()
+                
+        elif force_valid:
+          
+            # textctrl is out of sync, discard and reset
+            self.SetValue(self.GetValue())
+        
+
+    def SetFont(self, font=None):
+        """ Set The Underline wx.TextCtrl Font. """
+
+        if font is None:
+            font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
+
+        if not self._textctrl:
+            return False
+
+        return self._textctrl.SetFont(font)
+
+
+    def GetFont(self):
+        """ Returns The Underline wx.TextCtrl Font. """
+
+        if not self._textctrl:
+            return self.GetFont()
+        
+        return self._textctrl.GetFont()
+
+
+    def GetMin(self):
+        """ Returns The Minimum Value For FloatSpin. """
+        
+        return self._min
+
+
+    def GetMax(self):
+        """ Returns The Maximum Value For FloatSpin. """
+
+        return self._max
+
+
+    def HasRange(self):
+        """ Returns Whether FloatSpin Has A Range Or Not. """
+        
+        return self._min <= self._max        
+
+
+    def InRange(self, value):
+        """ Returns Whether A Value Is Inside FloatSpin Range. """
+
+        return not self.HasRange() or (value >= self._min and value <= 
self._max)
+
+
+    def GetTextCtrl(self):
+        """ Returns The Underline wx.TextCtrl. """
+
+        return self._textctrl
+
+
+    def IsFinite(self, value):
+        """ Tries To Determine If A Value Is Finite Or Infinite/NaN. """
+
+        try:
+            snap_value = (value - self._defaultvalue)/self._increment
+            finite = True
+        except:
+            finite = False
+            snap_value = None
+
+        return finite, snap_value            
+
+
+
+# Class FixedPoint, version 0.0.4.
+# Released to the public domain 28-Mar-2001,
+# by Tim Peters (tim.one@home.com).
+
+# Provided as-is; use at your own risk; no warranty; no promises; enjoy!
+
+"""
+FixedPoint objects support decimal arithmetic with a fixed number of
+digits (called the object's precision) after the decimal point.  The
+number of digits before the decimal point is variable & unbounded.
+
+The precision is user-settable on a per-object basis when a FixedPoint
+is constructed, and may vary across FixedPoint objects.  The precision
+may also be changed after construction via FixedPoint.set_precision(p).
+Note that if the precision of a FixedPoint is reduced via set_precision,
+information may be lost to rounding.
+
+>>> x = FixedPoint("5.55")  # precision defaults to 2
+>>> print x
+5.55
+>>> x.set_precision(1)      # round to one fraction digit
+>>> print x
+5.6
+>>> print FixedPoint("5.55", 1)  # same thing setting to 1 in constructor
+5.6
+>>> repr(x) #  returns constructor string that reproduces object exactly
+"FixedPoint('5.6', 1)"
+>>>
+
+When FixedPoint objects of different precision are combined via + - * /,
+the result is computed to the larger of the inputs' precisions, which also
+becomes the precision of the resulting FixedPoint object.
+
+>>> print FixedPoint("3.42") + FixedPoint("100.005", 3)
+103.425
+>>>
+
+When a FixedPoint is combined with other numeric types (ints, floats,
+strings representing a number) via + - * /, then similarly the computation
+is carried out using-- and the result inherits --the FixedPoint's
+precision.
+
+>>> print FixedPoint(1) / 7
+0.14
+>>> print FixedPoint(1, 30) / 7
+0.142857142857142857142857142857
+>>>
+
+The string produced by str(x) (implictly invoked by "print") always
+contains at least one digit before the decimal point, followed by a
+decimal point, followed by exactly x.get_precision() digits.  If x is
+negative, str(x)[0] == "-".
+
+The FixedPoint constructor can be passed an int, long, string, float,
+FixedPoint, or any object convertible to a float via float() or to a
+long via long().  Passing a precision is optional; if specified, the
+precision must be a non-negative int.  There is no inherent limit on
+the size of the precision, but if very very large you'll probably run
+out of memory.
+
+Note that conversion of floats to FixedPoint can be surprising, and
+should be avoided whenever possible.  Conversion from string is exact
+(up to final rounding to the requested precision), so is greatly
+preferred.
+
+>>> print FixedPoint(1.1e30)
+1099999999999999993725589651456.00
+>>> print FixedPoint("1.1e30")
+1100000000000000000000000000000.00
+>>>
+
+The following Python operators and functions accept FixedPoints in the
+expected ways:
+
+    binary + - * / % divmod
+        with auto-coercion of other types to FixedPoint.
+        + - % divmod  of FixedPoints are always exact.
+        * / of FixedPoints may lose information to rounding, in
+            which case the result is the infinitely precise answer
+            rounded to the result's precision.
+        divmod(x, y) returns (q, r) where q is a long equal to
+            floor(x/y) as if x/y were computed to infinite precision,
+            and r is a FixedPoint equal to x - q * y; no information
+            is lost.  Note that q has the sign of y, and abs(r) < abs(y).
+    unary -
+    == != < > <= >=  cmp
+    min  max
+    float  int  long    (int and long truncate)
+    abs
+    str  repr
+    hash
+    use as dict keys
+    use as boolean (e.g. "if some_FixedPoint:" -- true iff not zero)
+
+Methods unique to FixedPoints:
+   .copy()              return new FixedPoint with same value
+   .frac()              long(x) + x.frac() == x
+   .get_precision()
+   .set_precision(p)
+"""
+
+# 28-Mar-01 ver 0.0,4
+#     Use repr() instead of str() inside __str__, because str(long) changed
+#     since this was first written (used to produce trailing "L", doesn't
+#     now).
+#
+# 09-May-99 ver 0,0,3
+#     Repaired __sub__(FixedPoint, string); was blowing up.
+#     Much more careful conversion of float (now best possible).
+#     Implemented exact % and divmod.
+#
+# 14-Oct-98 ver 0,0,2
+#     Added int, long, frac.  Beefed up docs.  Removed DECIMAL_POINT
+#     and MINUS_SIGN globals to discourage bloating this class instead
+#     of writing formatting wrapper classes (or subclasses)
+#
+# 11-Oct-98 ver 0,0,1
+#     posted to c.l.py
+
+__version__ = 0, 0, 4
+
+# The default value for the number of decimal digits carried after the
+# decimal point.  This only has effect at compile-time.
+DEFAULT_PRECISION = 2
+
+class FixedPoint:
+
+    # the exact value is self.n / 10**self.p;
+    # self.n is a long; self.p is an int
+
+    def __init__(self, value=0, precision=DEFAULT_PRECISION):
+        self.n = self.p = 0
+        self.set_precision(precision)
+        p = self.p
+
+        if isinstance(value, type("42.3e5")):
+            n, exp = _string2exact(value)
+            # exact value is n*10**exp = n*10**(exp+p)/10**p
+            effective_exp = exp + p
+            if effective_exp > 0:
+                n = n * _tento(effective_exp)
+            elif effective_exp < 0:
+                n = _roundquotient(n, _tento(-effective_exp))
+            self.n = n
+            return
+
+        if isinstance(value, type(42)) or isinstance(value, type(42L)):
+            self.n = long(value) * _tento(p)
+            return
+
+        if isinstance(value, FixedPoint):
+            temp = value.copy()
+            temp.set_precision(p)
+            self.n, self.p = temp.n, temp.p
+            return
+
+        if isinstance(value, type(42.0)):
+            # XXX ignoring infinities and NaNs and overflows for now
+            import math
+            f, e = math.frexp(abs(value))
+            assert f == 0 or 0.5 <= f < 1.0
+            # |value| = f * 2**e exactly
+
+            # Suck up CHUNK bits at a time; 28 is enough so that we suck
+            # up all bits in 2 iterations for all known binary double-
+            # precision formats, and small enough to fit in an int.
+            CHUNK = 28
+            top = 0L
+            # invariant: |value| = (top + f) * 2**e exactly
+            while f:
+                f = math.ldexp(f, CHUNK)
+                digit = int(f)
+                assert digit >> CHUNK == 0
+                top = (top << CHUNK) | digit
+                f = f - digit
+                assert 0.0 <= f < 1.0
+                e = e - CHUNK
+
+            # now |value| = top * 2**e exactly
+            # want n such that n / 10**p = top * 2**e, or
+            # n = top * 10**p * 2**e
+            top = top * _tento(p)
+            if e >= 0:
+                n = top << e
+            else:
+                n = _roundquotient(top, 1L << -e)
+            if value < 0:
+                n = -n
+            self.n = n
+            return
+
+        if isinstance(value, type(42-42j)):
+            raise TypeError("can't convert complex to FixedPoint: " +
+                            `value`)
+
+        # can we coerce to a float?
+        yes = 1
+        try:
+            asfloat = float(value)
+        except:
+            yes = 0
+        if yes:
+            self.__init__(asfloat, p)
+            return
+
+        # similarly for long
+        yes = 1
+        try:
+            aslong = long(value)
+        except:
+            yes = 0
+        if yes:
+            self.__init__(aslong, p)
+            return
+
+        raise TypeError("can't convert to FixedPoint: " + `value`)
+
+    def get_precision(self):
+        """Return the precision of this FixedPoint.
+
+           The precision is the number of decimal digits carried after
+           the decimal point, and is an int >= 0.
+        """
+
+        return self.p
+
+    def set_precision(self, precision=DEFAULT_PRECISION):
+        """Change the precision carried by this FixedPoint to p.
+
+           precision must be an int >= 0, and defaults to
+           DEFAULT_PRECISION.
+
+           If precision is less than this FixedPoint's current precision,
+           information may be lost to rounding.
+        """
+
+        try:
+            p = int(precision)
+        except:
+            raise TypeError("precision not convertable to int: " +
+                            `precision`)
+        if p < 0:
+            raise ValueError("precision must be >= 0: " + `precision`)
+
+        if p > self.p:
+            self.n = self.n * _tento(p - self.p)
+        elif p < self.p:
+            self.n = _roundquotient(self.n, _tento(self.p - p))
+        self.p = p
+
+    def __str__(self):
+        n, p = self.n, self.p
+        i, f = divmod(abs(n), _tento(p))
+        if p:
+            frac = repr(f)[:-1]
+            frac = "0" * (p - len(frac)) + frac
+        else:
+            frac = ""
+        return "-"[:n<0] + \
+               repr(i)[:-1] + \
+               "." + frac
+
+    def __repr__(self):
+        return "FixedPoint" + `(str(self), self.p)`
+
+    def copy(self):
+        return _mkFP(self.n, self.p)
+
+    __copy__ = __deepcopy__ = copy
+
+    def __cmp__(self, other):
+        xn, yn, p = _norm(self, other)
+        return cmp(xn, yn)
+
+    def __hash__(self):
+        # caution!  == values must have equal hashes, and a FixedPoint
+        # is essentially a rational in unnormalized form.  There's
+        # really no choice here but to normalize it, so hash is
+        # potentially expensive.
+        n, p = self.__reduce()
+
+        # Obscurity: if the value is an exact integer, p will be 0 now,
+        # so the hash expression reduces to hash(n).  So FixedPoints
+        # that happen to be exact integers hash to the same things as
+        # their int or long equivalents.  This is Good.  But if a
+        # FixedPoint happens to have a value exactly representable as
+        # a float, their hashes may differ.  This is a teensy bit Bad.
+        return hash(n) ^ hash(p)
+
+    def __nonzero__(self):
+        return self.n != 0
+
+    def __neg__(self):
+        return _mkFP(-self.n, self.p)
+
+    def __abs__(self):
+        if self.n >= 0:
+            return self.copy()
+        else:
+            return -self
+
+    def __add__(self, other):
+        n1, n2, p = _norm(self, other)
+        # n1/10**p + n2/10**p = (n1+n2)/10**p
+        return _mkFP(n1 + n2, p)
+
+    __radd__ = __add__
+
+    def __sub__(self, other):
+        if not isinstance(other, FixedPoint):
+            other = FixedPoint(other, self.p)
+        return self.__add__(-other)
+
+    def __rsub__(self, other):
+        return (-self) + other
+
+    def __mul__(self, other):
+        n1, n2, p = _norm(self, other)
+        # n1/10**p * n2/10**p = (n1*n2/10**p)/10**p
+        return _mkFP(_roundquotient(n1 * n2, _tento(p)), p)
+
+    __rmul__ = __mul__
+
+    def __div__(self, other):
+        n1, n2, p = _norm(self, other)
+        if n2 == 0:
+            raise ZeroDivisionError("FixedPoint division")
+        if n2 < 0:
+            n1, n2 = -n1, -n2
+        # n1/10**p / (n2/10**p) = n1/n2 = (n1*10**p/n2)/10**p
+        return _mkFP(_roundquotient(n1 * _tento(p), n2), p)
+
+    def __rdiv__(self, other):
+        n1, n2, p = _norm(self, other)
+        return _mkFP(n2, p) / self
+
+    def __divmod__(self, other):
+        n1, n2, p = _norm(self, other)
+        if n2 == 0:
+            raise ZeroDivisionError("FixedPoint modulo")
+        # floor((n1/10**p)/(n2*10**p)) = floor(n1/n2)
+        q = n1 / n2
+        # n1/10**p - q * n2/10**p = (n1 - q * n2)/10**p
+        return q, _mkFP(n1 - q * n2, p)
+
+    def __rdivmod__(self, other):
+        n1, n2, p = _norm(self, other)
+        return divmod(_mkFP(n2, p), self)
+
+    def __mod__(self, other):
+        return self.__divmod__(other)[1]
+
+    def __rmod__(self, other):
+        n1, n2, p = _norm(self, other)
+        return _mkFP(n2, p).__mod__(self)
+
+    # caution! float can lose precision
+    def __float__(self):
+        n, p = self.__reduce()
+        return float(n) / float(_tento(p))
+
+    # XXX should this round instead?
+    # XXX note e.g. long(-1.9) == -1L and long(1.9) == 1L in Python
+    # XXX note that __int__ inherits whatever __long__ does,
+    # XXX and .frac() is affected too
+    def __long__(self):
+        answer = abs(self.n) / _tento(self.p)
+        if self.n < 0:
+            answer = -answer
+        return answer
+
+    def __int__(self):
+        return int(self.__long__())
+
+    def frac(self):
+        """Return fractional portion as a FixedPoint.
+
+           x.frac() + long(x) == x
+        """
+        return self - long(self)
+
+    # return n, p s.t. self == n/10**p and n % 10 != 0
+    def __reduce(self):
+        n, p = self.n, self.p
+        if n == 0:
+            p = 0
+        while p and n % 10 == 0:
+            p = p - 1
+            n = n / 10
+        return n, p
+
+# return 10L**n
+
+def _tento(n, cache={}):
+    try:
+        return cache[n]
+    except KeyError:
+        answer = cache[n] = 10L ** n
+        return answer
+
+# return xn, yn, p s.t.
+# p = max(x.p, y.p)
+# x = xn / 10**p
+# y = yn / 10**p
+#
+# x must be FixedPoint to begin with; if y is not FixedPoint,
+# it inherits its precision from x.
+#
+# Note that this is called a lot, so default-arg tricks are helpful.
+
+def _norm(x, y, isinstance=isinstance, FixedPoint=FixedPoint,
+                _tento=_tento):
+    assert isinstance(x, FixedPoint)
+    if not isinstance(y, FixedPoint):
+        y = FixedPoint(y, x.p)
+    xn, yn = x.n, y.n
+    xp, yp = x.p, y.p
+    if xp > yp:
+        yn = yn * _tento(xp - yp)
+        p = xp
+    elif xp < yp:
+        xn = xn * _tento(yp - xp)
+        p = yp
+    else:
+        p = xp  # same as yp
+    return xn, yn, p
+
+def _mkFP(n, p, FixedPoint=FixedPoint):
+    f = FixedPoint()
+    f.n = n
+    f.p = p
+    return f
+
+# divide x by y, rounding to int via nearest-even
+# y must be > 0
+# XXX which rounding modes are useful?
+
+def _roundquotient(x, y):
+    assert y > 0
+    n, leftover = divmod(x, y)
+    c = cmp(leftover << 1, y)
+    # c < 0 <-> leftover < y/2, etc
+    if c > 0 or (c == 0 and (n & 1) == 1):
+        n = n + 1
+    return n
+
+# crud for parsing strings
+import re
+
+# There's an optional sign at the start, and an optional exponent
+# at the end.  The exponent has an optional sign and at least one
+# digit.  In between, must have either at least one digit followed
+# by an optional fraction, or a decimal point followed by at least
+# one digit.  Yuck.
+
+_parser = re.compile(r"""
+    \s*
+    (?P<sign>[-+])?
+    (
+        (?P<int>\d+) (\. (?P<frac>\d*))?
+    |
+        \. (?P<onlyfrac>\d+)
+    )
+    ([eE](?P<exp>[-+]? \d+))?
+    \s* $
+""", re.VERBOSE).match
+
+del re
+
+# return n, p s.t. float string value == n * 10**p exactly
+
+def _string2exact(s):
+    m = _parser(s)
+    if m is None:
+        raise ValueError("can't parse as number: " + `s`)
+
+    exp = m.group('exp')
+    if exp is None:
+        exp = 0
+    else:
+        exp = int(exp)
+
+    intpart = m.group('int')
+    if intpart is None:
+        intpart = "0"
+        fracpart = m.group('onlyfrac')
+    else:
+        fracpart = m.group('frac')
+        if fracpart is None or fracpart == "":
+            fracpart = "0"
+    assert intpart
+    assert fracpart
+
+    i, f = long(intpart), long(fracpart)
+    nfrac = len(fracpart)
+    i = i * _tento(nfrac) + f
+    exp = exp - nfrac
+
+    if m.group('sign') == "-":
+        i = -i
+
+    return i, exp

Modified: trunk/SwigInterface/manta.i
==============================================================================
--- trunk/SwigInterface/manta.i (original)
+++ trunk/SwigInterface/manta.i Fri Jun  9 12:44:07 2006
@@ -277,8 +277,6 @@
 #include <Interface/TexCoordMapper.h>
 #include <Core/Util/Align.h>
 #include <Interface/RayPacket.h>
-#include <Interface/Light.h>
-#include <Interface/LightSet.h>
 %}
 
 %include <Core/Geometry/Ray.h>
@@ -288,25 +286,29 @@
 %include <Interface/TexCoordMapper.h>
 %include <Core/Util/Align.h>
 %include <Interface/RayPacket.h>
-%include <Interface/Light.h>
-%include <Interface/LightSet.h>
 
 
 ////////////////////////////////////////////////////////
 // Lights and backgrounds
 %{
+#include <Interface/Light.h>
+#include <Interface/LightSet.h>
 #include <Interface/AmbientLight.h>
 #include <Model/AmbientLights/ConstantAmbient.h>
 #include <Interface/Background.h>
 #include <Model/Backgrounds/ConstantBackground.h>
 #include <Model/Lights/PointLight.h>
+#include <Model/Lights/HeadLight.h>
 %}
 
+%include <Interface/Light.h>
+%include <Interface/LightSet.h>
 %include <Interface/AmbientLight.h>
 %include <Model/AmbientLights/ConstantAmbient.h>
 %include <Interface/Background.h>
 %include <Model/Backgrounds/ConstantBackground.h>
 %include <Model/Lights/PointLight.h>
+%include <Model/Lights/HeadLight.h>
 
 namespace Manta {
   // This tells SWIG to deallocate the memory from toString functions.
@@ -324,6 +326,24 @@
       return strdup(self->toString().c_str());
     }
   };
+
+  %extend Light {
+    Manta::PointLight* asPointLight() {
+      return dynamic_cast<Manta::PointLight*>(self);
+    }
+  };
+
+  %extend Light {
+    Manta::HeadLight* asHeadLight() {
+      return dynamic_cast<Manta::HeadLight*>(self);
+    }
+  };
+
+//   %extend PointLight {
+//     static PointLight* fromLight(Light* parent) {
+//       return dynamic_cast<Manta::PointLight*>(parent);
+//     }
+//   };
 }
 
 /////////////////////////////////////////////////////

Modified: trunk/SwigInterface/wxManta.py
==============================================================================
--- trunk/SwigInterface/wxManta.py      (original)
+++ trunk/SwigInterface/wxManta.py      Fri Jun  9 12:44:07 2006
@@ -6,12 +6,15 @@
 from wxPython.glcanvas import wxGLCanvas
 import threading
 import math
+import wx.lib.colourselect as csel
 
 from manta import *
 from pycallback import *
 
 from OpenGL.GL import *
 
+import FloatSpin as FS
+
 
 # Number of workers.
 numworkers = 2
@@ -143,6 +146,127 @@
 class Frame(wx.Frame):
     pass
 
+class LightFrame(wx.Frame):
+    def __init__(self, parent, engine):
+        wx.Frame.__init__(self, parent=parent, title="Lights")
+
+        self.engine = engine
+        self.colorButtonRefs = {}
+
+        panel= wx.Panel(self, -1)
+
+        gbs = wx.GridBagSizer(5,5)
+        
+        lights = engine.getScene().getLights()
+        for i in range(lights.numLights()):
+            gbs.Add( self.addLight(panel, lights.getLight(i)), (i, 0))
+
+        button = wx.Button(panel, -1, "Close")
+        gbs.Add( button, (lights.numLights(),0) )
+        self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button)
+        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
+
+        panel.SetSizerAndFit(gbs)
+        self.SetClientSize(panel.GetSize())
+
+    def OnCloseMe(self, event):
+        self.Close(True)
+
+    def OnCloseWindow(self, event):
+        self.Destroy()
+        
+    def addLight(self, where, light):
+        point_light = light.asPointLight()
+        if (point_light != None):
+            return self.addPointLight(where, point_light)
+        head_light = light.asHeadLight()
+        if (head_light != None):
+            return self.addHeadLight(where, head_light)
+
+    def addPointLight(self, where, light):
+        location = light.getPosition()
+        color = light.getColor().convertRGB()
+
+        panel = wx.Panel(where, -1)
+        
+        gbs = wx.GridBagSizer(5,5)
+        gbs.Add( wx.StaticText(panel, -1, "Location"), (0,0))
+        spinnerX = self.addSpinner(panel, location.x())
+        spinnerY = self.addSpinner(panel, location.y())
+        spinnerZ = self.addSpinner(panel, location.z())
+        spinnerX.light = light
+        spinnerX.X = spinnerX
+        spinnerX.Y = spinnerY
+        spinnerX.Z = spinnerZ
+        spinnerY.light = light
+        spinnerY.X = spinnerX
+        spinnerY.Y = spinnerY
+        spinnerY.Z = spinnerZ
+        spinnerZ.light = light
+        spinnerZ.X = spinnerX
+        spinnerZ.Y = spinnerY
+        spinnerZ.Z = spinnerZ
+        gbs.Add( spinnerX, (0,1))
+        gbs.Add( spinnerY, (0,2))
+        gbs.Add( spinnerZ, (0,3))
+
+        # Shortcut for namespace
+        colorTup = ( int(color.r() * 255),
+                     int(color.g() * 255),
+                     int(color.b() * 255) )
+        colorButton =  csel.ColourSelect(panel, -1, "Color",
+                                                        colorTup)
+        colorButton.Bind(csel.EVT_COLOURSELECT, self.OnSelectColor)
+        self.colorButtonRefs[colorButton.GetId()] = colorButton
+        colorButton.light = light
+
+        gbs.Add( colorButton, (0,4))
+
+        panel.SetSizerAndFit(gbs)
+        return panel
+
+    def addSpinner(self, where, value):
+        floatspin = FS.FloatSpin(where, -1, min=1, max=0,
+                                 increment=0.01, value=value,
+                                 extrastyle=FS.FS_LEFT)
+        floatspin.SetFormat("%g")
+        floatspin.SetDigits(5)
+        floatspin.Bind(FS.EVT_FLOATSPIN, self.OnFloatSpin)
+        return floatspin
+
+    def OnFloatSpin(self, event):
+        # Pull out the new value
+        spinner = event.GetEventObject()
+        x = float(spinner.X.GetValue())
+        y = float(spinner.Y.GetValue())
+        z = float(spinner.Z.GetValue())
+        newPosition = Vector(x,y,z)
+        cbArgs = ( newPosition, )
+        self.engine.addTransaction("Light Position",
+                                   
manta_new(PyCallback.static_createMantaCallback(spinner.light.setPosition, 
cbArgs)))
+
+
+    def OnSelectColor(self, event):
+        try:
+            colorButton = self.colorButtonRefs[event.GetId()]
+        except:
+            dlg = wx.MessageDialog(self, 'Getting Wrong IDs from Color 
event!',
+                                   'ERROR',
+                                   wx.OK | wx.ICON_ERROR
+                                   )
+            dlg.ShowModal()
+            dlg.Destroy()
+            return
+        color = event.GetValue()
+        rgbColor = RGBColor(color.Red()  /255.0,
+                            color.Green()/255.0,
+                            color.Blue() /255.0)
+        cbArgs = ( Color(rgbColor), )
+        self.engine.addTransaction("Light Color",
+                                   
manta_new(PyCallback.static_createMantaCallback(colorButton.light.setColor, 
cbArgs)))
+        
+        
+        
 class App(wx.App) :
 
 
@@ -154,8 +278,10 @@
 #                           size=wx.Size(xres, yres) )
         self.frame.Show()
 
+        # Create the StatusBar
         self.frame.statusbar = self.frame.CreateStatusBar()
 
+        # Create the menu
         menuBar = wx.MenuBar()
         menu1 = wx.Menu()
         self.frame.Bind(wx.EVT_MENU, self.OnQuit,
@@ -166,10 +292,13 @@
                   menu2.Append(wx.NewId(), "About Manta"))
         menuBar.Append(menu2, "&Help")
         self.frame.SetMenuBar(menuBar)
-        
 
+        # Create the Main panel that will hold the renderer
         self.panel = wx.Panel(self.frame)
         self.panel.SetSize(wx.Size(xres, yres))
+
+        ############################################################
+        # Layout
         box = wx.BoxSizer(wx.HORIZONTAL)
         box.Add(self.panel, 1, wx.EXPAND)
         self.frame.SetSizerAndFit(box)
@@ -239,6 +368,7 @@
         # Make canvas the initial focus
         wx.CallAfter(self.canvas.SetFocus)
 
+
         ##################################################################
         # globals
         self.trackball_radius = 0.8
@@ -285,6 +415,8 @@
                 print "Found a 'p'"
             elif key == 'V':
                 print "Found a 'v'"
+            elif key == "L":
+                LightFrame(self.frame, self.engine).Show()
             elif key == 'Q':
                 print "Quitting"
                 self.frame.Close()




  • [MANTA] r1110 - in trunk: Core/Geometry Engine/Display Model/Lights SwigInterface, bigler, 06/09/2006

Archive powered by MHonArc 2.6.16.

Top of page