Автор Тема: Программирование редакторов для внесения каких-то изменений в ром.  (Прочитано 16671 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн SeregaZ

  • Пользователь
  • Сообщений: 3005
  • Пол: Мужской
  • ливнул с форума
    • Youtube
    • Просмотр профиля
тут это... затык  :lol:

вопрос по ромхакерской направленности. вспомнил что у меня есть тестовой ром, показывающий картинки, но он требует 40х28 тайловые карты. и соответственно в процессе работы конвертирует 40х28 в 64х28. в моем же случае карты уже 64х28. как их втулить то? уже и комментил функцию и чего только не делал - не хочет :)

там что-то типа:
lea pic_map1,a0
move.l #$40000003,(a2) ; VDP PORT ADDRESS VRAM $C000 - MAP1
move.w #$0001,d3
bsr.s load_map_40x28


load_map_40x28: ; map 40x28 -> 64x28 conversion
moveq #27,d2
moveq #0,d4
@copy_n
moveq #63,d1 ; 39
@copy_l
move.w (a0)+,d0
add.w d3,d0
move.w d0,(a1)
dbf d1,@copy_l
moveq #0,d1 ; 23
@fill_l:
move.w d3,(a1)
dbf d1,@fill_l
dbf d2,@copy_n
rts

полагаю что-то вместо load_map_40x28 надо вписать, чтобы оно pic_map1 (64х28 карта) втулило в нужный кусочек памяти - там где тайловая карта должна болтаться.

у меня не выходит :(

как оказалось ссылки все сдохли

Оффлайн Sharpnull

  • Пользователь
  • Сообщений: 5754
    • Просмотр профиля
соответственно в процессе работы конвертирует 40х28 в 64х28. в моем же случае карты уже 64х28. как их втулить то?
Попробуйте так:
load_map_64x28:
moveq #27,d2
@copy_n
moveq #63,d1
@copy_l
move.w (a0)+,d0
add.w d3,d0
move.w d0,(a1)
dbf d1,@copy_l
dbf d2,@copy_n
rts
Т. е. я убрал цикл @fill_l, который добавлял тайлы для заполнения (d3, он же базовый для остальных).
UPD: Или короче:
load_map_64x28:
move.l #64*28-1,d1
@copy_n
move.w (a0)+,d0
add.w d3,d0
move.w d0,(a1)
dbf d1,@copy_n
rts
UPD2: вместо move.l #64*28-1,d1 можно move.w #64*28-1,d1, потому что в dbf только 16 бит учитываются от регистра.
« Последнее редактирование: 05 Ноября 2024, 22:15:34 от Sharpnull »

Оффлайн SeregaZ

  • Пользователь
  • Сообщений: 3005
  • Пол: Мужской
  • ливнул с форума
    • Youtube
    • Просмотр профиля
заработало, спасибо :)



Добавлено позже:
Было бы неплохо маленько добавить визуальное разделение на экране. Типа сделать вертикальную зеленую полоску границы экрана на 320 пикселях и добавить сетку тайлов 8х8 пикселей. Полупрозрачных причем.

Еще наверное надо добавить второе большое окно, где отображались бы эти самые зеркала и приоритет. Наверное сделаю тайл чуть ярче чем черный, если приоритет 1. И добавлю значек х или у если были зеркала.

Рисовать будем классической бейсиковской командой Line. Там не сложно сначала стартовые координаты точки откуда линия рисуется, дальше относительные координаты в какую сторону от старта двигаться. А чтобы сделать линию полупрозрачной - надо вместо RGB указывать RGBA, где четвертый параметр как раз таки прозрачность. Так-же режим рисования надо будет переключить на DrawingMode(#PB_2DDrawing_AlphaBlend)

Ну и поскольку отображение этих полосок мы сделаем включаемо-отключаемыми, то значит и перерисовка нам будет нужна несколько раз, а для этого чтобы не повторять один и тот-же код по писят раз в программе - сделаем рисование, то есть обновление гаджета, в процедуре. И будем вызывать эту процедуру когда нам надо - сразу после отключения-включения галок. Получить статус чекбокса можно с помощью GetGadgetState.

Ага... в процессе запиливания стало понятно что зеленый цвет на голубом фоне флага виден не очень. Значит надо сделать переключатель какого цвета будет граница экрана и самих тайлов. Типа зеленый я обычно леплю, но можно и черный и фиолетовый к примеру. И изначальный выбор зеленого цвета надо будет указать на гаджет зеленого путем использования SetGadgetState.

Ну и раз пошла такая пьянка, то хорошо бы сразу сделать кнопку со сборкой рома через ASM68K.exe, и потом запуск эмуля, где можно было бы поглядеть как оно будет выглядеть в итоге. Для чего понадобится RunProgram. Ну и для переменной EmulatorPath$ надо будет указать свой путь до эмулятора, иначе волшебства не произойдет.

Ну и может быть такой вариант, что сборка рома ASM68K.exe зафейлится и тогда мы запиливаем диалог ошибки с возможностью выбора запуска бат файла отдельно. Дело в том, что при запуске ASM68K.exe окошко мелькает и сразу-же закрывается, не давая прочитать любовные письма, которые он там пишет. Как бы PB имеет функции чтения чужого консольного окна, но затык в том, что ASM68K.exe не дает прочитать, скатина. Гранаты там не той системы и соответственно лог работы ассемблера не дается. С большинством же других консольных программ нет никаких проблем.

Что касается самих зеркал, то там используются те-же самые циклы, как при рисовании обычного тайла без зеркал. Просто мы меняем значения от и докуда крутить местами и в самом цикле указываем направление Step -1, то есть от большего к меньшему. Ну и в случае с Х зеркалом x - 1 для второго пикселя, вместо х + 1 как было при обычном тайле без зеркал.




В конечном итоге дизайн окна теперь выглядит так:

« Последнее редактирование: 12 Ноября 2025, 15:58:07 от ghostdog3 »

как оказалось ссылки все сдохли

Оффлайн Yoti

  • Пользователь
  • Сообщений: 4686
  • Пол: Мужской
  • Не тро-гай ме-ня
    • Steam
    • Просмотр профиля
Ага... в процессе запиливания стало понятно что зеленый цвет на голубом фоне флага виден не очень. Значит надо сделать переключатель какого цвета будет
Почему просто не инвертировать цвет?
Коэффициент интеллекта прямо пропорционален грамотности сообщений на форуме.
"Чудище обло, озорно, огромно, стозевно и лаяй"
"Не нравится мне это место, чую, что бесовщина, но обосновать не могу"

Оффлайн SeregaZ

  • Пользователь
  • Сообщений: 3005
  • Пол: Мужской
  • ливнул с форума
    • Youtube
    • Просмотр профиля
ну... проще все-таки обычная линия, нежели еще один цикл, где бы проверялась каждая точка на пути этой линии, инвертировался цвет этой точки и перерисовывался. нужен как можно простой код, чтобы новичку было легче вкатывать в тему. а там уже когда наш подозреваемый втянется в вопрос и откроет тайну вселенной, что программировать на самом деле не сильно сложно - то сам уже сможет и инвертирование и блек джек и легкодоступных женщин там напрограммировать.

как оказалось ссылки все сдохли

Оффлайн SeregaZ

  • Пользователь
  • Сообщений: 3005
  • Пол: Мужской
  • ливнул с форума
    • Youtube
    • Просмотр профиля
в общем тяжело что-то там родил... алгоритм вставки такой:
1. 24 битное изображение 320х224 пикселя сначала перекрашиваем в 512 сеговских цветов.
2. измеряем вес пикселей, количество пикселей одинакового цвета на изображении и отбираем 16 с самым большим весом в палитру.
3. перерисовываем 512 цветное изображение в 16 подготовленную палитру.

Чтобы вставить картинку, надо в пейнте вырезать область размером 320х224 и нажать вставку на экране программы. Если результат нормальный - можно нажать сохранить, а потом кнопку тест и увидеть результат уже в эмуляторе.

Итоговый результат конечно такой себе :) В архиве как пример железный человек лежит. При его вставке - весь красный цвет идет по бороде и изображение преимущественно упарывается в синий оттенок. Палетквант из интырнетов сделает в тыщу раз лучше :)

Поскольку я совсем растерял навыки, а код брал из другого места, который до этого мои кривые руки на что-то там правили - вполне мог напортачить :) Надо было оригинальный буржуинский код найти и его копировать, а не мою недо-переделку. Я забыл уже все нюансы... так что местами в коде ашипки. Надо опять по новой вникать. И надо еще подумать над палитрой, чтобы в ней в любом случае присутствовал черный цвет как первый в палитре. Как раз в моей доделке оно и было... но я забыл как это включать :) Сейчас черный цвет может уплыть или не быть вовсе в палитре и поэтому правая часть окна может быть не черной, как изначально с Дюной.

Пока-что в изображении не выкидываются повторяющиеся тайлы, то есть изображение сохраняется целиком. Это я потом добавлю. А вот другие две вещи - было бы неплохо подумать, как сделать.
1. сжатие графики, по типу МК3. декомпрессор-компрессор как ехешку с форума - не предлагать. надо прям по детски объяснение как это работает, чтобы я мог сделать что-то похожее "по мотивам".
2. прямая запись в эмулятор образа рома. именно не как файл, а прям кусман памяти вписать в эмулятор с ромом, дабы не создавать всякие мусорные временные файлы на жестком диске (у меня просто пунктик на эту тему).

В код добавлен не мой модуль по подбору цветов и пожатии палитры из 24бит в заданное количество. Это очень много кода. Он там во многом без комментариев, ибо я сам хрен знает что там происходит. Но во всех остальных местах комментариев написал как можно больше с объяснениями.

И да! Надо опять таки в коде исправить путь до своего эмулятора. Там сейчас мой путь и кнопка ТЕСТ работать не будет если не исправить. Можно конечно через ини файл сделать. Типа при первом запуске потребует путь, а после уже будет всегда знать где эмулятор лежит. Так-же путь до рома тоже надо будет подумать как доделать.

как оказалось ссылки все сдохли

Оффлайн SeregaZ

  • Пользователь
  • Сообщений: 3005
  • Пол: Мужской
  • ливнул с форума
    • Youtube
    • Просмотр профиля
родил  :cool: . 2 дня убил, но вроде раздуплил. есть и код на PB с сжатием тайлового сета и на ASM разжатия и записи в VDP. ляпота! теперь можно подумать как втуливать образ памяти в эмулятор, чтобы не создавать временный файл рома на жестком диске. бегло глянул - пока не ясно. нашло пяток адресов, где вроде как ром сидит в памяти эмуля. надо будет тестить, вникать.

***

Итак. Теория выкидывания повторяющихся тайлов. Сейчас пишет тайлы прям друг за другом, как оно идет на изображении. Алгоритм будет такой:
1. создаем сложный массив, как ранее мы делали для палитры. там одна ячейка будет состоять из 4 ячеек-образов в памяти по 32 байта.
2. при создании тайлового сета следует изменить немного логику:
2а. самый первый тайл в любом случае пишем в наш сложный массив, в первую из четырех ячеек, как есть.
2б. запускаем процедуру переворота тайлов и пишем готовые результаты в 2-3-4 ячейки этого-же элемента массива. то есть с зеркалами по Х, У, и оба зеркала.
2в. начиная со второго тайла прогонять через сравнение памяти весь этот массив, добавляя если совпадений не было. недобавляя, но отмечая галку зеркал в тайловой карте - если какой-то из тайлов в массиве совпался с текущим.
Получается образ в памяти тайловой карты и тайловый сет надо будет делать одновременно.

Схемы переворотов тайлов были выше (картинку прикладывал). В теории тут все понятно, а вот с точки зрения циферок надо будет мудрить. Так как в 1 байте там по 2 пикселя, то есть каждый байт надо будет переворачивать. Где-то в старых проектах я это уже делал. Как найду где - скопирую оттуда и приложу к проекту. Таким образом у нас будет выкидывание повторяющихся тайлов. Хотя наверное в начале надо было сделать просто повторяющихся, а в следующей итерации кода - повторяющиеся и зеркальные, чтобы было проще в тему вникнуть. Сразу с обоими - как есть и зеркальными - код будет сложнее.

« Последнее редактирование: 10 Ноября 2025, 13:45:08 от SeregaZ »

как оказалось ссылки все сдохли

Оффлайн SeregaZ

  • Пользователь
  • Сообщений: 3005
  • Пол: Мужской
  • ливнул с форума
    • Youtube
    • Просмотр профиля
Итак, та часть где происходит переворачивание инфы. Сделал через "жесткий" массив, это там где Array[x]То есть он как бы всегда одинаковый размер имеет.
Такой-же массив, но с круглыми скобками Array(х) может изменять свой размер с помощью ReDim.
По итогу при запуске кода в окошке дебага будет высвечен текстом "тайл" без зеркал, и ниже с зеркалами для понимания, что должно происходить при зеркалировании.
; сложная структура массива для тайлов, чтобы организовать выкидывание повторяющихся тайлов
Structure usedtilesstruct
  original.a[32] ; .a[32] - жесткий массив на 32 байта
  xmirr.a[32]
  ymirr.a[32]
  bothmirr.a[32]
EndStructure
Global Dim UsedTiles.usedtilesstruct(1120) ; .usedtilesstruct(0) - изменяемый массив со структурой


Procedure CreateMirrors(arrayitemnum.u)
 
  ; у нас есть оригинальный тайл - UsedTiles(arrayitemnum)\original
  ; нужно просто перевернуть его данные для зеркал
 
  ; самое простое - по вертикали.
  ; просто перенос 1 строчки в 8, 2 в 7, 3 в 6, и так далее
  For y = 0 To 31 Step 4    ; мотаем 8 строк
    For px = 0 To 3         ; по 4 байта в строчке
      UsedTiles(arrayitemnum)\ymirr[px + 28 - y] = UsedTiles(arrayitemnum)\original[px + y]
    Next
  Next
 
  ; по горизонтали.
  ; каждый байт надо переносить и докучи еще переворачивать внутри
  ; $12, $34, $56, $78 в $87, $65, $43, $21
  ; используются сдвиги >> и маска & $F
  For y = 0 To 31 Step 4    ; мотаем 8 строк
    For px = 0 To 3         ; мотаем 4 байта, то есть 8 пикселей или 8 столбиков
      UsedTiles(arrayitemnum)\xmirr[y + px] = UsedTiles(arrayitemnum)\original[y + 3 - px] >> 4
      UsedTiles(arrayitemnum)\xmirr[y + px] + (UsedTiles(arrayitemnum)\original[y + 3 - px] & $F) << 4
    Next
  Next
 
  ; оба зеркала
  ; надо повторить зеркалирование по вертикали,
  ; просто вместо original указать xmirr - уже отзеркаленное по Х в качестве входных данных
  For y = 0 To 31 Step 4    ; мотаем 8 строк
    For px = 0 To 3         ; по 4 байта в строчке
      UsedTiles(arrayitemnum)\bothmirr[px + 28 - y] = UsedTiles(arrayitemnum)\xmirr[px + y]
    Next
  Next 
 
EndProcedure

UsedTiles(0)\original[0] = $1 ;{ заполняем наш "тайл" ерундой от 1 до 32
UsedTiles(0)\original[1] = $2
UsedTiles(0)\original[2] = $3
UsedTiles(0)\original[3] = $4
UsedTiles(0)\original[4] = $5
UsedTiles(0)\original[5] = $6
UsedTiles(0)\original[6] = $7
UsedTiles(0)\original[7] = $8
UsedTiles(0)\original[8] = $9
UsedTiles(0)\original[9] = $10
UsedTiles(0)\original[10] = $11
UsedTiles(0)\original[11] = $12
UsedTiles(0)\original[12] = $13
UsedTiles(0)\original[13] = $14
UsedTiles(0)\original[14] = $15
UsedTiles(0)\original[15] = $16
UsedTiles(0)\original[16] = $17
UsedTiles(0)\original[17] = $18
UsedTiles(0)\original[18] = $19
UsedTiles(0)\original[19] = $20
UsedTiles(0)\original[20] = $21
UsedTiles(0)\original[21] = $22
UsedTiles(0)\original[22] = $23
UsedTiles(0)\original[23] = $24
UsedTiles(0)\original[24] = $25
UsedTiles(0)\original[25] = $26
UsedTiles(0)\original[26] = $27
UsedTiles(0)\original[27] = $28
UsedTiles(0)\original[28] = $29
UsedTiles(0)\original[29] = $30
UsedTiles(0)\original[30] = $31
UsedTiles(0)\original[31] = $32
;}

Debug "original:"
For i = 0 To 31 Step 4
  Debug RSet(Hex(UsedTiles(0)\original[i]), 2, "0") + " " + RSet(Hex(UsedTiles(0)\original[i + 1]), 2, "0") + " " + RSet(Hex(UsedTiles(0)\original[i + 2]), 2, "0") + " " + RSet(Hex(UsedTiles(0)\original[i + 3]), 2, "0")
Next

CreateMirrors(arrayitemnum.u)

Debug ""
Debug "ymirr:"
For i = 0 To 31 Step 4
  Debug RSet(Hex(UsedTiles(0)\ymirr[i]), 2, "0") + " " + RSet(Hex(UsedTiles(0)\ymirr[i + 1]), 2, "0") + " " + RSet(Hex(UsedTiles(0)\ymirr[i + 2]), 2, "0") + " " + RSet(Hex(UsedTiles(0)\ymirr[i + 3]), 2, "0")
Next

Debug ""
Debug "xmirr:"
For i = 0 To 31 Step 4
  Debug RSet(Hex(UsedTiles(0)\xmirr[i]), 2, "0") + " " + RSet(Hex(UsedTiles(0)\xmirr[i + 1]), 2, "0") + " " + RSet(Hex(UsedTiles(0)\xmirr[i + 2]), 2, "0") + " " + RSet(Hex(UsedTiles(0)\xmirr[i + 3]), 2, "0")
Next

Debug ""
Debug "both:"
For i = 0 To 31 Step 4
  Debug RSet(Hex(UsedTiles(0)\bothmirr[i]), 2, "0") + " " + RSet(Hex(UsedTiles(0)\bothmirr[i + 1]), 2, "0") + " " + RSet(Hex(UsedTiles(0)\bothmirr[i + 2]), 2, "0") + " " + RSet(Hex(UsedTiles(0)\bothmirr[i + 3]), 2, "0")
Next


Основной же код будет чуть позжее... надо допиливать  :blush: пока-что работает не так как надо...

Так-же наверное сразу докручу сжатие. Хотя над сжатием еще бы покумекать. Основную идею то я понял... типа читает по 2 байта. И если вдруг 3 раза подряд это будет одно и то-же значение, то это дело можно поджать.
Было: "12 34 12 34 12 34"
Стало: "80 03 12 34"
Типа первый бит в 80 - означает сжатие, дальше 003 - что три раза повторяются следующие 2 байта.


***

В очередной раз, пока спал - думал. Надо переосмыслить подход. Плясать не от тайлового сета, а от тайловой карты. Читать номер тайла, переворачивать его в нужные зеркала, согласно инфе из карты, искать совпадения в уже внесенных тайлах в том моем сложном массиве и вносить в массив, если не было. А если было - просто менять старый номер на новый и править зеркала, если там были зеркала. Как бы с одной стороны куча ненужной работы в виде временного переворачивания тайла из тайлового сета... с другой стороны это делается средствами винды и современным компьютером, то как бы и ср@ть все равно ведь будет быстро. Внутренний перфекционист конечно сейчас бунтует... В выкидывателе тайлов я делал по другому. Можно конечно взять все оттуда, но хочу переосмыслить.
« Последнее редактирование: 12 Ноября 2025, 01:32:17 от SeregaZ »

как оказалось ссылки все сдохли

Оффлайн SeregaZ

  • Пользователь
  • Сообщений: 3005
  • Пол: Мужской
  • ливнул с форума
    • Youtube
    • Просмотр профиля
Сжатие, что описывал выше, будет примерно выглядеть так:
Enumeration
  #File
EndEnumeration

; RLE word compressor (16bit). PureBasic.
; вход: *src указывает на необработанные данные (tile set), size - размер в байтах
; выход: *dst - сжатые данные
; PureBasic RLE-word encoder with big endian output for Sega MD

Procedure WriteBEWord(*dst, pos, value)
  ; write 16bit big endian
  PokeA(*dst + pos, value >> 8)
  PokeA(*dst + pos + 1, value & $FF)
EndProcedure

Procedure ReadBEWord(*src, pos)
  ; Read 16-bit big-endian word from buffer (*src + pos)
  high = PeekA(*src + pos)
  low  = PeekA(*src + pos + 1)
  ProcedureReturn (high * 256) + low
EndProcedure

Procedure RLEWord_Encode(*src, size, *dst)
  i = 0
  o = 0

  ; first 2 bytes = decompressed size in bytes
  WriteBEWord(*dst, o, size) : o + 2

  While i < size
    ; Check for RLE run
    w = ReadBEWord(*src, i)
    count = 1
    j = i + 2
   
    ; Count consecutive identical words
    While j < size And ReadBEWord(*src, j) = w And count < $7FFF
      count + 1
      j + 2
    Wend
   
    If count >= 3  ; RLE encode if 3+ identical words
      WriteBEWord(*dst, o, $8000 | count) : o + 2
      WriteBEWord(*dst, o, w) : o + 2
      i = j
    Else
      ; RAW block - collect until we find 3+ identical words
      count = 1
      j = i + 2
     
      While j < size And count < $7FFF
        ; Check if we have 3 identical words ahead for RLE
        If j + 4 < size
          w1 = ReadBEWord(*src, j)
          w2 = ReadBEWord(*src, j + 2) 
          w3 = ReadBEWord(*src, j + 4)
          If w1 = w2 And w1 = w3
            Break  ; Stop RAW block before RLE run
          EndIf
        EndIf
        count + 1
        j + 2
      Wend
     
      WriteBEWord(*dst, o, count) : o + 2
     
      ; Copy raw words
      For k = 0 To count - 1
        WriteBEWord(*dst, o, ReadBEWord(*src, i + k * 2)) : o + 2
      Next
     
      i + count * 2
    EndIf
  Wend
 
  ; End marker
  ;WriteBEWord(*dst, o, 0) : o + 2
 
  ProcedureReturn o
 
EndProcedure

; Main program
error = 0

If ReadFile(#File, "tset.bin")
  ; получаем размер открытого файла
  tsetsize = Lof(#File)
  If tsetsize
    ; если размер больше 0 байт
   
    ; резервируем память нужного размера
    tsetmemory = AllocateMemory(tsetsize)
    tsetpakmem = AllocateMemory(tsetsize * 2) ; Может быть больше оригинала
    If tsetmemory And tsetpakmem
      ; если память зарезервировалась
     
      ; читаем из открытого файла в память
      ReadData(#File, tsetmemory, tsetsize)
    Else
      error = 1
    EndIf
  Else
    ; добавляем текст ошибки, на случай если файл тайл сета 0 байт - пустой
    MessageRequester("ошибка", "файл тайл сета по всей видимости пуст - 0 байт")
    error = 1
  EndIf
  CloseFile(#File)
Else
  ; добавляем текст ошибки, на случай если файла тайл сета нет
  MessageRequester("ошибка", "нет файла тайл сета")
  error = 1
EndIf

If error = 0
  Debug "Original size: " + Str(tsetsize)
  paksize = RLEWord_Encode(tsetmemory, tsetsize, tsetpakmem)
  Debug "Compressed size: " + Str(paksize)
 
  If CreateFile(#File, "tsetP.bin")
    WriteData(#File, tsetpakmem, paksize)
    CloseFile(#File)
    ;MessageRequester("Успех", "Сжатие завершено!")
  Else
    MessageRequester("Ошибка", "Не могу создать файл tsetP.bin")
  EndIf
 
  FreeMemory(tsetmemory)
  FreeMemory(tsetpakmem)
EndIf

Но смысла в этом не много... ибо если делать какие-то экраны для ромхаков, то ведь в разных играх по разному сжатие работает. Мне то для мув мейкера пойдет. А вот для ромхаков не очень... Так-же наверное надо сделать галку - нужно сжатие или не нужно. Так-же в самом асм коде надо будет добавить вилку - со сжатием тайловый сет или без и соответственно чтоб собиралось в ром или со сжатием или без, в зависимости от выбора. Еще правда с первыми двумя байтами - указанием размера разжатых данных - тоже надо покумекать... может оно и не нужно вовсе. С другой стороны - дополнительная проверка, а то ли мы разжали? Своеобразная контрольная сумма.

как оказалось ссылки все сдохли

Оффлайн SeregaZ

  • Пользователь
  • Сообщений: 3005
  • Пол: Мужской
  • ливнул с форума
    • Youtube
    • Просмотр профиля
Добавил галку дизеринга, так-же раздуплил как нулевым номером в палитре заливать черный, независимо от того есть ли он на изображении или нет. Хотя еще надо потестить. Пока-что результаты с Железным Человеком такие:

302091-0

Мой код из коробки, рожает по весу пикселей - жрет красный цвет накорню. С галкой дизеринга результат чуть лучше (понятно что одинаковых тайлов будет меньше, а изображение займет больше места в роме). Но палент квант, от которого я писаю кипятком, убил :) а контрольным в голову стал 4 палитровый вариант. Правда код импорта с 4 палитрами в сеговские цвета я недопилил, посему последнее изображение "сырое", но результат будет очень близкий. Наверное сделаю галки для импорта - в 1 палитру писать или в 4. Но если в 4, то тогда из палеткванта нужно будет сохранять два изображения - саму подготовленную картинку и палитру к ней.

Просьба не размещать с помощью тэга img изображение со стороной более 700 пикселей. Предупреждение №2. ghostdog3
« Последнее редактирование: 19 Ноября 2025, 05:00:39 от ghostdog3 »

как оказалось ссылки все сдохли

Оффлайн SeregaZ

  • Пользователь
  • Сообщений: 3005
  • Пол: Мужской
  • ливнул с форума
    • Youtube
    • Просмотр профиля
Марафон кодинга уперся в стену :) По всей видимости, когда размер тайлового сета очень большой - больше, чем 32767, то есть видимо этот самый .w вместо .u - то есть +32767 -32767 вместо +65535, то распаковка не работает. Если тайловый сет меньше, то проблемы вроде нет. Еще не понимаю почему не вижу тайловую карту. Ведь карта загружается до тайлового сета, то есть до ошибки в коде. По идее я должен в VDP увидеть карту. Палитру вижу, что загрузилась. Загрузка палитры еще выше по коду. Сранно все это :)

***

Так... GPT обрисовал картину, и предположил что дело в DecompressCheckEOF. Он сразу-же он выдал рекомендации изменить код и теперь там лонги вместо вордов и все завелось. Так-же правда остался затык с первыми двумя байтами в пожатом тайловом сете - они то скорей всего читаются как ворд в asm коде, а PB туда пишет как unicode. Выкинуть наверное надо... Все равно проверки на итоговый распакованный результат не прикрутил.

Как бы то нибыло - результатом доволен.

Чтобы загрузить 4 палитровое изображение из палеткванта надо сделать следующее:

https://rilden.github.io/tiledpalettequant/

1. загрузить нужное изображение из интырнетов, размером 320х224
2. изменить в настройках количество палитр с 8 на 4
3. количество цветов для палитры - поставить 16
4. bit per channel - 3 вместо 5
5. отметить shared color и оставить его черным - тогда первый цвет во всех 4 палитрах будет черным
6. дизеринг я ставлю fast, но можно поиграться, если знать что там выбирать диагональ не диагональ и фракции какие-то там...
7. жмакнуть квантизировать

По итогу на этой веб страничке появится изображение с уже пересобранными цветами. Сохраняем изображение под произвольным именем, а вот вторую картинку - картинка палитры - сохраняем в папку с нашей программой и под именем pqpal.png

После этого уже можно запускать нашу программу, и импортировать в неё это изображение. Оно разобьется на тайлы с разными палитрами и все сохранит в "сеговском" формате.

Кода очень много. Старался, комментировал все что возможно, чтоб было понятно. Но кода прям очень много и можно поплыть :) Старые то примеры делал коротенькие файлы, чтобы акцентироваться на каких-то маленьких кирпичиках, из которых потом можно рожать пирамиды как у Хеопса... но тут прям завал.

как оказалось ссылки все сдохли