mirror of
https://github.com/red031000/nitrog3d.git
synced 2025-06-18 13:15:35 -04:00
488 lines
17 KiB
Python
488 lines
17 KiB
Python
from .utils import error, read8, read32, np_fixed_to_float, fixed_to_float, to_rgb, vec10_to_vec, PolygonMode, CullMode, TexturePalette0Mode, TextureFlip, TextureRepeat, TextureTSize, TextureSSize, TextureConversionMode, TextureFormat, PrimitiveType, TranslucentPolygonSortMode, DepthBufferSelection
|
|
from enum import IntEnum
|
|
import numpy as np
|
|
|
|
def parse_dl(data, size, report_func):
|
|
offset = 0
|
|
display_list = []
|
|
while offset < size:
|
|
commandData = read32(data, offset)
|
|
offset += 4
|
|
commands, offset = parse_dl_command(data, offset, commandData, report_func)
|
|
display_list.append(commands)
|
|
return display_list
|
|
|
|
def parse_dl_command(data, offset, commandData, report_func):
|
|
commands = []
|
|
for i in range(4):
|
|
command = (commandData >> i * 8) & 0xFF
|
|
|
|
if command == 0x00:
|
|
commands.append(DLCommandNoop())
|
|
elif command == 0x10:
|
|
mode = MatrixMode(read32(data, offset))
|
|
offset += 4
|
|
commands.append(DLCommandMtxMode(mode))
|
|
elif command == 0x11:
|
|
commands.append(DLCommandPushMtx())
|
|
elif command == 0x12:
|
|
matrixId = read32(data, offset)
|
|
offset += 4
|
|
commands.append(DLCommandPopMtx(matrixId))
|
|
elif command == 0x13:
|
|
matrixId = read32(data, offset)
|
|
offset += 4
|
|
commands.append(DLCommandStoreMtx(matrixId))
|
|
elif command == 0x14:
|
|
matrixId = read32(data, offset)
|
|
offset += 4
|
|
commands.append(DLCommandRestoreMtx(matrixId))
|
|
elif command == 0x15:
|
|
commands.append(DLCommandIdentity())
|
|
elif command == 0x16:
|
|
matrix = np_fixed_to_float(np.frombuffer(data[offset:offset + 64], dtype=np.dtype('uint32').newbyteorder('<')).reshape((4, 4)))
|
|
offset += 64
|
|
commands.append(DLCommandLoadMtx44(matrix))
|
|
elif command == 0x17:
|
|
matrix = np_fixed_to_float(np.frombuffer(data[offset:offset + 48], dtype=np.dtype('uint32').newbyteorder('<')).reshape((4, 3)))
|
|
offset += 48
|
|
commands.append(DLCommandLoadMtx43(matrix))
|
|
elif command == 0x18:
|
|
matrix = np_fixed_to_float(np.frombuffer(data[offset:offset + 64], dtype=np.dtype('uint32').newbyteorder('<')).reshape((4, 4)))
|
|
offset += 64
|
|
commands.append(DLCommandMultMtx44(matrix))
|
|
elif command == 0x19:
|
|
matrix = np_fixed_to_float(np.frombuffer(data[offset:offset + 48], dtype=np.dtype('uint32').newbyteorder('<')).reshape((4, 3)))
|
|
offset += 48
|
|
commands.append(DLCommandMultMtx43(matrix))
|
|
elif command == 0x1A:
|
|
matrix = np_fixed_to_float(np.frombuffer(data[offset:offset + 36], dtype=np.dtype('uint32').newbyteorder('<')).reshape((3, 3)))
|
|
offset += 36
|
|
commands.append(DLCommandMultMtx33(matrix))
|
|
elif command == 0x1B:
|
|
x = fixed_to_float(read32(data, offset))
|
|
y = fixed_to_float(read32(data, offset + 4))
|
|
z = fixed_to_float(read32(data, offset + 8))
|
|
matrix = np.identity(4)
|
|
matrix[0, 0] = x
|
|
matrix[1, 1] = y
|
|
matrix[2, 2] = z
|
|
offset += 12
|
|
commands.append(DLCommandScale(matrix))
|
|
elif command == 0x1C:
|
|
x = fixed_to_float(read32(data, offset))
|
|
y = fixed_to_float(read32(data, offset + 4))
|
|
z = fixed_to_float(read32(data, offset + 8))
|
|
matrix = np.identity(4)
|
|
matrix[0, 3] = x
|
|
matrix[1, 3] = y
|
|
matrix[2, 3] = z
|
|
offset += 12
|
|
commands.append(DLCommandTranslate(matrix))
|
|
elif command == 0x20:
|
|
color = read32(data, offset)
|
|
rgb = to_rgb(color)
|
|
offset += 4
|
|
commands.append(DLCommandColor(rgb))
|
|
elif command == 0x21:
|
|
normal = vec10_to_vec(read32(data, offset))
|
|
offset += 4
|
|
commands.append(DLCommandNormal(normal))
|
|
elif command == 0x22:
|
|
texcoord = read32(data, offset)
|
|
s = fixed_to_float((texcoord & 0xFFFF) << 8) # unsure if this shift is correct
|
|
t = fixed_to_float(((texcoord >> 16) & 0xFFFF) << 8)
|
|
offset += 4
|
|
commands.append(DLCommandTexcoord(s, t))
|
|
elif command == 0x23:
|
|
xy = read32(data, offset)
|
|
z = fixed_to_float(read32(data, offset + 4))
|
|
x = fixed_to_float(xy & 0xFFFF)
|
|
y = fixed_to_float((xy >> 16) & 0xFFFF)
|
|
vertex = np.array([x, y, z])
|
|
offset += 8
|
|
commands.append(DLCommandVtx(vertex))
|
|
elif command == 0x24:
|
|
vertex = vec10_to_vec(read32(data, offset))
|
|
offset += 4
|
|
commands.append(DLCommandVtx(vertex))
|
|
elif command == 0x25:
|
|
xy = read32(data, offset)
|
|
x = fixed_to_float(xy & 0xFFFF)
|
|
y = fixed_to_float((xy >> 16) & 0xFFFF)
|
|
vertex = np.array([x, y])
|
|
offset += 4
|
|
commands.append(DLCommandVtxXY(vertex))
|
|
elif command == 0x26:
|
|
xz = read32(data, offset)
|
|
x = fixed_to_float(xz & 0xFFFF)
|
|
z = fixed_to_float((xz >> 16) & 0xFFFF)
|
|
vertex = np.array([x, z])
|
|
offset += 4
|
|
commands.append(DLCommandVtxXZ(vertex))
|
|
elif command == 0x27:
|
|
yz = read32(data, offset)
|
|
y = fixed_to_float(yz & 0xFFFF)
|
|
z = fixed_to_float((yz >> 16) & 0xFFFF)
|
|
vertex = np.array([y, z])
|
|
offset += 4
|
|
commands.append(DLCommandVtxYZ(vertex))
|
|
elif command == 0x28:
|
|
vertex = vec10_to_vec(read32(data, offset))
|
|
offset += 4
|
|
commands.append(DLCommandVtxDiff(vertex))
|
|
elif command == 0x29:
|
|
attributes = read32(data, offset)
|
|
offset += 4
|
|
polyAttr = DLCommandPolygonAttr()
|
|
polyAttr.parse(attributes)
|
|
commands.append(polyAttr)
|
|
elif command == 0x2A:
|
|
attributes = read32(data, offset)
|
|
offset += 4
|
|
texImageParam = DLCommandTexImageParam()
|
|
texImageParam.parse(attributes)
|
|
commands.append(texImageParam)
|
|
elif command == 0x2B:
|
|
address = read32(data, offset)
|
|
offset += 4
|
|
commands.append(DLCommandTexPlttBase(address))
|
|
elif command == 0x30:
|
|
attributes = read32(data, offset)
|
|
offset += 4
|
|
materialColourDiffAmb = DLCommandMaterialColourDiffAmb()
|
|
materialColourDiffAmb.parse(attributes)
|
|
commands.append(materialColourDiffAmb)
|
|
elif command == 0x31:
|
|
attributes = read32(data, offset)
|
|
offset += 4
|
|
materialColourSpecEmi = DLCommandMaterialColourSpecEmi()
|
|
materialColourSpecEmi.parse(attributes)
|
|
commands.append(materialColourSpecEmi)
|
|
elif command == 0x32:
|
|
attributes = read32(data, offset)
|
|
offset += 4
|
|
lightId = (attributes >> 30) & 0x3
|
|
vertex = vec10_to_vec(attributes)
|
|
commands.append(DLCommandLightVector(lightId, vertex))
|
|
elif command == 0x33:
|
|
attributes = read32(data, offset)
|
|
offset += 4
|
|
lightId = (attributes >> 30) & 0x3
|
|
rgb = to_rgb(attributes & 0x7FFF)
|
|
commands.append(DLCommandLightColour(lightId, rgb))
|
|
elif command == 0x34:
|
|
shininessTable = []
|
|
for j in range(32):
|
|
shininess = read32(data, offset)
|
|
offset += 4
|
|
shininessTable.append(shininess & 0xFF)
|
|
shininessTable.append((shininess >> 8) & 0xFF)
|
|
shininessTable.append((shininess >> 16) & 0xFF)
|
|
shininessTable.append((shininess >> 24) & 0xFF)
|
|
commands.append(DLCommandShininess(shininessTable))
|
|
elif command == 0x40:
|
|
primitiveType = PrimitiveType(read32(data, offset) & 0x3)
|
|
offset += 4
|
|
commands.append(DLCommandBegin(primitiveType))
|
|
elif command == 0x41:
|
|
commands.append(DLCommandEnd())
|
|
elif command == 0x50:
|
|
attributes = read32(data, offset)
|
|
offset += 4
|
|
am = TranslucentPolygonSortMode(attributes & 0x1)
|
|
wz = DepthBufferSelection((attributes >> 1) & 0x1)
|
|
commands.append(DLCommandSwapBuffers(am, wz))
|
|
elif command == 0x60:
|
|
attributes = read32(data, offset)
|
|
offset += 4
|
|
x1 = attributes & 0xFF
|
|
y1 = (attributes >> 8) & 0xFF
|
|
x2 = (attributes >> 16) & 0xFF
|
|
y2 = (attributes >> 24) & 0xFF
|
|
vector = np.array([x1, x2, y1, y2])
|
|
commands.append(DLCommandViewport(vector))
|
|
elif command == 0x70:
|
|
# BoxTest (0x70) not implemented
|
|
offset += 3
|
|
elif command == 0x71:
|
|
# PositionTest (0x71) not implemented
|
|
offset += 2
|
|
elif command == 0x72:
|
|
# VectorTest (0x72) not implemented
|
|
offset += 1
|
|
elif command == 0xFF:
|
|
# DummyCommand (0xFF) not implemented
|
|
pass
|
|
else:
|
|
error('Unrecognised DL command: %02x. Parameter offsets are likely incorrect!' % command, report_func)
|
|
return commands, offset
|
|
|
|
class MatrixMode(IntEnum):
|
|
PROJECTION = 0
|
|
POSITION = 1
|
|
POSITION_VECTOR = 2
|
|
TEXTURE = 3
|
|
|
|
class DLCommand:
|
|
def __init__(self, commandId):
|
|
self.commandId = commandId
|
|
|
|
class DLCommandNoop(DLCommand):
|
|
def __init__(self):
|
|
super().__init__(0x00)
|
|
|
|
class DLCommandMtxMode(DLCommand):
|
|
def __init__(self, mode):
|
|
super().__init__(0x10)
|
|
self.mode = mode
|
|
|
|
class DLCommandPushMtx(DLCommand):
|
|
def __init__(self):
|
|
super().__init__(0x11)
|
|
|
|
class DLCommandPopMtx(DLCommand):
|
|
def __init__(self, matrixId):
|
|
super().__init__(0x12)
|
|
self.matrixId = matrixId
|
|
|
|
class DLCommandStoreMtx(DLCommand):
|
|
def __init__(self, matrixId):
|
|
super().__init__(0x13)
|
|
self.matrixId = matrixId
|
|
|
|
class DLCommandRestoreMtx(DLCommand):
|
|
def __init__(self, matrixId):
|
|
super().__init__(0x14)
|
|
self.matrixId = matrixId
|
|
|
|
class DLCommandIdentity(DLCommand):
|
|
def __init__(self):
|
|
super().__init__(0x15)
|
|
|
|
class DLCommandLoadMtx44(DLCommand):
|
|
def __init__(self, matrix):
|
|
super().__init__(0x16)
|
|
self.matrix = matrix
|
|
|
|
class DLCommandLoadMtx43(DLCommand):
|
|
def __init__(self, matrix):
|
|
super().__init__(0x17)
|
|
self.matrix = matrix
|
|
|
|
class DLCommandMultMtx44(DLCommand):
|
|
def __init__(self, matrix):
|
|
super().__init__(0x18)
|
|
self.matrix = matrix
|
|
|
|
class DLCommandMultMtx43(DLCommand):
|
|
def __init__(self, matrix):
|
|
super().__init__(0x19)
|
|
self.matrix = matrix
|
|
|
|
class DLCommandMultMtx33(DLCommand):
|
|
def __init__(self, matrix):
|
|
super().__init__(0x1A)
|
|
self.matrix = matrix
|
|
|
|
class DLCommandScale(DLCommand):
|
|
def __init__(self, matrix):
|
|
super().__init__(0x1B)
|
|
self.matrix = matrix
|
|
|
|
class DLCommandTranslate(DLCommand):
|
|
def __init__(self, matrix):
|
|
super().__init__(0x1C)
|
|
self.matrix = matrix
|
|
|
|
class DLCommandColor(DLCommand):
|
|
def __init__(self, color):
|
|
super().__init__(0x20)
|
|
self.color = color
|
|
|
|
class DLCommandNormal(DLCommand):
|
|
def __init__(self, normal):
|
|
super().__init__(0x21)
|
|
self.normal = normal
|
|
|
|
class DLCommandTexcoord(DLCommand):
|
|
def __init__(self, s, t):
|
|
super().__init__(0x22)
|
|
self.s = s
|
|
self.t = t
|
|
|
|
class DLCommandVtx(DLCommand):
|
|
def __init__(self, vertex):
|
|
super().__init__(0x23)
|
|
self.vertex = vertex
|
|
|
|
class DLCommandVtx10(DLCommand):
|
|
def __init__(self, vertex):
|
|
super().__init__(0x24)
|
|
self.vertex = vertex
|
|
|
|
class DLCommandVtxXY(DLCommand):
|
|
def __init__(self, vertex):
|
|
super().__init__(0x25)
|
|
self.vertex = vertex
|
|
|
|
class DLCommandVtxXZ(DLCommand):
|
|
def __init__(self, vertex):
|
|
super().__init__(0x26)
|
|
self.vertex = vertex
|
|
|
|
class DLCommandVtxYZ(DLCommand):
|
|
def __init__(self, vertex):
|
|
super().__init__(0x27)
|
|
self.vertex = vertex
|
|
|
|
class DLCommandVtxDiff(DLCommand):
|
|
def __init__(self, vertex):
|
|
super().__init__(0x28)
|
|
self.vertex = vertex
|
|
|
|
class DLCommandPolygonAttr(DLCommand):
|
|
def __init__(self):
|
|
super().__init__(0x29)
|
|
self.lights = [False, False, False, False]
|
|
self.polyMode = PolygonMode.MODULATE
|
|
self.cullMode = CullMode.NONE
|
|
self.polygonId = 0
|
|
self.alpha = 0
|
|
self.xluDepthUpdate = False
|
|
self.farClipping = False
|
|
self.display1Dot = False
|
|
self.depthTest = False
|
|
self.fog = False
|
|
|
|
def parse(self, attributes):
|
|
light = attributes & 0xF
|
|
self.lights[0] = (light & 0x1) != 0
|
|
self.lights[1] = (light & 0x2) != 0
|
|
self.lights[2] = (light & 0x4) != 0
|
|
self.lights[3] = (light & 0x8) != 0
|
|
|
|
polyMode = (attributes >> 4) & 0x3
|
|
self.polyMode = PolygonMode(polyMode)
|
|
|
|
cullMode = (attributes >> 6) & 0x3
|
|
self.cullMode = CullMode(cullMode)
|
|
|
|
polygonId = (attributes >> 24) & 0x3F
|
|
self.polygonId = polygonId
|
|
|
|
alpha = (attributes >> 16) & 0x1F
|
|
self.alpha = alpha
|
|
|
|
self.xluDepthUpdate = (attributes >> 11) & 0x1 != 0
|
|
|
|
self.farClipping = (attributes >> 12) & 0x1 != 0
|
|
|
|
self.display1Dot = (attributes >> 13) & 0x1 != 0
|
|
|
|
self.depthTest = (attributes >> 14) & 0x1 != 0
|
|
|
|
self.fog = (attributes >> 15) & 0x1 != 0
|
|
|
|
class DLCommandTexImageParam(DLCommand):
|
|
def __init__(self):
|
|
super().__init__(0x2A)
|
|
self.texturePalette0Mode = TexturePalette0Mode.USE
|
|
self.textureFlip = TextureFlip.NONE
|
|
self.textureRepeat = TextureRepeat.NONE
|
|
self.textureTSize = TextureTSize.T8
|
|
self.textureSSize = TextureSSize.S8
|
|
self.textureConversionMode = TextureConversionMode.NONE
|
|
self.textureFormat = TextureFormat.NONE
|
|
self.textureAddress = 0
|
|
|
|
def parse(self, attributes):
|
|
texturePalette0Mode = (attributes >> 29) & 0x1
|
|
self.texturePalette0Mode = TexturePalette0Mode(texturePalette0Mode)
|
|
|
|
textureFlip = (attributes >> 18) & 0x3
|
|
self.textureFlip = TextureFlip(textureFlip)
|
|
|
|
textureRepeat = (attributes >> 16) & 0x3
|
|
self.textureRepeat = TextureRepeat(textureRepeat)
|
|
|
|
textureTSize = (attributes >> 23) & 0x7
|
|
self.textureTSize = TextureTSize(textureTSize)
|
|
|
|
textureSSize = (attributes >> 20) & 0x7
|
|
self.textureSSize = TextureSSize(textureSSize)
|
|
|
|
textureConversionMode = (attributes >> 30) & 0x3
|
|
self.textureConversionMode = TextureConversionMode(textureConversionMode)
|
|
|
|
textureFormat = (attributes >> 26) & 0x7
|
|
self.textureFormat = TextureFormat(textureFormat)
|
|
|
|
self.textureAddress = attributes & 0xFFFF
|
|
|
|
class DLCommandTexPlttBase(DLCommand):
|
|
def __init__(self, address):
|
|
super().__init__(0x2B)
|
|
self.paletteAddress = address
|
|
|
|
class DLCommandMaterialColourDiffAmb(DLCommand):
|
|
def __init__(self):
|
|
super().__init__(0x30)
|
|
self.diffuse = (0, 0, 0)
|
|
self.ambient = (0, 0, 0)
|
|
self.isVertexColour = False
|
|
|
|
def parse(self, attributes):
|
|
self.diffuse = to_rgb(attributes & 0x7FFF)
|
|
self.isVertexColour = (attributes >> 15) & 0x1 != 0
|
|
self.ambient = to_rgb((attributes >> 16) & 0x7FFF)
|
|
|
|
class DLCommandMaterialColourSpecEmi(DLCommand):
|
|
def __init__(self):
|
|
super().__init__(0x31)
|
|
self.specular = (0, 0, 0)
|
|
self.emission = (0, 0, 0)
|
|
self.isShininess = False
|
|
|
|
def parse(self, attributes):
|
|
self.specular = to_rgb(attributes & 0x7FFF)
|
|
self.isShininess = (attributes >> 15) & 0x1 != 0
|
|
self.emission = to_rgb((attributes >> 16) & 0x7FFF)
|
|
|
|
class DLCommandLightVector(DLCommand):
|
|
def __init__(self, lightId, vertex):
|
|
super().__init__(0x32)
|
|
self.lightId = lightId
|
|
self.vertex = vertex
|
|
|
|
class DLCommandLightColour(DLCommand):
|
|
def __init__(self, lightId, colour):
|
|
super().__init__(0x33)
|
|
self.lightId = lightId
|
|
self.colour = colour
|
|
|
|
class DLCommandShininess(DLCommand):
|
|
def __init__(self, shininessTable):
|
|
super().__init__(0x34)
|
|
self.shininessTable = shininessTable
|
|
|
|
class DLCommandBegin(DLCommand):
|
|
def __init__(self, primitiveType):
|
|
super().__init__(0x40)
|
|
self.primitiveType = primitiveType
|
|
|
|
class DLCommandEnd(DLCommand):
|
|
def __init__(self):
|
|
super().__init__(0x41)
|
|
|
|
class DLCommandSwapBuffers(DLCommand):
|
|
def __init__(self, translucentPolygonSortMode, depthBufferSelection):
|
|
super().__init__(0x50)
|
|
self.translucentPolygonSortMode = translucentPolygonSortMode
|
|
self.depthBufferSelection = depthBufferSelection
|
|
|
|
class DLCommandViewport(DLCommand):
|
|
def __init__(self, vector):
|
|
super().__init__(0x60)
|
|
self.vector = vector
|