add portals
This commit is contained in:
parent
7e7e524735
commit
39b660dbd8
@ -18,7 +18,7 @@ import bmesh
|
|||||||
|
|
||||||
import unicodedata
|
import unicodedata
|
||||||
|
|
||||||
from math import radians, degrees, floor, cos, sin
|
from math import radians, degrees, floor, cos, sin, sqrt
|
||||||
|
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
|
|
||||||
@ -78,26 +78,6 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
def triangulate_object(obj):
|
def triangulate_object(obj):
|
||||||
|
|
||||||
# Triangulate an object's mesh
|
# Triangulate an object's mesh
|
||||||
@ -129,6 +109,26 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
def isInPlane(plane, obj):
|
def isInPlane(plane, obj):
|
||||||
|
|
||||||
# Checks if 'obj' has its coordinates contained between the plane's coordinate.
|
# Checks if 'obj' has its coordinates contained between the plane's coordinate.
|
||||||
@ -248,6 +248,48 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
return "intersect"
|
return "intersect"
|
||||||
|
|
||||||
|
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 ) ) )
|
||||||
|
|
||||||
|
vector.y = max ( 0, min ( resY, int( resY * vector.y ) ) )
|
||||||
|
|
||||||
|
vector.z = int( vector.z )
|
||||||
|
|
||||||
|
return screenPos
|
||||||
|
|
||||||
# Leave edit mode to avoid errors
|
# Leave edit mode to avoid errors
|
||||||
|
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
@ -349,7 +391,9 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
"struct CAMANGLE;\n" +
|
"struct CAMANGLE;\n" +
|
||||||
"struct SIBLINGS;\n" +
|
"struct SIBLINGS;\n" +
|
||||||
"struct CHILDREN;\n" +
|
"struct CHILDREN;\n" +
|
||||||
"struct NODE;\n\n")
|
"struct NODE;\n" +
|
||||||
|
"struct QUAD;\n" +
|
||||||
|
"\n")
|
||||||
|
|
||||||
# BODY
|
# BODY
|
||||||
|
|
||||||
@ -382,7 +426,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
f.write("typedef struct PRIM {\n" +
|
f.write("typedef struct PRIM {\n" +
|
||||||
"\tVECTOR order;\n" +
|
"\tVECTOR order;\n" +
|
||||||
"\tint code; // Same as POL3/POL4 codes : Code (F3 = 1, FT3 = 2, G3 = 3, GT3 = 4) Code (F4 = 5, FT4 = 6, G4 = 7, GT4 = 8)\n" +
|
"\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" +
|
||||||
"\t} PRIM;\n\n")
|
"\t} PRIM;\n\n")
|
||||||
|
|
||||||
# MESH
|
# MESH
|
||||||
@ -408,16 +452,27 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
"\tBODY * body;\n" +
|
"\tBODY * body;\n" +
|
||||||
"\tVANIM * anim;\n" +
|
"\tVANIM * anim;\n" +
|
||||||
"\tstruct NODE * node;\n" +
|
"\tstruct NODE * node;\n" +
|
||||||
"\tSVECTOR pos2D;\n" +
|
"\tVECTOR pos2D;\n" +
|
||||||
"\t} MESH;\n\n")
|
"\t} MESH;\n\n")
|
||||||
|
|
||||||
|
#QUAD
|
||||||
|
|
||||||
|
f.write("typedef struct QUAD {\n" +
|
||||||
|
"\tVECTOR v0, v1;\n" +
|
||||||
|
"\tVECTOR v2, v3;\n" +
|
||||||
|
"\t} QUAD;\n\n")
|
||||||
|
|
||||||
# CAMPOS
|
# CAMPOS
|
||||||
|
|
||||||
f.write("typedef struct CAMPOS {\n" +
|
f.write("typedef struct CAMPOS {\n" +
|
||||||
"\tVECTOR pos;\n" +
|
"\tVECTOR pos;\n" +
|
||||||
"\tSVECTOR rot;\n" +
|
"\tSVECTOR rot;\n" +
|
||||||
"\t} CAMPOS;\n\n" +
|
"\t} CAMPOS;\n\n" +
|
||||||
"\n// Blender cam ~= PSX cam with these settings : NTSC - 320x240, PAL 320x256, pixel ratio 1:1, cam focal length : perspective 90° ( 16 mm ))\n\n")
|
"\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")
|
||||||
|
|
||||||
# CAMANGLE
|
# CAMANGLE
|
||||||
|
|
||||||
@ -425,6 +480,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
"\tCAMPOS * campos;\n" +
|
"\tCAMPOS * campos;\n" +
|
||||||
"\tTIM_IMAGE * BGtim;\n" +
|
"\tTIM_IMAGE * BGtim;\n" +
|
||||||
"\tunsigned long * tim_data;\n" +
|
"\tunsigned long * tim_data;\n" +
|
||||||
|
"\tQUAD bw, fw;\n" +
|
||||||
"\tint index;\n" +
|
"\tint index;\n" +
|
||||||
"\tMESH * objects[];\n" +
|
"\tMESH * objects[];\n" +
|
||||||
"\t} CAMANGLE;\n\n")
|
"\t} CAMANGLE;\n\n")
|
||||||
@ -656,6 +712,8 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
for m in bpy.data.meshes:
|
for m in bpy.data.meshes:
|
||||||
|
|
||||||
|
if not m.get('isPortal') :
|
||||||
|
|
||||||
# Store vertices coordinates by axis to find max/min coordinates
|
# Store vertices coordinates by axis to find max/min coordinates
|
||||||
|
|
||||||
Xvals = []
|
Xvals = []
|
||||||
@ -1131,15 +1189,36 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
"\n};\n\n"
|
"\n};\n\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
f.write("MESH * meshes[" + str(len(bpy.data.meshes)) + "] = {\n")
|
# Remove portals from mesh list as we don't want them to be exported
|
||||||
|
|
||||||
for k in range(len(bpy.data.meshes)):
|
meshList = list(bpy.data.meshes)
|
||||||
|
|
||||||
cleanName = CleanName(bpy.data.meshes[k].name)
|
portalList = []
|
||||||
|
|
||||||
|
for mesh in meshList:
|
||||||
|
|
||||||
|
if mesh.get('isPortal'):
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
portalList.append( bpy.data.objects[mesh.name] )
|
||||||
|
|
||||||
|
f.write("MESH * meshes[" + str(len(meshList)) + "] = {\n")
|
||||||
|
|
||||||
|
for k in range(len(meshList)):
|
||||||
|
|
||||||
|
cleanName = CleanName(meshList[k].name)
|
||||||
|
|
||||||
f.write("\t&mesh" + cleanName)
|
f.write("\t&mesh" + cleanName)
|
||||||
|
|
||||||
if k != len(bpy.data.meshes) - 1:
|
if k != len(meshList) - 1:
|
||||||
|
|
||||||
f.write(",\n")
|
f.write(",\n")
|
||||||
|
|
||||||
@ -1153,9 +1232,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
"\t&camPos_" + CleanName(defaultCam) + ",\n" +
|
"\t&camPos_" + CleanName(defaultCam) + ",\n" +
|
||||||
|
|
||||||
"\t0,\n" +
|
"\t0,\n 0,\n {0},\n {0},\n 0,\n 0\n" +
|
||||||
|
|
||||||
"\t0\n" +
|
|
||||||
|
|
||||||
"};\n\n")
|
"};\n\n")
|
||||||
|
|
||||||
@ -1163,12 +1240,82 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
for camera in camAngles:
|
for camera in camAngles:
|
||||||
|
|
||||||
# Cast a ray from camera to each Rigid/Static body to determine visibility
|
|
||||||
|
|
||||||
# Get current scene
|
# Get current scene
|
||||||
|
|
||||||
scene = bpy.context.scene
|
scene = bpy.context.scene
|
||||||
|
|
||||||
|
# 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 ) )
|
||||||
|
|
||||||
# List of target found visible
|
# List of target found visible
|
||||||
|
|
||||||
visibleTarget = []
|
visibleTarget = []
|
||||||
@ -1177,9 +1324,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
# Chech object is in view frame
|
# Chech object is in view frame
|
||||||
|
|
||||||
inViewFrame = isInFrame(scene, camera, target)
|
if isInFrame(scene, camera, target):
|
||||||
|
|
||||||
if inViewFrame:
|
|
||||||
|
|
||||||
# Get normalized direction vector between camera and object
|
# Get normalized direction vector between camera and object
|
||||||
|
|
||||||
@ -1188,7 +1333,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
dirToTarget.normalize()
|
dirToTarget.normalize()
|
||||||
|
|
||||||
# Cast ray from camera to object
|
# Cast ray from camera to object
|
||||||
# Unpack results in several variables.
|
# Unpack results into several variables.
|
||||||
# We're only interested in 'hitObject' though
|
# We're only interested in 'hitObject' though
|
||||||
|
|
||||||
result, location, normal, index, hitObject, matrix = scene.ray_cast( camera.location, dirToTarget )
|
result, location, normal, index, hitObject, matrix = scene.ray_cast( camera.location, dirToTarget )
|
||||||
@ -1199,10 +1344,13 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
if hitObject in rayTargets:
|
if hitObject in rayTargets:
|
||||||
|
|
||||||
print(camera.name + ":" + hitObject.name + " - " + target.name )
|
|
||||||
|
|
||||||
visibleTarget.append(target)
|
visibleTarget.append(target)
|
||||||
|
|
||||||
|
if bpy.data.objects[ actorPtr ] not in visibleTarget:
|
||||||
|
|
||||||
|
visibleTarget.append( bpy.data.objects[ actorPtr ] )
|
||||||
|
|
||||||
|
|
||||||
prefix = CleanName(camera.name)
|
prefix = CleanName(camera.name)
|
||||||
|
|
||||||
# Include Tim data
|
# Include Tim data
|
||||||
@ -1227,7 +1375,33 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
"\t_binary_TIM_bg_" + prefix + "_tim_start,\n" +
|
"\t_binary_TIM_bg_" + prefix + "_tim_start,\n" +
|
||||||
|
|
||||||
"\t" + str( len( visibleTarget ) ) + ",\n" +
|
"\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:
|
||||||
|
|
||||||
|
s = objVertWtoS( scene, camera, portal )
|
||||||
|
|
||||||
|
# Write quad NW, NE, SE, SW
|
||||||
|
|
||||||
|
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" )
|
||||||
|
|
||||||
|
f.write("\t" + str( len( visibleTarget ) ) + ",\n" +
|
||||||
|
|
||||||
"\t{\n")
|
"\t{\n")
|
||||||
|
|
||||||
@ -1257,9 +1431,6 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
## Spatial Partitioning
|
## Spatial Partitioning
|
||||||
|
|
||||||
# ToDo :
|
|
||||||
# Auto-detect which plane the actor is on and set that as curNode
|
|
||||||
|
|
||||||
# Planes in the level - dict of strings
|
# Planes in the level - dict of strings
|
||||||
|
|
||||||
LvlPlanes = {}
|
LvlPlanes = {}
|
||||||
@ -1292,7 +1463,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
# Only loop through meshes
|
# Only loop through meshes
|
||||||
|
|
||||||
if o.type == 'MESH':
|
if o.type == 'MESH' and not o.data.get('isPortal'):
|
||||||
|
|
||||||
# Get Level planes coordinates
|
# Get Level planes coordinates
|
||||||
|
|
||||||
@ -1326,7 +1497,6 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
# For each object not a plane, get its coordinates
|
# For each object not a plane, get its coordinates
|
||||||
|
|
||||||
# ~ if not o.data.get('isLevel'):
|
|
||||||
if not o.data.get('isLevel'):
|
if not o.data.get('isLevel'):
|
||||||
|
|
||||||
# World matrix is used to convert local to global coordinates
|
# World matrix is used to convert local to global coordinates
|
||||||
@ -1416,7 +1586,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
levelPtr = p
|
levelPtr = p
|
||||||
nodePtr = p
|
nodePtr = p
|
||||||
|
|
||||||
# Add actor in every plane
|
# Add moveable objects in every plane
|
||||||
|
|
||||||
for moveable in Moveables:
|
for moveable in Moveables:
|
||||||
|
|
||||||
@ -1617,7 +1787,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
|||||||
|
|
||||||
if defaultCam != 'NULL':
|
if defaultCam != 'NULL':
|
||||||
|
|
||||||
bpy.context.scene.camera = bpy.data.objects[defaultCam]
|
bpy.context.scene.camera = bpy.data.objects[ defaultCam ]
|
||||||
|
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user