Image Scaling Algorithm with pg.c/.h?

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

Moderators: cheriff, TyRaNiD

Post Reply
seventoes
Posts: 79
Joined: Sun Oct 02, 2005 4:50 am

Image Scaling Algorithm with pg.c/.h?

Post by seventoes »

Hey im back with another algorithm problem xD

This time i need something to scale the 16 bit image. I have absolutely no idea how to do this... and i've tried using google but cant seem to get any good results.

I am using pc.c/.h to blit my pictures (I would use the GU but i dont get it..) and i have already added alpha blending as an extra argument. Heres my function right now:

Code: Select all

#define rgb2col&#40;r, g, b&#41; &#40;&#40;&#40;&#40;b>>3&#41; & 0x1F&#41;<<10&#41;+&#40;&#40;&#40;g>>3&#41; & 0x1F&#41;<<5&#41;+&#40;&#40;&#40;r>>3&#41; & 0x1F&#41;<<0&#41;+0x8000&#41;
#define getR&#40; c &#41; &#40; &#40;c & 0x1f&#41; << 3 &#41;
#define getG&#40; c &#41; &#40; &#40;&#40;c >> 5&#41; & 0x1f &#41; << 3 &#41;
#define getB&#40; c &#41; &#40; &#40;&#40;c >> 10&#41; & 0x1f&#41; << 3 &#41;

...

void pgBitBlt&#40;unsigned long x,unsigned long y,unsigned long w,unsigned long h,unsigned long mag,const unsigned short *d, int t&#41;
&#123;
	unsigned char *vptr0;		//pointer to vram
	unsigned char *vptr;		//pointer to vram
	unsigned long xx,yy,mx,my;
	const unsigned short *dd;
	int rB, gB, bB, rS, gS, bS, new_r, new_g, new_b; //color thingys
        
	vptr0=&#40;unsigned&#41;pgGetVramAddr&#40;x,y&#41;;
	for &#40;yy=0; yy<h; yy++&#41; &#123;
		for &#40;my=0; my<mag; my++&#41; &#123;
			vptr=vptr0;
			dd=d;
			for &#40;xx=0; xx<w; xx++&#41; &#123;
                            for &#40;mx=0; mx<mag; mx++&#41; &#123;
                                if &#40;*dd != 0x3e0&#41; &#123;
                                    if &#40;t != 255&#41; &#123;
                                            rB = getR&#40;*&#40;unsigned short *&#41;vptr&#41;;
                                            gB = getG&#40;*&#40;unsigned short *&#41;vptr&#41;;
                                            bB = getB&#40;*&#40;unsigned short *&#41;vptr&#41;;
                                            
                                            rS = getR&#40;*dd&#41;;
                                            gS = getG&#40;*dd&#41;;
                                            bS = getB&#40;*dd&#41;;
                                            
                                            new_r = rB + &#40;&#40;&#40;rS - rB&#41; * t&#41; / 256&#41;;
                                            new_g = gB + &#40;&#40;&#40;gS - gB&#41; * t&#41; / 256&#41;;
                                            new_b = bB + &#40;&#40;&#40;bS - bB&#41; * t&#41; / 256&#41;;
                                            
                                            
                                            *&#40;unsigned short *&#41;vptr = rgb2col&#40;new_r,new_g,new_b&#41;;
                                        &#125;
                                        else &#123;
                                            *&#40;unsigned short *&#41;vptr = *dd;
                                        &#125;
                                    &#125;
                                    vptr+=PIXELSIZE*2;
				&#125;
				dd++;
			&#125;
			vptr0+=LINESIZE*2;
		&#125;
		d+=w;
	&#125;
	
&#125;
How could i add a scaling factor to the function?
Brunni
Posts: 186
Joined: Sat Oct 08, 2005 10:27 pm

Post by Brunni »

Speaking about algorithm only, scaling is very simple. In 32 bits without conversion it would look like this:
spr: sprite (32-bit pixels)
vptr: vram (32-bit pixels, LARG_BUF is buffer line width, LARG=width, HAUT=height)
x0, y0: drawing coordinates
lb, hb: base width (l), height (h)
l, h: new width and height
I've not tested it, but this gives you an idea.

Code: Select all

#define VIRGULE 16

void Rescale&#40;unsigned short *spr, unsigned short *vptr, int x0, int y0, int lb, int hb, int l, int h&#41;		&#123;
	int x, y;
	unsigned short *bits=vptr, *ptr, *spr2, *sprite;
	int y_min, x_min, y_max, x_max;
	long scaleX, scaleY, dstX, dstY;
	int x1=x0+l, y1=y0+h;

	//Clipping
	if &#40;x0>=0&#41;			x_min=x0;
	else				x_min=0;
	if &#40;y0>=0&#41;			y_min=y0;
	else				y_min=0;
	if &#40;x1<LARG&#41;			x_max=x1;
	else				x_max=LARG;
	if &#40;y1<HAUT&#41;			y_max=y1;
	else				y_max=HAUT;
	scaleX=&#40;lb<<VIRGULE&#41;/l;
	scaleY=&#40;hb<<VIRGULE&#41;/h;
	dstY=scaleY*&#40;y_min-y0&#41;;

	for &#40;y=y_min;y<y_max;y++&#41;	&#123;
		ptr=bits+LARG_BUF*y+x_min;
		spr2=spr+lb*&#40;dstY>>VIRGULE&#41;;
		dstX=scaleX*&#40;x_min-x0&#41;;
		dstY+=scaleY;

		for &#40;x=x_min;x<x_max;x++&#41;	&#123;
			sprite=spr2+&#40;dstX>>VIRGULE&#41;;
			dstX+=scaleX;
			if &#40;*sprite==COLOR_TRANSPARENT&#41;		&#123;
				sprite++;
				ptr++;
				continue;
			&#125;
			*ptr++=*sprite++;
		&#125;
	&#125;
&#125;
Last edited by Brunni on Sun Dec 04, 2005 9:20 am, edited 2 times in total.
Sorry for my bad english
Image Oldschool library for PSP - PC version released
urchin
Posts: 121
Joined: Thu Jun 02, 2005 5:41 pm

Post by urchin »

Take a look at the sprites example in the SDK. Blitting and scaling a rect using GU is very easy. You get the option of filtering too.
seventoes
Posts: 79
Joined: Sun Oct 02, 2005 4:50 am

Post by seventoes »

That might work, but what are LARG and HAUT? And would that work with 16 bit images? because thats what im using.
Brunni
Posts: 186
Joined: Sat Oct 08, 2005 10:27 pm

Post by Brunni »

I changed the routine in my last post. With this one, it might work in 16-bit mode. LARG is the width of your sprite, and HAUT the height.
Typical 2x scaling for a 16x16 sprite on a 480x272 buffer (buffer width aligned to 512):
#define LARG 480
#define HAUT 272
#define LARG_BUF 512
Rescale(mysprite, myvideobuffer, 0, 0, 16, 16, 32, 32);
Sorry for my bad english
Image Oldschool library for PSP - PC version released
seventoes
Posts: 79
Joined: Sun Oct 02, 2005 4:50 am

Post by seventoes »

urchin wrote:Take a look at the sprites example in the SDK. Blitting and scaling a rect using GU is very easy. You get the option of filtering too.
I've tried that, but i just dont get it. If someone could write a SIMPLE example, maybe functions like gu_init(); or something...
I changed the routine in my last post. With this one, it might work in 16-bit mode. LARG is the width of your sprite, and HAUT the height.
Typical 2x scaling for a 16x16 sprite on a 480x272 buffer (buffer width aligned to 512):
#define LARG 480
#define HAUT 272
#define LARG_BUF 512
Rescale(mysprite, myvideobuffer, 0, 0, 16, 16, 32, 32);
Thanks, im trying that now.
dr_watson
Posts: 42
Joined: Mon Nov 28, 2005 11:30 am

Post by dr_watson »

Grab a copy of my little 2D game engine JGE (together with a small demo) and have a look of the related Gfx_RenderQuad() function. It uses Gu library for image rendering.

Engine source

And firmware 1.50 binary:

(You also need libpng and mikmodlib to build)

I'm still cleaning up the code and will do a "formal" posting at this forum soon, but at the meantime, you can check out the source and hope it can give you some hints :)
seventoes
Posts: 79
Joined: Sun Oct 02, 2005 4:50 am

Post by seventoes »

Thanks! The function worked brunni!

Ill take a look at your JGE thingy when i get home, im at school now.
dr_watson
Posts: 42
Joined: Mon Nov 28, 2005 11:30 am

Post by dr_watson »

You may like to grab the JGE source from here again, together with the source code of a game prototype (StarBugz) as well.
http://forums.ps2dev.org/viewtopic.php?t=4286
seventoes
Posts: 79
Joined: Sun Oct 02, 2005 4:50 am

Post by seventoes »

Thanks for the engine watson. I dont really understand C++, but ill try and work with it.
rinco
Posts: 255
Joined: Fri Jan 21, 2005 2:12 pm
Location: Canberra, Australia

Post by rinco »

SDL_rotozoom.c (part of SDL_gfx) can also stretch (and rotate). Currently it does not use any Gu functions, but it might one day.
Post Reply