aboutsummaryrefslogtreecommitdiff
path: root/tools/txt2img
diff options
context:
space:
mode:
Diffstat (limited to 'tools/txt2img')
-rwxr-xr-xtools/txt2img222
1 files changed, 0 insertions, 222 deletions
diff --git a/tools/txt2img b/tools/txt2img
deleted file mode 100755
index 7a89007..0000000
--- a/tools/txt2img
+++ /dev/null
@@ -1,222 +0,0 @@
-#!/usr/bin/env python3
-#
-"""Convert NXT data source files to readable files."""
-#
-# Copyright (C) 2024 Nicolas Schodet
-#
-# 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.
-#
-import argparse
-import os.path
-import struct
-
-import tomli_w
-from PIL import Image
-
-
-def image_from_data(w, h, data):
- """Create image from data.
-
- Pixels in NXT are organized as packets of 8 pixel high columns. PIL does not read
- this format, so just transpose every bytes then transpose the resulting image.
- """
- assert h % 8 == 0
- assert h / 8 * w == len(data)
- # Split in w pixel wide, 8 pixel high bands.
- data = [data[i : i + w] for i in range(0, len(data), w)]
- # Transpose.
- data = zip(*data)
- # Paste everything together.
- data = bytes(val for band in data for val in band)
- # Create the image.
- i = Image.frombytes("1", (h, w), data, "raw", "1;IR")
- # Transpose again.
- return i.transpose(Image.Transpose.TRANSPOSE)
-
-
-def decode_special(special_mask):
- """Decode menu special flags."""
- d = dict()
- if special_mask & 0x00000001:
- d["skip_this_mother_id"] = (special_mask >> 28) & 0xF
- if special_mask & 0x00000004:
- d["enter_act_as_exit"] = True
- if special_mask & 0x00000008:
- d["back_twice"] = True
- if special_mask & 0x00000010:
- d["exit_act_as_enter"] = True
- if special_mask & 0x00000020:
- d["leave_background"] = True
- if special_mask & 0x00000040:
- d["exit_calls_with_ff"] = True
- if special_mask & 0x00000080:
- d["exit_leaves_menufile"] = True
- if special_mask & 0x00000100:
- d["init_calls_with_0"] = True
- if special_mask & 0x00000200:
- d["left_right_as_call"] = True
- if special_mask & 0x00000400:
- d["enter_only_calls"] = True
- if special_mask & 0x00000800:
- d["exit_only_calls"] = True
- if special_mask & 0x00001000:
- d["auto_press_enter"] = True
- if special_mask & 0x00002000:
- d["enter_leaves_menufile"] = True
- if special_mask & 0x00004000:
- d["init_calls"] = True
- if special_mask & 0x00008000:
- d["accept_incoming_request"] = True
- if special_mask & 0x00010000:
- d["back_three_times"] = True
- if special_mask & 0x00020000:
- d["exit_disable"] = True
- if special_mask & 0x00040000:
- d["exit_load_pointer"] = (special_mask >> 24) & 0xF
- if special_mask & 0x00080000:
- d["exit_calls"] = True
- if special_mask & 0x00100000:
- d["init_calls_with_1"] = True
- if special_mask & 0x00200000:
- d["exit_load_menu"] = True
- if special_mask & 0x00400000:
- d["only_bt_on"] = True
- if special_mask & 0x00800000:
- d["only_datalog_enabled"] = True
- return d
-
-
-p = argparse.ArgumentParser(description=__doc__)
-p.add_argument("input", help="input file")
-p.add_argument("output_basename", nargs="?", help="output base file name")
-options = p.parse_args()
-
-if options.output_basename is None:
- options.output_basename = os.path.basename(os.path.splitext(options.input)[0])
-
-typ = None
-name = None
-data = []
-
-# Parse input file.
-with open(options.input) as i:
- for line in i:
- line = line.strip()
- if not line:
- continue
- if line.startswith("#define") or line.startswith("{") or line.startswith("}"):
- continue
- if line.startswith("//"):
- continue
- if typ is None:
- _, typ, name, _ = line.split()
- else:
- line = line.split("//")[0]
- data.extend(d.strip() for d in line.strip().rstrip(",").split(","))
-
-# Pack data.
-data = bytes(ord(d[1]) if d.startswith("'") else int(d, 16) for d in data)
-
-# Dump.
-if typ == "BMPMAP":
- fmt = ">HHBBBB"
- s = struct.calcsize(fmt)
- form, data_bytes, start_x, start_y, pixels_x, pixels_y = struct.unpack(
- fmt, data[0:s]
- )
- data = data[s:]
- info = dict(
- format="bitmap",
- start_x=start_x,
- start_y=start_y,
- )
- assert form == 0x0200
- # This field is garbage.
- # assert data_bytes == len(data), f"data_bytes is {data_bytes}, data is {len(data)}"
- with open(options.output_basename + ".toml", "wb") as o:
- tomli_w.dump(info, o)
- i = image_from_data(pixels_x, pixels_y, data)
- i.save(options.output_basename + ".png")
-elif typ == "ICON":
- fmt = ">HHBBBB"
- s = struct.calcsize(fmt)
- form, data_bytes, items_x, items_y, item_pixels_x, item_pixels_y = struct.unpack(
- fmt, data[0:s]
- )
- data = data[s:]
- info = dict(
- format="icon",
- item_pixels_x=item_pixels_x,
- item_pixels_y=item_pixels_y,
- )
- assert form == 0x0400
- assert data_bytes == len(data), f"data_bytes is {data_bytes}, data is {len(data)}"
- with open(options.output_basename + ".toml", "wb") as o:
- tomli_w.dump(info, o)
- i = image_from_data(items_x * item_pixels_x, items_y * item_pixels_y, data)
- i.save(options.output_basename + ".png")
-elif typ == "UBYTE": # Menu
- fmt = ">HHBBBB"
- s = struct.calcsize(fmt)
- form, data_bytes, item_size, items, item_pixels_x, item_pixels_y = struct.unpack(
- fmt, data[0:s]
- )
- data = data[s:]
- info = dict(
- format="menu",
- item_pixels_x=item_pixels_x,
- item_pixels_y=item_pixels_y,
- )
- assert form == 0x0700
- assert item_size == 0x1D
- assert data_bytes == len(data)
- assert items * item_size == len(data)
- items_data = [data[i : i + item_size] for i in range(0, len(data), item_size)]
- items = []
- for item_data in items_data:
- (
- item_id,
- special_mask,
- function_index,
- function_parameter,
- file_load_no,
- next_menu,
- icon_text,
- icon_image_no,
- ) = struct.unpack(f">LLBBBB{item_size - 13}sB", item_data)
- icon_text = icon_text.rstrip(b"\0").decode("ascii")
- items.append(
- dict(
- item_id=item_id,
- function_index=function_index,
- function_parameter=function_parameter,
- file_load_no=file_load_no,
- next_menu=next_menu,
- icon_text=icon_text,
- icon_image_no=icon_image_no,
- )
- )
- flags = decode_special(special_mask)
- if flags:
- items[-1]["flags"] = flags
- info["items"] = items
- with open(options.output_basename + ".toml", "wb") as o:
- tomli_w.dump(info, o)
-else:
- assert False, "unknown format"