mirror of
https://github.com/MapMakersAndProgrammers/io_scene_a3d.git
synced 2025-10-26 01:49:13 -07:00
Initial lightmapdata import
This commit is contained in:
@@ -30,7 +30,7 @@ from mathutils import Matrix
|
|||||||
|
|
||||||
from .A3D import A3D
|
from .A3D import A3D
|
||||||
from .A3DBlenderImporter import A3DBlenderImporter
|
from .A3DBlenderImporter import A3DBlenderImporter
|
||||||
from .BlenderMaterialUtils import addImageTextureToMaterial
|
from .BlenderMaterialUtils import addImageTextureToMaterial, decodeIntColorToTuple
|
||||||
|
|
||||||
class Prop:
|
class Prop:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -150,8 +150,9 @@ class BattleMapBlenderImporter:
|
|||||||
# Allows subsequent map loads to be faster
|
# Allows subsequent map loads to be faster
|
||||||
libraryCache = {}
|
libraryCache = {}
|
||||||
|
|
||||||
def __init__(self, mapData, propLibrarySourcePath, import_static_geom=True, import_collision_geom=False, import_spawn_points=False):
|
def __init__(self, mapData, lightmapData, propLibrarySourcePath, import_static_geom=True, import_collision_geom=False, import_spawn_points=False):
|
||||||
self.mapData = mapData
|
self.mapData = mapData
|
||||||
|
self.lightmapData = lightmapData
|
||||||
self.propLibrarySourcePath = propLibrarySourcePath
|
self.propLibrarySourcePath = propLibrarySourcePath
|
||||||
self.import_static_geom = import_static_geom
|
self.import_static_geom = import_static_geom
|
||||||
self.import_collision_geom = import_collision_geom
|
self.import_collision_geom = import_collision_geom
|
||||||
@@ -211,6 +212,26 @@ class BattleMapBlenderImporter:
|
|||||||
for ob in spawnPointObjects:
|
for ob in spawnPointObjects:
|
||||||
ob.parent = groupOB
|
ob.parent = groupOB
|
||||||
|
|
||||||
|
# Create a sun light object
|
||||||
|
li = bpy.data.lights.new("DirectionalLight", "SUN")
|
||||||
|
li.color = decodeIntColorToTuple(self.lightmapData.lightColour)
|
||||||
|
|
||||||
|
ob = bpy.data.objects.new(li.name, li)
|
||||||
|
ob.location = (0.0, 0.0, 1000.0) # Just place it like 10 meters off the ground (in alternativa units)
|
||||||
|
lightAngleX, lightAngleZ = self.lightmapData.lightAngle
|
||||||
|
ob.rotation_mode = "XYZ"
|
||||||
|
ob.rotation_euler = (lightAngleX, 0.0, lightAngleZ)
|
||||||
|
objects.append(ob)
|
||||||
|
|
||||||
|
# Set ambient world light
|
||||||
|
scene = bpy.context.scene
|
||||||
|
if scene.world == None:
|
||||||
|
wd = bpy.data.worlds.new("map")
|
||||||
|
scene.world = wd
|
||||||
|
world = scene.world
|
||||||
|
world.use_nodes = False
|
||||||
|
world.color = decodeIntColorToTuple(self.lightmapData.ambientLightColour)
|
||||||
|
|
||||||
return objects
|
return objects
|
||||||
|
|
||||||
def getPropLibrary(self, libraryName):
|
def getPropLibrary(self, libraryName):
|
||||||
@@ -253,6 +274,16 @@ class BattleMapBlenderImporter:
|
|||||||
propScale = (1.0, 1.0, 1.0)
|
propScale = (1.0, 1.0, 1.0)
|
||||||
propOB.scale = propScale
|
propOB.scale = propScale
|
||||||
|
|
||||||
|
# Lighting info
|
||||||
|
lightingMapObject = None
|
||||||
|
for mapObject in self.lightmapData.mapObjects:
|
||||||
|
if mapObject.index == propData.ID:
|
||||||
|
lightingMapObject = mapObject
|
||||||
|
break
|
||||||
|
if lightingMapObject != None:
|
||||||
|
#XXX: do something with lightingMapObject.recieveShadows??
|
||||||
|
propOB.visible_shadow = lightingMapObject.castShadows
|
||||||
|
|
||||||
# Material
|
# Material
|
||||||
ma = self.materials[propData.materialID]
|
ma = self.materials[propData.materialID]
|
||||||
if len(propOB.data.materials) != 0:
|
if len(propOB.data.materials) != 0:
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from bpy.types import ShaderNodeBsdfPrincipled
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Functions
|
Functions
|
||||||
'''
|
'''
|
||||||
@@ -41,4 +39,13 @@ def addImageTextureToMaterial(image, node_tree, linkAlpha=False):
|
|||||||
links.new(textureNode.outputs["Alpha"], bsdfNode.inputs["Alpha"])
|
links.new(textureNode.outputs["Alpha"], bsdfNode.inputs["Alpha"])
|
||||||
|
|
||||||
# Apply image
|
# Apply image
|
||||||
if image != None: textureNode.image = image
|
if image != None: textureNode.image = image
|
||||||
|
|
||||||
|
def decodeIntColorToTuple(intColor):
|
||||||
|
# Fromat is argb
|
||||||
|
a = (intColor >> 24) & 255
|
||||||
|
r = (intColor >> 16) & 255
|
||||||
|
g = (intColor >> 8) & 255
|
||||||
|
b = intColor & 255
|
||||||
|
|
||||||
|
return (r/255, g/255, b/255)
|
||||||
113
io_scene_a3d/LightmapData.py
Normal file
113
io_scene_a3d/LightmapData.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
'''
|
||||||
|
Copyright (c) 2025 Pyogenics <https://github.com/Pyogenics>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
'''
|
||||||
|
|
||||||
|
from .IOTools import unpackStream
|
||||||
|
from . import AlternativaProtocol
|
||||||
|
|
||||||
|
class LightmapData:
|
||||||
|
def __init__(self):
|
||||||
|
self.lightColour = (0.0, 0.0, 0.0)
|
||||||
|
self.ambientLightColour = (0.0, 0.0, 0.0)
|
||||||
|
self.lightAngle = (0.0, 0.0) # (x, z)
|
||||||
|
self.lightmaps = []
|
||||||
|
self.mapObjects = []
|
||||||
|
|
||||||
|
def read(self, stream):
|
||||||
|
print("Reading LightmapData")
|
||||||
|
|
||||||
|
# There is no signature so just start reading data and hope this is actually a lightmap data file
|
||||||
|
version, = unpackStream("<I", stream)
|
||||||
|
print(f"Reading LightmapData version {version}")
|
||||||
|
|
||||||
|
if version == 1:
|
||||||
|
self.read1(stream)
|
||||||
|
elif version == 2:
|
||||||
|
self.read2(stream)
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Unknown LightmapData version: {version}")
|
||||||
|
|
||||||
|
'''
|
||||||
|
Version specific readers
|
||||||
|
'''
|
||||||
|
def read1(self, stream):
|
||||||
|
raise RuntimeError("Version 1 LightmapData is not implemented yet")
|
||||||
|
|
||||||
|
def read2(self, stream):
|
||||||
|
# Light info
|
||||||
|
self.lightColour, self.ambientLightColour = unpackStream("<2I", stream)
|
||||||
|
self.lightAngle = unpackStream("<2f", stream)
|
||||||
|
|
||||||
|
# Lightmaps
|
||||||
|
lightmapCount, = unpackStream("<I", stream)
|
||||||
|
print(f"Reading {lightmapCount} lightmaps")
|
||||||
|
for _ in range(lightmapCount):
|
||||||
|
lightmap = AlternativaProtocol.readString(stream)
|
||||||
|
self.lightmaps.append(lightmap)
|
||||||
|
|
||||||
|
# Map objects
|
||||||
|
mapObjectCount, = unpackStream("<I", stream)
|
||||||
|
print(f"Reading {mapObjectCount} map objects")
|
||||||
|
for _ in range(mapObjectCount):
|
||||||
|
mapObject = MapObject()
|
||||||
|
mapObject.read(stream)
|
||||||
|
self.mapObjects.append(mapObject)
|
||||||
|
|
||||||
|
#XXX: there is more data but do we actually care about it?
|
||||||
|
|
||||||
|
print(f"[LightmapData2 lightColour: {hex(self.lightColour)} ambientLightColour: {hex(self.ambientLightColour)} lightAngle: {self.lightAngle}]")
|
||||||
|
|
||||||
|
'''
|
||||||
|
Objects
|
||||||
|
'''
|
||||||
|
class MapObject:
|
||||||
|
def __init__(self):
|
||||||
|
self.index = 0
|
||||||
|
self.lightmapIndex = 0
|
||||||
|
self.lightmapScaleOffset = (0.0, 0.0, 0.0, 0.0)
|
||||||
|
self.UV1 = []
|
||||||
|
self.UV2 = []
|
||||||
|
self.castShadows = False
|
||||||
|
self.recieveShadows = False
|
||||||
|
|
||||||
|
def read(self, stream):
|
||||||
|
self.index, self.lightmapIndex = unpackStream("<2i", stream)
|
||||||
|
|
||||||
|
# Read lightmap data
|
||||||
|
if self.lightmapIndex >= 0:
|
||||||
|
self.lightmapScaleOffset = unpackStream("<4f", stream)
|
||||||
|
|
||||||
|
# Check if we have UVs and read them
|
||||||
|
hasUVs, = unpackStream("b", stream)
|
||||||
|
if hasUVs > 0:
|
||||||
|
vertexCount, = unpackStream("<I", stream)
|
||||||
|
for _ in range(vertexCount//2):
|
||||||
|
UV1 = unpackStream("<2f", stream)
|
||||||
|
self.UV1.append(UV1)
|
||||||
|
UV2 = unpackStream("<2f", stream)
|
||||||
|
self.UV2.append(UV2)
|
||||||
|
|
||||||
|
# Light settings
|
||||||
|
castShadows, recieveShadows = unpackStream("2b", stream)
|
||||||
|
self.castShadows = castShadows > 0
|
||||||
|
self.recieveShadows = recieveShadows > 0
|
||||||
|
|
||||||
|
print(f"[MapObject index: {self.index} lightmapIndex: {self.lightmapIndex} lightmapScaleOffset: {self.lightmapScaleOffset} UV1: {len(self.UV1)} UV2: {len(self.UV2)} castShadows: {self.castShadows} recieveShadows: {self.recieveShadows}]")
|
||||||
@@ -29,6 +29,7 @@ from .A3D import A3D
|
|||||||
from .A3DBlenderImporter import A3DBlenderImporter
|
from .A3DBlenderImporter import A3DBlenderImporter
|
||||||
from .BattleMap import BattleMap
|
from .BattleMap import BattleMap
|
||||||
from .BattleMapBlenderImporter import BattleMapBlenderImporter
|
from .BattleMapBlenderImporter import BattleMapBlenderImporter
|
||||||
|
from .LightmapData import LightmapData
|
||||||
|
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from time import time
|
from time import time
|
||||||
@@ -122,14 +123,18 @@ class ImportBattleMap(Operator, ImportHelper):
|
|||||||
print(f"Reading BattleMap data from {self.filepath}")
|
print(f"Reading BattleMap data from {self.filepath}")
|
||||||
|
|
||||||
importStartTime = time()
|
importStartTime = time()
|
||||||
|
|
||||||
|
lightmapData = LightmapData()
|
||||||
|
with open(f"{self.directory}/lightmapdata", "rb") as file:
|
||||||
|
lightmapData.read(file)
|
||||||
|
|
||||||
mapData = BattleMap()
|
mapData = BattleMap()
|
||||||
with open(self.filepath, "rb") as file:
|
with open(self.filepath, "rb") as file:
|
||||||
mapData.read(file)
|
mapData.read(file)
|
||||||
|
|
||||||
# Import data into blender
|
# Import data into blender
|
||||||
preferences = context.preferences.addons[__package__].preferences # TODO: check if this is set before proceeding
|
preferences = context.preferences.addons[__package__].preferences # TODO: check if this is set before proceeding
|
||||||
mapImporter = BattleMapBlenderImporter(mapData, preferences.propLibrarySourcePath, self.import_static_geom, self.import_collision_geom, self.import_spawn_points)
|
mapImporter = BattleMapBlenderImporter(mapData, lightmapData, preferences.propLibrarySourcePath, self.import_static_geom, self.import_collision_geom, self.import_spawn_points)
|
||||||
objects = mapImporter.importData()
|
objects = mapImporter.importData()
|
||||||
|
|
||||||
# Link objects
|
# Link objects
|
||||||
|
|||||||
Reference in New Issue
Block a user