6 n__anim_8c
gullradriel edited this page 2026-10-09 00:55:18 +02:00

src/n_anim.c

Anim functions. More...

Detailed Description

Anim functions.

Author: Castagnier Mickael aka Gull Ra Driel

Version: 1.0

Date: 30/12/2016

Source code

/*
 * Nilorea Library
 * Copyright (C) 2005-2026 Castagnier Mickael
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#include "nilorea/n_anim.h"

#include "math.h"

ANIM_LIB* create_anim_library(const char* name, unsigned int size) {
    if (size < 1) {
        n_log(LOG_ERR, "Invalid size (<1) for anim lib creation");
        return NULL;
    }

    ANIM_LIB* lib = NULL;
    Malloc(lib, ANIM_LIB, 1);
    __n_assert(lib, return NULL);

    lib->gfxs = NULL;
    Malloc(lib->gfxs, ANIM_GFX*, size);
    if (!lib->gfxs) {
        n_log(LOG_ERR, "Unable to allocate a gfx_lib of size %d", size);
        Free(lib);
        return NULL;
    }

    if (name)
        lib->name = strdup(name);
    else
        lib->name = strdup("generic-name");

    lib->nb_max_gfxs = size;

    return lib;
} /* create_anim_lib */

int destroy_anim_lib(ANIM_LIB** lib) {
    __n_assert((*lib), return FALSE);

    for (uint32_t it = 0; it < (*lib)->nb_max_gfxs; it++) {
        if ((*lib)->gfxs[it]) {
            FreeNoLog((*lib)->gfxs[it]->frames);
            if ((*lib)->gfxs[it]->bmp) al_destroy_bitmap((*lib)->gfxs[it]->bmp);
        }
        FreeNoLog((*lib)->gfxs[it]);
    }
    Free((*lib)->gfxs);
    FreeNoLog((*lib)->name);
    Free((*lib));
    return TRUE;
} /* destroy_anim_lib */

int delete_bmp_from_lib(ANIM_LIB* lib, unsigned int id) {
    __n_assert(lib, return FALSE);
    __n_assert(lib->gfxs, return FALSE);

    if (id >= lib->nb_max_gfxs) return FALSE;
    if (lib->gfxs[id]) {
        FreeNoLog(lib->gfxs[id]->frames);
        if (lib->gfxs[id]->bmp) al_destroy_bitmap(lib->gfxs[id]->bmp);
        FreeNoLog(lib->gfxs[id]);
    }
    return TRUE;
} /* delete anim from lib */

int add_bmp_to_lib(ANIM_LIB* lib, unsigned int pos, char* file, char* resfile) {
    __n_assert(lib, return FALSE);
    __n_assert(file, return FALSE);
    __n_assert(resfile, return FALSE);

    if (pos >= lib->nb_max_gfxs) {
        n_log(LOG_ERR, "invalid position %d, can only go from 0 to %d in anim lib %s", pos, lib->nb_max_gfxs, lib->name);
        return FALSE;
    }
    if (lib->gfxs[pos] != NULL) {
        n_log(LOG_ERR, "there already is a gfx at pos %d in anim lib %s", pos, lib->name);
        return FALSE;
    }

    FILE* data = fopen(resfile, "r");
    if (!data) {
        n_log(LOG_ERR, "Unable to open %s !", resfile);
        return FALSE;
    }

    int check_id = 0;
    int check_fscanf = 0;
    ANIM_GFX* gfx = NULL;

    check_fscanf = fscanf(data, "%d", &check_id);
    if (check_fscanf == 1 && check_id == 211282) {
        Malloc(gfx, ANIM_GFX, 1);
        __n_assert(gfx, fclose(data); return FALSE);
    } else {
        n_log(LOG_ERR, "file %s: invalid check_id of %d, should be 211282", resfile, check_id);
        fclose(data);
        return FALSE;
    }

    if (fscanf(data, "%u %u %u", &gfx->w, &gfx->h, &gfx->nb_frames) != 3) {
        n_log(LOG_ERR, "file %s: invalid &gfx -> w, &gfx -> h, &gfx -> nb_frames !", resfile);
        Free(gfx);
        fclose(data);
        return FALSE;
    }

    if (gfx->nb_frames >= UINT_MAX) {
        n_log(LOG_ERR, "file %s: invalid number of frames: %u", resfile, gfx->nb_frames);
        Free(gfx);
        fclose(data);
        return FALSE;
    }
    // file stores last_frame_index (0-based), convert to count
    gfx->nb_frames += 1;

    Malloc(gfx->frames, ANIM_FRAME, gfx->nb_frames);
    if (!gfx->frames) {
        n_log(LOG_ERR, "file %s: could not allocate %d frames", resfile, gfx->nb_frames);
        Free(gfx);
        fclose(data);
        return FALSE;
    }

    gfx->bmp = al_load_bitmap(file);
    if (!gfx->bmp) {
        n_log(LOG_ERR, "file %s: unable to load image", file);
        Free(gfx->frames);
        Free(gfx);
        fclose(data);
        return FALSE;
    }

    for (unsigned int it = 0; it < gfx->nb_frames; it++) {
        if (fscanf(data, "%d %d %u", &gfx->frames[it].x, &gfx->frames[it].y, &gfx->frames[it].duration) != 3) {
            n_log(LOG_ERR, "file %s: invalid &gfx -> frames[ %d ].x, &gfx -> frames[ %d ].y, &gfx -> frames[ %d ] . duration !", resfile, it, it, it);
            Free(gfx->frames);
            Free(gfx);
            fclose(data);
            return FALSE;
        }
    }
    fclose(data);

    lib->gfxs[pos] = gfx;

    return TRUE;
} /* add_bmp_to_lib( ... ) */

int update_anim(ANIM_DATA* data, unsigned int delta_t) {
    __n_assert(data, return FALSE);

    // single-frame sprite, nothing to update
    if (data->lib->gfxs[data->id]->nb_frames <= 1)
        return TRUE;

    data->elapsed += delta_t;
    if (data->elapsed > data->lib->gfxs[data->id]->frames[data->frame].duration) {
        data->elapsed = 0;
        data->frame++;
        if (data->frame >= data->lib->gfxs[data->id]->nb_frames)
            data->frame = 0;
    }
    return TRUE;
} /* update_anim( ... ) */

int draw_anim(ANIM_DATA* data, int x, int y) {
    ALLEGRO_BITMAP* bmp = data->lib->gfxs[data->id]->bmp;

    unsigned int tilew = data->lib->gfxs[data->id]->w;
    unsigned int tileh = data->lib->gfxs[data->id]->h;

    int px = data->lib->gfxs[data->id]->frames[data->frame].x;
    int py = data->lib->gfxs[data->id]->frames[data->frame].y;

    unsigned int framex = data->frame * tilew;

    al_draw_bitmap_region(bmp, (float)framex, 0, (float)tilew, (float)tileh, (float)(x - px), (float)(y - py), 0);

    return TRUE;
}
/* draw_anim( ... ) */