mirror of
https://github.com/knightfox75/nds_nflib.git
synced 2025-06-18 16:55:32 -04:00

Types like u8 and u16 aren't always a good idea. For example: void function(u8 x, u8 y) { u32 value = (x << 16) | y; } The left shift of x will overflow because x is 8 bits wide. It is better to make both arguments 32 bit wide. It may also cause the compiler to introduce bit masking operations at the caller side because the caller doesn't know how the function behaves internally. In order to prevent this kind of issues, it's better to use 32 bit variables unless there is a very good reason to use smaller types (like in structs, to save RAM).
200 lines
6.1 KiB
C
200 lines
6.1 KiB
C
// SPDX-License-Identifier: MIT
|
|
//
|
|
// Copyright (c) 2009-2014 Cesar Rincon "NightFox"
|
|
//
|
|
// NightFox LIB - Include de funciones de carga de archivos multimedia
|
|
// http://www.nightfoxandco.com/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <nds.h>
|
|
|
|
#include "nf_basic.h"
|
|
#include "nf_bitmapbg.h"
|
|
#include "nf_media.h"
|
|
|
|
void NF_LoadBMP(const char *file, u32 slot)
|
|
{
|
|
// Temporary buffers
|
|
char *buffer = NULL;
|
|
|
|
// BMP header
|
|
typedef struct {
|
|
u32 bmp_size; // Size of the file in bytes
|
|
u16 res_a; // Reserved
|
|
u16 res_b; // Reserved
|
|
u32 offset; // Offset where data starts
|
|
u32 header_size; // Size of the header in bytes (40 bytes)
|
|
u32 width; // Image width in pixels
|
|
u32 height; // Image height in pixels
|
|
u16 color_planes; // Number of color planes
|
|
u16 bpp; // Bits per pixel
|
|
u32 compression; // Compression
|
|
u32 raw_size; // Size of raw data after the header
|
|
u32 dpi_hor; // Dots per inch (horizontal)
|
|
u32 dpi_ver; // Dots per inch (vertical)
|
|
u32 pal_colors; // Number of colors in the palette
|
|
u32 imp_colors; // Important colors
|
|
} bmp_header_info;
|
|
|
|
bmp_header_info bmp_header = { 0 };
|
|
|
|
// File path
|
|
char filename[256];
|
|
|
|
// Load BMP file
|
|
snprintf(filename, sizeof(filename), "%s/%s.bmp", NF_ROOTFOLDER, file);
|
|
FILE *file_id = fopen(filename, "rb");
|
|
if (file_id == NULL) // If the file can't be opened
|
|
NF_Error(101, filename, 0);
|
|
|
|
// Read magic string "BM" (0x00 - 0x01)
|
|
char magic_id[2];
|
|
fread(magic_id, 1, 2, file_id);
|
|
if ((magic_id[0] != 'B') || (magic_id[1] != 'M')) // If not a valid BMP file
|
|
NF_Error(101, "BMP", 0);
|
|
|
|
// Read the rest of the BMP header (0x02 - 0x36)
|
|
fread((void *)&bmp_header, 1, sizeof(bmp_header), file_id);
|
|
|
|
// Create a temporary buffer
|
|
buffer = malloc(bmp_header.raw_size);
|
|
if (buffer == NULL)
|
|
NF_Error(102, NULL, bmp_header.raw_size);
|
|
|
|
// Read data to RAM
|
|
fseek(file_id, bmp_header.offset, SEEK_SET);
|
|
fread(buffer, 1, bmp_header.raw_size, file_id);
|
|
fclose(file_id);
|
|
|
|
// Free the previous buffer and allocate a new one
|
|
free(NF_BG16B[slot].buffer);
|
|
|
|
u32 size = bmp_header.width * bmp_header.height * 2;
|
|
NF_BG16B[slot].buffer = malloc(size);
|
|
if (NF_BG16B[slot].buffer == NULL)
|
|
NF_Error(102, NULL, size);
|
|
|
|
switch (bmp_header.bpp)
|
|
{
|
|
case 8: // 8 bits per pixel
|
|
{
|
|
// Calculate palette size
|
|
u32 colors = (bmp_header.offset - 0x36) / 4; // Stored as RGBA
|
|
char *palette = malloc(colors * 4);
|
|
if (palette == NULL)
|
|
NF_Error(102, NULL, colors * 4);
|
|
|
|
// Reopen file and read the palette
|
|
file_id = fopen(filename, "rb");
|
|
if (file_id == NULL)
|
|
NF_Error(101, filename, 0);
|
|
|
|
fseek(file_id, 0x36, SEEK_SET);
|
|
fread(palette, 1, colors * 4, file_id);
|
|
fclose(file_id);
|
|
|
|
u32 idx = 0;
|
|
|
|
// Convert file to 16 bit per pixel
|
|
for (u32 y = 0; y < bmp_header.height; y++)
|
|
{
|
|
for (u32 x = 0; x < bmp_header.width; x++)
|
|
{
|
|
u32 offset = (((bmp_header.height - 1) - y) * bmp_header.width) + x;
|
|
|
|
u32 pixel = buffer[idx] << 2;
|
|
|
|
// Split BGR (not RGB) value
|
|
u32 b = palette[pixel] >> 3;
|
|
u32 g = palette[pixel + 1] >> 3;
|
|
u32 r = palette[pixel + 2] >> 3;
|
|
|
|
// Pack the components as RGB
|
|
pixel = r | (g << 5) | (b << 10) | BIT(15);
|
|
NF_BG16B[slot].buffer[offset] = pixel;
|
|
|
|
idx++;
|
|
}
|
|
|
|
// Align to 4 bytes at the end of the row
|
|
while ((idx % 4) != 0)
|
|
idx ++;
|
|
}
|
|
|
|
// Free palette from RAM
|
|
free(palette);
|
|
break;
|
|
}
|
|
case 16: // 16 bits per pixel
|
|
{
|
|
u32 idx = 0;
|
|
|
|
for (u32 y = 0; y < bmp_header.height; y++)
|
|
{
|
|
for (u32 x = 0; x < bmp_header.width; x++)
|
|
{
|
|
u32 offset = (((bmp_header.height - 1) - y) * bmp_header.width) + x;
|
|
|
|
u32 pixel = buffer[idx] + (buffer[idx + 1] << 8);
|
|
|
|
// Split BGR (not RGB) value
|
|
u32 b = pixel & 0x1F;
|
|
u32 g = (pixel >> 5) & 0x1F;
|
|
u32 r = (pixel >> 10) & 0x1F;
|
|
|
|
// Pack the components as RGB
|
|
pixel = r | (g << 5) | (b << 10) | BIT(15);
|
|
NF_BG16B[slot].buffer[offset] = pixel;
|
|
|
|
idx += 2;
|
|
}
|
|
|
|
// Align to 4 bytes at the end of the row
|
|
while ((idx % 4) != 0)
|
|
idx ++;
|
|
}
|
|
break;
|
|
}
|
|
case 24: // 24 bits per pixel
|
|
{
|
|
u32 idx = 0;
|
|
|
|
for (u32 y = 0; y < bmp_header.height; y++)
|
|
{
|
|
for (u32 x = 0; x < bmp_header.width; x++)
|
|
{
|
|
u32 offset = (((bmp_header.height - 1) - y) * bmp_header.width) + x;
|
|
|
|
u32 b = buffer[idx] >> 3;
|
|
u32 g = buffer[idx + 1] >> 3;
|
|
u32 r = buffer[idx + 2] >> 3;
|
|
|
|
// Pack the components as RGB
|
|
u32 pixel = r | (g << 5) | (b << 10) | BIT(15);
|
|
NF_BG16B[slot].buffer[offset] = pixel;
|
|
|
|
idx += 3;
|
|
}
|
|
|
|
// Align to 4 bytes at the end of the row
|
|
while ((idx % 4) != 0)
|
|
idx ++;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
NF_Error(106, NULL, bmp_header.bpp);
|
|
break;
|
|
}
|
|
|
|
// Save background information
|
|
NF_BG16B[slot].size = size;
|
|
NF_BG16B[slot].width = bmp_header.width;
|
|
NF_BG16B[slot].height = bmp_header.height;
|
|
NF_BG16B[slot].inuse = true; // Mark as used
|
|
|
|
// Free temporary buffer
|
|
free(buffer);
|
|
}
|