Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 51f9609327 |
|
Before Width: | Height: | Size: 404 B After Width: | Height: | Size: 265 B |
|
Before Width: | Height: | Size: 397 B After Width: | Height: | Size: 336 B |
|
Before Width: | Height: | Size: 400 B After Width: | Height: | Size: 241 B |
|
Before Width: | Height: | Size: 396 B After Width: | Height: | Size: 278 B |
|
Before Width: | Height: | Size: 400 B After Width: | Height: | Size: 297 B |
|
Before Width: | Height: | Size: 388 B After Width: | Height: | Size: 249 B |
|
Before Width: | Height: | Size: 395 B After Width: | Height: | Size: 297 B |
|
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 286 B |
|
Before Width: | Height: | Size: 402 B After Width: | Height: | Size: 307 B |
|
Before Width: | Height: | Size: 397 B After Width: | Height: | Size: 285 B |
|
Before Width: | Height: | Size: 403 B After Width: | Height: | Size: 314 B |
|
Before Width: | Height: | Size: 399 B After Width: | Height: | Size: 243 B |
|
Before Width: | Height: | Size: 407 B After Width: | Height: | Size: 409 B |
|
Before Width: | Height: | Size: 401 B After Width: | Height: | Size: 338 B |
|
Before Width: | Height: | Size: 400 B After Width: | Height: | Size: 316 B |
|
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 154 B |
|
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 139 B |
|
Before Width: | Height: | Size: 393 B After Width: | Height: | Size: 223 B |
|
Before Width: | Height: | Size: 404 B After Width: | Height: | Size: 210 B |
|
Before Width: | Height: | Size: 403 B After Width: | Height: | Size: 233 B |
|
Before Width: | Height: | Size: 408 B After Width: | Height: | Size: 184 B |
|
Before Width: | Height: | Size: 409 B After Width: | Height: | Size: 254 B |
|
Before Width: | Height: | Size: 393 B After Width: | Height: | Size: 151 B |
|
Before Width: | Height: | Size: 392 B After Width: | Height: | Size: 149 B |
|
Before Width: | Height: | Size: 397 B After Width: | Height: | Size: 269 B |
|
Before Width: | Height: | Size: 408 B After Width: | Height: | Size: 243 B |
|
Before Width: | Height: | Size: 394 B After Width: | Height: | Size: 128 B |
|
Before Width: | Height: | Size: 404 B After Width: | Height: | Size: 464 B |
|
Before Width: | Height: | Size: 411 B After Width: | Height: | Size: 257 B |
@@ -8,6 +8,7 @@
|
||||
Запуск: python3 tools/gen_models.py
|
||||
"""
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
import random
|
||||
@@ -1301,20 +1302,355 @@ ITEMS = [
|
||||
]
|
||||
|
||||
|
||||
def item_icon(color, seed):
|
||||
rnd = random.Random(seed)
|
||||
im = Image.new("RGBA", (16, 16), (0, 0, 0, 0))
|
||||
for y in range(2, 14):
|
||||
for x in range(4, 12):
|
||||
im.putpixel((x, y), tuple(clamp(c + rnd.randint(-10, 10)) for c in color) + (255,))
|
||||
for x in range(5, 11):
|
||||
im.putpixel((x, 3), (230, 230, 230, 255))
|
||||
im.putpixel((7, 6), (255, 60, 60, 255))
|
||||
im.putpixel((8, 6), (255, 60, 60, 255))
|
||||
for y in range(13, 16):
|
||||
im.putpixel((7, y), (40, 40, 40, 255))
|
||||
im.putpixel((8, y), (40, 40, 40, 255))
|
||||
return im
|
||||
# Иконки 16×16 без сглаживания. Каждый предмет рисуется своей функцией: категория задаёт основу
|
||||
# (машина ПВО, пуск с пламенем, РЛС, склад, прожектор, целеуказатель, стрелки, сворачивание),
|
||||
# внутри категории — мини-силуэт типа. Цвет предмета — только заливка, форма различает предметы.
|
||||
class _Icon:
|
||||
def __init__(self, color, seed):
|
||||
self.rnd = random.Random(seed)
|
||||
self.im = Image.new("RGBA", (16, 16), (0, 0, 0, 0))
|
||||
self.pal = {
|
||||
"b": tuple(color),
|
||||
"d": tuple(clamp(v * 0.6) for v in color),
|
||||
"l": tuple(clamp(v + 45) for v in color),
|
||||
"k": (30, 30, 34), "r": (255, 60, 60), "o": (255, 150, 40),
|
||||
"y": (255, 232, 120), "w": (236, 236, 236),
|
||||
}
|
||||
|
||||
def px(self, x, y, key):
|
||||
if 0 <= x < 16 and 0 <= y < 16:
|
||||
c = self.pal[key]
|
||||
if key in ("b", "d", "l"):
|
||||
c = tuple(clamp(v + self.rnd.randint(-6, 6)) for v in c)
|
||||
self.im.putpixel((x, y), c + (255,))
|
||||
|
||||
def rect(self, x0, y0, x1, y1, key):
|
||||
for y in range(y0, y1 + 1):
|
||||
for x in range(x0, x1 + 1):
|
||||
self.px(x, y, key)
|
||||
|
||||
def line(self, x0, y0, x1, y1, key):
|
||||
dx, dy = abs(x1 - x0), -abs(y1 - y0)
|
||||
sx, sy = (1 if x0 < x1 else -1), (1 if y0 < y1 else -1)
|
||||
err = dx + dy
|
||||
while True:
|
||||
self.px(x0, y0, key)
|
||||
if x0 == x1 and y0 == y1:
|
||||
break
|
||||
e2 = 2 * err
|
||||
if e2 >= dy:
|
||||
err += dy
|
||||
x0 += sx
|
||||
if e2 <= dx:
|
||||
err += dx
|
||||
y0 += sy
|
||||
|
||||
def disc(self, cx, cy, r, key):
|
||||
for y in range(cy - r - 1, cy + r + 2):
|
||||
for x in range(cx - r - 1, cx + r + 2):
|
||||
if (x - cx) ** 2 + (y - cy) ** 2 <= r * r + 0.5 * r:
|
||||
self.px(x, y, key)
|
||||
|
||||
def ring(self, cx, cy, lo, hi, key):
|
||||
for y in range(16):
|
||||
for x in range(16):
|
||||
if lo <= (x - cx) ** 2 + (y - cy) ** 2 <= hi:
|
||||
self.px(x, y, key)
|
||||
|
||||
def poly(self, pts, key):
|
||||
# Выпуклый многоугольник: заливка по строкам между крайними пересечениями рёбер.
|
||||
n = len(pts)
|
||||
for y in range(min(p[1] for p in pts), max(p[1] for p in pts) + 1):
|
||||
xs = []
|
||||
for i in range(n):
|
||||
(x1, y1), (x2, y2) = pts[i], pts[(i + 1) % n]
|
||||
if y1 == y2:
|
||||
if y1 == y:
|
||||
xs += [x1, x2]
|
||||
elif min(y1, y2) <= y <= max(y1, y2):
|
||||
xs.append(x1 + (y - y1) * (x2 - x1) / (y2 - y1))
|
||||
if xs:
|
||||
for x in range(math.ceil(min(xs) - 1e-9), math.floor(max(xs) + 1e-9) + 1):
|
||||
self.px(x, y, key)
|
||||
|
||||
|
||||
def _sam_base(c):
|
||||
c.rect(2, 8, 13, 11, "b")
|
||||
c.rect(3, 12, 4, 13, "k")
|
||||
c.rect(11, 12, 12, 13, "k")
|
||||
|
||||
|
||||
# Развёртывание ПВО: машина + пусковая установка.
|
||||
def _gepard(c): # ствольная турель, два длинных ствола
|
||||
_sam_base(c)
|
||||
c.disc(7, 6, 2, "b")
|
||||
c.line(9, 5, 15, 5, "d")
|
||||
c.line(9, 7, 15, 7, "d")
|
||||
|
||||
|
||||
def _pantsir(c): # ствольная турель с ракетными контейнерами сверху
|
||||
_sam_base(c)
|
||||
c.disc(7, 7, 2, "b")
|
||||
c.rect(4, 3, 5, 5, "l")
|
||||
c.rect(9, 3, 10, 5, "l")
|
||||
c.line(9, 6, 11, 6, "d")
|
||||
|
||||
|
||||
def _s400(c): # три вертикальных контейнера
|
||||
_sam_base(c)
|
||||
for x in (3, 6, 9):
|
||||
c.rect(x, 2, x + 1, 7, "b")
|
||||
c.rect(x, 2, x + 1, 2, "l")
|
||||
|
||||
|
||||
def _s500(c): # четыре вертикальных контейнера
|
||||
_sam_base(c)
|
||||
for x in (2, 5, 8, 11):
|
||||
c.rect(x, 2, x + 1, 7, "b")
|
||||
c.rect(x, 2, x + 1, 2, "l")
|
||||
|
||||
|
||||
def _patriot(c): # наклонный пусковой короб
|
||||
_sam_base(c)
|
||||
c.poly([(3, 8), (11, 3), (13, 5), (5, 10)], "b")
|
||||
c.line(7, 7, 9, 5, "d")
|
||||
|
||||
|
||||
def _buk(c): # наклонные направляющие с ракетой
|
||||
_sam_base(c)
|
||||
c.line(3, 8, 10, 2, "d")
|
||||
c.line(5, 9, 12, 3, "d")
|
||||
c.disc(12, 2, 1, "w")
|
||||
|
||||
|
||||
def _irist(c): # два наклонных контейнера
|
||||
_sam_base(c)
|
||||
c.poly([(3, 8), (7, 3), (9, 4), (5, 9)], "b")
|
||||
c.poly([(7, 9), (11, 3), (13, 4), (9, 10)], "b")
|
||||
|
||||
|
||||
def _nasams(c): # два горизонтальных контейнера
|
||||
_sam_base(c)
|
||||
c.rect(3, 2, 12, 3, "b")
|
||||
c.rect(3, 5, 12, 6, "b")
|
||||
c.line(3, 4, 12, 4, "d")
|
||||
|
||||
|
||||
def _tor(c): # сетка коротких вертикальных ячеек
|
||||
_sam_base(c)
|
||||
for x in (3, 6, 9):
|
||||
c.rect(x, 2, x + 1, 3, "b")
|
||||
c.rect(x, 5, x + 1, 6, "b")
|
||||
|
||||
|
||||
def _p1sun(c): # короб с мачтой
|
||||
_sam_base(c)
|
||||
c.rect(3, 5, 12, 7, "b")
|
||||
c.line(7, 1, 7, 4, "d")
|
||||
c.px(7, 1, "r")
|
||||
|
||||
|
||||
# Радиолокация и РЭБ.
|
||||
def _radar(c): # параболическая антенна на стойке
|
||||
c.disc(8, 5, 3, "l")
|
||||
c.line(8, 8, 8, 12, "d")
|
||||
c.rect(5, 13, 11, 14, "d")
|
||||
|
||||
|
||||
def _ew(c): # штырь-антенна с сигнальными дугами
|
||||
c.line(8, 6, 8, 14, "d")
|
||||
c.disc(8, 4, 1, "b")
|
||||
c.line(5, 2, 4, 4, "l")
|
||||
c.line(4, 4, 4, 6, "l")
|
||||
c.line(4, 6, 5, 8, "l")
|
||||
c.line(11, 2, 12, 4, "l")
|
||||
c.line(12, 4, 12, 6, "l")
|
||||
c.line(12, 6, 11, 8, "l")
|
||||
|
||||
|
||||
# Снабжение.
|
||||
def _depot(c): # штабель ящиков на поддоне
|
||||
c.rect(3, 8, 12, 13, "b")
|
||||
c.line(3, 10, 12, 10, "d")
|
||||
c.line(3, 12, 12, 12, "d")
|
||||
c.rect(2, 14, 13, 14, "d")
|
||||
c.rect(4, 4, 9, 7, "l")
|
||||
c.line(4, 6, 9, 6, "d")
|
||||
|
||||
|
||||
def _tzm(c): # грузовик с кабиной и кузовом
|
||||
c.rect(2, 7, 5, 11, "b")
|
||||
c.rect(3, 8, 4, 9, "w")
|
||||
c.rect(6, 4, 14, 11, "l")
|
||||
c.rect(3, 12, 4, 13, "k")
|
||||
c.rect(10, 12, 11, 13, "k")
|
||||
c.rect(13, 12, 14, 13, "k")
|
||||
|
||||
|
||||
# Прожектор.
|
||||
def _searchlight(c):
|
||||
c.rect(3, 4, 10, 8, "b")
|
||||
c.poly([(10, 4), (15, 1), (15, 11), (10, 8)], "y")
|
||||
c.line(6, 9, 6, 13, "d")
|
||||
c.rect(3, 14, 9, 14, "d")
|
||||
|
||||
|
||||
# Целеуказатель: кольцо с засечками.
|
||||
def _designator(c):
|
||||
c.ring(8, 8, 16, 26, "r")
|
||||
c.rect(7, 1, 8, 2, "r")
|
||||
c.rect(7, 13, 8, 14, "r")
|
||||
c.rect(1, 7, 2, 8, "r")
|
||||
c.rect(13, 7, 14, 8, "r")
|
||||
c.rect(7, 7, 8, 8, "r")
|
||||
|
||||
|
||||
# Пуски: огонь сзади, силуэт типа спереди.
|
||||
def _launch_base(c):
|
||||
c.rect(0, 7, 1, 8, "o")
|
||||
c.px(0, 7, "y")
|
||||
|
||||
|
||||
def _shahed(c): # треугольное крыло
|
||||
_launch_base(c)
|
||||
c.poly([(5, 2), (5, 13), (13, 7)], "b")
|
||||
|
||||
|
||||
def _geran3(c): # реактивный самолёт со стреловидным крылом
|
||||
_launch_base(c)
|
||||
c.rect(3, 7, 13, 8, "b")
|
||||
c.poly([(6, 7), (9, 2), (11, 2), (9, 7)], "d")
|
||||
c.poly([(6, 8), (9, 13), (11, 13), (9, 8)], "d")
|
||||
c.poly([(3, 7), (4, 3), (5, 3), (5, 7)], "d")
|
||||
|
||||
|
||||
def _lancet(c): # малый дрон с прямым крылом
|
||||
_launch_base(c)
|
||||
c.rect(3, 7, 12, 8, "b")
|
||||
c.rect(7, 2, 8, 13, "d")
|
||||
c.rect(3, 6, 4, 9, "d")
|
||||
|
||||
|
||||
def _kh101(c): # крылатая ракета: стреловидные крылья и хвост
|
||||
_launch_base(c)
|
||||
c.rect(3, 7, 12, 8, "b")
|
||||
c.poly([(12, 6), (15, 7), (15, 8), (12, 9)], "b")
|
||||
c.poly([(6, 7), (9, 3), (10, 3), (8, 7)], "d")
|
||||
c.poly([(6, 8), (9, 12), (10, 12), (8, 8)], "d")
|
||||
c.rect(2, 5, 3, 10, "d")
|
||||
|
||||
|
||||
def _kalibr(c): # крылатая ракета: тонкий корпус и четыре хвостовых киля
|
||||
_launch_base(c)
|
||||
c.rect(2, 7, 13, 8, "b")
|
||||
c.poly([(13, 6), (15, 7), (15, 8), (13, 9)], "b")
|
||||
c.rect(2, 4, 3, 5, "d")
|
||||
c.rect(2, 10, 3, 11, "d")
|
||||
|
||||
|
||||
def _kh22(c): # толстый корпус с большими дельта-крыльями
|
||||
_launch_base(c)
|
||||
c.rect(3, 6, 11, 9, "b")
|
||||
c.poly([(11, 6), (15, 7), (15, 8), (11, 9)], "b")
|
||||
c.poly([(4, 6), (8, 2), (9, 2), (7, 6)], "d")
|
||||
c.poly([(4, 9), (8, 13), (9, 13), (7, 9)], "d")
|
||||
|
||||
|
||||
def _zircon(c): # гиперзвук: корпус с одним передним стрейком
|
||||
_launch_base(c)
|
||||
c.rect(2, 7, 12, 8, "b")
|
||||
c.poly([(12, 7), (15, 7), (12, 8)], "b")
|
||||
c.poly([(8, 7), (12, 3), (13, 3), (11, 7)], "d")
|
||||
|
||||
|
||||
def _iskander(c): # баллистическая: длинный корпус, конус, сопло
|
||||
_launch_base(c)
|
||||
c.rect(3, 7, 11, 8, "b")
|
||||
c.poly([(11, 6), (15, 7), (15, 8), (11, 9)], "l")
|
||||
c.rect(2, 6, 2, 9, "d")
|
||||
|
||||
|
||||
def _oreshnik(c): # баллистическая с тремя головными частями
|
||||
_launch_base(c)
|
||||
c.rect(2, 6, 10, 9, "b")
|
||||
c.poly([(10, 5), (13, 6), (10, 7)], "l")
|
||||
c.poly([(10, 8), (13, 9), (10, 10)], "l")
|
||||
c.poly([(10, 6), (15, 7), (10, 8)], "b")
|
||||
|
||||
|
||||
def _kinzhal(c): # аэробаллистическая: корпус с треугольными килями
|
||||
_launch_base(c)
|
||||
c.rect(3, 7, 11, 8, "b")
|
||||
c.poly([(11, 6), (15, 7), (11, 9)], "b")
|
||||
c.poly([(4, 7), (7, 3), (8, 3), (6, 7)], "d")
|
||||
c.poly([(4, 8), (7, 12), (8, 12), (6, 8)], "d")
|
||||
|
||||
|
||||
def _mover(c): # четыре стрелки перемещения
|
||||
c.poly([(8, 0), (4, 5), (12, 5)], "b")
|
||||
c.rect(7, 4, 8, 7, "b")
|
||||
c.poly([(8, 15), (4, 10), (12, 10)], "b")
|
||||
c.rect(7, 8, 8, 11, "b")
|
||||
c.poly([(0, 8), (5, 4), (5, 12)], "b")
|
||||
c.rect(4, 7, 7, 8, "b")
|
||||
c.poly([(15, 8), (10, 4), (10, 12)], "b")
|
||||
c.rect(8, 7, 11, 8, "b")
|
||||
|
||||
|
||||
def _remover(c): # стрелка вниз над лотком: свёртывание
|
||||
c.poly([(8, 9), (3, 4), (13, 4)], "b")
|
||||
c.rect(7, 1, 8, 4, "b")
|
||||
c.rect(2, 11, 13, 13, "b")
|
||||
c.line(2, 11, 13, 11, "l")
|
||||
|
||||
|
||||
def _flare(c): # звезда осветительной ракеты на стержне
|
||||
c.disc(8, 7, 1, "y")
|
||||
c.line(8, 2, 8, 4, "y")
|
||||
c.line(8, 10, 8, 12, "y")
|
||||
c.line(3, 7, 5, 7, "y")
|
||||
c.line(11, 7, 13, 7, "y")
|
||||
c.line(4, 4, 5, 5, "w")
|
||||
c.line(11, 4, 10, 5, "w")
|
||||
c.line(4, 10, 5, 9, "w")
|
||||
c.line(11, 10, 10, 9, "w")
|
||||
c.rect(7, 12, 8, 15, "k")
|
||||
|
||||
|
||||
ICON_DRAW = {
|
||||
"designator": _designator,
|
||||
"launch_shahed": _shahed, "launch_geran3": _geran3, "launch_lancet": _lancet,
|
||||
"launch_kh101": _kh101, "launch_kalibr": _kalibr, "launch_kh22": _kh22,
|
||||
"launch_zircon": _zircon, "launch_iskander": _iskander, "launch_oreshnik": _oreshnik,
|
||||
"launch_kinzhal": _kinzhal,
|
||||
"deploy_patriot": _patriot, "deploy_gepard": _gepard, "deploy_pantsir": _pantsir,
|
||||
"deploy_s400": _s400, "deploy_s500": _s500, "deploy_irist": _irist,
|
||||
"deploy_nasams": _nasams, "deploy_buk": _buk, "deploy_tor": _tor, "deploy_p1sun": _p1sun,
|
||||
"deploy_radar": _radar, "deploy_ew": _ew,
|
||||
"deploy_depot": _depot, "deploy_tzm": _tzm,
|
||||
"deploy_light": _searchlight,
|
||||
"mover": _mover, "remover": _remover, "flare_gun": _flare,
|
||||
}
|
||||
|
||||
|
||||
def item_icon(name, color, seed):
|
||||
c = _Icon(color, seed)
|
||||
ICON_DRAW[name](c)
|
||||
# Контур по краю силуэта: тёмные предметы — светлым, светлые — тёмным, чтобы читались на обоих фонах.
|
||||
# Альфа-маска не меняется: контур перекрашивает только уже нарисованные пиксели.
|
||||
lum = 0.3 * color[0] + 0.59 * color[1] + 0.11 * color[2]
|
||||
edge = (160, 160, 160) if lum < 100 else (70, 70, 70) if lum > 190 else None
|
||||
if edge:
|
||||
src = c.im.copy()
|
||||
|
||||
def opaque(x, y):
|
||||
return 0 <= x < 16 and 0 <= y < 16 and src.getpixel((x, y))[3] > 0
|
||||
|
||||
for y in range(16):
|
||||
for x in range(16):
|
||||
if opaque(x, y) and not all(opaque(x + dx, y + dy) for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1))):
|
||||
c.im.putpixel((x, y), edge + (255,))
|
||||
return c.im
|
||||
|
||||
|
||||
def write_json(path, obj):
|
||||
@@ -1350,7 +1686,7 @@ def main():
|
||||
im = GT.burn(im, zlib.crc32(name.encode()), "glass" if base.startswith("glass") else "paint")
|
||||
im.save(os.path.join(a, "textures", "block", name + ".png"))
|
||||
for i, (name, title, color) in enumerate(ITEMS):
|
||||
item_icon(color, i).save(os.path.join(a, "textures", "item", name + ".png"))
|
||||
item_icon(name, color, zlib.crc32(name.encode())).save(os.path.join(a, "textures", "item", name + ".png"))
|
||||
write_json(os.path.join(a, "models", "item", name + ".json"),
|
||||
{"parent": "minecraft:item/generated", "textures": {"layer0": f"{NS}:item/{name}"}})
|
||||
write_json(os.path.join(a, "items", name + ".json"),
|
||||
|
||||