shithub: qk1

Download patch

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);
 }
-
-