mirror of
https://github.com/MapMakersAndProgrammers/io_scene_a3d.git
synced 2025-10-25 17:39:10 -07:00
Initial lightmapdata import
This commit is contained in:
@@ -30,7 +30,7 @@ from mathutils import Matrix
|
||||
|
||||
from .A3D import A3D
|
||||
from .A3DBlenderImporter import A3DBlenderImporter
|
||||
from .BlenderMaterialUtils import addImageTextureToMaterial
|
||||
from .BlenderMaterialUtils import addImageTextureToMaterial, decodeIntColorToTuple
|
||||
|
||||
class Prop:
|
||||
def __init__(self):
|
||||
@@ -150,8 +150,9 @@ class BattleMapBlenderImporter:
|
||||
# Allows subsequent map loads to be faster
|
||||
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.lightmapData = lightmapData
|
||||
self.propLibrarySourcePath = propLibrarySourcePath
|
||||
self.import_static_geom = import_static_geom
|
||||
self.import_collision_geom = import_collision_geom
|
||||
@@ -211,6 +212,26 @@ class BattleMapBlenderImporter:
|
||||
for ob in spawnPointObjects:
|
||||
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
|
||||
|
||||
def getPropLibrary(self, libraryName):
|
||||
@@ -253,6 +274,16 @@ class BattleMapBlenderImporter:
|
||||
propScale = (1.0, 1.0, 1.0)
|
||||
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
|
||||
ma = self.materials[propData.materialID]
|
||||
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.
|
||||
'''
|
||||
|
||||
from bpy.types import ShaderNodeBsdfPrincipled
|
||||
|
||||
'''
|
||||
Functions
|
||||
'''
|
||||
@@ -41,4 +39,13 @@ def addImageTextureToMaterial(image, node_tree, linkAlpha=False):
|
||||
links.new(textureNode.outputs["Alpha"], bsdfNode.inputs["Alpha"])
|
||||
|
||||
# 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 .BattleMap import BattleMap
|
||||
from .BattleMapBlenderImporter import BattleMapBlenderImporter
|
||||
from .LightmapData import LightmapData
|
||||
|
||||
from glob import glob
|
||||
from time import time
|
||||
@@ -122,14 +123,18 @@ class ImportBattleMap(Operator, ImportHelper):
|
||||
print(f"Reading BattleMap data from {self.filepath}")
|
||||
|
||||
importStartTime = time()
|
||||
|
||||
|
||||
lightmapData = LightmapData()
|
||||
with open(f"{self.directory}/lightmapdata", "rb") as file:
|
||||
lightmapData.read(file)
|
||||
|
||||
mapData = BattleMap()
|
||||
with open(self.filepath, "rb") as file:
|
||||
mapData.read(file)
|
||||
|
||||
# Import data into blender
|
||||
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()
|
||||
|
||||
# Link objects
|
||||
|
||||
Reference in New Issue
Block a user