瀏覽代碼

* Support for multiple frames in canvases.

tags/v0.99.beta14
Sam Hocevar sam 18 年之前
父節點
當前提交
9a65579cf6
共有 4 個檔案被更改,包括 179 行新增288 行删除
  1. +70
    -26
      cucul/cucul.c
  2. +10
    -16
      cucul/cucul.h
  3. +8
    -1
      cucul/cucul_internals.h
  4. +91
    -245
      cucul/sprite.c

+ 70
- 26
cucul/cucul.c 查看文件

@@ -54,6 +54,13 @@ cucul_canvas_t * cucul_create_canvas(unsigned int width, unsigned int height)
cv->chars = NULL;
cv->attr = NULL;

cv->frame = 0;
cv->framecount = 1;
cv->allchars = malloc(sizeof(uint32_t *));
cv->allattr = malloc(sizeof(uint32_t *));
cv->allchars[0] = NULL;
cv->allattr[0] = NULL;

/* Initialise to a default size. 80x32 is arbitrary but matches AAlib's
* default X11 window. When a graphic driver attaches to us, it can set
* a different size. */
@@ -169,10 +176,15 @@ char const *cucul_get_color_name(unsigned int color)
*/
void cucul_free_canvas(cucul_canvas_t *cv)
{
unsigned int f;

_cucul_end_dither();

free(cv->chars);
free(cv->attr);
for(f = 0; f < cv->framecount; f++)
{
free(cv->allchars[f]);
free(cv->allattr[f]);
}

free(cv);
}
@@ -196,7 +208,7 @@ int cucul_rand(int min, int max)
void _cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
unsigned int height)
{
unsigned int x, y, old_width, old_height, new_size, old_size;
unsigned int x, y, f, old_width, old_height, new_size, old_size;

old_width = cv->width;
old_height = cv->height;
@@ -209,8 +221,13 @@ void _cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
/* Step 1: if new area is bigger, resize the memory area now. */
if(new_size > old_size)
{
cv->chars = realloc(cv->chars, new_size * sizeof(uint32_t));
cv->attr = realloc(cv->attr, new_size * sizeof(uint32_t));
for(f = 0; f < cv->framecount; f++)
{
cv->allchars[f] = realloc(cv->allchars[f],
new_size * sizeof(uint32_t));
cv->allattr[f] = realloc(cv->allattr[f],
new_size * sizeof(uint32_t));
}
}

/* Step 2: move line data if necessary. */
@@ -224,19 +241,25 @@ void _cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
/* New width is bigger than old width, which means we need to
* copy lines starting from the bottom of the screen otherwise
* we will overwrite information. */
for(y = height < old_height ? height : old_height; y--; )
for(f = 0; f < cv->framecount; f++)
{
for(x = old_width; x--; )
uint32_t *chars = cv->allchars[f];
uint32_t *attr = cv->allattr[f];

for(y = height < old_height ? height : old_height; y--; )
{
cv->chars[y * width + x] = cv->chars[y * old_width + x];
cv->attr[y * width + x] = cv->attr[y * old_width + x];
for(x = old_width; x--; )
{
chars[y * width + x] = chars[y * old_width + x];
attr[y * width + x] = attr[y * old_width + x];
}

/* Zero the end of the line */
for(x = width - old_width; x--; )
chars[y * width + old_width + x] = (uint32_t)' ';
memset(attr + y * width + old_width, 0,
(width - old_width) * 4);
}

/* Zero the end of the line */
for(x = width - old_width; x--; )
cv->chars[y * width + old_width + x] = (uint32_t)' ';
memset(cv->attr + y * width + old_width, 0,
(width - old_width) * 4);
}
}
else
@@ -245,12 +268,18 @@ void _cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
* the first line, it is already in place. */
unsigned int lines = height < old_height ? height : old_height;

for(y = 1; y < lines; y++)
for(f = 0; f < cv->framecount; f++)
{
for(x = 0; x < width; x++)
uint32_t *chars = cv->allchars[f];
uint32_t *attr = cv->allattr[f];

for(y = 1; y < lines; y++)
{
cv->chars[y * width + x] = cv->chars[y * old_width + x];
cv->attr[y * width + x] = cv->attr[y * old_width + x];
for(x = 0; x < width; x++)
{
chars[y * width + x] = chars[y * old_width + x];
attr[y * width + x] = attr[y * old_width + x];
}
}
}
}
@@ -258,18 +287,33 @@ void _cucul_set_canvas_size(cucul_canvas_t *cv, unsigned int width,
/* Step 3: fill the bottom of the new screen if necessary. */
if(height > old_height)
{
/* Zero the bottom of the screen */
for(x = (height - old_height) * width; x--; )
cv->chars[old_height * width + x] = (uint32_t)' ';
memset(cv->attr + old_height * width, 0,
(height - old_height) * width * 4);
for(f = 0; f < cv->framecount; f++)
{
uint32_t *chars = cv->allchars[f];
uint32_t *attr = cv->allattr[f];

/* Zero the bottom of the screen */
for(x = (height - old_height) * width; x--; )
chars[old_height * width + x] = (uint32_t)' ';
memset(attr + old_height * width, 0,
(height - old_height) * width * 4);
}
}

/* Step 4: if new area is smaller, resize memory area now. */
if(new_size <= old_size)
{
cv->chars = realloc(cv->chars, new_size * sizeof(uint32_t));
cv->attr = realloc(cv->attr, new_size * sizeof(uint32_t));
for(f = 0; f < cv->framecount; f++)
{
cv->allchars[f] = realloc(cv->allchars[f],
new_size * sizeof(uint32_t));
cv->allattr[f] = realloc(cv->allattr[f],
new_size * sizeof(uint32_t));
}
}

/* Reset the current frame shortcut */
cv->chars = cv->allchars[cv->frame];
cv->attr = cv->allattr[cv->frame];
}


+ 10
- 16
cucul/cucul.h 查看文件

@@ -33,8 +33,6 @@ extern "C"

/** \e libcucul context */
typedef struct cucul_canvas cucul_canvas_t;
/** sprite structure */
typedef struct cucul_sprite cucul_sprite_t;
/** dither structure */
typedef struct cucul_dither cucul_dither_t;
/** data buffer structure */
@@ -143,20 +141,16 @@ void cucul_draw_thin_triangle(cucul_canvas_t *, int, int, int, int, int, int);
void cucul_fill_triangle(cucul_canvas_t *, int, int, int, int, int, int, char const *);
/* @} */

/** \defgroup sprite libcucul sprite handling
/** \defgroup frame libcucul canvas frame handling
*
* These functions provide high level routines for sprite loading, animation
* and rendering.
* These functions provide high level routines for canvas frame insertion,
* removal, copying etc.
*
* @{ */
cucul_sprite_t * cucul_load_sprite(char const *);
int cucul_get_sprite_frames(cucul_sprite_t const *);
int cucul_get_sprite_width(cucul_sprite_t const *, int);
int cucul_get_sprite_height(cucul_sprite_t const *, int);
int cucul_get_sprite_dx(cucul_sprite_t const *, int);
int cucul_get_sprite_dy(cucul_sprite_t const *, int);
void cucul_draw_sprite(cucul_canvas_t *, int, int, cucul_sprite_t const *, int);
void cucul_free_sprite(cucul_sprite_t *);
unsigned int cucul_get_canvas_frame_count(cucul_canvas_t *);
void cucul_set_canvas_frame(cucul_canvas_t *, unsigned int);
void cucul_create_canvas_frame(cucul_canvas_t *, unsigned int);
void cucul_free_canvas_frame(cucul_canvas_t *, unsigned int);
/* @} */

/** \defgroup dither libcucul bitmap dithering
@@ -166,9 +160,9 @@ void cucul_free_sprite(cucul_sprite_t *);
*
* @{ */
cucul_dither_t *cucul_create_dither(unsigned int, unsigned int,
unsigned int, unsigned int,
unsigned int, unsigned int,
unsigned int, unsigned int);
unsigned int, unsigned int,
unsigned int, unsigned int,
unsigned int, unsigned int);
void cucul_set_dither_palette(cucul_dither_t *,
unsigned int r[], unsigned int g[],
unsigned int b[], unsigned int a[]);


+ 8
- 1
cucul/cucul_internals.h 查看文件

@@ -27,12 +27,19 @@ typedef long unsigned int uintptr_t;

struct cucul_canvas
{
/* Context size */
/* Canvas size */
unsigned int width, height;

/* Shortcut to the active frame */
uint32_t *chars;
uint32_t *attr;

/* Frame information */
unsigned int frame, framecount;
uint32_t **allchars;
uint32_t **allattr;

/* Painting context */
uint16_t fgcolor;
uint16_t bgcolor;



+ 91
- 245
cucul/sprite.c 查看文件

@@ -12,7 +12,7 @@
*/

/*
* This file contains a small framework for sprite loading and blitting.
* This file contains a small framework for canvas frame management.
*/

#include "config.h"
@@ -26,288 +26,134 @@
#include "cucul.h"
#include "cucul_internals.h"

#if !defined(_DOXYGEN_SKIP_ME)
struct cucul_frame
{
int w, h;
int dx, dy;
char *chars;
int *color;
};

struct cucul_sprite
{
int nf;
struct cucul_frame *frames;
};
#endif

/** \brief Allocate a sprite loaded from a file.
/** \brief Get the number of frames in a canvas.
*
* \param file The filename.
* \return The sprite, or NULL if an error occured.
*/
cucul_sprite_t *cucul_load_sprite(char const *file)
{
char buf[BUFSIZ];
cucul_sprite_t *sprite;
FILE *fd;

fd = fopen(file, "r");
if(fd == NULL)
return NULL;

sprite = malloc(sizeof(cucul_sprite_t));
if(sprite == NULL)
goto sprite_alloc_failed;

sprite->nf = 0;
sprite->frames = NULL;

while(!feof(fd))
{
int x, y;
int w = 0, h = 0, dx = 0, dy = 0;
struct cucul_frame *frame;

/* Get width and height */
if(!fgets(buf, BUFSIZ, fd))
break;

sscanf(buf, "%i %i %i %i", &w, &h, &dx, &dy);
if(w <= 0 || h <= 0 || w > BUFSIZ / 2)
break;

if(sprite->nf)
{
void *tmp = realloc(sprite->frames,
(sprite->nf + 1) * sizeof(struct cucul_frame));
if(tmp == NULL)
goto frame_failed;
sprite->frames = tmp;
sprite->nf++;
}
else
{
sprite->frames = malloc((sprite->nf + 1) * sizeof(struct cucul_frame));
if(sprite->frames == NULL)
goto sprite_failed;
sprite->nf++;
}

frame = &sprite->frames[sprite->nf - 1];

frame->w = w;
frame->h = h;
frame->dx = dx;
frame->dy = dy;
frame->chars = malloc(w * h * sizeof(char));
if(frame->chars == NULL)
{
sprite->nf--;
goto frame_failed;
}
frame->color = malloc(w * h * sizeof(int));
if(frame->color == NULL)
{
free(frame->chars);
sprite->nf--;
goto frame_failed;
}

for(y = 0; y < h; y++)
{
if(!fgets(buf, BUFSIZ, fd))
goto frame_failed;

for(x = 0; x < w && buf[x] && buf[x] != '\r' && buf[x] != '\n'; x++)
frame->chars[w * y + x] = buf[x];

for(; x < w; x++)
frame->chars[w * y + x] = ' ';
}

for(y = 0; y < h; y++)
{
if(!fgets(buf, BUFSIZ, fd))
goto frame_failed;

for(x = 0; x < w && buf[x] && buf[x] != '\r' && buf[x] != '\n'; x++)
frame->color[w * y + x] = buf[x] - 'a';

for(; x < w; x++)
frame->color[w * y + x] = ' ' - 'a';
}

continue;
}

if(sprite->nf == 0)
goto sprite_failed;

fclose(fd);
return sprite;

frame_failed:
while(sprite->nf)
{
free(sprite->frames[sprite->nf - 1].color);
free(sprite->frames[sprite->nf - 1].chars);
sprite->nf--;
}
sprite_failed:
free(sprite);
sprite_alloc_failed:
fclose(fd);
return NULL;
}

/** \brief Return the number of frames in a sprite.
* This function returns the current canvas frame count.
*
* \param sprite The sprite.
* \return The number of frames.
* \param cv A libcucul canvas
* \return The frame count
*/
int cucul_get_sprite_frames(cucul_sprite_t const *sprite)
unsigned int cucul_get_canvas_frame_count(cucul_canvas_t *cv)
{
if(sprite == NULL)
return 0;

return sprite->nf;
return cv->framecount;
}

/** \brief Return the width of a sprite.
/** \brief Activate a given canvas frame.
*
* \param sprite The sprite.
* \param f The frame index.
* \return The width of the given frame of the sprite.
*/
int cucul_get_sprite_width(cucul_sprite_t const *sprite, int f)
{
if(sprite == NULL)
return 0;

if(f < 0 || f >= sprite->nf)
return 0;

return sprite->frames[f].w;
}

/** \brief Return the height of a sprite.
* This function sets the active canvas frame. All subsequent drawing
* operations will be performed on that frame. The current painting
* context set by cucul_set_color() or cucul_set_truecolor() is inherited.
*
* If the frame index is outside the canvas' frame range, nothing happens.
*
* \param sprite The sprite.
* \param f The frame index.
* \return The height of the given frame of the sprite.
* \param cv A libcucul canvas
* \param frame The canvas frame to activate
*/
int cucul_get_sprite_height(cucul_sprite_t const *sprite, int f)
void cucul_set_canvas_frame(cucul_canvas_t *cv, unsigned int frame)
{
if(sprite == NULL)
return 0;
if(frame >= cv->framecount)
return;

if(f < 0 || f >= sprite->nf)
return 0;
cv->frame = frame;

return sprite->frames[f].h;
cv->chars = cv->allchars[cv->frame];
cv->attr = cv->allattr[cv->frame];
}

/** \brief Return the X coordinate of a sprite's handle.
/** \brief Add a frame to a canvas.
*
* \param sprite The sprite.
* \param f The frame index.
* \return The X coordinate of the given frame's handle.
* This function creates a new frame within the given canvas. Its contents
* are copied from the currently active frame.
*
* The frame index indicates where the frame should be inserted. Valid
* values range from 0 to the current canvas frame count. If the frame
* index is greater the or equals the current canvas frame count, the new
* frame is appended at the end of the canvas.
*
* The active frame does not change, but its index may be renumbered due
* to the insertion.
*
* \param cv A libcucul canvas
* \param frame The index where to insert the new frame
*/
int cucul_get_sprite_dx(cucul_sprite_t const *sprite, int f)
void cucul_create_canvas_frame(cucul_canvas_t *cv, unsigned int frame)
{
if(sprite == NULL)
return 0;
unsigned int size = cv->width * cv->height * sizeof(uint32_t);
unsigned int f;

if(f < 0 || f >= sprite->nf)
return 0;
if(frame > cv->framecount)
frame = cv->framecount;

return sprite->frames[f].dx;
}
cv->framecount++;
cv->allchars = realloc(cv->allchars, sizeof(uint32_t *) * cv->framecount);
cv->allattr = realloc(cv->allattr, sizeof(uint32_t *) * cv->framecount);

/** \brief Return the Y coordinate of a sprite's handle.
*
* \param sprite The sprite.
* \param f The frame index.
* \return The Y coordinate of the given frame's handle.
*/
int cucul_get_sprite_dy(cucul_sprite_t const *sprite, int f)
{
if(sprite == NULL)
return 0;
for(f = cv->framecount - 1; f > frame; f--)
{
cv->allchars[f] = cv->allchars[f - 1];
cv->allattr[f] = cv->allattr[f - 1];
}

cv->allchars[frame] = malloc(size);
memcpy(cv->allchars[frame], cv->chars, size);
cv->allattr[frame] = malloc(size);
memcpy(cv->allattr[frame], cv->attr, size);

if(f < 0 || f >= sprite->nf)
return 0;
if(cv->frame >= frame)
cv->frame++;

return sprite->frames[f].dy;
cv->chars = cv->allchars[cv->frame];
cv->attr = cv->allattr[cv->frame];
}

/** \brief Draw a sprite's specific frame at the given coordinates. If the
* frame does not exist, nothing is displayed.
/** \brief Remove a frame from a canvas.
*
* This function deletes a frame from a given canvas.
*
* It is not legal to remove the last frame from a canvas. Such a request
* will be ignored by cucul_free_canvas_frame().
*
* The frame index indicates the frame to delete. Valid values range from
* 0 to the current canvas frame count minus 1. If the frame index is
* greater the or equals the current canvas frame count, the last frame
* is deleted.
*
* If the active frame is deleted, frame 0 becomes the new active frame.
* Otherwise, the active frame does not change, but its index may be
* renumbered due to the deletion.
*
* \param cv A libcucul canvas
* \param x The X coordinate.
* \param y The Y coordinate.
* \param sprite The sprite.
* \param f The frame index.
* \return void
* \param frame The index of the frame to delete
*/
void cucul_draw_sprite(cucul_canvas_t *cv, int x, int y,
cucul_sprite_t const *sprite, int f)
void cucul_free_canvas_frame(cucul_canvas_t *cv, unsigned int frame)
{
int i, j;
unsigned int oldfg, oldbg;
struct cucul_frame *frame;
unsigned int f;

if(sprite == NULL)
if(frame >= cv->framecount)
return;

if(f < 0 || f >= sprite->nf)
if(cv->framecount == 1)
return;

frame = &sprite->frames[f];
free(cv->allchars[frame]);
free(cv->allattr[frame]);

oldfg = cv->fgcolor;
oldbg = cv->bgcolor;

for(j = 0; j < frame->h; j++)
for(f = frame + 1; f < cv->framecount; f++)
{
for(i = 0; i < frame->w; i++)
{
int col = frame->color[frame->w * j + i];
if(col >= 0)
{
cucul_set_color(cv, col, CUCUL_COLOR_BLACK);
cucul_putchar(cv, x + i - frame->dx, y + j - frame->dy,
frame->chars[frame->w * j + i]);
}
}
cv->allchars[f - 1] = cv->allchars[f];
cv->allattr[f - 1] = cv->allattr[f];
}

cucul_set_color(cv, oldfg, oldbg);
}
cv->framecount--;
cv->allchars = realloc(cv->allchars, sizeof(uint32_t *) * cv->framecount);
cv->allattr = realloc(cv->allattr, sizeof(uint32_t *) * cv->framecount);

/** \brief Free the memory associated with a sprite.
*
* \param sprite The sprite to be freed.
* \return void
*/
void cucul_free_sprite(cucul_sprite_t *sprite)
{
int i;

if(sprite == NULL)
return;

for(i = sprite->nf; i--;)
{
struct cucul_frame *frame = &sprite->frames[i];
free(frame->chars);
free(frame->color);
}
if(cv->frame > frame)
cv->frame--;
else if(cv->frame == frame)
cv->frame = 0;

free(sprite->frames);
free(sprite);
cv->chars = cv->allchars[cv->frame];
cv->attr = cv->allattr[cv->frame];
}


Loading…
取消
儲存