Posted By: HeelX
bmap_savetga - 04/14/13 07:36
Some users reported that they can't properly save a bitmap as TGA with bmap_save, because the bitmap gets mirrored. This is due the fact that TGA stores a handedness flag that defines if the image origin is in the upper- or lower left corner. --- I found out, that if you set the flag in the TGA, that indicates the origin in the lower left corner, and you write the image upside down into the file, the bitmap is saved correctly and is loaded correctly back into the engine.
So I have written the following function "bmap_savetga" a while ago (inspired by ventilator's C-Script in the wiki) in Lite-C for another project to circumvent the upside-down problem; it also saves the alpha channel in the TGA, if and only if the passed BMAP* has an alpha channel, too; otherwise the TGA just saves RGB data.
Here is the function:
Here is an example, that creates an RGBA image with a horizontal color gradient and a vertical alpha gradient, saves it and loads it again:
Screenshot:
I hope you find this useful.
Regards,
-Christian
So I have written the following function "bmap_savetga" a while ago (inspired by ventilator's C-Script in the wiki) in Lite-C for another project to circumvent the upside-down problem; it also saves the alpha channel in the TGA, if and only if the passed BMAP* has an alpha channel, too; otherwise the TGA just saves RGB data.
Here is the function:
Code:
// Saves a bitmap as tga file BOOL bmap_savetga (BMAP* b, char* filename) { BOOL bSuccess = false; if (b && filename && strlen(filename) > 0) { var fh = file_open_write(filename); if (fh) { int height = b->height; int width = b->width; var format = bmap_lock(b, 0); // if the bitmap has an alpha channel BOOL bAlpha = (((format == 8888) || (format == 1555) || (format == 4444)) && (b->bytespp == 4)); // header int i; for (i = 0; i < 2; i++) file_asc_write(fh, 0); file_asc_write(fh, 2); // uncompressed for (i = 0; i < 7; i++) file_asc_write(fh, 0); // y origin (lower left corner) file_asc_write(fh, height & 255); file_asc_write(fh, (height >> 8) & 255); file_asc_write(fh, width & 255); file_asc_write(fh, (width >> 8) & 255); file_asc_write(fh, height & 255); file_asc_write(fh, (height >> 8) & 255); int bypp = 24; if (bAlpha) bypp = 32; file_asc_write(fh, bypp); // bypp file_asc_write(fh, 0); // pixels COLOR bgr; var alpha; int ix, iy; for (iy = 0; iy < height; iy++) { for (ix = 0; ix < width; ix++) { // retrieve BGR color and alpha pixel_to_vec(&bgr, &alpha, format, pixel_for_bmap(b, ix, height - 1 - iy)); file_asc_write(fh, bgr.blue); // b file_asc_write(fh, bgr.green); // g file_asc_write(fh, bgr.red); // r if (bAlpha) file_asc_write(fh, alpha * 2.55); // a } } // done! bmap_unlock(b); file_close(fh); bSuccess = true; } } return(bSuccess); }
Here is an example, that creates an RGBA image with a horizontal color gradient and a vertical alpha gradient, saves it and loads it again:
Code:
#include <acknex.h> #include <default.c> int main () { wait(3); int format = 8888; BMAP* b = bmap_createblack(100, 200, format); bmap_lock(b, 0); // create red to green gradient from left to right // and alpha gradient from translucent to solid from up to bottom int ix, iy; for (ix = 0; ix < b->width; ix++) { for (iy = 0; iy < b->height; iy++) { double fx = (double)ix / (double)(b->width-1); double fy = (double)iy / (double)(b->height-1); VECTOR color; vec_lerp(&color, COLOR_RED, COLOR_GREEN, fx); var pixel = pixel_for_vec(&color, 100 * fy, format); pixel_to_bmap(b, ix, iy, pixel); } } bmap_unlock(b); // save to file bmap_savetga(b, "b.tga"); // load from file to compare BMAP* bf = bmap_create("b.tga"); video_set(32+b->width+16+bf->width+32, 32+maxv(b->height, bf->height)+32, 0, 2); while (1) { draw_text("engine", 32, 32, COLOR_WHITE); draw_quad(b, vector(32, 48, 0), NULL, NULL, NULL, NULL, 100, 0); draw_text("file", 32 + b->width + 16, 32, COLOR_WHITE); draw_quad(bf, vector(32 + b->width + 16, 48, 0), NULL, NULL, NULL, NULL, 100, 0); wait(1); } }
Screenshot:
I hope you find this useful.
Regards,
-Christian