[MESH!!!] Blender exporter for UE1 almost complete

Discussions about Coding and Scripting

[MESH!!!] Blender exporter for UE1 almost complete

Postby Gustavo6046 » Fri Apr 22, 2016 1:01 am




It ALMOST works! :D Time for debugging?

Script in Blender:
Code: Select all
from struct import pack
import bpy

class NotTrianglePolygonError(Exception):

if __name__ == "__main__":
    mesh = bpy.context.object

    print("Got context and selected object! Checking for triangulated polygons...")

    for poly in mesh.data.polygons:
        if len(poly.vertices) != 3:
            raise NotTrianglePolygonError("The polygon {} is not a triangle!".format(repr(poly)))

    print("All polygons are triangulated! Writing to aniv file...")

    with open("C:\\Users\\gusta_000.ACER\\Documents\\UnrealTournament\\BlenderModels\\current_a.3d", "ab") as Aniv:

        Aniv.write(pack("HL", bpy.context.scene.frame_end - bpy.context.scene.frame_start, len(mesh.data.vertices) * 4))

        print("Aniv file header written!")

        bpy.context.scene.frame_current = bpy.context.scene.frame_start
        while bpy.context.scene.frame_current <= bpy.context.scene.frame_end:
            vertices = mesh.data.vertices
            for v in vertices:
                Aniv.write(pack("L", (int(v.co.x * 8.0) & 0x7ff) | ((int(v.co.y * 8.0) & 0x7ff) << 11) | ((int(v.co.z * 4.0) & 0x3ff) << 22 )))
            bpy.context.scene.frame_current += 1

    print("Aniv file written! Writing to data file...")
    with open("C:\\Users\\gusta_000.ACER\\Documents\\UnrealTournament\\BlenderModels\\current_d.3d", "ab") as Data_File:
        Data_File.write(pack("4H7L12B", len(mesh.data.polygons), len(mesh.data.vertices), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
        print("Data file header written!")

        for poly in mesh.data.polygons:
            Data_File.write(pack("3H2b", poly.vertices[0], poly.vertices[1], poly.vertices[2], 1, 0))
            uvs = []
            for x in poly.vertices:
                uvs.append(int(mesh.data.uv_layers.active.data[x].uv[0] * 255))
                uvs.append(int(mesh.data.uv_layers.active.data[x].uv[1] * 255))
            Data_File.write(pack("6B", *uvs))
            Data_File.write(pack("2b", 1, 0))

    print("Data file written! Succesful!")

All that I need to improve is one weird vertex and the UV coordinate system, but other than that.. YEA! LET'S ROCK! REVOLUTION IN 1999 INDUSTRY! :rock:

Ok, Jukebox... DUKE3D

Why did nobody did this before? :noidea

EDIT: ops, wrong forum :P
Last edited by Gustavo6046 on Fri Sep 09, 2016 11:44 pm, edited 2 times in total.
User avatar
Posts: 773
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Finite


Postby FXANBSS » Fri Apr 22, 2016 2:19 am

Everyone did this, but nobody told you.
User avatar
Posts: 228
Joined: Thu Dec 26, 2013 7:03 pm


Postby Gustavo6046 » Fri Apr 22, 2016 8:31 pm

FXANBSS wrote:Everyone did this, but nobody told you.

Yeah, I always wondered how did they make NW3 meshes. It was awesome!
BTW, do you think my exporter is getting close?
User avatar
Posts: 773
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Finite

Re: Blender exporter for UE1 almost complete

Postby Gustavo6046 » Fri Sep 09, 2016 9:15 pm

Bump because update and because I don't know why the heck isn't this working.
The structs for the data exported are all correct according to the Paul Borke's Unreal Mesh File Format Specification (shorten it please :lol: ), and I can't identify the actual problem. Now the meshes seems to have some problems with vertex distortion (despite being better now) and the vertices don't get out of some cubic area. So if someone experienced with those could help... :(
Code: Select all
from struct import pack, calcsize
from time import strftime
from shutil import rmtree
import os
import bpy
import bpy_extras

bl_info = {
   "name"         : "Export to Unreal Mesh (_a.3d, _d.3d)",
   "category"      : "Import-Export",
   "description"    : "Exports a mesh to Unreal Engine 1 (vertex-animation) format.",
   "version"       : (0, 2),
   "blender"       : (2, 7, 7),
   "location"      : "Operator",
   "warning"       : "This is a test addon and it is known to export meshes with a mess of polygons. Use on your own discretion or to export the class file with the #exec directives.",
   "support"       : "TESTING",

def log(file_, logging, print_it=False):
   if print_it:
      print("[{}] {}".format(strftime("%I:%M:%S"), logging))

   return file_.write("[{}] {}\n".format(strftime("%I:%M:%S"), logging))

class UnrealMeshException(BaseException):

class NotTrianglePolygonError(UnrealMeshException):

class NoUVError(UnrealMeshException):
def ensure_dir(dirpath):
   if not os.path.isdir(dirpath):
   print("Dir ensured: " + dirpath)
def unreal_vertex(coord):
   return int( int(coord[0] * 8.0) & int("0x7ff", 16) | ( ( int(coord[1] * 8.0) & int("0x7ff", 16) ) << 11 ) | ( ( int(coord[2] * 4.0) & int("0x3ff", 16) ) << 22 ))
class UnrealMeshExport(bpy.types.Operator):
   bl_idname = "io.ue1_mesh"
   bl_label = "Export to Unreal format (_a.3d, _d.3d)"

   scale = bpy.props.FloatProperty(name="Scale", default=16, min=1, max=8192, description="Scale, in Blender Units -> Unreal Units metrics.")
   package_name = bpy.props.StringProperty(name="Package Name", default="MyPackage", description="The name of the package to contain the mesh and the actor.")
   unreal_path = bpy.props.StringProperty(name="Unreal|UT Path", description="The path to your Unreal Engine 1 game (without a backslash in the end!).", subtype="DIR_PATH", default="C:\\UnrealTournament")
   mesh_name = bpy.props.StringProperty(name="Mesh Name", description="Name of the mesh to export")
   class_name = bpy.props.StringProperty(name="Class Name", description="Name of the Unreal class to export (and therefore of the UnrealScript file).")

   def execute(self, context):
      unreal_path = self.unreal_path
      package_name = self.package_name
      ensure_dir(unreal_path + "\\{}\\".format(package_name))
      ensure_dir(unreal_path + "\\{}\\Models\\".format(package_name))
      ensure_dir(unreal_path + "\\{}\\Help\\".format(package_name))
      ensure_dir(unreal_path + "\\{}\\Skins\\".format(package_name))
      ensure_dir(unreal_path + "\\{}\\Classes\\".format(package_name))
      with open(unreal_path + "\\{}\\Help\\log.txt".format(package_name), "w") as log_file:
         log(log_file, "Getting selected object and triangulating mesh.", True)
         mesh = context.object

         with open(unreal_path + "\\{}\\Models\\{}_a.3d".format(package_name, self.mesh_name), "wb") as Aniv:
            Aniv.write(pack("=I", bpy.context.scene.frame_end - bpy.context.scene.frame_start))
            Aniv.write(pack("=L", len(mesh.data.vertices) * calcsize("L")))
            log(log_file, "Aniv file header written!", True)

            old_frame = bpy.context.scene.frame_current

            while bpy.context.scene.frame_current <= bpy.context.scene.frame_end:
               log(log_file, u"frame {} (".format(bpy.context.scene.frame_current))
               for i, v in enumerate(mesh.data.vertices):
                  coord = [x * self.scale for x in v.co]
                  log(log_file, u"   vertex {} coord=({},{},{}) -> {}".format(i, coord[0], coord[1], coord[2], unreal_vertex(coord)))
                  Aniv.write(pack("=L", unreal_vertex(coord)))
               log(log_file, ")")
               bpy.context.scene.frame_set(bpy.context.scene.frame_current + 1)

         log(log_file, "Aniv file written! Writing to data file...", True)
         with open(unreal_path + "\\{}\\Models\\{}_d.3d".format(package_name, self.mesh_name), "wb") as Data_File:
            Data_File.write(pack("4H7L12B", len(mesh.data.polygons), len(mesh.data.vertices), *([0] * 21)))
            log(log_file, "Data file header written!", True)

            for i, poly in enumerate(mesh.data.polygons):
               uvs = []
               for x in poly.vertices:
                     uvs.append(int(mesh.data.uv_layers.active.data[x].uv[0] * 255))
                     uvs.append(int(mesh.data.uv_layers.active.data[x].uv[1] * 255))
                  except AttributeError:
                     raise NoUVError("Mesh has no UV coordinates!")   
               log(log_file, "poly {} vertexes {} {} {}".format(i, *poly.vertices))
               Data_File.write(pack("3H2b6B2b", poly.vertices[0], poly.vertices[1], poly.vertices[2], 1, 0, *uvs, 1, 0))
         log(log_file, "Data file written! Writing class file...", True)
         with open(unreal_path + "\\{}\\Classes\\{}.uc".format(package_name, self.class_name), "w") as Class_File:
            Class_File.write("#exec MESH IMPORT MESH={0} ANIVFILE=Models\{0}_a.3d DATAFILE=Models\{0}_d.3d X=0 Y=0 Z=0\n".format(self.mesh_name))
            Class_File.write("#exec MESH ORIGIN MESH={} X=0 Y=0 Z=0 ROLL=0\n\n".format(self.mesh_name))

            Class_File.write("#exec MESH SEQUENCE MESH={} SEQ=All     STARTFRAME=0  NUMFRAMES={}\n".format(self.mesh_name, bpy.context.scene.frame_end - bpy.context.scene.frame_start))
            Class_File.write("#exec MESH SEQUENCE MESH={} SEQ=Still  STARTFRAME=0  NUMFRAMES=1\n\n".format(self.mesh_name))

            Class_File.write("#exec TEXTURE IMPORT NAME=J{0} FILE=Skins\{0}skin.bmp GROUP=\"Skins\"\n\n".format(self.mesh_name))

            Class_File.write("#exec MESHMAP SCALE MESHMAP={} X=1 Y=1 Z=1\n".format(self.mesh_name))
            Class_File.write("#exec MESHMAP SETTEXTURE MESHMAP={0} NUM=1 TEXTURE=J{0}\n\n".format(self.mesh_name))

            Class_File.write("class {} extends Decoration;\n".format(self.class_name))
         log(log_file, "Class file written! Operation succesfull! Now all that remains is adding 256-bit skin, adding to editpackages and compiling in UCC!", True)
         return {'FINISHED'}
   def invoke(self, context, event):
      wm = context.window_manager
      return wm.invoke_props_dialog(self)

def register():

def unregister():
if __name__ == "__main__":

Also, I have never heard of Higorian formulas?
User avatar
Posts: 773
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Finite

Re: [MESH!!!] Blender exporter for UE1 almost complete

Postby Gustavo6046 » Thu Sep 29, 2016 6:03 pm

I am starting to lose my hope. It seems that not even in C++ my converter will ever be able to work! >.<

I need to know why, after many and many attempts, not even the DISTORTION itself changes! It's as if all the methods I use result in the same freaking distorted model. I'm starting to blame 64-bit. So last attempt: using static stdint.

EDIT 1: Nope. It won't work. And I can't figure out what it is. I though it was 64-bit crap, but <stdint.h> won't work either... >.<
User avatar
Posts: 773
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Finite

Return to Coding, Scripting

Who is online

Users browsing this forum: No registered users and 3 guests