Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » A5 Screenshot Code: For Wiki?

This thread is locked; no one can reply to it. rss feed Print
A5 Screenshot Code: For Wiki?
Billybob
Member #3,136
January 2003
avatar

I didn't see any Allegro 5 screenshot-ing code in the wiki, so I wrote some:

EDIT: Code was updated. Original is in spoiler at bottom of post.

#SelectExpand
1/////////////////////////////////////////////////////////////////////////////// 2// 3// Allegro 5 Screenshot Functions 4// 5// Usage: 6// 7// To save a screenshot Call: 8// ale_screenshot(const char *destination_path, const char *gamename) 9// 10// 11// If you simply want a screenshot to be saved when F12 is pressed, call: 12// 13// ale_screenshot_process_event(ALLEGRO_EVENT ev, const char *destination_path, const char *gamename) 14// 15// after receiving an Event, and the function will automatically check for the 16// key press. 17// 18/////////////////////////////////////////////////////////////////////////////// 19 20 21 22 23// Save a copy of the current target_bitmap (usually what's on the screen). 24// The screenshot is placed in `destination_path`. 25// The filename will follow the format "`gamename`-YYYYMMDD[a-z].png" 26// Where [a-z] starts at 'a' and increases (towards 'z') to prevent duplicates 27// on the same day. 28// This filename format allows for easy time-based sorting in a file manager, 29// even if the "Modified Date" or other file information is lost. 30// 31// Arguments: 32// `destination_path` - Where to put the screenshot. If NULL, uses 33// ALLEGRO_USER_DOCUMENTS_PATH. 34// 35// `gamename` - The name of your game (only use path-valid characters). 36// If NULL, uses al_get_app_name(). 37// 38// 39// Returns: 40// 0 on success, anything else on failure. 41inline int ale_screenshot(const char *destination_path, const char *gamename) 42{ 43 ALLEGRO_PATH *path; 44 char *filename, *filename_wp; 45 struct tm *tmp; 46 time_t t; 47 unsigned int i; 48 const char *path_cstr; 49 50 if(!destination_path) 51 path = al_get_standard_path(ALLEGRO_USER_DOCUMENTS_PATH); 52 else 53 path = al_create_path_for_directory(destination_path); 54 55 if(!path) 56 return -1; 57 58 if(!gamename) { 59 if( !(gamename = al_get_app_name()) ) { 60 al_destroy_path(path); 61 return -2; 62 } 63 } 64 65 t = time(0); 66 tmp = localtime(&t); 67 if(!tmp) { 68 al_destroy_path(path); 69 return -3; 70 } 71 72 // Length of gamename + length of "-YYYYMMDD" + length of maximum [a-z] + NULL terminator 73 if ( !(filename_wp = filename = (char *)malloc(strlen(gamename) + 9 + 2 + 1)) ) { 74 al_destroy_path(path); 75 return -4; 76 } 77 78 strcpy(filename, gamename); 79 // Skip to the '.' in the filename, or the end. 80 for(; *filename_wp != '.' && *filename_wp != 0; ++filename_wp); 81 82 *filename_wp++ = '-'; 83 if(strftime(filename_wp, 9, "%Y%m%d", tmp) != 8) { 84 free(filename); 85 al_destroy_path(path); 86 return -5; 87 } 88 filename_wp += 8; 89 90 for(i = 0; i < 26*26; ++i) { 91 if(i > 25) { 92 filename_wp[0] = (i / 26) + 'a'; 93 filename_wp[1] = (i % 26) + 'a'; 94 filename_wp[2] = 0; 95 } 96 else { 97 filename_wp[0] = (i % 26) + 'a'; 98 filename_wp[1] = 0; 99 } 100 101 al_set_path_filename(path, filename); 102 al_set_path_extension(path, ".png"); 103 path_cstr = al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP); 104 105 if (al_filename_exists(path_cstr)) 106 continue; 107 108 al_save_bitmap(path_cstr, al_get_target_bitmap()); 109 free(filename); 110 al_destroy_path(path); 111 return 0; 112 } 113 114 free(filename); 115 al_destroy_path(path); 116 117 return -6; 118} 119 120 121// Automatically calls ale_screenshot when F12 is pressed. 122// Returns 0 if a screenshot is saved, 1 if not, and anything else if an error occurs. 123inline int ale_screenshot_process_event(ALLEGRO_EVENT ev, const char *destination_path, const char *gamename) 124{ 125 if(ev.type != ALLEGRO_EVENT_KEY_DOWN) 126 return 1; 127 128 if(ev.keyboard.keycode != ALLEGRO_KEY_F12) 129 return 1; 130 131 return ale_screenshot(destination_path, gamename); 132}

It's supposed to be copy-paste-able, so other people can just drop it into their games and live the joys of screenshots.

It's used like this:

al_wait_for_event(event_queue, &ev);

ale_screenshot_process_event(ev, "screenshots/", "IonWave");

... the rest of your game logic ...

or

if(User clicks the screenshot button, or does a funny dance)
     ale_screenshot("screenshots/", "IonWave");

Works great for me! Should I put it on the wiki? Comments? Additions? Complaints?

Note: I tried to have the key be ALLEGRO_KEY_PRINTSCREEN, but that event never fired on my system. Of course, you're free to use whatever key you like.

Old Versions

#SelectExpand
1/////////////////////////////////////////////////////////////////////////////// 2// 3// Allegro 5 Screenshot Functions 4// 5// Usage: 6// 7// To save a screenshot Call: 8// al_screenshot(const char *destination_path, const char *gamename) 9// 10// 11// If you simply want a screenshot to be saved when F11 is pressed, call: 12// 13// al_screenshot_process_event(ALLEGRO_EVENT ev, const char *destination_path, const char *gamename) 14// 15// after receiving an Event, and the function will automatically check for the 16// key press. 17// 18/////////////////////////////////////////////////////////////////////////////// 19 20 21 22 23// Save a copy of the current target_bitmap (usually what's on the screen). 24// The screenshot is placed in `destination_path`. 25// The filename will follow the format "`gamename`-YYYYMMDD[a-z].png" 26// Where [a-z] starts at 'a' and increases (towards 'z') to prevent duplicates 27// on the same day. 28// This filename format allows for easy time-based sorting in a file manager, 29// even if the "Modified Date" or other file information is lost. 30// 31// Arguments: 32// `destination_path` - Where to put the screenshot. If NULL, uses 33// ALLEGRO_USER_DOCUMENTS_PATH. 34// 35// `gamename` - The name of your game (only use path-valid characters). 36// 37// 38// Returns: 39// 0 on success, anything else on failure. 40inline int al_screenshot(const char *destination_path, const char *gamename) 41{ 42 ALLEGRO_PATH *path; 43 size_t gamename_len; 44 char *filename; 45 struct tm *tmp; 46 time_t t; 47 unsigned int i; 48 const char *path_cstr; 49 50 if(destination_path == NULL) 51 path = al_get_standard_path(ALLEGRO_USER_DOCUMENTS_PATH); 52 else 53 path = al_create_path_for_directory(destination_path); 54 55 if(gamename == NULL) 56 return -1; 57 58 if(path == NULL) 59 return -2; 60 61 gamename_len = strlen(gamename); 62 t = time(NULL); 63 tmp = localtime(&t); 64 if(tmp == NULL) 65 return -3; 66 67 // Length of gamename + length of "-YYYYMMDD" + length of maximum [a-z] + NULL terminator 68 filename = (char *)malloc(gamename_len + 9 + 2 + 1); 69 if(filename == NULL) 70 return -4; 71 strcpy(filename, gamename); 72 filename[gamename_len] = '-'; 73 if(strftime(filename + gamename_len + 1, 9, "%Y%m%d", tmp) != 8) 74 return -5; 75 76 for(i = 0; i < 26*26; ++i) { 77 if(i > 25) { 78 filename[gamename_len+9] = (i / 26) + 'a'; 79 filename[gamename_len+10] = (i % 26) + 'a'; 80 filename[gamename_len+11] = 0; 81 } 82 else { 83 filename[gamename_len+9] = (i % 26) + 'a'; 84 filename[gamename_len+10] = 0; 85 } 86 87 al_set_path_filename(path, filename); 88 al_set_path_extension(path, ".png"); 89 path_cstr = al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP); 90 91 if (al_filename_exists(path_cstr)) 92 continue; 93 94 al_save_bitmap(path_cstr, al_get_target_bitmap()); 95 free(filename); 96 al_destroy_path(path); 97 return 0; 98 } 99 100 free(filename); 101 al_destroy_path(path); 102 103 return -6; 104} 105 106 107// Automatically calls al_screenshot when F11 is pressed. 108// Returns 0 if a screenshot is saved, 1 if not, and anything else if an error occurs. 109inline int al_screenshot_process_event(ALLEGRO_EVENT ev, const char *destination_path, const char *gamename) 110{ 111 if(ev.type != ALLEGRO_EVENT_KEY_DOWN) 112 return 1; 113 114 if(ev.keyboard.keycode != ALLEGRO_KEY_F11) 115 return 1; 116 117 return al_screenshot(destination_path, gamename); 118}

#SelectExpand
1 2 3// Call this during your event processing. 4// Takes a screenshot of your game when F11 is pressed. 5// Saves the screenshot to the folder specified by `destination_path` 6// Files are saved in the format: "`gamename`-YYYYMMDD[a-z].png" 7// Where [a-z] starts a, and increases (to prevent duplicates on the same day) 8// Using YYYYMMDD[a-z] means that the filenames sort correctly in a file viewer, 9// even if the "Date Modified" information gets messed up. 10inline void screenshoter_event(ALLEGRO_EVENT ev, const char *destination_path, const char *gamename) 11{ 12 ALLEGRO_FILE *fp; 13 ALLEGRO_PATH *path; 14 size_t gamename_len; 15 char *filename; 16 struct tm *tmp; 17 time_t t; 18 unsigned int i; 19 const char *path_cstr; 20 21 if(ev.type != ALLEGRO_EVENT_KEY_DOWN) 22 return; 23 24 if(ev.keyboard.keycode != ALLEGRO_KEY_F11) 25 return; 26 27 path = al_create_path_for_directory(destination_path); 28 29 gamename_len = strlen(gamename); 30 t = time(NULL); 31 tmp = localtime(&t); 32 if(tmp == NULL) 33 return; 34 35 // Length of gamename + length of "-YYYYMMDD" + length of maximum [a-z] + NULL terminator 36 filename = (char *)malloc(gamename_len + 9 + 2 + 1); 37 if(filename == NULL) 38 return; 39 strcpy(filename, gamename); 40 filename[gamename_len] = '-'; 41 if(strftime(filename + gamename_len + 1, 9, "%Y%m%d", tmp) != 8) 42 return; 43 44 for(i = 0; i < 26*26; ++i) { 45 if(i > 25) { 46 filename[gamename_len+9] = (i / 26) + 'a'; 47 filename[gamename_len+10] = (i % 26) + 'a'; 48 filename[gamename_len+11] = 0; 49 } 50 else { 51 filename[gamename_len+9] = (i % 26) + 'a'; 52 filename[gamename_len+10] = 0; 53 } 54 55 al_set_path_filename(path, filename); 56 al_set_path_extension(path, ".png"); 57 path_cstr = al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP); 58 59 fp = al_fopen(path_cstr, "rb"); 60 if(fp != NULL) { 61 al_fclose(fp); 62 continue; 63 } 64 65 al_save_bitmap(path_cstr, al_get_target_bitmap()); 66 break; 67 } 68 69 free(filename); 70 al_destroy_path(path); 71}

_________________________________________________
"God speed, my lonely angel."
Bitcoin | Bitcoin Ponzi Scheme

Evert
Member #794
November 2000
avatar

My main complaint/comment about that piece of code is that there doesn't seem to be a good reason for the function to take an ALLEGRO_EVENT. In fact, it's probably better if it doesn't, because as it is you can't "drop it in" as is if you want different ways to safe a screenshot. Cleaner, in my opinion, is to catch the relevant event in the main loop and then call the relevant function.

Matthew Leverton
Supreme Loser
January 1999
avatar

If the path is NULL, you could default to the ALLEGRO_USER_DOCUMENTS_PATH folder. If gamename is NULL, you could default to al_get_app_name().

You could use al_filename_exists().

Billybob
Member #3,136
January 2003
avatar

Thank you for the suggestions and comments!

I updated the code in the original post. Compiles and runs in my game (Allegro 5.0.0, MinGW).

I couldn't figure out a simple way to take adventage of al_get_app_name, since it can return the EXE's full filename (test.exe), and that would mess up the later call to al_set_path_extension(path, ".png"); (It would overwrite the timecode things)

I'll work on that a little bit more and post another update later.

Evert said:

My main complaint/comment about that piece of code is that there doesn't seem to be a good reason for the function to take an ALLEGRO_EVENT.

Fixed that too. Now there's two functions al_screenshot which just takes a path and name, and immediately takes the screenshot; and al_screenshot_process_event which is the convenience function that calls al_screenshot when F11 is pressed.

EDIT: Oh, also, it returns success codes now, so you can check that and have your game display "Screenshot taken" or something.

_________________________________________________
"God speed, my lonely angel."
Bitcoin | Bitcoin Ponzi Scheme

kazzmir
Member #1,786
December 2001
avatar

nitpick: a lot of people expect F11 to go into fullscreen mode. Maybe you should use F12 for screenshot.

Matthew Leverton
Supreme Loser
January 1999
avatar

Billybob said:

I couldn't figure out a simple way to take adventage of al_get_app_name, since it can return the EXE's full filename

It would be on the programmer to set the app name first.

But since al_get_app_name() returns a const char*, it wouldn't really be any extra effort for the programmer to pass that if he wanted.

Peter Wang
Member #23
April 2000

Please don't use the al_ prefix.

Billybob
Member #3,136
January 2003
avatar

Code updated again.

kazzmir said:

nitpick: a lot of people expect F11 to go into fullscreen mode. Maybe you should use F12 for screenshot.

Fixed.

It would be on the programmer to set the app name first.

Well, anyway, I fixed the code to handle '.' in the gamename.

Please don't use the al_ prefix.

Sorry :'( I've now changed it to ale_ simply because it's related to Allegro's functions and couldn't come up with a more appropriate prefix (feel free to suggest).

EDIT: So, should this go on the Wiki, or is it complete garbage? I haven't tried to edit the wiki before ...

_________________________________________________
"God speed, my lonely angel."
Bitcoin | Bitcoin Ponzi Scheme

AMCerasoli
Member #11,955
May 2010
avatar

It isn't garbge, put it on the wiki right away!

_Kronk_
Member #12,347
November 2010

I agree with amcerasoli. The more content the better!

--------------------------------------------------
"If only our dreams were fires to ignite, then we could let the whole world burn" -Emery

My blog: http://joshuadover.tumblr.com

Billybob
Member #3,136
January 2003
avatar

Cool 8-)
Alright I wrote a page on the wiki Allegro 5 Screenshot

I hope I did it right. So ... how do I link it from one of the categories and which category would it go under?

EDIT: Welp, I figured out how to put it in a category. It's just under Allegro for now...

_________________________________________________
"God speed, my lonely angel."
Bitcoin | Bitcoin Ponzi Scheme

Neil Walker
Member #210
April 2000
avatar

Do you not think it's confusing that the allegro wiki mixes A4 and A5 to the point where you are guessing which one you are reading (e.g. click on the 'examples' wiki entry).

Perhaps it's time to actively promote A5 and legacyise (a made-up word perhaps) A4; the best way being to make A4 wiki less prominent and make the wiki A5 focused? Just like in the allegro.cc home page where the entry point for 'Files' is allegro 5.

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

Edgar Reynaldo
Member #8,592
May 2007
avatar

Neil Roy
Member #2,229
April 2002
avatar

I kind of like the way World of Warcraft names their screenshots.

WoWScrnShot_010411_015003

You have whatever name you wish, followed by the MMDDYY_HHMMSS (although I prefer YYMMDD_HHMMSS myself, the files will then be listed in the right order in a directory). This gets rid of any limits on how many you can do in a day because they will never be over written and it makes it easy to know when you took the screenshot at a glance.

You could also simply do a "screenshot%d" or "screenshot%03d" and add on a number you increment for each shot.

The function prefix could also be "a5_screenshot" if you're looking for something that is easily recognizable other than "al_".

Edit: I would also prefer it to be automated so that nothing needs to be passed to the function, just have it get the executable filename, crop the ".exe" off of it, then save the screenshot into the same folder that the executable resides in, perhaps creating a "screenshots" folder if one doesn't exist and saving all screenshots in there.

Evert
Member #794
November 2000
avatar

Neil Roy said:

I would also prefer it to be automated so that nothing needs to be passed to the function, just have it get the executable filename, crop the ".exe" off of it, then save the screenshot into the same folder that the executable resides in, perhaps creating a "screenshots" folder if one doesn't exist and saving all screenshots in there.

Horrible idea in general. That's not the sort of behaviour you want to hard-code inside the function, because it's not portable.

Neil Roy
Member #2,229
April 2002
avatar

Guess my screenshot function will be horrible and windows only then. :P

Billybob
Member #3,136
January 2003
avatar

It's perfectly okay to write another wrapper function that does those things and then calls the underlying ale_screenshot function (everything except the different time-format).

I personally like the idea of having the screenshots folder being created automatically, but past some point I didn't want to bloat out my code. I'm hoping for it to be part-useful tool/part-useful learning guide. Too much complexity and it becomes hard to understand.

So yeah, if you do write a wrapper, put it on the Wiki. It can be another sub-section of the article I put up, or a separate article linked from the original.

And thanks for commenting on it regardless! 8-)

_________________________________________________
"God speed, my lonely angel."
Bitcoin | Bitcoin Ponzi Scheme

Neil Roy
Member #2,229
April 2002
avatar

Ah yes, for a learning tool, you definitely need to stick to just the basics. You can then perhaps gives tips for how the reader could expand it.

Evert
Member #794
November 2000
avatar

Neil Roy said:

Guess my screenshot function will be horrible and windows only then.

In Windows you can't be sure that you can write to the executable directory either. Allegro has a function for querying standard path locations.

Neil Roy
Member #2,229
April 2002
avatar

I'm curious, under which circumstances would an allegro game not be able to write to it's own directory?

Billybob
Member #3,136
January 2003
avatar

Neil Roy said:

I'm curious, under which circumstances would an allegro game not be able to write to it's own directory?

Installed in Program Files, and you're not admin.

_________________________________________________
"God speed, my lonely angel."
Bitcoin | Bitcoin Ponzi Scheme

Timorg
Member #2,028
March 2002

Under GNU/Linux, the executable may be installed to '/usr/bin', with its data stored at '/usr/share/mygame', then user files and configuration go to '~/.mygame'. The user will not have permissions to write to the executable or data directory.

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

Neil Roy
Member #2,229
April 2002
avatar

Well that explains why I don't install my games in program files and why I don't use Linux. :)

In my games, I make the default installation directory %userprofile%/GameName

Go to: