 |
|
 |
|
| SMW/ROMhacking tool related code library |
|
Forum Index - Hobbies - Computers & Technology - SMW/ROMhacking tool related code library |
|
Pages: 1 2  |
|
|
|
| Posted on 2009-12-21 11:22:13 AM |
Link | Quote |
|
I decided to post a couple core functions from Xkas GUI here for good measure.
RemoveCommentsAndTrim
trims up an ASM patch so it can be more easily processed
Codeprivate string[] removeCommentsAndTrim(string[] input)
{
for (int i = 0; i < input.Length; i++)
{
if (input[i].Contains(";"))
{
input[i] = input[i].Substring(0, input[i ].IndexOf(";"));
}
if (input[i].Contains("//"))
{
input[i] = input[i].Substring(0, input[i].IndexOf("//"));
}
input[i] = input[i].Trim();
}
return input;
}
CountBytes
Counts the bytes in an ASM patch, starting at a given line and ending at the next ORG or the end of the file
Codeprivate int countbytes(string asmpath, int startline)
{
int n = 0;
string[] a = File.ReadAllLines(asmpath);
a = removeCommentsAndTrim(a);
for (int i = startline; i < a.Length && !a[ i].ToLowerInvariant().Contains("org"); i++)
{
a[i] = a[i].ToLowerInvariant();
if (a[i].Contains(":"))
continue;
if (a[i].ToLowerInvariant().Contains("incbin"))
{
n += File.ReadAllBytes(asmpath.Substring(0, asmpath.LastIndexOf("\\") + 1) + a[i].Substring(7)).Length;
continue;
}
if (a[i].ToLowerInvariant().Contains("incsrc"))
{
n += countbytes(asmpath.Substring (0, asmpath.LastIndexOf("\\") + 1) + a[i].Substring(7), 0);
continue; // 1 2 /2 /1
}
int fair = 0;
for (int j = 0; j < a[i].Length; j++)
{
if (a[i].Substring(j, 1).IndexOfAny(letters) != -1)
{
fair++;
if (fair >= 3)
{
fair = 0;
n++;
}
}
else
fair = 0;
}
fair = 0;
for (int j = 0; j < a[i ].Length; j++)
{
if (a[i].Substring(j, 1).IndexOfAny(hex) != -1)
{
fair++;
if (fair >= 2)
{
fair = 0;
n++;
}
}
else
fair = 0;
}
}
return n;
}
GetFreeSpace
Searches for a given number of unprotected bytes in a ROM, starting in bank 10. Returns "not" if there isn't a string of free bytes long enough, "exp" if the ROM hasn't been expanded, or returns the hex address of the freespace.
Codeprivate string getfreespace(string rompath, int bytesneeded)
{
byte[] rombyte = File.ReadAllBytes(rompath);
if (rombyte.Length < 513 * 1024)
return "exp";
int header = 0;
if (rombyte[11] == 0 && rombyte[12] == 0 && rombyte[13] == 0)
header = 0x200;
int freebytes = 0;
int freespace = 0x80000 + header;
for (int i = freespace; i < rombyte.Length; i++)
{
if (rombyte[i] == 0x53)
{
if (rombyte[i + 1] == 0x54)
{
if (rombyte[i + 2] == 0x41)
{
if ((rombyte[i + 3] == 0x52) || (((i - header) & 0x77FFF) | 0x8000) == 0x8000)
{
if (freebytes >= bytesneeded)
{
rombyte[freespace] = 0x52;
rombyte[freespace + 1] = 0x41;
rombyte[freespace + 2] = 0x54;
rombyte[freespace + 3] = 0x53;
rombyte[freespace + 4] = (byte)(bytesneeded & 0xFF);
rombyte[freespace + 5] = (byte)(bytesneeded >> 8 & 0xFF);
rombyte[freespace + 6] = (byte)(bytesneeded ^ 0xFFFF & 0xFF);
rombyte[freespace + 7] = (byte)(bytesneeded ^ 0xFFFF >> 8 & 0xFF);
File.WriteAllBytes(rompath, rombyte);
string freestring = String.Format("{0:X}", PCSNES(freespace, header));
while (freestring.Length < 6)
{
freestring = "0" + freestring;
}
return freestring;
}
freebytes = 0;
i += 5 + rombyte[i + 4] + (rombyte[i + 5] * 0x100);
freespace = i;
}
}
}
}
freebytes++;
}
if (freespace >= bytesneeded)
{
rombyte[freespace] = 0x52;
rombyte[freespace + 1] = 0x41;
rombyte[freespace + 2] = 0x54;
rombyte[freespace + 3] = 0x53;
rombyte[freespace + 4] = (byte)(bytesneeded & 0xFF);
rombyte[freespace + 5] = (byte)(bytesneeded >> 8 & 0xFF);
rombyte[freespace + 6] = (byte)(bytesneeded ^ 0xFFFF & 0xFF);
rombyte[freespace + 7] = (byte)(bytesneeded ^ 0xFFFF >> 8 & 0xFF);
File.WriteAllBytes(rompath, rombyte);
string freestring = String.Format("{0:X}", PCSNES(freespace, header));
while (freestring.Length < 6)
{
freestring = "0" + freestring;
}
return freestring;
}
return "not";
}
mRecreateResourses
A great code I found somewhere on the internet. It re-creates a given resource in the folder of the tool.
Code private void mRecreateResource(string filename)
{
// Get Current Assembly refrence
Assembly currentAssembly = Assembly.GetExecutingAssembly();
// Get all imbedded resources
string[] arrResources = currentAssembly.GetManifestResourceNames();
foreach (string resourceName in arrResources)
{
if (resourceName == filename)
{
//Name of the file saved on disk
string saveAsName = AppDomain.CurrentDomain.BaseDirectory + filename;
FileInfo fileInfoOutputFile = new FileInfo(saveAsName);
//CHECK IF FILE EXISTS AND DO SOMETHING DEPENDING ON YOUR NEEDS
if (fileInfoOutputFile.Exists)
{
File.Delete(fileInfoOutputFile.ToString());
}
//OPEN NEWLY CREATING FILE FOR WRITTING
FileStream streamToOutputFile = fileInfoOutputFile.OpenWrite();
//GET THE STREAM TO THE RESOURCES
Stream streamToResourceFile =
currentAssembly.GetManifestResourceStream(resourceName);
//---------------------------------
//SAVE TO DISK OPERATION
//---------------------------------
const int size = 4096;
byte[] bytes = new byte[4096];
int numBytes;
while ((numBytes = streamToResourceFile.Read(bytes, 0, size)) > 0)
{
streamToOutputFile.Write(bytes, 0, numBytes);
}
streamToOutputFile.Close();
streamToResourceFile.Close();
}//end_if
}//end_foreach
}
...yep, that's about all for now.
One thing I am constantly annoyed at about SMWC is that if I try to index an array with int i, SMWC reads it as an italics tag.
Ersan to the rescue with [!
|
| Last edited on 2009-12-21 01:02:31 PM by Noobish Noobsicle. |
|
| Posted on 2009-12-29 06:58:47 PM |
Link | Quote |
|
Here is a small code I wrote in C# for a 'layer 3 palette editor', to get the current palette and color number on a 16x16 color palette grid. (Actually it was meant for a NES palette editor but both of their palettes pretty much behave the same)
Code int paletteNumber = (((e.X >> 4) / 4) + ((e.Y >> 4) * 4));
int colorNumber = ((e.X >> 4) & 0x03);
This can be used in a mouseover event.
Example values (numbers and borders put by me):
|
|
| Posted on 2010-09-10 08:23:30 PM |
Link | Quote |
|
I don't really have anything useful to share, but I do have a (not very efficient, but absolute) algorithm for converting hex to dec for C. This is for a two-character hex number, which you put in the argument.
COPYPASTA!
Codeint hexadecimaltc(char value[2]) //Two-character hexadecimal converter. Converts from hex to dec.
{
int num; //The number you get after the process is done.
int temp; //A temporary controller for the number you add to num.
if (value[0] == '0'){
temp = 0;
}
if (value[0] == '1'){
temp = 1;
}
if (value[0] == '2'){
temp = 2;
}
if (value[0] == '3'){
temp = 3;
}
if (value[0] == '4'){
temp = 4;
}
if (value[0] == '5'){
temp = 5;
}
if (value[0] == '6'){
temp = 6;
}
if (value[0] == '7'){
temp = 7;
}
if (value[0] == '8'){
temp = 8;
}
if (value[0] == '9'){
temp = 9;
}
if (value[0] == 'A' || value[0] == 'a'){
temp = 10;
}
if (value[0] == 'B' || value[0] == 'b'){
temp = 11;
}
if (value[0] == 'C' || value[0] == 'c'){
temp = 12;
}
if (value[0] == 'D' || value[0] == 'd'){
temp = 13;
}
if (value[0] == 'E' || value[0] == 'e'){
temp = 14;
}
if (value[0] == 'F' || value[0] == 'f'){
temp = 15;
}
num = 16 * temp;
if (value[1] == '0'){
temp = 0;
}
if (value[1] == '1'){
temp = 1;
}
if (value[1] == '2'){
temp = 2;
}
if (value[1] == '3'){
temp = 3;
}
if (value[1] == '4'){
temp = 4;
}
if (value[1] == '5'){
temp = 5;
}
if (value[1] == '6'){
temp = 6;
}
if (value[1] == '7'){
temp = 7;
}
if (value[1] == '8'){
temp = 8;
}
if (value[1] == '9'){
temp = 9;
}
if (value[1] == 'A' || value[1] == 'a'){
temp = 10;
}
if (value[1] == 'B' || value[1] == 'b'){
temp = 11;
}
if (value[1] == 'C' || value[1] == 'c'){
temp = 12;
}
if (value[1] == 'D' || value[1] == 'd'){
temp = 13;
}
if (value[1] == 'E' || value[1] == 'e'){
temp = 14;
}
if (value[1] == 'F' || value[1] == 'f'){
temp = 15;
}
num = num + temp;
return num;
}
|
|
| Posted on 2010-09-11 01:12:16 AM |
Link | Quote |
|
|
Or you could use the strtol() function? (It is located in stdlib.h)
|
|
| Posted on 2010-09-11 01:30:26 AM |
Link | Quote |
|
Code#include <iostream>
[...]
cout << dec << 0xff << endl Results in 255.
|
|
| Posted on 2010-09-11 03:48:56 AM |
Link | Quote |
|
Originally posted by YakovCode#include <iostream>
[...]
cout << dec << 0xff << endl Results in 255.
strtol is used when the given number is coming from a string. When it comes to inputting number from a programmers perspective like you did will usually result in a decimal output. The only exception to that would be using output modifiers on the iostream(or print style functions of C).
|
|
| Posted on 2010-09-11 11:40:08 PM |
Link | Quote |
|
Originally posted by p4plus2Or you could use the strtol() function? (It is located in stdlib.h)
What's that? I need something to convert decimal to hex anyway, and I don't know how %x works.
|
|
| Posted on 2010-09-12 12:27:28 AM |
Link | Quote |
|
Originally posted by mszegedyOriginally posted by p4plus2Or you could use the strtol() function? (It is located in stdlib.h)
What's that? I need something to convert decimal to hex anyway, and I don't know how %x works.
It will take a char array input and will return a long int.
Code
long int strtol(const char *start, char **end, int base);
More information can be found here:
http://www.cplusplus.com/reference/clibrary/cstdlib/strtol/
Also, %x works like this:
Code
printf("hex: %x", 100);
|
|
| Posted on 2011-07-13 01:33:07 PM |
Link | Quote |
|
Originally posted by x-tremeSorry for the bump, but what is the code for patch a ips patch in VB2008?
CodeDim romstream As New FileStream(romname, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
Dim ipsstream As New FileStream(patchname, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
Dim lint As Integer = CInt(ipsstream.Length)
Dim ipsbyte As Byte() = New Byte(ipsstream.Length - 1) {}
Dim rombyte As Byte() = New Byte(romstream.Length - 1) {}
Dim romresult As IAsyncResult
Dim ipsresult As IAsyncResult = ipsstream.BeginRead(ipsbyte, 0, lint, Nothing, Nothing)
ipsstream.EndRead(ipsresult)
Dim ipson As Integer = 5
Dim totalrepeats As Integer = 0
Dim offset As Integer = 0
Dim keepgoing As Boolean = True
'''///////////////End Init code
'''///////////////Start main code
While keepgoing = True
offset = ipsbyte(ipson) * &H10000 + ipsbyte(ipson + 1) * &H100 + ipsbyte(ipson + 2)
ipson += 1
ipson += 1
ipson += 1
'''//////////split between repeating byte mode and standard mode
If ipsbyte(ipson) * 256 + ipsbyte(ipson + 1) = 0 Then
'''/////////repeating byte mode
ipson += 1
ipson += 1
totalrepeats = ipsbyte(ipson) * 256 + ipsbyte(ipson + 1)
ipson += 1
ipson += 1
Dim repeatbyte As Byte() = New Byte(totalrepeats - 1) {}
For ontime As Integer = 0 To totalrepeats - 1
repeatbyte(ontime) = ipsbyte(ipson)
Next
romstream.Seek(offset, SeekOrigin.Begin)
romresult = romstream.BeginWrite(repeatbyte, 0, totalrepeats, Nothing, Nothing)
romstream.EndWrite(romresult)
ipson += 1
Else
'''/////////standard mode
totalrepeats = ipsbyte(ipson) * 256 + ipsbyte(ipson + 1)
ipson += 1
ipson += 1
romstream.Seek(offset, SeekOrigin.Begin)
romresult = romstream.BeginWrite(ipsbyte, ipson, totalrepeats, Nothing, Nothing)
romstream.EndWrite(romresult)
ipson = ipson + totalrepeats
End If
'''//////////Test For "EOF"
If ipsbyte(ipson) = 69 AndAlso ipsbyte(ipson + 1) = 79 AndAlso ipsbyte(ipson + 2) = 70 Then
keepgoing = False
End If
End While
romstream.Close()
ipsstream.Close()
Sorry for bumping the tread but since its sticked.....
|
| Last edited on 2011-07-13 01:33:39 PM by MarioErmando. |
|
| Posted on 2011-09-01 01:12:26 AM |
Link | Quote |
|
Some generic snes functions in Python, suggested by imamelia:
Codedef addresstostring(address, endianness = "little"):
return "".join([hex(ord(x))[2:] if len(hex(ord(x))[2:]) == 2 else "0"+hex(ord(x))[2:] for x in (address[::-1] if endianness == "little" else address)])
Takes in an address in little endian (or big endian if you specify anything else but "little" for the endianness parameter) and returns it as a formatted string (e.g. "\x00\x00\x08" will become "080000")
Codedef LoRomtoPC(address,header=False):
return (((address & 0x7f0000) >> 1) | (address & 0x7fff)) + header*0x200
def HiRomtoPC(address,header=False):
return (address & 0x3fffff) + header*0x200
def PCtoLoRom(address,header=False):
address = address-(header*0x200)
return ((address & 0x7F8000) << 1) + 0x8000 + (address & 0x7FFF)
def PCtoHiRom(address,header=False):
return 0xC00000 + ((address - header*0x200)&0x3FFFFF)
Pretty self explanatory, just the snes/PC conversion routines
Code
import re
class FreeSpace(object):
def __init__(self,start,length):
self.start = start
self.LoRom = PCtoLoRom(start)
self.HiRom = PCtoHiRom(start)
self.length = length
def __str__(self):
return "<FreeSpace object, start= {0} , length= {1} >".format(hex(self.start),hex(self.length))
def FindFreespace(data,size=1,zeros=False):
matches = re.finditer("STAR(....)",data,re.S)
count, RATs, addresses, lastRAT = 0,[],[],(0,0)
for match in matches:
length = int(addresstostring(match.groups()[0][0:2]),16)
if length^0xFFFF == int(addresstostring(match.groups()[0][2:]),16) and \
match.start() + 8 + length >= lastRAT[1]:
RATs.append((match.start(),match.start()+8+length))
lastRAT = (match.start(),match.start()+8+length)
if zeros:
for RAT in zip([(0,0)]+RATs,RATs+[(len(data),len(data))]):
if RAT[0][1]+1 < RAT[1][0]:
matches=re.finditer("".join(["\x00" for x in xrange(size)])+"\x00*",data[RAT[0][1]+1:RAT[1][0]])
for match in matches:
freespace = FreeSpace(RAT[0][1]+1+match.start(),match.end()-match.start())
addresses.append(freespace)
else:
for RAT in zip([(0,0)]+RATs,RATs+[(len(data),len(data))]):
if RAT[0][1]+1 < RAT[1][0]:
freespace = FreeSpace(RAT[0][1]+1, RAT[1][0]-RAT[0][1])
if freespace.length >= size:
addresses.append(freespace)
return addresses
First one is a class, it's not necessary (I could just use a tuple) but it's nicer to be able to call freespace.start than having to do freespace[0].
Following that is a freespace finder. It takes in the ROM data, how many bytes of freespace it should look for, and whether it should look for zeros or just space between RATs, and it returns a list of "FreeSpace" objects that represent areas of freespace in the ROM. And, just for fun, here's the 8 line version (Pastebinned because otherwise it creates massive table stretch) Beat that p4plus2 
Codedef FindFreespaceByBanks(data,size=1,zeros=False):
freespaces = FindFreespace(data,size,zeros)
bankfreespaces = [[] for x in xrange(len(data)//0x8000)]
for freespace in freespaces:
banknum = freespace.start//0x8000
posinbank = freespace.start%0x8000
if posinbank + freespace.length > 0x8000:
tempfreespaces = []
length = freespace.length
newfreespace = FreeSpace(freespace.start,0x8000-posinbank)
bankfreespaces[banknum].append(newfreespace)
tempfreespaces.append(newfreespace)
length -= 0x8000-posinbank
banknum += 1
while length > 0x8000:
newfreespace = FreeSpace(0x8000*banknum,0x8000)
bankfreespaces[banknum].append(newfreespace)
tempfreespaces.append(newfreespace)
length -= 0x8000
banknum += 1
newfreespace = FreeSpace(0x8000*banknum,length)
bankfreespaces[banknum].append(newfreespace)
tempfreespaces.append(newfreespace)
else:
bankfreespaces[banknum].append(freespace)
return bankfreespaces
This is a convenience wrapper around the freespace finding function. Essentially it just takes the freespace and splits it up into banks, it takes the same parameters as the freespace function and returns a list of lists of freepsace objects. Each item in the list corresponds to a bank, so if you wanted, e.g., all freespace within bank ten, you would just grab the tenth item in the list and it would be a list of freespace objects that correspond to the freespace found in bank 10.
These are all available as a module, plus a slogger clone to give an idea of how to use them, from here. Not that really anyone else uses python, but now it's out there if anyone needs it.
|
|
| Posted on 2011-09-05 11:32:58 AM |
Link | Quote |
|
|
Now we just need a convenience wrapper for the convenience wrapper. As much as I appreciate you making these, I still don't see why you had to do the function that way and not just have one that finds the first available area of freespace given a file handle and size (and not letting it cross a bank boundary, of course). That just seems to be needlessly complicating things, if you ask me.
|
| Last edited on 2011-09-05 11:33:45 AM by imamelia. |
|
| Posted on 2011-09-05 04:19:29 PM |
Link | Quote |
|
Originally posted by imameliaI still don't see why you had to do the function that way and not just have one that finds the first available area of freespace given a file handle and size (and not letting it cross a bank boundary, of course). That just seems to be needlessly complicating things, if you ask me.
It's slow to look for freespace every single time. This way, it would take a minimal amount of coding on your part to vastly speed up the searching. However, I added a little function anyways that takes what is returned by "FindFreespaceByBanks" function, a length, and whether or not the freespace should be updated (True by default) and returns a freespace object for you, updating the one in the list so that it will take into account the code you are inserting (Eww, side effect). This also included changing the freespace object, but merely for convenience:
Codeclass FreeSpace(object):
def __init__(self,start,length):
self.start = start
self.LoRom = PCtoLoRom(start)
self.HiRom = PCtoHiRom(start)
self.length = length
def UpdateAddress(self,length):
self.length -= length
self.start += length
self.LoRom = PCtoLoRom(self.start)
self.HiRom = PCtoHiRom(self.start)
def __str__(self):
return "<FreeSpace object, start= {0} , length= {1} >".format(hex(self.start),hex(self.length))
def GetFirstFreespace(banks,length, update = True):
for freespaces in banks:
for freespace in freespaces:
if freespace.length >= length:
tmpfreespace = FreeSpace(freespace.start,freespace.length)
if update:
freespace.UpdateAddress(length)
return tmpfreespace
return None
I've updated the download for snesproc to add these.
Possible usage would look like this:
Codeimport snesproc
file1 = open("ROM.smc",'rb')
data = file1.read()
file1.close()
if len(data)%1024:
data=data[0x200:]
freespaces = snesproc.FindFreespaceByBanks(data,1,True)
print snesproc.GetFirstFreespace(freespaces[0x10:],0x343)
I don't know if I mentioned, but these all require the ROM to be non headered.
|
|
| Posted on 2011-12-15 05:48:26 PM |
Link | Quote |
|
This method of converting between 8-bit colour channels and 5-bit colour channels is far more accurate than simple bit-shifts.
Codebyte Convert8BitTo5Bit(byte value)
{
return (byte)((value * (31.0 / 255.0) + 0.5);
}
byte Convert5BitTo8Bit(byte value)
{
return (byte)(((value & 31) * (255.0 / 31.0) + 0.5);
}
Alternatively, if you want to use bit shifts to convert a 5-bit channel value to an 8-bit channel value, the following code shows the most accurate way to do this.
Codebyte Convert5BitTo8Bit(byte value)
{
return (byte)(((value & 31) << 3) | ((value & 31) >> 2));
}
Of 32 possible values, 4 are off by 1.
|
|
| Posted on 2011-12-16 06:51:30 AM |
Link | Quote |
|
|
using floating point casting is an amazingly inefficient method.
|
|
| Posted on 2011-12-16 04:13:04 PM |
Link | Quote |
|
Originally posted by spel werdz riteusing floating point casting is an amazingly inefficient method.
I tried it in .NET before. I did 1 billion 500 million conversions from a 5-bit channel to an 8-bit channel.
e: 1 billion values takes too long for my results; must have been 500 million values instead.
The "bitbashing" method I showed took ~4 ~3.687 seconds to compute.
Using floating point method took ~6 ~5.618 seconds to compute.
If you want to see what's really inefficient, using Math.Round instead of the method I showed, the floating point method took ~12 ~18.339 seconds to compute.
Using Convert.ToByte took ~42 seconds to compute. Holy crap, now THAT's inefficient.
e: Did it again, got ~13.569 seconds with 500 million values. How odd.
If the floating point method taking 50% longer is a problem, just use the bitbashing method I demonstrated. It is far superior to simple bit shifting (AKA "dumb conversion").
e: A precomputed lookup table works fine, too. After all, when converting a 5-bit channel to an 8-bit channel, a lookup table would only be 32 bytes.
Using the lookup table took ~3.390 for the same 500 million values.
|
| Last edited on 2011-12-17 01:19:40 PM by ShadowFan-X. |
|
| Posted on 2012-03-29 07:50:16 PM |
Link | Quote |
|
Lua: load ROM into a table
Code-- Prompt user for ROM name.
local file, fileName, bytes
while not fileOpen do
io.write("Enter ROM name:\n")
fileName = io.read()
file = io.open(fileName, "rb")
if not file then print("Error opening file\n") else fileOpen = true end
end
-- Now, split file into a table.
local romBuffer = {}
while true do
local bytes = file:read(1)
if not bytes then break end
romBuffer[#romBuffer + 1] = bytes
end
The ROM is loaded byte by byte into romBuffer table.
Now we can test out this code by printing some bytes from ROM:
Codefor i = 1, 1000 do
io.write(string.format("%02X ", string.byte( romBuffer[ i ] )))
if i % 8 == 0 then io.write("\n") end
end
I hope this is helpful for those who use Lua. It's very simple and quick, but maybe the code could be optimized more. ;)
|
|
| Posted on 2012-08-10 02:46:18 AM |
Link | Quote |
|
Here's a class, written in Java, that converts a 4BPP .bin file back and forth between a more useful format:
Codepublic class DataConverter {
/**
* Converts data from the SNES 4BPP format to a packed array of palette values.
*
* @param data data to convert
* @return converted array
*/
public static byte[] fromSNES4BPP(byte[] data) {
byte[] tileData = new byte[data.length*2];
for (int i = 0; i < tileData.length; i++) {
int tile = i / 64;
int row = (i % 64) / 8;
int col = i % 8;
byte value = 0;
value |= getBit(data[0 + tile*32 + row*2], (byte) 7 - col);
value |= getBit(data[1 + tile*32 + row*2], (byte) 7 - col) << 1;
value |= getBit(data[16 + tile*32 + row*2], (byte) 7 - col) << 2;
value |= getBit(data[17 + tile*32 + row*2], (byte) 7 - col) << 3;
tileData[i] = value;
}
return tileData;
}
/**
* Converts data from a packed array of palette values to the SNES 4BPP format.
*
* @param data data to convert
* @return converted array
*/
public static byte[] toSNES4BPP(byte[] tileData) {
byte[] data = new byte[tileData.length/2];
for (int i = 0; i < tileData.length; i++) {
int tile = i / 64;
int row = (i % 64) / 8;
int col = i % 8;
data[0 + tile*32 + row*2] |= getBit(tileData[i], 0) << 7 - col;
data[1 + tile*32 + row*2] |= getBit(tileData[i], 1) << 7 - col;
data[16 + tile*32 + row*2] |= getBit(tileData[i], 2) << 7 - col;
data[17 + tile*32 + row*2] |= getBit(tileData[i], 3) << 7 - col;
}
return data;
}
/**
* Gets the value of a bit in a byte.
*
* @param value byte value to check
* @param bit which bit to check
* @return either 0 or 1
*/
public static byte getBit(byte value, int bit) {
return (byte) (value >>> bit & 0x1);
}
}
The converted array contains nothing more than a series of palette values, from 0x0 to 0xF. While this is Java code, it could easily be converted to other languages.
Note that this comes from my tile editor, SNESTile, and a prettier version of this class can be found here.
|
|
|
Pages: 1 2  |
|
|
|
|
Forum Index - Hobbies - Computers & Technology - SMW/ROMhacking tool related code library |
|
|
 |
|
 |
The purpose of this site is not to distribute copyrighted material, but to honor one of our favourite games.
Copyright © 2005 - 2013 - SMW Central Legal Information - Link To UsTotal queries: 29
|
|
|
|