Skip to content

Instantly share code, notes, and snippets.

@Kristonitas
Created January 11, 2023 14:44
Show Gist options
  • Save Kristonitas/6f511bf618883d926b2409620cc53e57 to your computer and use it in GitHub Desktop.
Save Kristonitas/6f511bf618883d926b2409620cc53e57 to your computer and use it in GitHub Desktop.
hf2 heightmap parser for python
# Copyright 2023 Kristupas Stumbrys
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# See https://www.gnu.org/licenses/gpl-3.0.en.html
# spec
# http://www.bundysoft.com/docs/doku.php?id=l3dt:formats:specs:hf2
from struct import unpack
FILE_ID = b'HF2\x00'
VERSION = 0
def parse(bytes):
fileId, version, width, height, tileSize, verticalPrecision, horizontalScale, extendedHeaderLength = unpack(
'=4sHLLHffL', bytes[0:28])
# Ignoring the extended header
bytes = bytes[28 + extendedHeaderLength:]
if fileId != FILE_ID:
raise Exception(
"Invalid fileId, excepted " + str(FILE_ID) + ", got " + str(fileId))
if version != VERSION:
raise Exception(
"Invalid version, excepted " + str(VERSION) + ", got " + str(version))
heights = [0] * (width * height)
# Inner loop is x coord!
for y in range(0, height, tileSize):
for x in range(0, width, tileSize):
# Parsing tile
verticalScale, verticalOffset = unpack('=ff', bytes[0:8])
bytes = bytes[8:]
for l in range(0, min(tileSize, height - y)):
# Parsing line
byteDepth, startValue = unpack('=BL', bytes[0:5])
bytes = bytes[5:]
lineIndex = x + (y + l) * width
heights[lineIndex] = startValue * \
verticalScale + verticalOffset
lastValue = startValue
for i in range(0, min(tileSize, width - x) - 1):
# Parsing cell
if byteDepth == 1:
offset = unpack('=b', bytes[0:1])[0]
bytes = bytes[1:]
elif byteDepth == 2:
offset = unpack('=h', bytes[0:2])[0]
bytes = bytes[2:]
elif byteDepth == 4:
offset = unpack('=l', bytes[0:4])[0]
bytes = bytes[4:]
else:
raise Exception(
"Unexpected byteDepth: " + str(byteDepth))
value = lastValue + offset
lastValue = value
heights[lineIndex + i + 1] = value * \
verticalScale + verticalOffset
if len(bytes) != 0:
raise Exception("Not all bytes were parsed in the hfz: " + str(bytes))
return (width, height, heights)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment