KAZIK/tools/build_casino_assets.py

240 lines
8 KiB
Python

import os
from pathlib import Path
from PIL import Image
BRAIN_DIR = Path(r"C:\Users\user\.gemini\antigravity-ide\brain\68821b0e-0e7d-4871-92bc-f142243303b2")
PROJECT_DIR = Path(r"F:\покер")
OUT_DIR = PROJECT_DIR / "assets" / "textures"
OUT_BIN = OUT_DIR / "casino3d.bin"
CHROMAKEY = (255, 0, 255) # Magenta: 0x00FF00FF
TEX_SIZE = 64
TOTAL_SLOTS = 48
def clean_chromakey_black(img: Image.Image, threshold=40) -> Image.Image:
"""Resize with NEAREST so pixels never blend with chromakey!"""
img = img.resize((TEX_SIZE, TEX_SIZE), Image.Resampling.NEAREST).convert("RGB")
pixels = img.load()
for y in range(TEX_SIZE):
for x in range(TEX_SIZE):
r, g, b = pixels[x, y]
if r < threshold and g < threshold and b < threshold:
pixels[x, y] = CHROMAKEY
return img
def clean_chromakey_white(img: Image.Image, threshold=220) -> Image.Image:
img = img.resize((TEX_SIZE, TEX_SIZE), Image.Resampling.NEAREST).convert("RGB")
pixels = img.load()
for y in range(TEX_SIZE):
for x in range(TEX_SIZE):
r, g, b = pixels[x, y]
if r > threshold and g > threshold and b > threshold:
pixels[x, y] = CHROMAKEY
return img
def img_to_raw_dwords(img: Image.Image) -> bytes:
img = img.resize((TEX_SIZE, TEX_SIZE), Image.Resampling.NEAREST).convert("RGB")
data = bytearray()
pixels = img.load()
for y in range(TEX_SIZE):
for x in range(TEX_SIZE):
r, g, b = pixels[x, y]
# Little-endian 32-bit: [Blue, Green, Red, 0]
data.extend([b, g, r, 0])
return bytes(data)
def make_wood_wall() -> bytes:
data = bytearray()
for y in range(TEX_SIZE):
for x in range(TEX_SIZE):
plank = (x // 16)
grain = (y * 3 + x * 7) % 13
r = min(255, 120 + plank * 15 + grain)
g = min(255, 60 + plank * 8 + (grain // 2))
b = min(255, 25 + plank * 4)
if x % 16 == 0 or y == 0 or y == 63:
r, g, b = 45, 20, 10
data.extend([b, g, r, 0])
return bytes(data)
def make_carpet_floor() -> bytes:
data = bytearray()
for y in range(TEX_SIZE):
for x in range(TEX_SIZE):
# Rich emerald green casino carpet with gold diamond pattern
cx = (x % 16) - 8
cy = (y % 16) - 8
d = abs(cx) + abs(cy)
if d == 6 or d == 7:
# Gold line
r, g, b = 212, 175, 55
elif d < 6:
# Dark emerald center
r, g, b = 15, 75, 35
else:
# Deep velvet green
r, g, b = 20, 110, 45
data.extend([b, g, r, 0])
return bytes(data)
def make_ceiling_tex() -> bytes:
data = bytearray()
for y in range(TEX_SIZE):
for x in range(TEX_SIZE):
# Dark navy casino ceiling with warm gold recessed lamps
dx = (x % 32) - 16
dy = (y % 32) - 16
dist2 = dx * dx + dy * dy
if dist2 < 16:
# Bright warm lamp
r, g, b = 255, 240, 180
elif dist2 < 36:
# Gold bezel
r, g, b = 180, 140, 40
else:
# Dark acoustic tile
grid = 15 if (x % 32 == 0 or y % 32 == 0) else 35
r, g, b = grid, grid, grid + 10
data.extend([b, g, r, 0])
return bytes(data)
def make_atm() -> bytes:
data = bytearray()
for y in range(TEX_SIZE):
for x in range(TEX_SIZE):
if x < 14 or x > 49 or y < 6:
r, g, b = CHROMAKEY
elif 10 <= y <= 22 and 18 <= x <= 45:
# Glowing green screen
r, g, b = 20, 220, 40
elif 26 <= y <= 30 and 20 <= x <= 43:
r, g, b = 10, 10, 10
elif 42 <= y <= 54 and 18 <= x <= 45:
# Gold dispenser
r, g, b = 220, 180, 40
else:
r, g, b = 70, 75, 85
data.extend([b, g, r, 0])
return bytes(data)
def make_backroom_table() -> bytes:
data = bytearray()
for y in range(TEX_SIZE):
for x in range(TEX_SIZE):
if x < 8 or x > 55 or y < 16:
r, g, b = CHROMAKEY
elif y < 38:
r, g, b = 80, 40, 20
if 22 <= x <= 36 and 22 <= y <= 28:
r, g, b = 160, 160, 170 # Gun
elif (x - 44)**2 + (y - 28)**2 < 9:
r, g, b = 180, 10, 10 # Blood
else:
if (12 <= x <= 16 or 47 <= x <= 51):
r, g, b = 45, 20, 10
else:
r, g, b = CHROMAKEY
data.extend([b, g, r, 0])
return bytes(data)
def main():
OUT_DIR.mkdir(parents=True, exist_ok=True)
atlas = {}
# 1: Velvet Wall
velvet_path = BRAIN_DIR / "casino_wall_velvet_1790125679687.jpg"
if velvet_path.exists():
im = Image.open(velvet_path)
atlas[1] = img_to_raw_dwords(im)
else:
atlas[1] = make_wood_wall()
# 2: Neon Strip Club Wall
neon_path = BRAIN_DIR / "strip_club_wall_1790125693490.jpg"
if neon_path.exists():
im = Image.open(neon_path)
atlas[2] = img_to_raw_dwords(im)
else:
atlas[2] = make_wood_wall()
# 3: Carpet Floor
carpet_path = BRAIN_DIR / "casino_carpet_floor_1790125783306.jpg"
if carpet_path.exists():
im = Image.open(carpet_path)
atlas[3] = img_to_raw_dwords(im)
else:
atlas[3] = make_carpet_floor()
# 4: Hell Wall
hell_path = BRAIN_DIR / "doom_hell_wall_1790125800167.jpg"
if hell_path.exists():
im = Image.open(hell_path)
atlas[4] = img_to_raw_dwords(im)
else:
atlas[4] = make_wood_wall()
# 5: Ceiling
atlas[5] = make_ceiling_tex()
# 6: Wood Wall
atlas[6] = make_wood_wall()
# 10..13: Stripper Dancers (Clean crop with NEAREST)
dancer_path = BRAIN_DIR / "stripper_dancer_sprite_1790125706706.jpg"
if dancer_path.exists():
sheet = Image.open(dancer_path).convert("RGB")
w, h = sheet.size
fw = w // 4
for i in range(4):
crop = sheet.crop((i * fw, 0, (i + 1) * fw, h))
crop_clean = clean_chromakey_black(crop, threshold=40)
atlas[10 + i] = img_to_raw_dwords(crop_clean)
# 20..22: Slot Machine Frames
slot_path = BRAIN_DIR / "slot_machine_sprite_1790125722742.jpg"
if slot_path.exists():
sheet = Image.open(slot_path).convert("RGB")
w, h = sheet.size
fw = w // 3
for i in range(3):
crop = sheet.crop((i * fw, 0, (i + 1) * fw, h))
crop_clean = clean_chromakey_black(crop, threshold=35)
atlas[20 + i] = img_to_raw_dwords(crop_clean)
# 30: Blackjack Table
bj_path = BRAIN_DIR / "blackjack_table_sprite_1790125738107.jpg"
if bj_path.exists():
im = Image.open(bj_path)
atlas[30] = img_to_raw_dwords(clean_chromakey_white(im, threshold=225))
# 31: Roulette Table
roul_path = BRAIN_DIR / "roulette_table_sprite_1790125754084.jpg"
if roul_path.exists():
im = Image.open(roul_path)
atlas[31] = img_to_raw_dwords(clean_chromakey_black(im, threshold=35))
# 32: Bartender
shop_path = BRAIN_DIR / "bartender_shop_sprite_1790125768774.jpg"
if shop_path.exists():
im = Image.open(shop_path)
atlas[32] = img_to_raw_dwords(clean_chromakey_white(im, threshold=225))
# 33: ATM
atlas[33] = make_atm()
# 34: Backroom Table
atlas[34] = make_backroom_table()
# Monolithic binary write
slot_len = TEX_SIZE * TEX_SIZE * 4
with open(OUT_BIN, "wb") as f:
for slot in range(TOTAL_SLOTS):
data = atlas.get(slot, atlas.get(1, make_wood_wall()))
if len(data) != slot_len:
data = data.ljust(slot_len, b'\x00')[:slot_len]
f.write(data)
print(f"Generated clean casino3d.bin ({OUT_BIN.stat().st_size} bytes)")
if __name__ == "__main__":
main()