# Soya 3D
# Copyright (C) 2003-2004 Jean-Baptiste LAMY -- jiba@tuxfamily.org
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


# Some raypick stuff (including raypick context).
# Other raypick codes (e.g. raypick method) are in the objects themselves.

cdef object make_raypick_result(float* f, float z, float* normal, CoordSyst coordsyst, _Point p, _Vector v):
  if f == NULL: return None
  if p is None:
    p = Point (coordsyst, f[0] + f[3] * z, f[1] + f[4] * z, f[2] + f[5] * z)
    v = Vector(coordsyst)
    memcpy(v._matrix, normal, 3 * sizeof(float))
    return p, v
  else:
    p._parent = v._parent = coordsyst
    p._matrix[0] = f[0] + f[3] * z
    p._matrix[1] = f[1] + f[4] * z
    p._matrix[2] = f[2] + f[5] * z
    memcpy(v._matrix, normal, 3 * sizeof(float))
    return 1



cdef class RaypickData:
  #cdef int       option
  #cdef Chunk*    raypicked
  #cdef Chunk*    raypick_data
  #cdef float     root_data[7], normal[3], result, root_result
  #cdef CoordSyst result_coordsyst
  
  def __init__(self):
    self.raypicked    = get_chunk()
    self.raypick_data = get_chunk()
    
  def __dealloc__(self):
    drop_chunk(self.raypicked)
    drop_chunk(self.raypick_data)
    
cdef RaypickData raypick_data
raypick_data = RaypickData()

cdef RaypickData get_raypick_data():
  raypick_data.result_coordsyst = None
  raypick_data.raypicked   .nb = 0
  raypick_data.raypick_data.nb = 0
  return raypick_data


cdef class RaypickContext:
  #cdef Chunk* _items
  #cdef _World _root
  
  def __init__(self, _World root):
    self._items = get_chunk()
    self._root  = root
    
  def __dealloc__(self):
    drop_chunk(self._items)
    
  def raypick(self, Position origin not None, _Vector direction not None, float distance = -1.0, int half_line = 1, int cull_face = 1, _Point p = None, _Vector v = None):
    """raypick(origin, direction, distance = -1.0, half_line = 1, cull_face = 1, p = None, v = None) -> None or (Point, Vector)

See World.raypick"""
    cdef Chunk*      items
    items = self._items
    if items.nb == 0: return None
    
    cdef RaypickData data
    cdef _CObj       obj
    cdef CoordSyst   coordsyst
    cdef float*      d
    cdef int         max
    data = get_raypick_data()
    
    origin   ._out(data.root_data)
    direction._out(data.root_data + 3)
    vector_normalize(data.root_data + 3)
    data.root_data[6] = distance
    data.option       = RAYPICK_CULL_FACE * cull_face + RAYPICK_HALF_LINE * half_line
    
    max = items.nb
    items.nb = 0
    while items.nb < max:
      obj = <_CObj> chunk_get_ptr(items)
      if isinstance(obj, _TreeShape): (<_TreeShape> obj)._raypick_from_context(data, items)
      else:                           (<CoordSyst>  obj)._raypick(data, (<CoordSyst> obj)._parent)
      
    if data.result_coordsyst is None: d = NULL
    else:                             d = data.result_coordsyst._raypick_data(data)
    
    max = data.raypicked.nb
    data.raypicked.nb = 0
    while data.raypicked.nb < max:
      coordsyst = <CoordSyst> chunk_get_ptr(data.raypicked)
      coordsyst.__raypick_data = -1
      
    return make_raypick_result(d, data.result, data.normal, data.result_coordsyst, p, v)
    
  def raypick_b(self, Position origin not None, _Vector direction not None, float distance = -1.0, int half_line = 1, int cull_face = 1, _Point p = None, _Vector v = None):
    """raypick_b(origin, direction, distance = -1.0, half_line = 1, cull_face = 1, p = None, v = None) -> bool

See World.raypick_b"""
    cdef Chunk*      items
    items = self._items
    if items.nb == 0: return 0
    
    cdef RaypickData data
    cdef _CObj       obj
    cdef CoordSyst   coordsyst
    cdef int         result, max
    data = get_raypick_data()
    origin   ._out(data.root_data)
    direction._out(data.root_data + 3)
    vector_normalize(data.root_data + 3)
    data.root_data[6] = distance
    data.option       = RAYPICK_CULL_FACE * cull_face + RAYPICK_HALF_LINE * half_line
    
    max = items.nb
    items.nb = 0
    while items.nb < max:
      obj = <_CObj> chunk_get_ptr(items)
      if isinstance(obj, _TreeShape):
        if (<_TreeShape> obj)._raypick_from_context_b(data, items): result = 1; break
      else:
        if (<CoordSyst>  obj)._raypick_b(data, (<CoordSyst> obj)._parent) : result = 1; break
    else: result = 0
    
    max = data.raypicked.nb
    data.raypicked.nb = 0
    while data.raypicked.nb < max:
      coordsyst = <CoordSyst> chunk_get_ptr(data.raypicked)
      coordsyst.__raypick_data = -1
      
    return result
  

    

  

