You are not logged in.
Hi, if in my game I want to copy what's on the screen to use it later. I need to copy the buffer xfb[fb]?
Is there a function to do that, I know memcpy would work, but is there a GX function?
Offline
The xfb is sort of a lower resolution image, and is on the CPU's side. To copy parts of an image, you would use the following functions on GX:
GX_SetTexCopySrc(u16 left,u16 top,u16 wd,u16 ht);//This sets the location on the efb you want to copy from GX_SetTexCopyDst(u16 wd,u16 ht,u32 fmt,u8 mipmap);//This is what kind of texture you want to copy from //format is close to the texture initializer if you know what that is. // To make it the same format as what you are using in GRRLIB, you would set this to (width,height, GX_TF_RGBA8,GX_FALSE) //Next, make a buffer to hold the texture: u8 * newTexture = memalign(32, GX_GetTexBufferSize(width,height,GX_TF_RGBA8,GX_FALSE,1)); GX_CopyTex(newTexture, boolClear);//do you want to clear the buffer after copying the image portion?
Last edited by RedShade (2008-07-07 19:14:04)
Offline
I tried this function:
/** * Make a snapshot of the sreen in a texture. * @return A texture representing the screen. */ u8 *GRRLIB_Screen2Texture() { void *my_texture; GX_SetTexCopySrc(0, 0, 640, 480); GX_SetTexCopyDst(640, 480, GX_TF_RGBA8, GX_FALSE); my_texture = memalign(32, 640 * 480 * 4); // GX_GetTexBufferSize(640, 480, GX_TF_RGBA8, GX_FALSE, 1) GX_CopyTex(my_texture, GX_FALSE); return my_texture; }
It's almost working, the only problem I have is when I put back the texture on screen. There is weird pixels on the top of the screen. They appear while drawing on top of the texture (when I move the cursor or when the button is changing state).
This is my code to copy the screen to a texture:
u8 *CopiedImg; CopiedImg = GRRLIB_Screen2Texture();
This my code to put it back on the screen:
GRRLIB_DrawImg(0, 0, 640, 480, CopiedImg, 0, 1, 1, 255);
The libOGC Documentation is not accurate on some function arguments:
http://libogc.devkitpro.org/
For example:
/*! * \fn void GX_SetTexCopyDst(u16 wd,u16 ht,u32 fmt,u8 mipmap) * \brief Copies the embedded framebuffer(XFB) to the texture image buffer <b><i>dest</i></b> in main memory. This is useful * when creating textures using the Graphics Processor(CP). * If the <b><i>clear</i></b> flag is set to GX_TRUE, the EFB will be cleared to the current color(see GX_SetCopyClear()) * during the copy operation. * * \param[in] wd pointer to the image buffer in main memory. <b><i>dest</i></b> should be 32B aligned. * \param[in] ht flag that indicates framebuffer should be cleared if GX_TRUE. * \param[in] fmt \ref texfmt * \param[in] mipmap * * \return none */
I'm so close to make this work, if you have an hint I would appreciate it a lot.
Thanks!
Offline
This is what I get at the top of my screen:
I cut the rest of the screenshot because all the rest is ok???
Offline
Something is writing over your the texture, either from an incomplete draw to EFB, or between the copy of the texture and the drawing back onto the EFB :-/...
What settings are confusing? It's similar to :
GX_InitTexObj (GXTexObj *obj, void *img_ptr, u16 wd, u16 ht, u8 fmt, u8 wrap_s, u8 wrap_t, u8 mipmap)
except you don't set wrapping or texobj
have you tried it on smaller code segments? *The kind of thing that can be pasted here to look over, or on pastie or something to try out.
Last edited by RedShade (2008-07-08 23:29:14)
Offline
Right now I'm not at home, so this is the information that I can provide. I will do some test tonight.
I'm working in C++ project, so CopiedImg is private attribute declare as u8 *. These are all the places where CopiedImg is being used:
This for my HOME page (when the HOME button is pressed). I only want draw the game screen once and to add an effect on it. CopiedImg will be used has a background image, buttons and other stuff will be draw over it:
if(CopiedImg == NULL) { GameScreen(); // Draw the game screen GRRLIB_Rectangle(0, 0, 640, 480, 0xCC000000, 1); // Make the screen look disable CopiedImg = GRRLIB_Screen2Texture(); } else { // Put the copied texture on screen GRRLIB_DrawImg(0, 0, 640, 480, CopiedImg, 0, 1, 1, 255); } // Buttons are drawn on screen ExitButton[0].Paint(); ExitButton[1].Paint(); ExitButton[2].Paint();
When I change screen (going back in the game) this code is called, I don't know if it's proper way to free a texture:
if(CopiedImg) { free(CopiedImg); CopiedImg = NULL; }
In my constructor I have:
CopiedImg = NULL;
In my destructor I have:
if(CopiedImg) free(CopiedImg);
Offline
OK just a small update, I was able to make it work correctly by loading a 640x480 texture to CopiedImg before using it.
So my code in the constructor is now:
CopiedImg = GRRLIB_LoadTexture(splash);
splash is the image I'm using for my intro screen. I don't know what is going on in GRRLIB_LoadTexture, but it is now initializing correctly.
I still want to understand the problem, so if someone has a idea on how to solve it, well post it here...
Offline
Don't think that does anything but shift the memory around a little. You are still having a pointer that is doing:
CopiedImage -> 0;
CopiedImage -> points to splash
CopiedImage -> points to screen capture
so the logic goes:
u32 ptr = 0;
//ptr = 1; //uncommenting this line changes the result?
ptr = 2;
I believe free(ptr) is the correct way to free memalign-ed memory
I don't know if GX_DrawDone() would help in the copying of the texture or not :-/
Offline
I think that the DCFlushRange line fixed the problem, I saw that in the snes9x-gx code.
So the function should look like this:
u8 *GRRLIB_Screen2Texture() { void *my_texture; GX_SetTexCopySrc(0, 0, 640, 480); GX_SetTexCopyDst(640, 480, GX_TF_RGBA8, GX_FALSE); my_texture = memalign(32, 640 * 480 * 4); // GX_GetTexBufferSize(640, 480, GX_TF_RGBA8, GX_FALSE, 1) GX_CopyTex(my_texture, GX_FALSE); GX_PixModeSync(); DCFlushRange(my_texture, 640 * 480 * 4); return my_texture; }
Offline
Hi,
This function looks like just what I need, but there seems to be a bug with it (or else with GRRLIB_DrawImg) or I am misunderstanding something.
I am using this function to copy the screen buffer before rendering it so that I can re-use it - looking at the tic-tac-toe source, this seems to be correct.
If I use this function in a loop, my graphics fall off the bottom of the screen so it seems that the screen image is being rendered slightly lower down when re-draw it.
The following program demonstrates the problem. It draws a rectangle and then when you press "A" it goes into a loop which should just keep redrawing the screen as is, but in fact the rectangle falls off the bottom.
#include <wiiuse/wpad.h> #include "GRRLIB/GRRLIB.h" Mtx GXmodelView2D; u8 *GRRLIB_Screen2Texture() { void *my_texture; GX_SetTexCopySrc(0, 0, 640, 480); GX_SetTexCopyDst(640, 480, GX_TF_RGBA8, GX_FALSE); my_texture = memalign(32, 640 * 480 * 4); // GX_GetTexBufferSize(640, 480, GX_TF_RGBA8, GX_FALSE, 1) GX_CopyTex(my_texture, GX_FALSE); GX_PixModeSync(); DCFlushRange(my_texture, 640 * 480 * 4); return my_texture; } int main(){ VIDEO_Init(); WPAD_Init(); GRRLIB_InitVideo(); GRRLIB_Start(); GRRLIB_FillScreen(0xFF000000); GRRLIB_Rectangle(100,100,200,100,0xFFFFFFFF,1); // copy the soon to be rendered screen to an image u8 *copiedImg = GRRLIB_Screen2Texture(); GRRLIB_Render(); // just wait for A to be pressed bool aPressed = false; while(!aPressed){ WPAD_ScanPads(); u32 wpaddown = WPAD_ButtonsDown(0); aPressed = (wpaddown & WPAD_BUTTON_A); } // loop copying and redrawing until A pressed again aPressed = false; while(!aPressed){ // draw the previously copied screen image GRRLIB_DrawImg(0, 0, 640, 480, copiedImg, 0, 1, 1, 255); // free the memory free(copiedImg); // copy the updated screen copiedImg = GRRLIB_Screen2Texture(); //render the screen GRRLIB_Render(); // exit when we press A WPAD_ScanPads(); u32 wpaddown = WPAD_ButtonsDown(0); aPressed = (wpaddown & WPAD_BUTTON_A); } free(copiedImg); return 0; }
Thanks,
SammyStag
Offline
Yes your right, since I was not using it in a loop I never felt like finding a solution for that issue. Anyway I suck with GX functions. Hopefully someone will find a solution.
Meanwhile, you could try to use this:
GRRLIB_DrawImg(0, -1, 640, 479, copiedImg, 0, 1, 1, 255);
Right now I could not test it (not at home).
Offline
Thanks for the reply, unfortunately this doesn't seem to fix it.
I tried a few other values and strange things happen. For example
GRRLIB_DrawImg(0, -20, 640, 460, copiedImg, 0, 1, 1, 255);
has the image stretch out to the top and bottom of the screen and then horizontally as it becomes ghost like. I wasn't sure if the 4th argument should remain at 480, but that didn't seem to make any difference.
Offline
as i already said a lot of times, be sure to use the latest libogc !!! old version produce "VOODOO gx effects". catch the svn version and tell us if it resolv your stuff.
Offline
I've tried this again with the new libogc 1.7.0 release and am still getting the same results.
Offline