Skip to content

Instantly share code, notes, and snippets.

@attic-stuff
Last active July 29, 2025 17:19
Show Gist options
  • Select an option

  • Save attic-stuff/7831fa3ec2cde75bc8dfacbd20515a4e to your computer and use it in GitHub Desktop.

Select an option

Save attic-stuff/7831fa3ec2cde75bc8dfacbd20515a4e to your computer and use it in GitHub Desktop.
small libary for reading/writing jasc-pal palette files
/**
* creates a struct object for managing a JASC-PAL color palette
* @param {Real} dot_pal_file the path to the .pal file
*/
function jasc_pal_pallette(dot_pal_file) constructor {
/**
* parses the .pal file
* @param {string} dot_pal_file the path toe the .pal file
*/
static parse_jasc_pal_file = function(dot_pal_file) {
var pal_file_buffer = buffer_load(dot_pal_file);
var pal_file_contents = buffer_read(pal_file_buffer, buffer_text);
pal_file_contents = string_trim(pal_file_contents);
buffer_delete(pal_file_buffer);
self.palette = string_split(pal_file_contents, "\r\n");
if (palette[0] != "JASC-PAL" or palette[1] != "0100") {
palette = [ ];
return;
}
array_delete(palette, 0, 3);
array_map_ext(palette, function(color_string) {
var character_index = 1;
var color_string_length = string_length(color_string);
var left_shift = 0;
var color_integer = 0;
var accumulated_text = ""
while (character_index <= color_string_length) {
var this_character = string_char_at(color_string, character_index);
if (this_character == " ") {
color_integer = color_integer | (real(accumulated_text) << (8 * left_shift));
accumulated_text = "";
left_shift = left_shift + 1;
} else {
accumulated_text = accumulated_text + this_character
}
character_index = character_index + 1;
}
color_integer = color_integer | (real(accumulated_text) << (8 * left_shift));
return color_integer;
});
}
/**
* returns a normalized set of channel values for a color
* @param {real} palette_index which color to use
*/
static fetch_normalized_color = function(palette_index) {
var color_integer = palette[palette_index];
biased_color.r = (color_integer & 255) / 255;
biased_color.g = ((color_integer >> 8) & 255) / 255;
biased_color.b = ((color_integer >> 16) & 255) / 255;
return biased_color;
}
/**
* populates a uniform-ready array of the palette for a shader
* @param {real} total_colors the total number of colors expected for the uniform
*/
static populate_shader_array = function(total_colors) {
shader_array = array_create(total_colors * 3, 0);
array_foreach(palette, function(color_integer, palette_index) {
var index_offset = palette_index * 3;
shader_array[index_offset] = (color_integer & 255) / 255;
shader_array[index_offset + 1] = ((color_integer >> 8) & 255) / 255;
shader_array[index_offset + 2] = ((color_integer >> 16) & 255) / 255;
})
}
/**
* turns the palette into a propr jasc-pal .pal file
* @param {string} palette_name the name of the palette, used for the filename
*/
static write_palette_to_pal_file = function(palette_name) {
array_foreach(palette, function(color_integer) {
var red = color_integer & 255;
var green = (color_integer >> 8) & 255;
var blue = (color_integer >> 16) & 255;
file_header = file_header + $"{red} {green} {blue}\r\n";
});
var file_byte_size = string_byte_length(file_header);
var pal_file_buffer = buffer_create(file_byte_size, buffer_fixed, 1);
buffer_write(pal_file_buffer, file_header, buffer_text);
buffer_save(pal_file_buffer, $"{palette_name}.pal");
buffer_delete(pal_file_buffer);
file_header = $"JASC-PAL\r\n0100\r\n{color_count}\r\n";
}
/**
* returns a color integer from the palette
* @param {real} palette_index which color to fetch
*/
static fetch_color = function(palette_index) {
return palette[palette_index];
}
/**
* sets a old color to a new color
* @param {real} palette_index which color to swap
* @param {real} new_color_integer the new color
*/
static set_color = function(palette_index, new_color_integer) {
palette[palette_index] = new_color_integer;
}
/**
* adds a new color to the palette
* @param {real} new_color_integer the new color
*/
static add_color = function(new_color_integer) {
array_push(palette, new_color_integer);
color_count = array_length(palette);
}
/**
* removes a color from the palette
* @param {real} palette_index which color to yeet
*/
static remove_color = function(palette_index) {
array_delete(palette, palette_index, 1);
color_count = array_length(palette);
}
/**
* creates a png with each of the colors
* @param {string} palette_name the name of the file, uncluding the path, without the png
* @param {real} [color_size] the size of each block of color
*/
static write_palette_to_png = function(palette_name, color_size = 4) {
var color_columns = ceil(color_count * 0.5 * 0.5) * 2;
var palette_canvas = surface_create(color_columns * color_size, 2 *color_size);
surface_set_target(palette_canvas) {
draw_clear_alpha(#000000, 0);
for (var palette_index = 0; palette_index < color_count; palette_index = palette_index + 1) {
var color_column = palette_index mod color_columns;
var color_row = palette_index div color_columns;
var color_integer = palette[palette_index];
var x1 = color_column * color_size;
var y1 = color_row * color_size;
var x2 = x1 + color_size - 1;
var y2 = y1 + color_size - 1;
draw_rectangle_color(x1, y1, x2, y2, color_integer, color_integer, color_integer, color_integer, false);
}
surface_reset_target();
}
surface_save(palette_canvas, $"{palette_name}.png");
surface_free(palette_canvas);
}
palette = [ ];
biased_color = { r: 0, g: 0, b: 0 }
shader_array = undefined;
parse_jasc_pal_file(dot_pal_file);
color_count = array_length(palette);
file_header = $"JASC-PAL\r\n0100\r\n{color_count}\r\n";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment