mirror of
https://git.code.sf.net/p/quake/newtree
synced 2024-11-29 23:32:16 +00:00
17ea696c0d
memory in software mode. This is now taken care of, the memory is now grabbed using calloc. On Unix systems and all systems using SDL, the default video memory is now 8MB. This should now be enough for almost everybody, unless you have some truly huge maps and boatloads of sounds. The minimum memory allowable is now down to 4MB, but complex maps and/or models can cause the game to quit -- not like this wasn't a problem already with the old 5.3MB lower limit, but there it is.
1015 lines
22 KiB
C
1015 lines
22 KiB
C
/*
|
|
vid_ggi.c
|
|
|
|
general LibGGI video driver
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
Copyright (C) 1999 Marcus Sundberg [mackan@stacken.kth.se]
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to:
|
|
|
|
Free Software Foundation, Inc.
|
|
59 Temple Place - Suite 330
|
|
Boston, MA 02111-1307, USA
|
|
|
|
$Id$
|
|
*/
|
|
|
|
#define _BSD
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ggi/ggi.h>
|
|
|
|
#include "bothdefs.h" // needed by: common.h, net.h, client.h
|
|
|
|
#include "quakedef.h"
|
|
|
|
#include "bspfile.h" // needed by: glquake.h
|
|
#include "vid.h"
|
|
#include "sys.h"
|
|
#include "mathlib.h" // needed by: protocol.h, render.h, client.h,
|
|
// modelgen.h, glmodel.h
|
|
#include "wad.h"
|
|
#include "draw.h"
|
|
#include "cvar.h"
|
|
#include "net.h" // needed by: client.h
|
|
#include "protocol.h" // needed by: client.h
|
|
#include "cmd.h"
|
|
#include "keys.h"
|
|
#include "sbar.h"
|
|
#include "sound.h"
|
|
#include "render.h" // needed by: client.h, gl_model.h, glquake.h
|
|
#include "client.h" // need cls in this file
|
|
#include "model.h" // needed by: glquake.h
|
|
#include "console.h"
|
|
#include "qendian.h"
|
|
#include "qargs.h"
|
|
#include "compat.h"
|
|
#include "d_local.h"
|
|
#include "input.h"
|
|
|
|
#include "joystick.h"
|
|
|
|
extern viddef_t vid; // global video state
|
|
unsigned short d_8to16table[256];
|
|
|
|
cvar_t *m_filter;
|
|
cvar_t *_windowed_mouse;
|
|
|
|
/* Unused */
|
|
int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar;
|
|
byte *VGA_pagebase;
|
|
|
|
#define NUM_STDBUTTONS 3
|
|
#define NUM_BUTTONS 10
|
|
|
|
static qboolean mouse_avail;
|
|
static float mouse_x, mouse_y;
|
|
static float old_mouse_x, old_mouse_y;
|
|
static int p_mouse_x, p_mouse_y;
|
|
static float old_windowed_mouse;
|
|
|
|
static ggi_visual_t ggivis = NULL;
|
|
static ggi_mode mode;
|
|
static const ggi_directbuffer *dbuf1 = NULL, *dbuf2 = NULL;
|
|
|
|
static uint8 *drawptr = NULL;
|
|
static void *frameptr[2] = { NULL, NULL };
|
|
static void *oneline = NULL;
|
|
static void *palette = NULL;
|
|
static int curframe = 0;
|
|
|
|
static int realwidth, realheight;
|
|
static int doublebuffer;
|
|
static int scale;
|
|
static int stride, drawstride;
|
|
static int pixelsize;
|
|
static int usedbuf, havedbuf;
|
|
|
|
int VID_options_items = 1;
|
|
|
|
static void
|
|
do_scale8(int xsize, int ysize, uint8 *dest, uint8 *src)
|
|
{
|
|
int i, j, destinc = stride*2-xsize*2;
|
|
for (j = 0; j < ysize; j++) {
|
|
for (i = 0; i < xsize; /* i is incremented below */) {
|
|
register uint32 pix1 = src[i++], pix2 = src[i++];
|
|
#ifdef GGI_LITTLE_ENDIAN
|
|
*((uint32 *) (dest + stride))
|
|
= *((uint32 *) dest)
|
|
= (pix1 | (pix1 << 8)
|
|
| (pix2 << 16) | (pix2 << 24));
|
|
#else
|
|
*((uint32 *) (dest + stride))
|
|
= *((uint32 *) dest)
|
|
= (pix2 | (pix2 << 8)
|
|
| (pix1 << 16) | (pix1 << 24));
|
|
#endif
|
|
dest += 4;
|
|
}
|
|
dest += destinc;
|
|
src += xsize;
|
|
}
|
|
}
|
|
|
|
static void
|
|
do_scale16(int xsize, int ysize, uint8 *dest, uint8 *src)
|
|
{
|
|
int i, j, destinc = stride*2-xsize*4;
|
|
uint16 *palptr = palette;
|
|
for (j = 0; j < ysize; j++) {
|
|
for (i = 0; i < xsize; /* i is incremented below */) {
|
|
register uint32 pixel = palptr[src[i++]];
|
|
*((uint32 *) (dest + stride))
|
|
= *((uint32 *) dest)
|
|
= pixel | (pixel << 16);
|
|
dest += 4;
|
|
}
|
|
dest += destinc;
|
|
src += xsize;
|
|
}
|
|
}
|
|
|
|
static void
|
|
do_scale32(int xsize, int ysize, uint8 *dest, uint8 *src)
|
|
{
|
|
int i, j, destinc = stride*2-xsize*8;
|
|
uint32 *palptr = palette;
|
|
for (j = 0; j < ysize; j++) {
|
|
for (i = 0; i < xsize; /* i is incremented below */) {
|
|
register uint32 pixel = palptr[src[i++]];
|
|
*((uint32 *) (dest + stride))
|
|
= *((uint32 *) (dest)) = pixel;
|
|
dest += 4;
|
|
*((uint32 *) (dest + stride))
|
|
= *((uint32 *) (dest)) = pixel;
|
|
dest += 4;
|
|
}
|
|
dest += destinc;
|
|
src += xsize;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
do_copy8(int xsize, int ysize, uint8 *dest, uint8 *src)
|
|
{
|
|
int i, j;
|
|
uint8 *palptr = palette;
|
|
|
|
for (j = 0; j < ysize; j++) {
|
|
for (i = 0; i < xsize; i++) {
|
|
dest[i] = palptr[src[i]];
|
|
}
|
|
dest += stride;
|
|
src += xsize;
|
|
}
|
|
}
|
|
|
|
static void
|
|
do_copy16(int xsize, int ysize, void *destptr, uint8 *src)
|
|
{
|
|
int i, j, destinc = (stride/2 - xsize)/2;
|
|
uint16 *palptr = palette;
|
|
uint32 *dest = destptr;
|
|
|
|
for (j = 0; j < ysize; j++) {
|
|
for (i = 0; i < xsize; /* i is incremented below */) {
|
|
register uint32 pixel = palptr[src[i++]];
|
|
#ifdef GGI_LITTLE_ENDIAN
|
|
*(dest++) = pixel | (palptr[src[i++]] << 16);
|
|
#else
|
|
*(dest++) = (palptr[src[i++]] << 16) | pixel;
|
|
#endif
|
|
}
|
|
dest += destinc;
|
|
src += xsize;
|
|
}
|
|
}
|
|
|
|
static void
|
|
do_copy32(int xsize, int ysize, uint32 *dest, uint8 *src)
|
|
{
|
|
int i, j, destinc = stride/4;
|
|
uint32 *palptr = palette;
|
|
|
|
for (j = 0; j < ysize; j++) {
|
|
for (i = 0; i < xsize; i++) {
|
|
dest[i] = palptr[src[i]];
|
|
}
|
|
dest += destinc;
|
|
src += xsize;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ResetFrameBuffer(void)
|
|
{
|
|
int tbuffersize, tcachesize;
|
|
void *vid_surfcache;
|
|
|
|
// Calculate the sizes we want first
|
|
tbuffersize = vid.width * vid.height * sizeof (*d_pzbuffer);
|
|
tcachesize = D_SurfaceCacheForRes(vid.width, vid.height);
|
|
|
|
// Free the old z-buffer
|
|
if (d_pzbuffer) {
|
|
free (d_pzbuffer);
|
|
d_pzbuffer = NULL;
|
|
}
|
|
|
|
// Free the old surface cache
|
|
vid_surfcache = D_SurfaceCacheAddress ();
|
|
if (vid_surfcache) {
|
|
D_FlushCaches ();
|
|
free (vid_surfcache);
|
|
vid_surfcache = NULL;
|
|
}
|
|
|
|
// Allocate the new z-buffer
|
|
d_pzbuffer = calloc (tbuffersize, 1);
|
|
if (!d_pzbuffer) {
|
|
Sys_Error ("Not enough memory for video mode\n");
|
|
}
|
|
|
|
// Allocate the new surface cache; free the z-buffer if we fail
|
|
vid_surfcache = calloc (tcachesize, 1);
|
|
if (!vid_surfcache) {
|
|
free (d_pzbuffer);
|
|
d_pzbuffer = NULL;
|
|
Sys_Error ("Not enough memory for video mode\n");
|
|
}
|
|
|
|
D_InitCaches (vid_surfcache, tcachesize);
|
|
}
|
|
|
|
|
|
// Called at startup to set up translation tables, takes 256 8 bit RGB values
|
|
// the palette data will go away after the call, so it must be copied off if
|
|
// the video driver will need it again
|
|
|
|
void
|
|
VID_Init (unsigned char *pal)
|
|
{
|
|
int pnum;
|
|
|
|
vid.width = GGI_AUTO;
|
|
vid.height = GGI_AUTO;
|
|
|
|
srandom(getpid());
|
|
|
|
if (ggiInit() < 0) {
|
|
Sys_Error("VID: Unable to init LibGGI\n");
|
|
}
|
|
ggivis = ggiOpen(NULL);
|
|
if (!ggivis) {
|
|
Sys_Error("VID: Unable to open default visual\n");
|
|
}
|
|
|
|
/* Go into async mode */
|
|
ggiSetFlags(ggivis, GGIFLAG_ASYNC);
|
|
|
|
/* check for command-line window size */
|
|
if ((pnum=COM_CheckParm("-winsize")))
|
|
{
|
|
if (pnum >= com_argc-2)
|
|
Sys_Error("VID: -winsize <width> <height>\n");
|
|
vid.width = atoi(com_argv[pnum+1]);
|
|
vid.height = atoi(com_argv[pnum+2]);
|
|
if (!vid.width || !vid.height)
|
|
Sys_Error("VID: Bad window width/height\n");
|
|
}
|
|
if ((pnum=COM_CheckParm("-width"))) {
|
|
if (pnum >= com_argc-1)
|
|
Sys_Error("VID: -width <width>\n");
|
|
vid.width = atoi(com_argv[pnum+1]);
|
|
if (!vid.width)
|
|
Sys_Error("VID: Bad window width\n");
|
|
}
|
|
if ((pnum=COM_CheckParm("-height"))) {
|
|
if (pnum >= com_argc-1)
|
|
Sys_Error("VID: -height <height>\n");
|
|
vid.height = atoi(com_argv[pnum+1]);
|
|
if (!vid.height)
|
|
Sys_Error("VID: Bad window height\n");
|
|
}
|
|
|
|
scale = COM_CheckParm("-scale");
|
|
|
|
/* specify a LibGGI mode */
|
|
if ((pnum=COM_CheckParm("-ggimode")))
|
|
{
|
|
if (pnum >= com_argc-1)
|
|
Sys_Error("VID: -ggimode <mode>\n");
|
|
ggiParseMode(com_argv[pnum+1], &mode);
|
|
} else {
|
|
/* This will give the default mode */
|
|
ggiParseMode("", &mode);
|
|
/* Now put in any parameters given above */
|
|
mode.visible.x = vid.width;
|
|
mode.visible.y = vid.height;
|
|
}
|
|
|
|
if (scale) {
|
|
mode.visible.x *= 2;
|
|
mode.visible.y *= 2;
|
|
}
|
|
|
|
/* We prefer 8 bit mode unless otherwise specified */
|
|
if (mode.graphtype == GT_AUTO) mode.graphtype = GT_8BIT;
|
|
|
|
/* We want double buffering if possible */
|
|
if (mode.frames == GGI_AUTO) {
|
|
ggi_mode tmpmode = mode;
|
|
|
|
tmpmode.frames = 2;
|
|
if (ggiCheckMode(ggivis, &tmpmode) == 0) {
|
|
mode = tmpmode;
|
|
} else {
|
|
tmpmode.frames = 2;
|
|
if (ggiCheckMode(ggivis, &tmpmode) == 0) {
|
|
mode = tmpmode;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ggiSetMode(ggivis, &mode) != 0) {
|
|
/* Try again with suggested mode */
|
|
if (ggiSetMode(ggivis, &mode) != 0) {
|
|
Sys_Error("VID: LibGGI can't set any modes!\n");
|
|
}
|
|
}
|
|
|
|
/* Pixel size must be 1, 2 or 4 bytes */
|
|
if (GT_SIZE(mode.graphtype) != 8 &&
|
|
GT_SIZE(mode.graphtype) != 16 &&
|
|
GT_SIZE(mode.graphtype) != 32) {
|
|
if (GT_SIZE(mode.graphtype) == 24) {
|
|
Sys_Error("VID: 24 bits per pixel not supported - try using the palemu target.\n");
|
|
} else {
|
|
Sys_Error("VID: %d bits per pixel not supported by GGI Quake.\n",
|
|
GT_SIZE(mode.graphtype));
|
|
}
|
|
}
|
|
|
|
realwidth = mode.visible.x;
|
|
realheight = mode.visible.y;
|
|
if (scale) {
|
|
vid.width = realwidth / 2;
|
|
vid.height = realheight / 2;
|
|
} else {
|
|
vid.width = realwidth;
|
|
vid.height = realheight;
|
|
}
|
|
|
|
if (mode.frames >= 2) doublebuffer = 1;
|
|
else doublebuffer = 0;
|
|
|
|
pixelsize = (GT_SIZE(mode.graphtype)+7) / 8;
|
|
if (mode.graphtype != GT_8BIT) {
|
|
if ((palette = malloc(pixelsize*256)) == NULL) {
|
|
Sys_Error("VID: Unable to allocate palette table\n");
|
|
}
|
|
}
|
|
|
|
VID_SetPalette(pal);
|
|
|
|
usedbuf = havedbuf = 0;
|
|
drawstride = vid.width;
|
|
stride = realwidth*pixelsize;
|
|
if ((dbuf1 = ggiDBGetBuffer(ggivis, 0)) != NULL &&
|
|
(dbuf1->type & GGI_DB_SIMPLE_PLB)) {
|
|
havedbuf = 1;
|
|
stride = dbuf1->buffer.plb.stride;
|
|
if (doublebuffer) {
|
|
if ((dbuf2 = ggiDBGetBuffer(ggivis, 1)) == NULL ||
|
|
!(dbuf2->type & GGI_DB_SIMPLE_PLB)) {
|
|
/* Only one DB? No double buffering then */
|
|
doublebuffer = 0;
|
|
}
|
|
}
|
|
if (doublebuffer) {
|
|
fprintf(stderr, "VID: Got two DirectBuffers\n");
|
|
} else {
|
|
fprintf(stderr, "VID: Got one DirectBuffer\n");
|
|
}
|
|
if (doublebuffer && !scale && !palette) {
|
|
usedbuf = 1;
|
|
drawstride = stride;
|
|
frameptr[0] = dbuf1->write;
|
|
if (doublebuffer) {
|
|
frameptr[1] = dbuf2->write;
|
|
} else {
|
|
frameptr[1] = frameptr[0];
|
|
}
|
|
drawptr = frameptr[0];
|
|
fprintf(stderr, "VID: Drawing into DirectBuffer\n");
|
|
}
|
|
}
|
|
|
|
if (!usedbuf) {
|
|
if ((drawptr = malloc(vid.width * vid.height)) == NULL) {
|
|
Sys_Error("VID: Unable to allocate draw buffer\n");
|
|
}
|
|
if (!havedbuf && (scale || palette)) {
|
|
int linesize = pixelsize*realwidth;
|
|
if (scale) linesize *= 4;
|
|
if ((oneline = malloc(linesize)) == NULL) {
|
|
Sys_Error("VID: Unable to allocate line buffer\n");
|
|
}
|
|
}
|
|
fprintf(stderr,
|
|
"VID: Drawing into offscreen memory\n");
|
|
}
|
|
|
|
ResetFrameBuffer();
|
|
|
|
curframe = 0;
|
|
vid.maxwarpwidth = WARP_WIDTH;
|
|
vid.maxwarpheight = WARP_HEIGHT;
|
|
vid.numpages = doublebuffer ? 2 : 1;
|
|
vid.colormap = host_colormap;
|
|
vid.buffer = drawptr;
|
|
vid.rowbytes = drawstride;
|
|
vid.direct = drawptr;
|
|
vid.conbuffer = vid.buffer;
|
|
vid.conrowbytes = vid.rowbytes;
|
|
vid.conwidth = vid.width;
|
|
vid.conheight = vid.height;
|
|
vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0);
|
|
vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048));
|
|
}
|
|
|
|
void
|
|
VID_ShiftPalette(unsigned char *pal)
|
|
{
|
|
VID_SetPalette(pal);
|
|
}
|
|
|
|
|
|
void
|
|
VID_SetPalette (unsigned char *pal)
|
|
{
|
|
|
|
int i;
|
|
ggi_color colors[256];
|
|
|
|
for (i=0 ; i<256 ; i++) {
|
|
colors[i].r = pal[i*3] * 257;
|
|
colors[i].g = pal[i*3+1] * 257;
|
|
colors[i].b = pal[i*3+2] * 257;
|
|
}
|
|
if (palette) {
|
|
ggiPackColors(ggivis, palette, colors, 256);
|
|
} else {
|
|
ggiSetPalette(ggivis, 0, 256, colors);
|
|
}
|
|
}
|
|
|
|
// Called at shutdown
|
|
|
|
void
|
|
VID_Shutdown (void)
|
|
{
|
|
Con_Printf("VID_Shutdown\n");
|
|
|
|
if (!usedbuf) {
|
|
free(drawptr);
|
|
drawptr = NULL;
|
|
}
|
|
if (oneline) {
|
|
free(oneline);
|
|
oneline = NULL;
|
|
}
|
|
if (palette) {
|
|
free(palette);
|
|
palette = NULL;
|
|
}
|
|
if (ggivis) {
|
|
ggiClose(ggivis);
|
|
ggivis = NULL;
|
|
}
|
|
ggiExit();
|
|
}
|
|
|
|
|
|
// flushes the given rectangles from the view buffer to the screen
|
|
|
|
void
|
|
VID_Update (vrect_t *rects)
|
|
{
|
|
int height = 0;
|
|
|
|
#if 0
|
|
// if the window changes dimension, skip this frame
|
|
|
|
if (config_notify)
|
|
{
|
|
fprintf(stderr, "config notify\n");
|
|
config_notify = 0;
|
|
vid.width = config_notify_width & ~7;
|
|
vid.height = config_notify_height;
|
|
if (doShm)
|
|
ResetSharedFrameBuffers();
|
|
else
|
|
ResetFrameBuffer();
|
|
vid.rowbytes = x_framebuffer[0]->bytes_per_line;
|
|
vid.buffer = x_framebuffer[curframe]->data;
|
|
vid.conbuffer = vid.buffer;
|
|
vid.conwidth = vid.width;
|
|
vid.conheight = vid.height;
|
|
vid.conrowbytes = vid.rowbytes;
|
|
vid.recalc_refdef = 1; // force a surface cache flush
|
|
Con_CheckResize();
|
|
Con_Clear_f();
|
|
return;
|
|
}
|
|
|
|
// force full update if not 8bit
|
|
if (x_visinfo->depth != 8) {
|
|
extern int scr_fullupdate;
|
|
|
|
scr_fullupdate = 0;
|
|
}
|
|
#endif
|
|
|
|
while (rects) {
|
|
int y = rects->y + rects->height;
|
|
if (y > height) height = y;
|
|
rects = rects->pnext;
|
|
}
|
|
|
|
if (!usedbuf) {
|
|
int i;
|
|
|
|
if (havedbuf) {
|
|
if (ggiResourceAcquire(dbuf1->resource,
|
|
GGI_ACTYPE_WRITE) != 0 ||
|
|
(doublebuffer ?
|
|
ggiResourceAcquire(dbuf2->resource,
|
|
GGI_ACTYPE_WRITE) != 0
|
|
: 0)) {
|
|
ggiPanic("Unable to acquire DirectBuffer!\n");
|
|
}
|
|
/* ->write is allowed to change at acquire time */
|
|
frameptr[0] = dbuf1->write;
|
|
if (doublebuffer) {
|
|
frameptr[1] = dbuf2->write;
|
|
} else {
|
|
frameptr[1] = frameptr[0];
|
|
}
|
|
}
|
|
if (scale) {
|
|
switch (pixelsize) {
|
|
case 1: if (havedbuf) {
|
|
do_scale8(vid.width, height,
|
|
frameptr[curframe], drawptr);
|
|
} else {
|
|
uint8 *buf = drawptr;
|
|
for (i=0; i < height; i++) {
|
|
do_scale8(vid.width, 1, oneline,buf);
|
|
ggiPutBox(ggivis, 0, i*2, realwidth,
|
|
2, oneline);
|
|
buf += vid.width;
|
|
}
|
|
}
|
|
break;
|
|
case 2: if (havedbuf) {
|
|
do_scale16(vid.width, height,
|
|
frameptr[curframe], drawptr);
|
|
} else {
|
|
uint8 *buf = drawptr;
|
|
for (i=0; i < height; i++) {
|
|
do_scale16(vid.width, 1,
|
|
oneline, buf);
|
|
ggiPutBox(ggivis, 0, i*2, realwidth,
|
|
2, oneline);
|
|
buf += vid.width;
|
|
}
|
|
}
|
|
break;
|
|
case 4: if (havedbuf) {
|
|
do_scale32(vid.width, height,
|
|
frameptr[curframe], drawptr);
|
|
} else {
|
|
uint8 *buf = drawptr;
|
|
for (i=0; i < height; i++) {
|
|
do_scale32(vid.width, 1,
|
|
oneline, buf);
|
|
ggiPutBox(ggivis, 0, i*2, realwidth,
|
|
2, oneline);
|
|
buf += vid.width;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
} else if (palette) {
|
|
switch (pixelsize) {
|
|
case 1: if (havedbuf) {
|
|
do_copy8(vid.width, height,
|
|
frameptr[curframe], drawptr);
|
|
} else {
|
|
uint8 *buf = drawptr;
|
|
for (i=0; i < height; i++) {
|
|
do_copy8(vid.width, 1, oneline,buf);
|
|
ggiPutBox(ggivis, 0, i, realwidth,
|
|
1, oneline);
|
|
buf += vid.width;
|
|
}
|
|
}
|
|
break;
|
|
case 2: if (havedbuf) {
|
|
do_copy16(vid.width, height,
|
|
frameptr[curframe], drawptr);
|
|
} else {
|
|
uint8 *buf = drawptr;
|
|
for (i=0; i < height; i++) {
|
|
do_copy16(vid.width, 1,
|
|
oneline, buf);
|
|
ggiPutBox(ggivis, 0, i, realwidth,
|
|
1, oneline);
|
|
buf += vid.width;
|
|
}
|
|
}
|
|
break;
|
|
case 4: if (havedbuf) {
|
|
do_copy32(vid.width, height,
|
|
frameptr[curframe], drawptr);
|
|
} else {
|
|
uint8 *buf = drawptr;
|
|
for (i=0; i < height; i++) {
|
|
do_copy32(vid.width, 1,
|
|
oneline, buf);
|
|
ggiPutBox(ggivis, 0, i, realwidth,
|
|
1, oneline);
|
|
buf += vid.width;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
ggiPutBox(ggivis, 0, 0, vid.width, height,
|
|
drawptr);
|
|
}
|
|
if (havedbuf) {
|
|
ggiResourceRelease(dbuf1->resource);
|
|
if (doublebuffer) {
|
|
ggiResourceRelease(dbuf2->resource);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (doublebuffer) {
|
|
ggiSetDisplayFrame(ggivis, curframe);
|
|
curframe = !curframe;
|
|
if (usedbuf) {
|
|
vid.buffer = vid.conbuffer = vid.direct
|
|
= drawptr = frameptr[curframe];
|
|
}
|
|
ggiSetWriteFrame(ggivis, curframe);
|
|
}
|
|
|
|
#if 0
|
|
if (GT_SIZE(mode.graphtype) == 16) {
|
|
do_copy16(vid.width, height,
|
|
(uint16*)frameptr, drawptr);
|
|
} else if (GT_SIZE(mode.graphtype) == 32) {
|
|
do_copy32(vid.width, height,
|
|
(uint32*)frameptr, drawptr);
|
|
}
|
|
#endif
|
|
|
|
ggiFlush(ggivis);
|
|
}
|
|
|
|
void D_BeginDirectRect(int x, int y, byte *pbitmap, int width, int height)
|
|
{
|
|
// direct drawing of the "accessing disk" icon isn't supported under Linux
|
|
}
|
|
|
|
void D_EndDirectRect (int x, int y, int width, int height)
|
|
{
|
|
// direct drawing of the "accessing disk" icon isn't supported under Linux
|
|
}
|
|
|
|
|
|
/*
|
|
***************************************************************************
|
|
Input handling
|
|
***************************************************************************
|
|
*/
|
|
|
|
static int XLateKey(ggi_key_event *ev)
|
|
{
|
|
int key = 0;
|
|
|
|
if (GII_KTYP(ev->label) == GII_KT_DEAD) {
|
|
ev->label = GII_KVAL(ev->label);
|
|
}
|
|
switch(ev->label) {
|
|
case GIIK_P9: key = KP_PGUP; break;
|
|
case GIIK_PageUp: key = K_PGUP; break;
|
|
|
|
case GIIK_P3: key = KP_PGDN; break;
|
|
case GIIK_PageDown: key = K_PGDN; break;
|
|
|
|
case GIIK_P7: key = KP_HOME; break;
|
|
case GIIK_Home: key = K_HOME; break;
|
|
|
|
case GIIK_P1: key = KP_END; break;
|
|
case GIIK_End: key = K_END; break;
|
|
|
|
case GIIK_P4: key = KP_LEFTARROW; break;
|
|
case GIIK_Left: key = K_LEFTARROW; break;
|
|
|
|
case GIIK_P6: key = KP_RIGHTARROW; break;
|
|
case GIIK_Right: key = K_RIGHTARROW; break;
|
|
|
|
case GIIK_P2: key = KP_DOWNARROW; break;
|
|
case GIIK_Down: key = K_DOWNARROW; break;
|
|
|
|
case GIIK_P8: key = KP_UPARROW; break;
|
|
case GIIK_Up: key = K_UPARROW; break;
|
|
|
|
case GIIK_P5: key = KP_5; break;
|
|
case GIIK_PBegin: key = K_AUX32; break;
|
|
|
|
case GIIK_P0: key = KP_INS; break;
|
|
case GIIK_Insert: key = K_INS; break;
|
|
|
|
case GIIK_PSeparator:
|
|
case GIIK_PDecimal: key = KP_DEL; break;
|
|
case GIIUC_Delete: key = K_DEL; break;
|
|
|
|
case GIIK_PStar: key = KP_MULTIPLY; break;
|
|
case GIIK_PPlus: key = KP_PLUS; break;
|
|
case GIIK_PMinus: key = KP_MINUS; break;
|
|
case GIIK_PSlash: key = KP_DIVIDE; break;
|
|
|
|
case GIIK_PEnter: key = KP_ENTER; break;
|
|
case GIIUC_Return: key = K_ENTER; break;
|
|
|
|
case GIIUC_Escape: key = K_ESCAPE; break;
|
|
|
|
case GIIUC_Tab: key = K_TAB; break;
|
|
|
|
case GIIK_F1: key = K_F1; break;
|
|
case GIIK_F2: key = K_F2; break;
|
|
case GIIK_F3: key = K_F3; break;
|
|
case GIIK_F4: key = K_F4; break;
|
|
case GIIK_F5: key = K_F5; break;
|
|
case GIIK_F6: key = K_F6; break;
|
|
case GIIK_F7: key = K_F7; break;
|
|
case GIIK_F8: key = K_F8; break;
|
|
case GIIK_F9: key = K_F9; break;
|
|
case GIIK_F10: key = K_F10; break;
|
|
case GIIK_F11: key = K_F11; break;
|
|
case GIIK_F12: key = K_F12; break;
|
|
|
|
case GIIUC_BackSpace: key = K_BACKSPACE; break;
|
|
|
|
case GIIK_ShiftL:
|
|
case GIIK_ShiftR: key = K_SHIFT; break;
|
|
|
|
case GIIK_Execute:
|
|
case GIIK_CtrlL:
|
|
case GIIK_CtrlR: key = K_CTRL; break;
|
|
|
|
case GIIK_AltL:
|
|
case GIIK_MetaL:
|
|
case GIIK_AltR:
|
|
case GIIK_MetaR:
|
|
case GIIK_AltGr:
|
|
case GIIK_ModeSwitch: key = K_ALT; break;
|
|
|
|
case GIIK_Caps: key = K_CAPSLOCK; break;
|
|
case GIIK_PrintScreen: key = K_PRNTSCR; break;
|
|
case GIIK_ScrollLock: key = K_SCRLCK; break;
|
|
case GIIK_Pause: key = K_PAUSE; break;
|
|
case GIIK_NumLock: key = KP_NUMLCK; break;
|
|
|
|
case GIIUC_Comma: case GIIUC_Minus: case GIIUC_Period:
|
|
key = ev->label;
|
|
break;
|
|
case GIIUC_Section: key = '~'; break;
|
|
|
|
default:
|
|
if (ev->label >= 0 && ev->label <= 9) return ev->label;
|
|
if (ev->label >= 'A' && ev->label <= 'Z') {
|
|
return ev->label - 'A' + 'a';
|
|
}
|
|
if (ev->label >= 'a' && ev->label <= 'z') return ev->label;
|
|
|
|
if (ev->sym <= 0x7f) {
|
|
key = ev->sym;
|
|
if (key >= 'A' && key <= 'Z') {
|
|
key = key - 'A' + 'a';
|
|
}
|
|
return key;
|
|
}
|
|
if (ev->label <= 0x7f) {
|
|
return ev->label;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
static void GetEvent(void)
|
|
{
|
|
ggi_event ev;
|
|
uint32 b;
|
|
|
|
ggiEventRead(ggivis, &ev, emAll);
|
|
switch(ev.any.type) {
|
|
case evKeyPress:
|
|
Key_Event(XLateKey(&ev.key), true);
|
|
break;
|
|
|
|
case evKeyRelease:
|
|
Key_Event(XLateKey(&ev.key), false);
|
|
break;
|
|
|
|
case evPtrRelative:
|
|
mouse_x += (float) ev.pmove.x;
|
|
mouse_y += (float) ev.pmove.y;
|
|
break;
|
|
|
|
case evPtrAbsolute:
|
|
mouse_x += (float) (ev.pmove.x-p_mouse_x);
|
|
mouse_y += (float) (ev.pmove.y-p_mouse_y);
|
|
p_mouse_x = ev.pmove.x;
|
|
p_mouse_y = ev.pmove.y;
|
|
break;
|
|
|
|
case evPtrButtonPress:
|
|
if (!mouse_avail) return;
|
|
|
|
b = ev.pbutton.button - 1;
|
|
|
|
if (b < NUM_STDBUTTONS) {
|
|
Key_Event(K_MOUSE1 + b, true);
|
|
} else if (b < NUM_BUTTONS) {
|
|
Key_Event(K_AUX32 - NUM_BUTTONS + b, true);
|
|
}
|
|
break;
|
|
|
|
case evPtrButtonRelease:
|
|
if (!mouse_avail) return;
|
|
|
|
b = ev.pbutton.button - 1;
|
|
|
|
if (b < NUM_STDBUTTONS) {
|
|
Key_Event(K_MOUSE1 + b, false);
|
|
} else if (b < NUM_BUTTONS) {
|
|
Key_Event(K_AUX32 - NUM_BUTTONS + b, false);
|
|
}
|
|
break;
|
|
|
|
#if 0
|
|
case ConfigureNotify:
|
|
//printf("config notify\n");
|
|
config_notify_width = ev.xconfigure.width;
|
|
config_notify_height = ev.xconfigure.height;
|
|
config_notify = 1;
|
|
break;
|
|
|
|
default:
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
void IN_SendKeyEvents(void)
|
|
{
|
|
/* Get events from LibGGI */
|
|
if (ggivis) {
|
|
struct timeval t = {0,0};
|
|
|
|
if (ggiEventPoll(ggivis, emAll, &t)) {
|
|
int i = ggiEventsQueued(ggivis, emAll);
|
|
while (i--) GetEvent();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
IN_Init(void)
|
|
{
|
|
JOY_Init ();
|
|
|
|
_windowed_mouse = Cvar_Get("_windowed_mouse", "0", CVAR_ARCHIVE, "None");
|
|
old_windowed_mouse = -1; /* Force update */
|
|
m_filter = Cvar_Get("m_filter", "0", CVAR_ARCHIVE, "None");
|
|
if (COM_CheckParm ("-nomouse")) return;
|
|
|
|
mouse_x = mouse_y = 0.0;
|
|
mouse_avail = 1;
|
|
}
|
|
|
|
|
|
void
|
|
IN_Shutdown(void)
|
|
{
|
|
JOY_Shutdown ();
|
|
|
|
Con_Printf("IN_Shutdown\n");
|
|
mouse_avail = 0;
|
|
}
|
|
|
|
|
|
void
|
|
IN_Commands (void)
|
|
{
|
|
JOY_Command ();
|
|
|
|
/* Only supported by LibGII 0.7 or later. */
|
|
#ifdef GII_CMDCODE_PREFER_RELPTR
|
|
if (old_windowed_mouse != _windowed_mouse->int_val) {
|
|
gii_event ev;
|
|
|
|
old_windowed_mouse = _windowed_mouse->int_val;
|
|
|
|
ev.cmd.size = sizeof(gii_cmd_nodata_event);
|
|
ev.cmd.type = evCommand;
|
|
ev.cmd.target = GII_EV_TARGET_ALL;
|
|
ev.cmd.code = _windowed_mouse->int_val ? GII_CMDCODE_PREFER_RELPTR
|
|
: GII_CMDCODE_PREFER_ABSPTR;
|
|
|
|
ggiEventSend(ggivis, &ev);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
void
|
|
IN_Move(usercmd_t *cmd)
|
|
{
|
|
JOY_Move (cmd);
|
|
|
|
if (!mouse_avail)
|
|
return;
|
|
|
|
if (m_filter->int_val) {
|
|
mouse_x = (mouse_x + old_mouse_x) * 0.5;
|
|
mouse_y = (mouse_y + old_mouse_y) * 0.5;
|
|
}
|
|
|
|
old_mouse_x = mouse_x;
|
|
old_mouse_y = mouse_y;
|
|
|
|
mouse_x *= sensitivity->value;
|
|
mouse_y *= sensitivity->value;
|
|
|
|
if ( (in_strafe.state & 1) || (lookstrafe->int_val && freelook))
|
|
cmd->sidemove += m_side->value * mouse_x;
|
|
else
|
|
cl.viewangles[YAW] -= m_yaw->value * mouse_x;
|
|
if (freelook)
|
|
V_StopPitchDrift ();
|
|
|
|
if (freelook && !(in_strafe.state & 1)) {
|
|
cl.viewangles[PITCH] += m_pitch->value * mouse_y;
|
|
cl.viewangles[PITCH] = bound (-70, cl.viewangles[PITCH], 80);
|
|
} else {
|
|
if ((in_strafe.state & 1) && noclip_anglehack)
|
|
cmd->upmove -= m_forward->value * mouse_y;
|
|
else
|
|
cmd->forwardmove -= m_forward->value * mouse_y;
|
|
}
|
|
mouse_x = mouse_y = 0.0;
|
|
}
|
|
|
|
|
|
void VID_InitCvars(void) {}
|
|
void VID_LockBuffer(void) {}
|
|
void VID_UnlockBuffer(void) {}
|
|
|
|
void VID_SetCaption (char *text)
|
|
{
|
|
}
|
|
|