gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Graphics > Algorithmically generated animation to images

#37598 - kajic - Mon Mar 14, 2005 12:59 am

I feel the need for a c/c++ function that takes data about an image and when given a command dumps the image to a file. I would like to use such a function to be able to extract the images of an animation generated by some algorithm. So I let my algorithm create a frame in an animation and as the frame is created I send its data to this function, and at the end of each cycle of the algorithm I tell the function to dump an image containing the data sent to it.
I am thinking about making this function myself but I though maybe someone has already done something similar and feels like sharing the source.

- Robert

#37601 - sajiimori - Mon Mar 14, 2005 1:31 am

Are you talking about building a 2D array of colors algorithmically and then writing a file based on that? Do you already have the code to generate the array?

Depending on the image format you want to produce, the procedure for writing the array to a file might be trivial.

#37604 - kajic - Mon Mar 14, 2005 2:50 am

sajiimori wrote:
Are you talking about building a 2D array of colors algorithmically and then writing a file based on that? Do you already have the code to generate the array?

Depending on the image format you want to produce, the procedure for writing the array to a file might be trivial.


I am not talking of any algorithm in particular. I am thinking of making a game in which a lot of the animations can be genrated with code. So what I am looking for is a way to calculate those animations in beforehand and then just dump each frame of an animation to an image. I would then convert the images to sprites and use them in my animations.
So lets say I have an algorithm that while looping makes some animation. I want a function that my algorithm can send the pixels calculated to and at the end of each frame tell the function to dump all pixels to an image. The declaration of the function could for example look like this:

Code:

typedef struct image {
   int red;
   int green;
   int blue;
   struct image *next;
} image;

void d2img(image *i, int red, int green, int blue, int width, int dump) {
}


So in this particullar case lets say I first call the function a few hundred times with various rgb values. For each call it would store the values into the linked list suplied. When I finally call the function with dump set to 1 it would generate a image of some nice format (jpg,gif,etc.) from the data in the linked list (the width argument would be used to tell the function when to break the image into a new row).
The boring part (the part that made me post here hoping someone allready did all this) is I dont want to spend time learning how to generate an image.

#37610 - tepples - Mon Mar 14, 2005 5:57 am

For one thing, you do not put pixels in a linked list. Make a two dimensional array, and then we'll talk.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#37611 - poslundc - Mon Mar 14, 2005 6:43 am

There are endless possibilities of mathematically interesting images and animations you can generate, thanks to endless mathematics that can be used to govern image generation.

But you are unlikely to find that someone will have pre-created something that suits your particular needs, especially if you want a tool that conveniently generates the images and exports the results to a GBA-compatible format.

Dan.

#37612 - sajiimori - Mon Mar 14, 2005 6:53 am

It's difficult to make any sort of meaningful response because your description of your intent is vague, and you seem to have decided upon a very strange architecture that doesn't fit the work that needs to be done.

It doesn't help things to talk in terms of nebulous ideas like dumping animation frames to images, converting images to sprites, or sending pixels to a function and then telling it to dump those pixels to an image. These formulations don't fit the actual nature of the concepts involved.

Just focus on expressing what you actually want to accomplish, and not the architecture behind it, then we can talk about some reasonable ways to go about it.

#37626 - kajic - Mon Mar 14, 2005 11:53 am

tepples wrote:
For one thing, you do not put pixels in a linked list. Make a two dimensional array, and then we'll talk.


It seems like you are missing my point. My example was just indended to show what I was talking about, the linked list was just an idea of how to store the image, not something I have decided I MUST use. But I wouldn't mind if you could explain what is wrong with a linked list as I dont see it myself.

sajiimori wrote:
It's difficult to make any sort of meaningful response because your description of your intent is vague, and you seem to have decided upon a very strange architecture that doesn't fit the work that needs to be done.

It doesn't help things to talk in terms of nebulous ideas like dumping animation frames to images, converting images to sprites, or sending pixels to a function and then telling it to dump those pixels to an image. These formulations don't fit the actual nature of the concepts involved.

Just focus on expressing what you actually want to accomplish, and not the architecture behind it, then we can talk about some reasonable ways to go about it.


The only reason I expressed myself as I did is I was hoping it would make you better understand what I was talking about. I am sorry it turned out to be nebulous.
I don't know if there is any good in trying to explain again because I would probably end up repeating myself but I'll try one more time (in a very short way).

I am looking for a function that given data about a image will create a file of a well known format. The data given to it hasn't to be in a linked list but can be handed over in any way convenient, the linked list was just a though of mine.
I just came to think of GD and I guess there should be something in it that suits my needs even if you still don't understand what I am talking about. Ill be sure to post the source here when I'm done though and hopefully you will then.

#37641 - josath - Mon Mar 14, 2005 6:03 pm

it seems like to me, all you are asking is if there are librarys that support writing image files. the answer is yes, lots and lots of them. there are many free ones. names like libpng or libjpeg are specific to one image format. try searching on google for 'c image library' , or sourceforge.net for just 'image library', you'll find dozens of more generic ones that handle many formats.

#37642 - poslundc - Mon Mar 14, 2005 6:19 pm

kajic wrote:
I am looking for a function that given data about a image will create a file of a well known format. The data given to it hasn't to be in a linked list but can be handed over in any way convenient, the linked list was just a though of mine.
I just came to think of GD and I guess there should be something in it that suits my needs even if you still don't understand what I am talking about. Ill be sure to post the source here when I'm done though and hopefully you will then.


GD is great. I've used the PHP interface to it pretty much exclusively for the various GBA tools programming I've done. If all you want is a way to generate image files from your own internal representation of an image, you can't go wrong with GD.

Dan.

#37656 - tepples - Mon Mar 14, 2005 9:28 pm

kajic wrote:
It seems like you are missing my point. My example was just indended to show what I was talking about, the linked list was just an idea of how to store the image, not something I have decided I MUST use.

I strongly deprecated linked lists because I felt that they were clouding both your concept and our concept of what you really want to accomplish. Sometimes you need to crawl before you walk; start by learning the basics of digital signal processing.

Quote:
But I wouldn't mind if you could explain what is wrong with a linked list as I dont see it myself.

The most common data structure for a digital signal is an array, also called a vector. As images are two-dimensional signals, one would use a two-dimensional array. Programs that must handle images of various sizes will use a one-dimensional array treated as two-dimensional in software. Accessing an element in an array takes O(1) time. A linked list with one pixel per list element, on the other hand, will use half the memory for pointers, and accessing the nth element by number is O(n).

Anyway, you typically convert images to and from well-known image formats using a library such as GD, and you typically convert images to and from platform-specific image formats using your own code written to the platform's documentation. For GBA data formats, one complete reference is GBATEK by Martin Korth.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.


Last edited by tepples on Mon Mar 14, 2005 9:34 pm; edited 1 time in total

#37659 - kajic - Mon Mar 14, 2005 9:32 pm

josath: Well I guess it is :)
I just got GD compiled and managed to compile a simple program using it. I had problems at first as I didnt realize gcc required the path of libgd.a to be specified. Anyway, now that it works I guess I have everything I indended to ask for in my first post.
Thanks for trying to help anyway!

PS.
A friend pointed out the benefits of storing the image in a 2d array instead of a linked list :)

#37668 - kajic - Mon Mar 14, 2005 11:29 pm

Here is a simple program I wrote that should explain what I was looking for.
UPDATE:
I added the ability to export to a gif-animation.

Code:

#include<gd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define WIDTH 320
#define HEIGHT 240
#define GIF_NAME "animation.gif"


/* determine if a file exists */

int fileExists(char *filename) {
  /* declare file */
  FILE *file;
 
  /* try to open file */
  if ((file = fopen(filename, "r")) == NULL)
    return 0;

  /* as the file exists we must close it */
  fclose(file);
  return 1;
}


/* add the frame to the gif-animation specified by GIF_NAME. if no such
   animation exists one will be created and before we add the frame the
   header of the gif will be written to the created file */

void makeGif(gdImagePtr im) {
  /* declare output file */
  FILE *outFile;

  /* if there exists no animatione we will create one and write its header */
  if (!fileExists(GIF_NAME)) {
    /* open file */
    outFile = fopen(GIF_NAME, "wb");
       
    /* write the header */
    gdImageGifAnimBegin(im, outFile, 0, 0);

    /* close the file */
    fclose(outFile);
  }

  /* open file im append mode */
  outFile = fopen(GIF_NAME, "ab");

  /* add the frame */
  gdImageGifAnimAdd(im, outFile, 1, 0, 0, 1, gdDisposalNone, NULL);

  /* close the file */
  fclose(outFile);
}


/* terminate the gif-animation specified by GIF_NAME. this is done
   by adding a semicolon to the end of the file. */

void closeGif() {
  /* declare output file */
  FILE *outFile;

  /* open file in append mode */
  outFile = fopen(GIF_NAME, "ab"); 

  gdImageGifAnimEnd(outFile);
}


/* save the frame at im to a png-file */

void makePng(gdImagePtr im, int frame) {
  /* declare output file */
  FILE *outFile;

  char frameName[11];
  frameName[0] = '\0';
 
  /* convert frame int to string */
  sprintf(frameName, "%d", frame);

  /* append the extension */
  strcat(frameName, ".png\0");

  /* open output file */
  outFile = fopen(frameName, "wb");

  /* output the image */
  gdImagePng(im, outFile);

  /* close file */
  fclose(outFile);
}


/* if the current frame shouldnt be skipped we can either call
   upon makePng for it to create the frame OR makeGif so that
   the frame can be added to the gif-animation specified by
   GIF_NAME */

void makeFile(gdImagePtr im, char *type, int frame, int frameSkipping) {
  /* check if the frame we are at should be outputed */
  if (frame % frameSkipping)
    return;

  /* check what type of image we want to output */
  if (!strcmp(type, "gif"))
    makeGif(im);
  else if (!strcmp(type, "png"))
    makePng(im, frame);
}


/* sets the given pixel in the frame im to the given color */

void putPixel(gdImagePtr im, int x_pos, int y_pos, int red, int green, int blue) {
  int color;

  /* set the drawing color  */
  color = gdImageColorResolve(im, red, green, blue);

  /* put a pixel to the image */
  gdImageSetPixel(im, x_pos, y_pos, color);
}


/* create a frame with the given dimensions/background color
   note: the color of the background is also made transparent */

gdImagePtr createImage(gdImagePtr im, int width, int height, int red, int green, int blue) {
  /* allocate the image */
  im = gdImageCreate(width, height);

  /* allocate the background color, as it is the first color allocated in a new
     image it will be used as background */
  int bg;
  bg = gdImageColorAllocate(im, red, green, blue);

  return im;
}


/* create a backup of the animation specified by GIF_NAME */

void backupAnimation(void) {
  if (fileExists(GIF_NAME)) {
    char newName[200];
    newName[0] = '\0';
   
    int n;
    for (n=1; n>0; n++) {
      sprintf(newName, "old.%d." GIF_NAME, n);
      if (!fileExists(newName))
   n=-1;
    }

    rename(GIF_NAME, newName);
  }
}


int main(int argc, char *argv[]) {
  /* check if the correct number of arguments have been suplied */
  if (argc != 3) {
    /* print usage message */
    printf("Usage: %s [string png/gif] [int frameSkip where frameSkip>0]\nExample: %s gif 10; would produce a gif animation where every tenth frame is used. \nExample: %s png 1; would produce one png image for each frame. \nNote: The first frame can't be skipped. \n", argv[0], argv[0], argv[0]);
    return 20;
  }
 
  /* set output type */
  char outType[3];
  strcpy(outType, argv[1]);

  /* set frameSkip value */
  int frameSkip;
  frameSkip = atoi(argv[2]); /* this will cause an floating point exception if argv[2] cant be converted to and int */

  /* backup the animation file if it already exists */
  if (!strcmp(outType, "gif"))
    backupAnimation();
 
  /* declare the image */
  gdImagePtr im;

  /* create the image */
  im = createImage(im, WIDTH, HEIGHT, 0, 0, 0);

  /* a simple algorithm indended for testing */
  int frame;
  int red=0, green=0, blue=0;
  for (frame=0; frame<HEIGHT; frame++) {
    /* put pixels to image */
    int i;
    for (i=0; i<WIDTH; i++)
      putPixel(im, i, frame, red, green, blue);

    /* output the image */
    makeFile(im, outType, frame, frameSkip);

    /* change the color of the next row */
    red++;
  }

  /* close gif */
  if (!strcmp(outType, "gif"))
    closeGif();

  /* destroy image */
  gdImageDestroy(im);

  return 0;
}

#78343 - StoneCypher - Thu Apr 06, 2006 11:58 pm

Quote:
It seems like you are missing my point. My example was just indended to show what I was talking about, the linked list was just an idea of how to store the image, not something I have decided I MUST use. But I wouldn't mind if you could explain what is wrong with a linked list as I dont see it myself.


Uh. Because you need to dereference a pointer to find the next pixel, instead of incrementing? because that prevents array copies or blits? because it's not conceptually a list? Because it wastes almost as much space as encoding 5-bit unsigned packed values in 32-bit signed space?

This is an image:
u16 myPic[size];

This is your approach:
struct { int r,g,b; void* next; } myPic[size];

Differences:

- Your approach takes 8 times as much space as it should. On a platform as desperately short of memory as the DS, that's suicide.

- Optimized assembly takes seven cycles minimum (probably more due to bank latency) to read a pixel; the normal approach generally takes about a fifth of a cycle through things like STMIA loops. On a platform as cycle-limited as the DS, that's suicide.

- Your approach has extremely poor clustering qualities, which is poison on an architecture as cache-dependant as the DS is.

- Your approach bears no apparent resemblance to a bitmap. There's a reason that word gets used both for arrays and images: images *are* arrays (vector images notwithstanding.)

- Your approach ignores the fundamental nature of the data

- Your approach means you have to seek from the beginning of the image to get *any* pixel, giving an average seek time of o(n), instead of the average seek time of o(1) had by an array

- Your approach ignores the nature of VRAM; this simply won't work in video memory, period, end of story.

- <dolemite> Nigga, is you crazy? </dolemite>

Look, this would be a performance problem on a PC. Time to learn the fundamentals of data structures.
_________________
Quidquid Latine dictum sit, altum Sonatur
[Images not permitted - Click here to view it]

#82475 - Ant6n - Sat May 06, 2006 8:09 pm

nice bashing there, stonebusta