Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifndef __TGAC
- #define __TGAC
- #include "tga_v4.h"
- uint8_t* tga_new_pixelbuffer( uint16_t w, uint16_t h, uint8_t bpp ) {
- uint32_t length;
- if(w == 0 || h == 0) return NULL;
- length = w; length *= h;
- switch( bpp ) {
- case 8: return (uint8_t*)malloc( length );
- case 24: return (uint8_t*)malloc( length * 3U );
- case 32: return (uint8_t*)malloc( length * 4U );
- default: return NULL;
- }
- return NULL; // this should never happen
- }
- void* tga_free_pixelbuffer( void* buf ) {
- if( !buf ) return NULL;
- free( buf ); buf = NULL;
- return NULL;
- }
- tga_t* tga_new( uint16_t w, uint16_t h, uint8_t bpp ) {
- tga_t* t;
- if( w == 0 || h == 0 || (bpp != 24 && bpp != 32 && bpp != 8) ) return NULL;
- t = (tga_t*)malloc( sizeof(tga_t) );
- if( !t ) return NULL;
- t->pixels = tga_new_pixelbuffer( w, h, bpp );
- if( !t->pixels ) {
- free( t );
- return NULL;
- }
- // I guess its worth noting that I do not clear the pixel buffer here
- t->ext_pixels = 0;
- t->inverted = 0;
- t->w = w;
- t->h = h;
- t->bpp = bpp;
- t->refcount = 1;
- return t;
- }
- tga_t* tga_new_internal1( uint16_t w, uint16_t h, uint8_t bpp, uint8_t inverted ) {
- tga_t* temp;
- temp = tga_new( w, h, bpp );
- if( !temp ) return NULL;
- temp->inverted = inverted;
- return temp;
- }
- tga_t* tga_new_formatted( uint16_t w, uint16_t h, tga_t* tga_ref ) {
- if( !tga_ref ) return NULL;
- if( w == 0 ) w = tga_ref->w;
- if( h == 0 ) h = tga_ref->h;
- return tga_new_internal1( w, h, tga_ref->bpp, tga_ref->inverted );
- }
- tga_t* tga_new_from_data( uint16_t w, uint16_t h, uint8_t bpp, uint8_t inverted, uint8_t* data ) {
- tga_t* t;
- if( !data ) return NULL;
- if( w == 0 || h == 0 || (bpp != 24 && bpp != 32 && bpp != 8) ) return NULL;
- t = (tga_t*)malloc( sizeof(tga_t) );
- if( !t ) return NULL;
- t->ext_pixels = 1;
- t->inverted = inverted;
- t->pixels = data;
- t->w = w;
- t->h = h;
- t->bpp = bpp;
- t->refcount = 1;
- return t;
- }
- tga_t* tga_free( tga_t* t ) {
- if( t == NULL ) return NULL;
- if( t->refcount > 0 ) --t->refcount;
- if( t->refcount > 0 ) return NULL;
- if( !t->ext_pixels )
- if( t->pixels )
- free( t->pixels );
- free( t ); t = NULL;
- return NULL;
- }
- color_t tga_pixel_get( tga_t* t, uint16_t x, uint16_t y ) {
- uint32_t pos; color_t c;
- if( !t ) return 0;
- if( !t->pixels || x >= t->w || y >= t->h ) return 0;
- if( t->inverted ) y = ( t->h - 1 ) - y;
- pos = y; pos *= t->w; pos += x;
- switch( t->bpp ) {
- case 8: { // Y
- c = t->pixels[ pos ];
- c = ( c << 24 ) | ( c << 16 ) | ( c << 8 ) | 0xFF;
- return c;
- } break;
- case 24: { // BGR
- c = (uint32_t)t->pixels[ (pos*3U)+0U ] << 8U;
- c |= (uint32_t)t->pixels[ (pos*3U)+1U ] << 16U;
- c |= (uint32_t)t->pixels[ (pos*3U)+2U ] << 24U;
- c |= 0xFF;
- return c;
- } break;
- case 32: { // BGRA
- c = (uint32_t)t->pixels[ (pos*4U)+0U ] << 8U;
- c |= (uint32_t)t->pixels[ (pos*4U)+1U ] << 16U;
- c |= (uint32_t)t->pixels[ (pos*4U)+2U ] << 24U;
- c |= (uint32_t)t->pixels[ (pos*4U)+3U ];
- return c;
- } break;
- default: return 0;
- }
- return 0; // this should never happen
- }
- uint8_t tga_pixel_get8( tga_t* t, uint16_t x, uint32_t y ) {
- if( !t ) return 0;
- if( x >= t->w || y >= t->h ) return 0;
- if( t->bpp != 8 ) {
- return tga_pixel_get( t, x, y ) >> 16;
- }
- y *= t->w; y += x;
- return ((uint8_t*)(t->pixels))[ y ];
- }
- void tga_pixel_set8( tga_t* t, uint16_t x, uint32_t y, uint8_t c ) {
- if( !t ) return;
- if( x >= t->w || y >= t->h ) return;
- if( t->bpp != 8 ) {
- color_t c32;
- c32 = c; c32 <<= 8; c32 |= c; c32 <<= 8; c32 |= c; c32 <<= 8; c32 |= 255U;
- tga_pixel_set( t, x, y, c32 );
- return;
- }
- y *= t->w; y += x;
- ((uint8_t*)(t->pixels))[ y ] = c;
- }
- void tga_pixel_set( tga_t* t, uint16_t x, uint16_t y, color_t c ) {
- uint32_t pos;
- if( !t ) return;
- if( !t->pixels || x >= t->w || y >= t->h ) return;
- if( t->inverted ) y = ( t->h - 1 ) - y;
- pos = y; pos *= t->w; pos += x;
- switch( t->bpp ) {
- case 8: { // Y
- // use the green channel
- t->pixels[ pos ] = c >> 16U;
- } break;
- case 24: { // BGR
- t->pixels[ (pos*3)+0 ] = c >> 8U;
- t->pixels[ (pos*3)+1 ] = c >> 16U;
- t->pixels[ (pos*3)+2 ] = c >> 24U;
- } break;
- case 32: { // BGRA
- t->pixels[ (pos*4)+0 ] = c >> 8U;
- t->pixels[ (pos*4)+1 ] = c >> 16U;
- t->pixels[ (pos*4)+2 ] = c >> 24U;
- t->pixels[ (pos*4)+3 ] = c;
- } break;
- default: break;
- }
- }
- color_t tga_new_color_from_shade( uint8_t s ) {
- color_t r;
- r = s; r <<= 8;
- r |= s; r <<= 8;
- r |= s; r <<= 8;
- r |= 0xFF;
- return r;
- }
- void tga_line( int32_t x0, int32_t y0, int32_t x1, int32_t y1, color_t color, tga_t* tga ) {
- int32_t dx, dy, sx, sy, err, e2;
- dx = x1 - x0;
- if( dx < 0 ) dx = -dx;
- dy = y1 - y0;
- if( dy < 0 ) dy = -dy;
- sx = (x0<x1 ? 1 : -1);
- sy = (y0<y1 ? 1 : -1);
- err = ((dx>dy ? dx : -dy)/2);
- while(1){
- tga_pixel_set( tga, (uint16_t)x0, (uint16_t)y0, color );
- if( x0==x1 && y0==y1 ) break;
- e2 = err;
- if( e2 >-dx ) {err -= dy; x0 += sx;}
- if( e2 < dy ) {err += dx; y0 += sy;}
- }
- }
- void tga_line_thick( int32_t x0, int32_t y0, int32_t x1, int32_t y1, color_t color, tga_t* tga ) {
- int32_t kx, ky, c, i, dx, dy;
- dx = x1 - x0;
- kx = 0;
- if( dx > 0 ) kx = +1;
- if( dx < 0 ) { kx = -1; dx = -dx; }
- dx++;
- dy = y1 - y0;
- ky = 0;
- if( dy > 0 ) ky = +1;
- if( dy < 0 ) { ky = -1; dy = -dy; }
- dy++;
- if( dx >= dy ) {
- for( c = dx, i = 0; i < dx; i++, x0 += kx ) {
- tga_pixel_set( tga, (uint16_t)x0, (uint16_t)y0, color );
- c -= dy;
- if( c <= 0 ) {
- if( i != dx - 1 ) {
- ;//tga_pixel_set( tga, (uint16_t)(x0 + kx), (uint16_t)y0, color );
- }
- c += dx;
- y0 += ky;
- if( i != dx - 1 ) {
- tga_pixel_set( tga, (uint16_t)x0, (uint16_t)y0, color );
- }
- }
- }
- } else {
- for( c = dy, i = 0; i < dy; i++, y0 += ky ) {
- tga_pixel_set( tga, (uint16_t)x0, (uint16_t)y0, color );
- c -= dx;
- if( c <= 0 ) {
- if( i != dy - 1 ) {
- ;//tga_pixel_set( tga, (uint16_t)x0, (uint16_t)(y0 + ky), color );
- }
- c += dy;
- x0 += kx;
- if( i != dy - 1 ) {
- tga_pixel_set( tga, (uint16_t)x0, (uint16_t)y0, color );
- }
- }
- }
- }
- }
- void tga_circle_filled( tga_t* tga, int x0, int y0, int radius, color_t color ) {
- int x, y, x_change, y_change, radius_error, i;
- if( !tga ) return;
- x = radius;
- y = 0;
- x_change = 1 - ( radius << 1 );
- y_change = 0;
- radius_error = 0;
- while( x >= y ) {
- for( i = x0 - x; i <= x0 + x; i++ ) {
- tga_pixel_set( tga, i, y0 + y, color );
- tga_pixel_set( tga, i, y0 - y, color );
- }
- for( i = x0 - y; i <= x0 + y; i++ ) {
- tga_pixel_set( tga, i, y0 + x, color );
- tga_pixel_set( tga, i, y0 - x, color );
- }
- y++;
- radius_error += y_change;
- y_change += 2;
- if( ( ( radius_error << 1 ) + x_change ) > 0 ) {
- x--;
- radius_error += x_change;
- x_change += 2;
- }
- }
- }
- void tga_circle( tga_t* tga, int x0, int y0, int radius, color_t color ) {
- int x, y, x_change, y_change, radius_error;
- if( !tga ) return;
- x = radius;
- y = 0;
- x_change = 1 - ( radius << 1 );
- y_change = 0;
- radius_error = 0;
- while( x >= y ) {
- tga_pixel_set( tga, x0 + x, y0 + y, color );
- tga_pixel_set( tga, x0 + x, y0 - y, color );
- tga_pixel_set( tga, x0 - x, y0 + y, color );
- tga_pixel_set( tga, x0 - x, y0 - y, color );
- tga_pixel_set( tga, x0 + y, y0 + x, color );
- tga_pixel_set( tga, x0 + y, y0 - x, color );
- tga_pixel_set( tga, x0 - y, y0 + x, color );
- tga_pixel_set( tga, x0 - y, y0 - x, color );
- y++;
- radius_error += y_change;
- y_change += 2;
- if( ( ( radius_error << 1 ) + x_change ) > 0 ) {
- x--;
- radius_error += x_change;
- x_change += 2;
- }
- }
- }
- #define _min( n1, n2 ) ( (n1) < (n2) ? (n1) : (n2) )
- #define _max( n1, n2 ) ( (n1) > (n2) ? (n1) : (n2) )
- // dest rect does not use w or h for anything
- int tga_blit( tga_t* source, tga_t* dest, tga_rect_t rect_src, tga_rect_t rect_dest ) {
- uint16_t x, y, w, h;
- if( source == NULL ) return -1;
- if( dest == NULL ) return -2;
- x = y = 0;
- w = rect_src.w; // size only matters for source rect
- h = rect_src.h;
- for( y = 0; y < h; ++y ) {
- for( x = 0; x < w; ++x ) {
- uint16_t inx, iny, outx, outy;
- color_t c;
- inx = x + (uint16_t)(rect_src.x);
- iny = y + (uint16_t)(rect_src.y);
- outx = x + (uint16_t)(rect_dest.x);
- outy = y + (uint16_t)(rect_dest.y);
- c = tga_pixel_get( source, inx, iny );
- tga_pixel_set( dest, outx, outy, c );
- }
- }
- return 0;
- }
- int tga_blit_simple( tga_t* source, tga_t* dest, int dest_x, int dest_y ) {
- tga_rect_t rs, rd;
- if( !source ) return -1;
- if( !dest ) return -2;
- rs.w = source->w;
- rs.h = source->h;
- rs.x = 0;
- rs.y = 0;
- rd.x = dest_x;
- rd.y = dest_y;
- return tga_blit( source, dest, rs, rd );
- }
- int tga_blit_simple_fast( tga_t* source, tga_t* dest ) {
- // the goal here is to be stupid-fast
- // but it only does 1 thing
- uint8_t* px_offset_dest;
- uint8_t* px_offset_source;
- int y, h, source_pitch, dest_pitch;
- if( !source || !dest ) return -1;
- if( source->w > dest->w ) return -2;
- if( source->bpp != dest->bpp ) return -3;
- h = ( dest->h > source->h ) ? source->h : dest->h;
- px_offset_dest = dest->pixels;
- px_offset_source = source->pixels;
- source_pitch = source->w * ( source->bpp >> 3 );
- dest_pitch = dest->w * ( source->bpp >> 3 );
- for( y = 0; y < h; ++y ) {
- memcpy( px_offset_dest, px_offset_source, source_pitch );
- px_offset_dest += dest_pitch;
- px_offset_source += source_pitch;
- }
- return 0;
- }
- void tga_copy( tga_t* source, tga_t* dest ) {
- uint16_t x, y, w, h;
- if( !source || !dest ) return;
- w = _min( source->w, dest->w );
- h = _min( source->h, dest->h );
- for( y = 0; y < h; ++y )
- for( x = 0; x < w; ++x )
- tga_pixel_set( dest, x, y, tga_pixel_get( source, x, y ) );
- }
- int tga_rect_fill( tga_t* img, tga_rect_t rect, color_t c ) {
- int32_t x, y;
- if( !img ) return -1;
- if( rect.w == 0 || rect.h == 0 ) return 0;
- for( y = rect.y; y < (rect.h + rect.y); ++y )
- for( x = rect.x; x < (rect.w + rect.x); ++x ) {
- tga_pixel_set( img, x, y, c );
- }
- return 0;
- }
- int tga_fill( tga_t* img, color_t c ) {
- uint32_t x, y;
- if( !img ) return -1;
- if( !img->pixels ) return -1;
- for( y = 0; y < img->h; ++y ) {
- for( x = 0; x < img->w; ++x ) {
- tga_pixel_set( img, x, y, c );
- }
- }
- return 0;
- }
- int tga_fill8( tga_t* img, uint8_t c ) {
- uint64_t len;
- if( !img ) return -1;
- if( img->bpp != 8 ) return -2;
- len = img->w; len *= img->h;
- memset( img->pixels, c, len );
- return 0;
- }
- void tga_vflip( tga_t* t ) {
- tga_t* temp;
- if( !t ) return;
- if( t->h < 2 ) return;
- temp = tga_new_formatted( 0, 0, t );
- if( !temp ) return;
- temp->inverted = 0;
- tga_copy( t, temp );
- free( t->pixels );
- t->pixels = temp->pixels;
- temp->ext_pixels = 1;
- temp = tga_free( temp );
- t->inverted = 0;
- #if __TGAH_verbose
- fputs( "Flipped TGA\n", stdout );
- #endif
- }
- tga_t* tga_load( char* fname ) {
- tga_t* t; FILE* fp; uint64_t len;
- uint16_t w, h, x, y; uint8_t bpp, pixelformat; uint8_t inverted;
- //_Bool tga_is_color;
- _Bool FU; // TGA format unsupported
- if(fname == NULL) return NULL;
- fp = fopen(fname, "rb");
- if(fp == NULL) {
- printf("The file %s does not exist\n", fname);
- return NULL;
- }
- fseek(fp, 0x2 ,SEEK_SET);
- fread(&pixelformat, sizeof(uint8_t), 1, fp);
- fseek(fp, 0x8 ,SEEK_SET);
- fread(&x, sizeof(uint16_t), 1, fp);
- fseek(fp, 0xA ,SEEK_SET);
- fread(&y, sizeof(uint16_t), 1, fp);
- fseek(fp, 0xC ,SEEK_SET);
- fread(&w, sizeof(uint16_t), 1, fp);
- fseek(fp, 0xE ,SEEK_SET);
- fread(&h, sizeof(uint16_t), 1, fp);
- fseek(fp, 0x10 ,SEEK_SET);
- bpp = fgetc(fp);
- inverted = ( ~fgetc( fp ) >> 5 ) & 1;
- #if __TGAH_verbose
- printf("X%u Y%u W%u H%u BPP%u\n", x, y, w, h, bpp);
- #endif
- FU = 0;
- if( pixelformat == 2 ) { // color
- if( bpp != 24 && bpp != 32 ) {
- FU = 1;
- }
- //tga_is_color = 1;
- } else if( pixelformat == 3 ) { // grayscale
- if( bpp != 8 ) {
- FU = 1;
- }
- } else {
- FU = 1;
- }
- if( FU ) {
- fputs( "I don't support the format of this TGA!\n", stdout );
- fclose(fp);
- fflush(stdout);
- return NULL;
- }
- if( w == 0 || h == 0 ) {
- fclose( fp );
- fputs( "This TGA has zero pixels\n", stdout );
- fflush( stdout );
- return NULL;
- }
- len = w; len *= h;
- t = tga_new(w, h, bpp);
- if(t == NULL) {
- fclose(fp);
- printf("Could not create TGA from %s\n", fname);
- return NULL;
- }
- if(t->pixels == NULL) {
- free((void*)t);
- fclose(fp);
- return NULL;
- }
- t->ext_pixels = 0;
- switch( t->bpp ) {
- case 8: fread( t->pixels, 1U, len, fp ); break;
- case 24: fread( t->pixels, 3U, len, fp ); break;
- case 32: fread( t->pixels, 4U, len, fp ); break;
- default: break;
- }
- fclose(fp);
- t->inverted = inverted;
- // if( inverted ) tga_vflip( t );
- #if __TGAH_verbose
- printf("TGA Pixel buffer: %p\n", t->pixels);
- #endif
- t->refcount = 1;
- return t;
- }
- uint16_t fp_read_u16( FILE* fp ) {
- uint16_t r1, r2;
- if( !fp ) return 0;
- r1 = fgetc( fp ) & 255U;
- r2 = fgetc( fp ) & 255U;
- return ( r2 << 8 ) | r1;
- }
- tga_info_t tga_load_info( char* fname ) {
- FILE* fp;
- tga_info_t info;
- memset( &info, 0, sizeof(tga_info_t) );
- if( !fname ) return info;
- fp = fopen( fname, "rb" );
- if( !fp ) return info;
- fseek( fp, 2, SEEK_SET );
- info.pixel_type = fgetc( fp );
- fseek( fp, 8, SEEK_SET );
- info.rect.x = fp_read_u16( fp );
- info.rect.y = fp_read_u16( fp );
- info.rect.w = fp_read_u16( fp );
- info.rect.h = fp_read_u16( fp );
- info.bits_per_pixel = fgetc( fp );
- info.bits_per_alpha = fgetc( fp );
- fclose( fp ); fp = NULL;
- info.inverted = ( info.bits_per_alpha >> 5 ) & 1U;
- info.bits_per_alpha &= 15U;
- return info;
- }
- void tga_save( char* fname, tga_t* t ) {
- FILE* fp;
- uint8_t filler[ 8 ]; uint8_t bpa, pixel_type; uint64_t len;
- if( !t || !fname ) return;
- if( !t->pixels || t->w == 0 || t->h == 0 || (t->bpp != 24 && t->bpp != 32 && t->bpp != 8) ) return;
- {int i;for(i=0;i<8;++i)filler[i]=0;}
- fp = fopen( fname, "wb" );
- if( !fp ) return;
- // calculate the bits-per-alpha value/bitflag
- bpa = t->bpp; bpa -= 24; bpa &= 15; // yes this works with 8bpp
- bpa |= ( !t->inverted ) << 5;
- if( t->bpp == 24 || t->bpp == 32 ) pixel_type = 2; // color RGB
- if( t->bpp == 8 ) pixel_type = 3; // grayscale
- len = t->w; len *= t->h;
- fwrite( filler, 1, 2, fp ); // write two 0-bytes
- fputc( pixel_type, fp ); // pixel format
- // 5 0-bytes, and then 0 for the X origin
- fwrite( filler, 1, 7, fp );
- // write the Y-origin
- if( t->inverted ) fwrite( filler, 1, 2, fp );
- else fwrite( &(t->h), sizeof(uint16_t), 1, fp );
- // the image dimensions
- fwrite( &(t->w), sizeof(uint16_t), 1, fp );
- fwrite( &(t->h), sizeof(uint16_t), 1, fp );
- // more pixel format
- fputc( t->bpp, fp ); // bits per pixel
- fputc( bpa, fp ); // bits per alpha
- switch( t->bpp ) {
- case 8: fwrite( t->pixels, 1U, len, fp ); break;
- case 24: fwrite( t->pixels, 3U, len, fp ); break;
- case 32: fwrite( t->pixels, 4U, len, fp ); break;
- default: break;
- }
- fclose( fp );
- }
- void print_tga_info( tga_t* t ) {
- if( !t ) {
- fputs("TGA pointer is null\n", stdout);
- fflush(stdout);
- return;
- }
- fprintf(stdout, "TGA width: %u height: %u bits per pixel: %u references: %u\n",
- t->w, t->h, (uint16_t)t->bpp, (unsigned)t->refcount);
- fflush(stdout);
- }
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement