Skip to content

Commit

Permalink
Implement importing mesh type 1 (prerendered backgrounds)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dragorn421 committed Aug 3, 2021
1 parent 8b1be5e commit 917e76d
Showing 1 changed file with 140 additions and 10 deletions.
150 changes: 140 additions & 10 deletions io_import_z64.py
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,107 @@ def locateLinkAnimations(self):
if ( (len( self.segment[0x07] ) > 0) and (self.animTotal > 0)):
self.buildLinkAnimations(self.hierarchy[0], 0)

def importJFIF(self, data, initPropsOffset, name_format='bg_%08X'):
log = getLogger('F3DZEX.importJFIF')
( imagePtr,
unknown, unknown2,
background_width, background_height,
imageFmt, imageSiz, imagePal, imageFlip
) = struct.unpack_from('>IIiHHBBHH', data, initPropsOffset)
t = Tile()
t.texFmt = imageFmt
t.texSiz = imageSiz
log.debug(
'JFIF background image init properties\n'
'imagePtr=0x%X size=%dx%d fmt=%d, siz=%d (%s) imagePal=%d imageFlip=%d',
imagePtr, background_width, background_height,
imageFmt, imageSiz, t.getFormatName(), imagePal, imageFlip
)
if imagePtr >> 24 != 0x03:
log.error('Skipping JFIF background image, pointer 0x%08X is not in segment 0x03', imagePtr)
return False
jfifDataStart = imagePtr & 0xFFFFFF
# read header just for sanity checks
# source: CloudModding wiki https://wiki.cloudmodding.com/oot/JFIF_Backgrounds
( marker_begin,
marker_begin_header, header_length,
jfif, null, version,
dens, densx, densy,
thumbnail_width, thumbnail_height,
marker_end_header
) = struct.unpack_from('>HHHIBHBHHBBH', data, jfifDataStart)
badJfif = []
if marker_begin != 0xFFD8:
badJfif.append('Expected marker_begin=0xFFD8 instead of 0x%04X' % marker_begin)
if marker_begin_header != 0xFFE0:
badJfif.append('Expected marker_begin_header=0xFFE0 instead of 0x%04X' % marker_begin_header)
if header_length != 16:
badJfif.append('Expected header_length=16 instead of %d=0x%04X' % (header_length, header_length))
if jfif != 0x4A464946: # JFIF
badJfif.append('Expected jfif=0x4A464946="JFIF" instead of 0x%08X' % jfif)
if null != 0:
badJfif.append('Expected null=0 instead of 0x%02X' % null)
if version != 0x0101:
badJfif.append('Expected version=0x0101 instead of 0x%04X' % version)
if dens != 0:
badJfif.append('Expected dens=0 instead of %d=0x%02X' % (dens, dens))
if densx != 1:
badJfif.append('Expected densx=1 instead of %d=0x%04X' % (densx, densx))
if densy != 1:
badJfif.append('Expected densy=1 instead of %d=0x%04X' % (densy, densy))
if thumbnail_width != 0:
badJfif.append('Expected thumbnail_width=0 instead of %d=0x%02X' % (thumbnail_width, thumbnail_width))
if thumbnail_height != 0:
badJfif.append('Expected thumbnail_height=0 instead of %d=0x%02X' % (thumbnail_height, thumbnail_height))
if marker_end_header != 0xFFDB:
badJfif.append('Expected marker_end_header=0xFFDB instead of 0x%04X' % marker_end_header)
if badJfif:
log.error('Bad JFIF format for background image at 0x%X:', jfifDataStart)
for badJfifMessage in badJfif:
log.error(badJfifMessage)
return False
jfifData = None
i = jfifDataStart
for i in range(jfifDataStart, len(data)-1):
if data[i] == 0xFF and data[i+1] == 0xD9:
jfifData = data[jfifDataStart:i+2]
break
if jfifData is None:
log.error('Did not find end marker 0xFFD9 in background image at 0x%X', jfifDataStart)
return False
try:
os.mkdir(fpath + '/textures')
except FileExistsError:
pass
except:
log.exception('Could not create textures directory %s' % (fpath + '/textures'))
pass
jfifPath = '%s/textures/jfif_%s.jfif' % (fpath, (name_format % jfifDataStart))
with open(jfifPath, 'wb') as f:
f.write(jfifData)
log.info('Copied jfif image to %s', jfifPath)
jfifImage = load_image(jfifPath)
me = bpy.data.meshes.new(name_format % jfifDataStart)
me.vertices.add(4)
cos = (
(background_width, 0),
(0, 0),
(0, background_height),
(background_width, background_height),
)
import bmesh
bm = bmesh.new()
transform = Matrix.Scale(scaleFactor, 4)
bm.faces.new(bm.verts.new(transform * Vector((cos[i][0], 0, cos[i][1]))) for i in range(4))
bm.to_mesh(me)
bm.free()
del bmesh
me.uv_textures.new().data[0].image = jfifImage
ob = bpy.data.objects.new(name_format % jfifDataStart, me)
ob.location.z = max(max(v.co.z for v in obj.data.vertices) for obj in bpy.context.scene.objects if obj.type == 'MESH')
bpy.context.scene.objects.link(ob)
return ob

def importMap(self):
if importStrategy == 'NO_DETECTION':
self.importMapWithHeaders()
Expand Down Expand Up @@ -984,16 +1085,45 @@ def importMapWithHeaders(self):
self.use_transparency = True
self.buildDisplayList(None, [None], xlu, mesh_name_format='%s_xlu')
elif type == 1:
log.error('mesh type 1 unimplemented')
continue
# fixme

if count == 1:
#Noka here
end = start + 8
for j in range(start, end, 4):
self.buildDisplayList(None, [None], unpack_from(">L", data, j)[0])

format = data[mho+1]
entrySeg = data[mho+4]
entry = (data[mho+5] << 16) | (data[mho+6] << 8) | data[mho+7]
if entrySeg == 0x03:
opa = unpack_from(">L", data, entry)[0]
if opa:
self.use_transparency = False
self.buildDisplayList(None, [None], opa, mesh_name_format='%s_opa')
xlu = unpack_from(">L", data, entry+4)[0]
if xlu:
self.use_transparency = True
self.buildDisplayList(None, [None], xlu, mesh_name_format='%s_xlu')
else:
log.error('Skipping mesh header at 0x%X of type %d: entry is in segment 0x%02X', mho, type, entrySeg)
if format == 1:
if not self.importJFIF(data, mho + 8):
log.error('Failed to import jfif background image, mesh header at 0x%X of type 1 format 1', mho)
elif format == 2:
background_count = data[mho + 8]
backgrounds_array = unpack_from(">L", data, mho + 0xC)[0]
if backgrounds_array >> 24 == 0x03:
backgrounds_array &= 0xFFFFFF
for i in range(background_count):
bg_record_offset = backgrounds_array + i * 0x1C
unk82, bgid = struct.unpack_from('>HB', data, bg_record_offset)
if unk82 != 0x0082:
log.error('Skipping JFIF: mesh header at 0x%X type 1 format 2 background record entry #%d at 0x%X expected unk82=0x0082, not 0x%04X', mho, i, bg_record_offset, unk82)
continue
ob = self.importJFIF(
data, bg_record_offset + 4,
name_format='bg_%d_%s' % (i, '%08X')
)
ob.location.y -= scaleFactor * 100 * i
if not ob:
log.error('Failed to import jfif background image from record entry #%d at 0x%X, mesh header at 0x%X of type 1 format 2', i, bg_record_offset, mho)
else:
log.error('Skipping mesh header at 0x%X of type 1 format 2: backgrounds_array=0x%08X is not in segment 0x03', mho, backgrounds_array)
else:
log.error('Unknown format %d for mesh type 1 in mesh header at 0x%X', format, mho)
elif type == 2:
if mho + 12 > len(data):
log.error('Mesh header at 0x%X of type %d extends past the zmap file size, skipping', mho, type)
Expand Down

0 comments on commit 917e76d

Please sign in to comment.