Здраствуйте всем кто слышит. Вот мне нужно написать распоковщек графики для игры на нес, но как подойти к ентай штуке незнаю. Так вот. Немогли вы бы мне мне рассказать принцапы по написанию распаковщека или дать исходник какого-нибудь распаковщика к уже переведенной игре, что бы разобраться(желательно Pascal).
P.S. Прошу мня простить что вообще обноглел(Не сильно обижусь если куда-нибудь пошлете).
Помогите молодому программисту
Сообщений 1 страница 14 из 14
Поделиться12006-08-31 20:15:40
Поделиться22006-08-31 20:59:15
Эээ... А что именно распаковывать надо? Могу привести VB код распаковщика LZ77 графики в Pac-Man 2 на Sega.
Private Sub Command1_Click() If Dir(file1) = "" Then MsgBox "Указанный вами файл не существует!", vbCritical: Exit Sub If Dir(file2) <> "" Then If MsgBox("Файл уже существует, перезаписать?", vbQuestion + vbYesNo) = vbNo Then Exit Sub Else Kill (file2) Dim bte As Byte Dim uprbyte As Integer Open file1 For Binary As 1 Open file2 For Binary As 2 adr2 = 1 adr1 = Val("&H" + Adress) + 1 Get #1, adr1, bte If bte > 16 Then MsgBox "Неверный адрес начала архива!": Close: Exit Sub 'MsgBox "Считан начальный байт " & Hex(bte) & " по адресу " & Hex$(adr1 - 1) adr1 = adr1 + 1 num = 16 - bte dic = 2 ^ bte - 1 getuprbyte: Get #1, adr1, bte 'If bte > 16 Then MsgBox "ROM не правильного формата!": Close: Exit Sub 'MsgBox "Считан управляющий байт " & Hex(bte) & " по адресу " & Hex$(adr1 - 1) cnt = 0 adr1 = adr1 + 1 uprbyte = bte If uprbyte = 0 Then MsgBox "Управляющий байт по адресу " & Hex$(adr1 - 1) & " равен нулю - выход." GoTo ENDUNP End If count: cnt = cnt + 1 If cnt = 8 Or uprbyte = 0 Then GoTo getuprbyte ' If uprbyte / 2 = uprbyte \ 2 Then rbit = 0 Else rbit = 1 'MsgBox "Правый бит байта " & Hex(uprbyte) & " равен " & rbit uprbyte = uprbyte \ 2 If rbit = 1 Then Get #1, adr1, bte: adr1 = adr1 + 1 Put #2, adr2, bte: adr2 = adr2 + 1 'MsgBox "Правый бит равен 1, просто считываем байт " & Hex(bte) & " по адресу " & Hex(adr1 - 2) & " и пишем байт " & Hex(bte) & " по адресу " & Hex(adr2 - 2) GoTo count Else Get #1, adr1, bte: adr1 = adr1 + 1: pbyte1 = bte Get #1, adr1, bte: adr1 = adr1 + 1: pbyte2 = bte 'MsgBox "Правый бит равен 0, читаем байты " & Hex(pbyte1) & " и " & Hex(pbyte2) & " по адресу " & Hex(adr1 - 3) 'pbyte = Val("&h" + Right$("00" + Hex$(pbyte1), 2) + Right$("00" + Hex$(pbyte2), 2)) 'If pbyte < 0 Then pbyte = (pbyte1 * 256) + pbyte2 'MsgBox pbyte 'End If For koef = 1 To 16 If pbyte / 2 = pbyte \ 2 Then bitst = "0" & bitst Else bitst = "1" & bitst pbyte = pbyte \ 2 Next koef Right(Str$(bitsn1), Len(Str$(bitsn1)) - 1), 8) 'MsgBox bitsn2 & bitsn1 & "|" & bitst & "|" & Hex(adr1 - 3) & "|" & pbyte1 & " " & pbyte2 & "|" & pbyte bits2 = Right(bitst, 16 - num) bits1 = Left(bitst, num) For r = 0 To Len(bits1) - 1 byte1 = byte1 + Val(Mid(bits1, Len(bits1) - r, 1)) * (2 ^ r) Next r For r = 0 To Len(bits2) - 1 byte2 = byte2 + Val(Mid(bits2, Len(bits2) - r, 1)) * (2 ^ r) Next r If byte2 = 0 Then byte2 = 2048 adr2b = adr2 - byte2 If adr2b < 1 Then MsgBox adr2b & " " & adr2 & " - " & byte2 & "|||" & Hex(adr1 - 3) & " " & bitst If byte1 = 0 Then byte1 = 32 For cntr = 1 To byte1 Get #2, adr2b, bte: adr2b = adr2b + 1 Put #2, adr2, bte: adr2 = adr2 + 1 If bte < 0 Then MsgBox adr1 & " " & adr2 & " " & adr2b Next cntr End If bitst = "" pbyte = 0 bits = 0 bitsn1 = 0 bitsn2 = 0 byte1 = 0 byte2 = 0 adr2b = 0 GoTo count MsgBox "Почему выход?" ENDUNP: Close MsgBox "Всё! Последний байт по адресу " & Hex$(adr1 - 1) End Sub
З.Ы. ' - это комментарии, то есть не рабочий код.
З.З.Ы. Код ещё немного не доработан, так как я не знаю, что делать с размером словаря. Его небольшой глюк в том, что он выдаёт немного мусора после графики(видимо размер словаря ограничивает объём данных).
З.З.З.Ы. Да, скажите мне кто-нибудь пожалуйста, что же всё таки делает размер словаря.
З.З.З.З.Ы. Если надо - разъясню, как работает.
Отредактировано HoRRoR (2006-08-31 21:24:04)
Поделиться32006-09-01 02:54:57
Спасибо за код.
З.З.З.З.Ы. Если надо - разъясню, как работает
Но нечего не понял что делает так-что прошу разяснений(Непонял потому что vb незнаю).
Отредактировано D.s3mm (2006-09-01 02:55:52)
Поделиться42006-09-01 05:13:38
Думаю, объяснять тебе LZ77 бесполезно... Это все само придет с опытом и с годами. Кстати, что за игра? Ты уверен, что графика пожата?
Отредактировано Griever (2006-09-01 05:15:52)
Поделиться52006-09-01 07:36:16
Кстати, что за игра?
Cabal(U).nes
Ты уверен, что графика пожата?
Незнаю, но вот что видно в в тайлах.
(Несмею судить о том что это, но выравневание не помогает).
З.Ы. Появился вопрос размеры вот я читал в что ромы Snes расширять можно, а остольных приставок это возможно? ЕСли да то посколько?
Отредактировано D.s3mm (2006-09-01 08:03:34)
Поделиться62006-09-01 17:23:58
Думаю, объяснять тебе LZ77 бесполезно...
Почему? Там всё оооооочень просто.
З.Ы. Появился вопрос размеры вот я читал в что ромы Snes расширять можно, а остольных приставок это возможно? ЕСли да то посколько?
Можно всё, только надо либо знать асм, либо чтобы условия это позволяли(радиус действия указателей и т.п.
Тут, кстати, графика похоже не пожата.
Сейчас допишу пояснения к моему коду.
Поделиться72006-09-01 17:38:21
Разъясняю(давненько дело было, могу чё неправильно написать):
If Dir(file1) = "" Then MsgBox "Указанный вами файл не существует!", vbCritical: Exit Sub If Dir(file2) <> "" Then If MsgBox("Файл уже существует, перезаписать?", vbQuestion + vbYesNo) = vbNo Then Exit Sub Else Kill (file2) Dim bte As Byte Dim uprbyte As Integer Open file1 For Binary As 1 Open file2 For Binary As 2 adr2 = 1 adr1 = Val("&H" + Adress) + 1
Открытие файла, описание и присвоение переменным нужных значений. adr2=1, то есть адрес получаемого файла графики устанавливается как 1, т.к. в VB адрес начинается с 1. adr1=значению, полученному при обращении текста, введённого пользователем, то есть конвертируется из шестнадцатиричного формата, тебе это не обязательно. 1 прибавляетсяпо той же причине. То есть получется так: adr1=адрес в РОМе, adr2=адрес в получаемом файле.
Get #1, adr1, bte If bte > 16 Then MsgBox "Неверный адрес начала архива!": Close: Exit Sub 'MsgBox "Считан начальный байт " & Hex(bte) & " по адресу " & Hex$(adr1 - 1) adr1 = adr1 + 1 num = 16 - bte dic = 2 ^ bte - 1
Считывается первый байт, определяющий, сколько бит будет отводиться в двух байтах под кол-во считываемых байт, а сколько под "указатель", который указывает на сколько байт назад вернуться. Адрес РОМа увеличивается на 1, т.е. переходим к следующему байту. num=16-bte - определяется кол-во бит, отводящихся под кол-во повторений. Т.е., допустим, под указатель отводится 7 из 16 бит, => остаётся 9 бит под кол-во повторений.
getuprbyte: Get #1, adr1, bte 'If bte > 16 Then MsgBox "ROM не правильного формата!": Close: Exit Sub 'MsgBox "Считан управляющий байт " & Hex(bte) & " по адресу " & Hex$(adr1 - 1) cnt = 0 adr1 = adr1 + 1 uprbyte = bte If uprbyte = 0 Then MsgBox "Управляющий байт по адресу " & Hex$(adr1 - 1) & " равен нулю - выход." GoTo ENDUNP End If
Считывается "управляющий" байт, который будет говорить распаковщику, что делать.
Если он равен 0, то значит процедура распаковки закончена, если же нет, то идём дальше.
count: cnt = cnt + 1 If cnt = 8 Or uprbyte = 0 Then GoTo getuprbyte ' If uprbyte / 2 = uprbyte \ 2 Then rbit = 0 Else rbit = 1 'MsgBox "Правый бит байта " & Hex(uprbyte) & " равен " & rbit uprbyte = uprbyte \ 2 If rbit = 1 Then Get #1, adr1, bte: adr1 = adr1 + 1 Put #2, adr2, bte: adr2 = adr2 + 1 'MsgBox "Правый бит равен 1, просто считываем байт " & Hex(bte) & " по адресу " & Hex(adr1 - 2) & " и пишем байт " & Hex(bte) & " по адресу " & Hex(adr2 - 2) GoTo count Else Get #1, adr1, bte: adr1 = adr1 + 1: pbyte1 = bte Get #1, adr1, bte: adr1 = adr1 + 1: pbyte2 = bte 'MsgBox "Правый бит равен 0, читаем байты " & Hex(pbyte1) & " и " & Hex(pbyte2) & " по адресу " & Hex(adr1 - 3) 'pbyte = Val("&h" + Right$("00" + Hex$(pbyte1), 2) + Right$("00" + Hex$(pbyte2), 2)) 'If pbyte < 0 Then pbyte = (pbyte1 * 256) + pbyte2 'MsgBox pbyte 'End If For koef = 1 To 16 If pbyte / 2 = pbyte \ 2 Then bitst = "0" & bitst Else bitst = "1" & bitst pbyte = pbyte \ 2 Next koef Right(Str$(bitsn1), Len(Str$(bitsn1)) - 1), 8) bits2 = Right(bitst, 16 - num) bits1 = Left(bitst, num) For r = 0 To Len(bits1) - 1 byte1 = byte1 + Val(Mid(bits1, Len(bits1) - r, 1)) * (2 ^ r) Next r For r = 0 To Len(bits2) - 1 byte2 = byte2 + Val(Mid(bits2, Len(bits2) - r, 1)) * (2 ^ r) Next r If byte2 = 0 Then byte2 = 2048 adr2b = adr2 - byte2 If adr2b < 1 Then MsgBox adr2b & " " & adr2 & " - " & byte2 & "|||" & Hex(adr1 - 3) & " " & bitst If byte1 = 0 Then byte1 = 32 For cntr = 1 To byte1 Get #2, adr2b, bte: adr2b = adr2b + 1 Put #2, adr2, bte: adr2 = adr2 + 1 If bte < 0 Then MsgBox adr1 & " " & adr2 & " " & adr2b Next cntr End If bitst = "" pbyte = 0 bits = 0 bitsn1 = 0 bitsn2 = 0 byte1 = 0 byte2 = 0 adr2b = 0 GoTo count MsgBox "Почему выход?" ENDUNP: Close MsgBox "Всё! Последний байт по адресу " & Hex$(adr1 - 1) End Sub
Тут байт разлаживается по битам, начиная с правого. Происходит это путём логического сдвига вправо, т.е. все биты сдвигаются вправо и самый правый читается программой. Если бит равен 1, то просто считываем байт в файл(приставка делает это в видеопамять). Если бит равен 0, то считывается два байта подряд, у которых потом берутся первые num бит(num - кол-во бит, отводящееся под кол-во повторений), хотя можно взять первые num-16 бит с другой стороны, то есть если на указатель отводится n бит, то на кол-во повторений остаётся 16-n бит, т.к. в двух байтах 16 бит. В данном случае справа берётся num-16 бит, это будет "указатель". Оставшейся биты определяют кол-во повторений. Ну так вот, программа возвращается назад в создаваемом файле графики на столько байт, какое значение имеет "указатель", считывает кол-во байт, которое определяется битами, отвечающими за кол-во повторений, а затем пишет их в этот же файл, только уже в конце.
Всё это будет повторятся, пока "управляющий" байт не станет равен нулю, затем программа переходит к считыванию следующего "управляющего" байта, пока она не встретин нулевой "управляющий" байт.
Дальше идёт присвоение переменным исходных значений.
Хочу ещё раз обратить внимание на знаки ' , после них идёт не рабочая часть кода, это просто комментарии.
Если чего не понял - спрашивай, я иногда сам себя не понимаю
Отредактировано HoRRoR (2006-09-01 19:39:08)
Поделиться82006-09-01 17:44:02
Тут, кстати, графика похоже не пожата.
Хотя, может RLE...
Поделиться92006-09-01 20:22:15
З.Ы. Появился вопрос размеры вот я читал в что ромы Snes расширять можно, а остольных приставок это возможно? ЕСли да то посколько?
В конец рома можно что-нибудь запихнуть,изменив при этом пойнтер.На Genesis,по-моему, можно до 4 Mb.(Или до 8-не помню).
Поделиться102006-09-02 19:19:46
Чёрт... У тебя нюх что-ли на такие вещи? К счастью, мне опять было нечего делать весь день: да, графика пожата RLE.
Правда, такого RLE я ещё не встречал.
Поначалу я всё думал, что тут им и не пахнет, однако, разобравшись в коде понял, что принципиально
он напоминает именно RLE. Точнее, сам алгоритм не так сложен, но с точки зрения кода игры можно было
всё это cделать намного легче, как в большинстве других игр - эффективность сжатия от этого бы не
снизилась. Специально не говорю что за алгоритм - если захочешь - можешь попробовать сам всё распаковать -
не буду лишать удовольствия. Вот что у меня получилось:
Тайловая карта титульника(конечно не только титульника) пожата тем же муторным алгоритмом.
На рисунке - разжатая графика титульника, повешенная на разжатую тайловую карту титульника.
Графика внутриигровая не пожата, зато повсюду спрайтовые надписи =).
Текст, вроде, нормальный,судя по заставке - дальше мне лень было лезть. А есть ли там вообще текст?
Не стоит забывать и о главной проблеме: написание упаковщика. Чем легче алгоритм(а RLE относится
к элементарным), тем хуже он жмёт данные. Т.е. поставил лишнюю чёрточку в одной букве(особенно это
касается Ж) - RLE пожмёт данные в бОльшую цепочку - ресурс не влезет в ром. Та же ситуация и с
тайловой картой, но она нагляднее, плюс - оригинальная тайловая карта тоже очень плохо пожалась.
И, наконец, очень трудно само написание упаковщика. Мало того, что нельзя воспользоваться подобием
из кода игры (как это бывает с распаком), так ещё возникают тысячи мелких проблем с особенностями
работы упаковщика. Помнится, я под самый общий RLE писал упаковщик - до сих пор как-то криво жмёт,
но, вроде, это не сказывается на качестве графики...
Отредактировано Griever (2006-09-02 19:24:34)
Поделиться112006-09-03 03:14:07
Огромное спасибо за сделаную за меня работу.
P.S. после прочтения темы форума про RLE в N-цатый раз у меня появился вопрос(кахись с него и нодо было начинать разговор) вот там написано:
...{Неизвестный байт}{00}{Описывающий байт}{Байты графики}...
В чем, где этот код виден и как его отличить от ненужного?
Поделиться122006-09-03 03:46:42
В чем, где этот код виден и как его отличить от ненужного?
Этот код ты можешь увидить в обычном hex-редакторе, а чтобы отличить его от ненужного, ты должен заранее найти место с пожатыми данными, например поганкой, т.е. поганить РОМ до тех пор, пока не изменятся искомые данные. Определив границы кода тебе легче будет разобраться с алгоритмом, ещё легче это будет при знании асма и имении дебагера.
Поделиться132006-09-06 01:32:24
Да, ещё есть житейский способ: особенность RLE в том что есть цепь с непожатыми данными(если байты идут все время разные). вот их и ищешь. смотришь где они обрываются на каком-нибудь необычном байте - он и будет управляющим.
Поделиться142006-09-06 02:05:36
В LZ77 первые байты, кстати, тоже идут не пожатыми.