Skip to content

Instantly share code, notes, and snippets.

@Enichan
Last active January 21, 2020 10:53
Show Gist options
  • Save Enichan/a5e808a65c3d8854c5639b15b7a1d20b to your computer and use it in GitHub Desktop.
Save Enichan/a5e808a65c3d8854c5639b15b7a1d20b to your computer and use it in GitHub Desktop.
Takes a byte[] array with binary data, and outputs that to the .p8 pico 8 cartridge format
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class P8Writer {
public const int RomSize = 0x4300;
private byte[] data;
private StringBuilder str;
public P8Writer(byte[] data) {
this.data = data;
}
public string Write() {
str = new StringBuilder();
str.Append(@"pico-8 cartridge // http://www.pico-8.com
version 16
__lua__
-- data cartridge
");
if (data.Length > 0) {
var gfx = new byte[0x2000];
Buffer.BlockCopy(data, 0, gfx, 0, Math.Min(gfx.Length, data.Length));
WriteGfx(gfx);
}
if (data.Length > 0x3000) {
var gff = new byte[0x100];
Buffer.BlockCopy(data, 0x3000, gff, 0, Math.Min(gff.Length, data.Length - 0x3000));
WriteGff(gff);
}
if (data.Length > 0x2000) {
var map = new byte[0x1000];
Buffer.BlockCopy(data, 0x2000, map, 0, Math.Min(map.Length, data.Length - 0x2000));
WriteMap(map);
}
if (data.Length > 0x3200) {
var sfx = new byte[0x1100];
Buffer.BlockCopy(data, 0x3200, sfx, 0, Math.Min(sfx.Length, data.Length - 0x3200));
WriteSfx(sfx);
}
if (data.Length > 0x3100) {
var music = new byte[0x100];
Buffer.BlockCopy(data, 0x3100, music, 0, Math.Min(music.Length, data.Length - 0x3100));
WriteMusic(music);
}
if (data.Length > 0x4300) {
throw new Exception("Data won't fit!");
}
return str.ToString();
}
private void WriteGfx(byte[] data) {
str.AppendLine("__gfx__");
for (int i = 0, o = 0; i < 128; i++) {
for (int j = 0; j < 64; j++, o++) {
str.Append(Reverse(data[o].ToString("x2")));
}
str.AppendLine();
}
}
private string Reverse(string s) {
var str = new StringBuilder();
for (int i = s.Length - 1; i >= 0; i--) {
str.Append(s[i]);
}
return str.ToString();
}
private void WriteGff(byte[] data) {
str.AppendLine("__gff__");
for (int i = 0, o = 0; i < 2; i++) {
for (int j = 0; j < 128; j++, o++) {
str.Append(data[o].ToString("x2"));
}
str.AppendLine();
}
}
private void WriteMap(byte[] data) {
str.AppendLine("__map__");
for (int i = 0, o = 0; i < 32; i++) {
for (int j = 0; j < 128; j++, o++) {
str.Append(data[o].ToString("x2"));
}
str.AppendLine();
}
}
private void WriteSfx(byte[] data) {
str.AppendLine("__sfx__");
for (int i = 0, o = 0; i < 64; i++) {
str.Append(data[o + 64].ToString("x2")); // editor mode
str.Append(data[o + 65].ToString("x2")); // speed
str.Append(data[o + 66].ToString("x2")); // loop start
str.Append(data[o + 67].ToString("x2")); // loop end
for (int j = 0; j < 32; j++, o += 2) {
// first byte
var pitch = data[o] & 0x3F; // 00111111
var waveform1 = (data[o] & 0x40) >> 6; // 01000000
var waveform2 = (data[o] & 0x80) >> 7; // 10000000
// second byte
var waveform3 = data[o + 1] & 0x1; // 00000001
var volume = (data[o + 1] & 0xE) >> 1; // 00001110
var effect = (data[o + 1] & 0x70) >> 4; // 01110000
var custom = (data[o + 1] & 0x80) >> 7; // 10000000
// 0x?? - pitch
str.Append(pitch.ToString("x2"));
// 0x? - waveform
var waveform = waveform1 | (waveform2 << 1) | (waveform3 << 2) | (custom << 3);
str.Append(waveform.ToString("x1"));
// 0x? - volume
str.Append(volume.ToString("x1"));
// 0x? - effect
str.Append(effect.ToString("x1"));
}
str.AppendLine();
o += 4;
}
}
private void WriteMusic(byte[] data) {
str.AppendLine("__music__");
for (int i = 0, o = 0; i < 64; i++, o += 4) {
byte flags = 0;
if ((data[o] & 128) != 0) {
data[o] &= 0x7F;
flags |= 1;
}
if ((data[o + 1] & 128) != 0) {
data[o + 1] &= 0x7F;
flags |= 2;
}
if ((data[o + 2] & 128) != 0) {
data[o + 2] &= 0x7F;
flags |= 4;
}
if ((data[o + 3] & 128) != 0) {
data[o + 3] &= 0x7F;
flags |= 8;
}
str.AppendFormat("{0} {1}{2}{3}{4}",
flags.ToString("x2"), data[o].ToString("x2"), data[o + 1].ToString("x2"), data[o + 2].ToString("x2"), data[o + 3].ToString("x2"));
str.AppendLine();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment