ref: 3191e80bf7fda36bf0c951b0363cd52fa6ceac6b
dir: /i_video.c/
/* i_video.c */
#include "h2stdinc.h"
#include "doomdef.h"
#include "i_system.h"
extern byte *screens;
int DisplayTicker = 0;
int UpdateState = 0;
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
static int resized;
static int mouseactive;
extern int usemouse;
static Rectangle grabout;
static Point center;
static void kbdproc(void);
static void mouseproc(void);
static uchar cmap[3*256];
static int kbdpid = -1;
static int mousepid = -1;
static Image *backtile = nil;
static uchar tiledata[4096*3];
static void
catch(void *, char *msg)
{
/* in case we crash, disable mouse grab */
if(strncmp(msg, "sys:", 4) == 0)
mouseactive = 0;
noted(NDFLT);
}
static void I_UpdateTile(void)
{
uchar *s, *d, *m;
uchar *e;
if(backtile == nil){
if(shareware)
s = W_CacheLumpName ("FLOOR04", PU_CACHE);
else
s = W_CacheLumpName ("FLAT513", PU_CACHE);
d = tiledata;
e = s + 4096;
for(; s < e; s++){
m = &cmap[*s * 3];
*d++ = m[2];
*d++ = m[1];
*d++ = m[0];
}
backtile = allocimage(display, Rect(0, 0, 64, 64), RGB24, 1, DNofill);
loadimage(backtile, backtile->r, tiledata, sizeof tiledata);
if(backtile == nil)
sysfatal("allocimage: %r");
}
draw(screen, screen->r, backtile, nil, ZP);
}
void I_InitGraphics(void)
{
int pid;
notify(catch);
if(initdraw(nil, nil, "heretic") < 0)
I_Error("I_InitGraphics failed");
I_SetPalette ((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE));
I_UpdateTile();
center = addpt(screen->r.min, Pt(Dx(screen->r)/2, Dy(screen->r)/2));
grabout = insetrect(screen->r, Dx(screen->r)/8);
if((pid = rfork(RFPROC|RFMEM)) == 0){
kbdproc();
exits(nil);
}
kbdpid = pid;
if((pid = rfork(RFPROC|RFMEM)) == 0){
mouseproc();
exits(nil);
}
mousepid = pid;
}
void I_ShutdownGraphics(void)
{
if(kbdpid != -1){
postnote(PNPROC, kbdpid, "shutdown");
kbdpid = -1;
}
if(mousepid != -1){
postnote(PNPROC, mousepid, "shutdown");
mousepid = -1;
}
}
void I_SetPalette(byte *palette)
{
uchar *c;
c = cmap;
while(c < cmap+3*256)
*c++ = gammatable[usegamma][*palette++];
}
void I_UpdateNoBlit(void)
{
// DELETEME?
}
void I_StartFrame(void)
{
}
void I_Update(void)
{
Image *rowimg;
Rectangle r;
int y, scale;
uchar *s, *e, *d, *m;
uchar buf[SCREENWIDTH*3*12];
if(UpdateState == I_NOUPDATE)
return;
if(resized){
resized = 0;
if(getwindow(display, Refnone) < 0)
sysfatal("getwindow: %r");
I_UpdateTile();
center = addpt(screen->r.min, Pt(Dx(screen->r)/2, Dy(screen->r)/2));
grabout = insetrect(screen->r, Dx(screen->r)/8);
}
scale = Dx(screen->r)/SCREENWIDTH;
if(scale <= 0)
scale = 1;
else if(scale > 12)
scale = 12;
if (UpdateState & I_FULLSCRN){
UpdateState = I_NOUPDATE;
}
/* where to draw the scaled row */
r = rectsubpt(rectaddpt(Rect(0, 0, scale*SCREENWIDTH, scale), center),
Pt(scale*SCREENWIDTH/2, scale*SCREENHEIGHT/2));
/* the row image, y-axis gets scaled with repl flag */
rowimg = allocimage(display, Rect(0, 0, scale*SCREENWIDTH, 1), RGB24, scale > 1, DNofill);
if(rowimg == nil)
sysfatal("allocimage: %r");
s = screens;
for(y = 0; y < SCREENHEIGHT; y++){
d = buf;
e = s + SCREENWIDTH;
for(; s < e; s++){
m = &cmap[*s * 3];
switch(scale){
case 12:
*d++ = m[2];
*d++ = m[1];
*d++ = m[0];
case 11:
*d++ = m[2];
*d++ = m[1];
*d++ = m[0];
case 10:
*d++ = m[2];
*d++ = m[1];
*d++ = m[0];
case 9:
*d++ = m[2];
*d++ = m[1];
*d++ = m[0];
case 8:
*d++ = m[2];
*d++ = m[1];
*d++ = m[0];
case 7:
*d++ = m[2];
*d++ = m[1];
*d++ = m[0];
case 6:
*d++ = m[2];
*d++ = m[1];
*d++ = m[0];
case 5:
*d++ = m[2];
*d++ = m[1];
*d++ = m[0];
case 4:
*d++ = m[2];
*d++ = m[1];
*d++ = m[0];
case 3:
*d++ = m[2];
*d++ = m[1];
*d++ = m[0];
case 2:
*d++ = m[2];
*d++ = m[1];
*d++ = m[0];
case 1:
*d++ = m[2];
*d++ = m[1];
*d++ = m[0];
}
}
loadimage(rowimg, rowimg->r, buf, d - buf);
draw(screen, r, rowimg, nil, ZP);
r.min.y += scale;
r.max.y += scale;
}
freeimage(rowimg);
flushimage(display, 1);
}
void I_MouseEnable(int on)
{
static char nocurs[2*4+2*2*16];
static int fd = -1;
if(mouseactive == on || !usemouse)
return;
if(mouseactive = on){
if((fd = open("/dev/cursor", ORDWR|OCEXEC)) < 0)
return;
write(fd, nocurs, sizeof(nocurs));
}else if(fd >= 0) {
close(fd);
fd = -1;
}
}
void I_ReadScreen(byte *scr)
{
memcpy (scr, screens, SCREENWIDTH*SCREENHEIGHT);
}
void I_BeginRead(void)
{
I_Error("PORTME i_video.c I_BeginRead");
}
void I_EndRead(void)
{
I_Error("PORTME i_video.c I_EndRead");
}
void I_StartTic(void)
{
}
void I_WaitVBL(int)
{
}
static int
runetokey(Rune r)
{
switch(r){
case Kleft:
return KEY_LEFTARROW;
case Kright:
return KEY_RIGHTARROW;
case Kup:
return KEY_UPARROW;
case Kdown:
return KEY_DOWNARROW;
case Kshift:
return KEY_RSHIFT;
case Kctl:
return KEY_RCTRL;
case Kalt:
return KEY_LALT;
case Kaltgr:
return KEY_RALT;
case Kbs:
return KEY_BACKSPACE;
case '\n':
return KEY_ENTER;
case Kprint:
return KEY_PAUSE;
case KF|1:
case KF|2:
case KF|3:
case KF|4:
case KF|5:
case KF|6:
case KF|7:
case KF|8:
case KF|9:
case KF|10:
case KF|11:
case KF|12:
return KEY_F1+(r-(KF|1));
default:
if(r < 0x80)
return r;
}
return 0;
}
static int
keytorune(int key)
{
switch(key){
case KEY_LEFTARROW:
return Kleft;
case KEY_RIGHTARROW:
return Kright;
case KEY_UPARROW:
return Kup;
case KEY_DOWNARROW:
return Kdown;
case KEY_RSHIFT:
return Kshift;
case KEY_RCTRL:
return Kctl;
case KEY_LALT:
return Kalt;
case KEY_BACKSPACE:
return Kbs;
case KEY_ENTER:
return '\n';
case KEY_PAUSE:
return Kprint;
case KEY_F1:
case KEY_F2:
case KEY_F3:
case KEY_F4:
case KEY_F5:
case KEY_F6:
case KEY_F7:
case KEY_F8:
case KEY_F9:
case KEY_F10:
case KEY_F11:
case KEY_F12:
return (KF|1)+(key-KEY_F1);
default:
if(key < 0x80)
return key;
}
return 0;
}
static void
kbdproc(void)
{
static char keys[MAXKEYS];
char buf[128], *s, *p;
int kfd, n;
Rune r;
event_t e;
int i;
if((kfd = open("/dev/kbd", OREAD)) < 0)
sysfatal("can't open kbd: %r");
buf[0] = 0;
memset(keys, 0, sizeof keys);
procsetname("hexen kbdproc");
for(;;){
n = read(kfd, buf, sizeof(buf)-1);
if(n <= 0)
break;
buf[n] = 0;
e.data1 = -1;
e.data2 = -1;
e.data3 = -1;
for(p = buf; p - buf < n; p += strlen(p)+1){
switch(*p){
case 'c':
chartorune(&r, p+1);
if(r){
e.data1 = r;
e.type = ev_char;
D_PostEvent(&e);
}
/* no break */
default:
continue;
case 'k':
s = p+1;
while(*s){
s += chartorune(&r, s);
if((e.data1 = runetokey(r)) && keys[e.data1] == 0){
keys[e.data1] = 1;
e.type = ev_keydown;
D_PostEvent(&e);
}
}
break;
case 'K':
s = p+1;
for(i = 0; i < MAXKEYS; i++){
if(keys[i] == 0)
continue;
r = keytorune(i);
if(!utfrune(s, r)){
e.data1 = i;
keys[e.data1] = 0;
e.type = ev_keyup;
D_PostEvent(&e);
}
}
break;
}
}
}
}
static void
mouseproc(void)
{
int fd, n, nerr;
Mouse m, om;
char buf[1+5*12];
event_t e;
if((fd = open("/dev/mouse", ORDWR)) < 0)
sysfatal("can't open mouse: %r");
memset(&m, 0, sizeof m);
memset(&om, 0, sizeof om);
nerr = 0;
for(;;){
n = read(fd, buf, sizeof buf);
if(n != 1+4*12){
fprint(2, "mouse: bad count %d not 49: %r\n", n);
if(n<0 || ++nerr>10)
break;
continue;
}
nerr = 0;
switch(buf[0]){
case 'r':
resized = 1;
/* fall through */
case 'm':
if(!mouseactive)
break;
m.xy.x = atoi(buf+1+0*12);
m.xy.y = atoi(buf+1+1*12);
m.buttons = atoi(buf+1+2*12);
m.msec = atoi(buf+1+3*12);
if(!ptinrect(m.xy, grabout)){
fprint(fd, "m%d %d", center.x, center.y);
m.xy = center;
om.xy = center;
}
e.type = ev_mouse;
e.data1 = m.buttons;
e.data2 = m.xy.x - om.xy.x;
e.data3 = om.xy.y - m.xy.y;
D_PostEvent(&e);
om = m;
break;
}
}
}