summaryrefslogtreecommitdiffstats
path: root/src/sprites.h
blob: e249e95fee9b5d5e0f75365e907171f5533e9788 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#ifndef GBAEXP_SPRITES_H
#define GBAEXP_SPRITES_H

#include "common.h"

u32
unpack_1bb(u8 hex) {
    const u32 conversion_u32[16] = {
        0x00000000, 0x00000001, 0x00000010, 0x00000011,
        0x00000100, 0x00000101, 0x00000110, 0x00000111,
        0x00001000, 0x00001001, 0x00001010, 0x00001011,
        0x00001100, 0x00001101, 0x00001110, 0x00001111,
    };
    u8 low = hex & 0xF;
    u8 high = (hex >> 4) & 0xF;
    return (conversion_u32[high] << 16) | conversion_u32[low];
}

typedef struct Sprite {
    // A unique sprite identifier.
    size_t id;
    // The number of tiles for a single sprite frame.
    size_t n_tiles;
    // The starting tile of this sprite.
    size_t tile_start;
    // The associated palette bank for this sprite.
    size_t pal_bank;
} Sprite;


#define NUM_SPRITES 128
Sprite sprites[NUM_SPRITES];

// Keeping track of unique sprites and current sprite memory pointer using
// global singletons.
size_t sprite_counter = 0;
size_t sprite_tile_counter = 0;
u32 *sprite_memory = NULL;

// Loads the sprite data into video memory and initialize the Sprite structure.
size_t
load_sprite_data(u32 *sprite_data, size_t n_tiles, size_t n_frames) {
    memcpy(sprite_memory, sprite_data, 8 * n_tiles * n_frames * sizeof(u32));
    sprite_memory += 8 * n_tiles * n_frames;
    Sprite sprite = {
        .id = sprite_counter,
        .n_tiles = n_tiles,
        .tile_start = sprite_tile_counter,
    };
    sprite_tile_counter += n_tiles * n_frames;
    sprites[sprite_counter] = sprite;
    return sprite_counter++;
}

size_t
load_packed_sprite_data(u32 *sprite_data, size_t n_tiles, size_t n_frames) {
    size_t counter = 0;
    for (size_t i = 0; i < 8 * n_tiles * n_frames / 4; ++i) {
        u32 hex = sprite_data[i];
        sprite_memory[counter++] = unpack_1bb((hex >> 24) & 0xFF);
        sprite_memory[counter++] = unpack_1bb((hex >> 16) & 0xFF);
        sprite_memory[counter++] = unpack_1bb((hex >> 8) & 0xFF);
        sprite_memory[counter++] = unpack_1bb((hex) & 0xFF);
    }
    sprite_memory += 8 * n_tiles * n_frames;
    Sprite sprite = {
        .id = sprite_counter,
        .n_tiles = n_tiles,
        .tile_start = sprite_tile_counter,
    };
    sprite_tile_counter += n_tiles * n_frames;
    sprites[sprite_counter] = sprite;
    return sprite_counter++;
}

void
init_sprites(size_t starting_tile) {
    // Initialize all attributes by disabling rendering. If we don't do this,
    // glitches may appear.
    for (size_t i = 0; i < 128; ++i) {
        OBJ_ATTR_0(i) = (1 << 9);
    }

    sprite_counter = 0;
    // Prepare global sprite_memory address.
    sprite_memory = &TILE_MEM[4][starting_tile];
}

void
init_sprite_pal(size_t starting_index, Color col) {
    // Add colors to the sprite color palette. Tiles with color number 0 are
    // treated as transparent.
    for (size_t i = 0; i < 16; ++i) {
        PAL_BUFFER_SPRITES[i + starting_index] = col;
    }

}

#endif // GBAEXP_SPRITES_H