![]() |
|
A5 Screenshot Code: For Wiki? |
Billybob
Member #3,136
January 2003
|
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. 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
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}
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}
|
Evert
Member #794
November 2000
![]() |
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
![]() |
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
|
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.
|
kazzmir
Member #1,786
December 2001
![]() |
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
![]() |
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
|
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. Matthew Leverton said: It would be on the programmer to set the app name first. Well, anyway, I fixed the code to handle '.' in the gamename. Peter Wang said: Please don't use the al_ prefix.
Sorry EDIT: So, should this go on the Wiki, or is it complete garbage? I haven't tried to edit the wiki before ...
|
AMCerasoli
Member #11,955
May 2010
![]() |
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! -------------------------------------------------- My blog: http://joshuadover.tumblr.com |
Billybob
Member #3,136
January 2003
|
Cool 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...
|
Neil Walker
Member #210
April 2000
![]() |
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. wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
Better yet would be to make a separate category for Allegro 4 and Allegro 5. There's no reason to make Allegro 4 articles 'deprecated' or anything like that. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Neil Roy
Member #2,229
April 2002
![]() |
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
![]() |
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
![]() |
Guess my screenshot function will be horrible and windows only then. --- |
Billybob
Member #3,136
January 2003
|
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!
|
Neil Roy
Member #2,229
April 2002
![]() |
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
![]() |
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
![]() |
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
|
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.
|
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. ____________________________________________________________________________________________ |
Neil Roy
Member #2,229
April 2002
![]() |
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 --- |
|