diff --git a/CMakeLists.txt b/CMakeLists.txt index a722015..42ab0a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -156,6 +156,7 @@ target_sources(xsystem4 PRIVATE src/hll/InputString.c src/hll/KiwiSoundEngine.c src/hll/LoadCG.c + src/hll/MADLoader.c src/hll/MainEXFile.c src/hll/MainSurface.c src/hll/MamanyoDemo.c @@ -171,6 +172,8 @@ target_sources(xsystem4 PRIVATE src/hll/MusicSystem.c src/hll/NewFont.c src/hll/OutputLog.c + src/hll/P3MapSprite.c + src/hll/P3SquareSprite.c src/hll/PassRegister.c src/hll/PastelChime2.c src/hll/PartsEngine.c diff --git a/include/gfx/gfx.h b/include/gfx/gfx.h index fa09c2d..3ae2abc 100644 --- a/include/gfx/gfx.h +++ b/include/gfx/gfx.h @@ -184,6 +184,8 @@ void gfx_copy_with_alpha_map(Texture *dst, int dx, int dy, Texture *src, int sx, void gfx_fill_with_alpha(Texture *dst, int x, int y, int w, int h, int r, int g, int b, int a); void gfx_copy_stretch_with_alpha_map(Texture *dst, int dx, int dy, int dw, int dh, Texture *src, int sx, int sy, int sw, int sh); void gfx_copy_grayscale(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h); +void gfx_copy_grayscale_with_alpha_map(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h); +void gfx_copy_grayscale_reverse_LR_with_alpha_map(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h); void gfx_draw_line(Texture *dst, int x0, int y0, int x1, int y1, int r, int g, int b); void gfx_draw_line_to_amap(Texture *dst, int x0, int y0, int x1, int y1, int a); void gfx_draw_glyph(Texture *dst, float dx, int dy, Texture *glyph, SDL_Color color, float scale_x, float bold_width, bool blend); diff --git a/shaders/copy_grayscale.f.glsl b/shaders/copy_grayscale.f.glsl index 8dec9b3..d678d8f 100644 --- a/shaders/copy_grayscale.f.glsl +++ b/shaders/copy_grayscale.f.glsl @@ -20,6 +20,7 @@ in vec2 tex_coord; out vec4 frag_color; void main() { - float gray = dot(texture(tex, tex_coord).rgb, vec3(0.299, 0.587, 0.114)); - frag_color = vec4(vec3(gray), 1); + vec4 texel = texture(tex, tex_coord); + float gray = dot(texel.rgb, vec3(0.299, 0.587, 0.114)); + frag_color = vec4(vec3(gray), texel.a); } diff --git a/src/draw.c b/src/draw.c index f9ed4ac..0015c37 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1094,6 +1094,33 @@ void gfx_copy_grayscale(Texture *dst, int dx, int dy, Texture *src, int sx, int restore_blend_mode(); } +void gfx_copy_grayscale_with_alpha_map(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h) +{ + glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO); + + struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h); + run_copy_shader(©_grayscale_shader.s, dst, src, &data); + + restore_blend_mode(); +} + +void gfx_copy_grayscale_reverse_LR_with_alpha_map(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h) +{ + mat4 mw_transform = MAT4( + -src->w, 0, 0, sx + w, + 0, src->h, 0, -sy, + 0, 0, 1, 0, + 0, 0, 0, 1); + mat4 wv_transform = WV_TRANSFORM(w, h); + + glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO); + + struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h); + run_draw_shader(©_grayscale_shader.s, dst, src, mw_transform, wv_transform, &data); + + restore_blend_mode(); +} + static void draw_line(Texture *dst, int x0, int y0, int x1, int y1, struct copy_data *data) { GLfloat w = dst->w; diff --git a/src/ffi.c b/src/ffi.c index 4834436..85a6742 100644 --- a/src/ffi.c +++ b/src/ffi.c @@ -469,6 +469,7 @@ extern struct static_library lib_InputDevice; extern struct static_library lib_InputString; extern struct static_library lib_KiwiSoundEngine; extern struct static_library lib_LoadCG; +extern struct static_library lib_MADLoader; extern struct static_library lib_MainEXFile; extern struct static_library lib_MainSurface; extern struct static_library lib_MamanyoDemo; @@ -484,6 +485,8 @@ extern struct static_library lib_MsgSkip; extern struct static_library lib_MusicSystem; extern struct static_library lib_NewFont; extern struct static_library lib_OutputLog; +extern struct static_library lib_P3MapSprite; +extern struct static_library lib_P3SquareSprite; extern struct static_library lib_PassRegister; extern struct static_library lib_PastelChime2; extern struct static_library lib_PartsEngine; @@ -587,6 +590,7 @@ static struct static_library *static_libraries[] = { &lib_InputString, &lib_KiwiSoundEngine, &lib_LoadCG, + &lib_MADLoader, &lib_MainEXFile, &lib_MainSurface, &lib_MamanyoDemo, @@ -602,6 +606,8 @@ static struct static_library *static_libraries[] = { &lib_MusicSystem, &lib_NewFont, &lib_OutputLog, + &lib_P3MapSprite, + &lib_P3SquareSprite, &lib_PassRegister, &lib_PastelChime2, &lib_PartsEngine, diff --git a/src/hll/MADLoader.c b/src/hll/MADLoader.c new file mode 100644 index 0000000..576cc1b --- /dev/null +++ b/src/hll/MADLoader.c @@ -0,0 +1,336 @@ +/* Copyright (C) 2026 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include + +#include "system4/little_endian.h" +#include "system4/file.h" +#include "system4/string.h" +#include "system4/cg.h" + +#include "hll.h" +#include "id_pool.h" +#include "xsystem4.h" +#include "gfx/gfx.h" +#include "sact.h" + +// A MAD file consists of this header, followed by `nr_images` QNT images, each +// prefixed with its size. +struct MADHeader { + char magic[4]; // "MAD\0" + unsigned char unknown1[8]; + int width; + int height; + int total_time; + int nr_images; + int draw_method; + int is_loop; + unsigned char unknown2[8]; + int keep_last_frame; +}; + +struct MAD { + struct MADHeader header; + Texture textures[]; +}; + +static struct id_pool pool; + +static void MADLoader_ModuleInit(void) +{ + id_pool_init(&pool, 0); +} + +static void MADLoader_Close(int handle) +{ + struct MAD *mad = id_pool_release(&pool, handle); + if (!mad) + return; + for (int i = 0; i < mad->header.nr_images; i++) { + if (mad->textures[i].handle) + gfx_delete_texture(&mad->textures[i]); + } + free(mad); +} + +static void MADLoader_Delete(void) +{ + for (int i = id_pool_get_first(&pool); i >= 0; i = id_pool_get_next(&pool, i)) + MADLoader_Close(i); +} + +static void MADLoader_ModuleFini(void) +{ + MADLoader_Delete(); + id_pool_delete(&pool); +} + +static FILE *mad_open(struct string *filename, struct MADHeader *header) +{ + char *path = gamedir_path(filename->text); + FILE *fp = file_open_utf8(path, "rb"); + free(path); + if (!fp) + return NULL; + + uint8_t buf[48]; + if (fread(buf, sizeof buf, 1, fp) != 1 || memcmp(buf, "MAD", 4)) { + fclose(fp); + return NULL; + } + + memcpy(header->magic, buf, 4); + memcpy(header->unknown1, buf + 4, 8); + header->width = LittleEndian_getDW(buf, 12); + header->height = LittleEndian_getDW(buf, 16); + header->total_time = LittleEndian_getDW(buf, 20); + header->nr_images = LittleEndian_getDW(buf, 24); + header->draw_method = LittleEndian_getDW(buf, 28); + header->is_loop = LittleEndian_getDW(buf, 32); + memcpy(header->unknown2, buf + 36, 8); + header->keep_last_frame = LittleEndian_getDW(buf, 44); + + return fp; +} + +static bool mad_read_header(struct string *filename, struct MADHeader *header) +{ + FILE *fp = mad_open(filename, header); + fclose(fp); + return fp != NULL; +} + +static int MADLoader_Open(struct string *filename) +{ + struct MADHeader header; + FILE *fp = mad_open(filename, &header); + if (!fp) + return -1; + + struct MAD *mad = xcalloc(1, sizeof(struct MAD) + header.nr_images * sizeof(Texture)); + mad->header = header; + for (int i = 0; i < mad->header.nr_images; i++) { + uint8_t buf[4]; + if (fread(buf, 4, 1, fp) != 1) + VM_ERROR("MADLoader: failed to read image size %d of %s", i, display_sjis0(filename->text)); + uint32_t image_size = LittleEndian_getDW(buf, 0); + uint8_t *image_data = xmalloc(image_size); + if (fread(image_data, image_size, 1, fp) != 1) + VM_ERROR("MADLoader: failed to read image data %d of %s", i, display_sjis0(filename->text)); + struct cg *cg = cg_load_buffer(image_data, image_size); + if (!cg) + VM_ERROR("MADLoader: failed to load cg %d of %s", i, display_sjis0(filename->text)); + gfx_init_texture_with_cg(&mad->textures[i], cg); + cg_free(cg); + free(image_data); + } + fclose(fp); + + int handle = id_pool_get_unused(&pool); + id_pool_set(&pool, handle, mad); + return handle; +} + +static bool MADLoader_GetSize(int handle, int *width, int *height) +{ + struct MAD *mad = id_pool_get(&pool, handle); + if (!mad) + return false; + *width = mad->header.width; + *height = mad->header.height; + return true; +} + +static int MADLoader_GetNumof(int handle) +{ + struct MAD *mad = id_pool_get(&pool, handle); + return mad ? mad->header.nr_images : -1; +} + +static int MADLoader_GetTotalTime(int handle) +{ + struct MAD *mad = id_pool_get(&pool, handle); + return mad ? mad->header.total_time : -1; +} + +static int MADLoader_GetDrawMethod(int handle) +{ + struct MAD *mad = id_pool_get(&pool, handle); + return mad ? mad->header.draw_method : -1; +} + +static bool MADLoader_IsLoop(int handle) +{ + struct MAD *mad = id_pool_get(&pool, handle); + return mad && mad->header.is_loop == 1; +} + +static bool MADLoader_IsKeepLastFrame(int handle) +{ + struct MAD *mad = id_pool_get(&pool, handle); + return mad && mad->header.keep_last_frame == 1; +} + +static bool MADLoader_IsLoading(int handle) +{ + // We don't support background loading. + return false; +} + +static int MADLoader_GetLoadNumof(int handle) +{ + struct MAD *mad = id_pool_get(&pool, handle); + return mad ? mad->header.nr_images : 0; +} + +static bool MADLoader_GetSizeFromFile(struct string *filename, int *width, int *height) +{ + struct MADHeader header; + if (!mad_read_header(filename, &header)) + return false; + *width = header.width; + *height = header.height; + return true; +} + +static int MADLoader_GetNumofFromFile(struct string *filename) +{ + struct MADHeader header; + if (!mad_read_header(filename, &header)) + return -1; + return header.nr_images; +} + +static int MADLoader_GetTotalTimeFromFile(struct string *filename) +{ + struct MADHeader header; + if (!mad_read_header(filename, &header)) + return -1; + return header.total_time; +} + +static int MADLoader_GetDrawMethodFromFile(struct string *filename) +{ + struct MADHeader header; + if (!mad_read_header(filename, &header)) + return -1; + return header.draw_method; +} + +static bool MADLoader_IsLoopFromFile(struct string *filename) +{ + struct MADHeader header; + if (!mad_read_header(filename, &header)) + return false; + return header.is_loop == 1; +} + +static bool MADLoader_IsKeepLastFrameFromFile(struct string *filename) +{ + struct MADHeader header; + if (!mad_read_header(filename, &header)) + return false; + return header.keep_last_frame == 1; +} + +static Texture *get_mad_texture(int handle, int index) +{ + struct MAD *mad = id_pool_get(&pool, handle); + if (!mad || index < 0 || index >= mad->header.nr_images) + return NULL; + return &mad->textures[index]; +} + +static Texture *get_dest_texture(int sp_no) +{ + struct sact_sprite *sp = sact_get_sprite(sp_no); + if (!sp) + return NULL; + sprite_dirty(sp); + return sprite_get_texture(sp); +} + +static bool MADLoader_Copy(int handle, int sprite, int index) +{ + Texture *src = get_mad_texture(handle, index); + Texture *dst = get_dest_texture(sprite); + if (!src || !dst) + return false; + + gfx_copy_with_alpha_map(dst, 0, 0, src, 0, 0, src->w, src->h); + return true; +} + +static bool MADLoader_CopyReverseLR(int handle, int sprite, int index) +{ + Texture *src = get_mad_texture(handle, index); + Texture *dst = get_dest_texture(sprite); + if (!src || !dst) + return false; + + gfx_copy_reverse_LR_with_alpha_map(dst, 0, 0, src, 0, 0, src->w, src->h); + return true; +} + +static bool MADLoader_CopyGrayscale(int handle, int sprite, int index) +{ + Texture *src = get_mad_texture(handle, index); + Texture *dst = get_dest_texture(sprite); + if (!src || !dst) + return false; + + gfx_copy_grayscale_with_alpha_map(dst, 0, 0, src, 0, 0, src->w, src->h); + return true; +} + +static bool MADLoader_CopyGrayscaleReverseLR(int handle, int sprite, int index) +{ + Texture *src = get_mad_texture(handle, index); + Texture *dst = get_dest_texture(sprite); + if (!src || !dst) + return false; + + gfx_copy_grayscale_reverse_LR_with_alpha_map(dst, 0, 0, src, 0, 0, src->w, src->h); + return true; +} + +HLL_LIBRARY(MADLoader, + HLL_EXPORT(_ModuleInit, MADLoader_ModuleInit), + HLL_EXPORT(_ModuleFini, MADLoader_ModuleFini), + HLL_EXPORT(Delete, MADLoader_Delete), + HLL_EXPORT(Open, MADLoader_Open), + HLL_EXPORT(Close, MADLoader_Close), + HLL_EXPORT(GetSize, MADLoader_GetSize), + HLL_EXPORT(GetNumof, MADLoader_GetNumof), + HLL_EXPORT(GetTotalTime, MADLoader_GetTotalTime), + HLL_EXPORT(GetDrawMethod, MADLoader_GetDrawMethod), + HLL_EXPORT(IsLoop, MADLoader_IsLoop), + HLL_EXPORT(IsKeepLastFrame, MADLoader_IsKeepLastFrame), + HLL_EXPORT(IsLoading, MADLoader_IsLoading), + HLL_EXPORT(GetLoadNumof, MADLoader_GetLoadNumof), + HLL_EXPORT(GetSizeFromFile, MADLoader_GetSizeFromFile), + HLL_EXPORT(GetNumofFromFile, MADLoader_GetNumofFromFile), + HLL_EXPORT(GetTotalTimeFromFile, MADLoader_GetTotalTimeFromFile), + HLL_EXPORT(GetDrawMethodFromFile, MADLoader_GetDrawMethodFromFile), + HLL_EXPORT(IsLoopFromFile, MADLoader_IsLoopFromFile), + HLL_EXPORT(IsKeepLastFrameFromFile, MADLoader_IsKeepLastFrameFromFile), + HLL_EXPORT(Copy, MADLoader_Copy), + HLL_EXPORT(CopyReverseLR, MADLoader_CopyReverseLR), + HLL_EXPORT(CopyGrayscale, MADLoader_CopyGrayscale), + HLL_EXPORT(CopyGrayscaleReverseLR, MADLoader_CopyGrayscaleReverseLR) + ); diff --git a/src/hll/P3MapSprite.c b/src/hll/P3MapSprite.c new file mode 100644 index 0000000..313e2b4 --- /dev/null +++ b/src/hll/P3MapSprite.c @@ -0,0 +1,121 @@ +/* Copyright (C) 2026 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "gfx/gfx.h" +#include "vm/page.h" +#include "hll.h" +#include "sact.h" +#include "xsystem4.h" + +static struct { + Texture bg; + Texture grid; + int blend_rate; +} p3map; + +// Initializes the grid texture with isometric tiles based on the provided array. +static void init_grid_texture(Texture *tile, int offset_x, int offset_y, int rows, int cols, struct page *array) +{ + if (array->nr_vars != rows * cols) + VM_ERROR("Expected %d variables in array, got %d", rows * cols, array->nr_vars); + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + if (array->values[row * cols + col].i != 0) + continue; + // Isometric Coordinates. + int x = ((col - row) - 1) * (tile->w / 2) + offset_x; + int y = (col + row) * (tile->h / 2) + offset_y; + gfx_copy_with_alpha_map(&p3map.grid, x, y, tile, 0, 0, tile->w, tile->h); + } + } +} + +// Creates the map background and grid textures. +static bool P3MapSprite_Create(int src_sprite, int square_sprite, int x, int y, int line, int column, int blend_rate, struct page *array) +{ + struct sact_sprite *src = sact_try_get_sprite(src_sprite); + struct sact_sprite *square = sact_try_get_sprite(square_sprite); + if (!src || !square) + return false; + Texture *tx_src = sprite_get_texture(src); + Texture *tx_square = sprite_get_texture(square); + int width = tx_src->w; + int height = tx_src->h; + + if (p3map.bg.handle) + gfx_delete_texture(&p3map.bg); + gfx_init_texture_blank(&p3map.bg, width, height); + gfx_copy(&p3map.bg, 0, 0, tx_src, 0, 0, width, height); + + if (p3map.grid.handle) + gfx_delete_texture(&p3map.grid); + gfx_init_texture_rgba(&p3map.grid, width, height, COLOR(0, 0, 0, 0)); + init_grid_texture(tx_square, x, y, line, column, array); + + p3map.blend_rate = blend_rate; + return true; +} + +// Deletes the map background and grid textures. +static void P3MapSprite_Delete(void) +{ + if (p3map.grid.handle) + gfx_delete_texture(&p3map.grid); + if (p3map.bg.handle) + gfx_delete_texture(&p3map.bg); +} + +// Copies the map background and optionally blends the grid to a destination sprite. +static bool P3MapSprite_Copy(int dest_sprite, int src_x, int src_y, bool copy_square) +{ + struct sact_sprite *dst = sact_get_sprite(dest_sprite); + if (!dst) + return false; + Texture *tx_dst = sprite_get_texture(dst); + int w = sprite_get_width(dst); + int h = sprite_get_height(dst); + gfx_copy(tx_dst, 0, 0, &p3map.bg, src_x, src_y, w, h); + if (copy_square) + gfx_blend_amap_alpha(tx_dst, 0, 0, &p3map.grid, src_x, src_y, w, h, p3map.blend_rate); + return true; +} + +// Sets the blend rate for map rendering. +static bool P3MapSprite_CreateMatrixPixel(int blend_rate) +{ + p3map.blend_rate = blend_rate; + return true; +} + +// Blends the grid texture onto a destination sprite. +static bool P3MapSprite_CopyMatrix(int dest_sprite, int dest_x, int dest_y, int src_x, int src_y, int width, int height) +{ + struct sact_sprite *dst = sact_get_sprite(dest_sprite); + if (!dst) + return false; + Texture *tx_dst = sprite_get_texture(dst); + gfx_blend_amap(tx_dst, dest_x, dest_y, &p3map.grid, src_x, src_y, width, height); + gfx_copy_amap_max(tx_dst, dest_x, dest_y, &p3map.grid, src_x, src_y, width, height); + return true; +} + +HLL_LIBRARY(P3MapSprite, + HLL_EXPORT(Create, P3MapSprite_Create), + HLL_EXPORT(Delete, P3MapSprite_Delete), + HLL_EXPORT(Copy, P3MapSprite_Copy), + HLL_EXPORT(CreateMatrixPixel, P3MapSprite_CreateMatrixPixel), + HLL_EXPORT(CopyMatrix, P3MapSprite_CopyMatrix) + ); diff --git a/src/hll/P3SquareSprite.c b/src/hll/P3SquareSprite.c new file mode 100644 index 0000000..c1ac01a --- /dev/null +++ b/src/hll/P3SquareSprite.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2026 kichikuou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "sact.h" +#include "gfx/gfx.h" +#include "vm/page.h" +#include "hll.h" +#include "xsystem4.h" + +static bool P3SquareSprite_Copy(int dest_handle, int src_handle, int size, struct page *matrix) +{ + struct sact_sprite *dest = sact_try_get_sprite(dest_handle); + struct sact_sprite *src = sact_try_get_sprite(src_handle); + + if (!dest || !src) + return false; + + Texture *dest_tex = sprite_get_texture(dest); + Texture *src_tex = sprite_get_texture(src); + + int tile_w = src_tex->w; + int tile_h = src_tex->h; + int half_w = tile_w / 2; + int half_h = tile_h / 2; + + int canvas_center_x = dest_tex->w / 2; + int canvas_center_y = dest_tex->h / 2; + + int side_count = size * 2 + 1; + + if (matrix->nr_vars != side_count * side_count) + VM_ERROR("Expected %d variables in array, got %d", side_count * side_count, matrix->nr_vars); + + int index = 0; + for (int y = -size; y <= size; ++y) { + for (int x = -size; x <= size; ++x) { + // Check if we should draw this tile + if (matrix->values[index++].i == 0) + continue; + + // Isometric coordinate conversion + int screen_pos_x = canvas_center_x + (x - y - 1) * half_w; + int screen_pos_y = canvas_center_y + (x + y - 1) * half_h; + + // Draw the sprite + gfx_copy_use_amap_border(dest_tex, screen_pos_x, screen_pos_y, src_tex, 0, 0, tile_w, tile_h, 1); + gfx_copy_amap_max(dest_tex, screen_pos_x, screen_pos_y, src_tex, 0, 0, tile_w, tile_h); + } + } + + return true; +} + +HLL_LIBRARY(P3SquareSprite, + HLL_EXPORT(Copy, P3SquareSprite_Copy) + ); diff --git a/src/meson.build b/src/meson.build index 652abbf..22dda43 100644 --- a/src/meson.build +++ b/src/meson.build @@ -117,6 +117,7 @@ xsystem4 = [version_h, 'hll/InputString.c', 'hll/KiwiSoundEngine.c', 'hll/LoadCG.c', + 'hll/MADLoader.c', 'hll/MainEXFile.c', 'hll/MainSurface.c', 'hll/MamanyoDemo.c', @@ -132,6 +133,8 @@ xsystem4 = [version_h, 'hll/MusicSystem.c', 'hll/NewFont.c', 'hll/OutputLog.c', + 'hll/P3MapSprite.c', + 'hll/P3SquareSprite.c', 'hll/PassRegister.c', 'hll/PastelChime2.c', 'hll/PartsEngine.c',