Skip to content

Commit

Permalink
Basic importing using rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
Pyogenics committed Sep 23, 2023
1 parent c8d27c0 commit f79a3fe
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 116 deletions.
39 changes: 35 additions & 4 deletions blender/io_scene_dava/FileIO/KA.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
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.
'''

import StreamBuffer
from .StreamBuffer import StreamBuffer

from io import BytesIO

Expand All @@ -18,6 +18,38 @@
class KAReadError(RuntimeError): pass
class KAWriteError(RuntimeError): pass

'''
Data types
'''
class Types:
NONE = 0
BOOLEAN = 1
INT32 = 2
FLOAT = 3
STRING = 4
WIDE_STRING = 5
BYTE_ARRAY = 6
UINT32 = 7
KEYED_ARCHIVE = 8
INT64 = 9
UINT64 = 10
VECTOR2 = 11
VECTOR3 = 12
VECTOR4 = 13
MATRIX2 = 14
MATRIX3 = 15
MATRIX4 = 16
COLOR = 17
FASTNAME = 18
AABBOX3 = 19
FILEPATH = 20
FLOAT64 = 21
INT8 = 22
UINT8 = 23
INT16 = 24
UINT16 = 25
ARRAY = 27

'''
Primitive data readers
'''
Expand Down Expand Up @@ -172,9 +204,8 @@ def readKAHeader(stream):
if stream.readBytes(2) != b"KA":
raise KAReadError("Invalid magic string")

version = stream.readInt32(False)
version = stream.readInt16(False)
nodeCount = stream.readInt32(False)
stream.readInt32(False) #TODO: duplicate of node count?

return (version, nodeCount)

Expand Down Expand Up @@ -229,7 +260,7 @@ def readKA258(stream, stringTable):
return {}

archive = {}
for _ in range nodeCount:
for _ in range(nodeCount):
key, value = V2DataReader.readPair(stream, stringTable)
archive[key] = value

Expand Down
4 changes: 2 additions & 2 deletions blender/io_scene_dava/FileIO/SCG.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
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 KA import readKA1
from .KA import readKA1

'''
Errors
Expand All @@ -33,7 +33,7 @@ def readSCG(stream):
if node["##name"] != "PolygonGroup":
print("Warning: SCG node wasn't a polygon group, skipping")
continue
polygonGroups[ node["#id"] ] = node
polygonGroups[ int.from_bytes(node["#id"], "little") ] = node

return polygonGroups

Expand Down
93 changes: 45 additions & 48 deletions blender/io_scene_dava/Geometry/PolygonGroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
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 io import BytesIO

from ..FileIO.StreamBuffer import StreamBuffer

class VertexTypes:
Expand Down Expand Up @@ -56,6 +58,7 @@ def __init__(self, fmt):
self.JOINTWEIGHT = -1

# Parse format
stride = 0
if (fmt & VertexTypes.VERTEX):
self.VERTEX = stride
stride += 3 * 4
Expand Down Expand Up @@ -130,6 +133,7 @@ def __init__(self, polyGroup):
self.id = polyGroup["#id"]
self.cubeTextureCoordCount = polyGroup["cubeTextureCoordCount"]
self.primitiveType = polyGroup["rhi_primitiveType"]
self.primitiveCount = polyGroup["primitiveCount"]

# Vertices
self.vertices = []
Expand All @@ -147,7 +151,7 @@ def __init__(self, polyGroup):
self.cubetexcoords = []

# Parse vertex format
vertexFormat = VertexFormat(polyGroup["self"])
vertexFormat = VertexFormat(polyGroup["vertexFormat"])

# Parse vertices TODO
stream = StreamBuffer( BytesIO(polyGroup["vertices"]) )
Expand All @@ -156,6 +160,7 @@ def __init__(self, polyGroup):
self.vertices.append(
(stream.readFloat(), stream.readFloat(), stream.readFloat())
)
stream.readBytes(vertexFormat.stride - 12) # Read off unhandled data

# Parse indices
# 0 = uint16_t
Expand All @@ -167,57 +172,49 @@ def __init__(self, polyGroup):
if polyGroup["indexFormat"] == 1:
for _ in range(polyGroup["indexCount"]): self.indices.append( stream.readInt32(False) )

'''
Primitive builders
line list, triangle list, triangle strip
'''
# Turn indices + vertices into a single vertex array
def collectVertices(self, indices):
vertexArray = []
for index in indices:
vertexArray.append( self.vertices[index] )
return vertexArray

def generateTriangleList(self):
faceIndices = []
for i in range(0, count, 3):
faceIndices.append([
self.indices[i],
self.indices[i+1],
self.indices[i+2]
])

return self.collectVertices(faceIndices)

#NOTE: We convert trianglestrip to trianglist to make the import easier
def generateTriangleStrip(self):
faceIndices = []

# First triangle
'''
Primitive builders
line list, triangle list, triangle strip
'''
def getTriangleList(self):
faceIndices = []
for i in range(0, len(self.indices), 3):
faceIndices.append([
self.indices[0],
self.indices[1],
self.indices[2]
self.indices[i],
self.indices[i+1],
self.indices[i+2]
])

# Digest triangestrip into trianglelist
for i in range(3, count):
faceIndices.append([
self.indices[i-2],
self.indices[i-1],
self.indices[i]
])
return faceIndices

return self.collectVertices(indices)
#NOTE: We convert trianglestrip to trianglist to make the import easier
def getTriangleStrip(self):
faceIndices = []

def generateLineList(self):
edgeIndices = []
for i in range(0, count, 2):
edgeIndices.append([
self.indices[i],
self.indices[i+1]
])
# First triangle
faceIndices.append([
self.indices[0],
self.indices[1],
self.indices[2]
])

# Digest triangestrip into trianglelist
for i in range(3, len(self.indices)):
faceIndices.append([
self.indices[i-2],
self.indices[i-1],
self.indices[i]
])

return faceIndices

def getLineList(self):
edgeIndices = []
for i in range(0, len(self.indices), 2):
edgeIndices.append([
self.indices[i],
self.indices[i+1]
])

return self.collectVertices(edgeIndices)
return edgeIndices
108 changes: 46 additions & 62 deletions blender/io_scene_dava/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,119 +25,103 @@
from bpy.props import StringProperty
from bpy_extras.io_utils import ImportHelper, ExportHelper

from os.path import basename

from .FileIO import FileBuffer
from .SCG.SCGReader import SCGReader
from .SC2.SC2Reader import SC2Reader
from .FileIO.StreamBuffer import StreamBuffer
from .FileIO.SCG import readSCG
from .Geometry.PolygonGroup import PrimitiveTypes, PolygonGroup

'''
Operators
'''
class ImportSCG(Operator, ImportHelper):
class ImportDAVA(Operator, ImportHelper):
bl_idname = "import_scene.scg"
bl_label = "Import DAVA geometry"
bl_description = "Import a DAVA geometry file"
bl_description = "Import a DAVA scene file"

filter_glob: StringProperty(default="*.scg", options={'HIDDEN'})

def invoke(self, context, event):
return ImportHelper.invoke(self, context, event)

# Just import SCG whilst we get proper full imports working
def execute(self, context):
filepath = self.filepath
filename = basename(filepath).split(".")[0]
print(f"Importing DAVA geometry from {filepath}")

with open(filepath, "rb") as f:
stream = FileBuffer(f)
geometry = SCGReader.readFromBuffer(stream)

# Add geometry to scene
collection = bpy.data.collections.new(filename)
for groupId, polyGroup in geometry.polygonGroups.items():
print(f"Importing DAVA scene from {filepath}")

with open(filepath, "rb") as scg:
polyGroups = readSCG(
StreamBuffer(scg)
)

# Parse polygon groups
for groupID in polyGroups.keys():
polyGroups[groupID] = PolygonGroup( polyGroups[groupID] )

# Add polygon groups to scene
collection = bpy.data.collections.new("DAVAMesh")
for groupID in polyGroups.keys():
group = polyGroups[groupID]
mesh = bpy.data.meshes.new("mesh")
mesh.from_pydata(polyGroup.vertices.VERTEX, polyGroup.edges, polyGroup.faces)

if group.primitiveType == PrimitiveTypes.TRIANGLELIST:
mesh.from_pydata(group.vertices, [], group.getTriangleList())
elif group.primitiveType == PrimitiveTypes.TRIANGLESTRIP:
mesh.from_pydata(group.vertices, [], group.getTriangleStrip())
elif group.primitiveType == PrimitiveTypes.LINELIST:
mesh.from_pydata(group.vertices, group.getLineList(), [])
mesh.update()

obj = bpy.data.objects.new(f"PolygonGroup{groupId}", mesh)
obj = bpy.data.objects.new(f"PolygonGroup{groupID}", mesh)
collection.objects.link(obj)
bpy.context.scene.collection.children.link(collection)
self.report({"INFO"}, f"Loaded {len(geometry.polygonGroups)} polygon groups")
self.report({"INFO"}, f"Loaded {len(polyGroups)} polygon groups")

return {"FINISHED"}

class ExportSCG(Operator, ExportHelper):
bl_idname = "export_scene.scg"
class ExportDAVA(Operator, ExportHelper):
bl_idname = "export_scene.sc2"
bl_label = "Export DAVA geometry"
bl_description = "Export a DAVA geometry file"
bl_description = "Export a scene file"

filter_glob: StringProperty(default="*.scg", options={'HIDDEN'})
filename_ext: StringProperty(default=".scg", options={'HIDDEN'})
filter_glob: StringProperty(default="*.sc2", options={'HIDDEN'})
filename_ext: StringProperty(default=".sc2", options={'HIDDEN'})

def invoke(self, context, event):
return ExportHelper.invoke(self, context, event)

def execute(self, context):
filepath = self.filepath
print(f"Exporting DAVA geometry to {filepath}")
print(f"Exporting DAVA scene to {filepath}")
return {'FINISHED'}

class ImportSC2(Operator, ImportHelper):
bl_idname = "import_scene.sc2"
bl_label = "Import DAVA scene"
bl_description = "Import a DAVA scene file"

filter_glob: StringProperty(default="*.sc2", options={'HIDDEN'})

def invoke(self, context, event):
return ImportHelper.invoke(self, context, event)

def execute(self, context):
filepath = self.filepath
print(f"Importing DAVA scene file from {filepath}")

with open(filepath, "rb") as f:
stream = FileBuffer(f)
SC2Reader.readFromBuffer(stream)

return {"FINISHED"}

'''
Menu
'''
def menu_func_import_scg(self, context):
self.layout.operator(ImportSCG.bl_idname, text="DAVA scene geometry (.scg)")

def menu_func_export_scg(self, context):
self.layout.operator(ExportSCG.bl_idname, text="DAVA scene geometry (.scg)")
def menu_func_import_dava(self, context):
self.layout.operator(ImportDAVA.bl_idname, text="DAVA scene (.sc2/.scg)")

def menu_func_import_sc2(self, context):
self.layout.operator(ImportSC2.bl_idname, text="DAVA scene file (.sc2)")
def menu_func_export_dava(self, context):
self.layout.operator(ExportDAVA.bl_idname, text="DAVA scene (.sc2/.scg)")

'''
Register
'''
classes = {
ExportSCG,
ImportSCG,
ImportSC2
ExportDAVA,
ImportDAVA
}

def register():
# Register classes
for c in classes:
bpy.utils.register_class(c)
# File > Import-Export
bpy.types.TOPBAR_MT_file_import.append(menu_func_import_scg)
bpy.types.TOPBAR_MT_file_export.append(menu_func_export_scg)
bpy.types.TOPBAR_MT_file_import.append(menu_func_import_sc2)
bpy.types.TOPBAR_MT_file_import.append(menu_func_import_dava)
# bpy.types.TOPBAR_MT_file_export.append(menu_func_export_dava)

def unregister():
# Unregister classes
for c in classes:
bpy.utils.unregister_class(c)
# Remove `File > Import-Export`
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import_scg)
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export_scg)
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import_sc2)
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import_dava)
# bpy.types.TOPBAR_MT_file_export.remove(menu_func_export_dava)

0 comments on commit f79a3fe

Please sign in to comment.