pysoy

changeset 1758:fe48f01093f5

Added fog property from Scene.pym, deleting now obsolete Scene.pym
author Arc Riley <arcriley@gmail.com>
date Mon, 12 Dec 2011 02:31:27 -0500
parents 58021b8791ec
children 542901300d1c
files src/scenes/Scene.c src/scenes/Scene.pym
diffstat 2 files changed, 12 insertions(+), 390 deletions(-) [+]
line diff
     1.1 --- a/src/scenes/Scene.c	Sun Dec 11 14:48:50 2011 -0500
     1.2 +++ b/src/scenes/Scene.c	Mon Dec 12 02:31:27 2011 -0500
     1.3 @@ -89,11 +89,23 @@
     1.4  PYSOY_PROP_OBJECT_OWNED(scenes, scene, ambient, atoms_Color);
     1.5  
     1.6  
     1.7 +static char
     1.8 +fog_doc[] = "Scene fog\n"
     1.9 +"\n"
    1.10 +"    This is a scene-wide layer of fog of which the density is set by the\n"
    1.11 +"    color's alpha channel.\n"
    1.12 +"\n"
    1.13 +"    Defaults to Color('clear')\n"
    1.14 +"\n";
    1.15 +PYSOY_PROP_OBJECT_OWNED(scenes, scene, fog, atoms_Color)
    1.16 +
    1.17 +
    1.18  /////////////////////////////////////////////////////////////////////////////
    1.19  // Type structs
    1.20  
    1.21  static PyGetSetDef tp_getset[] = {
    1.22      PYSOY_PROPSTRUCT(ambient),
    1.23 +    PYSOY_PROPSTRUCT(fog),
    1.24      {NULL}                                                 // sentinel
    1.25  };
    1.26  
     2.1 --- a/src/scenes/Scene.pym	Sun Dec 11 14:48:50 2011 -0500
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,390 +0,0 @@
     2.4 -# PySoy's scenes.Scene class
     2.5 -#
     2.6 -# Copyright (C) 2006,2007,2008,2009 PySoy Group
     2.7 -#
     2.8 -#  This program is free software; you can redistribute it and/or modify
     2.9 -#  it under the terms of the GNU Affero General Public License as published
    2.10 -#  by the Free Software Foundation, either version 3 of the License, or
    2.11 -#  (at your option) any later version.
    2.12 -#
    2.13 -#  This program is distributed in the hope that it will be useful,
    2.14 -#  but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.15 -#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.16 -#  GNU Affero General Public License for more details.
    2.17 -#
    2.18 -#  You should have received a copy of the GNU Affero General Public License
    2.19 -#  along with this program; if not, see http://www.gnu.org/licenses
    2.20 -#
    2.21 -# $Id: Scene.pym 1393 2008-12-31 23:51:25Z ArcRiley $
    2.22 -DEF GeomScene = 1
    2.23 -DEF GeomBody  = 2
    2.24 -DEF GeomField = 4
    2.25 -DEF GeomLight = 8
    2.26 -DEF GeomGhost = 16
    2.27 -cdef class Scene (soy._internals.Loopable) :
    2.28 -  '''PySoy Scene
    2.29 -
    2.30 -    Scenes are containers in physics space for bodies.
    2.31 -    Objects in different scenes cannot interact, for example,
    2.32 -    bodies in two different scenes cannot collide.
    2.33 -    
    2.34 -    Scenes also apply gravity to bodies.
    2.35 -
    2.36 -  '''
    2.37 -
    2.38 -  ############################################################################
    2.39 -  #
    2.40 -  # Python functions
    2.41 -  #
    2.42 -  
    2.43 -  def __cinit__(self, *args, **kw) :
    2.44 -    from soy.colors import gray
    2.45 -    self._worldID      = ode.dWorldCreate()
    2.46 -    self._spaceID      = ode.dSimpleSpaceCreate(NULL)
    2.47 -    self._contactGroup = ode.dJointGroupCreate(0)
    2.48 -    self._bodies       = soy._internals.Children()
    2.49 -    self._fields       = soy._internals.Children()
    2.50 -    self._joints       = soy._internals.Children()
    2.51 -    self._lights       = soy._internals.Children()
    2.52 -    self._ambient      = gray
    2.53 -    self._fogDensity   = 0.0
    2.54 -    self._stepSize     = 0.01
    2.55 -    self._friction     = 0
    2.56 -    self._prevTime     = _time()
    2.57 -    self._stepMutex    = py.PyThread_allocate_lock()
    2.58 -    # a list cor keeping track of the fields in the scene.
    2.59 -    self._giveFields   = soy._internals.PointerSet()
    2.60 -    # 
    2.61 -    self._callFields   = soy._internals.PointerSet()
    2.62 -    _scenes._append(<void*> self)
    2.63 -
    2.64 -
    2.65 -  def __dealloc__(self) :
    2.66 -    _scenes._remove(<void*> self)
    2.67 -    if self._worldID != NULL :
    2.68 -      ode.dWorldDestroy(self._worldID)
    2.69 -    if self._spaceID != NULL :
    2.70 -      ode.dSpaceDestroy(self._spaceID)
    2.71 -
    2.72 -
    2.73 -  def __repr__(self) :
    2.74 -    report = []
    2.75 -
    2.76 -    if self._bodies._current == 1 :
    2.77 -      report.append('1 body')
    2.78 -    else:
    2.79 -      report.append('%d bodies' % self._bodies._current)
    2.80 -
    2.81 -    if self._lights._current == 1 :
    2.82 -      report.append('1 light')
    2.83 -    else :
    2.84 -      report.append('%d lights' % self._lights._current)
    2.85 -
    2.86 -    return '<Scene with %s>' % ', '.join(report)
    2.87 -  
    2.88 -  ############################################################################
    2.89 -  #
    2.90 -  # Properties
    2.91 -  #
    2.92 -  
    2.93 -  property fog :
    2.94 -    '''Scene fog
    2.95 -
    2.96 -    This is a scene-wide layer of fog of which the density is set by you
    2.97 -
    2.98 -    Takes a float for fog density from 0-2, fog is disabled when at 0.
    2.99 -    '''
   2.100 -    def __get__(self) :
   2.101 -      return self._fogDensity
   2.102 -    
   2.103 -    def __set__(self, value) :
   2.104 -      assert type(value) == float and value <= 2 and value >= 0, \
   2.105 -          "Fog density must be a float in the range of 0-2."
   2.106 -      self._fogDensity = value
   2.107 -
   2.108 -  ############################################################################
   2.109 -  #
   2.110 -  # C functions
   2.111 -  #
   2.112 -  
   2.113 -  cdef int _loop(self) nogil :
   2.114 -    cdef int _i, _steps
   2.115 -    self._time = _time()
   2.116 -    self._callFields._empty()
   2.117 -    self._giveFields._empty()
   2.118 -    #
   2.119 -    self._fields._iterStart()
   2.120 -    for _i from 0 <= _i < self._fields._current :
   2.121 -      # Make sure every field is in givefields & _give each one
   2.122 -      if not self._giveFields._has_key(self._fields._list[_i]) :
   2.123 -        (<soy.fields.Field> self._fields._list[_i])._give(0)
   2.124 -        self._giveFields._insert(self._fields._list[_i])
   2.125 -    #
   2.126 -    for _i from 0 <= _i < self._fields._current :
   2.127 -      # Apply fields; add incompletly applied fields to the list
   2.128 -      if not (<soy.fields.Field> self._fields._list[_i])._apply() :
   2.129 -        pass
   2.130 -        #self._callFields._insert(self._fields.list[_i])
   2.131 -    #
   2.132 -    # Apply any outstanding fields
   2.133 -    self._callFields._foreach(_runField, NULL)
   2.134 -    self._fields._iterDone()
   2.135 -    #
   2.136 -    self._stepLock()
   2.137 -    _steps = self._steps()
   2.138 -    for _i from 0 <= _i < _steps :
   2.139 -      self._time = _time()
   2.140 -      self._giveFields._foreach(_prerunField, NULL)
   2.141 -      self._callFields._empty()
   2.142 -      ode.dSpaceCollide(self._spaceID, <void*> self,
   2.143 -                        <void(*)(void*, ode.dGeomID, ode.dGeomID) nogil>
   2.144 -                        Scene._callback)
   2.145 -      ode.dWorldQuickStep(self._worldID, self._stepSize)
   2.146 -      ode.dJointGroupEmpty(self._contactGroup)
   2.147 -      if _i != 0 :
   2.148 -        self._callFields._foreach(_runField, NULL)
   2.149 -    self._stepUnLock()
   2.150 -    return 1
   2.151 -
   2.152 -
   2.153 -  cdef void _render(self, gl.GLdouble _fovy,  gl.GLdouble _aspect,
   2.154 -                          gl.GLdouble _znear, gl.GLdouble _zfar) :
   2.155 -    cdef int _i
   2.156 -    cdef gl.GLfloat _fogColor[4]
   2.157 -    _fogColor[0] = .5
   2.158 -    _fogColor[1] = .5
   2.159 -    _fogColor[2] = .5
   2.160 -    _fogColor[3] = 1.0
   2.161 -    #
   2.162 -    # Setup projection matrix
   2.163 -    gl.glMatrixMode(gl.GL_PROJECTION)
   2.164 -    gl.glLoadIdentity()
   2.165 -    gl.gluPerspective(_fovy, _aspect, _znear, _zfar)
   2.166 -    gl.glMatrixMode(gl.GL_MODELVIEW)
   2.167 -    #
   2.168 -    # Setup scene-level rendering
   2.169 -    gl.glClear(gl.GL_DEPTH_BUFFER_BIT)
   2.170 -    gl.glEnable(gl.GL_DEPTH_TEST)
   2.171 -    gl.glEnable(gl.GL_LIGHTING)
   2.172 -    gl.glLightModelfv(gl.GL_LIGHT_MODEL_AMBIENT, self._ambient._rgba)
   2.173 -    
   2.174 -    if self._fogDensity > 0 :
   2.175 -      #
   2.176 -      # Turn on some fog!
   2.177 -      gl.glClearColor(0.5,0.5,0.5,1.0)  # We'll Clear To The Color Of The Fog ( Modified )
   2.178 -      gl.glEnable(gl.GL_FOG)                    #Enables GL_FOG
   2.179 -      gl.glFogi(gl.GL_FOG_MODE, gl.GL_EXP2)     #Fog Mode
   2.180 -      gl.glFogfv(gl.GL_FOG_COLOR, _fogColor)    #Set Fog Color
   2.181 -      gl.glFogf(gl.GL_FOG_DENSITY, self._fogDensity/10)        #How Dense Will The Fog Be
   2.182 -      gl.glHint(gl.GL_FOG_HINT, gl.GL_NICEST)   #Fog Hint Value
   2.183 -      gl.glFogf(gl.GL_FOG_START, 1.0)           #Fog Start Depth
   2.184 -      gl.glFogf(gl.GL_FOG_END, 50.0)             #Fog End Depth
   2.185 -
   2.186 -    #
   2.187 -    # Turn on each light, keep it's iteration locked against mod until done
   2.188 -    self._lights._iterStart()
   2.189 -    for _i from 0 <= _i < self._lights._current :
   2.190 -      # This is a quick hack (gl.GL_LIGHT0 + _i)
   2.191 -      (<soy.bodies.Light> self._lights._list[_i])._on(gl.GL_LIGHT0 + _i)
   2.192 - 
   2.193 -
   2.194 -    
   2.195 -    #
   2.196 -    # Iterate over bodies
   2.197 -    self._bodies._iterStart()
   2.198 -    for _i from 0 <= _i < self._bodies._current :
   2.199 -      if (<soy.bodies.Body> self._bodies._list[_i])._model is not None :
   2.200 -        (<soy.models.Model>
   2.201 -         (<soy.bodies.Body> self._bodies._list[_i])._model)._render(
   2.202 -         (<soy.bodies.Body> self._bodies._list[_i]))
   2.203 -    self._bodies._iterDone()
   2.204 -    
   2.205 -    #
   2.206 -    # Turn off all lights and finish iteration loop
   2.207 -    for _i from 0 <= _i < self._lights._current :
   2.208 -      # This is a quick hack (gl.GL_LIGHT0 + _i)
   2.209 -      (<soy.bodies.Light> self._lights._list[_i])._off(gl.GL_LIGHT0 + _i)
   2.210 -    self._lights._iterDone()
   2.211 -    
   2.212 -    if self._fogDensity > 0 :
   2.213 -      gl.glDisable(gl.GL_FOG)
   2.214 -    gl.glDisable(gl.GL_LIGHTING)
   2.215 -    gl.glDisable(gl.GL_DEPTH_TEST)
   2.216 -
   2.217 -
   2.218 -  cdef int _steps(self) nogil :
   2.219 -    cdef int     _step
   2.220 -    cdef double  _lapsTime
   2.221 -    _lapsTime = _time() - self._prevTime
   2.222 -    if _lapsTime < math.FLT_EPSILON :
   2.223 -      _lapsTime = math.FLT_EPSILON
   2.224 -    _step = math.lround(_lapsTime / self._stepSize)
   2.225 -    if _step > 12 :
   2.226 -      _step = 12
   2.227 -    self._prevTime = self._prevTime + (_step * self._stepSize)
   2.228 -    return _step
   2.229 -    
   2.230 -
   2.231 -  cdef void _stepLock(self) nogil :
   2.232 -    py.PyThread_acquire_lock(self._stepMutex,1)
   2.233 -
   2.234 -
   2.235 -  cdef int _stepTryLock(self) nogil :
   2.236 -    return py.PyThread_acquire_lock(self._stepMutex,0)
   2.237 -
   2.238 -
   2.239 -  cdef void _stepUnLock(self) nogil :
   2.240 -    py.PyThread_release_lock(self._stepMutex)
   2.241 -
   2.242 -
   2.243 -  cdef void _callback(self, ode.dGeomID _geomA, ode.dGeomID _geomB) nogil :
   2.244 -    cdef int                _contactGeoms, _f, _i
   2.245 -    cdef ode.dJointID       _joint
   2.246 -    cdef ode.dContact       _contact
   2.247 -    cdef ode.dContactGeom   _contactGeom[2]
   2.248 -    cdef ode.dGeomID        _geomIDs[2]
   2.249 -    cdef ode.dBodyID        _bodyIDs[2]
   2.250 -
   2.251 -    #
   2.252 -    # Start by generating up to four contacts between 2 bodies
   2.253 -    _contactGeoms = ode.dCollide(_geomA, _geomB, 2,
   2.254 -                                 _contactGeom, sizeof(_contactGeom[0]))
   2.255 -    #
   2.256 -    # Don't waste time when there's no collision
   2.257 -    if _contactGeoms == 0 :
   2.258 -      return
   2.259 -    #
   2.260 -    # This makes case-testing much simpler in the code
   2.261 -    _geomIDs[0] = _geomA
   2.262 -    _geomIDs[1] = _geomB
   2.263 -    #
   2.264 -    # Scene Check
   2.265 -    for _i from 0 <= _i < 2 :
   2.266 -      if ode.dGeomGetCategoryBits(_geomIDs[_i]) == GeomScene :
   2.267 -        _bodyIDs[_i] = NULL
   2.268 -        #stdio.printf('Scene Collision %d\n', _i)
   2.269 -      else :
   2.270 -        _bodyIDs[_i] = ode.dGeomGetBody(_geomIDs[_i])
   2.271 -        #stdio.printf('Body Collision %d %d\n', _i, _bodyIDs[_i])
   2.272 -    #
   2.273 -    # Ghost Check
   2.274 -    for _i from 0 <= _i < 2 :
   2.275 -      if ode.dGeomGetCategoryBits(_geomIDs[_i]) == GeomGhost :
   2.276 -        #stdio.printf('Ghost Collision\n')
   2.277 -        _bodyIDs[(_i + 1) % 2] = NULL
   2.278 -    #
   2.279 -    # If we ended up with a null-null collision, just return now
   2.280 -    if _bodyIDs[0] == NULL and _bodyIDs[1] == NULL :
   2.281 -      #stdio.printf('Both bodies null, aborting\n')
   2.282 -      return
   2.283 -    #
   2.284 -    # Add each joint to the bodies we just determined
   2.285 -    for _i from 0 <= _i < _contactGeoms :
   2.286 -      _contact.geom = _contactGeom[_i]
   2.287 -      _contact.surface.mode = ode.dContactBounce
   2.288 -      _contact.surface.mu = self._friction
   2.289 -      _contact.surface.bounce = 0.8
   2.290 -      _contact.surface.bounce_vel = 0
   2.291 -      #stdio.printf('Creating joint\n')
   2.292 -      _joint = ode.dJointCreateContact(self._worldID, self._contactGroup, 
   2.293 -                                       &_contact)
   2.294 -      #stdio.printf('Attaching joint\n')
   2.295 -      ode.dJointAttach(_joint, _bodyIDs[0], _bodyIDs[1])
   2.296 -      #stdio.printf('Processed contact joint %d\n', _i)
   2.297 -    return
   2.298 -
   2.299 -    '''
   2.300 -    # This is the old code, mostly for fields.  It needs to be merged into
   2.301 -    # the above but for now we're just testing Scene and Ghosts
   2.302 -    if _c > 0 :
   2.303 -      # Get the Body objects
   2.304 -      _bo1 = <soy.bodies.Body> ode.dBodyGetData(_b1)
   2.305 -      _bo2 = <soy.bodies.Body> ode.dBodyGetData(_b2)
   2.306 -      _f = 0
   2.307 -      # activate any fields present...
   2.308 -      if isinstance(_bo1, soy.fields.Field) :
   2.309 -        _f = 1
   2.310 -        if not (<soy.fields.Field> _bo1)._exert(_bo2) :
   2.311 -          self._callFields._insert(<void*> _bo1)
   2.312 -      if isinstance(_bo2, soy.fields.Field) :
   2.313 -        _f = 1
   2.314 -        if not (<soy.fields.Field> _bo2)._exert(_bo1) :
   2.315 -          self._callFields._insert(<void*> _bo2)
   2.316 -      # if neither shape is a field
   2.317 -      if _f == 0 :
   2.318 -        _ct.geom = _cg
   2.319 -        # surface parameters should have an exposed interface on soy.shapes.Shape
   2.320 -        # this code should pull parameters from there.
   2.321 -        _ct.surface.mode = ode.dContactBounce
   2.322 -        _ct.surface.bounce = 0.8
   2.323 -        _ct.surface.bounce_vel = 0
   2.324 -        _j = ode.dJointCreateContact(self._worldID, self._contactGroup, &_ct)
   2.325 -        ode.dJointAttach(_j, _b1, _b2)
   2.326 -    '''
   2.327 -
   2.328 -  ############################################################################
   2.329 -  #
   2.330 -  # Properties
   2.331 -  #
   2.332 -  
   2.333 -  property gravity :
   2.334 -    '''Scene gravity
   2.335 -
   2.336 -    This is a scene-wide pseudo-force drawing all bodies in a single 
   2.337 -    direction.  This should not be confused with a monopole force or other
   2.338 -    forces which are often used for gravity in larger scenes.
   2.339 -
   2.340 -    Takes a (x,y,z) tuple of numbers, defaults to (0.0, 0.0, 0.0)
   2.341 -    '''
   2.342 -    def __get__(self) :
   2.343 -      cdef ode.dVector3 grav
   2.344 -      ode.dWorldGetGravity(self._worldID, grav)
   2.345 -      return (grav[0], grav[1], grav[2])
   2.346 -    def __set__(self, value) :
   2.347 -      ode.dWorldSetGravity(self._worldID, value[0], value[1], value[2])
   2.348 -
   2.349 -
   2.350 -  property stepsize :
   2.351 -    '''Step Size
   2.352 -
   2.353 -    This is the fraction of time each "step" calculates for.  Larger steps
   2.354 -    trade accuracy for speed.
   2.355 -
   2.356 -    Takes a float, defaults to .01
   2.357 -    '''
   2.358 -    def __get__(self) :
   2.359 -      return self._stepSize
   2.360 -    def __set__(self, value) :
   2.361 -      self._stepLock()
   2.362 -      self._stepSize = value
   2.363 -      self._stepUnLock()
   2.364 -
   2.365 -
   2.366 -  property ambient :
   2.367 -    '''Scene's ambient light
   2.368 -
   2.369 -    This is the ambient light for the scene.  When no light is used this is 
   2.370 -    the only light available in the scene - use it well.
   2.371 -
   2.372 -    Defaults to :const:`soy.colors.gray`
   2.373 -    '''
   2.374 -    def __get__(self) :
   2.375 -      return self._ambient
   2.376 -    def __set__(self, soy.colors.Color value) :
   2.377 -      self._ambient = value
   2.378 -
   2.379 -
   2.380 -  property friction :
   2.381 -    '''Scene's Friction
   2.382 -    
   2.383 -    This is the amount of friction given to ode's contact joint.
   2.384 -    
   2.385 -    Defaults to 0 ( Really Slippery )
   2.386 -    '''
   2.387 -    def __get__(self) :
   2.388 -      return self._friction
   2.389 -    def __set__(self, value) :
   2.390 -      if isinstance(value, int):
   2.391 -        self._friction = value
   2.392 -      else: 
   2.393 -        raise TypeError("Friction must be an int of some sort")