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

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

Оффлайн SeregaZ

  • Пользователь
  • Сообщений: 2704
  • Пол: Мужской
  • ливнул с форума
    • 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

  • Пользователь
  • Сообщений: 5640
    • Просмотр профиля
соответственно в процессе работы конвертирует 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

  • Пользователь
  • Сообщений: 2704
  • Пол: Мужской
  • ливнул с форума
    • 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

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

Оффлайн SeregaZ

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

Оффлайн SeregaZ

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

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

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

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

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

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

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

Оффлайн SeregaZ

  • Пользователь
  • Сообщений: 2704
  • Пол: Мужской
  • ливнул с форума
    • 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

  • Пользователь
  • Сообщений: 2704
  • Пол: Мужской
  • ливнул с форума
    • 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

  • Пользователь
  • Сообщений: 2704
  • Пол: Мужской
  • ливнул с форума
    • 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

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

302091-0

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

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

Оффлайн SeregaZ

  • Пользователь
  • Сообщений: 2704
  • Пол: Мужской
  • ливнул с форума
    • 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

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

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