shithub: qk2

ref: a4c4b45d8b2136733c76a4b86c7896bfa939ad25
dir: /vid.c/

View raw version
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <stdio.h>
#include <ctype.h>
#include "dat.h"
#include "fns.h"

refexport_t re;	/* exported functions from refresh DLL */
int resized, dumpwin;
Point center;
Rectangle grabr;

typedef ulong PIXEL;

static int rwon;
static uchar *fb;
static Image *fbi;
static s32int fbpal[256];

refexport_t GetRefAPI(refimport_t);


static void
drawfb(void)
{
	uchar *s;
	int n, we, w8, wr, *d, dy;

	we = vid.width - 1;
	w8 = vid.width + 7 >> 3;
	wr = vid.width % 8;
	dy = vid.height * vid.rowbytes;
	while((dy -= vid.rowbytes) >= 0){
		s = fb + dy;
		d = ((int *)s) + we;
		s += we;
		n = w8;
		switch(wr){
		case 0:	do{	*d-- = fbpal[*s--];
		case 7:		*d-- = fbpal[*s--];
		case 6:		*d-- = fbpal[*s--];
		case 5:		*d-- = fbpal[*s--];
		case 4:		*d-- = fbpal[*s--];
		case 3:		*d-- = fbpal[*s--];
		case 2:		*d-- = fbpal[*s--];
		case 1:		*d-- = fbpal[*s--];
			}while(--n > 0);
		}
	}
}

/* only exists to allow taking tear-free screenshots ingame... */
static int
writebit(void)
{
	int n, fd;
	char *s;

	mkdir(va("%s/scrnshot", ri.FS_Gamedir()));
	s = va("%s/scrnshot/quake.%d.bit", ri.FS_Gamedir(), time(nil));
	if(access(s, AEXIST) != -1){
		fprint(2, "writebit: not overwriting %s\n", s);
		return -1;
	}
	if(fd = create(s, OWRITE, 0644), fd < 0)
		return -1;
	n = writeimage(fd, fbi, 0);
	close(fd);
	if(n >= 0)
		ri.Con_Printf(PRINT_ALL, "Wrote %s\n", s);
	return n;
}

static void
resetfb(void)
{
	Point p;

	vid.width = Dx(screen->r);
	vid.height = Dy(screen->r);
	free(fb);
	fb = emalloc(vid.width * vid.height * sizeof *fbpal);
	freeimage(fbi);
	if((fbi = allocimage(display, Rect(0, 0, vid.width, vid.height), XRGB32, 0, 0)) == nil)
		sysfatal("allocimage: %r");
	vid.buffer = fb;
	vid.rowbytes = vid.width * sizeof *fbpal;
	center = addpt(screen->r.min, Pt(vid.width/2, vid.height/2));
	p = Pt(vid.width/4, vid.height/4);
	grabr = Rpt(subpt(center, p), addpt(center, p));
	sw_mode->modified = true;	/* make ref_soft refresh its shit */
}

void
flipfb(void)
{
	if(resized){
		resized = 0;
		if(getwindow(display, Refnone) < 0)
			sysfatal("getwindow: %r\n");
		resetfb();
		return;
	}
	drawfb();
	loadimage(fbi, fbi->r, fb, vid.height * vid.rowbytes);
	draw(screen, screen->r, fbi, nil, ZP);
	flushimage(display, 1);
	if(dumpwin){
		if(writebit() < 0)
			ri.Con_Printf(PRINT_ALL, "Could not write screenshot\n");
		dumpwin = 0;
	}
}

void
setpal(uchar *p)
{
	int *fp;

	if(p == nil)
        	p = (uchar *)sw_state.currentpalette;
	for(fp=fbpal; fp<fbpal+nelem(fbpal); p+=4)
		*fp++ = p[0] << 16 | p[1] << 8 | p[2];
}

void
VID_Printf(int print_level, char *fmt, ...)
{
	va_list argptr;
	char msg[4096];
	
	va_start(argptr, fmt);
	vsprintf(msg, fmt, argptr);
	va_end(argptr);
	if(print_level == PRINT_ALL)
		Com_Printf("%s", msg);
	else
		Com_DPrintf("%s", msg);
}

void
VID_Error(int err_level, char *fmt, ...)
{
	va_list argptr;
	char msg[4096];
	
	va_start(argptr, fmt);
	vsprintf(msg, fmt, argptr);
	va_end(argptr);
	Com_Error(err_level, "%s", msg);
}

void
initfb(void)
{
	refimport_t ri;

	if(initdraw(nil, nil, "quake2") < 0)
		sysfatal("VID_Init:initdraw: %r\n");
	vidref_val = VIDREF_SOFT;
	ri.Cmd_AddCommand = Cmd_AddCommand;
	ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
	ri.Cmd_Argc = Cmd_Argc;
	ri.Cmd_Argv = Cmd_Argv;
	ri.Cmd_ExecuteText = Cbuf_ExecuteText;
	ri.Con_Printf = VID_Printf;
	ri.Sys_Error = VID_Error;
	ri.FS_LoadFile = FS_LoadFile;
	ri.FS_FreeFile = FS_FreeFile;
	ri.FS_Gamedir = FS_Gamedir;
	ri.Cvar_Get = Cvar_Get;
	ri.Cvar_Set = Cvar_Set;
	ri.Cvar_SetValue = Cvar_SetValue;
	ri.Vid_MenuInit = VID_MenuInit;

	re = GetRefAPI(ri);
	re.Init();
	resetfb();
}