mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 11:35:05 +08:00
platform: new fbdev bakend, move in_evdev to bakends
This commit is contained in:
465
engine/platform/linux/in_evdev.c
Normal file
465
engine/platform/linux/in_evdev.c
Normal file
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
in_evdev.c - linux evdev interface support
|
||||
Copyright (C) 2015-2018 mittorn
|
||||
|
||||
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 3 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.
|
||||
*/
|
||||
#include "platform/platform.h"
|
||||
#ifdef XASH_USE_EVDEV
|
||||
|
||||
|
||||
#include "common.h"
|
||||
#include "input.h"
|
||||
#include "client.h"
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <linux/input.h>
|
||||
#include <dirent.h>
|
||||
#define MAX_EVDEV_DEVICES 5
|
||||
|
||||
struct evdev_s
|
||||
{
|
||||
int initialized, devices;
|
||||
int fds[MAX_EVDEV_DEVICES];
|
||||
string paths[MAX_EVDEV_DEVICES];
|
||||
qboolean grab;
|
||||
double grabtime;
|
||||
float x, y;
|
||||
qboolean chars;
|
||||
qboolean shift;
|
||||
} evdev;
|
||||
|
||||
static int KeycodeFromEvdev(int keycode, int value)
|
||||
{
|
||||
switch (keycode) {
|
||||
|
||||
case KEY_0: return '0';
|
||||
case KEY_1: return '1';
|
||||
case KEY_2: return '2';
|
||||
case KEY_3: return '3';
|
||||
case KEY_4: return '4';
|
||||
case KEY_5: return '5';
|
||||
case KEY_6: return '6';
|
||||
case KEY_7: return '7';
|
||||
case KEY_8: return '8';
|
||||
case KEY_9: return '9';
|
||||
case KEY_BACKSPACE: return K_BACKSPACE;
|
||||
case KEY_ENTER: return K_ENTER;
|
||||
case KEY_ESC: return K_ESCAPE;
|
||||
case KEY_KP0: return K_KP_INS;
|
||||
case KEY_KP1: return K_KP_END;
|
||||
case KEY_KP2: return K_KP_DOWNARROW;
|
||||
case KEY_KP3: return K_KP_PGDN;
|
||||
case KEY_KP4: return K_KP_LEFTARROW;
|
||||
case KEY_KP5: return K_KP_5;
|
||||
case KEY_KP6: return K_KP_RIGHTARROW;
|
||||
case KEY_KP7: return K_KP_HOME;
|
||||
case KEY_KP8: return K_KP_UPARROW;
|
||||
case KEY_KP9: return K_KP_PGUP;
|
||||
case KEY_KPDOT: return K_KP_DEL;
|
||||
case KEY_KPENTER: return K_KP_ENTER;
|
||||
case KEY_Q: return 'q';
|
||||
case KEY_W: return 'w';
|
||||
case KEY_E: return 'e';
|
||||
case KEY_R: return 'r';
|
||||
case KEY_T: return 't';
|
||||
case KEY_Y: return 'y';
|
||||
case KEY_U: return 'u';
|
||||
case KEY_I: return 'i';
|
||||
case KEY_O: return 'o';
|
||||
case KEY_P: return 'p';
|
||||
case KEY_A: return 'a';
|
||||
case KEY_S: return 's';
|
||||
case KEY_D: return 'd';
|
||||
case KEY_F: return 'f';
|
||||
case KEY_G: return 'g';
|
||||
case KEY_H: return 'h';
|
||||
case KEY_J: return 'j';
|
||||
case KEY_K: return 'k';
|
||||
case KEY_L: return 'l';
|
||||
case KEY_Z: return 'z';
|
||||
case KEY_X: return 'x';
|
||||
case KEY_C: return 'c';
|
||||
case KEY_V: return 'v';
|
||||
case KEY_B: return 'b';
|
||||
case KEY_N: return 'n';
|
||||
case KEY_M: return 'm';
|
||||
case KEY_LEFTBRACE: return '[';
|
||||
case KEY_RIGHTBRACE: return ']';
|
||||
case KEY_MINUS: return '-';
|
||||
case KEY_EQUAL: return '=';
|
||||
case KEY_TAB: return K_TAB;
|
||||
case KEY_SEMICOLON: return ';';
|
||||
case KEY_APOSTROPHE: return '\'';
|
||||
case KEY_GRAVE: return '`';
|
||||
case KEY_BACKSLASH: return '\\';
|
||||
case KEY_COMMA: return ',';
|
||||
case KEY_DOT: return '.';
|
||||
case KEY_SLASH: return '/';
|
||||
case KEY_SPACE: return K_SPACE;
|
||||
case KEY_KPASTERISK: return '*';
|
||||
case KEY_RIGHTCTRL:
|
||||
case KEY_LEFTCTRL:
|
||||
return K_CTRL;
|
||||
case KEY_RIGHTSHIFT:
|
||||
case KEY_LEFTSHIFT:
|
||||
return K_SHIFT;
|
||||
case KEY_LEFT: return K_LEFTARROW;
|
||||
case KEY_RIGHT: return K_RIGHTARROW;
|
||||
case KEY_UP: return K_UPARROW;
|
||||
case KEY_DOWN: return K_DOWNARROW;
|
||||
case BTN_LEFT: return K_MOUSE1;
|
||||
case BTN_RIGHT: return K_MOUSE2;
|
||||
case BTN_MIDDLE: return K_MOUSE3;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static void Evdev_CheckPermissions( void )
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
system( "su 0 chmod 664 /dev/input/event*" );
|
||||
#endif
|
||||
}
|
||||
|
||||
void Evdev_Setup( void )
|
||||
{
|
||||
if( evdev.initialized )
|
||||
return;
|
||||
#ifdef __ANDROID__
|
||||
system( "su 0 supolicy --live \"allow appdomain input_device dir { ioctl read getattr search open }\" \"allow appdomain input_device chr_file { ioctl read write getattr lock append open }\"" );
|
||||
system( "su 0 setenforce permissive" );
|
||||
#endif
|
||||
evdev.initialized = true;
|
||||
}
|
||||
|
||||
#define EV_HASBIT( x, y ) ( x[y / 32] & (1 << y % 32) )
|
||||
|
||||
void Evdev_Autodetect_f( void )
|
||||
{
|
||||
int i;
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
Evdev_Setup();
|
||||
|
||||
Evdev_CheckPermissions();
|
||||
|
||||
if( !( dir = opendir( "/dev/input" ) ) )
|
||||
return;
|
||||
|
||||
while( ( entry = readdir( dir ) ) )
|
||||
{
|
||||
int fd;
|
||||
string path;
|
||||
uint types[EV_MAX] = {0};
|
||||
uint codes[( KEY_MAX - 1 ) / 32 + 1] = {0};
|
||||
qboolean hasbtnmouse;
|
||||
|
||||
if( evdev.devices >= MAX_EVDEV_DEVICES )
|
||||
continue;
|
||||
|
||||
Q_snprintf( path, MAX_STRING, "/dev/input/%s", entry->d_name );
|
||||
|
||||
for( i = 0; i < evdev.devices; i++ )
|
||||
if( !Q_strncmp( evdev.paths[i], path, MAX_STRING ) )
|
||||
goto next;
|
||||
|
||||
if( Q_strncmp( entry->d_name, "event", 5 ) )
|
||||
continue;
|
||||
|
||||
fd = open( path, O_RDONLY | O_NONBLOCK );
|
||||
|
||||
if( fd == -1 )
|
||||
continue;
|
||||
|
||||
ioctl( fd, EVIOCGBIT( 0, EV_MAX ), types );
|
||||
|
||||
if( !EV_HASBIT( types, EV_KEY ) )
|
||||
goto close;
|
||||
|
||||
ioctl( fd, EVIOCGBIT( EV_KEY, KEY_MAX ), codes );
|
||||
|
||||
if( EV_HASBIT( codes, KEY_LEFTCTRL ) && EV_HASBIT( codes, KEY_SPACE ) )
|
||||
goto open;
|
||||
|
||||
if( !EV_HASBIT( codes, BTN_MOUSE ) )
|
||||
goto close;
|
||||
|
||||
if( EV_HASBIT( types, EV_REL ) )
|
||||
{
|
||||
memset( codes, 0, sizeof( codes ) );
|
||||
ioctl( fd, EVIOCGBIT( EV_REL, KEY_MAX ), codes );
|
||||
|
||||
if( !EV_HASBIT( codes, REL_X ) )
|
||||
goto close;
|
||||
|
||||
if( !EV_HASBIT( codes, REL_Y ) )
|
||||
goto close;
|
||||
|
||||
if( !EV_HASBIT( codes, REL_WHEEL ) )
|
||||
goto close;
|
||||
|
||||
goto open;
|
||||
}
|
||||
goto close;
|
||||
open:
|
||||
Q_strncpy( evdev.paths[evdev.devices], path, MAX_STRING );
|
||||
evdev.fds[evdev.devices++] = fd;
|
||||
Msg( "Opened device %s\n", path );
|
||||
#if XASH_INPUT == INPUT_EVDEV
|
||||
if( Sys_CheckParm( "-grab" ) )
|
||||
ioctl( evdev.fds[i], EVIOCGRAB, (void*) 1 );
|
||||
#endif
|
||||
goto next;
|
||||
close:
|
||||
close( fd );
|
||||
next:
|
||||
continue;
|
||||
}
|
||||
closedir( dir );
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
Evdev_OpenDevice
|
||||
|
||||
For shitty systems that cannot provide relative mouse axes
|
||||
===========
|
||||
*/
|
||||
void Evdev_OpenDevice ( const char *path )
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
if ( evdev.devices >= MAX_EVDEV_DEVICES )
|
||||
{
|
||||
Msg( "Only %d devices supported!\n", MAX_EVDEV_DEVICES );
|
||||
return;
|
||||
}
|
||||
|
||||
Evdev_Setup();
|
||||
|
||||
Evdev_CheckPermissions(); // use root to grant access to evdev
|
||||
|
||||
for( i = 0; i < evdev.devices; i++ )
|
||||
{
|
||||
if( !Q_strncmp( evdev.paths[i], path, MAX_STRING ) )
|
||||
{
|
||||
Msg( "device %s already open!\n", path );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ret = open( path, O_RDONLY | O_NONBLOCK );
|
||||
if( ret < 0 )
|
||||
{
|
||||
Con_Reportf( S_ERROR "Could not open input device %s: %s\n", path, strerror( errno ) );
|
||||
return;
|
||||
}
|
||||
Msg( "Input device #%d: %s opened sucessfully\n", evdev.devices, path );
|
||||
evdev.fds[evdev.devices] = ret;
|
||||
Q_strncpy( evdev.paths[evdev.devices++], path, MAX_STRING );
|
||||
|
||||
#if XASH_INPUT == INPUT_EVDEV
|
||||
if( Sys_CheckParm( "-grab" ) )
|
||||
ioctl( evdev.fds[i], EVIOCGRAB, (void*) 1 );
|
||||
#endif
|
||||
}
|
||||
|
||||
void Evdev_OpenDevice_f( void )
|
||||
{
|
||||
if( Cmd_Argc() < 2 )
|
||||
Msg( S_USAGE "evdev_opendevice <path>\n" );
|
||||
|
||||
Evdev_OpenDevice( Cmd_Argv( 1 ) );
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
Evdev_CloseDevice_f
|
||||
===========
|
||||
*/
|
||||
void Evdev_CloseDevice_f ( void )
|
||||
{
|
||||
uint i;
|
||||
const char *arg;
|
||||
|
||||
if( Cmd_Argc() < 2 )
|
||||
return;
|
||||
|
||||
arg = Cmd_Argv( 1 );
|
||||
|
||||
if( Q_isdigit( arg ) )
|
||||
i = Q_atoi( arg );
|
||||
else for( i = 0; i < evdev.devices; i++ )
|
||||
if( !Q_strncmp( evdev.paths[i], arg, MAX_STRING ) )
|
||||
break;
|
||||
|
||||
if( i >= evdev.devices )
|
||||
{
|
||||
Msg( "Device %s is not open\n", arg );
|
||||
return;
|
||||
}
|
||||
|
||||
close( evdev.fds[i] );
|
||||
evdev.devices--;
|
||||
Msg( "Device %s closed successfully\n", evdev.paths[i] );
|
||||
|
||||
for( ; i < evdev.devices; i++ )
|
||||
{
|
||||
Q_strncpy( evdev.paths[i], evdev.paths[i+1], MAX_STRING );
|
||||
evdev.fds[i] = evdev.fds[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
void IN_EvdevFrame ( void )
|
||||
{
|
||||
int dx = 0, dy = 0, i;
|
||||
|
||||
for( i = 0; i < evdev.devices; i++ )
|
||||
{
|
||||
struct input_event ev;
|
||||
|
||||
while ( read( evdev.fds[i], &ev, 16) == 16 )
|
||||
{
|
||||
if ( ev.type == EV_REL )
|
||||
{
|
||||
switch ( ev.code )
|
||||
{
|
||||
case REL_X: dx += ev.value;
|
||||
break;
|
||||
|
||||
case REL_Y: dy += ev.value;
|
||||
break;
|
||||
|
||||
case REL_WHEEL:
|
||||
if( ev.value > 0)
|
||||
{
|
||||
Key_Event( K_MWHEELDOWN, 1 );
|
||||
Key_Event( K_MWHEELDOWN, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
Key_Event( K_MWHEELUP, 1 );
|
||||
Key_Event( K_MWHEELUP, 0 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( ( ev.type == EV_KEY ) && (cls.key_dest == key_game || XASH_INPUT == INPUT_EVDEV ) )
|
||||
{
|
||||
int key = KeycodeFromEvdev( ev.code, ev.value );
|
||||
Key_Event ( key , ev.value );
|
||||
|
||||
if( evdev.chars && ev.value )
|
||||
{
|
||||
if( key >= 32 && key < 127 )
|
||||
{
|
||||
if( evdev.shift )
|
||||
{
|
||||
key = Q_toupper( key );
|
||||
if( key == '-' )
|
||||
key = '_';
|
||||
if( key == '=' )
|
||||
key = '+';
|
||||
}
|
||||
CL_CharEvent( key );
|
||||
}
|
||||
}
|
||||
if( key == K_SHIFT )
|
||||
evdev.shift = ev.value;
|
||||
}
|
||||
}
|
||||
|
||||
if( evdev.grab && evdev.grabtime <= host.realtime )
|
||||
{
|
||||
ioctl( evdev.fds[i], EVIOCGRAB, (void*) 1 );
|
||||
Key_ClearStates();
|
||||
}
|
||||
|
||||
if( CVAR_TO_BOOL(m_ignore) )
|
||||
continue;
|
||||
|
||||
evdev.x += -dx * m_yaw->value;
|
||||
evdev.y += dy * m_pitch->value;
|
||||
}
|
||||
if( evdev.grabtime <= host.realtime )
|
||||
evdev.grab = false;
|
||||
}
|
||||
|
||||
void Evdev_SetGrab( qboolean grab )
|
||||
{
|
||||
// grab only if evdev is secondary input source
|
||||
#if XASH_INPUT != INPUT_EVDEV
|
||||
int i;
|
||||
|
||||
if( grab )
|
||||
{
|
||||
Key_Event( K_ESCAPE, 0 ); //Do not leave ESC down
|
||||
evdev.grabtime = host.realtime + 0.5;
|
||||
Key_ClearStates();
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < evdev.devices; i++ )
|
||||
ioctl( evdev.fds[i], EVIOCGRAB, (void*) 0 );
|
||||
}
|
||||
evdev.grab = grab;
|
||||
#endif
|
||||
}
|
||||
|
||||
void IN_EvdevMove( float *yaw, float *pitch )
|
||||
{
|
||||
*yaw += evdev.x;
|
||||
*pitch += evdev.y;
|
||||
evdev.x = evdev.y = 0.0f;
|
||||
}
|
||||
|
||||
#if XASH_INPUT == INPUT_EVDEV
|
||||
|
||||
void Platform_EnableTextInput( qboolean enable )
|
||||
{
|
||||
evdev.chars = enable;
|
||||
evdev.shift = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Evdev_Init( void )
|
||||
{
|
||||
Cmd_AddCommand ("evdev_open", Evdev_OpenDevice_f, "Open event device");
|
||||
Cmd_AddCommand ("evdev_close", Evdev_CloseDevice_f, "Close event device");
|
||||
Cmd_AddCommand ("evdev_autodetect", Evdev_Autodetect_f, "Automaticly open mouses and keyboards");
|
||||
#if XASH_INPUT == INPUT_EVDEV
|
||||
Evdev_Autodetect_f();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Evdev_Shutdown( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
Cmd_RemoveCommand( "evdev_open" );
|
||||
Cmd_RemoveCommand( "evdev_close" );
|
||||
Cmd_RemoveCommand( "evdev_autodetect" );
|
||||
|
||||
for( i = 0; i < evdev.devices; i++ )
|
||||
{
|
||||
ioctl( evdev.fds[i], EVIOCGRAB, (void*) 0 );
|
||||
close( evdev.fds[i] );
|
||||
evdev.fds[i] = -1;
|
||||
}
|
||||
evdev.devices = 0;
|
||||
}
|
||||
|
||||
#endif // XASH_USE_EVDEV
|
||||
296
engine/platform/linux/vid_fbdev.c
Normal file
296
engine/platform/linux/vid_fbdev.c
Normal file
@@ -0,0 +1,296 @@
|
||||
#include "platform/platform.h"
|
||||
#if XASH_VIDEO == VIDEO_FBDEV
|
||||
#include "input.h"
|
||||
#include "client.h"
|
||||
#include "filesystem.h"
|
||||
#include "vid_common.h"
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef __ANDROID__
|
||||
#include <linux/kd.h>
|
||||
#else
|
||||
#include <sys/kd.h>
|
||||
#endif
|
||||
|
||||
struct fb_s
|
||||
{
|
||||
int fd, tty_fd;
|
||||
void *map;
|
||||
struct fb_var_screeninfo vinfo;
|
||||
struct fb_fix_screeninfo finfo;
|
||||
qboolean vsync;
|
||||
int doublebuffer;
|
||||
} fb;
|
||||
|
||||
#define DEFAULT_FBDEV "/dev/fb0"
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_SwapBuffers
|
||||
|
||||
Update screen. Use native EGL if possible
|
||||
========================
|
||||
*/
|
||||
void GL_SwapBuffers( void )
|
||||
{
|
||||
}
|
||||
|
||||
void FB_GetScreenRes(int *x, int *y)
|
||||
{
|
||||
*x = fb.vinfo.xres;
|
||||
*y = fb.vinfo.yres;
|
||||
}
|
||||
|
||||
qboolean R_Init_Video( const int type )
|
||||
{
|
||||
qboolean retval;
|
||||
string fbdev = DEFAULT_FBDEV;
|
||||
fb.fd = -1;
|
||||
|
||||
VID_StartupGamma();
|
||||
|
||||
if( type != REF_SOFTWARE )
|
||||
return false;
|
||||
|
||||
Sys_GetParmFromCmdLine( "-fbdev", fbdev );
|
||||
|
||||
fb.fd = open( fbdev, O_RDWR );
|
||||
|
||||
if( fb.fd < 0 )
|
||||
{
|
||||
Con_Printf( S_ERROR, "failed to open framebuffer device: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
if( Sys_CheckParm( "-ttygfx" ) )
|
||||
fb.tty_fd = open( "/dev/tty", O_RDWR ); // only need this to set graphics mode, optional
|
||||
|
||||
ioctl(fb.fd, FBIOGET_FSCREENINFO, &fb.finfo);
|
||||
ioctl(fb.fd, FBIOGET_VSCREENINFO, &fb.vinfo);
|
||||
|
||||
if( !(retval = VID_SetMode()) )
|
||||
{
|
||||
return retval;
|
||||
}
|
||||
|
||||
host.renderinfo_changed = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void R_Free_Video( void )
|
||||
{
|
||||
// VID_DestroyWindow ();
|
||||
|
||||
// R_FreeVideoModes();
|
||||
if( fb.doublebuffer )
|
||||
{
|
||||
fb.vinfo.yoffset = 0;
|
||||
fb.vinfo.yres_virtual >>= 1;
|
||||
ioctl( fb.fd, FBIOPAN_DISPLAY, &fb.vinfo );
|
||||
}
|
||||
if( fb.map )
|
||||
munmap( fb.map, fb.finfo.smem_len );
|
||||
close( fb.fd );
|
||||
|
||||
fb.fd = -1;
|
||||
fb.map = NULL;
|
||||
|
||||
if( fb.tty_fd >= 0 )
|
||||
{
|
||||
ioctl( fb.tty_fd, KDSETMODE, KD_TEXT );
|
||||
close( fb.tty_fd );
|
||||
fb.tty_fd = -1;
|
||||
}
|
||||
|
||||
ref.dllFuncs.GL_ClearExtensions();
|
||||
}
|
||||
|
||||
|
||||
qboolean VID_SetMode( void )
|
||||
{
|
||||
if( fb.tty_fd > 0 )
|
||||
ioctl( fb.tty_fd, KDSETMODE, KD_GRAPHICS );
|
||||
R_ChangeDisplaySettings( 0, 0, false ); // width and height are ignored anyway
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
rserr_t R_ChangeDisplaySettings( int width, int height, qboolean fullscreen )
|
||||
{
|
||||
FB_GetScreenRes( &width, &height );
|
||||
|
||||
Con_Reportf( "R_ChangeDisplaySettings: forced resolution to %dx%d)\n", width, height);
|
||||
|
||||
R_SaveVideoMode( width, height );
|
||||
|
||||
host.window_center_x = width / 2;
|
||||
host.window_center_y = height / 2;
|
||||
|
||||
refState.wideScreen = true; // V_AdjustFov will check for widescreen
|
||||
|
||||
return rserr_ok;
|
||||
}
|
||||
|
||||
int GL_SetAttribute( int attr, int val )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GL_GetAttribute( int attr, int *val )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int R_MaxVideoModes( void )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
vidmode_t* R_GetVideoMode( int num )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* GL_GetProcAddress( const char *name ) // RenderAPI requirement
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void GL_UpdateSwapInterval( void )
|
||||
{
|
||||
// disable VSync while level is loading
|
||||
if( cls.state < ca_active )
|
||||
{
|
||||
// setup fb vsync here
|
||||
fb.vsync = false;
|
||||
SetBits( gl_vsync->flags, FCVAR_CHANGED );
|
||||
}
|
||||
else if( FBitSet( gl_vsync->flags, FCVAR_CHANGED ))
|
||||
{
|
||||
ClearBits( gl_vsync->flags, FCVAR_CHANGED );
|
||||
fb.vsync = true;
|
||||
}
|
||||
}
|
||||
|
||||
void *SW_LockBuffer( void )
|
||||
{
|
||||
if( fb.vsync )
|
||||
{
|
||||
int stub = 0;
|
||||
ioctl(fb.fd, FBIO_WAITFORVSYNC, &stub);
|
||||
}
|
||||
if( fb.doublebuffer )
|
||||
{
|
||||
static int page = 0;
|
||||
page = !page;
|
||||
fb.vinfo.yoffset = page * fb.vinfo.yres;
|
||||
return fb.map + page * fb.doublebuffer;
|
||||
}
|
||||
else
|
||||
return fb.map;
|
||||
}
|
||||
|
||||
void SW_UnlockBuffer( void )
|
||||
{
|
||||
// some single-buffer fb devices need this too
|
||||
ioctl(fb.fd, FBIOPAN_DISPLAY, &fb.vinfo);
|
||||
}
|
||||
|
||||
#define FB_BF_TO_MASK(x) (((1 << x.length) - 1) << (x.offset))
|
||||
|
||||
qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b )
|
||||
{
|
||||
*bpp = fb.vinfo.bits_per_pixel >> 3;
|
||||
*stride = fb.vinfo.xres_virtual;
|
||||
*r = FB_BF_TO_MASK(fb.vinfo.red);
|
||||
*g = FB_BF_TO_MASK(fb.vinfo.green);
|
||||
*b = FB_BF_TO_MASK(fb.vinfo.blue);
|
||||
|
||||
if( Sys_CheckParm("-doublebuffer") )
|
||||
{
|
||||
fb.doublebuffer = *bpp * *stride * fb.vinfo.yres;
|
||||
fb.vinfo.yres_virtual = fb.vinfo.yres * 2;
|
||||
if(ioctl (fb.fd, FBIOPUT_VSCREENINFO, &fb.vinfo ))
|
||||
{
|
||||
fb.vinfo.transp.length = fb.vinfo.transp.offset = 0;
|
||||
if( ioctl (fb.fd, FBIOPUT_VSCREENINFO, &fb.vinfo ) )
|
||||
{
|
||||
Con_Printf( S_ERROR "failed to enable double buffering!\n" );
|
||||
}
|
||||
}
|
||||
|
||||
ioctl( fb.fd, FBIOGET_FSCREENINFO, &fb.finfo );
|
||||
ioctl( fb.fd, FBIOGET_VSCREENINFO, &fb.vinfo );
|
||||
ioctl( fb.fd, FBIOPAN_DISPLAY, &fb.vinfo );
|
||||
|
||||
if( fb.finfo.smem_len < fb.doublebuffer * 2 )
|
||||
{
|
||||
Con_Printf( S_ERROR "not enough memory for double buffering, disabling!\n" );
|
||||
fb.doublebuffer = 0;
|
||||
}
|
||||
}
|
||||
if( fb.map )
|
||||
munmap(fb.map, fb.finfo.smem_len);
|
||||
fb.map = mmap(0, fb.finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb.fd, 0);
|
||||
|
||||
if( !fb.map )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// unrelated stubs
|
||||
void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow )
|
||||
{
|
||||
|
||||
}
|
||||
void Platform_GetClipboardText( char *buffer, size_t size )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Platform_SetClipboardText( const char *buffer, size_t size )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Platform_PreCreateMove( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// will be implemented later
|
||||
void Platform_RunEvents( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void *Platform_GetNativeObject( const char *name )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Platform_GetMousePos( int *x, int *y )
|
||||
{
|
||||
*x = *y = 0;
|
||||
}
|
||||
|
||||
|
||||
void Platform_SetMousePos(int x, int y)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Platform_Vibrate(float life, char flags)
|
||||
{
|
||||
|
||||
}
|
||||
int Platform_JoyInit( int numjoy )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user