nds_nflib/source/nf_collision.c
Antonio Niño Díaz 06557f1773 library: Support colmaps with extensions .map and .img
Currently it is needed to rename the extension of the collision maps
from .img and .map to .dat and .cmp for NFlib to find the files. This
patch makes it also try to load the original extensions so that the
renaming isn't required.
2023-12-24 03:05:46 +01:00

246 lines
6.7 KiB
C

// SPDX-License-Identifier: MIT
//
// Copyright (c) 2009-2014 Cesar Rincon "NightFox"
// Copyright (c) 2023 Antonio Niño Díaz "AntonioND"
//
// NightFox LIB - Collision maps functions
// http://www.nightfoxandco.com/
#include <stdio.h>
#include <string.h>
#include <nds.h>
#include "nf_basic.h"
#include "nf_collision.h"
// Struct that holds information about all collision maps
NF_TYPE_CMAP_INFO NF_CMAP[NF_SLOTS_CMAP];
void NF_InitCmapBuffers(void)
{
for (int n = 0; n < NF_SLOTS_CMAP; n++)
{
NF_CMAP[n].tiles = NULL;
NF_CMAP[n].map = NULL;
NF_CMAP[n].tiles_size = 0;
NF_CMAP[n].map_size = 0;
NF_CMAP[n].width = 0;
NF_CMAP[n].height = 0;
NF_CMAP[n].inuse = false; // Mark as unused
}
}
void NF_ResetCmapBuffers(void)
{
// Free all buffers
for (int n = 0; n < NF_SLOTS_CMAP; n++)
{
free(NF_CMAP[n].tiles);
free(NF_CMAP[n].map);
}
// Reset state of the collision maps
NF_InitCmapBuffers();
}
void NF_LoadCollisionMap(const char *file, u32 id, u32 width, u32 height)
{
// Verify that the slot ID is valid
if (id >= NF_SLOTS_CMAP)
NF_Error(106, "Collision Map", NF_SLOTS_CMAP);
// Verify that this slot is free
if (NF_CMAP[id].inuse)
NF_Error(109, "Collision Map", id);
// Free buffers if they were in use
free(NF_CMAP[id].map);
NF_CMAP[id].map = NULL;
// File path
char filename[256];
// Load .CMP/.MAP file (tilemap)
snprintf(filename, sizeof(filename), "%s/%s.cmp", NF_ROOTFOLDER, file);
if (!NF_FileExists(filename))
{
snprintf(filename, sizeof(filename), "%s/%s.map", NF_ROOTFOLDER, file);
if (!NF_FileExists(filename))
NF_Error(101, filename, 0);
}
NF_FileLoad(filename, &NF_CMAP[id].map, &NF_CMAP[id].map_size, 0);
// Save map size
NF_CMAP[id].width = width;
NF_CMAP[id].height = height;
// Mark this slot as in use
NF_CMAP[id].inuse = true;
}
void NF_UnloadCollisionMap(u32 id)
{
// Verify that the slot ID is valid
if (id >= NF_SLOTS_CMAP)
NF_Error(106, "Collision Map", NF_SLOTS_CMAP);
// Verify that this slot is used
if (!NF_CMAP[id].inuse)
NF_Error(110, "Collision Map", id);
// Free buffer
free(NF_CMAP[id].map);
NF_CMAP[id].map = NULL;
// Mark this slot as free
NF_CMAP[id].inuse = false;
}
u32 NF_GetTile(u32 slot, s32 x, s32 y)
{
// If the coordinate is outside of the map, return 0
if ((x < 0) || (y < 0) || (x >= NF_CMAP[slot].width) || (y >= NF_CMAP[slot].height))
return 0;
// Calculate width of the map in tiles
u32 columns = NF_CMAP[slot].width / 8;
// Calculate tile where the pixel is located
u32 tile_x = x / 8;
u32 tile_y = (y / 8) + 1; // Skip first row, it's used for the tile reference
// Calculate the address of the tile in the map
u32 address = ((tile_y * columns) + tile_x) * 2;
// Read tile number
u32 lobyte = *(NF_CMAP[slot].map + address);
u32 hibyte = *(NF_CMAP[slot].map + (address + 1));
return (hibyte << 8) | lobyte;
}
void NF_SetTile(u32 slot, s32 x, s32 y, u32 value)
{
// If the coordinate is outside of the map, return
if ((x < 0) && (y < 0) && (x >= NF_CMAP[slot].width) && (y >= NF_CMAP[slot].height))
return;
// Calculate width of the map in tiles
u32 columns = NF_CMAP[slot].width / 8;
// Calculate tile where the pixel is located
u32 tile_x = x / 8;
u32 tile_y = (y / 8) + 1; // Skip first row, it's used for the tile reference
// Calculate the address of the tile in the map
s32 address = ((tile_y * columns) + tile_x) * 2; // Each tile uses 2 bytes
// Split new tile number
u32 hibyte = (value >> 8) & 0xff;
u32 lobyte = value & 0xff;
// Write the new tile number
*(NF_CMAP[slot].map + address) = lobyte;
*(NF_CMAP[slot].map + (address + 1)) = hibyte;
}
void NF_LoadCollisionBg(const char *file, u32 id, u32 width, u32 height)
{
// Verify that the slot ID is valid
if (id >= NF_SLOTS_CMAP)
NF_Error(106, "Collision map", NF_SLOTS_CMAP);
// Verify that this slot is free
if (NF_CMAP[id].inuse)
NF_Error(109, "Collision map", id);
// Free buffers if they were in use
free(NF_CMAP[id].tiles);
NF_CMAP[id].tiles = NULL;
free(NF_CMAP[id].map);
NF_CMAP[id].map = NULL;
// File path
char filename[256];
// Load .DAT/.IMG file (tileset)
snprintf(filename, sizeof(filename), "%s/%s.dat", NF_ROOTFOLDER, file);
if (!NF_FileExists(filename))
{
snprintf(filename, sizeof(filename), "%s/%s.img", NF_ROOTFOLDER, file);
if (!NF_FileExists(filename))
NF_Error(101, filename, 0);
}
NF_FileLoad(filename, &NF_CMAP[id].tiles, &NF_CMAP[id].tiles_size, 0);
// Load .CMP/.MAP file (tilemap)
snprintf(filename, sizeof(filename), "%s/%s.cmp", NF_ROOTFOLDER, file);
if (!NF_FileExists(filename))
{
snprintf(filename, sizeof(filename), "%s/%s.map", NF_ROOTFOLDER, file);
if (!NF_FileExists(filename))
NF_Error(101, filename, 0);
}
NF_FileLoad(filename, &NF_CMAP[id].map, &NF_CMAP[id].map_size, 0);
// Save map size
NF_CMAP[id].width = width;
NF_CMAP[id].height = height;
// Mark this slot as in use
NF_CMAP[id].inuse = true;
}
void NF_UnloadCollisionBg(u32 id)
{
// Verify that the slot ID is valid
if (id >= NF_SLOTS_CMAP)
NF_Error(106, "Collision map", NF_SLOTS_CMAP);
// Verify that this slot is used
if (!NF_CMAP[id].inuse)
NF_Error(110, "Collision map", id);
// Free the buffers
free(NF_CMAP[id].tiles);
NF_CMAP[id].tiles = NULL;
free(NF_CMAP[id].map);
NF_CMAP[id].map = NULL;
// Mark this map as unused
NF_CMAP[id].inuse = false;
}
u8 NF_GetPoint(u32 slot, s32 x, s32 y)
{
// If the coordinate is outside of the map, return 0
if ((x < 0) || (y < 0) || (x >= NF_CMAP[slot].width) || (y >= NF_CMAP[slot].height))
return 0;
// Calculate width of the map in tiles
u32 columns = NF_CMAP[slot].width / 8;
// Calculate tile where the pixel is located
u32 tile_x = x / 8;
u32 tile_y = (y / 8) + 1; // Skip first row, it's used for the tile reference
// Calculate pixel coordinates inside the tile
u32 pixel_x = x & 7;
u32 pixel_y = y & 7;
// Calculate the address of the tile in the map
s32 address = ((tile_y * columns) + tile_x) * 2; // Each tile uses 2 bytes
// Read tile number
u32 lobyte = *(NF_CMAP[slot].map + address);
u32 hibyte = *(NF_CMAP[slot].map + (address + 1));
u32 tile = (hibyte << 8) | lobyte;
// Read value of the pixel inside the tile
address = (tile * 64) + (pixel_y * 8) + pixel_x;
lobyte = *(NF_CMAP[slot].tiles + address);
return lobyte;
}