ZenHAX

Free Game Research Forum | Official QuickBMS support | twitter @zenhax | SSL HTTPS://zenhax.com
It is currently Tue Apr 20, 2021 3:51 pm

All times are UTC




Post new topic  Reply to topic  [ 17 posts ] 
Author Message
PostPosted: Sat Oct 06, 2018 7:32 pm 
User avatar

Joined: Fri Apr 20, 2018 12:41 am
Posts: 764
Any idea on how to open XGM files properly? It would help a lot. The 10 byte header is always : 15 00 00 00 18 00 00 00 58 47 53 4D 26 01 01 01. I heard hex2obj is the best for this but I'm not sure...

ABGO full game dump: https://drive.google.com/open?id=10Lp3D ... JdUTljgDzo

_________________
Hacking Angry Birds since 2016


Last edited by LolHacksRule on Fri Dec 13, 2019 5:25 pm, edited 3 times in total.

Top
   
PostPosted: Sat Apr 20, 2019 4:16 am 
User avatar

Joined: Fri Apr 20, 2018 12:41 am
Posts: 764
Anything?

_________________
Hacking Angry Birds since 2016


Top
   
PostPosted: Sun Sep 29, 2019 7:57 pm 
User avatar

Joined: Fri Apr 20, 2018 12:41 am
Posts: 764
Bump again? Its not just me looking for these...

_________________
Hacking Angry Birds since 2016


Top
   
PostPosted: Fri Dec 13, 2019 5:16 pm 
User avatar

Joined: Fri Apr 20, 2018 12:41 am
Posts: 764
They are in the "models" directory of the game data in case you can't find them.

_________________
Hacking Angry Birds since 2016


Top
   
PostPosted: Sun Dec 15, 2019 12:09 am 
User avatar

Joined: Fri Aug 08, 2014 1:06 am
Posts: 706
maybe moving this to "3D/2D models" will gain the attention it needs? :)

_________________
Quickbms.com link thread
Search bms scripts


Top
   
PostPosted: Tue Dec 31, 2019 11:38 pm 
User avatar

Joined: Fri Apr 20, 2018 12:41 am
Posts: 764
I already sent a report to do so but thanks anyways.

_________________
Hacking Angry Birds since 2016


Top
   
PostPosted: Sat Jan 11, 2020 12:53 am 

Joined: Tue Jul 24, 2018 8:52 am
Posts: 501
This is your layout.
Image
This is your UV's
Image
Faces start right after last UV
Image
Faces
Image
Render
Image
Here is the file
https://drive.google.com/file/d/1KpWe2o ... sp=sharing


Top
   
PostPosted: Sat Jan 11, 2020 12:59 am 

Joined: Tue Jul 24, 2018 8:52 am
Posts: 501
Sorry. I would of posted sooner but don't really look in here. He's right this should be in 3D Models :D


Top
   
PostPosted: Sat Jan 11, 2020 5:43 pm 
User avatar

Joined: Fri Apr 20, 2018 12:41 am
Posts: 764
DUDE I LOVE YOU! But how would I open them? I don't have that program...

_________________
Hacking Angry Birds since 2016


Top
   
PostPosted: Sat Jan 11, 2020 5:54 pm 

Joined: Tue Jul 24, 2018 8:52 am
Posts: 501
Its free.
http://mr.game-viewer.org/


Top
   
PostPosted: Sat Jan 11, 2020 10:35 pm 
User avatar

Joined: Fri Apr 20, 2018 12:41 am
Posts: 764
Hell yeah!

_________________
Hacking Angry Birds since 2016


Top
   
PostPosted: Sun Jan 12, 2020 4:18 pm 
User avatar

Joined: Sun Oct 13, 2019 1:00 am
Posts: 18
DJ Normality wrote:
Sorry. I would of posted sooner but don't really look in here. He's right this should be in 3D Models :D

even more progress made for this not well known engine. do you think you could explain your process on how you found out what is what? i would like to do the same with the XGM models in need for speed hot pursuit (the wii version).
i have all of the game's files on this google drive link.


Top
   
PostPosted: Tue Feb 09, 2021 4:12 am 

Joined: Sat May 09, 2020 11:33 pm
Posts: 7
What about these files xgm?
https://www.mediafire.com/folder/lmyr80 ... es_Example


Top
   
PostPosted: Sun Mar 07, 2021 6:08 pm 

Joined: Sat May 09, 2020 11:33 pm
Posts: 7
JCBurgos01 wrote:

Nothing? Please


Top
   
PostPosted: Mon Mar 08, 2021 5:06 am 
User avatar

Joined: Fri Aug 08, 2014 12:59 am
Posts: 8
blender python script, goto the script tab press new and paste the script. press the play button (Alt + P) and you can open a xgm and import it into blender. From that point the script is registered and you can access the import function through the File > Import context until blender is restarted.

Code:
""" ======================================================================

    PythonScript:   [Mobile] Angry Birds Transformers
    Author:         mariokart64n
    Date:           March 07, 2021
    Version:        0.1

    ======================================================================

    ChangeLog:

    2021-03-37
        Script Wrote
   

    ====================================================================== """

import bpy  # Needed to interface with blender
import struct  # Needed for Binary Reader
import math
from pathlib import Path  # Needed for os stuff

useOpenDialog = True

#
# ====================================================================================
# MAXCSRIPT FUNCTIONS
# ====================================================================================
# These function are written to mimic native functions in
# maxscript. This is to make porting my old maxscripts
# easier, so alot of these functions may be redundant..
# ====================================================================================
#

signed, unsigned = 0, 1  # Enums for read function
seek_set, seek_cur, seek_end = 0, 1, 2  # Enums for seek function

def messageBox(message="", title="Message Box", icon='INFO'):
    def draw(self, context): self.layout.label(text=message)

    bpy.context.window_manager.popup_menu(draw, title=title, icon=icon)
    return None

def getFileSize(filename):
    return Path(filename).stat().st_size

def clearListener(len=64):
    for i in range(0, len): print('')

def append(array, value):
    array.append(value)
    return None

class fopen:
    little_endian = True
    file = ""
    mode = 'rb'
    data = bytearray()
    size = 0
    pos = 0
    isGood = False

    def __init__(self, filename=None, mode='rb', isLittleEndian=True):
        if mode == 'rb':
            if filename != None and Path(filename).is_file():
                self.data = open(filename, mode).read()
                self.size = len(self.data)
                self.pos = 0
                self.mode = mode
                self.file = filename
                self.little_endian = isLittleEndian
                self.isGood = True
        else:
            self.file = filename
            self.mode = mode
            self.data = bytearray()
            self.pos = 0
            self.size = 0
            self.little_endian = isLittleEndian
            self.isGood = False

        return None

    # def __del__(self):
    #    self.flush()

    def resize(self, dataSize=0):
        if dataSize > 0:
            self.data = bytearray(dataSize)
        else:
            self.data = bytearray()
        self.pos = 0
        self.size = dataSize
        self.isGood = False
        return None

    def flush(self):
        print("flush")
        print("file:\t%s" % self.file)
        print("isGood:\t%s" % self.isGood)
        print("size:\t%s" % len(self.data))
        if self.file != "" and not self.isGood and len(self.data) > 0:
            self.isGood = True

            s = open(self.file, 'w+b')
            s.write(self.data)
            s.close()

    def read_and_unpack(self, unpack, size):
        '''
          Charactor, Byte-order
          @,         native, native
          =,         native, standard
          <,         little endian
          >,         big endian
          !,         network

          Format, C-type,         Python-type, Size[byte]
          c,      char,           byte,        1
          b,      signed char,    integer,     1
          B,      unsigned char,  integer,     1
          h,      short,          integer,     2
          H,      unsigned short, integer,     2
          i,      int,            integer,     4
          I,      unsigned int,   integer,     4
          f,      float,          float,       4
          d,      double,         float,       8
        '''
        value = 0
        if self.size > 0 and self.pos + size < self.size:
            value = struct.unpack_from(unpack, self.data, self.pos)[0]
            self.pos += size
        return value

    def pack_and_write(self, pack, size, value):
        if self.pos + size > self.size:
            self.data.extend(b'\x00' * ((self.pos + size) - self.size))
            self.size = self.pos + size
        try:
            struct.pack_into(pack, self.data, self.pos, value)
        except:
            print('Pos:\t%i / %i (buf:%i) [val:%i:%i:%s]' % (self.pos, self.size, len(self.data), value, size, pack))
            pass
        self.pos += size
        return None

    def set_pointer(self, offset):
        self.pos = offset
        return None


def fclose(bitStream):
    bitStream.flush()
    bitStream.isGood = False


def fseek(bitStream, offset, dir):
    if dir == 0:
        bitStream.set_pointer(offset)
    elif dir == 1:
        bitStream.set_pointer(bitStream.pos + offset)
    elif dir == 2:
        bitStream.set_pointer(bitStream.pos - offset)
    return None


def ftell(bitStream):
    return bitStream.pos


def readByte(bitStream, isSigned=0):
    fmt = 'b' if isSigned == 0 else 'B'
    return (bitStream.read_and_unpack(fmt, 1))


def readShort(bitStream, isSigned=0):
    fmt = '>' if not bitStream.little_endian else '<'
    fmt += 'h' if isSigned == 0 else 'H'
    return (bitStream.read_and_unpack(fmt, 2))


def readLong(bitStream, isSigned=0):
    fmt = '>' if not bitStream.little_endian else '<'
    fmt += 'i' if isSigned == 0 else 'I'
    return (bitStream.read_and_unpack(fmt, 4))


def readFloat(bitStream):
    fmt = '>f' if not bitStream.little_endian else '<f'
    return (bitStream.read_and_unpack(fmt, 4))


def readString(bitStream, length=0):
    string = ''
    pos = bitStream.pos
    lim = length if length != 0 else bitStream.size - bitStream.pos
    for i in range(0, lim):
        b = bitStream.read_and_unpack('B', 1)
        if b != 0:
            string += chr(b)
        else:
            if length > 0:
                bitStream.set_pointer(pos + length)
            break
    return string


def mesh(vertices=[], faces=[], materialIDs=[], tverts=[], normals=[], colours=[], materials=[], mscale=1.0, flipAxis=False, obj_name="Object", lay_name=''):
    #
    # This function is pretty, ugly
    # imports the mesh into blender
    #

    # Clear Any Object Selections
    # for o in bpy.context.selected_objects: o.select = False
    bpy.context.view_layer.objects.active = None

    # Get Collection (Layers)
    if lay_name != '':
        # make collection
        layer = bpy.data.collections.new(lay_name)
        bpy.context.scene.collection.children.link(layer)
    else:
        layer = bpy.data.collections[bpy.context.view_layer.active_layer_collection.name]

    # make mesh
    msh = bpy.data.meshes.new('Mesh')

    # msh.name = msh.name.replace(".", "_")

    # Apply vertex scaling
    # mscale *= bpy.context.scene.unit_settings.scale_length
    if len(vertices) > 0:
        vertArray = [[float] * 3] * len(vertices)
        if flipAxis:
            for v in range(0, len(vertices)):
                vertArray[v] = (
                    vertices[v][0] * mscale,
                    -vertices[v][2] * mscale,
                    vertices[v][1] * mscale
                )
        else:
            for v in range(0, len(vertices)):
                vertArray[v] = (
                    vertices[v][0] * mscale,
                    vertices[v][1] * mscale,
                    vertices[v][2] * mscale
                )

    # assign data from arrays
    msh.from_pydata(vertArray, [], faces)

    # set surface to smooth
    msh.polygons.foreach_set("use_smooth", [True] * len(msh.polygons))

    # Set Normals
    if len(faces) > 0:
        if len(normals) > 0:
            msh.use_auto_smooth = True
            if len(normals) == (len(faces) * 3):
                msh.normals_split_custom_set(normals)
            else:
                normArray = [[float] * 3] * (len(faces) * 3)
                if flipAxis:
                    for i in range(0, len(faces)):
                        for v in range(0, 3):
                            normArray[(i * 3) + v] = (
                                [normals[faces[i][v]][0],
                                 -normals[faces[i][v]][2],
                                 normals[faces[i][v]][1]]
                            )
                else:
                    for i in range(0, len(faces)):
                        for v in range(0, 3):
                            normArray[(i * 3) + v] = (
                                [normals[faces[i][v]][0],
                                 normals[faces[i][v]][1],
                                 normals[faces[i][v]][2]]
                            )
                msh.normals_split_custom_set(normArray)

        # create texture corrdinates
        print("tverts ", len(tverts))
        # this is just a hack, i just add all the UVs into the same space <<<
        if len(tverts) > 0:
            uvw = msh.uv_layers.new()
            # if len(tverts) == (len(faces) * 3):
            #    for v in range(0, len(faces) * 3):
            #        msh.uv_layers[uvw.name].data[v].uv = tverts[v]
            # else:
            uvwArray = [[float] * 2] * len(tverts[0])
            for i in range(0, len(tverts[0])):
                uvwArray[i] = [0.0, 0.0]

            for v in range(0, len(tverts[0])):
                for i in range(0, len(tverts)):
                    uvwArray[v][0] += tverts[i][v][0]
                    uvwArray[v][1] += 1.0 - tverts[i][v][1]

            for i in range(0, len(faces)):
                for v in range(0, 3):
                    msh.uv_layers[uvw.name].data[(i * 3) + v].uv = (
                        uvwArray[faces[i][v]][0],
                        uvwArray[faces[i][v]][1]
                    )

        # create vertex colours
        if len(colours) > 0:
            col = msh.vertex_colors.new()
            if len(colours) == (len(faces) * 3):
                for v in range(0, len(faces) * 3):
                    msh.vertex_colors[col.name].data[v].color = colours[v]
            else:
                colArray = [[float] * 4] * (len(faces) * 3)
                for i in range(0, len(faces)):
                    for v in range(0, 3):
                        msh.vertex_colors[col.name].data[(i * 3) + v].color = colours[faces[i][v]]


    # Create Face Maps?
    # msh.face_maps.new()

    # Update Mesh
    msh.update()

    # Check mesh is Valid
    if msh.validate():
        # Erase Mesh
        print("Mesh Invalid!")
        msh.user_clear()
        bpy.data.meshes.remove(msh)
        return None

    # Assign Mesh to Object
    obj = bpy.data.objects.new(obj_name, msh)
    # obj.name = obj.name.replace(".", "_")

    for i in range(0, len(materials)):

        if len(obj.material_slots) < (i + 1):
            # if there is no slot then we append to create the slot and assign
            obj.data.materials.append(materials[i])
        else:
            # we always want the material in slot[0]
            obj.material_slots[0].material = materials[i]
        # obj.active_material = obj.material_slots[i].material

    for i in range(0, len(materialIDs)):
        obj.data.polygons[i].material_index = materialIDs[i]

    # obj.data.materials.append(material)
    layer.objects.link(obj)

    # Generate a Material
    # img_name = "Test.jpg"  # dummy texture
    # mat_count = len(texmaps)

    # if mat_count == 0 and len(materialIDs) > 0:
    #    for i in range(0, len(materialIDs)):
    #        if (materialIDs[i] + 1) > mat_count: mat_count = materialIDs[i] + 1

    # Assign Material ID's
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.mode_set(mode='EDIT', toggle=False)
    bpy.context.tool_settings.mesh_select_mode = [False, False, True]

    bpy.ops.object.mode_set(mode='OBJECT')
    # materialIDs

    # Redraw Entire Scene
    # bpy.context.scene.update()

    return obj


# END OF MAXSCRIPT FUNCTIONS #########################################################


#
# ====================================================================================
# BLENDER API FUNCTIONS
# ====================================================================================
# These are functions or wrappers specific with dealing with blender's API
# ====================================================================================
#


def deleteScene(include=[]):
    if len(include) > 0:
        # Exit and Interactions
        if bpy.context.view_layer.objects.active != None:
            bpy.ops.object.mode_set(mode='OBJECT')

        # Select All
        bpy.ops.object.select_all(action='SELECT')

        # Loop Through Each Selection
        for o in bpy.context.view_layer.objects.selected:
            for t in include:
                if o.type == t:
                    bpy.data.objects.remove(o, do_unlink=True)
                    break

        # De-Select All
        bpy.ops.object.select_all(action='DESELECT')
    return None



# Callback when file(s) are selected
def abt_xgm_imp_callback(fpath="", files=[], clearScene=True, mscale = 1.0):
    if len(files) > 0 and clearScene: deleteScene(['MESH', 'ARMATURE'])
    for file in files:
        read(fpath + file.name, mscale)
    if len(files) > 0:
        messageBox("Done!")
        return True
    else:
        return False


# Wrapper that Invokes FileSelector to open files from blender
def abt_xgm_imp(reload=False):
    # Un-Register Operator
    if reload and hasattr(bpy.types, "IMPORTHELPER_OT_abt_xgm_imp"):  # print(bpy.ops.importhelper.abt_xgm_imp.idname())

        try:
            bpy.types.TOPBAR_MT_file_import.remove(
                bpy.types.Operator.bl_rna_get_subclass_py('IMPORTHELPER_OT_abt_xgm_imp').menu_func_import)
        except:
            print("Failed to Unregister2")

        try:
            bpy.utils.unregister_class(bpy.types.Operator.bl_rna_get_subclass_py('IMPORTHELPER_OT_abt_xgm_imp'))
        except:
            print("Failed to Unregister1")

    # Define Operator
    class ImportHelper_abt_xgm_imp(bpy.types.Operator):

        # Operator Path
        bl_idname = "importhelper.abt_xgm_imp"
        bl_label = "Select File"

        # Operator Properties
        # filter_glob: bpy.props.StringProperty(default='*.jpg;*.jpeg;*.png;*.tif;*.tiff;*.bmp', options={'HIDDEN'})
        filter_glob: bpy.props.StringProperty(default='*.xgm', options={'HIDDEN'}, subtype='FILE_PATH')

        # Variables
        filepath: bpy.props.StringProperty(subtype="FILE_PATH")  # full path of selected item (path+filename)
        filename: bpy.props.StringProperty(subtype="FILE_NAME")  # name of selected item
        directory: bpy.props.StringProperty(subtype="FILE_PATH")  # directory of the selected item
        files: bpy.props.CollectionProperty(type=bpy.types.OperatorFileListElement)  # a collection containing all the selected items as filenames

        # Controls
        my_float1: bpy.props.FloatProperty(name="Scale", default=1.0, description="Changes Scale of the imported Mesh")
        my_bool1: bpy.props.BoolProperty(name="Clear Scene", default=True, description="Deletes everything in the scene prior to importing")

        # Runs when this class OPENS
        def invoke(self, context, event):

            # Retrieve Settings
            try: self.filepath = bpy.types.Scene.abt_xgm_imp_filepath
            except: bpy.types.Scene.abt_xgm_imp_filepath = bpy.props.StringProperty(subtype="FILE_PATH")

            try: self.directory = bpy.types.Scene.abt_xgm_imp_directory
            except: bpy.types.Scene.abt_xgm_imp_directory = bpy.props.StringProperty(subtype="FILE_PATH")

            try: self.my_float1 = bpy.types.Scene.abt_xgm_imp_my_float1
            except: bpy.types.Scene.abt_xgm_imp_my_float1 = bpy.props.FloatProperty(default=1.0)

            try: self.my_bool1 = bpy.types.Scene.abt_xgm_imp_my_bool1
            except: bpy.types.Scene.abt_xgm_imp_my_bool1 = bpy.props.BoolProperty(default=False)


            # Open File Browser
            # Set Properties of the File Browser
            context.window_manager.fileselect_add(self)
            context.area.tag_redraw()

            return {'RUNNING_MODAL'}

        # Runs when this Window is CANCELLED
        def cancel(self, context): print("run *SPAM*")

        # Runs when the class EXITS
        def execute(self, context):

            # Save Settings
            bpy.types.Scene.abt_xgm_imp_filepath = self.filepath
            bpy.types.Scene.abt_xgm_imp_directory = self.directory
            bpy.types.Scene.abt_xgm_imp_my_float1 = self.my_float1
            bpy.types.Scene.abt_xgm_imp_my_bool1 = self.my_bool1

            # Run Callback
            abt_xgm_imp_callback(self.directory + "\\", self.files, self.my_bool1, self.my_float1)

            return {"FINISHED"}

            # Window Settings

        def draw(self, context):

            self.layout.row().label(text="Import Settings")

            self.layout.separator()
            self.layout.row().prop(self, "my_bool1")
            self.layout.row().prop(self, "my_float1")

            self.layout.separator()

            col = self.layout.row()
            col.alignment = 'RIGHT'
            col.label(text="  Author:", icon='QUESTION')
            col.alignment = 'LEFT'
            col.label(text="mariokart64n")

            col = self.layout.row()
            col.alignment = 'RIGHT'
            col.label(text="Release:", icon='GRIP')
            col.alignment = 'LEFT'
            col.label(text="March 07, 2021")

        def menu_func_import(self, context):
            self.layout.operator("importhelper.abt_xgm_imp", text="Angrybirds Transformers (*.xgm)")

    # Register Operator
    bpy.utils.register_class(ImportHelper_abt_xgm_imp)
    bpy.types.TOPBAR_MT_file_import.append(ImportHelper_abt_xgm_imp.menu_func_import)

    # Call ImportHelper
    bpy.ops.importhelper.abt_xgm_imp('INVOKE_DEFAULT')


# END OF BLENDER FUNCTIONS ###########################################################


#
# ====================================================================================
# MAIN CODE
# ====================================================================================
# And the actual program... honesty I should have split the code into modules <_<
# ====================================================================================
#


def read(file="", mscale = 1.0):
    f = fopen(file, "rb")
    if f.isGood:

        fsize = getFileSize(file)
        type = 0
        info = 0
        blen = 0
        pos = 0
        mshName = "Mesh"
        version = 0
        vertBufAddr = 0
        faceBufAddr = 0
        faceBufAddr2 = 0
        vertBufSize = 0
        faceBufSize = 0
        vertBufStride = 24
        faceBufStride = 2
        vertCount = 0
        faceCount = 0
        vertArray = []
        tvertArray = []
        faceArray = []
        msh = None
        face = [1, 1, 1]
        maxVert = 0
        addrs = []

        while ftell(f) < fsize:
            pos = ftell(f)
            type = readShort(f, unsigned)
            info = readShort(f, unsigned)
            blen = readLong(f, unsigned)
            if type == 0x15:
                fseek(f, 4, seek_cur)
                version = readByte(f, unsigned)

            elif type == 0x2D:
                fseek(f, 2, seek_cur)
                mshName = readString(f)
                print("mshName:\t%s" % mshName)

            elif type == 0x11:
                if version == 0x24:
                    fseek(f, 0x14, seek_cur)
                    addrs = []
                    for i in range(0, 10):
                        addrs.append(readLong(f, unsigned))
                    addrs.append(blen)
                    vertBufAddr = addrs[0]
                    normBuffAddr = addrs[1]
                    faceBufAddr = addrs[2]
                    tvertBufAddr = addrs[4]

                    print("vertBufAddr:\t%i" % vertBufAddr)
                    print("faceBufAddr:\t%i" % faceBufAddr)

                    addrs.sort()

                    vertCount = 0
                    for i in range(10, -1, -1):
                        if addrs[i] == vertBufAddr:
                            vertCount = int((addrs[i + 1] - vertBufAddr) / 12)
                            print("vertCount:\t%i" % vertCount)
                            break

                    if vertCount > 0:
                        fseek(f, pos + vertBufAddr, seek_set)
                        vertArray = [[float] * 3] * vertCount
                        tvertArray = [[float] * 3] * vertCount
                        for i in range(0, vertCount):
                            vertArray[i] = [readFloat(f), readFloat(f), readFloat(f)]

                        fseek(f, pos + tvertBufAddr, seek_set)
                        for i in range(0, vertCount):
                            tvertArray[i] = [readFloat(f), readFloat(f), 0.0]

                    faceCount = 0
                    for i in range(len(addrs) - 1, -1, -1):
                        if addrs[i] == faceBufAddr:
                            faceCount = int((addrs[i + 1] - faceBufAddr) / 2 / 3)
                            print("faceCount:\t%i" % faceCount)
                            break

                    if faceCount > 0:
                        maxVert = 0
                        fseek(f, pos + faceBufAddr, seek_set)
                        for i in range(0, faceCount):
                            face = [readShort(f, unsigned), readShort(f, unsigned), readShort(f, unsigned)]
                            if face[0] + 1 > maxVert: maxVert = face[0] + 1
                            if face[1] + 1 > maxVert: maxVert = face[1] + 1
                            if face[2] + 1 > maxVert: maxVert = face[2] + 1

                            if maxVert <= len(vertArray):
                                append(faceArray, face)

                            else:
                                print("index over")
                                break

                        print("maxVert:\t%i" % maxVert)

                    print(ftell(f))
                    if len(vertArray) > 0:
                        msh = mesh(vertices=vertArray, faces=faceArray, tverts=[tvertArray], mscale=mscale)

                    break


            elif type == 0x31:
                fseek(f, 0x78, seek_cur)
                vertBufAddr = readLong(f, unsigned)
                fseek(f, 0x04, seek_cur)
                faceBufAddr = readLong(f, unsigned)
                fseek(f, 0x34, seek_cur)
                vertBufSize = readLong(f, unsigned)
                faceBufSize = readLong(f, unsigned)

                vertCount = int(vertBufSize / vertBufStride)
                print("vertCount:\t%i" % vertCount)
                if vertCount > 0:
                    vertArray = [[float] * 3] * vertCount
                    tvertArray = [[float] * 3] * vertCount
                    fseek(f, pos + vertBufAddr, seek_set)
                    for i in range(0, vertCount):
                        vertArray[i] = [readFloat(f), readFloat(f), readFloat(f)]
                        fseek(f, 4, seek_cur)  # Normal
                        fseek(f, 4, seek_cur)  # Vertex Colour
                        tvertArray[i] = [readShort(f, signed) / 32767.0 + 0.5, readShort(f, signed) / 32767.0 + 0.5, 0.0]
                        tvertArray[i] = [1.0 - vertArray[i][1], vertArray[i][2], 0.0]

                faceCount = int(faceBufSize / faceBufStride / 3)
                if faceCount > 0:
                    maxVert = 0
                    fseek(f, pos + faceBufAddr, seek_set)

                    for i in range(0, faceCount):
                        face = [readShort(f, unsigned), readShort(f, unsigned), readShort(f, unsigned)]
                        if face[0] + 1 > maxVert: maxVert = face[0] + 1
                        if face[1] + 1 > maxVert: maxVert = face[1] + 1
                        if face[2] + 1 > maxVert: maxVert = face[2] + 1

                        if maxVert <= len(vertArray):
                            append(faceArray, [face[0], face[2], face[1]])

                        else:
                            print("index over")
                            break

                if len(vertArray) > 0 and len(faceArray) > 0:
                    msh = mesh(vertices=vertArray, faces=faceArray, tverts=[tvertArray], mscale=mscale)

                break

            else:
                print("Unsupported Chunk [%i] @ %i\n" % (type, pos))

            fseek(f, pos + blen, seek_set)

        fclose(f)

    else:
        print("Failed to Open File")
    return None



clearListener()  # clears out console
if not useOpenDialog:

    deleteScene(['MESH', 'ARMATURE'])  # Clear Scene
    read(
        "C:\\Users\\Corey\\Desktop\\grimlock\\models\\trophy_africancup.xgm"
        )
    messageBox("Done!")
else:
    abt_xgm_imp(True)
# bpy.context.scene.unit_settings.system = 'METRIC'

# bpy.context.scene.unit_settings.scale_length = 1.001


Top
   
PostPosted: Tue Mar 09, 2021 3:56 pm 

Joined: Sat May 09, 2020 11:33 pm
Posts: 7
mariokart64n wrote:
blender python script, goto the script tab press new and paste the script. press the play button (Alt + P) and you can open a xgm and import it into blender. From that point the script is registered and you can access the import function through the File > Import context until blender is restarted.

Code:
""" ======================================================================

    PythonScript:   [Mobile] Angry Birds Transformers
    Author:         mariokart64n
    Date:           March 07, 2021
    Version:        0.1

    ======================================================================

    ChangeLog:

    2021-03-37
        Script Wrote
   

    ====================================================================== """

import bpy  # Needed to interface with blender
import struct  # Needed for Binary Reader
import math
from pathlib import Path  # Needed for os stuff

useOpenDialog = True

#
# ====================================================================================
# MAXCSRIPT FUNCTIONS
# ====================================================================================
# These function are written to mimic native functions in
# maxscript. This is to make porting my old maxscripts
# easier, so alot of these functions may be redundant..
# ====================================================================================
#

signed, unsigned = 0, 1  # Enums for read function
seek_set, seek_cur, seek_end = 0, 1, 2  # Enums for seek function

def messageBox(message="", title="Message Box", icon='INFO'):
    def draw(self, context): self.layout.label(text=message)

    bpy.context.window_manager.popup_menu(draw, title=title, icon=icon)
    return None

def getFileSize(filename):
    return Path(filename).stat().st_size

def clearListener(len=64):
    for i in range(0, len): print('')

def append(array, value):
    array.append(value)
    return None

class fopen:
    little_endian = True
    file = ""
    mode = 'rb'
    data = bytearray()
    size = 0
    pos = 0
    isGood = False

    def __init__(self, filename=None, mode='rb', isLittleEndian=True):
        if mode == 'rb':
            if filename != None and Path(filename).is_file():
                self.data = open(filename, mode).read()
                self.size = len(self.data)
                self.pos = 0
                self.mode = mode
                self.file = filename
                self.little_endian = isLittleEndian
                self.isGood = True
        else:
            self.file = filename
            self.mode = mode
            self.data = bytearray()
            self.pos = 0
            self.size = 0
            self.little_endian = isLittleEndian
            self.isGood = False

        return None

    # def __del__(self):
    #    self.flush()

    def resize(self, dataSize=0):
        if dataSize > 0:
            self.data = bytearray(dataSize)
        else:
            self.data = bytearray()
        self.pos = 0
        self.size = dataSize
        self.isGood = False
        return None

    def flush(self):
        print("flush")
        print("file:\t%s" % self.file)
        print("isGood:\t%s" % self.isGood)
        print("size:\t%s" % len(self.data))
        if self.file != "" and not self.isGood and len(self.data) > 0:
            self.isGood = True

            s = open(self.file, 'w+b')
            s.write(self.data)
            s.close()

    def read_and_unpack(self, unpack, size):
        '''
          Charactor, Byte-order
          @,         native, native
          =,         native, standard
          <,         little endian
          >,         big endian
          !,         network

          Format, C-type,         Python-type, Size[byte]
          c,      char,           byte,        1
          b,      signed char,    integer,     1
          B,      unsigned char,  integer,     1
          h,      short,          integer,     2
          H,      unsigned short, integer,     2
          i,      int,            integer,     4
          I,      unsigned int,   integer,     4
          f,      float,          float,       4
          d,      double,         float,       8
        '''
        value = 0
        if self.size > 0 and self.pos + size < self.size:
            value = struct.unpack_from(unpack, self.data, self.pos)[0]
            self.pos += size
        return value

    def pack_and_write(self, pack, size, value):
        if self.pos + size > self.size:
            self.data.extend(b'\x00' * ((self.pos + size) - self.size))
            self.size = self.pos + size
        try:
            struct.pack_into(pack, self.data, self.pos, value)
        except:
            print('Pos:\t%i / %i (buf:%i) [val:%i:%i:%s]' % (self.pos, self.size, len(self.data), value, size, pack))
            pass
        self.pos += size
        return None

    def set_pointer(self, offset):
        self.pos = offset
        return None


def fclose(bitStream):
    bitStream.flush()
    bitStream.isGood = False


def fseek(bitStream, offset, dir):
    if dir == 0:
        bitStream.set_pointer(offset)
    elif dir == 1:
        bitStream.set_pointer(bitStream.pos + offset)
    elif dir == 2:
        bitStream.set_pointer(bitStream.pos - offset)
    return None


def ftell(bitStream):
    return bitStream.pos


def readByte(bitStream, isSigned=0):
    fmt = 'b' if isSigned == 0 else 'B'
    return (bitStream.read_and_unpack(fmt, 1))


def readShort(bitStream, isSigned=0):
    fmt = '>' if not bitStream.little_endian else '<'
    fmt += 'h' if isSigned == 0 else 'H'
    return (bitStream.read_and_unpack(fmt, 2))


def readLong(bitStream, isSigned=0):
    fmt = '>' if not bitStream.little_endian else '<'
    fmt += 'i' if isSigned == 0 else 'I'
    return (bitStream.read_and_unpack(fmt, 4))


def readFloat(bitStream):
    fmt = '>f' if not bitStream.little_endian else '<f'
    return (bitStream.read_and_unpack(fmt, 4))


def readString(bitStream, length=0):
    string = ''
    pos = bitStream.pos
    lim = length if length != 0 else bitStream.size - bitStream.pos
    for i in range(0, lim):
        b = bitStream.read_and_unpack('B', 1)
        if b != 0:
            string += chr(b)
        else:
            if length > 0:
                bitStream.set_pointer(pos + length)
            break
    return string


def mesh(vertices=[], faces=[], materialIDs=[], tverts=[], normals=[], colours=[], materials=[], mscale=1.0, flipAxis=False, obj_name="Object", lay_name=''):
    #
    # This function is pretty, ugly
    # imports the mesh into blender
    #

    # Clear Any Object Selections
    # for o in bpy.context.selected_objects: o.select = False
    bpy.context.view_layer.objects.active = None

    # Get Collection (Layers)
    if lay_name != '':
        # make collection
        layer = bpy.data.collections.new(lay_name)
        bpy.context.scene.collection.children.link(layer)
    else:
        layer = bpy.data.collections[bpy.context.view_layer.active_layer_collection.name]

    # make mesh
    msh = bpy.data.meshes.new('Mesh')

    # msh.name = msh.name.replace(".", "_")

    # Apply vertex scaling
    # mscale *= bpy.context.scene.unit_settings.scale_length
    if len(vertices) > 0:
        vertArray = [[float] * 3] * len(vertices)
        if flipAxis:
            for v in range(0, len(vertices)):
                vertArray[v] = (
                    vertices[v][0] * mscale,
                    -vertices[v][2] * mscale,
                    vertices[v][1] * mscale
                )
        else:
            for v in range(0, len(vertices)):
                vertArray[v] = (
                    vertices[v][0] * mscale,
                    vertices[v][1] * mscale,
                    vertices[v][2] * mscale
                )

    # assign data from arrays
    msh.from_pydata(vertArray, [], faces)

    # set surface to smooth
    msh.polygons.foreach_set("use_smooth", [True] * len(msh.polygons))

    # Set Normals
    if len(faces) > 0:
        if len(normals) > 0:
            msh.use_auto_smooth = True
            if len(normals) == (len(faces) * 3):
                msh.normals_split_custom_set(normals)
            else:
                normArray = [[float] * 3] * (len(faces) * 3)
                if flipAxis:
                    for i in range(0, len(faces)):
                        for v in range(0, 3):
                            normArray[(i * 3) + v] = (
                                [normals[faces[i][v]][0],
                                 -normals[faces[i][v]][2],
                                 normals[faces[i][v]][1]]
                            )
                else:
                    for i in range(0, len(faces)):
                        for v in range(0, 3):
                            normArray[(i * 3) + v] = (
                                [normals[faces[i][v]][0],
                                 normals[faces[i][v]][1],
                                 normals[faces[i][v]][2]]
                            )
                msh.normals_split_custom_set(normArray)

        # create texture corrdinates
        print("tverts ", len(tverts))
        # this is just a hack, i just add all the UVs into the same space <<<
        if len(tverts) > 0:
            uvw = msh.uv_layers.new()
            # if len(tverts) == (len(faces) * 3):
            #    for v in range(0, len(faces) * 3):
            #        msh.uv_layers[uvw.name].data[v].uv = tverts[v]
            # else:
            uvwArray = [[float] * 2] * len(tverts[0])
            for i in range(0, len(tverts[0])):
                uvwArray[i] = [0.0, 0.0]

            for v in range(0, len(tverts[0])):
                for i in range(0, len(tverts)):
                    uvwArray[v][0] += tverts[i][v][0]
                    uvwArray[v][1] += 1.0 - tverts[i][v][1]

            for i in range(0, len(faces)):
                for v in range(0, 3):
                    msh.uv_layers[uvw.name].data[(i * 3) + v].uv = (
                        uvwArray[faces[i][v]][0],
                        uvwArray[faces[i][v]][1]
                    )

        # create vertex colours
        if len(colours) > 0:
            col = msh.vertex_colors.new()
            if len(colours) == (len(faces) * 3):
                for v in range(0, len(faces) * 3):
                    msh.vertex_colors[col.name].data[v].color = colours[v]
            else:
                colArray = [[float] * 4] * (len(faces) * 3)
                for i in range(0, len(faces)):
                    for v in range(0, 3):
                        msh.vertex_colors[col.name].data[(i * 3) + v].color = colours[faces[i][v]]


    # Create Face Maps?
    # msh.face_maps.new()

    # Update Mesh
    msh.update()

    # Check mesh is Valid
    if msh.validate():
        # Erase Mesh
        print("Mesh Invalid!")
        msh.user_clear()
        bpy.data.meshes.remove(msh)
        return None

    # Assign Mesh to Object
    obj = bpy.data.objects.new(obj_name, msh)
    # obj.name = obj.name.replace(".", "_")

    for i in range(0, len(materials)):

        if len(obj.material_slots) < (i + 1):
            # if there is no slot then we append to create the slot and assign
            obj.data.materials.append(materials[i])
        else:
            # we always want the material in slot[0]
            obj.material_slots[0].material = materials[i]
        # obj.active_material = obj.material_slots[i].material

    for i in range(0, len(materialIDs)):
        obj.data.polygons[i].material_index = materialIDs[i]

    # obj.data.materials.append(material)
    layer.objects.link(obj)

    # Generate a Material
    # img_name = "Test.jpg"  # dummy texture
    # mat_count = len(texmaps)

    # if mat_count == 0 and len(materialIDs) > 0:
    #    for i in range(0, len(materialIDs)):
    #        if (materialIDs[i] + 1) > mat_count: mat_count = materialIDs[i] + 1

    # Assign Material ID's
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.mode_set(mode='EDIT', toggle=False)
    bpy.context.tool_settings.mesh_select_mode = [False, False, True]

    bpy.ops.object.mode_set(mode='OBJECT')
    # materialIDs

    # Redraw Entire Scene
    # bpy.context.scene.update()

    return obj


# END OF MAXSCRIPT FUNCTIONS #########################################################


#
# ====================================================================================
# BLENDER API FUNCTIONS
# ====================================================================================
# These are functions or wrappers specific with dealing with blender's API
# ====================================================================================
#


def deleteScene(include=[]):
    if len(include) > 0:
        # Exit and Interactions
        if bpy.context.view_layer.objects.active != None:
            bpy.ops.object.mode_set(mode='OBJECT')

        # Select All
        bpy.ops.object.select_all(action='SELECT')

        # Loop Through Each Selection
        for o in bpy.context.view_layer.objects.selected:
            for t in include:
                if o.type == t:
                    bpy.data.objects.remove(o, do_unlink=True)
                    break

        # De-Select All
        bpy.ops.object.select_all(action='DESELECT')
    return None



# Callback when file(s) are selected
def abt_xgm_imp_callback(fpath="", files=[], clearScene=True, mscale = 1.0):
    if len(files) > 0 and clearScene: deleteScene(['MESH', 'ARMATURE'])
    for file in files:
        read(fpath + file.name, mscale)
    if len(files) > 0:
        messageBox("Done!")
        return True
    else:
        return False


# Wrapper that Invokes FileSelector to open files from blender
def abt_xgm_imp(reload=False):
    # Un-Register Operator
    if reload and hasattr(bpy.types, "IMPORTHELPER_OT_abt_xgm_imp"):  # print(bpy.ops.importhelper.abt_xgm_imp.idname())

        try:
            bpy.types.TOPBAR_MT_file_import.remove(
                bpy.types.Operator.bl_rna_get_subclass_py('IMPORTHELPER_OT_abt_xgm_imp').menu_func_import)
        except:
            print("Failed to Unregister2")

        try:
            bpy.utils.unregister_class(bpy.types.Operator.bl_rna_get_subclass_py('IMPORTHELPER_OT_abt_xgm_imp'))
        except:
            print("Failed to Unregister1")

    # Define Operator
    class ImportHelper_abt_xgm_imp(bpy.types.Operator):

        # Operator Path
        bl_idname = "importhelper.abt_xgm_imp"
        bl_label = "Select File"

        # Operator Properties
        # filter_glob: bpy.props.StringProperty(default='*.jpg;*.jpeg;*.png;*.tif;*.tiff;*.bmp', options={'HIDDEN'})
        filter_glob: bpy.props.StringProperty(default='*.xgm', options={'HIDDEN'}, subtype='FILE_PATH')

        # Variables
        filepath: bpy.props.StringProperty(subtype="FILE_PATH")  # full path of selected item (path+filename)
        filename: bpy.props.StringProperty(subtype="FILE_NAME")  # name of selected item
        directory: bpy.props.StringProperty(subtype="FILE_PATH")  # directory of the selected item
        files: bpy.props.CollectionProperty(type=bpy.types.OperatorFileListElement)  # a collection containing all the selected items as filenames

        # Controls
        my_float1: bpy.props.FloatProperty(name="Scale", default=1.0, description="Changes Scale of the imported Mesh")
        my_bool1: bpy.props.BoolProperty(name="Clear Scene", default=True, description="Deletes everything in the scene prior to importing")

        # Runs when this class OPENS
        def invoke(self, context, event):

            # Retrieve Settings
            try: self.filepath = bpy.types.Scene.abt_xgm_imp_filepath
            except: bpy.types.Scene.abt_xgm_imp_filepath = bpy.props.StringProperty(subtype="FILE_PATH")

            try: self.directory = bpy.types.Scene.abt_xgm_imp_directory
            except: bpy.types.Scene.abt_xgm_imp_directory = bpy.props.StringProperty(subtype="FILE_PATH")

            try: self.my_float1 = bpy.types.Scene.abt_xgm_imp_my_float1
            except: bpy.types.Scene.abt_xgm_imp_my_float1 = bpy.props.FloatProperty(default=1.0)

            try: self.my_bool1 = bpy.types.Scene.abt_xgm_imp_my_bool1
            except: bpy.types.Scene.abt_xgm_imp_my_bool1 = bpy.props.BoolProperty(default=False)


            # Open File Browser
            # Set Properties of the File Browser
            context.window_manager.fileselect_add(self)
            context.area.tag_redraw()

            return {'RUNNING_MODAL'}

        # Runs when this Window is CANCELLED
        def cancel(self, context): print("run *SPAM*")

        # Runs when the class EXITS
        def execute(self, context):

            # Save Settings
            bpy.types.Scene.abt_xgm_imp_filepath = self.filepath
            bpy.types.Scene.abt_xgm_imp_directory = self.directory
            bpy.types.Scene.abt_xgm_imp_my_float1 = self.my_float1
            bpy.types.Scene.abt_xgm_imp_my_bool1 = self.my_bool1

            # Run Callback
            abt_xgm_imp_callback(self.directory + "\\", self.files, self.my_bool1, self.my_float1)

            return {"FINISHED"}

            # Window Settings

        def draw(self, context):

            self.layout.row().label(text="Import Settings")

            self.layout.separator()
            self.layout.row().prop(self, "my_bool1")
            self.layout.row().prop(self, "my_float1")

            self.layout.separator()

            col = self.layout.row()
            col.alignment = 'RIGHT'
            col.label(text="  Author:", icon='QUESTION')
            col.alignment = 'LEFT'
            col.label(text="mariokart64n")

            col = self.layout.row()
            col.alignment = 'RIGHT'
            col.label(text="Release:", icon='GRIP')
            col.alignment = 'LEFT'
            col.label(text="March 07, 2021")

        def menu_func_import(self, context):
            self.layout.operator("importhelper.abt_xgm_imp", text="Angrybirds Transformers (*.xgm)")

    # Register Operator
    bpy.utils.register_class(ImportHelper_abt_xgm_imp)
    bpy.types.TOPBAR_MT_file_import.append(ImportHelper_abt_xgm_imp.menu_func_import)

    # Call ImportHelper
    bpy.ops.importhelper.abt_xgm_imp('INVOKE_DEFAULT')


# END OF BLENDER FUNCTIONS ###########################################################


#
# ====================================================================================
# MAIN CODE
# ====================================================================================
# And the actual program... honesty I should have split the code into modules <_<
# ====================================================================================
#


def read(file="", mscale = 1.0):
    f = fopen(file, "rb")
    if f.isGood:

        fsize = getFileSize(file)
        type = 0
        info = 0
        blen = 0
        pos = 0
        mshName = "Mesh"
        version = 0
        vertBufAddr = 0
        faceBufAddr = 0
        faceBufAddr2 = 0
        vertBufSize = 0
        faceBufSize = 0
        vertBufStride = 24
        faceBufStride = 2
        vertCount = 0
        faceCount = 0
        vertArray = []
        tvertArray = []
        faceArray = []
        msh = None
        face = [1, 1, 1]
        maxVert = 0
        addrs = []

        while ftell(f) < fsize:
            pos = ftell(f)
            type = readShort(f, unsigned)
            info = readShort(f, unsigned)
            blen = readLong(f, unsigned)
            if type == 0x15:
                fseek(f, 4, seek_cur)
                version = readByte(f, unsigned)

            elif type == 0x2D:
                fseek(f, 2, seek_cur)
                mshName = readString(f)
                print("mshName:\t%s" % mshName)

            elif type == 0x11:
                if version == 0x24:
                    fseek(f, 0x14, seek_cur)
                    addrs = []
                    for i in range(0, 10):
                        addrs.append(readLong(f, unsigned))
                    addrs.append(blen)
                    vertBufAddr = addrs[0]
                    normBuffAddr = addrs[1]
                    faceBufAddr = addrs[2]
                    tvertBufAddr = addrs[4]

                    print("vertBufAddr:\t%i" % vertBufAddr)
                    print("faceBufAddr:\t%i" % faceBufAddr)

                    addrs.sort()

                    vertCount = 0
                    for i in range(10, -1, -1):
                        if addrs[i] == vertBufAddr:
                            vertCount = int((addrs[i + 1] - vertBufAddr) / 12)
                            print("vertCount:\t%i" % vertCount)
                            break

                    if vertCount > 0:
                        fseek(f, pos + vertBufAddr, seek_set)
                        vertArray = [[float] * 3] * vertCount
                        tvertArray = [[float] * 3] * vertCount
                        for i in range(0, vertCount):
                            vertArray[i] = [readFloat(f), readFloat(f), readFloat(f)]

                        fseek(f, pos + tvertBufAddr, seek_set)
                        for i in range(0, vertCount):
                            tvertArray[i] = [readFloat(f), readFloat(f), 0.0]

                    faceCount = 0
                    for i in range(len(addrs) - 1, -1, -1):
                        if addrs[i] == faceBufAddr:
                            faceCount = int((addrs[i + 1] - faceBufAddr) / 2 / 3)
                            print("faceCount:\t%i" % faceCount)
                            break

                    if faceCount > 0:
                        maxVert = 0
                        fseek(f, pos + faceBufAddr, seek_set)
                        for i in range(0, faceCount):
                            face = [readShort(f, unsigned), readShort(f, unsigned), readShort(f, unsigned)]
                            if face[0] + 1 > maxVert: maxVert = face[0] + 1
                            if face[1] + 1 > maxVert: maxVert = face[1] + 1
                            if face[2] + 1 > maxVert: maxVert = face[2] + 1

                            if maxVert <= len(vertArray):
                                append(faceArray, face)

                            else:
                                print("index over")
                                break

                        print("maxVert:\t%i" % maxVert)

                    print(ftell(f))
                    if len(vertArray) > 0:
                        msh = mesh(vertices=vertArray, faces=faceArray, tverts=[tvertArray], mscale=mscale)

                    break


            elif type == 0x31:
                fseek(f, 0x78, seek_cur)
                vertBufAddr = readLong(f, unsigned)
                fseek(f, 0x04, seek_cur)
                faceBufAddr = readLong(f, unsigned)
                fseek(f, 0x34, seek_cur)
                vertBufSize = readLong(f, unsigned)
                faceBufSize = readLong(f, unsigned)

                vertCount = int(vertBufSize / vertBufStride)
                print("vertCount:\t%i" % vertCount)
                if vertCount > 0:
                    vertArray = [[float] * 3] * vertCount
                    tvertArray = [[float] * 3] * vertCount
                    fseek(f, pos + vertBufAddr, seek_set)
                    for i in range(0, vertCount):
                        vertArray[i] = [readFloat(f), readFloat(f), readFloat(f)]
                        fseek(f, 4, seek_cur)  # Normal
                        fseek(f, 4, seek_cur)  # Vertex Colour
                        tvertArray[i] = [readShort(f, signed) / 32767.0 + 0.5, readShort(f, signed) / 32767.0 + 0.5, 0.0]
                        tvertArray[i] = [1.0 - vertArray[i][1], vertArray[i][2], 0.0]

                faceCount = int(faceBufSize / faceBufStride / 3)
                if faceCount > 0:
                    maxVert = 0
                    fseek(f, pos + faceBufAddr, seek_set)

                    for i in range(0, faceCount):
                        face = [readShort(f, unsigned), readShort(f, unsigned), readShort(f, unsigned)]
                        if face[0] + 1 > maxVert: maxVert = face[0] + 1
                        if face[1] + 1 > maxVert: maxVert = face[1] + 1
                        if face[2] + 1 > maxVert: maxVert = face[2] + 1

                        if maxVert <= len(vertArray):
                            append(faceArray, [face[0], face[2], face[1]])

                        else:
                            print("index over")
                            break

                if len(vertArray) > 0 and len(faceArray) > 0:
                    msh = mesh(vertices=vertArray, faces=faceArray, tverts=[tvertArray], mscale=mscale)

                break

            else:
                print("Unsupported Chunk [%i] @ %i\n" % (type, pos))

            fseek(f, pos + blen, seek_set)

        fclose(f)

    else:
        print("Failed to Open File")
    return None



clearListener()  # clears out console
if not useOpenDialog:

    deleteScene(['MESH', 'ARMATURE'])  # Clear Scene
    read(
        "C:\\Users\\Corey\\Desktop\\grimlock\\models\\trophy_africancup.xgm"
        )
    messageBox("Done!")
else:
    abt_xgm_imp(True)
# bpy.context.scene.unit_settings.system = 'METRIC'

# bpy.context.scene.unit_settings.scale_length = 1.001

Men, thanks for this but, How to Export?


Top
   
PostPosted: Wed Mar 10, 2021 4:22 am 

Joined: Tue Jul 24, 2018 8:52 am
Posts: 501
Noesis XGM importer
https://drive.google.com/file/d/1-YKRJW ... sp=sharing


Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 17 posts ] 

All times are UTC


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Limited