Page 1 of 1

Magnifying glass effect

Posted: Sun Dec 27, 2009 9:49 pm
by Quipeace
Hey all,

First of all, it's my first post here and I just started using libnds after playing around with PAlib. (PAlib is nice, but I like challenges). I've done little more than playing around with the framebuffer and 16bit backgrounds, but I don't mind looking things up so you don't have to treat me like a moron :)

What I'm trying to do, is magnify the bottom screen by two and show that image on the top screen.
Now I've been thinking about this for a while, and I think I know how I want to do it. I just can't seem to translate my thoughts to code.

On the bottom screen there's a 16 bit, 256*256 background with priority 3 (on vram C). I've got the top screen in framebuffer mode.

What I think I need to do is somehow grab the state of a pixel on the bottom screen, figure out where that has to go on the top screen and write it to vram_a.
I'm stuck on the grabbing-pixel part. In palib I'd use the getbgpixel function (or something like that) to get the color and then write that color to the top screen.

Could anyone point me in the right direction?

Re: Magnifying glass effect

Posted: Sun Dec 27, 2009 10:03 pm
by StevenH
Look at the double buffer example in your devkitPro install path, it shows you how to draw on the top screen, using the same techniques you can also access the bottom screen. You just need to change the function to get the graphics pointer from the top screen to the sub screen (IIRC it's bgGetSubGfxPtr() or bgGetGfxPtrSub() ).

Re: Magnifying glass effect

Posted: Sun Dec 27, 2009 10:08 pm
by Quipeace
Well, believe it or not, it worked :lol:, I've now got a 1 to 1 copy of the bottom screen on the top screen. actually zooming in shouldn't be too hard :), just copy a single pixel to four pixels on the top screen :)

Re: Magnifying glass effect

Posted: Sun Dec 27, 2009 11:27 pm
by StevenH
Do a search for fast integer scaling, that way you can add variable zoom levels.

Re: Magnifying glass effect

Posted: Mon Dec 28, 2009 6:37 pm
by Quipeace
Hey,

Now the magnifying stuff is working pretty well (although I can't find the integer scaling stuff you were talking about).

However I ran into a minor problem. What I'm trying to achieve is a perfect copy of the pixels on the bottom screen. However, what I've got now does not grab the text printed with printf, just from one particular layer (I think).

How would I get the actual image from the screen? (Like in an image editor, you've got multiple layers, but you can then merge them to get one layer)

If it can't be done I'll do something completely different but it would be nice to get it working :)

Thanks for your time.

EDIT: My code:

Code: Select all

void ShowTopScreen(int x1, int y1, int x2, int y2)
{
	int xp = x1;
	int topx = 0;
	int topy = 0;

	while(y1<y2)
	{
		x1 = xp;
		while(x1<x2)
		{
			VRAM_A[topx   + (topy)   * SCREEN_WIDTH] = SubBuffer[x1 + y1 * SCREEN_WIDTH];
			VRAM_A[topx   + (topy+1) * SCREEN_WIDTH] = SubBuffer[x1 + y1 * SCREEN_WIDTH];
			VRAM_A[topx+1 + (topy)   * SCREEN_WIDTH] = SubBuffer[x1 + y1 * SCREEN_WIDTH];
			VRAM_A[topx+1 + (topy+1) * SCREEN_WIDTH] = SubBuffer[x1 + y1 * SCREEN_WIDTH];
			x1++;
			topx+=2;
		}
		y1++;
		topy+=1;
	}
}

Re: Magnifying glass effect

Posted: Thu Dec 31, 2009 12:20 am
by StevenH
Unfortunately I don't know of any way to do what you want in code, but I may have an idea that you could try.

Use the hardware to do your scaling. Basically what you would have to do is copy the layers from the source screen to the destination screen one, and set the scaling on the destination screen. Since there are some registers and layer types that can do scaling this may well be able to do what you want.

Oh and a link to the scaling I was on about before - Quick image scaling

Re: Magnifying glass effect

Posted: Thu Dec 31, 2009 12:49 am
by WinterMute
You can use the video capture hardware to get a merged image, have a look at the screenshot demo in the nds examples.

Re: Magnifying glass effect

Posted: Sat Apr 17, 2010 3:45 am
by relminator
Sorry if this is a pretty old topic but I've made a lens effect last night. (new to DS coding)

Arrows to move
L/R to change radius.

Code: Select all

/*
lens effect
relsoft
http://rel.betterwebber.com

*/

#include <nds.h>
#include <stdio.h>
#include <math.h>
#include <string.h>


inline void cls(u16 color)
{
	//dmaFillWords (u32 value, void *dest, uint32 size)
	dmaFillWords (color, VRAM_A, SCREEN_HEIGHT * SCREEN_WIDTH * 2);
}

inline void pcopy(u16 *buffer1,u16 *buffer2)
{
	//dmaCopy (const void *source, void *dest, uint32 size)
	dmaCopy (buffer1, buffer2, SCREEN_HEIGHT * SCREEN_WIDTH*2);
}

inline void pset(s32 x, s32 y, u16 color)
{
	if (x<0) return;
	if (y<0) return;
	if (x>=SCREEN_WIDTH) return;
	if (y>=SCREEN_HEIGHT) return;
	
	VRAM_A[(y * SCREEN_WIDTH) + x] = color;
}    

void lens(u16 *page1,u16 *page2,s32 x, s32 y, s32 radius)
{

   	const int SCR_X_MAX = SCREEN_WIDTH - 1;
	const int SCR_Y_MAX = SCREEN_HEIGHT - 1;

    s32 wid, hei;
    s32 hypotsquared, radiussquared, h;
    s32 sx, sy, x1, y1, yt, xt;
    s32 px, py;
    s32 minx, miny;
    s32 wtemp, htemp;
    s32 sphereheight, cleaner;
    


    sphereheight = (radius >> 1);
    cleaner = sphereheight * 10;

    radiussquared = radius * radius;

    wid = radius << 1;
    hei = wid;


    minx = 0;
    miny = 0;

  	if (y < 0)
	{
		y = -y;
		miny = y;
		hei = hei - y;
		if (hei <= 0) return;
		y = 0;
	}

	if  ((y + hei) > SCR_Y_MAX)
	{
		htemp = (y + hei) - SCREEN_HEIGHT;
		hei = hei - htemp;
		if (hei <= 0) return;
	}

	if (x < 0)
	{
		x = -x;
		minx = x;
		wid = wid - x;
		if (wid <= 0) return;
		x = 0;
	}
	
	if  ((x + wid) > SCR_X_MAX)
	{
		wtemp = (x + wid) - SCREEN_WIDTH;
		wid = wid - wtemp;
		if (wid <= 0) return;
	}
        
    
    for (yt=0; yt<hei; yt++)
	{
		for (xt=0; xt<wid; xt++)
		{
			x1 = (xt - radius) + minx;
			y1 = (yt - radius) + miny;

			hypotsquared = (x1 * x1) + (y1 * y1);
			if (hypotsquared < (radiussquared - cleaner))
			{
				h = (sqrt32(radiussquared - hypotsquared));
				sx = (sphereheight - h);
				sy = (sphereheight - h);
				sx = sx * ((x1 << 16) / h);  //div32 here
				sy = sy * ((y1 << 16) / h);  // ditto 
				py = ((sy >> 16) + yt + y);
				px = ((sx >> 16) + xt + x);
				sx = (x+xt);
				sy = (y+yt);
				if ( (px > -1) && (px < SCREEN_WIDTH) && (py > -1) && (py < SCREEN_HEIGHT) )                  
				{
					page2[(sy * SCREEN_WIDTH) + sx] = page1[py * SCREEN_WIDTH + px];              
				}                
			}                                    
		}       
    }

}


u16 vpage1[SCREEN_HEIGHT*SCREEN_WIDTH];
u16 vpage2[SCREEN_HEIGHT*SCREEN_WIDTH];

int main(void)
{

	irqInit();
	irqEnable(IRQ_VBLANK);
	
	
	//initialize the DS Dos-like functionality
	consoleDemoInit();
 
	//set frame buffer mode 0
	videoSetMode(MODE_FB0);
 
	//enable VRAM A for writting by the cpu and use 
	//as a framebuffer by video hardware
	vramSetBankA(VRAM_A_LCD);
	
	u16 *p_offset = vpage1;
	for (int y=0; y<SCREEN_HEIGHT; y++)
	{
		for (int x=0; x<SCREEN_WIDTH; x++)
		{
			u16 c = x^y; 
			*p_offset++ = RGB15(c,c,c);
		}
	}
	
 
	int keys = 0;
	
	s32 lens_x=90;
	s32 lens_y=80;
	s32 lens_rad=40;
	
	while(1)
	{
		
		scanKeys();
        keys = keysHeld();
        
        if(keys & KEY_UP) lens_y--;
        if(keys & KEY_DOWN) lens_y++;
    
        if(keys & KEY_LEFT) lens_x--;
        if(keys & KEY_RIGHT) lens_x++;
		
		if(keys & KEY_L) if (lens_rad>20) lens_rad--;
        if(keys & KEY_R) if (lens_rad<55) lens_rad++;

        pcopy(vpage1,vpage2);
		
		lens(vpage1, vpage2,lens_x,lens_y,lens_rad);
		
		pcopy(vpage2,VRAM_A);
		
		swiWaitForVBlank();
		
		
		
	}
 
	return 0;
}