some audio things
[carveJwlIkooP6JGAAIwe30JlM.git] / blender_export.py
index 515acd770322a82979dc1391b40b1a81aef3c62a..3e4704ea466fa1e6d8d97eb3a4f44b6bb0dee6f2 100644 (file)
@@ -2,7 +2,7 @@
 # =============================================================================
 # 
 # Copyright  .        . .       -----, ,----- ,---.   .---.
-# 2021-2022  |\      /| |           /  |      |    | |    /|
+# 2021-2023  |\      /| |           /  |      |    | |    /|
 #            | \    / | +--        /   +----- +---'  |   / |
 #            |  \  /  | |         /    |      |   \  |  /  |
 #            |   \/   | |        /     |      |    \ | /   |
@@ -255,6 +255,40 @@ class classtype_gate(Structure):
    #}
 #}
 
+class classtype_nonlocal_gate(classtype_gate):
+#{
+   def encode_obj(_,node,node_def):
+   #{
+      node.classtype = 300
+
+      obj = node_def['obj']
+      _.target = encoder_process_pstr( node_def['obj'].cv_data.strp )
+
+      if obj.type == 'MESH':
+      #{
+         _.dims[0] = obj.data.cv_data.v0[0]
+         _.dims[1] = obj.data.cv_data.v0[1]
+         _.dims[2] = obj.data.cv_data.v0[2]
+      #}
+      else:
+      #{
+         _.dims[0] = obj.cv_data.v0[0]
+         _.dims[1] = obj.cv_data.v0[1]
+         _.dims[2] = obj.cv_data.v0[2]
+      #}
+   #}
+
+   @staticmethod
+   def editor_interface( layout, obj ):
+   #{
+      layout.prop( obj.cv_data, "strp", text="Nonlocal ID" )
+
+      mesh = obj.data
+      layout.label( text=F"(i) Data is stored in {mesh.name}" )
+      layout.prop( mesh.cv_data, "v0", text="Gate dimensions" )
+   #}
+#}
+
 # Classtype 3
 #
 #  Purpose: player can reset here, its a safe place
@@ -748,6 +782,11 @@ class classtype_audio(Structure):
       if obj.cv_data.bp1: flags |= 0x4
       if obj.cv_data.bp2: flags |= 0x8
 
+      if obj.cv_data.audio_format == 'stereo':
+         flags |= 0x200
+      if obj.cv_data.audio_format == 'remain compressed':
+         flags |= 0x400
+
       _.flags = flags
       _.volume = obj.cv_data.fltp
    #}
@@ -755,11 +794,14 @@ class classtype_audio(Structure):
    @staticmethod
    def editor_interface( layout, obj ):
    #{
-      layout.prop( obj.cv_data, "strp" )
+      layout.prop( obj.cv_data, "strp", text = "File (.ogg)" )
 
       layout.prop( obj.cv_data, "bp0", text = "Looping" )
       layout.prop( obj.cv_data, "bp1", text = "3D Audio" )
       layout.prop( obj.cv_data, "bp2", text = "Auto Start" )
+      layout.prop( obj.cv_data, "audio_format" )
+
+      layout.prop( obj.cv_data, "fltp", text = "Volume (0-1)" )
    #}
 
    @staticmethod
@@ -771,6 +813,82 @@ class classtype_audio(Structure):
    #}
 #}
 
+# Classtype 200
+# 
+#  Purpose: world light
+#
+class classtype_world_light( Structure ):
+#{
+   _pack_ = 1
+   _fields_ = [("type",c_uint32),
+               ("colour",c_float*4),
+               ("angle",c_float),
+               ("range",c_float)]
+
+   def encode_obj(_, node, node_def):
+   #{
+      node.classtype = 200
+
+      obj  = node_def['obj']
+      data = obj.data
+      _.colour[0] = data.color[0]
+      _.colour[1] = data.color[1]
+      _.colour[2] = data.color[2]
+      _.colour[3] = data.energy
+      _.range = data.cutoff_distance # this has to be manually set
+                                     # TODO: At some point, automate a min
+                                     #       threshold value
+
+      if obj.data.type == 'POINT':
+      #{
+         _.type = 0
+         _.angle = 0.0
+      #}
+      elif obj.data.type == 'SPOT':
+      #{
+         _.type = 1
+         _.angle = data.spot_size*0.5
+      #}
+
+      if data.cv_data.bp0:
+         _.type += 2
+   #}
+
+   @staticmethod
+   def editor_interface( layout, obj ):
+   #{
+      pass
+   #}
+#}
+
+# Classtype 201
+# 
+#  Purpose: lighting settings for world
+#
+class classtype_lighting_info(Structure):
+#{
+   _pack_ = 1
+   _fields_ = [("colours",(c_float*3)*3),
+               ("directions",(c_float*2)*3),
+               ("states",c_uint32*3),
+               ("shadow_spread",c_float),
+               ("shadow_length",c_float),
+               ("ambient",c_float*3)]
+
+   def encode_obj(_, node, node_def):
+   #{
+      node.classtype = 201
+
+      # TODO
+   #}
+
+   @staticmethod
+   def editor_interface( layout, obj ):
+   #{
+      pass
+   #}
+#}
+
 class classtype_spawn_link(Structure):
 #{
    _pack_ = 1
@@ -1156,6 +1274,7 @@ def encoder_process_material( mat ):
    if mat.cv_data.surface_prop == 'concrete': dest.surface_prop = 0
    if mat.cv_data.surface_prop == 'wood': dest.surface_prop = 1
    if mat.cv_data.surface_prop == 'grass': dest.surface_prop = 2
+   if mat.cv_data.surface_prop == 'tiles': dest.surface_prop = 3
 
    if mat.cv_data.shader == 'standard': dest.shader = 0
    if mat.cv_data.shader == 'standard_cutout': dest.shader = 1
@@ -1237,10 +1356,12 @@ def encoder_build_scene_graph( collection ):
 
    for obj in collection.all_objects:
    #{
-      if obj.parent: continue
+      #if obj.parent: continue
 
       def _extend( p, n, d ):
       #{
+         nonlocal collection
+
          uid = _new_uid()
          tree = {}
          tree["uid"] = uid
@@ -1249,7 +1370,7 @@ def encoder_build_scene_graph( collection ):
          tree["obj"] = n
          tree["parent"] = p
          n.cv_data.uid = uid
-         
+
          # Descend into amature
          #
          if n.type == 'ARMATURE':
@@ -1257,6 +1378,7 @@ def encoder_build_scene_graph( collection ):
             tree["bones"] = [None] # None is the root transform
             tree["ik_count"] = 0
             tree["collider_count"] = 0
+            tree["compile_animation"] = collection.cv_data.animations
             
             # Here also collects some information about constraints, ik and 
             # counts colliders for the armature.
@@ -1305,7 +1427,6 @@ def encoder_build_scene_graph( collection ):
          #
          for obj1 in n.children:
          #{
-            nonlocal collection
             for c1 in obj1.users_collection:
             #{
                if c1 == collection:
@@ -1667,7 +1788,12 @@ def encoder_compile_armature( node, node_def ):
    # extra info
    node_def['anim_start'] = len(animdata)
    node_def['anim_count'] = 0
-   
+   if not node_def['compile_animation']:
+   #{
+      return
+   #}  
+
    # Compile anims
    #
    if obj.animation_data:
@@ -1805,10 +1931,14 @@ def encoder_process_definition( node_def ):
    #{
       obj      = node_def['obj']
       obj_type = obj.type
-      obj_co   = obj.location
+      obj_co   = obj.matrix_world @ Vector((0,0,0))
 
       if obj_type == 'ARMATURE':
          obj_classtype = 'classtype_skeleton'
+      elif obj_type == 'LIGHT':
+      #{
+         obj_classtype = 'classtype_world_light'
+      #}
       else:
       #{
          obj_classtype = obj.cv_data.classtype
@@ -2528,6 +2658,31 @@ class CV_MESH_SETTINGS(bpy.types.PropertyGroup):
    v3: bpy.props.FloatVectorProperty(name="v3",size=3)
 #}
 
+class CV_LIGHT_SETTINGS(bpy.types.PropertyGroup):
+#{
+   bp0: bpy.props.BoolProperty( name="bp0" );
+#}
+
+class CV_LIGHT_PANEL(bpy.types.Panel):
+#{
+   bl_label="[Skate Rift]"
+   bl_idname="SCENE_PT_cv_light"
+   bl_space_type='PROPERTIES'
+   bl_region_type='WINDOW'
+   bl_context='data'
+
+   def draw(_,context):
+   #{
+      active_object = context.active_object
+      if active_object == None: return
+
+      if active_object.type != 'LIGHT': return
+
+      data = active_object.data.cv_data
+      _.layout.prop( data, "bp0", text="Only on during night" )
+   #}
+#}
+
 class CV_OBJ_SETTINGS(bpy.types.PropertyGroup):
 #{
    uid: bpy.props.IntProperty( name="" )
@@ -2566,6 +2721,15 @@ class CV_OBJ_SETTINGS(bpy.types.PropertyGroup):
       ('classtype_logic_achievement',"classtype_logic_achievement","",101),
       ('classtype_logic_relay',"classtype_logic_relay","",102),
       ('classtype_spawn_link',"classtype_spawn_link","",150),
+      ('classtype_nonlocal_gate', "classtype_nonlocal_gate", "", 300)
+      ])
+
+   audio_format: bpy.props.EnumProperty(
+      name="Loaded format",
+      items = [
+         ('mono', "mono", "", 0),
+         ('stereo', "stereo", "", 1),
+         ('remain compressed', "remain compressed", "", 2)
       ])
 #}
 
@@ -2594,7 +2758,7 @@ class CV_BONE_SETTINGS(bpy.types.PropertyGroup):
 
 class CV_BONE_PANEL(bpy.types.Panel):
 #{
-   bl_label="Bone Config"
+   bl_label="[Skate Rift]"
    bl_idname="SCENE_PT_cv_bone"
    bl_space_type='PROPERTIES'
    bl_region_type='WINDOW'
@@ -2631,6 +2795,7 @@ class CV_SCENE_SETTINGS(bpy.types.PropertyGroup):
 class CV_COLLECTION_SETTINGS(bpy.types.PropertyGroup):
 #{
    pack_textures: bpy.props.BoolProperty( name="Pack Textures", default=False )
+   animations:    bpy.props.BoolProperty( name="Export animation", default=True)
 #}
 
 class CV_MATERIAL_SETTINGS(bpy.types.PropertyGroup):
@@ -2650,7 +2815,8 @@ class CV_MATERIAL_SETTINGS(bpy.types.PropertyGroup):
       items = [
       ('concrete','concrete','',0),
       ('wood','wood','',1),
-      ('grass','grass','',2)
+      ('grass','grass','',2),
+      ('tiles','tiles','',3)
       ])
    
    collision: bpy.props.BoolProperty( \
@@ -2857,6 +3023,7 @@ class CV_INTERFACE(bpy.types.Panel):
       #{
          box.label( text=col.name + ".mdl" )
          box.prop( col.cv_data, "pack_textures" )
+         box.prop( col.cv_data, "animations" )
          box.operator( "carve.compile_this" )
       #}
       else:
@@ -2885,7 +3052,8 @@ class CV_INTERFACE(bpy.types.Panel):
 classes = [CV_OBJ_SETTINGS,CV_OBJ_PANEL,CV_COMPILE,CV_INTERFACE,\
            CV_MESH_SETTINGS, CV_SCENE_SETTINGS, CV_BONE_SETTINGS,\
            CV_BONE_PANEL, CV_COLLECTION_SETTINGS, CV_COMPILE_THIS,\
-           CV_MATERIAL_SETTINGS, CV_MATERIAL_PANEL ]
+           CV_MATERIAL_SETTINGS, CV_MATERIAL_PANEL, CV_LIGHT_SETTINGS,\
+           CV_LIGHT_PANEL]
 
 def register():
 #{
@@ -2902,6 +3070,7 @@ def register():
          bpy.props.PointerProperty(type=CV_COLLECTION_SETTINGS)
    bpy.types.Material.cv_data = \
          bpy.props.PointerProperty(type=CV_MATERIAL_SETTINGS)
+   bpy.types.Light.cv_data = bpy.props.PointerProperty(type=CV_LIGHT_SETTINGS)
 
    cv_view_draw_handler = bpy.types.SpaceView3D.draw_handler_add(\
       cv_draw,(),'WINDOW','POST_VIEW')