Jump to content
  • Advertisement
Sign in to follow this  
marcelloma

Pcx decoder and drawer problem

This topic is 3593 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everybody, I wrote a simple pcx decoder but it doesn't work as I expect so I hope you can help me find the bug(s). Each scanline of the image is decoded and stored in a 1-dimensional array img->pixels.The problem is that the image doesn't show up correctly, sometimes appearing half correctly half white, others totally messed up... Here is the code
#include <stdio.h>
#include "SDL/SDL.h"

#define BYTE unsigned char
#define TWOBYTES short int
#define SCREEN_WIDTH 400
#define SCREEN_HEIGTH 400
#define SCREEN_BPP 32

SDL_Surface *screen;
typedef struct
{
	SDL_Color palette[256];
	int w;
	int h;
	BYTE *pixels; /* indexes to palette array */
} sprite_t;

int PcxHeader(FILE *f,int *w, int *h, int *NPlanes, int *BytesPerLine)
{
	typedef struct
	{
		BYTE Manufacturer;
		BYTE Version;
		BYTE Encoding;
		BYTE BitsPerPixel;
		TWOBYTES XStart, YStart;
		TWOBYTES XEnd, YEnd;
		BYTE NotUsed1[52];
		BYTE Reserved;
		BYTE NPlanes;
		TWOBYTES BytesPerLine;
	} pcx_t;
	pcx_t H;

	/* Reads the header */
	fread(&H, sizeof(pcx_t), 1, f);

	/* Checks if image is ok */
	if (H.Manufacturer != 10	|| 
		H.Version != 5			||
		H.Encoding != 1			||
		H.BitsPerPixel != 8		||
		H.Reserved != 0
		)
		return 1;

	*w = H.XEnd - H.XStart + 1;
	*h = H.YEnd - H.YStart + 1;
	*NPlanes = H.NPlanes;
	*BytesPerLine = H.BytesPerLine;

	return 0;

}

int PcxPalette(FILE *f,SDL_Color *palette)
{
	int i;
	char c;
	/* Reads the 256 colors' palette located in the last 768 bytes of the file */
	if ((c = fgetc(f)) != 12)
	{
		printf("codice palette errato %d\n",c);
		return 1;
	}

	/* Writes the palette */
	for (i=0; i<256; i++)
	{
		palette.r = fgetc(f);
		palette.g = fgetc(f);
		palette.b = fgetc(f);
	}

	return 0;
}



int PcxScanLine(FILE *f, BYTE *buffer, int buffsize)
{
	BYTE c;
	static int runcount = 0; /* static, so we keep the value for the next scan lines */
	static int runvalue = 0;
	int decodedBytes = 0;

	while (decodedBytes < buffsize)
	{
		if (runcount == 0)
		{
			c = fgetc(f);

			if ((c & 0xC0) == 0xC0)
			{
				runcount = c & 0x3F;
				runvalue = fgetc(f);
			}
			else
			{
				runcount = 1;
				runvalue = c;
			}
		}

		for ( ; runcount && decodedBytes < buffsize; runcount--)
		{
			buffer[decodedBytes] = runvalue;
			decodedBytes++;
		}

	}


	return decodedBytes;
}


sprite_t *LoadPcx(char *filename)
{
	BYTE *scanLineBuffer;
	FILE *f,*fw;
	sprite_t *img;
	int i, j, TotalBytes, NPlanes, BytesPerLine;

	img = (sprite_t *)malloc(sizeof(sprite_t));
	if (img == NULL)
	{
		printf("Non c'è abbastanza memoria per allocare l'immagine\n");
		return NULL;
	}

	// Opening file
	f = fopen(filename, "r");
	if (f == NULL)
	{
		printf("Impossibile aprire il file\n");
		return NULL;
	}

	// Reads the header and stores img->w and img->h 
	if (PcxHeader(f,&img->w, &img->h,&NPlanes, &BytesPerLine) == 1)
	{
		printf("Errore nell'header del file\n");
		return NULL;
	}

	fseek(f, -769, SEEK_END);
	if (PcxPalette(f, img->palette) == 1)
	{
		printf("Errore nel trovare la palette\n");
		return NULL;
	}

	/* Back to the image */
	fseek(f,128,SEEK_SET);

	img->pixels = (BYTE *)malloc(img->w * img->h * sizeof(BYTE));



	TotalBytes = NPlanes * BytesPerLine; // always an even number

	printf("Totalbytes: %d\n", TotalBytes);

	scanLineBuffer = (BYTE *)malloc(TotalBytes * sizeof(BYTE));

	for (i=0; i<img->h; i++)
	{

		PcxScanLine(f, scanLineBuffer, TotalBytes);

		for (j=0; j<img->w; j++)
		{
			img->pixels[i * img->w + j] = scanLineBuffer[j];
		}
	}

	free(scanLineBuffer);

	fclose(f);
	return img;
}

void DrawPixel(int x, int y, SDL_Surface *surface, Uint8 r, Uint8 g, Uint8 b)
{
	Uint32 color;
	Uint32 *pixmem;

	color = SDL_MapRGB( surface->format, r, g, b );
	pixmem = (Uint32*)surface->pixels + x + SCREEN_WIDTH * y;
	SDL_LockSurface(surface);
	*pixmem = color;
	SDL_UnlockSurface(surface);
}

int main(int argc, char *argv[])
{
	int i;
	sprite_t *img = LoadPcx("Ship.pcx");
	if (img == NULL) exit(1);

	if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) exit(1); 
	screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGTH, SCREEN_BPP, SDL_SWSURFACE );

	printf("img w: %d\n", img->w);

	printf("img h: %d\n", img->h);
	
	for (i=0; i<img->w * img->h; i++)
	{
		DrawPixel(i % img->w, i / img->w, screen, img->palette[ img->pixels ].r,  img->palette[ img->pixels ].g, img->palette[ img->pixels ].b);
		//printf("%d\n",img->pixels);
	}
	
	SDL_Flip(screen);	
	SDL_Delay(100000000); // don't pay attention to it
	return 0;
}
hope you can help me thanks :)

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by David_pb
The indices have to be: img->palette[ img->pixels*3 ].r, ...

- Dave


the image had the palette so 1 bitplane..
But I solved the problem..I had to fopen the file in binary mode..not text mode even though I scan it char by char..

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!