Add new modules for Crusader map rendering and processing
- Implemented `formats.py` to define data structures and functions for handling map data, including reading and decoding shape and map items. - Created `png.py` for generating PNG images from shape frames and pixel data. - Developed `sorting.py` to manage the sorting and rendering order of map items based on their properties and spatial relationships. - Introduced `render_all_maps.py` to facilitate the rendering of all maps for specified games, including command-line argument parsing and subprocess management for rendering tasks.
This commit is contained in:
parent
af5b77ea13
commit
82ae89865a
47 changed files with 1602 additions and 1562 deletions
67
tools/crusader_map/png.py
Normal file
67
tools/crusader_map/png.py
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import struct
|
||||
import zlib
|
||||
from pathlib import Path
|
||||
|
||||
from .formats import ShapeFrame
|
||||
|
||||
|
||||
DEFAULT_BACKGROUND = (10, 12, 18, 255)
|
||||
|
||||
|
||||
def rgba_buffer(width: int, height: int, color: tuple[int, int, int, int]) -> bytearray:
|
||||
r, g, b, a = color
|
||||
row = bytes((r, g, b, a)) * width
|
||||
return bytearray(row * height)
|
||||
|
||||
|
||||
def blit_frame(
|
||||
buffer: bytearray,
|
||||
canvas_width: int,
|
||||
canvas_height: int,
|
||||
left: int,
|
||||
top: int,
|
||||
frame: ShapeFrame,
|
||||
pixels: list[int],
|
||||
palette: list[tuple[int, int, int]],
|
||||
flipped: bool,
|
||||
) -> None:
|
||||
for src_y in range(frame.height):
|
||||
dst_y = top + src_y
|
||||
if dst_y < 0 or dst_y >= canvas_height:
|
||||
continue
|
||||
row_base = src_y * frame.width
|
||||
for src_x in range(frame.width):
|
||||
color_index = pixels[row_base + (frame.width - 1 - src_x if flipped else src_x)]
|
||||
if color_index < 0:
|
||||
continue
|
||||
dst_x = left + src_x
|
||||
if dst_x < 0 or dst_x >= canvas_width:
|
||||
continue
|
||||
pixel_base = (dst_y * canvas_width + dst_x) * 4
|
||||
r, g, b = palette[color_index]
|
||||
buffer[pixel_base : pixel_base + 4] = bytes((r, g, b, 255))
|
||||
|
||||
|
||||
def write_png_rgba(path: Path, width: int, height: int, pixels: bytearray) -> None:
|
||||
def chunk(chunk_type: bytes, payload: bytes) -> bytes:
|
||||
return (
|
||||
struct.pack(">I", len(payload))
|
||||
+ chunk_type
|
||||
+ payload
|
||||
+ struct.pack(">I", zlib.crc32(chunk_type + payload) & 0xFFFFFFFF)
|
||||
)
|
||||
|
||||
rows = bytearray()
|
||||
stride = width * 4
|
||||
for row in range(height):
|
||||
rows.append(0)
|
||||
start = row * stride
|
||||
rows.extend(pixels[start : start + stride])
|
||||
|
||||
payload = bytearray(b"\x89PNG\r\n\x1a\n")
|
||||
payload.extend(chunk(b"IHDR", struct.pack(">IIBBBBB", width, height, 8, 6, 0, 0, 0)))
|
||||
payload.extend(chunk(b"IDAT", zlib.compress(bytes(rows), level=9)))
|
||||
payload.extend(chunk(b"IEND", b""))
|
||||
path.write_bytes(payload)
|
||||
Loading…
Add table
Add a link
Reference in a new issue