ref: 49eaf765f30cabeea15ce054636349f6db14b2ae
parent: 4605c9a98242a9d3e8e5f54f30b1cf27fc0ccba1
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Thu Dec 28 22:13:43 EST 2023
bring back "screenshot" command
--- a/fns.h
+++ b/fns.h
@@ -41,6 +41,8 @@
void* loadstklmp(char *, void *, int, int *);
void loadpoints(void);
FILE* openlmp(char *f, int *len);
+FILE* createfile(char *path);
+void removefile(char *path);
void dumpcfg(void);
void savnames(void);
int dumpsav(char*, char*);
@@ -61,6 +63,7 @@
char *lerr(void);
int sys_mkdir(char *path);
+char *sys_timestamp(void);
long sndqueued(void);
void sndstop(void);
--- a/fs.c
+++ b/fs.c
@@ -286,14 +286,17 @@
int r;
d = path;
- if(d == nil || *d == 0)
+ if(d == nil || *d == 0){
+ werrstr("mkpath: invalid path");
return -1;
+ }
if(*d == '/')
d++;
while(*d != 0){
if(*d == '/'){
*d = 0;
- r = sys_mkdir(path);
+ if((r = sys_mkdir(path)) != 0)
+ werrstr("mkpath: %s: %s", path, lerr());
*d = '/';
if(r < 0)
return -1;
@@ -300,7 +303,35 @@
}
d++;
}
- return sys_mkdir(path);
+ if(sys_mkdir(path) < 0){
+ werrstr("mkpath: %s: %s", path, lerr());
+ return -1;
+ }
+ return 0;
+}
+
+FILE *
+createfile(char *path)
+{
+ char *s;
+ int r;
+
+ path = va("%s/%s", fsdir, path);
+ if((s = strrchr(path, '/')) != nil){
+ *s = 0;
+ r = mkpath(path);
+ *s = '/';
+ if(r != 0)
+ return nil;
+ }
+
+ return fopen(path, "wb");
+}
+
+void
+removefile(char *path)
+{
+ remove(va("%s/%s", fsdir, path));
}
static void
--- a/i_tga.c
+++ b/i_tga.c
@@ -137,6 +137,38 @@
return p + h->pxsz;
}
+int
+TGA_Encode(byte **out, char *id, pixel_t *pix, int w, int h)
+{
+ int sz, n, i;
+ byte *p;
+
+ n = id == nil ? 0 : strlen(id);
+ sz = HeaderSize + n + w*h*3;
+ *out = p = emalloc(sz);
+ *p++ = n; /* idlen */
+ *p++ = 0; /* paltype */
+ *p++ = ImgTypeTrueColor; /* imgtype */
+ *p++ = 0; *p++ = 0; /* palfirst */
+ *p++ = 0; *p++ = 0; /* pallen */
+ *p++ = 0; /* palbpp */
+ *p++ = 0; *p++ = 0; /* ox */
+ *p++ = 0; *p++ = 0; /* oy */
+ *p++ = w & 0xff; *p++ = w>>8; /* w */
+ *p++ = h & 0xff; *p++ = h>>8; /* h */
+ *p++ = 24; /* bpp */
+ *p++ = FlagOriginTop; /* flags */
+ memmove(p, id, n); p += n; /* id */
+ n = w * h;
+ for(i = 0; i < n; i++){
+ *p++ = pix[i] >> 0;
+ *p++ = pix[i] >> 8;
+ *p++ = pix[i] >> 16;
+ }
+
+ return sz;
+}
+
qpic_t *
TGA_Decode(byte *in, int sz, bool *premult)
{
--- a/i_tga.h
+++ b/i_tga.h
@@ -1,1 +1,2 @@
+int TGA_Encode(byte **out, char *id, pixel_t *pix, int w, int h);
qpic_t *TGA_Decode(byte *in, int sz, bool *premultalpha);
--- a/pr_cmds.c
+++ b/pr_cmds.c
@@ -958,6 +958,7 @@
PR_RunError(pr, "PF_find: bad search string");
if((def = ED_FieldAtOfs(pr, f)) == nil)
PR_RunError(pr, "PF_find: invalid field offset %d", f);
+ USED(def);
// FIXME(sigrid): apparently this is common
//if(def->type != ev_string)
// Con_DPrintf("PF_find: not a string field: %s", PR_Str(pr, def->s_name));
--- a/qk1.c
+++ b/qk1.c
@@ -22,6 +22,23 @@
}
char *
+sys_timestamp(void)
+{
+ static char ts[32];
+ Tm *tm;
+ long t;
+
+ if((t = time(nil)) < 0 || (tm = localtime(t)) == nil)
+ return nil;
+ snprint(ts, sizeof(ts),
+ "%04d%02d%02d-%02d%02d%02d",
+ tm->year + 1900, tm->mon + 1, tm->mday, tm->hour, tm->min, tm->sec
+ );
+
+ return ts;
+}
+
+char *
lerr(void)
{
static char err[ERRMAX];
--- a/unix/qk1.c
+++ b/unix/qk1.c
@@ -12,7 +12,6 @@
lerr(void)
{
static char lasterrcopy[256];
-
if(*lasterr == 0 && errno != 0)
return strerror(errno);
strcpy(lasterrcopy, lasterr);
@@ -22,7 +21,24 @@
int
sys_mkdir(char *path)
{
- return mkdir(path, 0770);
+ return (mkdir(path, 0770) == 0 || errno == EEXIST) ? 0 : -1;
+}
+
+char *
+sys_timestamp(void)
+{
+ static char ts[32];
+ struct tm *tm;
+ time_t t;
+
+ if((t = time(nil)) == (time_t)-1 || (tm = localtime(&t)) == nil)
+ return nil;
+ snprint(ts, sizeof(ts),
+ "%04d%02d%02d-%02d%02d%02d",
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec
+ );
+
+ return ts;
}
int
--- a/view.c
+++ b/view.c
@@ -894,6 +894,39 @@
//============================================================================
+static void
+screenshot(void)
+{
+ static char opath[48];
+ static int pathcnt = 2;
+ char path[48], *t;
+ FILE *f;
+ byte *b;
+ int n;
+
+ if((t = sys_timestamp()) == nil){
+err:
+ Con_Printf("screenshot: %s\n", lerr());
+ return;
+ }
+ n = snprint(path, sizeof(path), "screenshots/%s.tga", t);
+ if(strncmp(opath, path, n-4) == 0)
+ snprint(path+n-4, sizeof(path)-(n-4), "x%d.tga", pathcnt++);
+ else
+ pathcnt = 2;
+ if((f = createfile(path)) == nil)
+ goto err;
+ if((n = TGA_Encode(&b, "qk1", vid.buffer, vid.width, vid.height)) > 0)
+ n = fwrite(b, n, 1, f);
+ free(b);
+ fclose(f);
+ if(n != 1){
+ removefile(path);
+ goto err;
+ }
+ strcpy(opath, path);
+}
+
/*
=============
V_Init
@@ -901,9 +934,10 @@
*/
void V_Init (void)
{
- Cmd_AddCommand ("v_cshift", V_cshift_f);
- Cmd_AddCommand ("bf", V_BonusFlash_f);
- Cmd_AddCommand ("centerview", V_StartPitchDrift);
+ Cmd_AddCommand("v_cshift", V_cshift_f);
+ Cmd_AddCommand("bf", V_BonusFlash_f);
+ Cmd_AddCommand("centerview", V_StartPitchDrift);
+ Cmd_AddCommand("screenshot", screenshot);
Cvar_RegisterVariable (&lcd_x);
Cvar_RegisterVariable (&lcd_yaw);
@@ -940,5 +974,3 @@
BuildGammaTable (1.0); // no gamma yet
Cvar_RegisterVariable (&v_gamma);
}
-
-