# 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


import sys, os, os.path, sets, soya, soya.model, soya.soya3d, soya.land, cStringIO

#EXPORT_TO_PATH = "/home/jiba/src/slune"
EXPORT_TO_PATH = "/home/jiba/src/balazar"

soya.model .Image   .PATH = "/home/jiba/src/balazar.c/images"
soya.model .Material.PATH = "/home/jiba/src/balazar.c/materials"
soya.model .Shape   .PATH = "/home/jiba/src/balazar.c/shapes"
soya.soya3d.World   .PATH = "/home/jiba/src/balazar.c/worlds"


import sys, os, os.path, sets, soya

BEGIN_CODE = """# Generated by %s

import sys, os, os.path, soya
soya.path.append("%s")
soya.init()

""" % (os.path.basename(__file__), EXPORT_TO_PATH)

END_CODE = """
"""

#SOYA_CLASSES = sets.Set(["Point", "Vector", "Face", "Vertex", "Volume", "World", "Light", "Camera", "Material", "Image"])

def soya_class(clazz):
  #if isinstance(clazz, type): return clazz
  if clazz.__module__.startswith("soya"): return clazz
  
  for mother_clazz in clazz.__bases__:
    mother_soya_class = soya_class(mother_clazz)
    if mother_soya_class: return mother_soya_class


def material2filename(material):
  if material: return material.filename
  return "__DEFAULT_MATERIAL__"


EXPORTEDS   = []
EXPORTEDIDS = []

TO_SAVE = []

def export_file(clazz, filename):
  print >> sys.stderr, """Exporting object %s.get("%s")...""" % (clazz.__name__, filename)
  export(clazz.get(filename))
  
def export(obj):
  objname = "obj%s" % id(obj)
  if not id(obj) in EXPORTEDIDS:
    EXPORTEDS  .append(obj)
    EXPORTEDIDS.append(id(obj))
    _export(obj, objname)
  return objname


def _export(obj, objname):
  #print >> sys.stderr, "  exporting %s..." % obj
  
  if obj is None:
    print '%s = None' % objname
    return
  
  if isinstance(obj, basestring):
    print '%s = """%s"""' % (objname, obj)
    return
  
  if isinstance(obj, int) or isinstance(obj, long) or isinstance(obj, float):
    print "%s = %s" % (objname, obj)
    return
  
  if type(obj) is list:
    print "%s = [%s]" % (objname, ", ".join(map(lambda value: export(value), obj)))
    return
  
  if type(obj) is dict:
    print "%s = {%s}" % (objname, ", ".join(map(lambda (key, value): "%s : %s" % (export(key), export(value)), obj.items())))
    return
  
  
  base = soya_class(obj.__class__)
  already_exported_attr = []
  printed = 0
  
  if (not base) or (not type(obj) is base):
    if base:
      if not printed: print >> sys.stderr, "  while exporting %s..." % obj; printed = 1
      print >> sys.stderr, "    warning, not pure soya object"
    else:
      if not printed: print >> sys.stderr, "  while exporting %s..." % obj; printed = 1
      print >> sys.stderr, "    warning, non-soya object"
    create = 0
    print "import %s # Import non-soya module" % obj.__class__.__module__
    print "%s   = %s.%s() # Creation of non-soya object" % (objname, obj.__class__.__module__, obj.__class__.__name__)
    
  else: create = 1
  
  if base:
    exporter = globals().get("export_" + base.__name__)
    if not exporter:
      print >> sys.stderr, "    ERROR: cannot export object of base %s!" % base
      return
      #raise NotImplementedError("cannot export object of base %s !" % base)
    exporter(obj, objname, already_exported_attr, create)
    
  already_exported_attr = sets.Set(already_exported_attr)
  for attr, value in obj.__dict__.items():
    if not attr in already_exported_attr:
      if not printed: print >> sys.stderr, "  while exporting %s..." % obj; printed = 1
      print >> sys.stderr, "    warning, extra non-soya attribute %s = %s" % (attr, repr(value))
      #if   isinstance(value, basestring): value = "'" + value + "'"
      #elif isinstance(value, int) or isinstance(value, long) or isinstance(value, float): pass
      #else: value = "'" + export(value) + "'"
      #print "%s.%s = %s # Additional attribute" % (objname, attr, value)
      print "%s.%s = %s # Additional attribute" % (objname, attr, export(value))
      
  print
  
  
def export_Saveable(obj, objname, already_exported_attr, create = 1):
  if obj.filename:
    print "%s.filename          = '%s'" % (objname, obj.filename)
    TO_SAVE.append(objname)
    
  already_exported_attr.extend(["_filename", "filename"])
    
  
def export_Material(obj, objname, already_exported_attr, create = 1):
  if create: print "%s                   = soya.Material()" % objname
  print "%s.additive_blending = %s" % (objname, obj.additive_blending)
  print "%s.separate_specular = %s" % (objname, obj.separate_specular)
  print "%s.diffuse           = %s" % (objname, obj.diffuse)
  print "%s.emissive          = %s" % (objname, obj.emissive)
  print "%s.shininess         = %s" % (objname, obj.shininess)
  print "%s.specular          = %s" % (objname, obj.specular)
  if obj.tex_filename:
    print """try: %s.texture      = soya.Image.get('%s')
except: print '    warning, texture %s not found'""" % (objname, obj.tex_filename, obj.tex_filename)
    
  export_Saveable(obj, objname, already_exported_attr)
  
  already_exported_attr.extend(["_tex_filename", "tex_filename"])
  

def export_CoordSyst(obj, objname, already_exported_attr, create = 1):
  print "%s.matrix          = %s" % (objname, obj._matrix)
  #print "%s.set_xyz(%s, %s, %s)" % (objname, obj.x, obj.y, obj.z)
  #print "%s.scale(%s, %s, %s)" % (objname, obj.scale_x, obj.scale_y, obj.scale_z)
  
  print "%s.visible         = %s" % (objname, obj.visible)
  print "%s.solid           = %s" % (objname, obj.solid)
  if obj.name:
    print "%s.name            = '%s'" % (objname, obj.name)
    
  already_exported_attr.extend(["_parent", "_matrix", "visible", "solid", "name", "_name"])
  
  
def export_Volume(obj, objname, already_exported_attr, create = 1):
  land = isinstance(obj.shape, soya.land.Land)
  
  if create:
    if land: print "%s                   = soya.Land(None, %s, %s)" % (objname, obj.shape.width, obj.shape.depth)
    else:    print "%s                   = soya.Volume()" % objname
    
  export_CoordSyst(obj, objname, already_exported_attr, 0)
  
  if land:
    print "%s.patch_size         = %s" % (objname, obj.shape.patch_size)
    print "%s.split_factor       = %s" % (objname, obj.shape.split_factor)
    print "%s.scale_factor       = %s" % (objname, obj.shape.scale_factor)
    print "%s.texture_factor     = %s" % (objname, obj.shape.texture_factor)
    print "%s.raypick_with_LOD   = %s" % (objname, obj.shape.raypick_with_LOD)
    #print "%s.has_vertex_options = %s" % (objname, obj.shape.has_vertex_options)
    
    
    datafile = os.path.join(EXPORT_TO_PATH, "export_world_%s_%s.data" % (EXPORTEDS[0].filename, objname))
    print """
data = open('%s').read()
for line in data.split("\\n"):
  values = line.split()
  if values:
    i = int(values[0])
    j = int(values[1])
    %s.set_height  (i, j, float(values[2]))
    %s.set_material(i, j, soya.Material.get(values[3]))
    if len(values) > 4:
      %s.set_vertex_option(i, j, int(values[4]), int(values[5]), int(values[6]), int(values[7]))
""" % (datafile, objname, objname, objname)
    
    data = open(datafile, "w")
    for i in range(obj.shape.width):
      for j in range(obj.shape.depth):
        data.write("%s %s %s %s" % (i, j, obj.shape.get_height(i, j), material2filename(obj.shape.get_material(i, j))))
        if obj.shape.has_vertex_options:
          option = obj.shape.get_vertex_option(i, j)
          data.write(" %s %s %s %s" % (int((option & 1) != 0), 0, int((option & 4) != 0), int((option & 8) != 0)))
        data.write("\n")
        #print "%s.set_height(%s, %s, %s)" % (objname, i, j, obj.shape.get_height(i, j))
        #print "%s.set_material(%s, %s, soya.Material.get('%s'))" % (objname, i, j, material2filename(obj.shape.get_material(i, j)))
        #if obj.shape.has_vertex_options:
        #  option = obj.shape.get_vertex_option(i, j)
        #  print "%s.set_vertex_option(%s, %s, %s, %s, %s, %s)" % (objname, i, j, (option & 1) != 0, 0, (option & 4) != 0, (option & 8) != 0)
        
  else:
    if obj.shape:
      if not obj.shape.filename in ["bonus_life", "bonus_green", "flag"]:
        print "%s.shape             = soya.Shape.get('%s')" % (objname, obj.shape.filename)
        
        
  already_exported_attr.extend(["shape", "_shape"])
  
  
def export_World(obj, objname, already_exported_attr, create = 1):
  if obj.filename and not obj is EXPORTEDS[0]:
    print "%s                   = soya.World.get('%s')" % (objname, obj.filename)
    return
    
  land = isinstance(obj.shape, soya.land.Land)
  if create: print "%s                   = soya.World()" % objname
  
  if land:
    landname = "extra%s" % id(obj)
    export_Volume  (obj, landname, [], 1)
    print "%s.set_identity()" % landname # The matrix is set on the world, NOT the inner land.
    print "%s.add(%s)" % (objname, landname)
    export_CoordSyst(obj, objname, already_exported_attr, 0)
    
  else:  
    export_Volume(obj, objname, already_exported_attr, 0)
    
  export_Saveable(obj, objname, already_exported_attr, 0)
  
  if obj.atmosphere:
    print "%s.atmosphere = %s" % (objname, export(obj.atmosphere))

  if obj.shapify_args:
    type, args = obj.shapify_args
    if type == "tree":         print "%s.shapifier = soya.TreeShapifier(collapsing_distance = %s, quality = %s, max_child_radius = %s)" % (objname, args.get("collapse", 0.9), args.get("mode", 0), args.get("params", [0.5])[0])
    
  for child in obj.children:
    print "%s.add(%s)" % (objname, export(child))

  already_exported_attr.extend(["shape", "_shape", "_atmosphere", "atmosphere", "_children", "children", "shapify_args"])
  

def export_Level(obj, objname, already_exported_attr, create = 1):
  print >> sys.stderr, "    WARNING, soya.level.Level is obsolete, converting to World instead"
  export_World(obj, objname, already_exported_attr, create)
  


def export_Face(obj, objname, already_exported_attr, create = 1):
  if create: print "%s                   = soya.Face()" % objname
  print "%s.double_sided = %s" % (objname, obj.double_sided)
  print "%s.smooth_lit   = %s" % (objname, obj.smooth_lit)
  print "%s.lit          = %s" % (objname, obj.lit)
  print "%s.solid        = %s" % (objname, obj.solid)
  print "%s.static_lit   = %s" % (objname, obj.static_lit)
  print "%s.solid        = %s" % (objname, obj.solid)
  
  if obj.material:
    print "%s.material = soya.Material.get('%s')" % (objname, material2filename(obj.material))
    
  for vertex in obj.vertices:
    print "%s.add(%s)" % (objname, export(vertex))
    
  already_exported_attr.extend(["_parent", "normal", "double_sided", "smooth_lit", "lit", "solid", "static_lit", "solid", "vertices", "_vertices", "material", "_material"])
  
  
def export_Vertex(obj, objname, already_exported_attr, create = 1):
  if create: print "%s                   = soya.Vertex()" % objname
  if obj.parent:
    print "%s.parent       = %s" % (objname, export(obj.parent))
    
  print "%s.set_xyz(%s, %s, %s)" % (objname, obj.x, obj.y, obj.z)
  print "%s.tex_x        = %s" % (objname, obj.tex_x)
  print "%s.tex_y        = %s" % (objname, obj.tex_y)
  print "%s.diffuse      = %s" % (objname, obj.color)
  #print "%s.emissive     = %s" % (objname, obj.emissive)
  
  already_exported_attr.extend(["face", "parent", "_parent", "tex_x", "tex_y", "diffuse", "emissive", "color"])
  
  
def export_Light(obj, objname, already_exported_attr, create = 1):
  if create: print "%s                   = soya.Light()" % objname
  export_CoordSyst(obj, objname, already_exported_attr, 0)
  
  print "%s.ambient           = %s" % (objname, obj.ambient)
  print "%s.diffuse           = %s" % (objname, obj.diffuse)
  print "%s.specular          = %s" % (objname, obj.specular)
  print "%s.shadow_color      = %s" % (objname, obj.shadow_color)
  print "%s.constant          = %s" % (objname, obj.constant)
  print "%s.linear            = %s" % (objname, obj.linear)
  print "%s.quadratic         = %s" % (objname, obj.quadratic)
  print "%s.angle             = %s" % (objname, obj.angle)
  print "%s.exponent          = %s" % (objname, obj.exponent)
  print "%s.directional       = %s" % (objname, obj.is_directional())
  print "%s.top_level         = %s" % (objname, obj.top_level)
  print "%s.cast_shadow       = %s" % (objname, obj.shadow_cast)
  #print "%s.static            = %s" % (objname, obj.static)
  
  already_exported_attr.extend([])


def export_Atmosphere(obj, objname, already_exported_attr, create = 1):
  if obj.skyplane: sky = 1
  else:            sky = 0
  
  if create:
    if sky: print "%s                   = soya.SkyAtmosphere()" % objname
    else:   print "%s                   = soya.Atmosphere()"    % objname
    
  print "%s.fog         = %s" % (objname, obj.fog)
  print "%s.fog_type    = %s" % (objname, obj.fog_type)
  print "%s.fog_start   = %s" % (objname, obj.fog_start)
  print "%s.fog_end     = %s" % (objname, obj.fog_end)
  print "%s.fog_density = %s" % (objname, obj.fog_density)
  print "%s.ambient     = %s" % (objname, obj.ambient)
  print "%s.bg_color    = %s" % (objname, obj.bg_color)
  print "%s.fog_color   = %s" % (objname, obj.fog_color)
  
  if sky:
    print "%s.sky_color = %s" % (objname, obj.sky_color)
    print "%s.cloud     = soya.Material.get('%s')" % (objname, material2filename(obj.cloud))
    
  already_exported_attr.extend([])


def export_Point(obj, objname, already_exported_attr, create = 1):
  if create: print "%s                   = soya.Point()" % objname
  print "%s.parent      = %s" % (objname, export(obj.parent))
  print "%s.x           = %s" % (objname, obj.x)
  print "%s.y           = %s" % (objname, obj.y)
  print "%s.z           = %s" % (objname, obj.z)
  already_exported_attr.extend(["x", "y", "z", "parent", "_parent"])

def export_Vector(obj, objname, already_exported_attr, create = 1):
  if create: print "%s                   = soya.Vector()" % objname
  export_Point(obj, objname, already_exported_attr, 0)

def export_Smoke(obj, objname, already_exported_attr, create = 1):
  if create: print "%s                   = soya.Smoke()" % objname
  export_CoordSyst(obj, objname, already_exported_attr, 0)
  
  print "%s.nb_max_particles        = %s" % (objname, obj.nb_max)
  print "%s.max_particles_per_round = %s" % (objname, obj.max_particles_per_round)
  
  already_exported_attr.extend(["max_particles_per_round"])
  


#export_file(soya.model.Material, "tux1")
#export_file(soya.soya3d.World, "world-crashfunkel")
#export_file(soya.soya3d.World, "shape-crashfunkel")
#export_file(soya.soya3d.World, "world-racinde")
#export_file(soya.soya3d.World, "level-mission-1")


# Materials

sys.stdout = open(os.path.join(EXPORT_TO_PATH, "export_all_materials.py"), "w")

print BEGIN_CODE

for filename in soya.model.Material.availables():
  if filename: export_file(soya.model.Material, filename)
  
print END_CODE
for objname in TO_SAVE: print "%s.save()" % objname
TO_SAVE = []
EXPORTEDS   = []
EXPORTEDIDS = []
sys.stdout = sys.__stdout__


# Worlds

# for filename in soya.soya3d.World.availables():
#   if filename and not os.path.exists(os.path.join(EXPORT_TO_PATH, "export_world_%s.py" % filename)):
# #for filename in ["world-urbancall"]:
# #  if filename:
# #    if not filename.startswith("world"): continue
    
    
    
#     #sys.stdout = open(os.path.join(EXPORT_TO_PATH, "export_world_%s.py" % filename), "w")
#     sys.stdout = cStringIO.StringIO()
#     print BEGIN_CODE
#     export_file(soya.soya3d.World, filename)
#     print END_CODE
#     for objname in TO_SAVE: print "%s.save()" % objname
#     TO_SAVE = []
#     EXPORTEDS   = []
#     EXPORTEDIDS = []
#     open(os.path.join(EXPORT_TO_PATH, "export_world_%s.py" % filename), "w").write(sys.stdout.getvalue())
    
#     sys.stdout = sys.__stdout__




#for objname in TO_SAVE:
#  print "%s.save()" % objname

# print """

# soya.init()

# scene = soya.World()

# scene = soya.World()
# tux = soya.World.get("tux1")
# tux.advance_time = lambda p : tux.rotate_lateral(p * 5.0)
# scene.add(tux)

# light = soya.Light(scene)
# light.set_xyz(0.5, 0.0, 2.0)

# camera = soya.Camera(scene)
# camera.z = 5.0
# soya.set_root_widget(camera)

# soya.Idler(scene).idle()

# """
