Problems with screenshot code.

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

Moderators: cheriff, TyRaNiD

OmahaStylee
Posts: 14
Joined: Mon Aug 29, 2005 5:00 pm
Location: Los Angeles, CA
Contact:

Post by OmahaStylee »

Okay... i got past that error. I had to move that line of code into my main function... But the image still looks the same... i'll keep looking through the code...otherwise, any ideas?

UPDATE: I tried moving the buffer start into the main function, but that didnt work. now its saying the usual BS errors, "VRAM undeclared", "First Use of this function"
Image
jason867
Posts: 78
Joined: Sun Jul 24, 2005 1:58 am
Contact:

Post by jason867 »

Let me see your source code in its current state?
Ask not for whom the bell tolls, it tolls for thee, besides, I'm playing my PSP, tee hee!
------------------------------------------------------
Visit my website for my PSP Homebrew!
OmahaStylee
Posts: 14
Joined: Mon Aug 29, 2005 5:00 pm
Location: Los Angeles, CA
Contact:

Post by OmahaStylee »

Here you go.

Code: Select all

// Include nescicary headers & other files
#include <pspkernel.h>
#include <pspdebug.h>
#include <string.h>
#include <stdlib.h>
#include <png.h>
#include <pspdisplay.h>

#define BUF_WIDTH &#40;512&#41;
#define SCR_WIDTH &#40;480&#41;
#define SCR_HEIGHT &#40;272&#41;
// Give the program a name -- This isnt the actual name
PSP_MODULE_INFO&#40;"xxxxxxxxxxx", 0, 1, 1&#41;;
// Rename things to make typing easier
#define printf	pspDebugScreenPrintf // Prints to debug screen
#define debugClear pspDebugScreenClear // Clears debug screen
#define textColor pspDebugScreenSetTextColor // Sets debug text color
#define setCursor pspDebugScreenSetXY // Sets cursor on debug screen
#define bgColor pspDebugScreenSetBackColor // Sets background color on Debug screen
// Color converter
#define RGB&#40;r, g, b&#41; &#40;&#40;b << 16&#41; | &#40;g << 8&#41; | r&#41;
#define STEELBLUE RGB&#40;43, 84, 126&#41;

u16* data = VRAM;


// Essential exit stuff
/* Exit callback */
int exit_callback&#40;int arg1, int arg2, void *common&#41; &#123;
	sceKernelExitGame&#40;&#41;;
	return 0;
&#125;
/* Callback thread */
int CallbackThread&#40;SceSize args, void *argp&#41; &#123;
	int cbid;
	cbid = sceKernelCreateCallback&#40;"Exit Callback", exit_callback, NULL&#41;;
	sceKernelRegisterExitCallback&#40;cbid&#41;;
	sceKernelSleepThreadCB&#40;&#41;;
	return 0;
&#125;
/* Sets up the callback thread and returns its thread id */
int SetupCallbacks&#40;void&#41; &#123;
	int thid = 0;
	thid = sceKernelCreateThread&#40;"update_thread", CallbackThread, 0x11, 0xFA0, 0, 0&#41;;
	if&#40;thid >= 0&#41; &#123;
		sceKernelStartThread&#40;thid, 0, 0&#41;;
	&#125;
	return thid;
&#125;

// Main function, executed before anything else
int main&#40;void&#41; &#123;
    sceDisplaySetMode&#40;1,SCR_WIDTH,SCR_HEIGHT&#41;;
    // Start screenshot buffer
    u16 *VRAM=&#40;void *&#41;&#40;0X44000000&#41;;
	pspDebugScreenInit&#40;&#41;;
	SetupCallbacks&#40;&#41;;
    // Set BG color
    bgColor&#40;SELECTED&#41;;
    pspDebugScreenClear&#40;&#41;;
    setCursor&#40;25, 16&#41;;
    printf&#40;"THIS IS A TEST OF THE PRINT SCREEN FEATURE"&#41;;
    screenshot&#40;"ms0&#58;/test.png"&#41;;
	sceKernelExitGame&#40;&#41;;
&#125;

void screenshot&#40;const char* filename&#41;
&#123;
   png_structp png_ptr;
   png_infop info_ptr;
   FILE* fp;
   int i, x, y;
   int width=SCR_WIDTH;
   int height=SCR_HEIGHT;
   int linesize=BUF_WIDTH;
   int saveAlpha=0;
   u8* line;

   if &#40;&#40;fp = fopen&#40;filename, "wb"&#41;&#41; == NULL&#41; return;
   png_ptr = png_create_write_struct&#40;PNG_LIBPNG_VER_STRING, NULL, NULL, NULL&#41;;
   if &#40;!png_ptr&#41; return;
   info_ptr = png_create_info_struct&#40;png_ptr&#41;;
   if &#40;!info_ptr&#41; &#123;
      png_destroy_write_struct&#40;&png_ptr, &#40;png_infopp&#41;NULL&#41;;
      return;
   &#125;
   png_init_io&#40;png_ptr, fp&#41;;
   png_set_IHDR&#40;png_ptr, info_ptr, width, height, 8,
      saveAlpha ? PNG_COLOR_TYPE_RGBA &#58; PNG_COLOR_TYPE_RGB,
      PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT&#41;;
   png_write_info&#40;png_ptr, info_ptr&#41;;
   line = &#40;u8*&#41; malloc&#40;width * &#40;saveAlpha ? 4 &#58; 3&#41;&#41;;
   for &#40;y = 0; y < height; y++&#41; &#123;
      for &#40;i = 0, x = 0; x < width; x++&#41; &#123;
         u16 color = data&#91;x + y * linesize&#93;;
         int r = &#40;color & 0x1f&#41; << 3;
         int g = &#40;&#40;color >> 5&#41; & 0x1f&#41; << 3 ;
         int b = &#40;&#40;color >> 10&#41; & 0x1f&#41; << 3 ;
         line&#91;i++&#93; = r;
         line&#91;i++&#93; = g;
         line&#91;i++&#93; = b;
         if &#40;saveAlpha&#41; &#123;
            int a = color & 0x8000 ? 0xff &#58; 0;
            line&#91;i++&#93; = a;
         &#125;
      &#125;
      png_write_row&#40;png_ptr, line&#41;;
   &#125;
   free&#40;line&#41;;
   png_write_end&#40;png_ptr, info_ptr&#41;;
   png_destroy_write_struct&#40;&png_ptr, &#40;png_infopp&#41;NULL&#41;;
   fclose&#40;fp&#41;;
&#125;
Image
jason867
Posts: 78
Joined: Sun Jul 24, 2005 1:58 am
Contact:

Post by jason867 »

I've looked through your source, messed around and expieriemented with it. I even used some of my stuff and tried the same thing. And I confess, this has me dumbfounded as hell!

No matter what I do, I can't get text to be saved in the screenshot without being distorted. I can save pixel-drawn images just fine, but the text is distorted. I also managed to get the text to distort in the same way, but on the psp screen itself. It seems when you set the video mode, it messes with the debug text stuff, causing it to distort on screen. But it looks the same in the png as well! When I don't change video modes, the text looks fine on screen, but still distorts in the png.

I'm not sure if I explained that clearly enough. I'm sorry to say that I'm of no further help to you. I'm a noob too so, yeah, lol.

Ask shine about this, he seems to know his stuff.

Good luck!

[Edit] P.S. Please let me know if you find out what's wrong, as I'd like to draw graphics and text, and take screenshots, without any of them messing up.
Ask not for whom the bell tolls, it tolls for thee, besides, I'm playing my PSP, tee hee!
------------------------------------------------------
Visit my website for my PSP Homebrew!
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

jason867 wrote:No matter what I do, I can't get text to be saved in the screenshot without being distorted. I can save pixel-drawn images just fine, but the text is distorted. I also managed to get the text to distort in the same way, but on the psp screen itself.
The debug text functions from PSPSDK uses 32 bit mode, which could cause problems if you are using 16 bit mode, like in the PNG save function.
OmahaStylee
Posts: 14
Joined: Mon Aug 29, 2005 5:00 pm
Location: Los Angeles, CA
Contact:

Post by OmahaStylee »

Any ideas shrine? Is there another screenshot script that'll work all the time?
Image
jason867
Posts: 78
Joined: Sun Jul 24, 2005 1:58 am
Contact:

Post by jason867 »

lol, I told you he knew what he was talking about...lol
Ask not for whom the bell tolls, it tolls for thee, besides, I'm playing my PSP, tee hee!
------------------------------------------------------
Visit my website for my PSP Homebrew!
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

OmahaStylee wrote:Any ideas shrine? Is there another screenshot script that'll work all the time?
If you are searching for a script, use Lua Player, this works all the time, C is not a script language :-)

But would be useful to have a C screenshot code, which works all the time, perhaps you can write one? Use sceDisplayGetFrameBuf to determine the pixelformat and the start of the framebuffer and use this information to select the appropriate bit shifting before writing it as PNG.
OmahaStylee
Posts: 14
Joined: Mon Aug 29, 2005 5:00 pm
Location: Los Angeles, CA
Contact:

Post by OmahaStylee »

Right after i finish porting WinXP...lol
Image
jason867
Posts: 78
Joined: Sun Jul 24, 2005 1:58 am
Contact:

Post by jason867 »

I could do that if I understood the bit shifting part. ( I do realize that bit shifting is simply rotating a series of bits in one direction or another, such as 00100 turning into 01000 or 00010, I just don't have any expierience in bit shifting)
Ask not for whom the bell tolls, it tolls for thee, besides, I'm playing my PSP, tee hee!
------------------------------------------------------
Visit my website for my PSP Homebrew!
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

jason867 wrote:I could do that if I understood the bit shifting part. ( I do realize that bit shifting is simply rotating a series of bits in one direction or another, such as 00100 turning into 01000 or 00010
Bit shifting in C is not rotating, it is shifting. The term "rotating" is used for example when left shifting and the highest bit is fed into the lowest bit again.
jason867 wrote:I just don't have any expierience in bit shifting)
Then this is a really good task to gain some experience :-)
OmahaStylee
Posts: 14
Joined: Mon Aug 29, 2005 5:00 pm
Location: Los Angeles, CA
Contact:

Post by OmahaStylee »

Go for it!
Image
Panajev2001a
Posts: 100
Joined: Sat Aug 20, 2005 3:25 am

Post by Panajev2001a »

For others who might have trouble using Jason's code, I thought it might be useful to see as many working implementations of it as possible.

This is how I call the screen_shot function in my main file:

Code: Select all

screenshot&#40;"ms0&#58;/PSP/PHOTO/screen_shot.png", &#40;u16 *&#41; UNCACHED_VRAM_PTR &#40;FRAME_BUFFER_1&#41;&#41;;
This is my custom file with all the important define's I use in my project (I centralized there some things from graphics.h and other files):

Code: Select all

#ifndef PSP_DEFINES_H
#define PSP_DEFINES_H

#include <psptypes.h>

#define addr_align&#40; x &#41; __attribute__&#40;&#40;aligned&#40; x &#41;&#41;&#41;;

#define PI       3.14159265358979323846
#define	PSP_LINE_SIZE 512
#define SCREEN_WIDTH 480
#define SCREEN_HEIGHT 272
#define IS_ALPHA&#40;COLOUR&#41; &#40;&#40;COLOUR&#41;&0x8000?0&#58;1&#41;
#define FRAMEBUFFER_SIZE &#40;PSP_LINE_SIZE*SCREEN_HEIGHT*2&#41;   //16 bpp color depth
#define MAX&#40;X, Y&#41; &#40;&#40;X&#41; > &#40;Y&#41; ? &#40;X&#41; &#58; &#40;Y&#41;&#41;

#define BUF_WIDTH &#40;512&#41;
#define SCR_WIDTH &#40;480&#41;
#define SCR_HEIGHT &#40;272&#41;

#define RGBA_5551 &#40;2&#41;
#define RGBA_5650 &#40;2&#41;
#define RGBA_4444 &#40;2&#41;
#define RGBA_8888 &#40;4&#41;

#define PIXEL_SIZE &#40;RGBA_5551&#41; /* change this if you change to another screenmode */
#define FRAME_SIZE &#40;BUF_WIDTH * SCR_HEIGHT * PIXEL_SIZE&#41;
#define ZBUF_SIZE &#40;BUF_WIDTH * SCR_HEIGHT * 2&#41; /* zbuffer seems to be 16-bit? */

#define UNCACHED_ADDR		0x40000000		

#define UNCACHED_PTR&#40;X&#41;		&#40;&#40;X&#41; | &#40;UNCACHED_ADDR&#41;&#41;

#define VRAM_PTR&#40;Y&#41;			&#40;&#40;Y&#41; | 0x04000000&#41;

#define SPRAM_PTR&#40;Y&#41;		&#40;&#40;Y&#41; | 0x00010000

#define MAIN_RAM_PTR&#40;Y&#41;		&#40;&#40;Y&#41; | 0x08800000&#41;

#define UNCACHED_VRAM_PTR&#40;Z&#41; &#40;&#40;VRAM_PTR&#40;Z&#41;&#41; | &#40;UNCACHED_ADDR&#41;&#41;

#define UNCACHED_SPRAM_PTR&#40;Z&#41; &#40;&#40;SPRAM_PTR&#40;Z&#41;&#41; | &#40;UNCACHED_ADDR&#41;&#41;

#define UNCACHED_MAIN_RAM_PTR&#40;Z&#41; &#40;&#40;MAIN_RAM_PTR&#40;Z&#41;&#41; | &#40;UNCACHED_ADDR&#41;&#41;

/* PSP Memory Map
Base Address 	Length 	Description
0×00010000	0×00004000 &#40;16 KiB&#41;	Allegrex Scratchpad
0×04000000	0×00200000 &#40;2 MiB&#41;	Ge VRAM
0×08000000	0×00800000 &#40;8 MiB&#41;	Allegrex Kernel memory
0×08800000	0×01800000 &#40;24 MiB&#41;	Allegrex User memory*/

//The following three Macro's are used to help set-up the screen and 
//assume the function you will pass the result to will take them as
//VRAM addresses, taking upon itself to OR them with the VRAM base address 0x04000000

#define FRAME_BUFFER_1 &#40;0x0&#41;
#define FRAME_BUFFER_2 &#40;FRAME_SIZE&#41;
#define Z_BUFFER &#40;&#40;FRAME_BUFFER_2&#41; + &#40;FRAME_SIZE&#41;&#41;

typedef union IGGSPspMatrix4 &#123;
	ScePspFMatrix4 	fm;
	ScePspIMatrix4 	im;
	ScePspFVector4 	fv&#91;4&#93;;
	ScePspIVector4 	iv&#91;4&#93;;
	ScePspVector4 	v&#91;4&#93;;
	float			m&#91;4*4&#93;;
	int				m_i&#91;4*4&#93;;
&#125; IGGSPspMatrix4 addr_align &#40;16&#41;;

typedef u16 Color;
typedef short unsigned int uint16;
typedef unsigned int uint32;
typedef unsigned long long uint64;
typedef unsigned long long ulong64;



#endif

This is my .h file in which the screen_shot function is located:

Code: Select all

#ifndef PSP_UTILS_H
#define PSP_UTILS_H

#include <psptypes.h>
#include "PSPDefines.h"

/**
 * Save an image or the screen in PNG format.
 *
 * @pre filename != NULL
 * @param filename - filename of the PNG image
 * @param data - start of Color type pixel data &#40;can be getVramDisplayBuffer&#40;&#41;&#41;
 * @param width - logical width of the image or SCREEN_WIDTH
 * @param height - height of the image or SCREEN_HEIGHT
 * @param lineSize - physical width of the image or PSP_LINE_SIZE
 * @param saveAlpha - if 0, image is saved without alpha channel
 */

/*when you call the screenshot, make sure to type a valid file path, such as;

screenshot&#40;"ms0&#58;/filepath.png"&#41;;

With filepath being your filepath. You have to have 'ms0&#58;/' at the 
beginning and '.png' at the end. Once called you'll see your memory stick led flash 
several times, and then when you hook up your psp to your pc, you'll find your filepath.png 
screenshot file at the directory of your memory stick that you set it to write to.*/ 

extern void screenshot&#40;const char* filename, u16 * VRAM_ADDR&#41;;

#endif

This is the corresponding .cpp file:

Code: Select all

#include <stdlib.h>
#include <malloc.h>
#include <pspdisplay.h>
#include <psputils.h>
#include <png.h>
#include <pspgu.h>
#include "PSPDefines.h"
#include "PSP_Utils.h"

//static unsigned int __attribute__&#40;&#40;aligned&#40;16&#41;&#41;&#41; list&#91;256&#93;;
//static int dispBufferNumber;
//static int initialized = 0;

void screenshot&#40;const char* filename, u16 * VRAM_ADDR&#41; &#123;

   png_structp png_ptr;
   png_infop info_ptr;
   FILE* fp;
   int i, x, y;
   u16* data = VRAM_ADDR;
   int width=SCR_WIDTH;
   int height=SCR_HEIGHT;
   int linesize=BUF_WIDTH;
   int saveAlpha=0;
   u8* line;

   if &#40;&#40;fp = fopen&#40;filename, "wb"&#41;&#41; == NULL&#41; return;
   png_ptr = png_create_write_struct&#40;PNG_LIBPNG_VER_STRING, NULL, NULL, NULL&#41;;
   if &#40;!png_ptr&#41; return;
   info_ptr = png_create_info_struct&#40;png_ptr&#41;;
   if &#40;!info_ptr&#41; &#123;
      png_destroy_write_struct&#40;&png_ptr, &#40;png_infopp&#41;NULL&#41;;
      return;
   &#125;
   png_init_io&#40;png_ptr, fp&#41;;
   png_set_IHDR&#40;png_ptr, info_ptr, width, height, 8,
      saveAlpha ? PNG_COLOR_TYPE_RGBA &#58; PNG_COLOR_TYPE_RGB,
      PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT&#41;;
   png_write_info&#40;png_ptr, info_ptr&#41;;
   line = &#40;u8*&#41; malloc&#40;width * &#40;saveAlpha ? 4 &#58; 3&#41;&#41;;
   for &#40;y = 0; y < height; y++&#41; &#123;
      for &#40;i = 0, x = 0; x < width; x++&#41; &#123;
         u16 color = data&#91;x + y * linesize&#93;;
         int r = &#40;color & 0x1f&#41; << 3;
         int g = &#40;&#40;color >> 5&#41; & 0x1f&#41; << 3 ;
         int b = &#40;&#40;color >> 10&#41; & 0x1f&#41; << 3 ;
         line&#91;i++&#93; = r;
         line&#91;i++&#93; = g;
         line&#91;i++&#93; = b;
         if &#40;saveAlpha&#41; &#123;
            int a = color & 0x8000 ? 0xff &#58; 0;
            line&#91;i++&#93; = a;
         &#125;
      &#125;
      png_write_row&#40;png_ptr, line&#41;;
   &#125;
   free&#40;line&#41;;
   png_write_end&#40;png_ptr, info_ptr&#41;;
   png_destroy_write_struct&#40;&png_ptr, &#40;png_infopp&#41;NULL&#41;;
   fclose&#40;fp&#41;;
&#125; 

//void flipScreen&#40;&#41; //here as commented sample code
//&#123;
//	if &#40;!initialized&#41; return;
//	Color* vram = getVramDrawBuffer&#40;&#41;;
//	sceGuSwapBuffers&#40;&#41;;
//	sceDisplaySetFrameBuf&#40;vram, PSP_LINE_SIZE, 1, 1&#41;;
//	dispBufferNumber ^= 1;
//&#125;



As you take from my define's file I am taking a single screen_shot, in the main file, from what it is the current front-buffer (I take it after the SwapBuffers function has been called).

I hope this helps in some way.
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

Panajev2001a wrote:For others who might have trouble using Jason's code, I thought it might be useful to see as many working implementations of it as possible.
I think one working implementation, which works with all pixel formats and all vram start adresses, is better:

main.c
Makefile
JJPeerless
Posts: 82
Joined: Mon Jun 20, 2005 3:32 am

Post by JJPeerless »

hey shine, ive been using your graphics.c and graphics.h files..and i was trying to do a 65 frame animation today (65 png files) and well, when displaying the 37th frame, i get an exception..and it points to the blittoscreen function

sceGuCopyImage(GU_PSM_5551, sx, sy, width, height, source->textureWidth, source->data, dx, dy, PSP_LINE_SIZE, vram);

points to that line..


not sure whats wrong? any idea?
Shiki
Posts: 10
Joined: Fri Sep 02, 2005 10:33 am

Post by Shiki »

Shine, I just tried your main.c and Makefile that you last posted. Either I'm having serious environment set up problems or it's just not compiling for me. I've compiled other sources before without errors, but I'm getting various errors. First one asks for png.h, so I downloaded it and put it with the source and that lead to a thread of errors that scrolls the screen for awhile.

Not sure what's happening here. Unless someone wants to run me through reinstallation. ;)
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

Shiki wrote:Shine, I just tried your main.c and Makefile that you last posted. Either I'm having serious environment set up problems or it's just not compiling for me. I've compiled other sources before without errors, but I'm getting various errors. First one asks for png.h, so I downloaded it and put it with the source and that lead to a thread of errors that scrolls the screen for awhile.
Quoting jason867 from earlier in this thread:
jason867 wrote:
in your Cygwin Bash Shell (or whatever you use) enter the folowing lines;
svn co svn://svn.ps2dev.org/psp/trunk/zlib -- press [Enter] and wait for the prompt to show back up.
svn co svn://svn.ps2dev.org/psp/trunk/libpng -- press [Enter] and wait for the prompt to show back up.

[Edit] Those two lines up just above this look like links to websites, but they're not, so don't even bother clicking on them.

then you need to change your directory in the bash shell to your psptoolchain/zlib folder, and then type 'make' and then 'make install'
then change the directory over to your psptoolchain/libpng folder and type 'make' and 'make install' again.
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

JJPeerless wrote:hey shine, ive been using your graphics.c and graphics.h files..and i was trying to do a 65 frame animation today (65 png files) and well, when displaying the 37th frame, i get an exception..and it points to the blittoscreen function

sceGuCopyImage(GU_PSM_5551, sx, sy, width, height, source->textureWidth, source->data, dx, dy, PSP_LINE_SIZE, vram);

points to that line..


not sure whats wrong? any idea?
Are you sure, that all pointer are valid (no NULL pointers)? If there is not enough memory, loadImage returns NULL and you have to check this. Maybe there are memory leaks in my functions or you forgot to free the memory, can't say it without your source.
Shiki
Posts: 10
Joined: Fri Sep 02, 2005 10:33 am

Post by Shiki »

Thanks, I forgot about the two lines after the edit note. Now to find out if it works.
Panajev2001a
Posts: 100
Joined: Sat Aug 20, 2005 3:25 am

Post by Panajev2001a »

Shine wrote:
Panajev2001a wrote:For others who might have trouble using Jason's code, I thought it might be useful to see as many working implementations of it as possible.
I think one working implementation, which works with all pixel formats and all vram start adresses, is better:

main.c
Makefile
Did I push 99% of your buttons at once ?

Hehe, come on I was trying to help. I am glad you posted that code though, it is clean and can be easy plugged in (I quickly replaced the other function: hey, I can admit when a tool is better than another one, after-all it is just a means to an end, not the goal itself :)... well for me, not for the tool designer maybe :D).

I noticed that the code we were using before has problem if the file you are trying to save as the same name as one on the memory stick (running the same program twice without deleting the svaed screenshot).

It should be an easy fix as I had it already in my screenshot code for PS2Linux.
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

Panajev2001a wrote:I noticed that the code we were using before has problem if the file you are trying to save as the same name as one on the memory stick (running the same program twice without deleting the svaed screenshot).
I have tested this with my latest code and of course there is no problem, because fopen with "wb" overwrites old files, as specified by the definition of fopen.
Panajev2001a
Posts: 100
Joined: Sat Aug 20, 2005 3:25 am

Post by Panajev2001a »

Shine wrote:
Panajev2001a wrote:I noticed that the code we were using before has problem if the file you are trying to save as the same name as one on the memory stick (running the same program twice without deleting the svaed screenshot).
I have tested this with my latest code and of course there is no problem, because fopen with "wb" overwrites old files, as specified by the definition of fopen.
Well, I was mentioning the old code (on which I based the code snippets I posted). It might have been related to something else, but I clearly observed it: took a screenshot, restarted the program... it hangs... restart PSP, restart the program... it hangs... restart the PSP, delete the screen_shot, restart the program... it works.

I still am not happy with "wb", it would be neat to just call the screen_shot function each frame and make small movies compositing the frames (this is what I did on PS2Linux... got the images to a series of .ppm files, converted them to jpeg's IIRC and made a small movie... which is fairly smooth too :)).

Memory Stick writes currently kinda "pause" the program, but if you have some "pre-defined" animation (user-input is kinda difficult to apply in an useful way when the fps count is low as if you took a screen_shot each frame: of course you could composite the movie directly in RAM and only save the final file, but that is a topic for another day) that is updated at each iteration of the infinite game loop, then you should be all set anyways.

Basically "wb" is good, but if the code can be modified to do this:

screenshot ("ms0:/image.png");

with this function generating image0000.png, image0001.png, image0002.png, image0003.png, image0005.png, etc... then it would be quasi-perfect IMHO.

Edit: as with the code snippet I have posted here, we could change a bit your function like so:

Code: Select all

static int m_SS_Number = 0;

sprintf &#40;name, "ms0&#58;/filename%05d.png", m_SS_Number&#41;;
   
// Open the file for writing to   
FILE * f = fopen&#40;name, "wb"&#41;;
Edit #2: well, we could change it to append the numbers to the original file-name too, of course leaving a cleaner utility function not hardcoded to a specific file-name.

Here is the code I was mentioning: I also create a .bat file to ease the conversion of the files into JPEG's. I am not sure if sprintf is supported with PSPSDK's libs. I do not see why it should not though.

Code: Select all

void ScreenShotPPM&#40;int addr&#41;
&#123;
	static int m_SS_Number = 0;
	static int numFrames = 0;

	numFrames++;

	char name&#91;256&#93;;
	char name1&#91;256&#93;;
	
	unsigned char * data;
	//unsigned char tmp;
	unsigned short Width, Height;
	int BytesPerPixel = 3;

	//_sps2SetEIDIEnabled&#40;1, m_iSPS2Desc&#41;;
	
	// Current Screen width and height
	Width = &#40;unsigned short&#41;sps2UScreenGetWidth&#40;&#41;;
	Height = &#40;unsigned short&#41;sps2UScreenGetHeight&#40;&#41;;
	
	//printf&#40;"%x %x", Width, Height&#41;;

	sprintf &#40;name, "video/movie%05d.ppm", m_SS_Number&#41;;
	sprintf &#40;name1, "IGGS_JPEG_script.bat"&#41;;
	
	// Open the file for writing to	
	FILE * f = fopen&#40;name, "wb"&#41;;
	FILE * pfScript = fopen&#40;name1, "ab"&#41;;

	// Create a targa header for a 640x480, 32bit picture
	
	const char header&#91;&#93; = &#123; "P6 640 448 255\n" &#125;;


	fprintf&#40;pfScript, "cjpeg.exe -outfile \\\\ps2linux\\Panajev\\IGGS_PS2\\video\\IGGS_PS2_%05d.jpg \\\\ps2linux\\Panajev\\IGGS_PS2\\video\\movie%05d.ppm\n", m_SS_Number, m_SS_Number &#41;;

	m_SS_Number++;

	
	//for&#40;int i =0; i< 18; i++&#41;printf&#40;"%x ", header&#91;i&#93;&#41;;printf&#40;"\n"&#41;;
	
	// write the header to the file	
	fwrite&#40;header, strlen &#40;header&#41;, 1, f&#41;;
	
	// Now Download the Frame buffer, from the bottom up
	for&#40;int y = 0; y < Height; y++&#41;
	&#123;
		DownloadVram&#40;m_ScreenShot_global_dma, m_ScreenShot_global, addr, 10, 0, &#40;y&#41;, Width, 1&#41;;

		// convert RGBA to BGRA
		data = &#40;unsigned char *&#41;m_ScreenShot_global;
		for&#40;int x = 0; x < Width; x++&#41;
		&#123;
			//tmp = data&#91;0&#93;;
			//data&#91;0&#93; = data&#91;2&#93;;
			//data&#91;2&#93; = tmp;
			//
			// Write pixel to file
			fwrite&#40;data, BytesPerPixel, 1, f&#41;;
			
			data += 4;
		&#125;
		// Write data to file
		//fwrite&#40;GetSShotBase&#40;&#41;, 4, Width, f&#41;;
	&#125;
	
	// Close the file
	fclose&#40;f&#41;;
	fclose&#40;pfScript&#41;;
	
&#125;

void DownloadVram &#40;void * const pDmaBase, void * const pMemBase, 
								int addr, int bufw, int x, int y, int w, int h&#41;
&#123;
	// Pointer to sps2 allocated unswapable memory.
	uint32 * pDmaMem = &#40;uint32 *&#41;pDmaBase;	

	uint32 uSrcPtr = addr;
	uint32 uQSize = &#40;w*h*4&#41;/16; // assuming 24/32bit framebuffer

	// Setup transfer texture back to memory
	pDmaMem&#91;0&#93; = 0; //NOP;
	pDmaMem&#91;1&#93; = 0x06008000; //MSKPATH3&#40;0x8000&#41;;
	pDmaMem&#91;2&#93; = 0x13000000; //FLUSHA;
	pDmaMem&#91;3&#93; = 0x50000006; //DIRECT&#40;6&#41;;

	// Add GifTag Data
	uint64 * pDmaMem64 = &#40;uint64 *&#41; &#40;pDmaMem + 4&#41;;
	
	// QW1&#58; The Giftag for A+D mode
	sps2GIFTag_t * pGIFTag = &#40;sps2GIFTag_t *&#41;pDmaMem64;
	pGIFTag->i128 = 0;
	pGIFTag->s.NLOOP = 5;	// We want to set 5 registers
	pGIFTag->s.PRE = 0;
	pGIFTag->s.EOP = 1;		// This is the end of the GS Packet
	pGIFTag->s.FLG = GIF_FLG_PACKED;
	pGIFTag->s.NREG = 1;
	pGIFTag->s.REGS = GIF_REG_A_D;
	
	pDmaMem64&#91;2&#93; = &#40;BITBLTBUF_SET&#40; uSrcPtr, bufw, 0, 0, 0, 0 &#41;&#41;;
	pDmaMem64&#91;3&#93; = &#40;GIF_A_D_REG_BITBLTBUF&#41;;

	pDmaMem64&#91;4&#93; = &#40;TRXPOS_SET&#40;x, y, 0, 0, 0&#41;&#41;; // SSAX, SSAY, DSAX, DSAY, DIR
	pDmaMem64&#91;5&#93; = &#40;GIF_A_D_REG_TRXPOS&#41;;

	pDmaMem64&#91;6&#93; = &#40;TRXREG_SET&#40;w, h&#41;&#41;; // RRW, RRh
	pDmaMem64&#91;7&#93; = &#40;GIF_A_D_REG_TRXREG&#41;;

	pDmaMem64&#91;8&#93; = &#40;0&#41;;
	pDmaMem64&#91;9&#93; = &#40;GIF_A_D_REG_FINISH&#41;;

	pDmaMem64&#91;10&#93; = &#40;TRXDIR_SET&#40;1&#41;&#41;; // XDIR
	pDmaMem64&#91;11&#93; = &#40;GIF_A_D_REG_TRXDIR&#41;;

	uint32 prev_chcr = *EE_D1_CHCR;
	
	// *_GS_IMR fetches the current setting of interrupt mask register &#40;imr&#41;
	// DPUT_GS_IMR&#40;&#41; sets the current value of imr
	// Mark interrupts from the FINISH Event &#40;GS Page 154&#41;
	uint32 prev_imr = *_GS_IMR;
	DPUT_GS_IMR&#40; prev_imr | 0x0200 &#41;;
	
	// vif1 must be available
	if &#40;&#40;*EE_D1_CHCR & 0x0100&#41; != 0&#41;
	&#123;
		printf&#40;"VIF1 is not available for the Screen Shot\n"&#41;;
		exit&#40;-1&#41;;
	&#125;	
	
	// Enable generation of the FINISH Event &#40;GS Page 145&#41;
	DPUT_GS_CSR&#40; 2 &#41;; 
	
	// Disable interrupts so we don't lose our finish event
	asm __volatile__ &#40;"di"&#41;;

	
	// Make sure all cache is writen to main memory
	sps2FlushCache&#40;iSPS2Device&#41;;
	
	// Setup and start DMA transfer to VIF1
	*EE_D1_QWC = 0x7;
	*EE_D1_MADR = sps2GetPhysicalAddress&#40;pDmaBase, memScreenShot &#41;;
	//             DIR      MOD       ASP     TTE       TIE      STR
	*EE_D1_CHCR = &#40;1<<0&#41; | &#40;0<<2&#41; | &#40;0<<4&#41; | &#40;0<<6&#41; | &#40;0<<7&#41; | &#40;1<<8&#41;;

	// Wait till memory load is complete
	asm __volatile__&#40; " sync.l " &#41;;
	
	// Wait till DMA is complete &#40;STR=0&#41;
	while &#40; *EE_D1_CHCR & 0x0100 &#41;;

	// Wait for the GS to finish loading the registers &#40;FINISH EVENT&#41;
	//while &#40; &#40;&#40;*GS_CSR_OFF&#40;SPS2_GS_REGISTERS_START&#41;&#41; & 2&#41; == 0 &#41;; 
	while &#40; &#40;*_GS_CSR & 2&#41; == 0 &#41;;
	
	// Re-enable interrupts
	asm __volatile__ &#40;"ei"&#41;;
	
	
	// START! The actual download to memory 
	// wait for VIF1-FIFO to empty and become idle 
	while&#40;*EE_VIF1_STAT & 0x1f000003&#41;; 
	
	// Change the VIF1 direction to VIF1->Memory
	*&#40;&#40;volatile uint32 *&#41; EE_VIF1_STAT&#41; = &#40;1<<23&#41;;
	
	// Change direction of VIF1 FIF0 Local->Host
	DPUT_GS_BUSDIR&#40; &#40; uint64 &#41; 0x00000001 &#41;;
	
	// Setup and start DMA transfer from VIF1
	*EE_D1_QWC = uQSize;
	*EE_D1_MADR = sps2GetPhysicalAddress&#40;pMemBase, memScreenShot&#41;;
	//          DIR    MOD       ASP     TTE       TIE      STR
	*EE_D1_CHCR = 0 | &#40;0<<2&#41; | &#40;0<<4&#41; | &#40;0<<6&#41; | &#40;0<<7&#41; | &#40;1<<8&#41;;

	// Wait till memory load is complete
	asm __volatile__&#40; " sync.l " &#41;;

	// check if DMA is complete &#40;STR=0&#41;
	while &#40; *EE_D1_CHCR & 0x0100 &#41;;
	
	// Restore CHCR and wait for it to complete
	*EE_D1_CHCR = prev_chcr;
	asm __volatile__&#40; " sync.l " &#41;;
	
	// wait for VIF1-FIFO to empty and become idle 
	while &#40; *EE_VIF1_STAT & 0x1f000003 &#41;; 

	
	// Change the VIF1 and VIF1 FIFO Direction back to normal
	*&#40;&#40;volatile uint32 *&#41; EE_VIF1_STAT&#41; = 0;
	DPUT_GS_BUSDIR&#40; &#40; uint64 &#41; 0 &#41;;
	
	
	// restore the setting of IMR
	DPUT_GS_IMR&#40; prev_imr&#41;;
	// set the FINISH event to default
	//dput_gs_csr&#40; GS_EE_CSR_FINISH_M &#41;;
	DPUT_GS_CSR&#40; 2 &#41;; 
	
	
	
	// Re-enable path3 transfers
	static uint32 enable_path3&#91;4&#93; ALIGN_QW = &#123;
	0x06000000, //MSKPATH3&#40;0&#41;,
	0,
	0,
	0&#125;;

	DPUT_EE_VIF1_FIFO&#40; *&#40; uint128 * &#41; enable_path3 &#41;;

	// Make sure data is written to main memory
	sps2FlushCache&#40;iSPS2Device&#41;;
&#125;
Panajev2001a
Posts: 100
Joined: Sat Aug 20, 2005 3:25 am

Post by Panajev2001a »

Here:

Code: Select all

char name&#91;256&#93;;

static int m_SS_Number = 0;

sprintf &#40;name, "_%05d.png", m_SS_Number&#41;; 

strcat &#40;filename, name&#41;;
        
fp = fopen&#40;filename, "wb"&#41;;
(I am testing it as we speak, it should work)

Conceptually, now writing proper C++ code is another matter... lol, I am hungry... need to feeeeed :).

The "filename" string needs now to be passed as a char * not as a const char * data.

just one smaller fix and this should be sweet: the use of strcat is not so intelligent done this way as it keeps adding the same string to the filename, getting it longer and longer.
Last edited by Panajev2001a on Fri Sep 02, 2005 9:30 pm, edited 1 time in total.
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

Panajev2001a wrote:Here:

Code: Select all

char name&#91;256&#93;;

static int m_SS_Number = 0;

sprintf &#40;name, "_%05d.png", m_SS_Number&#41;; 

strcat &#40;filename, name&#41;;
        
fp = fopen&#40;filename, "wb"&#41;;
(I am testing it as we speak, it should work)
No, this will crash in most cases, because you are writing to "filename", which could be shorter than the required number of bytes. Use sprintf(name, "%s_%05d.png", filename, m_SS_Number) instead and then "name" instead of "filename" for creating the file. To be sure, use malloc for "name" and free at end and calculate the length based on strlen(filename).
Panajev2001a
Posts: 100
Joined: Sat Aug 20, 2005 3:25 am

Post by Panajev2001a »

Shine wrote:
Panajev2001a wrote:Here:

Code: Select all

char name&#91;256&#93;;

static int m_SS_Number = 0;

sprintf &#40;name, "_%05d.png", m_SS_Number&#41;; 

strcat &#40;filename, name&#41;;
        
fp = fopen&#40;filename, "wb"&#41;;
(I am testing it as we speak, it should work)
No, this will crash in most cases, because you are writing to "filename", which could be shorter than the required number of bytes. Use sprintf(name, "%s_%05d.png", filename, m_SS_Number) instead and then "name" instead of "filename" for creating the file. To be sure, use malloc for "name" and free at end and calculate the length based on strlen(filename).
Edit: yeah, thanks Shine :).
Shiki
Posts: 10
Joined: Fri Sep 02, 2005 10:33 am

Post by Shiki »

How effective is this code in taking frames in a row? I made a variation which boots another file and tried to take screenshots while there was an animation happening and the results left the shots distorted. Is there a way to buffer up the frames and then give it time to slowly save it in memory after a few frames are buffered up?
Panajev2001a
Posts: 100
Joined: Sat Aug 20, 2005 3:25 am

Post by Panajev2001a »

Shiki wrote:How effective is this code in taking frames in a row? I made a variation which boots another file and tried to take screenshots while there was an animation happening and the results left the shots distorted. Is there a way to buffer up the frames and then give it time to slowly save it in memory after a few frames are buffered up?
That is very strange, never happened to me on PS2... well I had an HDD and not a Flash memory I was writing to and the RAM -> HDD process was a tad faster too I'd think than the PSP RAM -> Memory Stick transfer.
Shiki
Posts: 10
Joined: Fri Sep 02, 2005 10:33 am

Post by Shiki »

Panajev2001a, I think I was refering to the main.c that Shine posted.

But you seem to know what I'm talking about too. The program's function saves the screens in lines of pixels at a time, if the screen is animated each line will be different from the previous screens lines. This distorts the picture.

I wanted to take a few shots in a row and try animated it in flash.
Shine
Posts: 728
Joined: Fri Dec 03, 2004 12:10 pm
Location: Germany

Post by Shine »

Shiki wrote:Panajev2001a, I think I was refering to the main.c that Shine posted.

But you seem to know what I'm talking about too. The program's function saves the screens in lines of pixels at a time, if the screen is animated each line will be different from the previous screens lines. This distorts the picture.

I wanted to take a few shots in a row and try animated it in flash.
In the libpng folder is a sample, how to save one image at once, which uses 522240 bytes instead of only one line with 1920 bytes. If this is ok for your application, you should try it, but I don't think that it helps much.

Perhaps a better idea would be to transfer it with FTP. Really nice would be to write a network driver, which lets you to connect to a Unix NFS drive from PSP and write to it like to memory stick :-)
Panajev2001a
Posts: 100
Joined: Sat Aug 20, 2005 3:25 am

Post by Panajev2001a »

Shiki wrote:Panajev2001a, I think I was refering to the main.c that Shine posted.

But you seem to know what I'm talking about too. The program's function saves the screens in lines of pixels at a time, if the screen is animated each line will be different from the previous screens lines. This distorts the picture.

I wanted to take a few shots in a row and try animated it in flash.
Umph, that still should not be a problem.

Unless you write to the Display/Front-buffer I fail to see how this affects anything.

Let's go over what happens (how I see it anyway heh).

1.) You render the scene in the Draw/Back-buffer.

2.) Back and Front buffers are swapped (SwapBuffers ())

3.) Read from the Front-buffer while it is being displayed into the file (screenshot (...)).

4.) while the screenshot is being taken, your application is working on the next frame of animation rendering it into the "current" Back-buffer.

5.) go back to 2.)

Unless the screenshot (...) function reads from the buffer for a time longer than Vblank + 1 frame_time... there should not be any problems.

Something could be done if you saved the image in RAM and after that you wrote it to a file... adding a mid-step which would allow your function to take a little longer effectively pipelining things.


Edit: are you maybe taking the screenshot taking data from the back-buffer before the switch ? (it would be strange as his function seems to obtain from PSPSDK's libs the DisplayBuffer)
Post Reply