Files
airdef/tools/airdef_assets/texture_catalog.py
T

273 lines
10 KiB
Python

"""AirDef's deterministic model texture catalog and generated variants."""
import random
import zlib
from PIL import Image
import gen_tex as GT
# ---------------------------------------------------------------- текстуры
def clamp(v):
return max(0, min(255, int(v)))
def noise(base, amp, seed, size=16):
rnd = random.Random(seed)
im = Image.new("RGBA", (size, size))
for y in range(size):
for x in range(size):
d = rnd.randint(-amp, amp)
im.putpixel((x, y), tuple(clamp(c + d) for c in base) + (255,))
return im
def panels(base, seed, size=16, every=8):
im = noise(base, 4, seed, size)
line = tuple(clamp(c - 16) for c in base) + (255,)
lite = tuple(clamp(c + 10) for c in base) + (255,)
for i in range(size):
for k in range(0, size, every):
im.putpixel((i, k), line)
im.putpixel((k, i), line)
if k + 1 < size:
im.putpixel((i, k + 1), lite)
rnd = random.Random(seed + 99)
for _ in range(size // 2): # заклёпки
x, y = rnd.randrange(size), rnd.randrange(size)
im.putpixel((x, y), lite)
return im
def camo(colors, seed, size=32, blobs=7):
rnd = random.Random(seed)
im = noise(colors[0], 4, seed, size)
for col in colors[1:]:
for _ in range(blobs):
cx, cy = rnd.randrange(size), rnd.randrange(size)
rx, ry = rnd.randint(2, 6), rnd.randint(1, 4)
for y in range(cy - ry, cy + ry + 1):
for x in range(cx - rx, cx + rx + 1):
if ((x - cx) / rx) ** 2 + ((y - cy) / ry) ** 2 <= 1 + rnd.random() * 0.3:
im.putpixel((x % size, y % size), tuple(clamp(c + rnd.randint(-5, 5)) for c in col) + (255,))
return im
def stripes(base, line, step, seed, size=16):
im = noise(base, 3, seed, size)
for y in range(0, size, step):
for x in range(size):
im.putpixel((x, y), line + (255,))
return im
def gradient(top, bottom, size=16):
im = Image.new("RGBA", (size, size))
for y in range(size):
t = y / (size - 1)
c = tuple(clamp(top[i] + (bottom[i] - top[i]) * t) for i in range(3))
for x in range(size):
im.putpixel((x, y), c + (255,))
return im
def canister_front():
im = noise((92, 100, 72), 3, 11)
for cx in (4, 11):
for cy in (4, 11):
for y in range(16):
for x in range(16):
d = (x - cx + 0.5) ** 2 + (y - cy + 0.5) ** 2
if d <= 9:
im.putpixel((x, y), (36, 38, 30, 255))
elif d <= 12:
im.putpixel((x, y), (120, 124, 100, 255))
return im
def radar_face():
im = noise((70, 76, 56), 3, 17)
for y in range(1, 15):
for x in range(1, 15):
if (x + y) % 3 == 0:
im.putpixel((x, y), (54, 58, 44, 255))
return im
def glass():
im = noise((40, 58, 78), 5, 31)
for i in range(16):
im.putpixel((i, 15 - i), (130, 160, 180, 255))
if i < 15:
im.putpixel((i + 1, 15 - i), (100, 130, 150, 255))
return im
def missile():
im = noise((232, 232, 226), 3, 21)
for x in range(16):
for y in (3, 4):
im.putpixel((x, y), (40, 40, 40, 255))
return im
def target():
im = Image.new("RGBA", (16, 16))
for y in range(16):
for x in range(16):
d = abs(x - 7.5) + abs(y - 7.5)
im.putpixel((x, y), (255, clamp(40 + d * 12), 40, 255))
return im
def fire(seed):
rnd = random.Random(seed)
im = Image.new("RGBA", (16, 16))
for y in range(16):
for x in range(16):
t = rnd.random()
im.putpixel((x, y), (255, clamp(140 + 110 * t), clamp(30 + 120 * t * t), 255))
return im
def missile_ru():
im = noise((226, 228, 222), 3, 49)
for x in range(16):
im.putpixel((x, 5), (180, 40, 40, 255))
im.putpixel((x, 11), (40, 40, 40, 255))
return im
def tube_cap():
im = noise((80, 88, 60), 3, 50)
for y in range(16):
for x in range(16):
d = (x - 7.5) ** 2 + (y - 7.5) ** 2
if d <= 36:
im.putpixel((x, y), (44, 48, 36, 255))
elif d <= 48:
im.putpixel((x, y), (120, 128, 96, 255))
return im
def tubes6():
im = noise((82, 96, 60), 3, 51)
for cx in (3, 8, 13):
for cy in (4, 11):
for y in range(16):
for x in range(16):
if (x - cx) ** 2 + (y - cy) ** 2 <= 4:
im.putpixel((x, y), (30, 32, 26, 255))
return im
def radar_big():
im = noise((92, 100, 70), 3, 52)
for y in range(16):
for x in range(16):
if x % 2 == 0 and y % 2 == 0:
im.putpixel((x, y), (60, 66, 46, 255))
return im
TEXTURES = {
"shahed": lambda: panels((66, 68, 70), 1),
"shahed_nose": lambda: noise((104, 106, 108), 4, 2),
"geran": lambda: panels((28, 28, 31), 3),
"geran_engine": lambda: panels((60, 60, 64), 4),
"intake": lambda: noise((14, 14, 14), 2, 5),
"prop": lambda: noise((22, 22, 22), 3, 6),
"missile": missile,
"nozzle": lambda: noise((44, 42, 40), 4, 7),
"flame": lambda: gradient((255, 250, 210), (255, 120, 20)),
"fire": lambda: fire(8),
"nato_green": lambda: camo([(76, 86, 58), (58, 68, 44), (44, 48, 34)], 9),
"flecktarn": lambda: camo([(92, 100, 62), (62, 74, 44), (104, 84, 54), (30, 32, 26)], 10),
"track": lambda: stripes((36, 36, 34), (74, 74, 70), 3, 11),
"tire": lambda: stripes((24, 24, 24), (40, 40, 40), 4, 12),
"canister": lambda: panels((94, 102, 74), 13),
"canister_front": canister_front,
"radar_face": radar_face,
"glass": glass,
"metal": lambda: panels((118, 120, 122), 14),
"dark_metal": lambda: panels((52, 54, 52), 15),
"barrel": lambda: noise((40, 42, 38), 3, 16),
"dish": lambda: noise((176, 178, 174), 5, 18),
"target": target,
"foam": lambda: panels((196, 180, 150), 40),
"kh101": lambda: panels((84, 88, 92), 41),
"kh101_belly": lambda: noise((150, 152, 150), 4, 42),
"lancet": lambda: panels((70, 78, 66), 43),
"ru_green": lambda: camo([(82, 96, 60), (54, 70, 40), (110, 96, 64), (34, 36, 28)], 44, blobs=6),
"ru_khaki": lambda: camo([(108, 110, 80), (84, 90, 60), (60, 64, 44)], 45, blobs=5),
"missile_ru": missile_ru,
"missile_grey": lambda: panels((150, 154, 156), 46),
"booster": lambda: noise((60, 62, 58), 3, 47),
"tube": lambda: stripes((96, 106, 74), (70, 78, 54), 4, 48),
"tube_cap": tube_cap,
"tubes6": tubes6,
"radar_big": radar_big,
"tracer": lambda: noise((255, 40, 20), 6, 60),
"tracer_hot": lambda: noise((255, 190, 150), 6, 61),
"white": lambda: noise((250, 250, 246), 2, 19),
"nato_tan": lambda: camo([(150, 130, 96), (124, 106, 76), (96, 84, 62)], 62, blobs=5),
"crate": lambda: stripes((92, 78, 48), (70, 58, 34), 5, 63),
"concrete": lambda: panels((132, 130, 124), 64),
"lamp": lambda: gradient((255, 255, 240), (255, 230, 170)),
"beam": lambda: gradient((255, 250, 225), (255, 240, 200)),
"antenna": lambda: noise((70, 72, 70), 3, 65),
"nose_dark": lambda: noise((58, 60, 62), 3, 66),
}
RINGED = set()
def _ring(name, base, bands, seed, text=None):
RINGED.add(name)
TEXTURES[name] = lambda: GT.band_tex(base, bands, seed, text=text)
TEXTURES[name + "_t"] = lambda: GT.band_tex(base, bands, seed, transpose=True, text=text)
STRETCH_FN = {}
for _i, _k in enumerate(("nato_green", "flecktarn", "ru_green", "ru_khaki", "nato_tan")):
STRETCH_FN[_k] = (lambda sx, sy, k=_k, i=_i: GT.camo(k, 100 + i, 64, sx, sy))
TEXTURES[_k] = (lambda k=_k, i=_i: GT.camo(k, 100 + i, 64))
STRETCH_FN["track_side"] = lambda sx, sy: GT.track_side(7, 32, sx, sy)
PAL_RU, PAL_RU2 = GT.PAL["ru_green"][0], GT.PAL["ru_khaki"][0]
TEXTURES.update({
"track_side": lambda: GT.track_side(7),
"track": lambda: GT.track_tex(8),
"tire": lambda: GT.tire_tex(9),
"hub": lambda: GT.hub_tex(10),
"glass_cab": lambda: GT.glass_tex(11),
"bare_lamp": lambda: GT.glass_tex(12, tint=(200, 205, 190), refl=False),
"bare_barrel": lambda: GT.metal_tex((44, 46, 44), 13),
"bare_nozzle": lambda: GT.metal_tex((66, 58, 52), 14),
"bare_dish": lambda: GT.metal_tex((178, 180, 176), 15),
"bare_antenna": lambda: GT.metal_tex((112, 114, 112), 16),
"canister_front": lambda: GT.cap_tex(28),
"mk_ru": lambda: GT.marking("digits", PAL_RU, 40, "312"),
"mk_ru2": lambda: GT.marking("digits", PAL_RU2, 41, "507"),
"mk_us": lambda: GT.marking("digits", (76, 86, 58), 42, "1-7"),
"mk_star": lambda: GT.marking("star", PAL_RU, 43),
"mk_de": lambda: GT.marking("cross", (88, 98, 62), 44),
"glow_ember": lambda: GT.Canvas(16, 1, 1, (255, 170, 80), 17).out(),
"metal": lambda: GT.painted((118, 120, 122), 18, lift=1.15),
"dark_metal": lambda: GT.painted((52, 54, 52), 19, lift=1.1),
"canister": lambda: GT.painted((92, 102, 74), 20),
"shahed": lambda: GT.painted((92, 96, 98), 21, panel=(20, 10), lift=1.2),
"geran": lambda: GT.painted((28, 28, 31), 22, panel=(20, 10), lift=1.0),
"kh101": lambda: GT.painted((84, 88, 92), 23, panel=(18, 10)),
"lancet": lambda: GT.painted((74, 82, 70), 24),
"missile_grey": lambda: GT.painted((150, 154, 156), 25, lift=1.0),
"radar_face": lambda: GT.lattice(26, 32, (96, 104, 76), (170, 176, 150)),
"radar_big": lambda: GT.lattice(27, 32, (112, 124, 92), (190, 196, 168)),
})
_ring("rm_pac3", (228, 228, 222), [(0.12, 2, (30, 30, 30)), (0.78, 1.5, (200, 170, 40)), (0.9, 1, (30, 30, 30))], 30, [(8, 14, 10)])
_ring("rm_white", (232, 232, 226), [(0.1, 2, (200, 40, 36)), (0.82, 1.5, (40, 40, 44))], 31, [(10, 12, 8)])
_ring("rm_ru", (226, 228, 222), [(0.15, 2, (170, 40, 36)), (0.55, 1, (40, 40, 40)), (0.85, 2, (170, 40, 36))], 32, [(9, 20, 10)])
_ring("rm_grey", (148, 152, 154), [(0.2, 1.5, (210, 210, 205)), (0.8, 1.5, (210, 210, 205))], 33, [(6, 14, 12)])
_ring("rm_khaki", (110, 112, 84), [(0.25, 2, (60, 62, 48)), (0.7, 1.5, (200, 190, 150))], 34, [(8, 18, 8)])
_ring("rm_dark", (58, 60, 62), [(0.3, 1.5, (150, 150, 146)), (0.85, 1.5, (150, 150, 146))], 35)