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

Discussions about Coding and Scripting
Post Reply
User avatar
Gustavo6046
Godlike
Posts: 1462
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Resident Wallaby
Location: Porto Alegre, Brazil
Contact:

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

Post by Gustavo6046 »

look:

Blender:
Image

UnrealEd:
Image

It ALMOST works! :D Time for debugging?

Script in Blender:

Code: Select all

from struct import pack
import bpy

class NotTrianglePolygonError(Exception):
    pass

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.
"Everyone is an idea man. Everybody thinks they have a revolutionary new game concept that no one else has ever thought of. Having cool ideas will rarely get you anywhere in the games industry. You have to be able to implement your ideas or provide some useful skill. Never join a project whose idea man or leader has no obvious development skills. Never join a project that only has a web designer. You have your own ideas. Focus on them carefully and in small chunks and you will be able to develop cool projects."

Weapon of Destruction
User avatar
FXANBSS
Skilled
Posts: 231
Joined: Thu Dec 26, 2013 7:03 pm

Re: BLENDER EXPORTER WORKS!!!! BIG TIME FOR UE1

Post by FXANBSS »

Everyone did this, but nobody told you.
User avatar
Gustavo6046
Godlike
Posts: 1462
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Resident Wallaby
Location: Porto Alegre, Brazil
Contact:

Re: BLENDER EXPORTER WORKS!!!! BIG TIME FOR UE1

Post by Gustavo6046 »

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?
"Everyone is an idea man. Everybody thinks they have a revolutionary new game concept that no one else has ever thought of. Having cool ideas will rarely get you anywhere in the games industry. You have to be able to implement your ideas or provide some useful skill. Never join a project whose idea man or leader has no obvious development skills. Never join a project that only has a web designer. You have your own ideas. Focus on them carefully and in small chunks and you will be able to develop cool projects."

Weapon of Destruction
User avatar
Gustavo6046
Godlike
Posts: 1462
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Resident Wallaby
Location: Porto Alegre, Brazil
Contact:

Re: Blender exporter for UE1 almost complete

Post by Gustavo6046 »

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):
	pass

class NotTrianglePolygonError(UnrealMeshException):
	pass

class NoUVError(UnrealMeshException):
	pass
		
def ensure_dir(dirpath):
	if not os.path.isdir(dirpath):
		os.makedirs(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
		
		print(self.package_name)
		print(self.unreal_path)
		
		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

				bpy.context.scene.frame_set(bpy.context.scene.frame_start)
				
				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)
				 
				bpy.context.scene.frame_set(old_frame)

			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:
						try:
							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)
				
			log_file.close()
			
			return {'FINISHED'}
		
	def invoke(self, context, event):
		wm = context.window_manager
		return wm.invoke_props_dialog(self)

def register():
	bpy.utils.register_class(UnrealMeshExport)

def unregister():
	bpy.utils.unregister_class(UnrealMeshExport)
	
if __name__ == "__main__":
	register()
Also, I have never heard of Higorian formulas?
"Everyone is an idea man. Everybody thinks they have a revolutionary new game concept that no one else has ever thought of. Having cool ideas will rarely get you anywhere in the games industry. You have to be able to implement your ideas or provide some useful skill. Never join a project whose idea man or leader has no obvious development skills. Never join a project that only has a web designer. You have your own ideas. Focus on them carefully and in small chunks and you will be able to develop cool projects."

Weapon of Destruction
User avatar
Gustavo6046
Godlike
Posts: 1462
Joined: Mon Jun 01, 2015 7:08 pm
Personal rank: Resident Wallaby
Location: Porto Alegre, Brazil
Contact:

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

Post by Gustavo6046 »

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... >.<
"Everyone is an idea man. Everybody thinks they have a revolutionary new game concept that no one else has ever thought of. Having cool ideas will rarely get you anywhere in the games industry. You have to be able to implement your ideas or provide some useful skill. Never join a project whose idea man or leader has no obvious development skills. Never join a project that only has a web designer. You have your own ideas. Focus on them carefully and in small chunks and you will be able to develop cool projects."

Weapon of Destruction
Post Reply