1
\$\begingroup\$

I am learning the physics engine Chipmunk. In the source code, the example demo "LogoSmash" uses char array to store image_data, but I don't understand how to do that, it's amazing!

Here is the LogoSmash code in question:

static const unsigned char image_bitmap[] = {
  15, -16, 0, 0, ...
}

Will someone explain how this works and how I could do this?

\$\endgroup\$
6
\$\begingroup\$

In C++, a char is an integral data type. It holds numbers, and on most implementations you are likely to encounter, it will be capable of holding 8 bits of data.

The 24-bit RGB color representation (the most common one that does not encode transparency information) uses 8 bits for each red, blue and green channel. Thus, a single char can hold a single color channel of data, and three char objects can hold a complete RGB pixel. If you include transparency via an alpha channel (RGBA), four char objects can completely define a pixel.

Thus, an array of 4 x width x height char objects can hold the pixel information for a image of width by height pixels. Note that one usually uses unsigned chars in practice, since signed chars allow negative values which is generally semantic nonsense for color values.


Since chars are just numbers, it's perfectly possible to encode the image data directly into one's source code as follows:

unsigned char image[] = {
  255, 0, 0, 0,  // 1st RGBA pixel, completely red.
  0, 255, 0, 0,  // 2nd RGBA pixel, completely blue.
  // and so on
};

It's rather impractical for images of any kind of complexity, since it both requires you to write or find some tool that will save or convert bitmaps into source code, and it requires a re-compile to change any part of the image (which is not very good for iteration), but it's a common technique for really simple demos that don't want to confuse the issue being demonstrated with lots of file IO and image read code and whatnot.

However, I wouldn't recommend using this technique in production code (or really, at all, just load the image from a file, there are plenty of libraries to help you with that).

\$\endgroup\$
  • \$\begingroup\$ Thanks, Josh. But it seems a little different from the image_bitmap in the demo code. There are some negative numbers, and not all 0/1 numbers. So maybe it uses another way to store the image data. \$\endgroup\$ – ChildhoodAndy Feb 25 '14 at 3:52
  • \$\begingroup\$ I edited your question to generalize it, because asking how one specific project implements something or why they made a decision is not on-topic here. So this answer does not cover the specifics of the Chipmunk example. \$\endgroup\$ – Josh Feb 25 '14 at 3:55
  • 1
    \$\begingroup\$ That said, there are negative numbers in the initialization of the array in that code you linked, but the array is of "unsigned char" so the actual values are converted from their signed representation to unsigned representation. Using the negative values during initialization is just (sloppy) shorthand. Whether or not that linked code uses the values in the array to represent colors or something else, I'm not sure and didn't look into. It's not on-topic here. \$\endgroup\$ – Josh Feb 25 '14 at 3:56
  • 2
    \$\begingroup\$ I think it is worth mentioning that GIMP allows you to export your images as .c files. The output file contains a struct that stores width, height, bytes per pixel, as well as an array of unsigned chars. Also, I can see one reason for using this being that you can pack your entire program into a single executable (assuming that you don't have any other dynamic assets). This can save the user the inconvenience of having to unpack your program. \$\endgroup\$ – Lysol Feb 25 '14 at 4:53
2
\$\begingroup\$

In the case of the Chipmunk demos, I was really trying to cram the image bitmap into as little space as possible in the source code.

Some things:

  • It's a 1 bit per pixel bitmap, so each unsigned char in the array actually holds 8 pixels. The funky get_pixel() function is what unpacks the bits.
  • The image_bitmap array was generated by a Ruby script where I loaded a .png file, packed the bits for the image, and generated the C source code for the array.
  • The negative numbers are only there to make the source code a little bit shorter overall.

As Josh says, this isn't really a recommended way to work with bitmaps. Normally you'd load them from a separate file. I only did it that way in the Chipmunk demos because the image was very small and I wanted to avoid using an image loading library for an otherwise simple physics demo.

\$\endgroup\$
  • \$\begingroup\$ My friends often use box2d to develop games, I ask them why not use Chipmunk. The answer is the tutorials about Chipmunk written in Chinese are nearly none. You know not all people know English well, so I am ready to devote myself into popularizing Chipmunk in China, including translating docs, some tutorials and so on. I created a team in github:ChipmunkCommunityCN. \$\endgroup\$ – ChildhoodAndy Feb 25 '14 at 7:36
1
\$\begingroup\$

May I suggest an alternative representation for an image?

Create a class/struct to represent your color in any paradigm you want(32 bit RGBA, 24bit RGB or anything else really). For example:

class Color { uint8 red, green, blue, alpha; }

Now, make sure you use dynamic arrays, and since its a lot of data, prefer the heap over stack. The perfect container will be a std::vector perhaps. So:

std::vector image_data;

Now you can manage the container to have NxM pixels, and each of its elements represents a pixel within that image. Now you have a dynamic solution, ready to scale to any situation, you can easily convert between representations safely (raw array vs std::vector).

unsigned char* image_data_raw = reinterpret_cast(&image_data[0]);

Hope it helps. You just need to find what representation your colors have and you're set :)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.