add portals
This commit is contained in:
parent
7e7e524735
commit
39b660dbd8
@ -18,7 +18,7 @@ import bmesh
|
||||
|
||||
import unicodedata
|
||||
|
||||
from math import radians, degrees, floor, cos, sin
|
||||
from math import radians, degrees, floor, cos, sin, sqrt
|
||||
|
||||
from mathutils import Vector
|
||||
|
||||
@ -78,26 +78,6 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
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):
|
||||
|
||||
# Triangulate an object's mesh
|
||||
@ -129,6 +109,26 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
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):
|
||||
|
||||
# Checks if 'obj' has its coordinates contained between the plane's coordinate.
|
||||
@ -248,6 +248,48 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
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
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
@ -349,7 +391,9 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
"struct CAMANGLE;\n" +
|
||||
"struct SIBLINGS;\n" +
|
||||
"struct CHILDREN;\n" +
|
||||
"struct NODE;\n\n")
|
||||
"struct NODE;\n" +
|
||||
"struct QUAD;\n" +
|
||||
"\n")
|
||||
|
||||
# BODY
|
||||
|
||||
@ -382,7 +426,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
f.write("typedef struct PRIM {\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")
|
||||
|
||||
# MESH
|
||||
@ -408,16 +452,27 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
"\tBODY * body;\n" +
|
||||
"\tVANIM * anim;\n" +
|
||||
"\tstruct NODE * node;\n" +
|
||||
"\tSVECTOR pos2D;\n" +
|
||||
"\tVECTOR pos2D;\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
|
||||
|
||||
f.write("typedef struct CAMPOS {\n" +
|
||||
"\tVECTOR pos;\n" +
|
||||
"\tSVECTOR rot;\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
|
||||
|
||||
@ -425,6 +480,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
"\tCAMPOS * campos;\n" +
|
||||
"\tTIM_IMAGE * BGtim;\n" +
|
||||
"\tunsigned long * tim_data;\n" +
|
||||
"\tQUAD bw, fw;\n" +
|
||||
"\tint index;\n" +
|
||||
"\tMESH * objects[];\n" +
|
||||
"\t} CAMANGLE;\n\n")
|
||||
@ -656,6 +712,8 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
for m in bpy.data.meshes:
|
||||
|
||||
if not m.get('isPortal') :
|
||||
|
||||
# Store vertices coordinates by axis to find max/min coordinates
|
||||
|
||||
Xvals = []
|
||||
@ -1131,15 +1189,36 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
"\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)
|
||||
|
||||
if k != len(bpy.data.meshes) - 1:
|
||||
if k != len(meshList) - 1:
|
||||
|
||||
f.write(",\n")
|
||||
|
||||
@ -1153,9 +1232,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
"\t&camPos_" + CleanName(defaultCam) + ",\n" +
|
||||
|
||||
"\t0,\n" +
|
||||
|
||||
"\t0\n" +
|
||||
"\t0,\n 0,\n {0},\n {0},\n 0,\n 0\n" +
|
||||
|
||||
"};\n\n")
|
||||
|
||||
@ -1163,12 +1240,82 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
for camera in camAngles:
|
||||
|
||||
# Cast a ray from camera to each Rigid/Static body to determine visibility
|
||||
|
||||
# Get current 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
|
||||
|
||||
visibleTarget = []
|
||||
@ -1177,9 +1324,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
# Chech object is in view frame
|
||||
|
||||
inViewFrame = isInFrame(scene, camera, target)
|
||||
|
||||
if inViewFrame:
|
||||
if isInFrame(scene, camera, target):
|
||||
|
||||
# Get normalized direction vector between camera and object
|
||||
|
||||
@ -1188,7 +1333,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
dirToTarget.normalize()
|
||||
|
||||
# Cast ray from camera to object
|
||||
# Unpack results in several variables.
|
||||
# Unpack results into several variables.
|
||||
# We're only interested in 'hitObject' though
|
||||
|
||||
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:
|
||||
|
||||
print(camera.name + ":" + hitObject.name + " - " + target.name )
|
||||
|
||||
visibleTarget.append(target)
|
||||
|
||||
if bpy.data.objects[ actorPtr ] not in visibleTarget:
|
||||
|
||||
visibleTarget.append( bpy.data.objects[ actorPtr ] )
|
||||
|
||||
|
||||
prefix = CleanName(camera.name)
|
||||
|
||||
# Include Tim data
|
||||
@ -1227,7 +1375,33 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
"\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")
|
||||
|
||||
@ -1257,9 +1431,6 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
## Spatial Partitioning
|
||||
|
||||
# ToDo :
|
||||
# Auto-detect which plane the actor is on and set that as curNode
|
||||
|
||||
# Planes in the level - dict of strings
|
||||
|
||||
LvlPlanes = {}
|
||||
@ -1292,7 +1463,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
# Only loop through meshes
|
||||
|
||||
if o.type == 'MESH':
|
||||
if o.type == 'MESH' and not o.data.get('isPortal'):
|
||||
|
||||
# Get Level planes coordinates
|
||||
|
||||
@ -1326,7 +1497,6 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
|
||||
# For each object not a plane, get its coordinates
|
||||
|
||||
# ~ if not o.data.get('isLevel'):
|
||||
if not o.data.get('isLevel'):
|
||||
|
||||
# World matrix is used to convert local to global coordinates
|
||||
@ -1416,7 +1586,7 @@ class ExportMyFormat(bpy.types.Operator, ExportHelper):
|
||||
levelPtr = p
|
||||
nodePtr = p
|
||||
|
||||
# Add actor in every plane
|
||||
# Add moveable objects in every plane
|
||||
|
||||
for moveable in Moveables:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user