514 lines
14 KiB
Plaintext
514 lines
14 KiB
Plaintext
|
|
-------------------------------------------------------------------------------------
|
|
utility bluExport "BluFlame v0.2 Export"
|
|
(
|
|
-- Define variables that are visible to all functions in the utility
|
|
local ostream, tabs = ""
|
|
local version = 2
|
|
local usedMaterials = #()
|
|
|
|
-- Define the GUI interface
|
|
group "Options"
|
|
(
|
|
checkbox cb_exportSelOnly "Export Selected Only"
|
|
)
|
|
button btn_export "Save As..." width:100
|
|
|
|
------------------------------------------------------------------------------------
|
|
function computeTangent obj =
|
|
(
|
|
local theMesh = snapshotAsMesh obj
|
|
|
|
local tSpace = #()
|
|
|
|
-- Do we have to flip faces?
|
|
local flip = false
|
|
local indices = #(1, 2, 3)
|
|
if dot (cross obj.transform.row1 obj.transform.row2) obj.transform.row3 <= 0 do
|
|
(
|
|
indices[2] = 3
|
|
indices[3] = 2
|
|
flip = true
|
|
)
|
|
|
|
for nFace = 1 to theMesh.numFaces do
|
|
(
|
|
local face = getFace theMesh nFace
|
|
local tface = getTVFace theMesh nFace
|
|
|
|
local v1 = getVert theMesh face[indices[1]]
|
|
local v2 = getVert theMesh face[indices[2]]
|
|
local v3 = getVert theMesh face[indices[3]]
|
|
|
|
local uv1 = getTVert theMesh tface[indices[1]]
|
|
local uv2 = getTVert theMesh tface[indices[2]]
|
|
local uv3 = getTVert theMesh tface[indices[3]]
|
|
|
|
local dV1 = v1 - v2
|
|
local dV2 = v1 - v3
|
|
|
|
local dUV1 = uv1 - uv2
|
|
local dUV2 = uv1 - uv3
|
|
|
|
local area = dUV1.x * dUV2.y - dUV1.y * dUV2.x
|
|
local sign = if area < 0 then -1 else 1
|
|
|
|
local tangent = [0,0,1]
|
|
|
|
tangent.x = dV1.x * dUV2.y - dUV1.y * dV2.x
|
|
tangent.y = dV1.y * dUV2.y - dUV1.y * dV2.y
|
|
tangent.z = dV1.z * dUV2.y - dUV1.y * dV2.z
|
|
|
|
tangent = (normalize tangent) * sign
|
|
|
|
append tSpace tangent
|
|
)
|
|
|
|
delete theMesh
|
|
|
|
return tSpace
|
|
)
|
|
|
|
function AddMaterialToList inmaterial =
|
|
(
|
|
local canadd = true
|
|
for mat in usedMaterials do
|
|
(
|
|
if mat == inmaterial then
|
|
(
|
|
canadd = false
|
|
break
|
|
)
|
|
)
|
|
if canadd then
|
|
(
|
|
append usedMaterials inmaterial
|
|
)
|
|
)
|
|
|
|
-------------------------------------------------------------------------------------
|
|
-- This function exports a bones object to the BLU file.
|
|
function ExportNodeAnimation node =
|
|
(
|
|
-- animation header
|
|
writelong ostream 3 -- 3: animation
|
|
writestring ostream node.name
|
|
|
|
-- position
|
|
writelong ostream node.position.controller.keys.count #unsigned
|
|
for i = 1 to node.position.controller.keys.count do
|
|
(
|
|
writefloat ostream (node.position.controller.keys[i].time / 30.0)
|
|
|
|
if node.parent != undefined then
|
|
trans = in coordsys node.parent [node.pos.x_position.controller.keys[i].value, node.pos.y_position.controller.keys[i].value, node.pos.z_position.controller.keys[i].value]
|
|
else
|
|
trans = in coordsys world [node.pos.x_position.controller.keys[i].value, node.pos.y_position.controller.keys[i].value, node.pos.z_position.controller.keys[i].value]
|
|
|
|
writefloat ostream trans.x
|
|
writefloat ostream trans.y
|
|
writefloat ostream trans.z
|
|
)
|
|
|
|
-- scale
|
|
writelong ostream node.scale.controller.keys.count #unsigned
|
|
for i = 1 to node.scale.controller.keys.count do
|
|
(
|
|
writefloat ostream (node.scale.controller.keys[i].time / 30.0)
|
|
|
|
writefloat ostream node.scale.controller.keys[i].value.x
|
|
writefloat ostream node.scale.controller.keys[i].value.y
|
|
writefloat ostream node.scale.controller.keys[i].value.z
|
|
)
|
|
|
|
-- rotation
|
|
writelong ostream node.rotation.controller.keys.count #unsigned
|
|
for i = 1 to node.rotation.controller.keys.count do
|
|
(
|
|
writefloat ostream (node.rotation.controller.keys[i].time / 30.0)
|
|
|
|
writefloat ostream node.rotation.x_rotation.controller.keys[i].value
|
|
writefloat ostream node.rotation.y_rotation.controller.keys[i].value
|
|
writefloat ostream node.rotation.z_rotation.controller.keys[i].value
|
|
)
|
|
)
|
|
|
|
-------------------------------------------------------------------------------------
|
|
-- This function exports a bones object to the BLU file.
|
|
function ExportBone bone =
|
|
(
|
|
-- bone header
|
|
writelong ostream 2 -- 2: bone
|
|
writestring ostream bone.name
|
|
|
|
if bone.parent != undefined then
|
|
writestring ostream bone.parent.name
|
|
else
|
|
writestring ostream ""
|
|
|
|
-- Translation (IN PARENT SPACE)--
|
|
if bone.parent != undefined then
|
|
trans = in coordsys parent at time 0.0 bone.pos
|
|
else
|
|
trans = in coordsys world at time 0.0 bone.pos
|
|
writefloat ostream trans.x
|
|
writefloat ostream trans.y
|
|
writefloat ostream trans.z
|
|
|
|
print "bone:"
|
|
print trans
|
|
|
|
-- Rotation (IN PARENT SPACE)--
|
|
rot = in coordsys parent bone.rotation at time 0.0
|
|
writefloat ostream rot.x
|
|
writefloat ostream rot.y
|
|
writefloat ostream rot.z
|
|
writefloat ostream rot.w
|
|
|
|
-- Scale --
|
|
sca = bone.scale at time 0.0
|
|
writefloat ostream sca.x
|
|
writefloat ostream sca.y
|
|
writefloat ostream sca.z
|
|
)
|
|
|
|
-------------------------------------------------------------------------------------
|
|
-- This function exports a material object to the BLU file.
|
|
function ExportMaterial mat =
|
|
(
|
|
-- material header
|
|
writelong ostream 1 -- 1: material
|
|
writestring ostream mat.name
|
|
|
|
if classof mat.diffusemap == Bitmaptexture and mat.diffuseMapenable then
|
|
writestring ostream mat.diffuseMap.bitmap.filename
|
|
else
|
|
writestring ostream ""
|
|
|
|
if classof mat.specularmap == Bitmaptexture and mat.specularmapenable then
|
|
writestring ostream mat.specularmap .bitmap.filename
|
|
else
|
|
writestring ostream ""
|
|
|
|
if classof mat.bumpmap == Bitmaptexture and mat.bumpmapenable then
|
|
writestring ostream mat.bumpmap .bitmap.filename
|
|
else
|
|
writestring ostream ""
|
|
|
|
if classof mat.SelfIllumMap == Bitmaptexture and mat.SelfIllumMapenable then
|
|
writestring ostream mat.SelfIllumMap.bitmap.filename
|
|
else
|
|
writestring ostream ""
|
|
|
|
if classof mat.reflectionmap == Bitmaptexture and mat.reflectionmapenable then
|
|
writestring ostream mat.reflectionmap.bitmap.filename
|
|
else
|
|
writestring ostream ""
|
|
|
|
writefloat ostream mat.ambient.r
|
|
writefloat ostream mat.ambient.g
|
|
writefloat ostream mat.ambient.b
|
|
writefloat ostream mat.ambient.a
|
|
|
|
writefloat ostream mat.diffuse.r
|
|
writefloat ostream mat.diffuse.g
|
|
writefloat ostream mat.diffuse.b
|
|
writefloat ostream mat.diffuse.a
|
|
|
|
writefloat ostream mat.specular.r
|
|
writefloat ostream mat.specular.g
|
|
writefloat ostream mat.specular.b
|
|
writefloat ostream mat.specular.a
|
|
|
|
if (mat.selfIllumAmount > 0) then
|
|
(
|
|
writefloat ostream mat.selfIllumAmount
|
|
writefloat ostream mat.selfIllumAmount
|
|
writefloat ostream mat.selfIllumAmount
|
|
writefloat ostream mat.selfIllumAmount
|
|
)
|
|
else
|
|
(
|
|
writefloat ostream mat.selfIllumColor.r
|
|
writefloat ostream mat.selfIllumColor.g
|
|
writefloat ostream mat.selfIllumColor.b
|
|
writefloat ostream mat.selfIllumColor.a
|
|
)
|
|
|
|
writefloat ostream mat.specularlevel
|
|
writefloat ostream mat.glossiness
|
|
)
|
|
|
|
|
|
-------------------------------------------------------------------------------------
|
|
-- This function exports a geometry object to the BLU file.
|
|
function ExportMesh node meshObj name =
|
|
(
|
|
local isSkin = (node.modifiers["skin"] != undefined)
|
|
if isSkin then
|
|
(
|
|
max modify mode
|
|
modPanel.setCurrentObject node.modifiers["skin"]
|
|
)
|
|
|
|
-- mesh header
|
|
writelong ostream 0 -- 0: mesh
|
|
writestring ostream name
|
|
|
|
if meshObj.material != undefined then
|
|
(
|
|
writestring ostream meshObj.material.name
|
|
AddMaterialToList meshObj.material
|
|
)
|
|
else
|
|
(
|
|
writestring ostream ""
|
|
)
|
|
|
|
-- vertex count
|
|
writelong ostream meshObj.numVerts #unsigned
|
|
|
|
-- vertex elements
|
|
-- 0: Position2D
|
|
-- 1: Position3D
|
|
-- 2: Position4D
|
|
-- 3: Normal
|
|
-- 4: ColorRGB
|
|
-- 5: ColorARGB
|
|
-- 6: ColorRGBf
|
|
-- 7: ColorARGBf
|
|
-- 8: Texture2D
|
|
-- 9: Texture3D
|
|
-- 10: Texture4D
|
|
-- 11: Tangent3D
|
|
-- 12: Tangent4D
|
|
-- 13: BlendIndices
|
|
-- 14: BlendWeights
|
|
|
|
local numVElements = 3
|
|
|
|
if meshObj.material != undefined and meshObj.material.bumpmapenable then
|
|
numVElements += 1
|
|
if isSkin then
|
|
numVElements += 2 -- blendindicies and weights
|
|
|
|
writelong ostream numVElements -- number of vertexelements
|
|
|
|
writelong ostream 1
|
|
writelong ostream 3
|
|
writelong ostream 8
|
|
|
|
PerFaceTangents = #()
|
|
if meshObj.material != undefined and meshObj.material.bumpmapenable then
|
|
(
|
|
writelong ostream 11 -- tangent
|
|
PerFaceTangents = computeTangent meshObj
|
|
)
|
|
if isSkin then
|
|
(
|
|
writelong ostream 13 -- BlendIndices
|
|
writelong ostream 14 -- BlendWeights
|
|
)
|
|
|
|
local hasTooMuchBonesPerVertex = false
|
|
for i = 1 to meshObj.numVerts do
|
|
(
|
|
vert = ((GetVert meshObj i)-meshObj.pos)
|
|
writefloat ostream vert.x
|
|
writefloat ostream vert.y
|
|
writefloat ostream vert.z
|
|
|
|
normal = GetNormal meshObj i
|
|
writefloat ostream normal.x
|
|
writefloat ostream normal.y
|
|
writefloat ostream normal.z
|
|
|
|
uvw = GetTVert meshObj i
|
|
writefloat ostream uvw.x
|
|
writefloat ostream uvw.y
|
|
|
|
-- tangent
|
|
if meshObj.material != undefined and meshObj.material.bumpmapenable then
|
|
(
|
|
local vertfaces = meshop.getFacesUsingVert meshObj #{i}
|
|
local tangent = 0;
|
|
for face in vertfaces do
|
|
(
|
|
tangent += PerFaceTangents[face]
|
|
)
|
|
tangent = (normalize tangent)
|
|
writefloat ostream tangent.x
|
|
writefloat ostream tangent.y
|
|
writefloat ostream tangent.z
|
|
)
|
|
|
|
if isSkin then
|
|
(
|
|
local bone_idA = 0
|
|
local weightA = 0.0
|
|
local bone_idB = 0
|
|
local weightB = 0.0
|
|
local bone_idC = 0
|
|
local weightC = 0.0
|
|
local bone_idD = 0
|
|
local weightD = 0.0
|
|
|
|
if (skinops.getVertexWeightCount node.skin i > 0) then
|
|
(
|
|
local bone_idA = skinops.getVertexWeightBoneID node.skin i 1
|
|
local weightA = skinops.getVertexWeight node.skin i 1
|
|
)
|
|
if (skinops.getVertexWeightCount node.skin i > 1) then
|
|
(
|
|
local bone_idB = skinops.getVertexWeightBoneID node.skin i 2
|
|
local weightB = skinops.getVertexWeight node.skin i 2
|
|
)
|
|
if (skinops.getVertexWeightCount node.skin i > 2) then
|
|
(
|
|
local bone_idC = skinops.getVertexWeightBoneID node.skin i 3
|
|
local weightC = skinops.getVertexWeight node.skin i 3
|
|
)
|
|
if (skinops.getVertexWeightCount node.skin i > 3) then
|
|
(
|
|
local bone_idD = skinops.getVertexWeightBoneID node.skin i 4
|
|
local weightD = skinops.getVertexWeight node.skin i 4
|
|
)
|
|
if (skinops.getVertexWeightCount node.skin i > 4) then
|
|
hasTooMuchBonesPerVertex = true
|
|
|
|
writefloat ostream (bone_idA - 1)
|
|
writefloat ostream (bone_idB - 1)
|
|
writefloat ostream (bone_idC - 1)
|
|
writefloat ostream (bone_idD - 1)
|
|
|
|
writefloat ostream weightA
|
|
writefloat ostream weightB
|
|
writefloat ostream weightC
|
|
writefloat ostream weightD
|
|
)
|
|
)
|
|
|
|
writelong ostream (meshObj.numFaces * 3) #unsigned
|
|
|
|
|
|
for i = 1 to meshObj.numFaces do
|
|
(
|
|
poly = GetFace meshObj i
|
|
writelong ostream (poly.x as integer -1) #unsigned
|
|
writelong ostream (poly.y as integer -1) #unsigned
|
|
writelong ostream (poly.z as integer -1) #unsigned
|
|
)
|
|
|
|
if hasTooMuchBonesPerVertex then
|
|
MessageBox (name + " has too much bones per vertex.")
|
|
)
|
|
|
|
-------------------------------------------------------------------------------------
|
|
-- This function is called once per node in the scene.
|
|
-- A node in Max may be all sorts of things. We are only interested in geometry.
|
|
function ExportNode node =
|
|
(
|
|
-- Create node and export class specific data
|
|
if SuperClassOf node == GeometryClass and ClassOf node == BoneGeometry then
|
|
(
|
|
ExportBone node
|
|
)
|
|
else if SuperClassOf node == GeometryClass and ClassOf node == Editable_mesh then
|
|
(
|
|
ExportMesh node node node.name
|
|
)
|
|
else if SuperClassOf node == GeometryClass then
|
|
(
|
|
-- Build a mesh out of this object and save it
|
|
local temp = copy node
|
|
convertToMesh temp
|
|
if SuperClassOf temp == GeometryClass and ClassOf temp == Editable_mesh then
|
|
(
|
|
ExportMesh node temp node.name
|
|
)
|
|
|
|
delete temp
|
|
)
|
|
else -- Not geometry.. could be a camera, light, etc.
|
|
return false
|
|
|
|
if (node.position.controller.keys.count > 0 or
|
|
node.scale.controller.keys.count > 0 or
|
|
node.rotation.controller.keys.count > 0) then
|
|
(
|
|
ExportNodeAnimation node
|
|
)
|
|
|
|
return true
|
|
)
|
|
|
|
-------------------------------------------------------------------------------------
|
|
-- This function recurses down the node hierarchy calling ExportNode for each node.
|
|
function RecursiveExportNode node =
|
|
(
|
|
if (ExportNode node) == false then
|
|
return false
|
|
|
|
-- Recurse children before writing this node
|
|
for child in node.children do
|
|
RecursiveExportNode child
|
|
)
|
|
-------------------------------------------------------------------------------------
|
|
-- The highest level function called to export an BLU file.
|
|
function ExportBLU =
|
|
(
|
|
-- Write the BLU header
|
|
|
|
writestring ostream "BLUF"
|
|
writelong ostream version
|
|
|
|
if cb_exportSelOnly.checked then
|
|
(
|
|
for node in selection do
|
|
ExportNode node
|
|
)
|
|
else
|
|
(
|
|
for node in rootnode.children do
|
|
RecursiveExportNode node
|
|
)
|
|
|
|
for mat in usedMaterials do
|
|
(
|
|
ExportMaterial mat
|
|
)
|
|
|
|
)
|
|
-------------------------------------------------------------------------------------
|
|
-- Open an prepare a file handle for writing.
|
|
function GetSaveFileStream =
|
|
(
|
|
fname = GetSaveFileName types:"BLU (*.blu)|*.blu|All Files(*.*)|*.*|"
|
|
if fname == undefined then
|
|
return undefined
|
|
|
|
ostream = fopen fname "wbS" -- CreateFile fname
|
|
if ostream == undefined then
|
|
(
|
|
MessageBox "Couldn't open file for writing!"
|
|
return undefined
|
|
)
|
|
|
|
return ostream
|
|
)
|
|
|
|
-------------------------------------------------------------------------------------
|
|
-- This is the function called when the user activates the utility by pressing on
|
|
-- the export button. It opens the file and calls the export routine.
|
|
on btn_export pressed do
|
|
(
|
|
ostream = GetSaveFileStream()
|
|
if ostream != undefined then
|
|
(
|
|
ExportBLU()
|
|
fclose ostream
|
|
)
|
|
)
|
|
|
|
) -- End BLUExport
|