Loading bmp's

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
Bash$
Posts: 1
Joined: Tue Nov 08, 2005 3:57 am

Loading bmp's

Post by Bash$ »

im a noob at c but i am trying to learn, and create my own game, i have a background image, but how can i get it to load in c? and how do i send it to the back so all the other stuff is over it?
User avatar
outtony
Posts: 26
Joined: Thu Oct 13, 2005 2:46 am
Location: Slovakia
Contact:

Post by outtony »

use
int fd = sceIoOpen(fn, PSP_O_RDONLY, 0777);
to load it from file, but you should do your own format

then, you should load it as texture and correctly init it. (see sdk samples)

then draw quad and place that texture on it. (sdk samples too)
-----------------------------
Tony

www.n3.sk
Krust
Posts: 1
Joined: Tue Nov 15, 2005 7:27 am

Post by Krust »

As you know, a bitmap is an array of pixel. Each pixel is coded depending the resolution (from 1 to 64bits ?).We usualy use 24 bits mode (1 byte for each color (RGB)) with the psp.
But a bmp file doesn't not just include the bit array, it conains a header too with the size, resolution,...
The quikest way is to transform the bitmap to a c-array that you'll include to your sc, then you've just to point to this array as a texture.
You can use PSPConv v1.03 by Mach-one to convert bmp to a c-array.

little exemple :

Code: Select all

#include "logo.h" // The bmp converted to c-array

sceGuTexMode(GU_PSM_4444,0,0,0); //24bit texture mode.
sceGuTexImage(0,128,128,128,logo_start);  //Bind the texutre, logo_start is the name of the array. 128's are the dimentions (128*128pixels).
sceGuTexFunc(GU_TFX_ADD,GU_TCC_RGB); //We use RGB mode.
BlackPhoenix
Posts: 4
Joined: Tue Dec 06, 2005 2:59 am

Prog search

Post by BlackPhoenix »

Please could you give me a link to this elusive programme : PSPConv v1.03?
I am looking for a quick and easy BMP to C-String converter and I have wasted hours looking and still can't find!

Thanks for any help!
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Re: Prog search

Post by Shine »

BlackPhoenix wrote:Please could you give me a link to this elusive programme : PSPConv v1.03?
I am looking for a quick and easy BMP to C-String converter and I have wasted hours looking and still can't find!
This is a waste of memory, if you have more than one image or a large image. Use libpng and a PNG image and include it with bin2c in your make process (see e.g. Lua Player how to use bin2c).

If you don't want to include libpng, e.g. if your image is small and compression has no advantage, take a look at this topic: http://forums.ps2dev.org/viewtopic.php?p=16360
tomy
Posts: 2
Joined: Fri Jun 24, 2005 8:23 pm
Location: Hungary
Contact:

Re: Prog search

Post by tomy »

BlackPhoenix wrote:Please could you give me a link to this elusive programme : PSPConv v1.03?
I am looking for a quick and easy BMP to C-String converter and I have wasted hours looking and still can't find!

Thanks for any help!
http://mach-one.uw.hu/download.php?file ... m1pspc.zip
BlackPhoenix
Posts: 4
Joined: Tue Dec 06, 2005 2:59 am

Post by BlackPhoenix »

Thanks for the links, maybe it will help other newbies find their way without hassling you ;) I used the bin2c example that comes with the pspsdk and converted it to a Win32 prog and used the cmd line to dump the results as I couldn't find an easy way of compiling the sdk example.. I think the sdk wasn't setup correctly on my laptop :p *continues research*
jsharrad
Posts: 100
Joined: Thu Oct 20, 2005 3:06 am

Re: Prog search

Post by jsharrad »

Shine wrote:This is a waste of memory, if you have more than one image or a large image. Use libpng and a PNG image and include it with bin2c in your make process (see e.g. Lua Player how to use bin2c).

If you don't want to include libpng, e.g. if your image is small and compression has no advantage, take a look at this topic: http://forums.ps2dev.org/viewtopic.php?p=16360
I'm having this problem with something I'm working on... at the moment I am using raw images and including them in my eboot. I'd still like to leave the images in there, but is there an easy way of compressing them and loading the compressed versions? my eboot file is up to like 3mb but if I zip it, it's only about 50k.
kazlivsjy
Posts: 6
Joined: Sun Dec 25, 2005 2:24 am
Location: PSPain
Contact:

Post by kazlivsjy »

If this is of any help, I've written a simple BMP file loader which loads a .BMP file into memory from disk. OK, why use BMP when you can use PNG? Anyway, I'll post it here for educational purposes; bear in mind that BMP format is quite simple and can be convenient in case you don't have a library for handling any other image types. BMP files discussed here are: Windows Format, 32 bpp and reverse-scanline (you can set all these options from Photoshop when you save an image as BMP). With this, the fileformat is simplistic: at offset 0x12 you have the image with (32 bit); at offset 0x16 you get the image height (32 bits). It sometimes (!?) comes NEGATIVE, don't know why; at offset 0x36 you get the pixel data, and that's all (only thing to bear in mind: red and blue components must be reversed)

This function loads a BMP file from disk into a statically allocated buffer in memory:

int too_big(w, h) { // function for checking if a image is 'weirdly too big'
// just to prevent overflows (imagine the file you're
// loading is not even a BMP)

if((w*h)>(1024*1024)) return 1; // max size arbitrarily set to
// 1024 x 1024
else return 0;

}


// pixelsize is the size, in bytes, of each pixel (4 in case of RGBA8888)
// wb and hb are pointers to variables that will be set to the width and
// height of the image
// pixeldatalines is an array of pointers which point to the start addresses
// of every horizontal line in the statically allocated image buffer
//
// returns non-null value on success

void *loadBitmapFile_noMalloc(char *filename, int pixelsize, int *wb, int *hb, char **pixeldatalines) {

SceUID myFile;
int w = 0, h = 0;
int i, j, temp;

myFile = sceIoOpen(filename, IOASSIGN_RDONLY, 0777);
if(!myFile) {

//pspDebugScreenPrintf("Error loading file %s", filename);
return NULL;
}

sceIoLseek(myFile, 0x12, SEEK_SET);
sceIoRead(myFile, &w, 4);
sceIoLseek(myFile, 0x16, SEEK_SET);
sceIoRead(myFile, &h, 4);

if(h<0) h = -h;
if(w<0) w = -w;

if(too_big(w, h)) return NULL;

*hb = h;
*wb = w;

//pspDebugScreenPrintf("File: %s Width: %d Height: %d", filename, w, h);

sceIoLseek(myFile, 0x36, SEEK_SET);
for(i=0; i<h; ++i) {

sceIoRead(myFile, pixeldatalines, pixelsize*w);

}

for(i=0; i<h; ++i) { // reverse red and blue components

for(j=0; j<w; ++j) {

temp = pixeldatalines[j*pixelsize];
pixeldatalines[j*pixelsize] = pixeldatalines[j*pixelsize+2];
pixeldatalines[j*pixelsize+2] = temp;

}

}

sceIoClose(myFile);

return (void *)0xDEADBEEF; // ignore

}
void printSignature(void) {

printf("Brought to you by Kazlivsjy\n");

}
jubber
Posts: 6
Joined: Thu Jan 19, 2006 5:14 pm

nice bit of code

Post by jubber »

Just a quick thickie question - if I ask this function to load a 16 bit bitmap, will it still work (I haven't got display of bitmaps up and running yet, so tricky to test) - I ask because a section of the code flips red and blue parts, and looks to my untrained eye as if it may be hard coded for 32 bit textures.

Either way - thanks for putting this piece of code up. If I can get basic 2D blitting working with this and Blit from the pspsdk samples it would make for a nice easy to follow example for those slightly naff c coders like me who just want to start writing 2d games and apps.

Cheers,

Robin Jubber
User avatar
Stellar
Posts: 48
Joined: Mon Dec 12, 2005 9:13 am

Post by Stellar »

I dunno about 16 bit bmp yet (im sure its the same). but for 32bit you have to flip red and blue components.

also, i know its been posted, but heres my source using stdio's fopen/fclose/fread.... of course it needs changes for 16 bit loading.

Code: Select all

typedef struct  
&#123; 
	unsigned long nWidth; 
	unsigned long nHeight; 
	unsigned long nStride;
	unsigned long nSize;
	unsigned char *pData;
&#125; ImageBmp32;

Code: Select all

void ImageLoadBmp32&#40;
	char *filename,
	ImageBmp32 **pImage
&#41; 
&#123; 
	FILE *file; 
	FILE *fpLog;
	unsigned short nBpp;
	unsigned short nPlanes;

	file  = fopen&#40; filename, "rb"&#41;;

#if 1
	fpLog = stdout;
#else
	fpLog = fopen&#40; "image.txt", "a" &#41;;
#endif

	if &#40; file == NULL &#41; 
	&#123;
		goto FN_EXIT;
	&#125;

	if &#40; fpLog == NULL &#41;
	&#123;
		goto FN_EXIT;
	&#125;

	fprintf&#40; fpLog, "Loading Texture &#91;%s&#93;\n", filename &#41;;

	*pImage = &#40;ImageBmp32*&#41; calloc&#40; sizeof&#40; ImageBmp32 &#41;, 1 &#41;;

	if &#40; *pImage == NULL &#41;
	&#123;
		fprintf&#40; fpLog, "  Failed to allocate &#91;ImageBmp32&#93;\n" &#41;;
		goto FN_EXIT;
	&#125;
	
	if &#40; 0 != fseek&#40; file, 18, SEEK_CUR &#41; &#41;
	&#123;
		fprintf&#40; fpLog, "  Failed to fseek 18\n" &#41;;
		goto FN_EXIT;
	&#125;
	
	if &#40; 1 != fread&#40; &&#40;*pImage&#41;->nWidth, sizeof&#40; unsigned long &#41;, 1, file &#41; &#41;
	&#123;
		fprintf&#40; fpLog, "  Failed to read width\n" &#41;;
		goto FN_EXIT;
	&#125;

	&#40;*pImage&#41;->nStride = &#40;*pImage&#41;->nWidth;

	if &#40; 1 != fread&#40;&&#40;&#40;*pImage&#41;&#41;->nHeight, 4, 1, file&#41; &#41;
	&#123;
		fprintf&#40; fpLog, "  Failed to read height\n" &#41;;
		goto FN_EXIT;
	&#125;

	&#40;*pImage&#41;->nSize = &#40;*pImage&#41;->nWidth * &#40;*pImage&#41;->nHeight * 4; // 4 bytes per pixel XRGB

	if &#40; 1 != fread&#40;&nPlanes, 2, 1, file &#41; &#41;
	&#123;
		fprintf&#40; fpLog, "  Failed to read planes\n" &#41;;
		goto FN_EXIT;
	&#125;

	if &#40; 1 != fread&#40; &nBpp, 2, 1, file &#41; &#41;
	&#123;
		fprintf&#40; fpLog, "  Failed to read bpp\n" &#41;;
		goto FN_EXIT;
	&#125;

	if &#40; nBpp != 32 &#41;
	&#123;
		fprintf&#40; fpLog, "  Failed &#58; BPP != 32\n" &#41;;
		goto FN_EXIT;
	&#125;

	if &#40; nPlanes != 1 &#41;
	&#123;
		fprintf&#40; fpLog, "  Failed &#58; Planes != 1\n" &#41;;
		goto FN_EXIT;
	&#125;

	if &#40; 0 != fseek&#40; file, 24, SEEK_CUR &#41; &#41;
	&#123;
		fprintf&#40; fpLog, "  Failed to FSEEK 24\n" &#41;;
		goto FN_EXIT;
	&#125;

	// allocate for image pixels
	&#40;*pImage&#41;->pData = &#40; unsigned char * &#41; memalign&#40; 16, &#40;*pImage&#41;->nSize &#41;; // 

	if &#40; &#40;*pImage&#41;->pData == NULL &#41;
	&#123;
		fprintf&#40; fpLog, "  Failed to allocate &#40;%u&#41; for pixels\n", &#40;*pImage&#41;->nSize &#41;;
		goto FN_EXIT;
	&#125;

	// read image
	if &#40; 1 != fread&#40; &#40;*pImage&#41;->pData, &#40;*pImage&#41;->nSize, 1, file &#41; &#41;
	&#123;
		fprintf&#40; fpLog, "  Failed to read pixels\n" &#41;;
		goto FN_EXIT;
	&#125;

	// reorder the bytes into correct format ///////////
	for &#40; unsigned int i = 0; i < &#40;*pImage&#41;->nSize; i += 4 &#41;
	&#123;
		unsigned char xrgb&#91;4&#93;;

		memset&#40; xrgb, 0, sizeof&#40; unsigned char &#41; * 4 &#41;;

		// swap red and blue
		// pData -> R G B A
		// BMP   -> B G R A
		xrgb&#91;0&#93; = &#40;*pImage&#41;->pData&#91;i + 2&#93;; // DATA&#91;0&#93; = BMP&#91;2&#93; = red
		xrgb&#91;1&#93; = &#40;*pImage&#41;->pData&#91;i + 1&#93;; // green
 		xrgb&#91;2&#93; = &#40;*pImage&#41;->pData&#91;i + 0&#93;; // DATA&#91;2&#93; = BMP&#91;0&#93; = blue
		xrgb&#91;3&#93; = &#40;*pImage&#41;->pData&#91;i + 3&#93;; // alpha

		memcpy&#40; &&#40;*pImage&#41;->pData&#91;i&#93;, xrgb, sizeof&#40; char &#41; * 4 &#41;;
    &#125;

	fprintf&#40; fpLog, "  Texture Loaded\n" &#41;;

FN_EXIT &#58;
	if &#40; file != NULL &#41;
	&#123;
		fclose&#40; file &#41;;
	&#125;

	if &#40; fpLog != NULL &#41;
	&#123;
		fclose&#40; fpLog &#41;;
	&#125;
&#125;
Image
jubber
Posts: 6
Joined: Thu Jan 19, 2006 5:14 pm

Post by jubber »

thanks for the info

quick question - in 16bpp mode, as used in the Blit example code in pspsdk, the texture is sitting in ram then it is used as a texture on a poly to display. My question is this - what is the bit arrangement for the shorts in the texture (array in ram)? is it 1555 (ie ARGB or ABGR) as it seems to be if I write to it directly, or is it 5551, the value that turns up in the gu #defines. Or even 565? I'm getting some weird results. Targa files store 16 bit value 1555 so a shift left *should* be sufficient to get it to display, albeit with a chance of red and blue being swapped.
User avatar
Raphael
Posts: 646
Joined: Tue Jan 17, 2006 4:54 pm
Location: Germany
Contact:

Post by Raphael »

kazlivsjy:
With this, the fileformat is simplistic: at offset 0x12 you have the image with (32 bit); at offset 0x16 you get the image height (32 bits). It sometimes (!?) comes NEGATIVE, don't know why;
A negative height in the BMP Header indicates a bottom-top ordered image, rather than a reverse (top-bottom) ordered.

jubber:
ust a quick thickie question - if I ask this function to load a 16 bit bitmap, will it still work (I haven't got display of bitmaps up and running yet, so tricky to test) - I ask because a section of the code flips red and blue parts, and looks to my untrained eye as if it may be hard coded for 32 bit textures.
There isn't such a thing as a 16Bit BMP, even though it would theoretically be supported by the file format. At least I've never seen any 16Bit BMP, only 24 and 8/4Bit with CLUT or monochrome. You can however read a 24Bit BMP and convert it to a 16Bit image, it's not really hard.


Here's some code snips I used on PC to load BMP files of 24 and 8Bit:
First the header definitions:
#ifndef BMPLOAD__H
#define BMPLOAD__H

#ifndef BI_RGB
#define BI_RGB 0; // No Compression/Raw RGB Data
#endif
#ifndef BI_RLE8
#define BI_RLE8 1; // RLE 8 Bpp Compression / 256 Colors
#endif
#ifndef BI_RLE4
#define BI_RLE4 2; // RLE 4 Bpp Compression / 16 Colors
#endif

#define BYTE unsigned char
#define WORD unsigned short
#define DWORD unsigned long

typedef struct {
WORD bfType; // Signature ID 'BM'
DWORD bfSize; // Bytes Per Pixel in Bitmapdata (?)
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits; // Offset to Bitmap data
} BMPFILEHEADER;

typedef struct {
BYTE b;
BYTE g;
BYTE r;
BYTE a;
} BMPRGBQUAD;

typedef struct {
BYTE b;
BYTE g;
BYTE r;
} BMPRGBTRIPLE;

typedef struct {
DWORD biSize; // Size of the Info Header Structure
LONG biWidth; // Width of the Image
LONG biHeight; // Height of the Image
WORD biPlanes; // Number of Planes
WORD biBitCount; // Bits Per Pixel
DWORD biCompression; // Compression Type RGB/RLE
DWORD biSizeImage; // Image Size
LONG biXpelspmetre; // ???
LONG biYpelspmetre; // ?WTF?
DWORD biClrUsed; // Number of Used Colors In Palette (Size of Palette)
DWORD biClrImportant; // ??
} BMPINFOHEADER;

#endif
Here the important part of the loader:
FILE *f = fopen( name, "rb" );
if (f==NULL) return false;

BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;

unsigned char* tdata = NULL;
RGBQUAD pal[256];

ZeroMemory( &bfh, sizeof(BITMAPFILEHEADER) );
ZeroMemory( &bih, sizeof(BITMAPINFOHEADER) );

fread( &bfh, 1, sizeof(BITMAPFILEHEADER), f );
fseek( f, 14, 0 );
fread( &bih, 1, sizeof(BITMAPINFOHEADER), f );
fseek( f, 54, 0 );
// Check for File Format and Compression
if ( ( bih.biPlanes != 1 ) ||
( bih.biCompression != BI_RGB) ||
( bih.biBitCount < 8) ||
( bfh.bfType != 0x4d42 ) )
{
fclose( f );
return false;
}

mwidth = bih.biWidth;
mheight = bih.biHeight;

if (mheight<0) mheight=-mheight;

int bytesperline = ( (bih.biWidth * bih.biBitCount + 31) >> 5 ) << 2;

if ( ( bih.biClrUsed == 0 ) &&
( bih.biBitCount == 8 ) )
bih.biClrUsed = 256;

int fp = 54;
if ( bih.biClrUsed>0 ) {
fread( &pal, sizeof(RGBQUAD), bih.biClrUsed, f );
fp += bih.biClrUsed*sizeof(RGBQUAD);
fseek( f, fp, 0 );
}

pdata = (unsigned char*) malloc( mheight * bytesperline );
if (pdata==NULL)
{
fclose( f );
return FALSE;
}

if ( bih.biHeight < 0 )
{
for ( int i = 0; i < -bih.biHeight; i++ ) {
fread( pdata+i*bytesperline, 1, bytesperline, f );
fp += bytesperline;
fseek( f, fp, 0 );
}
} else {
for ( int i = bih.biHeight - 1; i >= 0; i--) {
fread( (pdata+i*bytesperline), 1, bytesperline, f );
fp += bytesperline;
fseek( f, fp, 0 );
}
}
This code should also load 32Bit BMP correctly, although I didn't see such a bmp yet. However, after this there's still left to reorder the given BGR data to RGB.

From there it's easy to convert the given data to any possible format, like RGB565 or RGB888. In my case I also added options to the function to generate alpha values from r,g,b or (r+g+b)/3 to generate also formats like RGBA5551 or RGBA4444 etc or just generate a lumi/alpha image from it.
I did equal loaders for TGA (with/without RLE) and also DXT compressed DDS files, but these are a bit messier (esp the DDS one).

It's a lot of work to get such flexible loaders working, but it's worth it as you can use the code in later projects without changes :)
Post Reply