new menu start
[carveJwlIkooP6JGAAIwe30JlM.git] / blender_export.py
index 7c61247c67aa8d902c55f33b5e7245b6b5eb7d82..ede1106b484ec22db611381473a47cb9cb501395 100644 (file)
@@ -32,7 +32,8 @@ sr_entity_list = [
    ('ent_traffic',      'Traffic Model',  '', 11 ),
    ('ent_skateshop',    'Skate Shop',     '', 12 ),
    ('ent_camera',       'Camera',         '', 13 ),
-   ('ent_swspreview', 'Workshop Preview', '', 14 )
+   ('ent_swspreview', 'Workshop Preview', '', 14 ),
+   ('ent_menuitem',     'Menu Item',      '', 15 )
 ]
 
 def get_entity_enum_id( alias ):
@@ -355,6 +356,51 @@ class ent_swspreview(Structure):
                ("id_display1",c_uint32)]
 #}
 
+class ent_menuitem_slider(Structure):
+#{
+   _fields_ = [("id_min",c_uint32),
+               ("id_max",c_uint32),
+               ("id_handle",c_uint32),
+               ("pstr_data",c_uint32)]
+#}
+
+class ent_menuitem_button(Structure):
+#{
+   _fields_ = [("pstr",c_uint32)]
+#}
+
+class ent_menuitem_checkmark(Structure):
+#{
+   _fields_ = [("id_check",c_uint32),
+               ("pstr_data",c_uint32)]
+#}
+
+class ent_menuitem_page(Structure):
+#{
+   _fields_ = [("pstr_name",c_uint32),
+               ("id_entrypoint",c_uint32),
+               ("id_viewpoint",c_uint32)]
+#}
+
+class ent_menuitem_anon_union(Union):
+#{
+   _fields_ = [("slider",ent_menuitem_slider),
+               ("button",ent_menuitem_button),
+               ("checkmark",ent_menuitem_checkmark),
+               ("page",ent_menuitem_page)]
+#}
+
+class ent_menuitem(Structure):
+#{
+   _fields_ = [("type",c_uint32), ("groups",c_uint32),
+               ("id_links",c_uint32*4),
+               #-- TODO: Refactor this into a simple mesh structure
+               ("transform",mdl_transform),
+               ("submesh_start",c_uint32),("submesh_count",c_uint32),
+               #-- end
+               ("_anonymous_union", ent_menuitem_anon_union)]
+#}
+
 class ent_camera(Structure):
 #{
    _fields_ = [("transform",mdl_transform),
@@ -387,7 +433,9 @@ def sr_filter_ent_type( obj, ent_types ):
 def compile_obj_transform( obj, transform ):
 #{
    co = obj.matrix_world @ Vector((0,0,0))
-   q = obj.matrix_local.to_quaternion()
+
+   # This was changed from matrix_local on 09.05.23
+   q = obj.matrix_world.to_quaternion() 
    s = obj.scale
    
    # Setup transform
@@ -434,6 +482,7 @@ def sr_compile_string( s ):
    
    index = len( sr_compile.string_data )
    sr_compile.string_cache[s] = index
+   sr_compile.string_data.extend( c_uint32(hash_djb2(s)) )
    sr_compile.string_data.extend( s.encode('utf-8') )
    sr_compile.string_data.extend( b'\0' )
 
@@ -1098,6 +1147,70 @@ def sr_compile_fonts( collection ):
    #}
 #}
 
+def sr_compile_menus( collection ):
+#{
+   print( "[SR] Compiling menus" )
+   groups = []
+
+   for obj in collection.all_objects:#{
+      if obj_ent_type(obj) != 'ent_menuitem': continue
+      obj_data = obj.SR_data.ent_menuitem[0]
+
+      bitmask = 0x00000000
+
+      for col in obj.users_collection:#{
+         name = col.name
+         if name not in groups: groups.append( name )
+         bitmask |= (0x1 << groups.index(name))
+      #}
+
+      item = ent_menuitem()
+      item.type = int( obj_data.tipo )
+      item.groups = bitmask
+
+      compile_obj_transform( obj, item.transform )
+      if obj.type == 'MESH':#{
+         item.submesh_start, item.submesh_count, _ = \
+               sr_compile_mesh_internal( obj )
+      #}
+
+      if item.type == 1 or item.type == 2:#{
+         item_button = item._anonymous_union.button
+         item_button.string = sr_compile_string( obj_data.string )
+      #}
+      elif item.type == 3:#{
+         item_checkmark = item._anonymous_union.checkmark
+         item_checkmark.pstr_data = sr_compile_string( obj_data.string )
+         item_checkmark.id_check = sr_entity_id( obj_data.checkmark )
+      #}
+      elif item.type == 4:#{
+         item_slider = item._anonymous_union.slider
+         item_slider.id_min = sr_entity_id( obj_data.slider_minloc )
+         item_slider.id_max = sr_entity_id( obj_data.slider_maxloc )
+         item_slider.id_handle = sr_entity_id( obj_data.slider_handle )
+      #}
+      elif item.type == 5:#{
+         item_page = item._anonymous_union.page
+         item_page.pstr_name = sr_compile_string( obj_data.string )
+         item_page.id_entrypoint = sr_entity_id( obj_data.newloc )
+         item_page.id_viewpoint = sr_entity_id( obj_data.camera )
+      #}
+
+      if obj_data.link0:
+         item.id_links[0] = sr_entity_id( obj_data.link0 )
+      if obj_data.link1:
+         item.id_links[1] = sr_entity_id( obj_data.link1 )
+      if item.type != 4:#{
+         if obj_data.link2:
+            item.id_links[2] = sr_entity_id( obj_data.link2 )
+         if obj_data.link3:
+            item.id_links[3] = sr_entity_id( obj_data.link3 )
+      #}
+
+      sr_ent_push( item )
+   #}
+#}
+
 def sr_compile_armature( obj ):
 #{
    node = mdl_armature()
@@ -1290,6 +1403,15 @@ def sr_array_title( arr, name, count, size, offset ):
    arr.item_size = size
 #}
 
+def hash_djb2(s):
+#{
+   picadillo = 5381
+   for x in s:#{
+      picadillo = (((picadillo << 5) + picadillo) + ord(x)) & 0xFFFFFFFF
+   #}
+   return picadillo
+#}
+
 def sr_compile( collection ):
 #{
    print( F"[SR] compiler begin ({collection.name}.mdl)" )
@@ -1328,6 +1450,11 @@ def sr_compile( collection ):
    sr_compile.entities = {}
    sr_compile.entity_ids = {}
 
+   # begin
+   # -------------------------------------------------------
+
+   sr_compile_string( "null" )
+
    mesh_count = 0
    for obj in collection.all_objects: #{
       if obj.type == 'MESH':#{
@@ -1355,6 +1482,7 @@ def sr_compile( collection ):
          if ent_type == 'ent_traffic': continue
          if ent_type == 'ent_font': continue
          if ent_type == 'ent_font_variant': continue
+         if ent_type == 'ent_menuitem': continue
          #--------------------------
 
          print( F'[SR] {i: 3}/{mesh_count} {obj.name:<40}', end='\r' )
@@ -1540,7 +1668,8 @@ def sr_compile( collection ):
       #}
    #}
 
-   sr_compile_fonts(collection)
+   sr_compile_menus( collection )
+   sr_compile_fonts( collection )
 
    def _children( col ):#{
       yield col
@@ -1639,7 +1768,7 @@ def sr_compile( collection ):
          compile_obj_transform( obj, traffic.transform )
          traffic.submesh_start, traffic.submesh_count, _ = \
                sr_compile_mesh_internal( obj )
-
+         
          # find best subsection
          
          graph_keys = list(dij.graph)
@@ -1733,7 +1862,7 @@ def sr_compile( collection ):
 
    fp = open( path, "wb" )
    header = mdl_header()
-   header.version = 100
+   header.version = 101
    sr_array_title( header.arrays, \
                    'index', len(file_array_instructions), \
                    sizeof(mdl_array), header_size )
@@ -2664,6 +2793,99 @@ class SR_OBJECT_ENT_WORKSHOP_PREVIEW(bpy.types.PropertyGroup):
            poll=lambda self,obj: sr_filter_ent_type(obj,['ent_camera']))
 #}
 
+class SR_OBJECT_ENT_MENU_ITEM(bpy.types.PropertyGroup):
+#{
+   link0: bpy.props.PointerProperty( \
+           type=bpy.types.Object, name="Link 0", \
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem']))
+   link1: bpy.props.PointerProperty( \
+           type=bpy.types.Object, name="Link 1", \
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem']))
+   link2: bpy.props.PointerProperty( \
+           type=bpy.types.Object, name="Link 2", \
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem']))
+   link3: bpy.props.PointerProperty( \
+           type=bpy.types.Object, name="Link 3", \
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem']))
+
+   newloc: bpy.props.PointerProperty( \
+           type=bpy.types.Object, name="New location", \
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem']))
+   camera: bpy.props.PointerProperty( \
+           type=bpy.types.Object, name="Camera", \
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_camera']))
+
+   slider_minloc: bpy.props.PointerProperty( \
+           type=bpy.types.Object, name="Slider min", \
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker']))
+   slider_maxloc: bpy.props.PointerProperty( \
+           type=bpy.types.Object, name="Slider max", \
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_marker']))
+   slider_handle: bpy.props.PointerProperty( \
+           type=bpy.types.Object, name="Slider handle", \
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem']))
+
+   checkmark: bpy.props.PointerProperty( \
+           type=bpy.types.Object, name="Checked", \
+           poll=lambda self,obj: sr_filter_ent_type(obj,['ent_menuitem']))
+
+   string: bpy.props.StringProperty( name="String" )
+   tipo: bpy.props.EnumProperty( name='Type',
+                                 items=[('0','visual',''),
+                                        ('1','event button',''),
+                                        ('2','page button',''),
+                                        ('3','toggle', ''),
+                                        ('4','slider',''),
+                                        ('5','page','')])
+
+   @staticmethod
+   def sr_inspector( layout, data ):
+   #{
+      data = data[0]
+      box = layout.box()
+      box.prop( data, 'tipo' )
+
+      if data.tipo == '0':#{
+         return
+      #}
+      elif data.tipo == '1':#{
+         box.prop( data, 'string', text='Event' )
+      #}
+      elif data.tipo == '2':#{
+         box.prop( data, 'string', text='Page' )
+         box.prop( data, 'newloc' )
+      #}
+      elif data.tipo == '3':#{
+         box.prop( data, 'string', text='Data (i32)' )
+         box.prop( data, 'checkmark' )
+      #}
+      elif data.tipo == '4':#{
+         box.prop( data, 'string', text='Data (f32)' )
+         box.prop( data, 'slider_minloc' )
+         box.prop( data, 'slider_maxloc' )
+         box.prop( data, 'slider_handle' )
+         box = box.box()
+         box.label( text="Links" )
+         box.prop( data, 'link0', text='v0' )
+         box.prop( data, 'link1', text='v1' )
+         return
+      #}
+      elif data.tipo == '5':#{
+         box.prop( data, 'string', text='Page Name' )
+         box.prop( data, 'newloc', text='Entry Point' )
+         box.prop( data, 'camera', text='Viewpoint' )
+         return
+      #}
+      
+      box = box.box()
+      box.label( text="Links" )
+      box.prop( data, 'link0' )
+      box.prop( data, 'link1' )
+      box.prop( data, 'link2' )
+      box.prop( data, 'link3' )
+   #}
+#}
+
 class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup):
 #{
    ent_gate: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_GATE)
@@ -2678,6 +2900,7 @@ class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup):
    ent_skateshop: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_SKATESHOP)
    ent_swspreview: \
          bpy.props.CollectionProperty(type=SR_OBJECT_ENT_WORKSHOP_PREVIEW)
+   ent_menuitem: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_MENU_ITEM)
 
    ent_type: bpy.props.EnumProperty(
       name="Type",
@@ -3665,6 +3888,77 @@ def cv_draw():
             if display1:
                cv_draw_ucube(display1.matrix_world, cc1, display_cu, display_co)
          #}
+         elif ent_type == 'ent_menuitem':#{
+            for i,col in enumerate(obj.users_collection):#{
+               colour32 = hash_djb2( col.name )
+               r = pow(((colour32    ) & 0xff) / 255.0, 2.2 )
+               g = pow(((colour32>>8 ) & 0xff) / 255.0, 2.2 )
+               b = pow(((colour32>>16) & 0xff) / 255.0, 2.2 )
+               cc = (r,g,b)
+               vs = [None for _ in range(8)]
+               scale = i*0.02
+               for j in range(8):#{
+                  v0 = Vector([(obj.bound_box[j][z]+\
+                        ((-1.0 if obj.bound_box[j][z]<0.0 else 1.0)*scale)) \
+                           for z in range(3)])
+                  vs[j] = obj.matrix_world @ v0
+               #}
+               indices = [(0,1),(1,2),(2,3),(3,0),(4,5),(5,6),(6,7),(7,4),\
+                          (0,4),(1,5),(2,6),(3,7)]
+               for l in indices:#{
+                  v0 = vs[l[0]]
+                  v1 = vs[l[1]]
+                  cv_view_verts += [(v0[0],v0[1],v0[2])]
+                  cv_view_verts += [(v1[0],v1[1],v1[2])]
+                  cv_view_colours += [cc,cc]
+               #}
+            #}
+            cv_draw_lines()
+            cc = (1.0,1.0,1.0)
+            data = obj.SR_data.ent_menuitem[0]
+            if data.tipo == '4':#{
+               if data.slider_minloc and data.slider_maxloc:#{
+                  v0 = data.slider_minloc.location
+                  v1 = data.slider_maxloc.location
+                  cv_draw_line( v0, v1, cc )
+               #}
+            #}
+
+            colour32 = hash_djb2(obj.name)
+            r = ((colour32    ) & 0xff) / 255.0
+            g = ((colour32>>8 ) & 0xff) / 255.0
+            b = ((colour32>>16) & 0xff) / 255.0
+            cc = (r,g,b)
+            origin = obj.location + (Vector((r,g,b))*2.0-Vector((1.0,1.0,1.0)))\
+                        * 0.04
+
+            size = 0.01
+
+            if data.tipo != '0':#{
+               if data.tipo == '4':#{
+                  if data.link0:#{
+                     cv_draw_arrow( origin, data.link0.location, cc, size )
+                  #}
+                  if data.link1:#{
+                     cv_draw_arrow( origin, data.link1.location, cc, size )
+                  #}
+               #}
+               else:#{
+                  if data.link0:#{
+                     cv_draw_arrow( origin, data.link0.location, cc, size )
+                  #}
+                  if data.link1:#{
+                     cv_draw_arrow( origin, data.link1.location, cc, size )
+                  #}
+                  if data.link2:#{
+                     cv_draw_arrow( origin, data.link2.location, cc, size )
+                  #}
+                  if data.link3:#{
+                     cv_draw_arrow( origin, data.link3.location, cc, size )
+                  #}
+               #}
+            #}
+         #}
       #}
    #}
 
@@ -3699,7 +3993,7 @@ classes = [ SR_INTERFACE, SR_MATERIAL_PANEL,\
             SR_OBJECT_ENT_GLYPH_ENTRY,\
             SR_UL_FONT_VARIANT_LIST,SR_UL_FONT_GLYPH_LIST,\
             SR_OBJECT_ENT_FONT,SR_OBJECT_ENT_TRAFFIC,SR_OBJECT_ENT_SKATESHOP,\
-            SR_OBJECT_ENT_WORKSHOP_PREVIEW,\
+            SR_OBJECT_ENT_WORKSHOP_PREVIEW,SR_OBJECT_ENT_MENU_ITEM,\
             \
             SR_OBJECT_PROPERTIES, SR_LIGHT_PROPERTIES, SR_BONE_PROPERTIES, 
             SR_MESH_PROPERTIES, SR_MATERIAL_PROPERTIES \