blender_io_export_psx_mesh/io_export_psx_tmesh.py

1949 lines
69 KiB
Python
Raw Normal View History

2021-03-01 20:05:38 +01:00
# bpy. app. debug = True
bl_info = {
"name": "PSX TMesh exporter",
"author": "Schnappy, TheDukeOfZill",
"blender": (2,7,9),
2021-03-22 20:26:41 +01:00
"version": (0,0,3),
"location": "File > Import-Export",
"description": "Export psx data format",
"category": "Import-Export"
}
2021-03-01 20:05:38 +01:00
import os
2021-03-12 13:06:21 +01:00
import bpy
2021-03-12 13:06:21 +01:00
2021-03-12 11:21:18 +01:00
import bmesh
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
import unicodedata
2021-03-12 13:06:21 +01:00
2021-04-02 12:41:32 +02:00
import subprocess
2021-03-31 20:28:02 +02:00
from math import radians, degrees, floor, cos, sin, sqrt
2021-03-12 13:06:21 +01:00
2021-03-12 11:21:18 +01:00
from mathutils import Vector
2021-02-19 18:00:42 +01:00
2021-03-12 13:06:21 +01:00
from collections import defaultdict
2021-02-19 18:00:42 +01:00
from bpy.props import (CollectionProperty,
StringProperty,
BoolProperty,
EnumProperty,
FloatProperty
)
from bpy_extras.io_utils import (ExportHelper,
2021-03-24 11:33:09 +01:00
axis_conversion)
from bpy_extras.object_utils import world_to_camera_view
2021-04-02 12:41:32 +02:00
from PIL import Image
class ExportMyFormat(bpy.types.Operator, ExportHelper):
2021-03-12 13:06:21 +01:00
bl_idname = "export_psx.c";
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
bl_label = "PSX compatible scene exporter";
2021-03-12 13:06:21 +01:00
bl_options = {'PRESET'};
2021-03-12 13:06:21 +01:00
filename_ext = ".c";
2021-02-19 18:00:42 +01:00
exp_Triangulate = BoolProperty(
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
name="Triangulate meshes ( Destructive ! )",
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
description="Triangulate meshes (destructive ! Do not use your original file)",
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
default=False,
)
exp_Scale = FloatProperty(
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
name="Scale",
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
description="Scale of exported mesh.",
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
min=1, max=1000,
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
default=65,
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
)
2021-03-01 20:05:38 +01:00
exp_Precalc = BoolProperty(
2021-03-12 13:06:21 +01:00
2021-03-01 20:05:38 +01:00
name="Use precalculated BGs",
2021-03-12 13:06:21 +01:00
2021-04-02 12:41:32 +02:00
description="Render backgrounds and converts them to TIMs",
2021-03-12 13:06:21 +01:00
2021-03-01 20:05:38 +01:00
default=False,
)
2021-04-02 12:41:32 +02:00
# ~ exp_ShowPortals = BoolProperty(
# ~ name="Render Portals in precalculated BGs",
# ~ description="Useful for debugging",
# ~ default=False,
# ~ )
def execute(self, context):
2021-03-12 11:21:18 +01:00
2021-03-12 13:06:21 +01:00
def triangulate_object(obj):
# Triangulate an object's mesh
# Source : https://blender.stackexchange.com/questions/45698/triangulate-mesh-in-python/45722#45722
2020-12-30 22:09:12 +01:00
me = obj.data
2021-03-12 13:06:21 +01:00
2020-12-30 22:09:12 +01:00
# Get a BMesh representation
bm = bmesh.new()
2021-03-12 13:06:21 +01:00
2020-12-30 22:09:12 +01:00
bm.from_mesh(me)
2021-03-12 13:06:21 +01:00
2020-12-30 22:09:12 +01:00
bmesh.ops.triangulate(bm, faces=bm.faces[:], quad_method=0, ngon_method=0)
2021-03-12 13:06:21 +01:00
2020-12-30 22:09:12 +01:00
# Finish up, write the bmesh back to the mesh
bm.to_mesh(me)
2021-03-12 13:06:21 +01:00
2020-12-30 22:09:12 +01:00
bm.free()
2021-02-19 18:00:42 +01:00
def CleanName(strName):
2021-03-12 13:06:21 +01:00
# Removes specials characters, dots ans space from string
2021-02-19 18:00:42 +01:00
name = strName.replace(' ','_')
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
name = name.replace('.','_')
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
name = unicodedata.normalize('NFKD',name).encode('ASCII', 'ignore').decode()
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
return name
2021-03-12 12:13:08 +01:00
2021-03-31 20:28:02 +02:00
def isInFrame(scene, cam, target):
position = world_to_camera_view(scene, cam, target.location)
if (
(position.x < 0 or position.x > 1 ) or
(position.y < 0 or position.y > 1 ) or
(position.z < 0 )
) :
return False
else:
return True
2021-03-12 13:06:21 +01:00
def isInPlane(plane, obj):
2021-03-12 13:06:21 +01:00
# Checks if 'obj' has its coordinates contained between the plane's coordinate.
# If 'obj' is contained, returns 1.
# If 'obj' is partly contained, returns which side (S == 2, W == 4, N == 8, E == 6) it's overlapping.
2021-03-12 13:06:21 +01:00
# If 'obj' is not contained in 'plane', returns 0.
if (
(plane.get('x1') <= obj.get('x1') and plane.get('x2') >= obj.get('x2') ) and
(plane.get('y1') <= obj.get('y1') and plane.get('y2') >= obj.get('y2') )
2021-03-12 13:06:21 +01:00
):
return 1
# Overlap on the West side of the plane
if (
( plane.get('x1') >= obj.get('x1') and plane.get('x1') <= obj.get('x2') ) and
( plane.get('y1') <= obj.get('y2') and plane.get('y2') >= obj.get('y1') )
2021-03-12 13:06:21 +01:00
):
return 4
# Overlap on the East side of the plane
if (
( plane.get('x2') <= obj.get('x2') and plane.get('x2') >= obj.get('x1') ) and
( plane.get('y1') <= obj.get('y2') and plane.get('y2') >= obj.get('y1') )
2021-03-12 13:06:21 +01:00
):
return 6
# Overlap on the North side of the plane
if (
( plane.get('y2') <= obj.get('y2') and plane.get('y2') >= obj.get('y1') ) and
( plane.get('x1') <= obj.get('x1') and plane.get('x2') >= obj.get('x2') )
2021-03-12 13:06:21 +01:00
):
return 8
# Overlap on the South side of the plane
if (
( plane.get('y1') >= obj.get('y1') and plane.get('y1') <= obj.get('y2') ) and
( plane.get('x1') <= obj.get('x1') and plane.get('x2') >= obj.get('x2') )
2021-03-12 13:06:21 +01:00
):
return 2
else:
return 0
def getSepLine(plane, side):
# Construct the line used for BSP generation from 'plane' 's coordinates, on specified side (S, W, N, E)
# Returns an array of 3 values
if side == 'N':
return [ LvlPlanes[plane]['x1'], LvlPlanes[plane]['y2'], LvlPlanes[plane]['x2'], LvlPlanes[plane]['y2'] ]
if side == 'S':
return [ LvlPlanes[plane]['x1'], LvlPlanes[plane]['y1'], LvlPlanes[plane]['x2'], LvlPlanes[plane]['y1'] ]
2021-03-12 13:06:21 +01:00
if side == 'W':
return [ LvlPlanes[plane]['x1'], LvlPlanes[plane]['y1'], LvlPlanes[plane]['x1'], LvlPlanes[plane]['y2'] ]
if side == 'E':
return [ LvlPlanes[plane]['x2'], LvlPlanes[plane]['y1'], LvlPlanes[plane]['x2'], LvlPlanes[plane]['y2'] ]
def checkLine(lineX1, lineY1 ,lineX2 ,lineY2, objX1, objY1, objX2, objY2):
# Returns wether object spanning from objXY1 to objXY2 is Back, Front, Same or Intersecting the line
# defined by points (lineXY1, lineXY2)
val1 = ( objX1 - lineX1 ) * ( lineY2-lineY1 ) - ( objY1 - lineY1 ) * ( lineX2 - lineX1 )
# rounding to avoid false positives
val1 = round(val1, 4)
val2 = ( objX2 - lineX1 ) * ( lineY2-lineY1 ) - ( objY2 - lineY1 ) * ( lineX2 - lineX1 )
val2 = round(val2, 4)
if ( (val1 > 0) and (val2 > 0) ):
return "front"
elif ( (val1 < 0) and (val2 < 0) ):
return "back"
elif ( (val1 == 0) and (val2 == 0) ):
2021-03-15 12:44:15 +01:00
return "connected"
2021-03-12 13:06:21 +01:00
elif (
( (val1>0) and (val2==0) ) or
( (val1==0) and (val2>0) )
):
return "front"
elif (
( (val1<0) and (val2==0) ) or
( (val1==0) and (val2<0) )
):
return "back"
elif (
( (val1<0) and (val2>0) ) or
( (val1>0) and (val2<0) )
):
return "intersect"
2021-04-02 12:41:32 +02:00
def objVertLtoW(target):
worldPos = []
mw = target.matrix_world
mesh = bpy.data.meshes[ target.name ]
for vertex in mesh.vertices:
worldPos.append( mw * vertex.co * scale )
return worldPos
2021-03-31 20:28:02 +02:00
def objVertWtoS(scene, cam, target, toScale = 1):
screenPos = []
# Get objects world matrix
mw = target.matrix_world
# Get object's mesh
mesh = bpy.data.meshes[ target.name ]
# For each vertex in mesh, get screen coordinates
for vertex in mesh.vertices:
# Get meshes world coordinates
screenPos.append( world_to_camera_view( scene, cam, ( mw * vertex.co ) ) )
if toScale:
# Get current scene rsolution
resX = scene.render.resolution_x
resY = scene.render.resolution_y
# Scale values
for vector in screenPos:
# ~ vector.x = int( resX * vector.x ) < 0 ? 0 : int( resX * vector.x ) > 320 ? 320 : int( resX * vector.x )
vector.x = max ( 0, min ( resX, int( resX * vector.x ) ) )
2021-04-02 12:41:32 +02:00
vector.y = resY - max ( 0, min ( resY, int( resY * vector.y ) ) )
2021-03-31 20:28:02 +02:00
vector.z = int( vector.z )
return screenPos
# Leave edit mode to avoid errors
2021-03-12 13:06:21 +01:00
2020-12-29 15:53:47 +01:00
bpy.ops.object.mode_set(mode='OBJECT')
2020-12-30 22:09:12 +01:00
2021-03-12 13:06:21 +01:00
# If set, triangulate objects of type mesh
2021-02-19 18:00:42 +01:00
if self.exp_Triangulate:
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
for o in range(len(bpy.data.objects)):
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
if bpy.data.objects[o].type == 'MESH':
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
triangulate_object(bpy.data.objects[o])
2021-03-12 13:06:21 +01:00
# Set Scale
2021-02-19 18:00:42 +01:00
scale = self.exp_Scale
2020-12-30 22:09:12 +01:00
2021-03-12 13:06:21 +01:00
# Get working directory path
2021-03-01 20:05:38 +01:00
filepath = bpy.data.filepath
2021-03-12 13:06:21 +01:00
2021-03-01 20:05:38 +01:00
folder = os.path.dirname(bpy.path.abspath(filepath))
2021-03-12 13:06:21 +01:00
2021-03-01 20:05:38 +01:00
dirpath = os.path.join(folder, "TIM")
2021-03-24 11:33:09 +01:00
### Export pre-calculated backgrounds and construct a list of visible objects for each camera angle
2021-03-12 13:06:21 +01:00
2021-03-01 20:05:38 +01:00
camAngles = []
2021-03-12 13:06:21 +01:00
2021-03-12 11:21:18 +01:00
defaultCam = 'NULL'
2021-03-24 11:33:09 +01:00
# List of Rigid/Static bodies to ray a cast upon
rayTargets = []
2021-03-12 13:06:21 +01:00
# If using precalculated BG, render and export them to ./TIM/
2021-03-01 20:05:38 +01:00
if self.exp_Precalc:
2021-04-02 12:41:32 +02:00
2021-03-12 13:06:21 +01:00
# Create folder if it doesn't exist
2021-03-01 20:05:38 +01:00
os.makedirs(dirpath, exist_ok = 1)
2021-03-12 13:06:21 +01:00
# Set file format config
2021-03-01 20:05:38 +01:00
bpy.context.scene.render.image_settings.file_format = 'PNG'
bpy.context.scene.render.image_settings.quality = 100
bpy.context.scene.render.image_settings.compression = 0
bpy.context.scene.render.image_settings.color_depth = '8'
2021-03-12 13:06:21 +01:00
# Get active cam
2021-03-24 11:33:09 +01:00
scene = bpy.context.scene
cam = scene.camera
2021-03-01 20:05:38 +01:00
2021-03-12 13:06:21 +01:00
# Find default cam, and cameras in camPath
2021-03-01 20:05:38 +01:00
for o in bpy.data.objects:
2021-03-12 13:06:21 +01:00
2021-03-12 11:21:18 +01:00
if o.type == 'CAMERA' and o.data.get('isDefault'):
2021-03-12 13:06:21 +01:00
2021-03-12 11:21:18 +01:00
defaultCam = o.name
2021-03-01 20:05:38 +01:00
if o.type == 'CAMERA' and o.name.startswith("camPath"):
2021-04-02 12:41:32 +02:00
filepath = folder + os.sep + "TIM" + os.sep
filename = "bg_" + CleanName(o.name)
fileext = "." + str(bpy.context.scene.render.image_settings.file_format).lower()
2021-03-12 13:06:21 +01:00
# Set camera as active
2021-03-01 20:05:38 +01:00
bpy.context.scene.camera = o
2021-03-12 13:06:21 +01:00
# Render and save image
2021-03-01 20:05:38 +01:00
bpy.ops.render.render()
2021-03-12 13:06:21 +01:00
2021-04-02 12:41:32 +02:00
bpy.data.images["Render Result"].save_render( filepath + filename + fileext )
# Convert to 256 colors png with PILlow
# TODO : Add Pillow lib
# ~ bgFile = Image.open( filepath + filename + fileext )
# ~ bgFile = bgFile.convert('RGB').convert('P', palette=Image.ADAPTIVE )
# ~ bgFile.save( filepath + filename + fileext )
# Convert to tim with img2tim ( https://github.com/Lameguy64/img2tim )
exe = ""
if os.name == 'nt':
exe = ".exe"
# ImageMagick alternative
# ~ subprocess.call( [ "convert", filepath + filename + fileext, "-colors", "256", filepath + filename + fileext ] )
# ~ subprocess.call( [ "img2tim" + exe, "-t", "-bpp", "8", "-org", "320", "0", "-plt" , "0", "481","-o", filepath + filename + ".tim", filepath + filename + fileext ] )
2021-03-01 20:05:38 +01:00
2021-03-12 13:06:21 +01:00
# Add camera object to camAngles
2021-03-01 20:05:38 +01:00
2021-03-12 13:06:21 +01:00
camAngles.append(o)
2021-03-24 11:33:09 +01:00
2021-03-12 13:06:21 +01:00
### Start writing output file
# Open file
f = open(os.path.normpath(self.filepath),"w+")
2020-12-30 11:23:36 +01:00
2021-03-12 13:06:21 +01:00
## Add C structures definitions
2021-03-16 16:18:05 +01:00
# Partial declaration of structures to avoid inter-dependencies issues
f.write("struct BODY;\n" +
"struct VANIM;\n" +
"struct PRIM;\n" +
"struct MESH;\n" +
"struct CAMPOS;\n" +
"struct CAMPATH;\n" +
"struct CAMANGLE;\n" +
"struct SIBLINGS;\n" +
"struct CHILDREN;\n" +
2021-03-31 20:28:02 +02:00
"struct NODE;\n" +
"struct QUAD;\n" +
"\n")
2021-03-16 16:18:05 +01:00
2021-03-12 13:06:21 +01:00
# BODY
2021-03-16 16:18:05 +01:00
f.write("typedef struct BODY {\n" +
2021-02-19 18:00:42 +01:00
"\tVECTOR gForce;\n" +
2021-01-14 17:22:44 +01:00
"\tVECTOR position;\n" +
"\tSVECTOR velocity;\n" +
2021-03-01 20:05:38 +01:00
"\tint mass;\n" +
2021-02-19 18:00:42 +01:00
"\tint invMass;\n" +
2021-01-14 17:22:44 +01:00
"\tVECTOR min; \n" +
"\tVECTOR max; \n" +
2021-02-19 18:00:42 +01:00
"\tint restitution; \n" +
2021-03-22 20:26:41 +01:00
# ~ "\tstruct NODE * curNode; \n" +
2021-01-14 17:22:44 +01:00
"\t} BODY;\n\n")
2021-03-12 12:13:08 +01:00
2021-03-12 13:06:21 +01:00
# VANIM
2021-03-16 16:18:05 +01:00
f.write("typedef struct VANIM { \n" +
2021-02-02 12:15:11 +01:00
"\tint nframes; // number of frames e.g 20\n" +
"\tint nvert; // number of vertices e.g 21\n" +
2021-03-01 20:05:38 +01:00
"\tint cursor; // anim cursor\n" +
"\tint lerpCursor; // anim cursor\n" +
"\tint dir; // playback direction (1 or -1)\n" +
"\tint interpolate; // use lerp to interpolate keyframes\n" +
2021-02-02 12:15:11 +01:00
"\tSVECTOR data[]; // vertex pos as SVECTORs e.g 20 * 21 SVECTORS\n" +
2021-02-19 18:00:42 +01:00
# ~ "\tSVECTOR normals[]; // vertex pos as SVECTORs e.g 20 * 21 SVECTORS\n" +
2021-02-02 12:15:11 +01:00
"\t} VANIM;\n\n")
2021-03-12 13:06:21 +01:00
# PRIM
2021-03-16 16:18:05 +01:00
f.write("typedef struct PRIM {\n" +
2021-02-19 18:00:42 +01:00
"\tVECTOR order;\n" +
2021-03-31 20:28:02 +02:00
"\tint code; // Same as POL3/POL4 codes : Code (F3 = 1, FT3 = 2, G3 = 3,\n// GT3 = 4) Code (F4 = 5, FT4 = 6, G4 = 7, GT4 = 8)\n" +
2021-02-19 18:00:42 +01:00
"\t} PRIM;\n\n")
2021-03-12 13:06:21 +01:00
# MESH
2021-03-16 16:18:05 +01:00
f.write("typedef struct MESH { \n"+
2021-01-04 18:28:27 +01:00
"\tTMESH * tmesh;\n" +
2021-02-19 18:00:42 +01:00
"\tPRIM * index;\n" +
2021-01-04 18:28:27 +01:00
"\tTIM_IMAGE * tim; \n" +
2021-03-01 20:05:38 +01:00
"\tunsigned long * tim_data;\n"+
2021-01-04 18:28:27 +01:00
"\tMATRIX * mat;\n" +
"\tVECTOR * pos;\n" +
"\tSVECTOR * rot;\n" +
2021-01-14 17:22:44 +01:00
"\tshort * isRigidBody;\n" +
2021-02-19 18:00:42 +01:00
"\tshort * isStaticBody;\n" +
2021-01-04 18:28:27 +01:00
"\tshort * isPrism;\n" +
2021-02-02 12:15:11 +01:00
"\tshort * isAnim;\n" +
2021-02-19 18:00:42 +01:00
"\tshort * isActor;\n" +
"\tshort * isLevel;\n" +
2021-03-01 20:05:38 +01:00
"\tshort * isBG;\n" +
2021-03-22 20:26:41 +01:00
"\tshort * isSprite;\n" +
2021-01-04 18:28:27 +01:00
"\tlong * p;\n" +
2021-03-01 20:05:38 +01:00
"\tlong * OTz;\n" +
2021-02-19 18:00:42 +01:00
"\tBODY * body;\n" +
"\tVANIM * anim;\n" +
2021-03-22 20:26:41 +01:00
"\tstruct NODE * node;\n" +
2021-03-31 20:28:02 +02:00
"\tVECTOR pos2D;\n" +
2020-12-30 11:23:36 +01:00
"\t} MESH;\n\n")
2021-03-31 20:28:02 +02:00
#QUAD
f.write("typedef struct QUAD {\n" +
"\tVECTOR v0, v1;\n" +
"\tVECTOR v2, v3;\n" +
"\t} QUAD;\n\n")
2021-03-12 13:06:21 +01:00
# CAMPOS
2021-03-16 16:18:05 +01:00
f.write("typedef struct CAMPOS {\n" +
2021-02-02 12:15:11 +01:00
"\tVECTOR pos;\n" +
"\tSVECTOR rot;\n" +
"\t} CAMPOS;\n\n" +
2021-03-31 20:28:02 +02:00
"\n// Blender cam ~= PSX cam with these settings : \n" +
"// NTSC - 320x240, PAL 320x256, pixel ratio 1:1,\n" +
"// cam focal length : perspective 90° ( 16 mm ))\n" +
"// With a FOV of 1/2, camera focal length is ~= 16 mm / 90°\n" +
"// Lower values mean wider angle\n\n")
2021-03-01 20:05:38 +01:00
2021-03-12 13:06:21 +01:00
# CAMANGLE
2021-03-16 16:18:05 +01:00
f.write("typedef struct CAMANGLE {\n" +
2021-03-01 20:05:38 +01:00
"\tCAMPOS * campos;\n" +
"\tTIM_IMAGE * BGtim;\n" +
"\tunsigned long * tim_data;\n" +
2021-03-31 20:28:02 +02:00
"\tQUAD bw, fw;\n" +
2021-03-24 11:33:09 +01:00
"\tint index;\n" +
"\tMESH * objects[];\n" +
2021-03-01 20:05:38 +01:00
"\t} CAMANGLE;\n\n")
2021-03-12 13:06:21 +01:00
# CAMPATH
2021-03-16 16:18:05 +01:00
f.write("typedef struct CAMPATH {\n" +
2021-03-01 20:05:38 +01:00
"\tshort len, cursor, pos;\n" +
2021-02-02 12:15:11 +01:00
"\tVECTOR points[];\n" +
"\t} CAMPATH;\n\n")
2021-03-16 16:18:05 +01:00
# SIBLINGS
2021-03-12 13:06:21 +01:00
2021-03-16 16:18:05 +01:00
f.write("typedef struct SIBLINGS {\n" +
2021-03-15 12:44:15 +01:00
"\tint index;\n" +
2021-03-16 16:18:05 +01:00
"\tstruct NODE * list[];\n" +
"\t} SIBLINGS ;\n\n")
2021-03-15 12:44:15 +01:00
2021-03-16 16:18:05 +01:00
# CHILDREN
2021-03-15 12:44:15 +01:00
2021-03-16 16:18:05 +01:00
f.write("typedef struct CHILDREN {\n" +
2021-03-15 12:44:15 +01:00
"\tint index;\n" +
2021-03-16 16:18:05 +01:00
"\tMESH * list[];\n" +
"\t} CHILDREN ;\n\n")
2021-03-15 12:44:15 +01:00
# NODE
2021-03-16 16:18:05 +01:00
f.write("typedef struct NODE {\n" +
"\tMESH * plane;\n" +
"\tSIBLINGS * siblings;\n" +
"\tCHILDREN * objects;\n" +
2021-03-18 19:21:40 +01:00
"\tCHILDREN * rigidbodies;\n" +
2021-03-12 12:13:08 +01:00
"\t} NODE;\n\n")
2021-03-12 13:06:21 +01:00
## Camera setup
# List of points defining the camera path
2021-02-02 12:15:11 +01:00
camPathPoints = []
2021-03-12 13:06:21 +01:00
# Define first mesh. Will be used as default if no properties are found in meshes
2021-02-19 18:00:42 +01:00
first_mesh = CleanName(bpy.data.meshes[0].name)
2021-02-02 12:15:11 +01:00
2021-03-12 13:06:21 +01:00
# Set camera position and rotation in the scene
2021-02-02 12:15:11 +01:00
for o in range(len(bpy.data.objects)):
2021-03-24 11:33:09 +01:00
# Add objects of type MESH with a Rigidbody or StaticBody flag set to a list
2021-03-25 10:50:54 +01:00
if bpy.data.objects[o].type == 'MESH':
2021-04-02 12:41:32 +02:00
if (
bpy.data.objects[o].data.get('isRigidBody') or
bpy.data.objects[o].data.get('isStaticBody')
#or bpy.data.objects[o].data.get('isPortal')
):
2021-03-24 11:33:09 +01:00
2021-03-25 10:50:54 +01:00
rayTargets.append(bpy.data.objects[o])
2021-03-24 11:33:09 +01:00
# Set object of type CAMERA with isDefault flag as default camera
2021-03-23 14:33:38 +01:00
2021-03-01 20:05:38 +01:00
if bpy.data.objects[o].type == 'CAMERA' and bpy.data.objects[o].data.get('isDefault'):
2021-03-23 14:33:38 +01:00
2021-03-01 20:05:38 +01:00
defaultCam = bpy.data.objects[o].name
2021-03-24 11:33:09 +01:00
# Declare each blender camera as a CAMPOS
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
if bpy.data.objects[o].type == 'CAMERA':
2021-03-23 14:33:38 +01:00
2021-03-01 20:05:38 +01:00
f.write("CAMPOS camPos_" + CleanName(bpy.data.objects[o].name) + " = {\n" +
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
"\t{" + str(round(-bpy.data.objects[o].location.x * scale)) + "," + str(round(bpy.data.objects[o].location.z * scale)) + "," +str(round(-bpy.data.objects[o].location.y * scale)) + "},\n" +
2021-03-23 14:33:38 +01:00
2021-03-01 20:05:38 +01:00
"\t{" + str(round(-(degrees(bpy.data.objects[o].rotation_euler.x)-90)/360 * 4096)) + "," + str(round(degrees(bpy.data.objects[o].rotation_euler.z)/360 * 4096)) + "," + str(round(-(degrees(bpy.data.objects[o].rotation_euler.y))/360 * 4096)) + "}\n" +
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
"};\n\n")
2021-03-01 20:05:38 +01:00
2021-03-12 13:06:21 +01:00
# Find camera path points and append them to camPathPoints[]
2021-03-01 20:05:38 +01:00
if bpy.data.objects[o].type == 'CAMERA' :
2021-03-23 14:33:38 +01:00
2021-03-01 20:05:38 +01:00
if bpy.data.objects[o].name.startswith("camPath") and not bpy.data.objects[o].data.get('isDefault'):
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
camPathPoints.append(bpy.data.objects[o].name)
2021-03-25 10:50:54 +01:00
2021-03-12 13:06:21 +01:00
# Write the CAMPATH structure
2021-02-02 12:15:11 +01:00
if camPathPoints:
2021-03-12 13:06:21 +01:00
# Populate with points found above
2021-02-02 12:15:11 +01:00
# ~ camPathPoints = list(reversed(camPathPoints))
for p in range(len(camPathPoints)):
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
if p == 0:
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
f.write("CAMPATH camPath = {\n" +
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
"\t" + str(len(camPathPoints)) + ",\n" +
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
"\t0,\n" +
2021-03-23 14:33:38 +01:00
2021-03-01 20:05:38 +01:00
"\t0,\n" +
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
"\t{\n")
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
f.write("\t\t{" + str(round(-bpy.data.objects[camPathPoints[p]].location.x * scale)) + "," + str(round(bpy.data.objects[camPathPoints[p]].location.z * scale)) + "," +str(round(-bpy.data.objects[camPathPoints[p]].location.y * scale)) + "}")
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
if p != len(camPathPoints) - 1:
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
f.write(",\n")
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
f.write("\n\t}\n};\n\n")
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
else:
2021-03-12 13:06:21 +01:00
# If no camera path points are found, use default
2021-02-19 18:00:42 +01:00
f.write("CAMPATH camPath = {\n" +
2021-03-23 14:33:38 +01:00
2021-02-19 18:00:42 +01:00
"\t0,\n" +
2021-03-23 14:33:38 +01:00
2021-02-19 18:00:42 +01:00
"\t0,\n" +
2021-03-23 14:33:38 +01:00
2021-02-19 18:00:42 +01:00
"\t0\n" +
2021-03-23 14:33:38 +01:00
2021-02-19 18:00:42 +01:00
"};\n\n")
2021-02-02 12:15:11 +01:00
2021-03-12 13:06:21 +01:00
## Lighting setup
# Light sources will be similar to Blender's sunlamp
# A maximum of 3 light sources will be used
# LLM : Local Light Matrix
2021-02-02 12:15:11 +01:00
if len(bpy.data.lamps) is not None:
# ~ f.write( "static MATRIX lgtmat = {\n" +
# ~ "\t 4096, 4096, 4096,\n" +
# ~ "\t -4096, 4096, 4096,\n" +
# ~ "\t -4096, 4096, -4096\n" +
# ~ "};\n")
cnt = 0
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
pad = 3 - len(bpy.data.lamps)
f.write( "static MATRIX lgtmat = {\n")
for l in range(len(bpy.data.lamps)):
2021-03-12 13:06:21 +01:00
# Lightsource energy
2021-02-02 12:15:11 +01:00
energy = int(bpy.data.lamps[l].energy * 4096)
2021-03-12 13:06:21 +01:00
# Get lightsource's world orientation
2021-02-02 12:15:11 +01:00
lightdir = bpy.data.objects[bpy.data.lamps[l].name].matrix_world * Vector((0,0,-1,0))
f.write(
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
"\t" + str(int(lightdir.x * energy)) + "," +
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
"\t" + str(int(-lightdir.z * energy)) + "," +
2021-03-23 14:33:38 +01:00
2021-02-19 18:00:42 +01:00
"\t" + str(int(lightdir.y * energy))
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
)
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
if l != len(bpy.data.lamps) - 1:
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
f.write(",\n")
2021-02-19 18:00:42 +01:00
2021-03-12 13:06:21 +01:00
# If less than 3 light sources exist in blender, fill the matrix with 0s.
2021-02-02 12:15:11 +01:00
if pad:
2021-03-23 14:33:38 +01:00
2021-02-19 18:00:42 +01:00
f.write(",\n")
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
while cnt < pad:
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
f.write("\t0,0,0")
2021-03-23 14:33:38 +01:00
2021-02-19 18:00:42 +01:00
if cnt != pad:
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
f.write(",\n")
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
cnt += 1
f.write("\n\t};\n\n")
# LCM : Local Color Matrix
2021-03-12 13:06:21 +01:00
2021-02-02 12:15:11 +01:00
f.write( "static MATRIX cmat = {\n")
LCM = []
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
for l in bpy.data.lamps:
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
LCM.append(str(int(l.color.r * 4096) if l.color.r else 0))
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
LCM.append(str(int(l.color.g * 4096) if l.color.g else 0))
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
LCM.append(str(int(l.color.b * 4096) if l.color.b else 0))
if len(LCM) < 9:
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
while len(LCM) < 9:
2021-03-23 14:33:38 +01:00
2021-02-02 12:15:11 +01:00
LCM.append('0')
2021-03-12 13:06:21 +01:00
# Write LC matrix
2021-02-02 12:15:11 +01:00
f.write(
"\t" + LCM[0] + "," + LCM[3] + "," + LCM[6] + ",\n" +
"\t" + LCM[1] + "," + LCM[4] + "," + LCM[7] + ",\n" +
"\t" + LCM[2] + "," + LCM[5] + "," + LCM[8] + "\n" )
f.write("\t};\n\n")
2021-03-12 13:06:21 +01:00
## Meshes
2021-02-19 18:00:42 +01:00
actorPtr = first_mesh
2021-03-23 14:33:38 +01:00
2021-02-19 18:00:42 +01:00
levelPtr = first_mesh
2021-03-23 14:33:38 +01:00
2021-02-19 18:00:42 +01:00
propPtr = first_mesh
2021-03-23 14:33:38 +01:00
2021-03-12 12:13:08 +01:00
nodePtr = first_mesh
2021-02-19 18:00:42 +01:00
2021-03-12 11:21:18 +01:00
timList = []
for m in bpy.data.meshes:
2021-03-31 20:28:02 +02:00
if not m.get('isPortal') :
# Store vertices coordinates by axis to find max/min coordinates
Xvals = []
Yvals = []
Zvals = []
cleanName = CleanName(m.name)
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
# Write vertices vectors
f.write("SVECTOR "+"model"+cleanName+"_mesh[] = {\n")
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
for i in range(len(m.vertices)):
v = m.vertices[i].co
# Append vertex coords to lists
Xvals.append(v.x)
Yvals.append(v.y)
Zvals.append(-v.z)
f.write("\t{"+str(round(v.x*scale))+","+str(round(-v.z*scale)) + "," + str(round(v.y*scale)) +"}")
if i != len(m.vertices) - 1:
f.write(",")
f.write("\n")
f.write("};\n\n")
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
# Write normals vectors
f.write("SVECTOR "+"model"+cleanName+"_normal[] = {\n")
2021-01-14 17:22:44 +01:00
2021-03-31 20:28:02 +02:00
for i in range(len(m.vertices)):
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
poly = m.vertices[i]
2021-01-14 17:22:44 +01:00
2021-03-31 20:28:02 +02:00
f.write("\t"+str(round(-poly.normal.x * 4096))+","+str(round(poly.normal.z * 4096))+","+str(round(-poly.normal.y * 4096))+",0")
2021-01-14 17:22:44 +01:00
2021-03-31 20:28:02 +02:00
if i != len(m.vertices) - 1:
2021-03-01 20:05:38 +01:00
2021-03-31 20:28:02 +02:00
f.write(",")
f.write("\n")
f.write("};\n\n")
# Write UVs vectors if a texture exists
# get name of texture image https://docs.blender.org/api/2.79b/bpy.types.Image.html#bpy.types.Image
# bpy.context.active_object.data.uv_textures.active.data[0].image.name
# bpy.context.active_object.data.uv_textures.active.data[0].image.filepath
# bpy.context.active_object.data.uv_textures.active.data[0].image.filepath_from_user()
#
# get image size x, y
# print(bpy.data.meshes[0].uv_textures[0].data[0].image.size[0]) # x
# print(bpy.data.meshes[0].uv_textures[0].data[0].image.size[1]) # y
if len(m.uv_textures) != None:
for t in range(len(m.uv_textures)):
if m.uv_textures[t].data[0].image != None:
f.write("SVECTOR "+"model"+cleanName+"_uv[] = {\n")
texture_image = m.uv_textures[t].data[0].image
tex_width = texture_image.size[0]
tex_height = texture_image.size[1]
uv_layer = m.uv_layers[0].data
for i in range(len(uv_layer)):
u = uv_layer[i].uv
ux = u.x * tex_width
uy = u.y * tex_height
# ~ if self.exp_Precalc and m.get('isBG'):
# ~ f.write("\t255, 255, 0, 0") # Clamp values to 0-255 to avoid tpage overflow
# ~ else:
f.write("\t"+str(max(0, min( round(ux) , 255 )))+","+str(max(0, min(round(tex_height - uy) , 255 )))+", 0, 0") # Clamp values to 0-255 to avoid tpage overflow
if i != len(uv_layer) - 1:
f.write(",")
f.write("\n")
f.write("};\n\n")
# Save UV texture to a file in ./TIM
# It will have to be converted to a tim file
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
if texture_image.filepath == '':
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
os.makedirs(dirpath, exist_ok = 1)
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
texture_image.filepath_raw = folder + os.sep + "TIM" + os.sep + CleanName(texture_image.name) + "." + texture_image.file_format
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
texture_image.save()
# Write vertex colors vectors
f.write("CVECTOR "+"model"+cleanName+"_color[] = {\n")
# If vertex colors exist, use them
2021-02-19 18:00:42 +01:00
2021-03-31 20:28:02 +02:00
if len(m.vertex_colors) != 0:
2021-02-19 18:00:42 +01:00
2021-03-31 20:28:02 +02:00
colors = m.vertex_colors[0].data
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
for i in range(len(colors)):
2021-02-02 12:15:11 +01:00
2021-03-31 20:28:02 +02:00
f.write("\t"+str(int(colors[i].color.r*255))+","+str(int(colors[i].color.g*255))+","+str(int(colors[i].color.b*255))+", 0")
2021-02-19 18:00:42 +01:00
2021-03-31 20:28:02 +02:00
if i != len(colors) - 1:
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
f.write(",")
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
f.write("\n")
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
# If no vertex colors, default to 2 whites, 1 grey
2021-03-25 16:53:04 +01:00
2021-03-31 20:28:02 +02:00
else:
for i in range(len(m.polygons) * 3):
if i % 3 == 0:
f.write("\t80,80,80,0")
else:
f.write("\t128,128,128,0")
if i != (len(m.polygons) * 3) - 1:
f.write(",")
f.write("\n")
f.write("};\n\n")
# Write polygons index + type
f.write("PRIM "+"model"+cleanName+"_index[] = {\n")
for i in range(len(m.polygons)):
poly = m.polygons[i]
f.write("\t"+str(poly.vertices[0])+","+str(poly.vertices[1])+","+str(poly.vertices[2]))
2021-03-25 16:53:04 +01:00
2021-03-31 20:28:02 +02:00
if len(poly.vertices) > 3:
f.write("," + str(poly.vertices[3]) + ",8")
else:
f.write(",0,4")
2021-03-25 16:53:04 +01:00
2021-03-31 20:28:02 +02:00
if i != len(m.polygons) - 1:
2021-03-25 16:53:04 +01:00
2021-03-31 20:28:02 +02:00
f.write(",")
2021-02-02 12:15:11 +01:00
2021-03-31 20:28:02 +02:00
f.write("\n")
2021-02-02 12:15:11 +01:00
2021-03-31 20:28:02 +02:00
f.write("};\n\n")
2021-02-02 12:15:11 +01:00
2021-03-31 20:28:02 +02:00
# Get object's custom properties
2021-02-02 12:15:11 +01:00
2021-03-31 20:28:02 +02:00
chkProp = {
'isAnim':0,
'isRigidBody':0,
'isStaticBody':0,
'isPrism':0,
'isActor':0,
'isLevel':0,
'isBG':0,
'isSprite':0,
'mass': 1,
'restitution': 0,
'lerp': 0
}
for prop in chkProp:
if m.get(prop) is not None:
chkProp[prop] = m[prop]
# put isBG back to 0 if using precalculated BGs
if not self.exp_Precalc:
chkProp['isBG'] = 0;
if m.get('isActor'):
actorPtr = m.name
if m.get('isLevel'):
levelPtr = cleanName
if m.get('isProp'):
propPtr = cleanName
## Vertex animation
# write vertex anim if isAnim != 0
# Source : https://stackoverflow.com/questions/9138637/vertex-animation-exporter-for-blender
if m.get("isAnim") is not None and m["isAnim"] != 0:
2021-02-02 12:15:11 +01:00
2021-03-31 20:28:02 +02:00
# Write vertex pos
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
o = bpy.data.objects[m.name]
2021-02-02 12:15:11 +01:00
2021-03-31 20:28:02 +02:00
# If an action exists with the same name as the object, use that
if m.name in bpy.data.actions:
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
frame_start = int(bpy.data.actions[m.name].frame_range[0])
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
frame_end = int(bpy.data.actions[m.name].frame_range[1])
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
else:
# Use scene's Start/End frames
frame_start = int( bpy.context.scene.frame_start )
frame_end = int( bpy.context.scene.frame_end )
nFrame = frame_end - frame_start
c = 0;
tmp_meshes = []
for i in range(frame_start, frame_end):
bpy.context.scene.frame_set(i)
bpy.context.scene.update()
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
nm = o.to_mesh(bpy.context.scene, True, 'PREVIEW')
if i == frame_start :
f.write("VANIM model"+cleanName+"_anim = {\n" +
"\t" + str(nFrame) + ",\n" +
"\t" + str(len(nm.vertices)) + ",\n" +
"\t0,\n" +
"\t0,\n" +
"\t1,\n" +
"\t" + str(chkProp['lerp']) + ",\n" +
"\t{\n"
)
for v in range(len(nm.vertices)):
if v == 0:
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
f.write("\t\t//Frame %d\n" % i)
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
f.write("\t\t{ " + str(round(nm.vertices[v].co.x*scale)) + "," + str(round(-nm.vertices[v].co.z*scale)) + "," + str(round(nm.vertices[v].co.y*scale)) + " }")
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
if c != len(nm.vertices) * (nFrame) * 3 - 3:
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
f.write(",\n")
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
if v == len(nm.vertices) - 1:
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
f.write("\n")
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
c += 3;
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
tmp_meshes.append(nm)
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
f.write("\n\t}\n};\n")
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
# Remove meshe's working copies
for nm in tmp_meshes:
bpy.data.meshes.remove(nm)
# bpy.data.objects[bpy.data.meshes[0].name].active_shape_key.value : access shape_key
2021-02-19 18:00:42 +01:00
2021-03-31 20:28:02 +02:00
## Mesh world transform setup
# Write object matrix, rot and pos vectors
f.write("MATRIX model"+cleanName+"_matrix = {0};\n" +
"VECTOR model"+cleanName+"_pos = {"+ str(round(bpy.data.objects[m.name].location.x * scale)) + "," + str(round(-bpy.data.objects[m.name].location.z * scale)) + "," + str(round(bpy.data.objects[m.name].location.y * scale)) + ", 0};\n" +
"SVECTOR model"+cleanName+"_rot = {"+ str(round(degrees(bpy.data.objects[m.name].rotation_euler.x)/360 * 4096)) + "," + str(round(degrees(-bpy.data.objects[m.name].rotation_euler.z)/360 * 4096)) + "," + str(round(degrees(bpy.data.objects[m.name].rotation_euler.y)/360 * 4096)) + "};\n" +
"short model"+cleanName+"_isRigidBody = " + str(int(chkProp['isRigidBody'])) + ";\n" +
"short model"+cleanName+"_isStaticBody = " + str(int(chkProp['isStaticBody'])) + ";\n" +
"short model"+cleanName+"_isPrism = " + str(int(chkProp['isPrism'])) + ";\n" +
"short model"+cleanName+"_isAnim = " + str(int(chkProp['isAnim'])) + ";\n" +
"short model"+cleanName+"_isActor = " + str(int(chkProp['isActor'])) + ";\n" +
"short model"+cleanName+"_isLevel = " + str(int(chkProp['isLevel'])) + ";\n" +
"short model"+cleanName+"_isBG = " + str(int(chkProp['isBG'])) + ";\n" +
"short model"+cleanName+"_isSprite = " + str(int(chkProp['isSprite'])) + ";\n" +
"long model"+cleanName+"_p = 0;\n" +
"long model"+cleanName+"_OTz = 0;\n" +
"BODY model"+cleanName+"_body = {\n" +
"\t{0, 0, 0, 0},\n" +
"\t" + str(round(bpy.data.objects[m.name].location.x * scale)) + "," + str(round(-bpy.data.objects[m.name].location.z * scale)) + "," + str(round(bpy.data.objects[m.name].location.y * scale)) + ", 0,\n" +
"\t"+ str(round(degrees(bpy.data.objects[m.name].rotation_euler.x)/360 * 4096)) + "," + str(round(degrees(-bpy.data.objects[m.name].rotation_euler.z)/360 * 4096)) + "," + str(round(degrees(bpy.data.objects[m.name].rotation_euler.y)/360 * 4096)) + ", 0,\n" +
"\t" + str(int(chkProp['mass'])) + ",\n" +
"\tONE/" + str(int(chkProp['mass'])) + ",\n" +
# write min and max values of AABBs on each axis
"\t" + str(round(min(Xvals) * scale)) + "," + str(round(min(Zvals) * scale)) + "," + str(round(min(Yvals) * scale)) + ", 0,\n" +
"\t" + str(round(max(Xvals) * scale)) + "," + str(round(max(Zvals) * scale)) + "," + str(round(max(Yvals) * scale)) + ", 0,\n" +
"\t" + str(int(chkProp['restitution'])) + ",\n" +
# ~ "\tNULL\n" +
"\t};\n\n")
# Write TMESH struct
f.write("TMESH "+"model"+cleanName+" = {\n")
f.write("\t"+"model"+cleanName+"_mesh, \n")
f.write("\t"+"model"+cleanName+"_normal,\n")
if len(m.uv_textures) != None:
for t in range(len(m.uv_textures)):
if m.uv_textures[0].data[0].image != None:
f.write("\t"+"model"+cleanName+"_uv,\n")
else:
f.write("\t0,\n")
else:
f.write("\t0,\n")
f.write("\t"+"model"+cleanName+"_color, \n")
# According to libgte.h, TMESH.len should be # of vertices. Meh...
f.write("\t"+str(len(m.polygons))+"\n")
f.write("};\n\n")
# Write texture binary name and declare TIM_IMAGE
# By default, loads the file from the ./TIM folder
if len(m.uv_textures) != None:
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
for t in range(len(m.uv_textures)):
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
if m.uv_textures[0].data[0].image != None:
tex_name = texture_image.name
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
prefix = str.partition(tex_name, ".")[0].replace('-','_')
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
prefix = CleanName(prefix)
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
# Add Tex name to list if it's not in there already
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
if prefix in timList:
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
break
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
else:
f.write("extern unsigned long "+"_binary_TIM_" + prefix + "_tim_start[];\n")
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
f.write("extern unsigned long "+"_binary_TIM_" + prefix + "_tim_end[];\n")
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
f.write("extern unsigned long "+"_binary_TIM_" + prefix + "_tim_length;\n\n")
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
f.write("TIM_IMAGE tim_" + prefix + ";\n\n")
timList.append(prefix)
2021-03-12 11:21:18 +01:00
2021-03-31 20:28:02 +02:00
f.write("MESH mesh"+cleanName+" = {\n")
f.write("\t&model"+ cleanName +",\n")
f.write("\tmodel" + cleanName + "_index,\n")
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
if len(m.uv_textures) != None:
for t in range(len(m.uv_textures)):
if m.uv_textures[0].data[0].image != None:
tex_name = texture_image.name
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
prefix = str.partition(tex_name, ".")[0].replace('-','_')
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
prefix = CleanName(prefix)
f.write("\t&tim_"+ prefix + ",\n")
f.write("\t_binary_TIM_" + prefix + "_tim_start,\n")
else:
f.write("\t0,\n" +
"\t0,\n")
else:
f.write("\t0,\n" +
"\t0,\n")
f.write("\t&model"+cleanName+"_matrix,\n" +
"\t&model"+cleanName+"_pos,\n" +
"\t&model"+cleanName+"_rot,\n" +
"\t&model"+cleanName+"_isRigidBody,\n" +
"\t&model"+cleanName+"_isStaticBody,\n" +
"\t&model"+cleanName+"_isPrism,\n" +
"\t&model"+cleanName+"_isAnim,\n" +
"\t&model"+cleanName+"_isActor,\n" +
"\t&model"+cleanName+"_isLevel,\n" +
"\t&model"+cleanName+"_isBG,\n" +
"\t&model"+cleanName+"_isSprite,\n" +
"\t&model"+cleanName+"_p,\n" +
"\t&model"+cleanName+"_OTz,\n" +
"\t&model"+cleanName+"_body,\n")
2021-03-12 11:21:18 +01:00
2021-03-31 20:28:02 +02:00
if m.get("isAnim") is not None and m["isAnim"] != 0:
f.write("\t&model"+cleanName+"_anim,\n")
else:
f.write("\t0,\n")
f.write(
"\t0" +
"\n};\n\n"
)
# Remove portals from mesh list as we don't want them to be exported
meshList = list(bpy.data.meshes)
portalList = []
for mesh in meshList:
if mesh.get('isPortal'):
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
meshList = [i for i in meshList if i != mesh]
# Nasty way of removing all occurrences of the mesh
# ~ try:
# ~ while True:
# ~ meshList.remove(mesh)
# ~ except ValueError:
# ~ pass
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
portalList.append( bpy.data.objects[mesh.name] )
f.write("MESH * meshes[" + str(len(meshList)) + "] = {\n")
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
for k in range(len(meshList)):
2021-03-12 11:21:18 +01:00
2021-03-31 20:28:02 +02:00
cleanName = CleanName(meshList[k].name)
2021-03-12 13:06:21 +01:00
2021-02-19 18:00:42 +01:00
f.write("\t&mesh" + cleanName)
2021-03-12 11:21:18 +01:00
2021-03-31 20:28:02 +02:00
if k != len(meshList) - 1:
2021-03-12 13:06:21 +01:00
2020-12-30 11:23:36 +01:00
f.write(",\n")
2021-03-12 13:06:21 +01:00
2020-12-30 11:23:36 +01:00
f.write("\n}; \n")
2021-03-01 20:05:38 +01:00
2021-03-12 13:06:21 +01:00
# If camAngles is empty, use default camera, and do not include pre-calculated backgrounds
2021-03-01 20:05:38 +01:00
if not camAngles:
2021-03-12 13:06:21 +01:00
2021-03-01 20:05:38 +01:00
f.write("CAMANGLE camAngle_" + CleanName(defaultCam) + " = {\n" +
2021-03-24 11:33:09 +01:00
2021-03-01 20:05:38 +01:00
"\t&camPos_" + CleanName(defaultCam) + ",\n" +
2021-03-24 11:33:09 +01:00
2021-03-31 20:28:02 +02:00
"\t0,\n 0,\n {0},\n {0},\n 0,\n 0\n" +
2021-03-24 11:33:09 +01:00
2021-03-01 20:05:38 +01:00
"};\n\n")
2021-03-12 13:06:21 +01:00
# If camAngles is populated, use backgrounds and camera angles
2021-03-24 11:33:09 +01:00
for camera in camAngles:
2021-03-25 10:50:54 +01:00
# Get current scene
2021-03-24 11:33:09 +01:00
scene = bpy.context.scene
2021-03-31 20:28:02 +02:00
# List of portals
visiblePortal = []
for portal in portalList:
if isInFrame(scene, camera, portal):
# Get normalized direction vector between camera and portal
dirToTarget = portal.location - camera.location
dirToTarget.normalize()
# Cast a ray from camera to body to determine visibility
result, location, normal, index, hitObject, matrix = scene.ray_cast( camera.location, dirToTarget )
# If hitObject is portal, nothing is obstructing it's visibility
if hitObject is not None:
if hitObject in portalList:
if hitObject == portal:
# ~ print(str(camera) + str(hitObject))
visiblePortal.append(hitObject)
# ~ print(str(camera) + ":" + str(visiblePortal))
# If more than one portal is visible, only keep the two closest ones
if len( visiblePortal ) > 2:
# Store the tested portals distance to camera
testDict = {}
for tested in visiblePortal:
# Get distance between cam and tested portal
distToTested = sqrt( ( tested.location - camera.location ) * ( tested.location - camera.location ) )
# Store distance
testDict[distToTested] = tested
# If dictionary has more than 2 portals, remove the farthest ones
while len( testDict ) > 2:
del testDict[max(testDict)]
# Reset visible portal
visiblePortal.clear()
# Get the portals stored in the dict and store them in the list
for Dportal in testDict:
visiblePortal.append(testDict[Dportal])
# Revert to find original order back
visiblePortal.reverse()
# ~ print( str( camera ) + " : " + str( visiblePortal ) )
2021-03-24 11:33:09 +01:00
# List of target found visible
visibleTarget = []
for target in rayTargets:
# Chech object is in view frame
2021-04-02 12:41:32 +02:00
if isInFrame(scene, camera, target):# and not target.data.get('isPortal') :
2021-03-25 10:50:54 +01:00
2021-03-24 11:33:09 +01:00
# Get normalized direction vector between camera and object
dirToTarget = target.location - camera.location
dirToTarget.normalize()
# Cast ray from camera to object
2021-03-31 20:28:02 +02:00
# Unpack results into several variables.
2021-03-24 11:33:09 +01:00
# We're only interested in 'hitObject' though
2021-04-02 12:41:32 +02:00
result, hitLocation, normal, index, hitObject, matrix = scene.ray_cast( camera.location, dirToTarget )
2021-03-24 11:33:09 +01:00
# If hitObject is the same as target, nothing is obstructing it's visibility
if hitObject is not None:
2021-04-02 12:41:32 +02:00
# If hit object is a portal, cast a new ray from hit location to target
if hitObject.data.get('isPortal'):
# Find out if we're left or right of portal
2021-04-02 12:53:55 +02:00
# Get vertices world coordinates
2021-04-02 12:41:32 +02:00
v0 = hitObject.matrix_world * hitObject.data.vertices[0].co
2021-04-02 12:53:55 +02:00
2021-04-02 12:41:32 +02:00
v1 = hitObject.matrix_world * hitObject.data.vertices[1].co
2021-04-02 12:53:55 +02:00
# Check side :
# 'back' : portal in on the right of the cam, cam is on left of portal
# 'front' : portal in on the left of the cam, cam is on right of portal
2021-04-02 12:41:32 +02:00
side = checkLine(v0.x, v0.y, v1.x, v1.y , camera.location.x, camera.location.y, camera.location.x, camera.location.y )
if side == 'front':
2021-04-02 12:53:55 +02:00
# we're on the right of the portal, origin.x must be > hitLocation.x
2021-04-02 12:41:32 +02:00
offset = [ 1.001, 0.999, 0.999 ]
else :
2021-04-02 12:53:55 +02:00
# we're on the left of the portal, origin.x must be < hitLocation.x
2021-04-02 12:41:32 +02:00
2021-04-02 12:53:55 +02:00
offset = [ 0.999, 1.001, 1.001 ]
# Add offset to hitLocation, so that the new ray won't hit the same portal
2021-04-02 12:41:32 +02:00
origin = Vector( ( hitLocation.x * offset[0], hitLocation.y * offset[1], hitLocation.z * offset[2] ) )
2021-04-02 12:53:55 +02:00
# ~ print(hitObject.name + " is a portal at " + str( hitLocation ) + " N : " + str(normal) + " - " + side + "Or : " + str(origin) )
2021-04-02 12:41:32 +02:00
result, hitLocationPort, normal, index, hitObjectPort, matrix = scene.ray_cast( origin , dirToTarget )
2021-04-02 12:53:55 +02:00
# ~ print( camera.name + " : recasting from " + str( origin ) + " to " + target.name )
2021-04-02 12:41:32 +02:00
if hitObjectPort is not None:
if hitObjectPort in rayTargets:
2021-04-02 12:53:55 +02:00
# ~ print(hitObjectPort.name)
2021-04-02 12:41:32 +02:00
visibleTarget.append(target)
2021-04-02 12:53:55 +02:00
# If hitObject is not a portal, just add it
2021-04-02 12:41:32 +02:00
elif hitObject in rayTargets:
2021-03-25 10:50:54 +01:00
2021-03-24 11:33:09 +01:00
visibleTarget.append(target)
2021-04-02 12:41:32 +02:00
2021-03-31 20:28:02 +02:00
if bpy.data.objects[ actorPtr ] not in visibleTarget:
visibleTarget.append( bpy.data.objects[ actorPtr ] )
2021-03-24 11:33:09 +01:00
prefix = CleanName(camera.name)
2021-03-01 20:05:38 +01:00
2021-03-12 13:06:21 +01:00
# Include Tim data
2021-03-01 20:05:38 +01:00
f.write("extern unsigned long "+"_binary_TIM_bg_" + prefix + "_tim_start[];\n")
2021-03-12 13:06:21 +01:00
2021-03-01 20:05:38 +01:00
f.write("extern unsigned long "+"_binary_TIM_bg_" + prefix + "_tim_end[];\n")
2021-03-12 13:06:21 +01:00
2021-03-01 20:05:38 +01:00
f.write("extern unsigned long "+"_binary_TIM_bg_" + prefix + "_tim_length;\n\n")
2021-03-12 13:06:21 +01:00
# Write corresponding TIM_IMAGE struct
2021-03-01 20:05:38 +01:00
f.write("TIM_IMAGE tim_bg_" + prefix + ";\n\n")
2021-03-12 13:06:21 +01:00
# Write corresponding CamAngle struct
2021-03-01 20:05:38 +01:00
f.write("CAMANGLE camAngle_" + prefix + " = {\n" +
2021-03-24 11:33:09 +01:00
2021-03-01 20:05:38 +01:00
"\t&camPos_" + prefix + ",\n" +
2021-03-24 11:33:09 +01:00
2021-03-01 20:05:38 +01:00
"\t&tim_bg_" + prefix + ",\n" +
2021-03-24 11:33:09 +01:00
"\t_binary_TIM_bg_" + prefix + "_tim_start,\n" +
2021-03-31 20:28:02 +02:00
"\t// Write quad NW, NE, SE, SW\n")
# If visiblePoratl length is under 2, this means there's only one portal, hence a fw portal
if len( visiblePortal ) < 2 :
f.write("\t{\n\t\t{ 0, 0, 0, 0 },\n\t\t{ 0, 0, 0, 0 },\n\t\t{ 0, 0, 0, 0 },\n\t\t{ 0, 0, 0, 0 }\n\t},\n")
for portal in visiblePortal:
2021-04-02 12:41:32 +02:00
w = objVertLtoW(portal)
2021-03-31 20:28:02 +02:00
2021-04-02 12:41:32 +02:00
f.write("// " + str(portal) + "\n" )
2021-03-31 20:28:02 +02:00
2021-04-02 12:41:32 +02:00
# Write portal'vertices world coordinates NW, NE, SE, SW
2021-03-31 20:28:02 +02:00
2021-04-02 12:41:32 +02:00
f.write("\t{\n\t\t" +
2021-03-31 20:28:02 +02:00
2021-04-02 12:41:32 +02:00
"{ " + str( int (w[3].x ) ) + ", " + str( int (w[3].y ) ) + ", " + str( int (w[3].z ) ) + ", 0 },\n\t\t" +
"{ " + str( int (w[2].x ) ) + ", " + str( int (w[2].y ) ) + ", " + str( int (w[2].z ) ) + ", 0 },\n\t\t" +
"{ " + str( int (w[0].x ) ) + ", " + str( int (w[0].y ) ) + ", " + str( int (w[0].z ) ) + ", 0 },\n\t\t" +
2021-03-31 20:28:02 +02:00
2021-04-02 12:41:32 +02:00
"{ " + str( int (w[1].x ) ) + ", " + str( int (w[1].y ) ) + ", " + str( int (w[1].z ) ) + ", 0 }\n" +
2021-03-31 20:28:02 +02:00
"\t},\n" )
2021-04-02 12:41:32 +02:00
# UNUSED : Screen coords
# ~ s = objVertWtoS( scene, camera, portal )
# ~ f.write("\t{\n\t\t" +
# ~ "{ " + str( int (s[3].x ) ) + ", " + str( int (s[3].y ) ) + ", " + str( int (s[3].z ) ) + ", 0 },\n\t\t" +
# ~ "{ " + str( int (s[2].x ) ) + ", " + str( int (s[2].y ) ) + ", " + str( int (s[2].z ) ) + ", 0 },\n\t\t" +
# ~ "{ " + str( int (s[0].x ) ) + ", " + str( int (s[0].y ) ) + ", " + str( int (s[0].z ) ) + ", 0 },\n\t\t" +
# ~ "{ " + str( int (s[1].x ) ) + ", " + str( int (s[1].y ) ) + ", " + str( int (s[1].z ) ) + ", 0 }\n" +
# ~ "\t},\n" )
2021-03-31 20:28:02 +02:00
f.write("\t" + str( len( visibleTarget ) ) + ",\n" +
2021-03-24 11:33:09 +01:00
"\t{\n")
for target in range( len( visibleTarget ) ) :
f.write( "\t\t&mesh" + CleanName(visibleTarget[target].name) )
if target < len(visibleTarget) - 1:
f.write(",\n")
f.write("\n\t}\n" +
2021-03-01 20:05:38 +01:00
"};\n\n")
2021-03-12 13:06:21 +01:00
# Write camera angles in an array for loops
2021-03-01 20:05:38 +01:00
f.write("CAMANGLE * camAngles[" + str(len(camAngles)) + "] = {\n")
2021-03-12 13:06:21 +01:00
2021-03-24 11:33:09 +01:00
for camera in camAngles:
2021-03-12 13:06:21 +01:00
2021-03-24 11:33:09 +01:00
prefix = CleanName(camera.name)
2021-03-12 13:06:21 +01:00
2021-03-01 20:05:38 +01:00
f.write("\t&camAngle_" + prefix + ",\n")
2021-03-12 13:06:21 +01:00
2021-03-01 20:05:38 +01:00
f.write("};\n\n")
2020-12-30 11:23:36 +01:00
2021-03-15 12:44:15 +01:00
## Spatial Partitioning
2021-03-16 11:58:00 +01:00
# Planes in the level - dict of strings
2021-03-15 12:44:15 +01:00
LvlPlanes = {}
2021-03-16 11:58:00 +01:00
# Objects in the level - dict of strings
2021-03-15 12:44:15 +01:00
LvlObjects = {}
# Link objects to their respective plane
2021-03-16 11:58:00 +01:00
PlanesObjects = defaultdict(dict)
2021-03-18 19:21:40 +01:00
PlanesRigidBodies = defaultdict(dict)
# List of objects that can travel ( actor , moveable props...)
Moveables = []
2021-03-15 12:44:15 +01:00
# Store XY1, XY2 values
Xvalues = []
Yvalues = []
# Find planes and objects bounding boxes
# Planes first
for o in bpy.data.objects:
# Only loop through meshes
2021-03-31 20:28:02 +02:00
if o.type == 'MESH' and not o.data.get('isPortal'):
2021-03-15 12:44:15 +01:00
# Get Level planes coordinates
if o.data.get('isLevel'):
# World matrix is used to convert local to global coordinates
mw = o.matrix_world
for v in bpy.data.objects[o.name].data.vertices:
# Convert local to global coords
Xvalues.append( (mw * v.co).x )
Yvalues.append( (mw * v.co).y )
LvlPlanes[o.name] = {'x1' : min(Xvalues),
2021-03-23 14:33:38 +01:00
2021-03-15 12:44:15 +01:00
'y1' : min(Yvalues),
2021-03-23 14:33:38 +01:00
2021-03-15 12:44:15 +01:00
'x2' : max(Xvalues),
2021-03-23 14:33:38 +01:00
2021-03-15 12:44:15 +01:00
'y2' : max(Yvalues)}
# Clear X/Y lists for next iteration
Xvalues = []
Yvalues = []
2021-03-16 11:58:00 +01:00
# For each object not a plane, get its coordinates
2021-03-15 12:44:15 +01:00
2021-03-16 11:58:00 +01:00
if not o.data.get('isLevel'):
2021-03-15 12:44:15 +01:00
# World matrix is used to convert local to global coordinates
mw = o.matrix_world
2021-03-16 11:58:00 +01:00
2021-03-15 12:44:15 +01:00
for v in bpy.data.objects[o.name].data.vertices:
# Convert local to global coords
Xvalues.append( (mw * v.co).x )
Yvalues.append( (mw * v.co).y )
LvlObjects[o.name] = {'x1' : min(Xvalues),
2021-04-02 12:41:32 +02:00
2021-03-15 12:44:15 +01:00
'y1' : min(Yvalues),
2021-04-02 12:41:32 +02:00
2021-03-15 12:44:15 +01:00
'x2' : max(Xvalues),
2021-04-02 12:41:32 +02:00
2021-03-15 12:44:15 +01:00
'y2' : max(Yvalues)}
# Clear X/Y lists for next iteration
Xvalues = []
Yvalues = []
# Add objects that can travel to the
if o.data.get("isRigidBody"):
Moveables.append(o.name)
2021-03-15 12:44:15 +01:00
2021-03-16 16:18:05 +01:00
# Declare LvlPlanes nodes to avoid declaration dependency issues
# ~ f.write("NODE ")
2021-03-15 12:44:15 +01:00
2021-03-16 16:18:05 +01:00
for k in LvlPlanes.keys():
f.write("NODE node" + CleanName(k) + ";\n\n")
2021-03-15 12:44:15 +01:00
# Sides of the plane to check
checkSides = [
['N','S'],
['S','N'],
['W','E'],
['E','W']
]
# Generate a dict :
# ~ {
# ~ 'S' : []
# ~ 'N' : [] list of planes connected to this plane, and side they're on
# ~ 'W' : []
# ~ 'E' : []
# ~ 'objects' : [] list of objects on this plane
# ~ ''
# ~ }
for p in LvlPlanes:
# Find objects on plane
for o in LvlObjects:
2021-03-16 11:58:00 +01:00
# If object is above plane
2021-03-15 12:44:15 +01:00
if isInPlane(LvlPlanes[p], LvlObjects[o]) == 1:
2021-03-15 12:44:15 +01:00
2021-03-22 20:26:41 +01:00
# Add all objects but the actor
2021-03-16 11:58:00 +01:00
2021-03-22 20:26:41 +01:00
if o != actorPtr:
2021-03-16 11:58:00 +01:00
2021-03-22 20:26:41 +01:00
# Add this object to the plane's list
if 'objects' in PlanesObjects[p]:
PlanesObjects[p]['objects'].append(o)
else:
PlanesObjects[p] = { 'objects' : [o] }
2021-03-15 12:44:15 +01:00
else:
2021-03-22 20:26:41 +01:00
# If actor is on this plane, use it as starting node
2021-03-24 11:33:09 +01:00
levelPtr = p
2021-03-22 20:26:41 +01:00
nodePtr = p
2021-03-15 12:44:15 +01:00
2021-03-31 20:28:02 +02:00
# Add moveable objects in every plane
for moveable in Moveables:
2021-03-18 19:21:40 +01:00
if 'rigidbodies' in PlanesRigidBodies[p]:
2021-03-18 19:21:40 +01:00
if moveable not in PlanesRigidBodies[p]['rigidbodies']:
2021-03-18 19:21:40 +01:00
PlanesRigidBodies[p]['rigidbodies'].append(CleanName(moveable))
else:
2021-03-18 19:21:40 +01:00
# ~ print(0)
PlanesRigidBodies[p] = { 'rigidbodies' : [ CleanName(moveable) ] }
2021-03-15 12:44:15 +01:00
# Find surrounding planes
for op in LvlPlanes:
# Loop on other planes
if op is not p:
# Check each side
for s in checkSides:
# If connected ('connected') plane exists...
if checkLine(
getSepLine(p, s[0])[0],
getSepLine(p, s[0])[1],
getSepLine(p, s[0])[2],
getSepLine(p, s[0])[3],
getSepLine(op, s[1])[0],
getSepLine(op, s[1])[1],
getSepLine(op, s[1])[2],
getSepLine(op, s[1])[3]
) == 'connected' and (
isInPlane( LvlPlanes[p], LvlPlanes[op] )
):
2021-03-15 12:44:15 +01:00
# ... add it to the list
if 'siblings' not in PlanesObjects[p]:
PlanesObjects[p]['siblings'] = {}
# If more than one plane is connected on the same side of the plane,
# add it to the corresponding list
if s[0] in PlanesObjects[p]['siblings']:
PlanesObjects[p]['siblings'][s[0]].append(op)
else:
PlanesObjects[p]['siblings'][s[0]] = [op]
pName = CleanName(p)
2021-03-16 16:18:05 +01:00
# Write SIBLINGS structure
2021-03-15 12:44:15 +01:00
2021-03-16 11:58:00 +01:00
nSiblings = 0
if 'siblings' in PlanesObjects[p]:
if 'S' in PlanesObjects[p]['siblings']:
2021-03-16 11:58:00 +01:00
nSiblings += len(PlanesObjects[p]['siblings']['S'])
2021-03-16 11:58:00 +01:00
if 'N' in PlanesObjects[p]['siblings']:
nSiblings += len(PlanesObjects[p]['siblings']['N'])
if 'E' in PlanesObjects[p]['siblings']:
nSiblings += len(PlanesObjects[p]['siblings']['E'])
if 'W' in PlanesObjects[p]['siblings']:
nSiblings += len(PlanesObjects[p]['siblings']['W'])
2021-03-16 11:58:00 +01:00
2021-03-16 16:18:05 +01:00
f.write("SIBLINGS node" + pName + "_siblings = {\n" +
2021-03-16 11:58:00 +01:00
"\t" + str(nSiblings) + ",\n" +
2021-03-15 12:44:15 +01:00
"\t{\n")
2021-03-15 15:02:26 +01:00
if 'siblings' in PlanesObjects[p]:
2021-03-15 12:44:15 +01:00
i = 0
2021-03-15 15:02:26 +01:00
for side in PlanesObjects[p]['siblings']:
2021-03-15 15:02:26 +01:00
for sibling in PlanesObjects[p]['siblings'][side]:
f.write("\t\t&node" + CleanName(sibling) )
if i < ( nSiblings - 1 ) :
f.write(",")
i += 1
f.write("\n")
2021-03-15 15:02:26 +01:00
else:
2021-03-18 19:21:40 +01:00
f.write("\t\t0\n")
2021-03-15 15:02:26 +01:00
2021-03-15 12:44:15 +01:00
f.write("\t}\n" +
"};\n\n")
2021-03-18 19:21:40 +01:00
# Write CHILDREN static objects structure
2021-03-15 12:44:15 +01:00
2021-03-16 16:18:05 +01:00
f.write("CHILDREN node" + pName + "_objects = {\n")
2021-03-15 12:44:15 +01:00
2021-03-15 15:02:26 +01:00
if 'objects' in PlanesObjects[p]:
2021-03-15 12:44:15 +01:00
2021-03-15 15:02:26 +01:00
f.write("\t" + str(len(PlanesObjects[p]['objects'])) + ",\n" +
"\t{\n")
i = 0
2021-03-15 15:02:26 +01:00
for obj in PlanesObjects[p]['objects']:
2021-03-15 12:44:15 +01:00
f.write( "\t\t&mesh" + CleanName(obj))
if i < len(PlanesObjects[p]['objects']) - 1:
f.write(",")
i += 1
f.write("\n")
2021-03-15 15:02:26 +01:00
else:
f.write("\t0,\n" +
"\t{\n\t\t0\n")
2021-03-15 15:02:26 +01:00
2021-03-15 12:44:15 +01:00
f.write("\t}\n" +
"};\n\n")
2021-03-18 19:21:40 +01:00
# Write CHILDREN rigidbodies structure
f.write("CHILDREN node" + pName + "_rigidbodies = {\n")
if 'rigidbodies' in PlanesRigidBodies[p]:
f.write("\t" + str(len(PlanesRigidBodies[p]['rigidbodies'])) + ",\n" +
"\t{\n")
i = 0
for obj in PlanesRigidBodies[p]['rigidbodies']:
2021-03-15 12:44:15 +01:00
2021-03-18 19:21:40 +01:00
f.write( "\t\t&mesh" + CleanName(obj))
if i < len(PlanesRigidBodies[p]['rigidbodies']) - 1:
f.write(",")
i += 1
f.write("\n")
else:
f.write("\t0,\n" +
"\t{\n\t\t0\n")
f.write("\t}\n" +
"};\n\n")
2021-03-15 12:44:15 +01:00
# Write NODE structure
f.write( "NODE node" + pName + " = {\n" +
"\t&mesh" + pName + ",\n" +
"\t&node" + pName + "_siblings,\n" +
2021-03-18 19:21:40 +01:00
"\t&node" + pName + "_objects,\n" +
"\t&node" + pName + "_rigidbodies\n" +
2021-03-15 12:44:15 +01:00
"};\n\n" )
2021-03-24 11:33:09 +01:00
f.write("MESH * actorPtr = &mesh" + CleanName(actorPtr) + ";\n")
f.write("MESH * levelPtr = &mesh" + CleanName(levelPtr) + ";\n")
f.write("MESH * propPtr = &mesh" + propPtr + ";\n\n")
f.write("CAMANGLE * camPtr = &camAngle_" + CleanName(defaultCam) + ";\n\n")
f.write("NODE * curNode = &node" + CleanName(nodePtr) + ";\n\n")
2021-03-12 12:13:08 +01:00
2021-03-12 13:06:21 +01:00
# Set default camera back in Blender
2021-03-12 11:21:18 +01:00
if defaultCam != 'NULL':
2021-03-12 13:06:21 +01:00
2021-03-31 20:28:02 +02:00
bpy.context.scene.camera = bpy.data.objects[ defaultCam ]
2021-03-12 11:21:18 +01:00
f.close()
2021-03-12 13:06:21 +01:00
return {'FINISHED'};
def menu_func(self, context):
2021-03-12 13:06:21 +01:00
self.layout.operator(ExportMyFormat.bl_idname, text="PSX Format(.c)");
def register():
2021-03-12 13:06:21 +01:00
bpy.utils.register_module(__name__);
2021-03-12 13:06:21 +01:00
bpy.types.INFO_MT_file_export.append(menu_func);
def unregister():
2021-03-12 13:06:21 +01:00
bpy.utils.unregister_module(__name__);
2021-03-12 13:06:21 +01:00
bpy.types.INFO_MT_file_export.remove(menu_func);
if __name__ == "__main__":
2021-03-12 13:06:21 +01:00
register()