Removing SDL - Doom now starts!

This commit is contained in:
Simon 2020-03-06 17:44:48 +00:00
parent 779178f798
commit 5f41c55468
58 changed files with 302 additions and 11695 deletions

View File

@ -40,9 +40,8 @@ Copyright : Copyright 2015 Oculus VR, LLC. All Rights reserved.
//#include <src/gl/loader.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_main.h>
//#include <src/client/header/client.h>
//#include <SDL2/SDL.h>
//#include <SDL2/SDL_main.h>
#include "VrCompositor.h"
#include "VrInput.h"
@ -509,7 +508,8 @@ static void ovrFramebuffer_Clear( ovrFramebuffer * frameBuffer )
frameBuffer->Height = 0;
frameBuffer->Multisamples = 0;
frameBuffer->TextureSwapChainLength = 0;
frameBuffer->TextureSwapChainIndex = 0;
frameBuffer->ProcessingTextureSwapChainIndex = 0;
frameBuffer->ReadyTextureSwapChainIndex = 0;
frameBuffer->ColorTextureSwapChain = NULL;
frameBuffer->DepthBuffers = NULL;
frameBuffer->FrameBuffers = NULL;
@ -598,7 +598,7 @@ void ovrFramebuffer_Destroy( ovrFramebuffer * frameBuffer )
void ovrFramebuffer_SetCurrent( ovrFramebuffer * frameBuffer )
{
//LOAD_GLES2(glBindFramebuffer);
GL( /*gles_*/glBindFramebuffer( GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[frameBuffer->TextureSwapChainIndex] ) );
GL( /*gles_*/glBindFramebuffer( GL_DRAW_FRAMEBUFFER, frameBuffer->FrameBuffers[frameBuffer->ProcessingTextureSwapChainIndex] ) );
}
void ovrFramebuffer_SetNone()
@ -620,7 +620,8 @@ void ovrFramebuffer_Resolve( ovrFramebuffer * frameBuffer )
void ovrFramebuffer_Advance( ovrFramebuffer * frameBuffer )
{
// Advance to the next texture from the set.
frameBuffer->TextureSwapChainIndex = ( frameBuffer->TextureSwapChainIndex + 1 ) % frameBuffer->TextureSwapChainLength;
frameBuffer->ReadyTextureSwapChainIndex = frameBuffer->ProcessingTextureSwapChainIndex;
frameBuffer->ProcessingTextureSwapChainIndex = ( frameBuffer->ProcessingTextureSwapChainIndex + 1 ) % frameBuffer->TextureSwapChainLength;
}
@ -1327,47 +1328,6 @@ static ovrApp gAppState;
static ovrJava java;
static bool destroyed = false;
void RenderFrame()
{
//Qcommon_BeginFrame (time * 1000);
ovrRenderer *renderer = useScreenLayer() ? &gAppState.Scene.CylinderRenderer : &gAppState.Renderer;
// Render the eye images.
for (int eye = 0; eye < renderer->NumBuffers; eye++) {
ovrFramebuffer *frameBuffer = &(renderer->FrameBuffer[eye]);
ovrFramebuffer_SetCurrent(frameBuffer);
{
GL(glEnable(GL_SCISSOR_TEST));
GL(glDepthMask(GL_TRUE));
GL(glEnable(GL_DEPTH_TEST));
GL(glDepthFunc(GL_LEQUAL));
//Weusing the size of the render target
GL(glViewport(0, 0, frameBuffer->Width, frameBuffer->Height));
GL(glScissor(0, 0, frameBuffer->Width, frameBuffer->Height));
GL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
GL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
GL(glDisable(GL_SCISSOR_TEST));
//Now do the drawing for this eye (or draw for left eye twice if using screen layer)
//Qcommon_Frame(useScreenLayer() ? 0 : eye);
}
//Clear edge to prevent smearing
ovrFramebuffer_ClearEdgeTexels(frameBuffer);
ovrFramebuffer_Resolve(frameBuffer);
ovrFramebuffer_Advance(frameBuffer);
}
ovrFramebuffer_SetNone();
}
void prepareEyeBuffer(int eye )
{
ovrRenderer *renderer = useScreenLayer() ? &gAppState.Scene.CylinderRenderer : &gAppState.Renderer;
@ -1482,9 +1442,9 @@ void * AppThreadFunction(void * parm ) {
jclass cls = (*java.Env)->GetObjectClass(java.Env, java.ActivityObject);
/* This interface could expand with ABI negotiation, callbacks, etc. */
SDL_Android_Init(java.Env, cls);
// SDL_Android_Init(java.Env, cls);
SDL_SetMainReady();
// SDL_SetMainReady();
// Note that AttachCurrentThread will reset the thread name.
prctl(PR_SET_NAME, (long) "OVR::Main", 0, 0, 0);
@ -1634,75 +1594,6 @@ void shutdownVR() {
vrapi_Shutdown();
}
ovrSubmitFrameDescription2 setupFrameDescriptor(ovrTracking2 *tracking) {
ovrSubmitFrameDescription2 frameDesc = {0 };
if (!useScreenLayer()) {
ovrLayerProjection2 layer = vrapi_DefaultLayerProjection2();
layer.HeadPose = (*tracking).HeadPose;
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
{
ovrFramebuffer * frameBuffer = &gAppState.Renderer.FrameBuffer[gAppState.Renderer.NumBuffers == 1 ? 0 : eye];
layer.Textures[eye].ColorSwapChain = frameBuffer->ColorTextureSwapChain;
layer.Textures[eye].SwapChainIndex = frameBuffer->TextureSwapChainIndex;
ovrMatrix4f projectionMatrix;
projectionMatrix = ovrMatrix4f_CreateProjectionFov(vrFOV, vrFOV,
0.0f, 0.0f, 0.1f, 0.0f);
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection(&projectionMatrix);
layer.Textures[eye].TextureRect.x = 0;
layer.Textures[eye].TextureRect.y = 0;
layer.Textures[eye].TextureRect.width = 1.0f;
layer.Textures[eye].TextureRect.height = 1.0f;
}
layer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CHROMATIC_ABERRATION_CORRECTION;
// Set up the description for this frame.
const ovrLayerHeader2 *layers[] =
{
&layer.Header
};
ovrSubmitFrameDescription2 frameDesc = {};
frameDesc.Flags = 0;
frameDesc.SwapInterval = gAppState.SwapInterval;
frameDesc.FrameIndex = gAppState.FrameIndex;
frameDesc.DisplayTime = gAppState.DisplayTime;
frameDesc.LayerCount = 1;
frameDesc.Layers = layers;
} else {
// Set-up the compositor layers for this frame.
// NOTE: Multiple independent layers are allowed, but they need to be added
// in a depth consistent order.
memset( gAppState.Layers, 0, sizeof( ovrLayer_Union2 ) * ovrMaxLayerCount );
gAppState.LayerCount = 0;
// Add a simple cylindrical layer
gAppState.Layers[gAppState.LayerCount++].Cylinder =
BuildCylinderLayer(&gAppState.Scene.CylinderRenderer,
gAppState.Scene.CylinderWidth, gAppState.Scene.CylinderHeight, tracking, radians(playerYaw) );
// Compose the layers for this frame.
const ovrLayerHeader2 * layerHeaders[ovrMaxLayerCount] = { 0 };
for ( int i = 0; i < gAppState.LayerCount; i++ )
{
layerHeaders[i] = &gAppState.Layers[i].Header;
}
// Set up the description for this frame.
frameDesc.Flags = 0;
frameDesc.SwapInterval = gAppState.SwapInterval;
frameDesc.FrameIndex = gAppState.FrameIndex;
frameDesc.DisplayTime = gAppState.DisplayTime;
frameDesc.LayerCount = gAppState.LayerCount;
frameDesc.Layers = layerHeaders;
}
return frameDesc;
}
void incrementFrameIndex()
{
// This is the only place the frame index is incremented, right before
@ -1731,33 +1622,81 @@ void getTrackedRemotesOrientation(int vr_control_scheme) {//Get info for tracked
}
}
void submitFrame(ovrSubmitFrameDescription2 *frameDesc)
void submitFrame(ovrTracking2 *tracking)
{
// Hand over the eye images to the time warp.
vrapi_SubmitFrame2(gAppState.Ovr, frameDesc);
ovrSubmitFrameDescription2 frameDesc = {0};
if (!useScreenLayer()) {
ovrLayerProjection2 layer = vrapi_DefaultLayerProjection2();
layer.HeadPose = (*tracking).HeadPose;
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
{
ovrFramebuffer * frameBuffer = &gAppState.Renderer.FrameBuffer[gAppState.Renderer.NumBuffers == 1 ? 0 : eye];
layer.Textures[eye].ColorSwapChain = frameBuffer->ColorTextureSwapChain;
layer.Textures[eye].SwapChainIndex = frameBuffer->ReadyTextureSwapChainIndex;
ovrMatrix4f projectionMatrix;
projectionMatrix = ovrMatrix4f_CreateProjectionFov(vrFOV, vrFOV,
0.0f, 0.0f, 0.1f, 0.0f);
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection(&projectionMatrix);
layer.Textures[eye].TextureRect.x = 0;
layer.Textures[eye].TextureRect.y = 0;
layer.Textures[eye].TextureRect.width = 1.0f;
layer.Textures[eye].TextureRect.height = 1.0f;
}
layer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CHROMATIC_ABERRATION_CORRECTION;
// Set up the description for this frame.
const ovrLayerHeader2 *layers[] =
{
&layer.Header
};
frameDesc.Flags = 0;
frameDesc.SwapInterval = gAppState.SwapInterval;
frameDesc.FrameIndex = gAppState.FrameIndex;
frameDesc.DisplayTime = gAppState.DisplayTime;
frameDesc.LayerCount = 1;
frameDesc.Layers = layers;
// Hand over the eye images to the time warp.
vrapi_SubmitFrame2(gAppState.Ovr, &frameDesc);
} else {
// Set-up the compositor layers for this frame.
// NOTE: Multiple independent layers are allowed, but they need to be added
// in a depth consistent order.
memset( gAppState.Layers, 0, sizeof( ovrLayer_Union2 ) * ovrMaxLayerCount );
gAppState.LayerCount = 0;
// Add a simple cylindrical layer
gAppState.Layers[gAppState.LayerCount++].Cylinder =
BuildCylinderLayer(&gAppState.Scene.CylinderRenderer,
gAppState.Scene.CylinderWidth, gAppState.Scene.CylinderHeight, tracking, radians(playerYaw) );
// Compose the layers for this frame.
const ovrLayerHeader2 * layerHeaders[ovrMaxLayerCount] = { 0 };
for ( int i = 0; i < gAppState.LayerCount; i++ )
{
layerHeaders[i] = &gAppState.Layers[i].Header;
}
// Set up the description for this frame.
frameDesc.Flags = 0;
frameDesc.SwapInterval = gAppState.SwapInterval;
frameDesc.FrameIndex = gAppState.FrameIndex;
frameDesc.DisplayTime = gAppState.DisplayTime;
frameDesc.LayerCount = gAppState.LayerCount;
frameDesc.Layers = layerHeaders;
// Hand over the eye images to the time warp.
vrapi_SubmitFrame2(gAppState.Ovr, &frameDesc);
}
}
//Need to replicate this code in gl_oculusquest.cpp
void vr_main()
{/*
if (!destroyed)
{
processHaptics();
ovrTracking2 tracking;
getHMDOrientation(&tracking);
getTrackedRemotesOrientation();
ovrSubmitFrameDescription2 frameDesc = setupFrameDescriptor(&tracking);
//Call the game drawing code
RenderFrame();
// Hand over the eye images to the time warp.
submitFrame(&frameDesc);
}
*/
}
static void ovrAppThread_Create( ovrAppThread * appThread, JNIEnv * env, jobject activityObject, jclass activityClass )
{
@ -1791,7 +1730,7 @@ Activity lifecycle
================================================================================
*/
JNIEXPORT jint JNICALL SDL_JNI_OnLoad(JavaVM* vm, void* reserved);
//JNIEXPORT jint JNICALL SDL_JNI_OnLoad(JavaVM* vm, void* reserved);
int JNI_OnLoad(JavaVM* vm, void* reserved)
{
@ -1802,7 +1741,7 @@ int JNI_OnLoad(JavaVM* vm, void* reserved)
return -1;
}
return SDL_JNI_OnLoad(vm, reserved);
return JNI_VERSION_1_4;
}
JNIEXPORT jlong JNICALL Java_com_drbeef_qzdoom_GLES3JNILib_onCreate( JNIEnv * env, jclass activityClass, jobject activity,

View File

@ -86,10 +86,9 @@ void getTrackedRemotesOrientation(int vr_control_scheme);
void incrementFrameIndex();
ovrSubmitFrameDescription2 setupFrameDescriptor(ovrTracking2 *tracking);
void prepareEyeBuffer(int eye );
void finishEyeBuffer(int eye );
void submitFrame(ovrSubmitFrameDescription2 *frameDesc);
void submitFrame(ovrTracking2 *tracking);
#ifdef __cplusplus
} // extern "C"

View File

@ -465,7 +465,7 @@ ovrLayerProjection2 ovrRenderer_RenderGroundPlaneToEyeBuffer( ovrRenderer * rend
{
ovrFramebuffer * frameBuffer = &renderer->FrameBuffer[eye];
layer.Textures[eye].ColorSwapChain = frameBuffer->ColorTextureSwapChain;
layer.Textures[eye].SwapChainIndex = frameBuffer->TextureSwapChainIndex;
layer.Textures[eye].SwapChainIndex = frameBuffer->ProcessingTextureSwapChainIndex;
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection( &tracking->Eye[eye].ProjectionMatrix );
}
layer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CHROMATIC_ABERRATION_CORRECTION;
@ -572,7 +572,7 @@ ovrLayerCylinder2 BuildCylinderLayer( ovrRenderer * cylinderRenderer,
ovrMatrix4f modelViewMatrix = ovrMatrix4f_Multiply( &tracking->Eye[eye].ViewMatrix, &cylinderTransform );
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_Inverse( &modelViewMatrix );
layer.Textures[eye].ColorSwapChain = cylinderFrameBuffer->ColorTextureSwapChain;
layer.Textures[eye].SwapChainIndex = cylinderFrameBuffer->TextureSwapChainIndex;
layer.Textures[eye].SwapChainIndex = cylinderFrameBuffer->ReadyTextureSwapChainIndex;
// Texcoord scale and bias is just a representation of the aspect ratio. The positioning
// of the cylinder is handled entirely by the TexCoordsFromTanAngles matrix.

View File

@ -59,7 +59,8 @@ typedef struct
int Height;
int Multisamples;
int TextureSwapChainLength;
int TextureSwapChainIndex;
int ProcessingTextureSwapChainIndex;
int ReadyTextureSwapChainIndex;
ovrTextureSwapChain * ColorTextureSwapChain;
GLuint * DepthBuffers;
GLuint * FrameBuffers;

View File

@ -21,9 +21,6 @@ float positional_movementSideways;
float positional_movementForward;
float snapTurn;
void sendButtonAction(const char* action, long buttonDown);
void sendButtonActionSimple(const char* action);
void acquireTrackedRemotesData(const ovrMobile *Ovr, double displayTime);
void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, ovrInputStateTrackedRemote *pDominantTrackedRemoteOld, ovrTracking* pDominantTracking,

View File

@ -81,29 +81,11 @@ float nonLinearFilter(float in)
return val;
}
void sendButtonActionSimple(const char* action)
{
char command[256];
snprintf( command, sizeof( command ), "%s\n", action );
// Cbuf_AddText( command );
}
bool between(float min, float val, float max)
{
return (min < val) && (val < max);
}
void sendButtonAction(const char* action, long buttonDown)
{
char command[256];
snprintf( command, sizeof( command ), "%s\n", action );
if (!buttonDown)
{
command[0] = '-';
}
// Cbuf_AddText( command );
}
void acquireTrackedRemotesData(const ovrMobile *Ovr, double displayTime) {//The amount of yaw changed by controller
for ( int i = 0; ; i++ ) {
ovrInputCapabilityHeader cap;

View File

@ -189,11 +189,13 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
if (inventoryManagementMode)
{
if (firingPrimary)
sendButtonActionSimple("invuse");
{
//Select inventory item
}
}
else
{
sendButtonAction("+attack", firingPrimary);
//fire primary
}
}
}
@ -202,8 +204,10 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
if ((pDominantTrackedRemoteNew->Buttons & domButton1) !=
(pDominantTrackedRemoteOld->Buttons & domButton1) &&
ducked != DUCK_CROUCHED) {
ducked = (pDominantTrackedRemoteNew->Buttons & domButton1) ? DUCK_BUTTON : DUCK_NOTDUCKED;
sendButtonAction("+movedown", (pDominantTrackedRemoteNew->Buttons & domButton1));
//Trigger Duck
}
//Weapon/Inventory Chooser
@ -217,11 +221,11 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
{
if (inventoryManagementMode)
{
sendButtonActionSimple("invprev");
//Previous Inventory Item
}
else
{
sendButtonActionSimple("weapprev");
//Next Inventory Item
}
}
@ -229,11 +233,11 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
{
if (inventoryManagementMode)
{
sendButtonActionSimple("invnext");
//Next Inventory Item
}
else
{
sendButtonActionSimple("weapnext");
//Next Weapon
}
}
itemSwitched = true;
@ -279,7 +283,8 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
//show help computer while X/A pressed
if ((pOffTrackedRemoteNew->Buttons & offButton1) !=
(pOffTrackedRemoteOld->Buttons & offButton1)) {
sendButtonActionSimple("cmd help");
//Help Computer
}

View File

@ -44,7 +44,7 @@ LOCAL_C_INCLUDES := \
$(GZDOOM_TOP_PATH)/src/scripting \
$(GZDOOM_TOP_PATH)/src/scripting/vm \
$(GZDOOM_TOP_PATH)/src/posix \
$(GZDOOM_TOP_PATH)/src/posix\oculusquest \
$(GZDOOM_TOP_PATH)/src/posix\nosdl \
$(SDL_INCLUDE_PATHS) \
$(SUPPORT_LIBS)/fluidsynth-lite/include \
$(SUPPORT_LIBS)/openal/include/AL \
@ -71,17 +71,15 @@ PLAT_POSIX_SOURCES = \
posix/i_cd.cpp \
posix/i_steam.cpp
PLAT_OCULUSQUEST_SOURCES = \
posix/oculusquest/crashcatcher.c \
posix/oculusquest/hardware.cpp \
posix/oculusquest/i_gui.cpp \
posix/oculusquest/i_input.cpp \
posix/oculusquest/i_joystick.cpp \
posix/oculusquest/i_main.cpp \
posix/oculusquest/i_system.cpp \
posix/oculusquest/glvideo.cpp \
posix/oculusquest/video.cpp \
posix/oculusquest/st_start.cpp
PLAT_NOSDL_SOURCES = \
posix/nosdl/crashcatcher.c \
posix/nosdl/hardware.cpp \
posix/nosdl/i_gui.cpp \
posix/nosdl/i_joystick.cpp \
posix/nosdl/i_system.cpp \
posix/nosdl/glvideo.cpp \
posix/nosdl/video.cpp \
posix/nosdl/st_start.cpp
SWRENDER_SOURCES = \
swrenderer/r_swcanvas.cpp \
@ -595,7 +593,7 @@ LOCAL_SRC_FILES = \
$(QZDOOM_SRC) \
$(ANDROID_SRC_FILES) \
$(PLAT_POSIX_SOURCES) \
$(PLAT_OCULUSQUEST_SOURCES) \
$(PLAT_NOSDL_SOURCES) \
$(FASTMATH_SOURCES) \
$(PCH_SOURCES) \
x86.cpp \
@ -634,8 +632,8 @@ LOCAL_LDLIBS += -lEGL
# This is stop a linker warning for mp123 lib failing build
#LOCAL_LDLIBS += -Wl,--no-warn-shared-textrel
LOCAL_STATIC_LIBRARIES := sndfile mpg123 fluidsynth-static SDL2_net libjpeg zlib_lz lzma_lz gdtoa_lz dumb_lz gme_lz bzip2_lz
LOCAL_SHARED_LIBRARIES := openal SDL2 vrapi
LOCAL_STATIC_LIBRARIES := sndfile mpg123 fluidsynth-static libjpeg zlib_lz lzma_lz gdtoa_lz dumb_lz gme_lz bzip2_lz
LOCAL_SHARED_LIBRARIES := openal vrapi
LOCAL_STATIC_LIBRARIES +=

View File

@ -1064,7 +1064,7 @@ void D_DoomLoop ()
if (gametic > lasttic)
{
lasttic = gametic;
I_StartFrame ();
//I_StartFrame (); // not used
}
I_SetFrameTime();
@ -2339,6 +2339,9 @@ static void CheckCmdLine()
//
//==========================================================================
// The command line arguments.
FArgs *Args;
void VR_DoomMain(int argc, char** argv)
{
progdir = "/sdcard/QzDoom/";

View File

@ -9,365 +9,5 @@ void D_ConfirmSendStats()
{
}
#else // !NO_SEND_STATS
#if defined(_WIN32)
#define _WIN32_WINNT 0x0501
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
extern int sys_ostype;
#else
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#else // !__APPLE__
#include <SDL.h>
#endif // __APPLE__
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#endif
#include <thread>
#include "c_cvars.h"
#include "x86.h"
#include "version.h"
#include "v_video.h"
EXTERN_CVAR(Bool, vid_glswfb)
extern int currentrenderer;
CVAR(Int, sys_statsenabled, -1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOSET)
CVAR(String, sys_statshost, "gzstats.drdteam.org", CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOSET)
CVAR(Int, sys_statsport, 80, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOSET)
// Each machine will only send two reports, one when started with hardware rendering and one when started with software rendering.
#define CHECKVERSION 331
#define CHECKVERSIONSTR "331"
CVAR(Int, sentstats_swr_done, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOSET)
CVAR(Int, sentstats_hwr_done, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOSET)
std::pair<double, bool> gl_getInfo();
#ifdef _WIN32
bool I_HTTPRequest(const char* request)
{
if (sys_statshost.GetHumanString() == NULL)
return false; // no host, disable
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
DPrintf(DMSG_ERROR, "WSAStartup failed.\n");
return false;
}
SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct hostent *host;
host = gethostbyname(sys_statshost.GetHumanString());
if (host == nullptr)
{
DPrintf(DMSG_ERROR, "Error looking up hostname.\n");
return false;
}
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(sys_statsport);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((uint32_t*)host->h_addr);
DPrintf(DMSG_NOTIFY, "Connecting to host %s\n", sys_statshost.GetHumanString());
if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0)
{
DPrintf(DMSG_ERROR, "Connection to host %s failed!\n", sys_statshost.GetHumanString());
return false;
}
send(Socket, request, (int)strlen(request), 0);
char buffer[1024];
int nDataLength;
while ((nDataLength = recv(Socket, buffer, 1024, 0)) > 0)
{
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r')
{
i++;
}
}
closesocket(Socket);
WSACleanup();
DPrintf(DMSG_NOTIFY, "Stats send successful.\n");
return true;
}
#else
bool I_HTTPRequest(const char* request)
{
if (sys_statshost.GetHumanString() == NULL || sys_statshost.GetHumanString()[0] == 0)
return false; // no host, disable
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
portno = sys_statsport;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
DPrintf(DMSG_ERROR, "Error opening TCP socket.\n");
return false;
}
server = gethostbyname(sys_statshost.GetHumanString());
if (server == NULL)
{
DPrintf(DMSG_ERROR, "Error looking up hostname.\n");
return false;
}
bzero((char*) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
DPrintf(DMSG_NOTIFY, "Connecting to host %s\n", sys_statshost.GetHumanString());
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
DPrintf(DMSG_ERROR, "Connection to host %s failed!\n", sys_statshost.GetHumanString());
return false;
}
n = write(sockfd, request, strlen(request));
if (n<0)
{
DPrintf(DMSG_ERROR, "Error writing to socket.\n");
close(sockfd);
return false;
}
char buffer[1024] = {};
n = read(sockfd, buffer, 1023);
close(sockfd);
DPrintf(DMSG_NOTIFY, "Stats send successful.\n");
return true;
}
#endif
static int GetOSVersion()
{
#ifdef _WIN32
if (sys_ostype == 1) return 1;
if (sizeof(void*) == 4) // 32 bit
{
BOOL res;
if (IsWow64Process(GetCurrentProcess(), &res) && res)
{
return 6;
}
if (sys_ostype == 2) return 2;
else return 4;
}
else
{
if (sys_ostype == 2) return 3;
else return 5;
}
#elif defined __APPLE__
if (sizeof(void*) == 4) // 32 bit
{
return 7;
}
else
{
return 8;
}
#else
// fall-through linux stuff here
#ifdef __arm__
return 10;
#elif __ppc__
return 9;
#else
if (sizeof(void*) == 4) // 32 bit
{
return 11;
}
else
{
return 12;
}
#endif
#endif
}
#ifdef _WIN32
static int GetCoreInfo()
{
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL;
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = NULL;
DWORD returnLength = 0;
int cores = 0;
uint32_t byteOffset = 0;
auto rc = GetLogicalProcessorInformation(buffer, &returnLength);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(returnLength);
if (!GetLogicalProcessorInformation(buffer, &returnLength)) return 0;
}
else
{
return 0;
}
ptr = buffer;
while (byteOffset + sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength)
{
if (ptr->Relationship == RelationProcessorCore) cores++;
byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
ptr++;
}
free(buffer);
return cores < 2 ? 0 : cores < 4 ? 1 : cores < 6 ? 2 : cores < 8 ? 3 : 4;
}
#else
static int GetCoreInfo()
{
int cores = std::thread::hardware_concurrency();
if (CPU.HyperThreading) cores /= 2;
return cores < 2? 0 : cores < 4? 1 : cores < 6? 2 : cores < 8? 3 : 4;
}
#endif
static int GetRenderInfo()
{
if (currentrenderer == 0)
{
if (!screen->Accel2D) return 0;
if (vid_glswfb) return 2;
if (screen->LegacyHardware()) return 6;
return 1;
}
else
{
auto info = gl_getInfo();
if (info.first < 3.3) return 3; // Legacy OpenGL. Don't care about Intel HD 3000 on Windows being run in 'risky' mode.
if (!info.second) return 4;
return 5;
}
}
static void D_DoHTTPRequest(const char *request)
{
if (I_HTTPRequest(request))
{
if (currentrenderer == 0)
{
cvar_forceset("sentstats_swr_done", CHECKVERSIONSTR);
}
else
{
cvar_forceset("sentstats_hwr_done", CHECKVERSIONSTR);
}
}
}
void D_DoAnonStats()
{
if (sys_statsenabled != 1)
{
return;
}
static bool done = false; // do this only once per session.
if (done) return;
done = true;
// Do not repeat if already sent.
if (currentrenderer == 0 && sentstats_swr_done >= CHECKVERSION) return;
if (currentrenderer == 1 && sentstats_hwr_done >= CHECKVERSION) return;
static char requeststring[1024];
mysnprintf(requeststring, sizeof requeststring, "GET /stats.py?render=%i&cores=%i&os=%i&renderconfig=%i HTTP/1.1\nHost: %s\nConnection: close\nUser-Agent: %s %s\n\n",
GetRenderInfo(), GetCoreInfo(), GetOSVersion(), currentrenderer, sys_statshost.GetHumanString(), GAMENAME, VERSIONSTR);
DPrintf(DMSG_NOTIFY, "Sending %s", requeststring);
std::thread t1(D_DoHTTPRequest, requeststring);
t1.detach();
}
void D_ConfirmSendStats()
{
if (sys_statsenabled >= 0)
{
return;
}
// TODO: texts
static const char *const MESSAGE_TEXT = "In order to decide where to focus development, the GZDoom team would like to know a little bit about the hardware it is run on.\n" \
"For this we would like to ask you if we may send three bits of information to gzstats.drdteam.org.\n" \
"The three items we would like to know about are:\n" \
"- Operating system\n" \
"- Number of processor cores\n" \
"- Currently used renderer\n\n" \
"All information sent will be anonymous. We will NOT be sending this information to any third party.\n" \
"It will merely be used for decision-making about GZDoom's future development.\n" \
"Data will only be sent at most twice per system, once for the software renderer and once for the hardware renderer.\n" \
"If you are getting this notice more than once per renderer, please let us know on the forums. Thanks!\n\n" \
"May we send this data? If you click 'no', nothing will be sent and you will not be asked again.";
static const char *const TITLE_TEXT = "GZDoom needs your help!";
UCVarValue enabled = { 0 };
#ifdef _WIN32
extern HWND Window;
enabled.Int = MessageBoxA(Window, MESSAGE_TEXT, TITLE_TEXT, MB_ICONQUESTION | MB_YESNO) == IDYES;
#elif defined __APPLE__
const CFStringRef messageString = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, MESSAGE_TEXT, kCFStringEncodingASCII, kCFAllocatorNull);
const CFStringRef titleString = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, TITLE_TEXT, kCFStringEncodingASCII, kCFAllocatorNull);
if (messageString != nullptr && titleString != nullptr)
{
CFOptionFlags response;
const SInt32 result = CFUserNotificationDisplayAlert(0, kCFUserNotificationNoteAlertLevel, nullptr, nullptr, nullptr,
titleString, messageString, CFSTR("Yes"), CFSTR("No"), nullptr, &response);
enabled.Int = result == 0 && (response & 3) == kCFUserNotificationDefaultResponse;
CFRelease(titleString);
CFRelease(messageString);
}
#else // !__APPLE__
const SDL_MessageBoxButtonData buttons[] =
{
{ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 0, "Yes" },
{ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 1, "No" },
};
const SDL_MessageBoxData messageboxdata =
{
SDL_MESSAGEBOX_INFORMATION,
nullptr,
TITLE_TEXT,
MESSAGE_TEXT,
SDL_arraysize(buttons),
buttons,
nullptr
};
int buttonid;
enabled.Int = SDL_ShowMessageBox(&messageboxdata, &buttonid) == 0 && buttonid == 0;
#endif // _WIN32
sys_statsenabled.ForceSet(enabled, CVAR_Int);
}
#endif // NO_SEND_STATS

View File

@ -418,7 +418,7 @@ namespace s3d
leftEyeView.submitFrame();
rightEyeView.submitFrame();
submitFrame(&frameDesc);
submitFrame(&tracking);
}
static int mAngleFromRadians(double radians)
@ -639,7 +639,6 @@ namespace s3d
//Get controller state here
ovrTracking2 tracking;
getHMDOrientation(&tracking);
//Set up stuff used in the tracking code
@ -649,8 +648,6 @@ namespace s3d
doomYawDegrees = GLRenderer->mAngles.Yaw.Degrees;
getTrackedRemotesOrientation(vr_control_scheme);
frameDesc = setupFrameDescriptor(&tracking);
/* player_t* player = r_viewpoint.camera ? r_viewpoint.camera->player : nullptr;
{
LSMatrix44 mat;

View File

@ -102,7 +102,7 @@ protected:
mutable int cachedViewwidth, cachedViewheight, cachedViewwindowx, cachedViewwindowy;
mutable F2DDrawer * cached2DDrawer;
mutable F2DDrawer * crossHairDrawer;
mutable ovrSubmitFrameDescription2 frameDesc;
mutable ovrTracking2 tracking;
private:
typedef Stereo3DMode super;

View File

@ -19,9 +19,9 @@ class OpenGLFrameBuffer : public Win32GLFrameBuffer
typedef Win32GLFrameBuffer Super;
#else
//#include "sdlglvideo.h"
class OpenGLFrameBuffer : public OculusQuestGLFB
class OpenGLFrameBuffer : public NoSDLGLFB
{
typedef OculusQuestGLFB Super; //[C]commented, DECLARE_CLASS defines this in linux
typedef NoSDLGLFB Super; //[C]commented, DECLARE_CLASS defines this in linux
#endif

View File

@ -53,17 +53,8 @@ static void CATCH(int a, int b, int c, int d, int e)
int glesLoad = 3; // TODO fix this!
void* SDL_GL_GetProcAddress(const char* proc);
static void *MOBILE_GetProcAddress(const char* name)
{
/* static int jwzLoaded = 0;
if( ! jwzLoaded )
{
void jwzgles_reset (void);
jwzgles_reset ();
jwzLoaded = 1;
}
*/
static void* h = NULL;
if (h == NULL)
@ -80,7 +71,7 @@ static void *MOBILE_GetProcAddress(const char* name)
}
else if( glesLoad == 3 )
{
return SDL_GL_GetProcAddress( name );
h = dlopen("libGLESv3.so", RTLD_LAZY | RTLD_LOCAL);
}
if (h == NULL)
@ -95,7 +86,7 @@ static void *MOBILE_GetProcAddress(const char* name)
if( glesLoad == 1 )
sprintf(newName,"jwzgles_%s",name);
else if( glesLoad == 2 )
else
sprintf(newName,"%s",name);
//
@ -117,66 +108,7 @@ static void *MOBILE_GetProcAddress(const char* name)
#endif
#if defined(_WIN32)
#ifdef APIENTRY
#undef APIENTRY
#endif
#include <windows.h>
#ifdef _MSC_VER
// disable inlining here because it creates an incredible amount of bloat in this file.
#pragma inline_depth(0)
#pragma warning(disable: 4055)
#pragma warning(disable: 4054)
#pragma warning(disable: 4996)
#endif
static int TestPointer(const PROC pTest)
{
ptrdiff_t iTest;
if(!pTest) return 0;
iTest = (ptrdiff_t)pTest;
if(iTest == 1 || iTest == 2 || iTest == 3 || iTest == -1) return 0;
return 1;
}
static PROC WinGetProcAddress(const char *name)
{
HMODULE glMod = NULL;
PROC pFunc = wglGetProcAddress((LPCSTR)name);
if(TestPointer(pFunc))
{
return pFunc;
}
glMod = GetModuleHandleA("OpenGL32.dll");
return (PROC)GetProcAddress(glMod, (LPCSTR)name);
}
#define IntGetProcAddress(name) WinGetProcAddress(name)
#else
#if defined(__APPLE__)
#define IntGetProcAddress(name) AppleGLGetProcAddress(name)
#elif defined(__ANDROID__)
#define IntGetProcAddress(name) MOBILE_GetProcAddress((const char*)name)
#else
#if defined(__sgi) || defined(__sun) || defined(__unix__)
void* SDL_GL_GetProcAddress(const char* proc);
#define IntGetProcAddress(name) SDL_GL_GetProcAddress((const char*)name)
//#define IntGetProcAddress(name) PosixGetProcAddress((const GLubyte*)name)
/* END OF MANUAL CHANGES, DO NOT REMOVE! */
#else /* GLX */
#include <GL/glx.h>
#define IntGetProcAddress(name) (*glXGetProcAddressARB)((const GLubyte*)name)
#endif
#endif
#endif
#define IntGetProcAddress(name) MOBILE_GetProcAddress((const char*)name)
int ogl_ext_ARB_buffer_storage = ogl_LOAD_FAILED;
int ogl_ext_ARB_shader_storage_buffer_object = ogl_LOAD_FAILED;

View File

@ -19,9 +19,9 @@ class OpenGLSWFrameBuffer : public Win32GLFrameBuffer
typedef Win32GLFrameBuffer Super;
#else
#include "glvideo.h"
class OpenGLSWFrameBuffer : public OculusQuestGLFB
class OpenGLSWFrameBuffer : public NoSDLGLFB
{
typedef OculusQuestGLFB Super; //[C]commented, DECLARE_CLASS defines this in linux
typedef NoSDLGLFB Super; //[C]commented, DECLARE_CLASS defines this in linux
#endif

View File

@ -253,8 +253,8 @@ bool DMenu::CallMenuEvent(int mkey, bool fromcontroller)
static void SetMouseCapture(bool on)
{
if (on) I_SetMouseCapture();
else I_ReleaseMouseCapture();
// if (on) I_SetMouseCapture();
// else I_ReleaseMouseCapture();
}
DEFINE_ACTION_FUNCTION_NATIVE(DMenu, SetMouseCapture, SetMouseCapture)
{
@ -382,7 +382,7 @@ void M_ActivateMenu(DMenu *menu)
if (CurrentMenu != nullptr && CurrentMenu->mMouseCapture)
{
CurrentMenu->mMouseCapture = false;
I_ReleaseMouseCapture();
//I_ReleaseMouseCapture();
}
CurrentMenu = menu;
GC::WriteBarrier(CurrentMenu);

View File

@ -1,77 +0,0 @@
/*
** i_common.h
**
**---------------------------------------------------------------------------
** Copyright 2012-2015 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#ifndef COCOA_I_COMMON_INCLUDED
#define COCOA_I_COMMON_INCLUDED
#import <AppKit/AppKit.h>
struct RenderBufferOptions
{
float pixelScale;
float shiftX;
float shiftY;
float width;
float height;
bool dirty;
};
extern RenderBufferOptions rbOpts;
// Version of AppKit framework we are interested in
// The following values are needed to build with earlier SDKs
#define AppKit10_7 1138
#define AppKit10_8 1187
#define AppKit10_9 1265
@interface NSWindow(ExitAppOnClose)
- (void)exitAppOnClose;
@end
void I_ProcessEvent(NSEvent* event);
void I_ProcessJoysticks();
NSSize I_GetContentViewSize(const NSWindow* window);
void I_SetMainWindowVisible(bool visible);
void I_SetNativeMouse(bool wantNative);
#endif // COCOA_I_COMMON_INCLUDED

View File

@ -1,789 +0,0 @@
/*
** i_input.mm
**
**---------------------------------------------------------------------------
** Copyright 2012-2015 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "i_common.h"
#import <Carbon/Carbon.h>
#include "c_console.h"
#include "c_cvars.h"
#include "c_dispatch.h"
#include "d_event.h"
#include "d_gui.h"
#include "dikeys.h"
#include "doomdef.h"
#include "doomstat.h"
#include "v_video.h"
#include "events.h"
EXTERN_CVAR(Int, m_use_mouse)
CVAR(Bool, use_mouse, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Bool, m_noprescale, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Bool, m_filter, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Bool, k_allowfullscreentoggle, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG | CVAR_ARCHIVE)
{
if (self < 0)
{
self = 0;
}
else if (self > 2)
{
self = 2;
}
}
extern int paused, chatmodeon;
extern constate_e ConsoleState;
bool GUICapture;
namespace
{
// TODO: remove this magic!
size_t s_skipMouseMoves;
// ---------------------------------------------------------------------------
void CheckGUICapture()
{
bool wantCapture = (MENU_Off == menuactive)
? (c_down == ConsoleState || c_falling == ConsoleState || chatmodeon)
: (MENU_On == menuactive || MENU_OnNoPause == menuactive);
// [ZZ] check active event handlers that want the UI processing
if (!wantCapture && E_CheckUiProcessors())
{
wantCapture = true;
}
if (wantCapture != GUICapture)
{
GUICapture = wantCapture;
ResetButtonStates();
}
}
void SetCursorPosition(const NSPoint position)
{
NSWindow* window = [NSApp keyWindow];
if (nil == window)
{
return;
}
const NSRect displayRect = [[window screen] frame];
const CGPoint eventPoint = CGPointMake(position.x, displayRect.size.height - position.y);
CGEventSourceRef eventSource = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
if (NULL != eventSource)
{
CGEventRef mouseMoveEvent = CGEventCreateMouseEvent(eventSource,
kCGEventMouseMoved, eventPoint, kCGMouseButtonLeft);
if (NULL != mouseMoveEvent)
{
CGEventPost(kCGHIDEventTap, mouseMoveEvent);
CFRelease(mouseMoveEvent);
}
CFRelease(eventSource);
}
// TODO: remove this magic!
s_skipMouseMoves = 2;
}
void CenterCursor()
{
NSWindow* window = [NSApp keyWindow];
if (nil == window)
{
return;
}
const NSRect displayRect = [[window screen] frame];
const NSRect windowRect = [window frame];
const NSPoint centerPoint = { NSMidX(windowRect), NSMidY(windowRect) };
SetCursorPosition(centerPoint);
}
bool IsInGame()
{
switch (mouse_capturemode)
{
default:
case 0:
return gamestate == GS_LEVEL;
case 1:
return gamestate == GS_LEVEL
|| gamestate == GS_INTERMISSION
|| gamestate == GS_FINALE;
case 2:
return true;
}
}
void CheckNativeMouse()
{
const bool windowed = (NULL == screen) || !screen->IsFullscreen();
bool wantNative;
if (windowed)
{
if (![NSApp isActive] || !use_mouse)
{
wantNative = true;
}
else if (MENU_WaitKey == menuactive)
{
wantNative = false;
}
else
{
wantNative = (!m_use_mouse || MENU_WaitKey != menuactive)
&& (!IsInGame() || GUICapture || paused || demoplayback);
}
}
else
{
// ungrab mouse when in the menu with mouse control on.
wantNative = m_use_mouse
&& (MENU_On == menuactive || MENU_OnNoPause == menuactive);
}
if (!wantNative && E_CheckRequireMouse())
wantNative = true;
I_SetNativeMouse(wantNative);
}
} // unnamed namespace
void I_GetEvent()
{
[[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
}
void I_StartTic()
{
CheckGUICapture();
CheckNativeMouse();
I_ProcessJoysticks();
I_GetEvent();
}
void I_StartFrame()
{
}
void I_SetMouseCapture()
{
}
void I_ReleaseMouseCapture()
{
}
void I_SetNativeMouse(bool wantNative)
{
static bool nativeMouse = true;
static NSPoint mouseLocation;
if (wantNative != nativeMouse)
{
nativeMouse = wantNative;
if (!wantNative)
{
mouseLocation = [NSEvent mouseLocation];
CenterCursor();
}
CGAssociateMouseAndMouseCursorPosition(wantNative);
if (wantNative)
{
SetCursorPosition(mouseLocation);
[NSCursor unhide];
}
else
{
[NSCursor hide];
}
}
}
// ---------------------------------------------------------------------------
namespace
{
const size_t KEY_COUNT = 128;
// See Carbon -> HIToolbox -> Events.h for kVK_ constants
const uint8_t KEYCODE_TO_DIK[KEY_COUNT] =
{
DIK_A, DIK_S, DIK_D, DIK_F, DIK_H, DIK_G, DIK_Z, DIK_X, // 0x00 - 0x07
DIK_C, DIK_V, 0, DIK_B, DIK_Q, DIK_W, DIK_E, DIK_R, // 0x08 - 0x0F
DIK_Y, DIK_T, DIK_1, DIK_2, DIK_3, DIK_4, DIK_6, DIK_5, // 0x10 - 0x17
DIK_EQUALS, DIK_9, DIK_7, DIK_MINUS, DIK_8, DIK_0, DIK_RBRACKET, DIK_O, // 0x18 - 0x1F
DIK_U, DIK_LBRACKET, DIK_I, DIK_P, DIK_RETURN, DIK_L, DIK_J, DIK_APOSTROPHE, // 0x20 - 0x27
DIK_K, DIK_SEMICOLON, DIK_BACKSLASH, DIK_COMMA, DIK_SLASH, DIK_N, DIK_M, DIK_PERIOD, // 0x28 - 0x2F
DIK_TAB, DIK_SPACE, DIK_GRAVE, DIK_BACK, 0, DIK_ESCAPE, 0, DIK_LWIN, // 0x30 - 0x37
DIK_LSHIFT, DIK_CAPITAL, DIK_LMENU, DIK_LCONTROL, DIK_RSHIFT, DIK_RMENU, DIK_RCONTROL, 0, // 0x38 - 0x3F
0, DIK_DECIMAL, 0, DIK_MULTIPLY, 0, DIK_ADD, 0, 0, // 0x40 - 0x47
DIK_VOLUMEUP, DIK_VOLUMEDOWN, DIK_MUTE, DIK_SLASH, DIK_NUMPADENTER, 0, DIK_SUBTRACT, 0, // 0x48 - 0x4F
0, DIK_NUMPAD_EQUALS, DIK_NUMPAD0, DIK_NUMPAD1, DIK_NUMPAD2, DIK_NUMPAD3, DIK_NUMPAD4, DIK_NUMPAD5, // 0x50 - 0x57
DIK_NUMPAD6, DIK_NUMPAD7, 0, DIK_NUMPAD8, DIK_NUMPAD9, 0, 0, 0, // 0x58 - 0x5F
DIK_F5, DIK_F6, DIK_F7, DIK_F3, DIK_F8, DIK_F9, 0, DIK_F11, // 0x60 - 0x67
0, DIK_F13, 0, DIK_F14, 0, DIK_F10, 0, DIK_F12, // 0x68 - 0x6F
0, DIK_F15, 0, DIK_HOME, 0, DIK_DELETE, DIK_F4, DIK_END, // 0x70 - 0x77
DIK_F2, 0, DIK_F1, DIK_LEFT, DIK_RIGHT, DIK_DOWN, DIK_UP, 0, // 0x78 - 0x7F
};
const uint8_t KEYCODE_TO_ASCII[KEY_COUNT] =
{
'a', 's', 'd', 'f', 'h', 'g', 'z', 'x', // 0x00 - 0x07
'c', 'v', 0, 'b', 'q', 'w', 'e', 'r', // 0x08 - 0x0F
'y', 't', '1', '2', '3', '4', '6', '5', // 0x10 - 0x17
'=', '9', '7', '-', '8', '0', ']', 'o', // 0x18 - 0x1F
'u', '[', 'i', 'p', 13, 'l', 'j', '\'', // 0x20 - 0x27
'k', ';', '\\', ',', '/', 'n', 'm', '.', // 0x28 - 0x2F
9, ' ', '`', 12, 0, 27, 0, 0, // 0x30 - 0x37
0, 0, 0, 0, 0, 0, 0, 0, // 0x38 - 0x3F
0, 0, 0, 0, 0, 0, 0, 0, // 0x40 - 0x47
0, 0, 0, 0, 0, 0, 0, 0, // 0x48 - 0x4F
0, 0, 0, 0, 0, 0, 0, 0, // 0x50 - 0x57
0, 0, 0, 0, 0, 0, 0, 0, // 0x58 - 0x5F
0, 0, 0, 0, 0, 0, 0, 0, // 0x60 - 0x67
0, 0, 0, 0, 0, 0, 0, 0, // 0x68 - 0x6F
0, 0, 0, 0, 0, 0, 0, 0, // 0x70 - 0x77
0, 0, 0, 0, 0, 0, 0, 0, // 0x78 - 0x7F
};
uint8_t ModifierToDIK(const uint32_t modifier)
{
switch (modifier)
{
case NSAlphaShiftKeyMask: return DIK_CAPITAL;
case NSShiftKeyMask: return DIK_LSHIFT;
case NSControlKeyMask: return DIK_LCONTROL;
case NSAlternateKeyMask: return DIK_LMENU;
case NSCommandKeyMask: return DIK_LWIN;
}
return 0;
}
int16_t ModifierFlagsToGUIKeyModifiers(NSEvent* theEvent)
{
const NSUInteger modifiers([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask);
return ((modifiers & NSShiftKeyMask ) ? GKM_SHIFT : 0)
| ((modifiers & NSControlKeyMask ) ? GKM_CTRL : 0)
| ((modifiers & NSAlternateKeyMask) ? GKM_ALT : 0)
| ((modifiers & NSCommandKeyMask ) ? GKM_META : 0);
}
bool ShouldGenerateGUICharEvent(NSEvent* theEvent)
{
const NSUInteger modifiers([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask);
return !(modifiers & NSControlKeyMask)
&& !(modifiers & NSAlternateKeyMask)
&& !(modifiers & NSCommandKeyMask)
&& !(modifiers & NSFunctionKeyMask);
}
NSStringEncoding GetEncodingForUnicodeCharacter(const unichar character)
{
if (character >= L'\u0100' && character <= L'\u024F')
{
return NSWindowsCP1250StringEncoding; // Central and Eastern Europe
}
else if (character >= L'\u0370' && character <= L'\u03FF')
{
return NSWindowsCP1253StringEncoding; // Greek
}
else if (character >= L'\u0400' && character <= L'\u04FF')
{
return NSWindowsCP1251StringEncoding; // Cyrillic
}
// TODO: add handling for other characters
// TODO: Turkish should use NSWindowsCP1254StringEncoding
return NSWindowsCP1252StringEncoding;
}
unsigned char GetCharacterFromNSEvent(NSEvent* theEvent, unichar *realchar)
{
const NSString* unicodeCharacters = [theEvent characters];
if (0 == [unicodeCharacters length])
{
return '\0';
}
const unichar unicodeCharacter = [unicodeCharacters characterAtIndex:0];
const NSStringEncoding encoding = GetEncodingForUnicodeCharacter(unicodeCharacter);
unsigned char character = '\0';
if (NSWindowsCP1252StringEncoding == encoding)
{
// TODO: make sure that the following is always correct
character = unicodeCharacter & 0xFF;
}
else
{
const NSData* const characters =
[[theEvent characters] dataUsingEncoding:encoding];
character = [characters length] > 0
? *static_cast<const unsigned char*>([characters bytes])
: '\0';
}
*realchar = unicodeCharacter;
return character;
}
void ProcessKeyboardEventInMenu(NSEvent* theEvent)
{
event_t event = {};
unichar realchar;
event.type = EV_GUI_Event;
event.subtype = NSKeyDown == [theEvent type] ? EV_GUI_KeyDown : EV_GUI_KeyUp;
event.data2 = GetCharacterFromNSEvent(theEvent, &realchar);
event.data3 = ModifierFlagsToGUIKeyModifiers(theEvent);
if (EV_GUI_KeyDown == event.subtype && [theEvent isARepeat])
{
event.subtype = EV_GUI_KeyRepeat;
}
const unsigned short keyCode = [theEvent keyCode];
switch (keyCode)
{
case kVK_Return: event.data1 = GK_RETURN; break;
case kVK_PageUp: event.data1 = GK_PGUP; break;
case kVK_PageDown: event.data1 = GK_PGDN; break;
case kVK_End: event.data1 = GK_END; break;
case kVK_Home: event.data1 = GK_HOME; break;
case kVK_LeftArrow: event.data1 = GK_LEFT; break;
case kVK_RightArrow: event.data1 = GK_RIGHT; break;
case kVK_UpArrow: event.data1 = GK_UP; break;
case kVK_DownArrow: event.data1 = GK_DOWN; break;
case kVK_Delete: event.data1 = GK_BACKSPACE; break;
case kVK_ForwardDelete: event.data1 = GK_DEL; break;
case kVK_Escape: event.data1 = GK_ESCAPE; break;
case kVK_F1: event.data1 = GK_F1; break;
case kVK_F2: event.data1 = GK_F2; break;
case kVK_F3: event.data1 = GK_F3; break;
case kVK_F4: event.data1 = GK_F4; break;
case kVK_F5: event.data1 = GK_F5; break;
case kVK_F6: event.data1 = GK_F6; break;
case kVK_F7: event.data1 = GK_F7; break;
case kVK_F8: event.data1 = GK_F8; break;
case kVK_F9: event.data1 = GK_F9; break;
case kVK_F10: event.data1 = GK_F10; break;
case kVK_F11: event.data1 = GK_F11; break;
case kVK_F12: event.data1 = GK_F12; break;
case kVK_F13: event.data1 = GK_SYSRQ; break;
default:
event.data1 = KEYCODE_TO_ASCII[keyCode];
break;
}
if (event.data1 < 128)
{
event.data1 = toupper(event.data1);
D_PostEvent(&event);
}
if (!iscntrl(event.data2)
&& EV_GUI_KeyUp != event.subtype
&& ShouldGenerateGUICharEvent(theEvent))
{
event.subtype = EV_GUI_Char;
event.data1 = realchar;
event.data2 = event.data3 & GKM_ALT;
D_PostEvent(&event);
}
}
void NSEventToGameMousePosition(NSEvent* inEvent, event_t* outEvent)
{
const NSWindow* window = [inEvent window];
const NSView* view = [window contentView];
const NSPoint screenPos = [NSEvent mouseLocation];
const NSRect screenRect = NSMakeRect(screenPos.x, screenPos.y, 0, 0);
const NSRect windowRect = [window convertRectFromScreen:screenRect];
const NSPoint viewPos = [view convertPointToBacking:windowRect.origin];
const CGFloat frameHeight = I_GetContentViewSize(window).height;
outEvent->data1 = static_cast<int16_t>( viewPos.x);
outEvent->data2 = static_cast<int16_t>(frameHeight - viewPos.y);
// Compensate letterbox adjustment done by cross-platform code
// More elegant solution is a bit problematic due to HiDPI/Retina support
outEvent->data2 += (int(frameHeight) - screen->VideoHeight) / 2;
screen->ScaleCoordsFromWindow(outEvent->data1, outEvent->data2);
}
void ProcessMouseMoveInMenu(NSEvent* theEvent)
{
event_t event = {};
event.type = EV_GUI_Event;
event.subtype = EV_GUI_MouseMove;
event.data3 = ModifierFlagsToGUIKeyModifiers(theEvent);
NSEventToGameMousePosition(theEvent, &event);
D_PostEvent(&event);
}
void ProcessMouseMoveInGame(NSEvent* theEvent)
{
int x([theEvent deltaX]);
int y(-[theEvent deltaY]);
if (0 == x && 0 == y)
{
return;
}
if (!m_noprescale)
{
x *= 3;
y *= 2;
}
event_t event = {};
static int lastX = 0, lastY = 0;
if (m_filter)
{
event.x = (x + lastX) / 2;
event.y = (y + lastY) / 2;
}
else
{
event.x = x;
event.y = y;
}
lastX = x;
lastY = y;
if (0 != event.x || 0 != event.y)
{
event.type = EV_Mouse;
D_PostEvent(&event);
}
}
void ProcessKeyboardEvent(NSEvent* theEvent)
{
const unsigned short keyCode = [theEvent keyCode];
if (keyCode >= KEY_COUNT)
{
assert(!"Unknown keycode");
return;
}
const bool isARepeat = [theEvent isARepeat];
if (k_allowfullscreentoggle
&& (kVK_ANSI_F == keyCode)
&& (NSCommandKeyMask & [theEvent modifierFlags])
&& (NSKeyDown == [theEvent type])
&& !isARepeat)
{
ToggleFullscreen = !ToggleFullscreen;
return;
}
if (GUICapture)
{
ProcessKeyboardEventInMenu(theEvent);
}
else if (!isARepeat)
{
event_t event = {};
event.type = NSKeyDown == [theEvent type] ? EV_KeyDown : EV_KeyUp;
event.data1 = KEYCODE_TO_DIK[ keyCode ];
if (0 != event.data1)
{
event.data2 = KEYCODE_TO_ASCII[ keyCode ];
D_PostEvent(&event);
}
}
}
void ProcessKeyboardFlagsEvent(NSEvent* theEvent)
{
if (GUICapture)
{
// Ignore events from modifier keys in menu/console/chat
return;
}
static const uint32_t FLAGS_MASK =
NSDeviceIndependentModifierFlagsMask & ~NSNumericPadKeyMask;
const uint32_t modifiers = [theEvent modifierFlags] & FLAGS_MASK;
static uint32_t oldModifiers = 0;
const uint32_t deltaModifiers = modifiers ^ oldModifiers;
if (0 == deltaModifiers)
{
return;
}
event_t event = {};
event.type = modifiers > oldModifiers ? EV_KeyDown : EV_KeyUp;
event.data1 = ModifierToDIK(deltaModifiers);
oldModifiers = modifiers;
if (DIK_CAPITAL == event.data1)
{
// Caps Lock is a modifier key which generates one event per state change
// but not per actual key press or release. So treat any event as key down
event.type = EV_KeyDown;
}
D_PostEvent(&event);
}
void ProcessMouseMoveEvent(NSEvent* theEvent)
{
if (!use_mouse)
{
return;
}
if (s_skipMouseMoves > 0)
{
--s_skipMouseMoves;
return;
}
if (GUICapture)
{
ProcessMouseMoveInMenu(theEvent);
}
else
{
ProcessMouseMoveInGame(theEvent);
}
}
void ProcessMouseButtonEvent(NSEvent* theEvent)
{
if (!use_mouse)
{
return;
}
event_t event = {};
const NSEventType cocoaEventType = [theEvent type];
if (GUICapture)
{
event.type = EV_GUI_Event;
event.data3 = ModifierFlagsToGUIKeyModifiers(theEvent);
switch (cocoaEventType)
{
case NSLeftMouseDown: event.subtype = EV_GUI_LButtonDown; break;
case NSRightMouseDown: event.subtype = EV_GUI_RButtonDown; break;
case NSOtherMouseDown: event.subtype = EV_GUI_MButtonDown; break;
case NSLeftMouseUp: event.subtype = EV_GUI_LButtonUp; break;
case NSRightMouseUp: event.subtype = EV_GUI_RButtonUp; break;
case NSOtherMouseUp: event.subtype = EV_GUI_MButtonUp; break;
default: break;
}
NSEventToGameMousePosition(theEvent, &event);
D_PostEvent(&event);
}
else
{
switch (cocoaEventType)
{
case NSLeftMouseDown:
case NSRightMouseDown:
case NSOtherMouseDown:
event.type = EV_KeyDown;
break;
case NSLeftMouseUp:
case NSRightMouseUp:
case NSOtherMouseUp:
event.type = EV_KeyUp;
break;
default:
break;
}
event.data1 = MIN(KEY_MOUSE1 + [theEvent buttonNumber], NSInteger(KEY_MOUSE8));
D_PostEvent(&event);
}
}
void ProcessMouseWheelEvent(NSEvent* theEvent)
{
if (!use_mouse)
{
return;
}
const int16_t modifiers = ModifierFlagsToGUIKeyModifiers(theEvent);
const CGFloat delta = (modifiers & GKM_SHIFT)
? [theEvent deltaX]
: [theEvent deltaY];
const bool isZeroDelta = fabs(delta) < 1.0E-5;
if (isZeroDelta && GUICapture)
{
return;
}
event_t event = {};
if (GUICapture)
{
event.type = EV_GUI_Event;
event.subtype = delta > 0.0f ? EV_GUI_WheelUp : EV_GUI_WheelDown;
event.data3 = modifiers;
}
else
{
event.type = isZeroDelta ? EV_KeyUp : EV_KeyDown;
event.data1 = delta > 0.0f ? KEY_MWHEELUP : KEY_MWHEELDOWN;
}
D_PostEvent(&event);
}
} // unnamed namespace
void I_ProcessEvent(NSEvent* event)
{
const NSEventType eventType = [event type];
switch (eventType)
{
case NSMouseMoved:
ProcessMouseMoveEvent(event);
break;
case NSLeftMouseDown:
case NSLeftMouseUp:
case NSRightMouseDown:
case NSRightMouseUp:
case NSOtherMouseDown:
case NSOtherMouseUp:
ProcessMouseButtonEvent(event);
break;
case NSLeftMouseDragged:
case NSRightMouseDragged:
case NSOtherMouseDragged:
ProcessMouseButtonEvent(event);
ProcessMouseMoveEvent(event);
break;
case NSScrollWheel:
ProcessMouseWheelEvent(event);
break;
case NSKeyDown:
case NSKeyUp:
ProcessKeyboardEvent(event);
break;
case NSFlagsChanged:
ProcessKeyboardFlagsEvent(event);
break;
default:
break;
}
}

View File

@ -1,531 +0,0 @@
/*
** i_main.mm
**
**---------------------------------------------------------------------------
** Copyright 2012-2018 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "i_common.h"
#include "s_sound.h"
#include "atterm.h"
#include <sys/sysctl.h>
#include <unistd.h>
#include "c_console.h"
#include "c_cvars.h"
#include "cmdlib.h"
#include "d_main.h"
#include "doomerrors.h"
#include "i_system.h"
#include "m_argv.h"
#include "s_sound.h"
#include "st_console.h"
#include "version.h"
#include "s_music.h"
#define ZD_UNUSED(VARIABLE) ((void)(VARIABLE))
// ---------------------------------------------------------------------------
CVAR (Bool, i_soundinbackground, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
EXTERN_CVAR(Int, vid_defwidth )
EXTERN_CVAR(Int, vid_defheight)
EXTERN_CVAR(Bool, vid_vsync )
EXTERN_CVAR(Bool, fullscreen )
// ---------------------------------------------------------------------------
void Mac_I_FatalError(const char* const message)
{
I_SetMainWindowVisible(false);
S_StopMusic(true);
FConsoleWindow::GetInstance().ShowFatalError(message);
}
static void I_DetectOS()
{
SInt32 majorVersion = 0;
Gestalt(gestaltSystemVersionMajor, &majorVersion);
SInt32 minorVersion = 0;
Gestalt(gestaltSystemVersionMinor, &minorVersion);
SInt32 bugFixVersion = 0;
Gestalt(gestaltSystemVersionBugFix, &bugFixVersion);
const char* name = "Unknown version";
if (10 == majorVersion) switch (minorVersion)
{
case 4: name = "Mac OS X Tiger"; break;
case 5: name = "Mac OS X Leopard"; break;
case 6: name = "Mac OS X Snow Leopard"; break;
case 7: name = "Mac OS X Lion"; break;
case 8: name = "OS X Mountain Lion"; break;
case 9: name = "OS X Mavericks"; break;
case 10: name = "OS X Yosemite"; break;
case 11: name = "OS X El Capitan"; break;
case 12: name = "macOS Sierra"; break;
case 13: name = "macOS High Sierra"; break;
case 14: name = "macOS Mojave"; break;
case 15: name = "macOS Catalina"; break;
}
char release[16] = "unknown";
size_t size = sizeof release - 1;
sysctlbyname("kern.osversion", release, &size, nullptr, 0);
const char* const architecture =
#ifdef __i386__
"32-bit Intel";
#elif defined __x86_64__
"64-bit Intel";
#else
"Unknown";
#endif
Printf("OS: %s %d.%d.%d (%s) %s\n", name,
int(majorVersion), int(minorVersion), int(bugFixVersion),
release, architecture);
}
FArgs* Args; // command line arguments
// Newer versions of GCC than 4.2 have a bug with C++ exceptions in Objective-C++ code.
// To work around we'll implement the try and catch in standard C++.
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61759
void OriginalMainExcept(int argc, char** argv);
void OriginalMainTry(int argc, char** argv)
{
Args = new FArgs(argc, argv);
/*
killough 1/98:
This fixes some problems with exit handling
during abnormal situations.
The old code called I_Quit() to end program,
while now I_Quit() is installed as an exit
handler and exit() is called to exit, either
normally or abnormally. Seg faults are caught
and the error handler is used, to prevent
being left in graphics mode or having very
loud SFX noise because the sound card is
left in an unstable state.
*/
atexit(call_terms);
atterm(I_Quit);
NSString* exePath = [[NSBundle mainBundle] executablePath];
progdir = [[exePath stringByDeletingLastPathComponent] UTF8String];
progdir += "/";
C_InitConsole(80 * 8, 25 * 8, false);
I_DetectOS();
D_DoomMain();
}
namespace
{
TArray<FString> s_argv;
void NewFailure()
{
I_FatalError("Failed to allocate memory from system heap");
}
int OriginalMain(int argc, char** argv)
{
printf(GAMENAME" %s - %s - Cocoa version\nCompiled on %s\n\n",
GetVersionString(), GetGitTime(), __DATE__);
seteuid(getuid());
std::set_new_handler(NewFailure);
// Set LC_NUMERIC environment variable in case some library decides to
// clear the setlocale call at least this will be correct.
// Note that the LANG environment variable is overridden by LC_*
setenv("LC_NUMERIC", "C", 1);
setlocale(LC_ALL, "C");
// Set reasonable default values for video settings
const NSSize screenSize = [[NSScreen mainScreen] frame].size;
vid_defwidth = static_cast<int>(screenSize.width);
vid_defheight = static_cast<int>(screenSize.height);
vid_vsync = true;
fullscreen = true;
OriginalMainExcept(argc, argv);
return 0;
}
} // unnamed namespace
// ---------------------------------------------------------------------------
@interface ApplicationController : NSResponder<NSApplicationDelegate>
{
}
- (void)keyDown:(NSEvent*)theEvent;
- (void)keyUp:(NSEvent*)theEvent;
- (void)applicationDidBecomeActive:(NSNotification*)aNotification;
- (void)applicationWillResignActive:(NSNotification*)aNotification;
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification;
- (BOOL)application:(NSApplication*)theApplication openFile:(NSString*)filename;
- (void)processEvents:(NSTimer*)timer;
@end
ApplicationController* appCtrl;
@implementation ApplicationController
- (void)keyDown:(NSEvent*)theEvent
{
// Empty but present to avoid playing of 'beep' alert sound
ZD_UNUSED(theEvent);
}
- (void)keyUp:(NSEvent*)theEvent
{
// Empty but present to avoid playing of 'beep' alert sound
ZD_UNUSED(theEvent);
}
extern bool AppActive;
- (void)applicationDidBecomeActive:(NSNotification*)aNotification
{
ZD_UNUSED(aNotification);
S_SetSoundPaused(1);
AppActive = true;
}
- (void)applicationWillResignActive:(NSNotification*)aNotification
{
ZD_UNUSED(aNotification);
S_SetSoundPaused(i_soundinbackground);
AppActive = false;
}
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification
{
// When starting from command line with real executable path, e.g. ZDoom.app/Contents/MacOS/ZDoom
// application remains deactivated for an unknown reason.
// The following call resolves this issue
[NSApp activateIgnoringOtherApps:YES];
// Setup timer for custom event loop
NSTimer* timer = [NSTimer timerWithTimeInterval:0
target:self
selector:@selector(processEvents:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSDefaultRunLoopMode];
FConsoleWindow::CreateInstance();
atterm(FConsoleWindow::DeleteInstance);
const size_t argc = s_argv.Size();
TArray<char*> argv(argc + 1, true);
for (size_t i = 0; i < argc; ++i)
{
argv[i] = s_argv[i].LockBuffer();
}
argv[argc] = nullptr;
exit(OriginalMain(argc, &argv[0]));
}
- (BOOL)application:(NSApplication*)theApplication openFile:(NSString*)filename
{
ZD_UNUSED(theApplication);
// Some parameters from command line are passed to this function
// These parameters need to be skipped to avoid duplication
// Note: SDL has different approach to fix this issue, see the same method in SDLMain.m
const char* const charFileName = [filename UTF8String];
for (size_t i = 0, count = s_argv.Size(); i < count; ++i)
{
if (0 == strcmp(s_argv[i], charFileName))
{
return FALSE;
}
}
bool iwad = false;
if (const char* const extPos = strrchr(charFileName, '.'))
{
iwad = 0 == stricmp(extPos, ".iwad")
|| 0 == stricmp(extPos, ".ipk3")
|| 0 == stricmp(extPos, ".ipk7");
}
s_argv.Push(iwad ? "-iwad" : "-file");
s_argv.Push(charFileName);
return TRUE;
}
- (void)processEvents:(NSTimer*)timer
{
ZD_UNUSED(timer);
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
while (true)
{
NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate dateWithTimeIntervalSinceNow:0]
inMode:NSDefaultRunLoopMode
dequeue:YES];
if (nil == event)
{
break;
}
I_ProcessEvent(event);
[NSApp sendEvent:event];
}
[NSApp updateWindows];
[pool release];
}
@end
// ---------------------------------------------------------------------------
namespace
{
NSMenuItem* CreateApplicationMenu()
{
NSMenu* menu = [NSMenu new];
[menu addItemWithTitle:[@"About " stringByAppendingString:@GAMENAME]
action:@selector(orderFrontStandardAboutPanel:)
keyEquivalent:@""];
[menu addItem:[NSMenuItem separatorItem]];
[menu addItemWithTitle:[@"Hide " stringByAppendingString:@GAMENAME]
action:@selector(hide:)
keyEquivalent:@"h"];
[[menu addItemWithTitle:@"Hide Others"
action:@selector(hideOtherApplications:)
keyEquivalent:@"h"]
setKeyEquivalentModifierMask:NSAlternateKeyMask | NSCommandKeyMask];
[menu addItemWithTitle:@"Show All"
action:@selector(unhideAllApplications:)
keyEquivalent:@""];
[menu addItem:[NSMenuItem separatorItem]];
[menu addItemWithTitle:[@"Quit " stringByAppendingString:@GAMENAME]
action:@selector(terminate:)
keyEquivalent:@"q"];
NSMenuItem* menuItem = [NSMenuItem new];
[menuItem setSubmenu:menu];
if ([NSApp respondsToSelector:@selector(setAppleMenu:)])
{
[NSApp performSelector:@selector(setAppleMenu:) withObject:menu];
}
return menuItem;
}
NSMenuItem* CreateEditMenu()
{
NSMenu* menu = [[NSMenu alloc] initWithTitle:@"Edit"];
[menu addItemWithTitle:@"Undo"
action:@selector(undo:)
keyEquivalent:@"z"];
[menu addItemWithTitle:@"Redo"
action:@selector(redo:)
keyEquivalent:@"Z"];
[menu addItem:[NSMenuItem separatorItem]];
[menu addItemWithTitle:@"Cut"
action:@selector(cut:)
keyEquivalent:@"x"];
[menu addItemWithTitle:@"Copy"
action:@selector(copy:)
keyEquivalent:@"c"];
[menu addItemWithTitle:@"Paste"
action:@selector(paste:)
keyEquivalent:@"v"];
[menu addItemWithTitle:@"Delete"
action:@selector(delete:)
keyEquivalent:@""];
[menu addItemWithTitle:@"Select All"
action:@selector(selectAll:)
keyEquivalent:@"a"];
NSMenuItem* menuItem = [NSMenuItem new];
[menuItem setSubmenu:menu];
return menuItem;
}
NSMenuItem* CreateWindowMenu()
{
NSMenu* menu = [[NSMenu alloc] initWithTitle:@"Window"];
[NSApp setWindowsMenu:menu];
[menu addItemWithTitle:@"Minimize"
action:@selector(performMiniaturize:)
keyEquivalent:@"m"];
[menu addItemWithTitle:@"Zoom"
action:@selector(performZoom:)
keyEquivalent:@""];
[menu addItem:[NSMenuItem separatorItem]];
[menu addItemWithTitle:@"Bring All to Front"
action:@selector(arrangeInFront:)
keyEquivalent:@""];
NSMenuItem* menuItem = [NSMenuItem new];
[menuItem setSubmenu:menu];
return menuItem;
}
void CreateMenu()
{
NSMenu* menuBar = [NSMenu new];
[menuBar addItem:CreateApplicationMenu()];
[menuBar addItem:CreateEditMenu()];
[menuBar addItem:CreateWindowMenu()];
[NSApp setMainMenu:menuBar];
}
void ReleaseApplicationController()
{
if (NULL != appCtrl)
{
[NSApp setDelegate:nil];
[NSApp deactivate];
[appCtrl release];
appCtrl = NULL;
}
}
} // unnamed namespace
int main(int argc, char** argv)
{
for (int i = 0; i < argc; ++i)
{
const char* const argument = argv[i];
#if _DEBUG
if (0 == strcmp(argument, "-wait_for_debugger"))
{
NSAlert* alert = [[NSAlert alloc] init];
[alert setMessageText:@GAMENAME];
[alert setInformativeText:@"Waiting for debugger..."];
[alert addButtonWithTitle:@"Continue"];
[alert runModal];
}
#endif // _DEBUG
s_argv.Push(argument);
}
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
[NSApplication sharedApplication];
// The following code isn't mandatory,
// but it enables to run the application without a bundle
if ([NSApp respondsToSelector:@selector(setActivationPolicy:)])
{
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
}
CreateMenu();
atterm(ReleaseApplicationController);
appCtrl = [ApplicationController new];
[NSApp setDelegate:appCtrl];
[NSApp run];
[pool release];
return EXIT_SUCCESS;
}

View File

@ -1,79 +0,0 @@
/*
** i_main_except.cpp
**
**---------------------------------------------------------------------------
** Copyright 2012-2015 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
// Workaround for GCC Objective-C++ with C++ exceptions bug.
#include <stdlib.h>
#include "doomerrors.h"
#include "vm.h"
#include "atterm.h"
// Import some functions from i_main.mm
void Mac_I_FatalError(const char* const message);
void OriginalMainTry(int argc, char** argv);
void OriginalMainExcept(int argc, char** argv)
{
try
{
OriginalMainTry(argc, argv);
}
catch(const std::exception& error)
{
const char* const message = error.what();
if (strcmp(message, "NoRunExit"))
{
if (CVMAbortException::stacktrace.IsNotEmpty())
{
Printf("%s", CVMAbortException::stacktrace.GetChars());
}
if (batchrun)
{
Printf("%s\n", message);
}
else
{
Mac_I_FatalError(message);
}
}
exit(-1);
}
catch(...)
{
call_terms();
throw;
}
}

View File

@ -1,376 +0,0 @@
/*
** i_system.mm
**
**---------------------------------------------------------------------------
** Copyright 2012-2018 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "i_common.h"
#include <fnmatch.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include "d_protocol.h"
#include "doomdef.h"
#include "doomerrors.h"
#include "doomstat.h"
#include "g_game.h"
#include "gameconfigfile.h"
#include "i_sound.h"
#include "i_system.h"
#include "st_console.h"
#include "v_text.h"
#include "x86.h"
#include "cmdlib.h"
#include "atterm.h"
void I_Tactile(int /*on*/, int /*off*/, int /*total*/)
{
}
ticcmd_t* I_BaseTiccmd()
{
static ticcmd_t emptycmd;
return &emptycmd;
}
double PerfToSec, PerfToMillisec;
static void CalculateCPUSpeed()
{
long long frequency;
size_t size = sizeof frequency;
if (0 == sysctlbyname("machdep.tsc.frequency", &frequency, &size, nullptr, 0) && 0 != frequency)
{
PerfToSec = 1.0 / frequency;
PerfToMillisec = 1000.0 / frequency;
if (!batchrun)
{
Printf("CPU speed: %.0f MHz\n", 0.001 / PerfToMillisec);
}
}
}
void I_Init(void)
{
CheckCPUID(&CPU);
CalculateCPUSpeed();
DumpCPUInfo(&CPU);
atterm(I_ShutdownSound);
I_InitSound();
}
static int has_exited;
void I_Quit()
{
has_exited = 1; // Prevent infinitely recursive exits -- killough
if (demorecording)
{
G_CheckDemoStatus();
}
C_DeinitConsole();
}
extern FILE* Logfile;
bool gameisdead;
static void I_FatalError(const char* const error, va_list ap)
{
static bool alreadyThrown = false;
gameisdead = true;
if (!alreadyThrown) // ignore all but the first message -- killough
{
alreadyThrown = true;
char errortext[MAX_ERRORTEXT];
int index;
index = vsnprintf(errortext, MAX_ERRORTEXT, error, ap);
extern void Mac_I_FatalError(const char*);
Mac_I_FatalError(errortext);
// Record error to log (if logging)
if (Logfile)
{
fprintf(Logfile, "\n**** DIED WITH FATAL ERROR:\n%s\n", errortext);
fflush(Logfile);
}
fprintf(stderr, "%s\n", errortext);
exit(-1);
}
if (!has_exited) // If it hasn't exited yet, exit now -- killough
{
has_exited = 1; // Prevent infinitely recursive exits -- killough
exit(-1);
}
}
void I_FatalError(const char* const error, ...)
{
va_list argptr;
va_start(argptr, error);
I_FatalError(error, argptr);
va_end(argptr);
}
void I_Error (const char *error, ...)
{
va_list argptr;
char errortext[MAX_ERRORTEXT];
va_start(argptr, error);
myvsnprintf (errortext, MAX_ERRORTEXT, error, argptr);
va_end (argptr);
throw CRecoverableError(errortext);
}
void I_SetIWADInfo()
{
}
void I_DebugPrint(const char *cp)
{
NSLog(@"%s", cp);
}
void I_PrintStr(const char* const message)
{
FConsoleWindow::GetInstance().AddText(message);
// Strip out any color escape sequences before writing to output
char* const copy = new char[strlen(message) + 1];
const char* srcp = message;
char* dstp = copy;
while ('\0' != *srcp)
{
if (TEXTCOLOR_ESCAPE == *srcp)
{
if ('\0' != srcp[1])
{
srcp += 2;
}
else
{
break;
}
}
else if (0x1d == *srcp || 0x1f == *srcp) // Opening and closing bar character
{
*dstp++ = '-';
++srcp;
}
else if (0x1e == *srcp) // Middle bar character
{
*dstp++ = '=';
++srcp;
}
else
{
*dstp++ = *srcp++;
}
}
*dstp = '\0';
fputs(copy, stdout);
delete[] copy;
fflush(stdout);
}
int I_PickIWad(WadStuff* const wads, const int numwads, const bool showwin, const int defaultiwad)
{
if (!showwin)
{
return defaultiwad;
}
I_SetMainWindowVisible(false);
extern int I_PickIWad_Cocoa(WadStuff*, int, bool, int);
const int result = I_PickIWad_Cocoa(wads, numwads, showwin, defaultiwad);
I_SetMainWindowVisible(true);
return result;
}
bool I_WriteIniFailed()
{
printf("The config file %s could not be saved:\n%s\n", GameConfig->GetPathName(), strerror(errno));
return false; // return true to retry
}
static const char *pattern;
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1080
static int matchfile(struct dirent *ent)
#else
static int matchfile(const struct dirent *ent)
#endif
{
return fnmatch(pattern, ent->d_name, FNM_NOESCAPE) == 0;
}
void* I_FindFirst(const char* const filespec, findstate_t* const fileinfo)
{
FString dir;
const char* const slash = strrchr(filespec, '/');
if (slash)
{
pattern = slash+1;
dir = FString(filespec, slash - filespec + 1);
}
else
{
pattern = filespec;
dir = ".";
}
fileinfo->current = 0;
fileinfo->count = scandir(dir.GetChars(), &fileinfo->namelist, matchfile, alphasort);
if (fileinfo->count > 0)
{
return fileinfo;
}
return (void*)-1;
}
int I_FindNext(void* const handle, findstate_t* const fileinfo)
{
findstate_t* const state = static_cast<findstate_t*>(handle);
if (state->current < fileinfo->count)
{
return ++state->current < fileinfo->count ? 0 : -1;
}
return -1;
}
int I_FindClose(void* const handle)
{
findstate_t* const state = static_cast<findstate_t*>(handle);
if (handle != (void*)-1 && state->count > 0)
{
for (int i = 0; i < state->count; ++i)
{
free(state->namelist[i]);
}
free(state->namelist);
state->namelist = NULL;
state->count = 0;
}
return 0;
}
int I_FindAttr(findstate_t* const fileinfo)
{
dirent* const ent = fileinfo->namelist[fileinfo->current];
bool isdir;
if (DirEntryExists(ent->d_name, &isdir))
{
return isdir ? FA_DIREC : 0;
}
return 0;
}
void I_PutInClipboard(const char* const string)
{
NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard];
NSString* const stringType = NSStringPboardType;
NSArray* const types = [NSArray arrayWithObjects:stringType, nil];
NSString* const content = [NSString stringWithUTF8String:string];
[pasteBoard declareTypes:types
owner:nil];
[pasteBoard setString:content
forType:stringType];
}
FString I_GetFromClipboard(bool returnNothing)
{
if (returnNothing)
{
return FString();
}
NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard];
NSString* const value = [pasteBoard stringForType:NSStringPboardType];
return FString([value UTF8String]);
}
unsigned int I_MakeRNGSeed()
{
return static_cast<unsigned int>(arc4random());
}
TArray<FString> I_GetGogPaths()
{
// GOG's Doom games are Windows only at the moment
return TArray<FString>();
}

View File

@ -1,90 +0,0 @@
/*
** sdlglvideo.h
**
**---------------------------------------------------------------------------
** Copyright 2012-2014 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
// IMPORTANT NOTE!
// This file was intentially named sdlglvideo.h but it has nothing with SDL
// The name was selected to avoid spreding of changes over the project
// The same applies to SDLGLFB class
// See gl/system/gl_framebuffer.h for details about its usage
#ifndef COCOA_SDLGLVIDEO_H_INCLUDED
#define COCOA_SDLGLVIDEO_H_INCLUDED
#include "v_video.h"
#include "gl/shaders/gl_shader.h"
#include "gl/textures/gl_hwtexture.h"
class SDLGLFB : public DFrameBuffer
{
public:
// This must have the same parameters as the Windows version, even if they are not used!
SDLGLFB(void *hMonitor, int width, int height, int, int, bool fullscreen, bool bgra);
~SDLGLFB();
virtual bool Lock(bool buffered = true);
virtual void Unlock();
virtual bool IsLocked();
virtual bool IsFullscreen();
virtual void SetVSync(bool vsync);
int GetClientWidth();
int GetClientHeight();
virtual int GetTrueHeight() { return GetClientHeight(); }
protected:
int m_Lock;
bool UpdatePending;
static const uint32_t GAMMA_CHANNEL_SIZE = 256;
static const uint32_t GAMMA_CHANNEL_COUNT = 3;
static const uint32_t GAMMA_TABLE_SIZE = GAMMA_CHANNEL_SIZE * GAMMA_CHANNEL_COUNT;
bool m_supportsGamma;
uint16_t m_originalGamma[GAMMA_TABLE_SIZE];
SDLGLFB();
void InitializeState();
void SwapBuffers();
void SetGammaTable(uint16_t* table);
void ResetGammaTable();
};
#endif // COCOA_SDLGLVIDEO_H_INCLUDED

View File

@ -1,96 +0,0 @@
/*
** st_console.h
**
**---------------------------------------------------------------------------
** Copyright 2015 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#ifndef COCOA_ST_CONSOLE_INCLUDED
#define COCOA_ST_CONSOLE_INCLUDED
@class NSButton;
@class NSProgressIndicator;
@class NSScrollView;
@class NSTextField;
@class NSTextView;
@class NSView;
@class NSWindow;
struct PalEntry;
class FConsoleWindow
{
public:
static FConsoleWindow& GetInstance();
static void CreateInstance();
static void DeleteInstance();
void Show(bool visible);
void ShowFatalError(const char* message);
void AddText(const char* message);
void SetTitleText();
void SetProgressBar(bool visible);
// FStartupScreen functionality
void Progress(int current, int maximum);
void NetInit(const char* message, int playerCount);
void NetProgress(int count);
void NetDone();
private:
NSWindow* m_window;
NSTextView* m_textView;
NSScrollView* m_scrollView;
NSProgressIndicator* m_progressBar;
NSView* m_netView;
NSTextField* m_netMessageText;
NSTextField* m_netCountText;
NSProgressIndicator* m_netProgressBar;
NSButton* m_netAbortButton;
unsigned int m_characterCount;
int m_netCurPos;
int m_netMaxPos;
FConsoleWindow();
void ExpandTextView(float height);
void AddText(const PalEntry& color, const char* message);
void ScrollTextToBottom();
};
#endif // COCOA_ST_CONSOLE_INCLUDED

View File

@ -1,533 +0,0 @@
/*
** st_console.mm
**
**---------------------------------------------------------------------------
** Copyright 2015 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "i_common.h"
#include "d_main.h"
#include "i_system.h"
#include "st_console.h"
#include "v_text.h"
#include "version.h"
#include "i_time.h"
static NSColor* RGB(const uint8_t red, const uint8_t green, const uint8_t blue)
{
return [NSColor colorWithCalibratedRed:red / 255.0f
green:green / 255.0f
blue:blue / 255.0f
alpha:1.0f];
}
static NSColor* RGB(const PalEntry& color)
{
return RGB(color.r, color.g, color.b);
}
static NSColor* RGB(const uint32_t color)
{
return RGB(PalEntry(color));
}
static const CGFloat PROGRESS_BAR_HEIGHT = 18.0f;
static const CGFloat NET_VIEW_HEIGHT = 88.0f;
FConsoleWindow::FConsoleWindow()
: m_window([NSWindow alloc])
, m_textView([NSTextView alloc])
, m_scrollView([NSScrollView alloc])
, m_progressBar(nil)
, m_netView(nil)
, m_netMessageText(nil)
, m_netCountText(nil)
, m_netProgressBar(nil)
, m_netAbortButton(nil)
, m_characterCount(0)
, m_netCurPos(0)
, m_netMaxPos(0)
{
const CGFloat initialWidth = 512.0f;
const CGFloat initialHeight = 384.0f;
const NSRect initialRect = NSMakeRect(0.0f, 0.0f, initialWidth, initialHeight);
[m_textView initWithFrame:initialRect];
[m_textView setEditable:NO];
[m_textView setBackgroundColor:RGB(70, 70, 70)];
[m_textView setMinSize:NSMakeSize(0.0f, initialHeight)];
[m_textView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[m_textView setVerticallyResizable:YES];
[m_textView setHorizontallyResizable:NO];
[m_textView setAutoresizingMask:NSViewWidthSizable];
NSTextContainer* const textContainer = [m_textView textContainer];
[textContainer setContainerSize:NSMakeSize(initialWidth, FLT_MAX)];
[textContainer setWidthTracksTextView:YES];
[m_scrollView initWithFrame:initialRect];
[m_scrollView setBorderType:NSNoBorder];
[m_scrollView setHasVerticalScroller:YES];
[m_scrollView setHasHorizontalScroller:NO];
[m_scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[m_scrollView setDocumentView:m_textView];
NSString* const title = [NSString stringWithFormat:@"%s %s - Console", GAMESIG, GetVersionString()];
[m_window initWithContentRect:initialRect
styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask
backing:NSBackingStoreBuffered
defer:NO];
[m_window setMinSize:[m_window frame].size];
[m_window setShowsResizeIndicator:NO];
[m_window setTitle:title];
[m_window center];
[m_window exitAppOnClose];
// Do not allow fullscreen mode for this window
[m_window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
[[m_window contentView] addSubview:m_scrollView];
[m_window makeKeyAndOrderFront:nil];
}
static FConsoleWindow* s_instance;
void FConsoleWindow::CreateInstance()
{
assert(NULL == s_instance);
s_instance = new FConsoleWindow;
}
void FConsoleWindow::DeleteInstance()
{
assert(NULL != s_instance);
delete s_instance;
s_instance = NULL;
}
FConsoleWindow& FConsoleWindow::GetInstance()
{
assert(NULL != s_instance);
return *s_instance;
}
void FConsoleWindow::Show(const bool visible)
{
if (visible)
{
[m_window orderFront:nil];
}
else
{
[m_window orderOut:nil];
}
}
void FConsoleWindow::ShowFatalError(const char* const message)
{
SetProgressBar(false);
NetDone();
const CGFloat textViewWidth = [m_scrollView frame].size.width;
ExpandTextView(-32.0f);
NSButton* quitButton = [[NSButton alloc] initWithFrame:NSMakeRect(textViewWidth - 76.0f, 0.0f, 72.0f, 30.0f)];
[quitButton setAutoresizingMask:NSViewMinXMargin];
[quitButton setBezelStyle:NSRoundedBezelStyle];
[quitButton setTitle:@"Quit"];
[quitButton setKeyEquivalent:@"\r"];
[quitButton setTarget:NSApp];
[quitButton setAction:@selector(terminate:)];
NSView* quitPanel = [[NSView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, textViewWidth, 32.0f)];
[quitPanel setAutoresizingMask:NSViewWidthSizable];
[quitPanel addSubview:quitButton];
[[m_window contentView] addSubview:quitPanel];
[m_window orderFront:nil];
AddText(PalEntry(255, 0, 0), "\nExecution could not continue.\n");
AddText(PalEntry(255, 255, 170), message);
AddText("\n");
ScrollTextToBottom();
[NSApp runModalForWindow:m_window];
}
static const unsigned int THIRTY_FPS = 33; // milliseconds per update
template <typename Function, unsigned int interval = THIRTY_FPS>
struct TimedUpdater
{
explicit TimedUpdater(const Function& function)
{
const unsigned int currentTime = I_msTime();
if (currentTime - m_previousTime > interval)
{
m_previousTime = currentTime;
function();
[[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
}
}
static unsigned int m_previousTime;
};
template <typename Function, unsigned int interval>
unsigned int TimedUpdater<Function, interval>::m_previousTime;
template <typename Function, unsigned int interval = THIRTY_FPS>
static void UpdateTimed(const Function& function)
{
TimedUpdater<Function, interval> dummy(function);
}
void FConsoleWindow::AddText(const char* message)
{
PalEntry color(223, 223, 223);
char buffer[1024] = {};
size_t pos = 0;
bool reset = false;
while (*message != '\0')
{
if ((TEXTCOLOR_ESCAPE == *message && 0 != pos)
|| (pos == sizeof buffer - 1)
|| reset)
{
buffer[pos] = '\0';
pos = 0;
reset = false;
AddText(color, buffer);
}
if (TEXTCOLOR_ESCAPE == *message)
{
const uint8_t* colorID = reinterpret_cast<const uint8_t*>(message) + 1;
if ('\0' == *colorID)
{
break;
}
const EColorRange range = V_ParseFontColor(colorID, CR_UNTRANSLATED, CR_YELLOW);
if (range != CR_UNDEFINED)
{
color = V_LogColorFromColorRange(range);
}
message += 2;
}
else if (0x1d == *message || 0x1f == *message) // Opening and closing bar characters
{
buffer[pos++] = '-';
++message;
}
else if (0x1e == *message) // Middle bar character
{
buffer[pos++] = '=';
++message;
}
else
{
buffer[pos++] = *message++;
}
}
if (0 != pos)
{
buffer[pos] = '\0';
AddText(color, buffer);
}
if ([m_window isVisible])
{
UpdateTimed([&]()
{
[m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)];
});
}
}
void FConsoleWindow::AddText(const PalEntry& color, const char* const message)
{
NSString* const text = [NSString stringWithCString:message
encoding:NSISOLatin1StringEncoding];
NSDictionary* const attributes = [NSDictionary dictionaryWithObjectsAndKeys:
[NSFont systemFontOfSize:14.0f], NSFontAttributeName,
RGB(color), NSForegroundColorAttributeName,
nil];
NSAttributedString* const formattedText =
[[NSAttributedString alloc] initWithString:text
attributes:attributes];
[[m_textView textStorage] appendAttributedString:formattedText];
m_characterCount += [text length];
}
void FConsoleWindow::ScrollTextToBottom()
{
[m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)];
[[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
}
void FConsoleWindow::SetTitleText()
{
static const CGFloat TITLE_TEXT_HEIGHT = 32.0f;
NSRect textViewFrame = [m_scrollView frame];
textViewFrame.size.height -= TITLE_TEXT_HEIGHT;
[m_scrollView setFrame:textViewFrame];
const NSRect titleTextRect = NSMakeRect(
0.0f,
textViewFrame.origin.y + textViewFrame.size.height,
textViewFrame.size.width,
TITLE_TEXT_HEIGHT);
// Temporary solution for the same foreground and background colors
// It's used in graphical startup screen, with Hexen style in particular
// Native OS X backend doesn't implement this yet
if (DoomStartupInfo.FgColor == DoomStartupInfo.BkColor)
{
DoomStartupInfo.FgColor = ~DoomStartupInfo.FgColor;
}
NSTextField* titleText = [[NSTextField alloc] initWithFrame:titleTextRect];
[titleText setStringValue:[NSString stringWithCString:DoomStartupInfo.Name
encoding:NSISOLatin1StringEncoding]];
[titleText setAlignment:NSCenterTextAlignment];
[titleText setTextColor:RGB(DoomStartupInfo.FgColor)];
[titleText setBackgroundColor:RGB(DoomStartupInfo.BkColor)];
[titleText setFont:[NSFont fontWithName:@"Trebuchet MS Bold" size:18.0f]];
[titleText setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
[titleText setSelectable:NO];
[titleText setBordered:NO];
[[m_window contentView] addSubview:titleText];
}
void FConsoleWindow::SetProgressBar(const bool visible)
{
if ( (!visible && nil == m_progressBar)
|| (visible && nil != m_progressBar))
{
return;
}
if (visible)
{
ExpandTextView(-PROGRESS_BAR_HEIGHT);
static const CGFloat PROGRESS_BAR_X = 2.0f;
const NSRect PROGRESS_BAR_RECT = NSMakeRect(
PROGRESS_BAR_X, 0.0f,
[m_window frame].size.width - PROGRESS_BAR_X * 2, 16.0f);
m_progressBar = [[NSProgressIndicator alloc] initWithFrame:PROGRESS_BAR_RECT];
[m_progressBar setIndeterminate:NO];
[m_progressBar setAutoresizingMask:NSViewWidthSizable];
[[m_window contentView] addSubview:m_progressBar];
}
else
{
ExpandTextView(PROGRESS_BAR_HEIGHT);
[m_progressBar removeFromSuperview];
[m_progressBar release];
m_progressBar = nil;
}
}
void FConsoleWindow::ExpandTextView(const float height)
{
NSRect textFrame = [m_scrollView frame];
textFrame.origin.y -= height;
textFrame.size.height += height;
[m_scrollView setFrame:textFrame];
}
void FConsoleWindow::Progress(const int current, const int maximum)
{
if (nil == m_progressBar)
{
return;
}
UpdateTimed([&]()
{
[m_progressBar setMaxValue:maximum];
[m_progressBar setDoubleValue:current];
});
}
void FConsoleWindow::NetInit(const char* const message, const int playerCount)
{
if (nil == m_netView)
{
SetProgressBar(false);
ExpandTextView(-NET_VIEW_HEIGHT);
// Message like 'Waiting for players' or 'Contacting host'
m_netMessageText = [[NSTextField alloc] initWithFrame:NSMakeRect(12.0f, 64.0f, 400.0f, 16.0f)];
[m_netMessageText setAutoresizingMask:NSViewWidthSizable];
[m_netMessageText setDrawsBackground:NO];
[m_netMessageText setSelectable:NO];
[m_netMessageText setBordered:NO];
// Text with connected/total players count
m_netCountText = [[NSTextField alloc] initWithFrame:NSMakeRect(428.0f, 64.0f, 72.0f, 16.0f)];
[m_netCountText setAutoresizingMask:NSViewMinXMargin];
[m_netCountText setAlignment:NSRightTextAlignment];
[m_netCountText setDrawsBackground:NO];
[m_netCountText setSelectable:NO];
[m_netCountText setBordered:NO];
// Connection progress
m_netProgressBar = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(12.0f, 40.0f, 488.0f, 16.0f)];
[m_netProgressBar setAutoresizingMask:NSViewWidthSizable];
[m_netProgressBar setMaxValue:playerCount];
if (0 == playerCount)
{
// Joining game
[m_netProgressBar setIndeterminate:YES];
[m_netProgressBar startAnimation:nil];
}
else
{
// Hosting game
[m_netProgressBar setIndeterminate:NO];
}
// Cancel network game button
m_netAbortButton = [[NSButton alloc] initWithFrame:NSMakeRect(432.0f, 8.0f, 72.0f, 28.0f)];
[m_netAbortButton setAutoresizingMask:NSViewMinXMargin];
[m_netAbortButton setBezelStyle:NSRoundedBezelStyle];
[m_netAbortButton setTitle:@"Cancel"];
[m_netAbortButton setKeyEquivalent:@"\r"];
[m_netAbortButton setTarget:NSApp];
[m_netAbortButton setAction:@selector(terminate:)];
// Panel for controls above
m_netView = [[NSView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, 512.0f, NET_VIEW_HEIGHT)];
[m_netView setAutoresizingMask:NSViewWidthSizable];
[m_netView addSubview:m_netMessageText];
[m_netView addSubview:m_netCountText];
[m_netView addSubview:m_netProgressBar];
[m_netView addSubview:m_netAbortButton];
NSRect windowRect = [m_window frame];
windowRect.origin.y -= NET_VIEW_HEIGHT;
windowRect.size.height += NET_VIEW_HEIGHT;
[m_window setFrame:windowRect display:YES];
[[m_window contentView] addSubview:m_netView];
ScrollTextToBottom();
}
[m_netMessageText setStringValue:[NSString stringWithUTF8String:message]];
m_netCurPos = 0;
m_netMaxPos = playerCount;
NetProgress(1); // You always know about yourself
}
void FConsoleWindow::NetProgress(const int count)
{
if (0 == count)
{
++m_netCurPos;
}
else
{
m_netCurPos = count;
}
if (nil == m_netView)
{
return;
}
if (m_netMaxPos > 1)
{
[m_netCountText setStringValue:[NSString stringWithFormat:@"%d / %d", m_netCurPos, m_netMaxPos]];
[m_netProgressBar setDoubleValue:MIN(m_netCurPos, m_netMaxPos)];
}
}
void FConsoleWindow::NetDone()
{
if (nil != m_netView)
{
ExpandTextView(NET_VIEW_HEIGHT);
[m_netView removeFromSuperview];
[m_netView release];
m_netView = nil;
// Released by m_netView
m_netMessageText = nil;
m_netCountText = nil;
m_netProgressBar = nil;
m_netAbortButton = nil;
}
}

View File

@ -1,194 +0,0 @@
/*
** st_start.mm
**
**---------------------------------------------------------------------------
** Copyright 2015 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <unistd.h>
#import <Foundation/NSRunLoop.h>
#include "c_cvars.h"
#include "st_console.h"
#include "st_start.h"
#include "v_text.h"
FStartupScreen *StartScreen;
CUSTOM_CVAR(Int, showendoom, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
if (self < 0)
{
self = 0;
}
else if (self > 2)
{
self = 2;
}
}
// ---------------------------------------------------------------------------
class FBasicStartupScreen : public FStartupScreen
{
public:
FBasicStartupScreen(int maxProgress, bool showBar);
~FBasicStartupScreen();
virtual void Progress();
virtual void NetInit(const char* message, int playerCount);
virtual void NetProgress(int count);
virtual void NetMessage(const char *format, ...);
virtual void NetDone();
virtual bool NetLoop(bool (*timerCallback)(void*), void* userData);
};
FBasicStartupScreen::FBasicStartupScreen(int maxProgress, bool showBar)
: FStartupScreen(maxProgress)
{
FConsoleWindow& consoleWindow = FConsoleWindow::GetInstance();
consoleWindow.SetProgressBar(true);
consoleWindow.SetTitleText();
#if 0
// Testing code, please do not remove
consoleWindow.AddText("----------------------------------------------------------------\n");
consoleWindow.AddText("1234567890 !@#$%^&*() ,<.>/?;:'\" [{]}\\| `~-_=+ "
"This is very very very long message needed to trigger word wrapping...\n\n");
consoleWindow.AddText("Multiline...\n\tmessage...\n\t\twith...\n\t\t\ttabs.\n\n");
consoleWindow.AddText(TEXTCOLOR_BRICK "TEXTCOLOR_BRICK\n" TEXTCOLOR_TAN "TEXTCOLOR_TAN\n");
consoleWindow.AddText(TEXTCOLOR_GRAY "TEXTCOLOR_GRAY & TEXTCOLOR_GREY\n");
consoleWindow.AddText(TEXTCOLOR_GREEN "TEXTCOLOR_GREEN\n" TEXTCOLOR_BROWN "TEXTCOLOR_BROWN\n");
consoleWindow.AddText(TEXTCOLOR_GOLD "TEXTCOLOR_GOLD\n" TEXTCOLOR_RED "TEXTCOLOR_RED\n");
consoleWindow.AddText(TEXTCOLOR_BLUE "TEXTCOLOR_BLUE\n" TEXTCOLOR_ORANGE "TEXTCOLOR_ORANGE\n");
consoleWindow.AddText(TEXTCOLOR_WHITE "TEXTCOLOR_WHITE\n" TEXTCOLOR_YELLOW "TEXTCOLOR_YELLOW\n");
consoleWindow.AddText(TEXTCOLOR_UNTRANSLATED "TEXTCOLOR_UNTRANSLATED\n");
consoleWindow.AddText(TEXTCOLOR_BLACK "TEXTCOLOR_BLACK\n" TEXTCOLOR_LIGHTBLUE "TEXTCOLOR_LIGHTBLUE\n");
consoleWindow.AddText(TEXTCOLOR_CREAM "TEXTCOLOR_CREAM\n" TEXTCOLOR_OLIVE "TEXTCOLOR_OLIVE\n");
consoleWindow.AddText(TEXTCOLOR_DARKGREEN "TEXTCOLOR_DARKGREEN\n" TEXTCOLOR_DARKRED "TEXTCOLOR_DARKRED\n");
consoleWindow.AddText(TEXTCOLOR_DARKBROWN "TEXTCOLOR_DARKBROWN\n" TEXTCOLOR_PURPLE "TEXTCOLOR_PURPLE\n");
consoleWindow.AddText(TEXTCOLOR_DARKGRAY "TEXTCOLOR_DARKGRAY\n" TEXTCOLOR_CYAN "TEXTCOLOR_CYAN\n");
consoleWindow.AddText(TEXTCOLOR_ICE "TEXTCOLOR_ICE\n" TEXTCOLOR_FIRE "TEXTCOLOR_FIRE\n");
consoleWindow.AddText(TEXTCOLOR_SAPPHIRE "TEXTCOLOR_SAPPHIRE\n" TEXTCOLOR_TEAL "TEXTCOLOR_TEAL\n");
consoleWindow.AddText(TEXTCOLOR_NORMAL "TEXTCOLOR_NORMAL\n" TEXTCOLOR_BOLD "TEXTCOLOR_BOLD\n");
consoleWindow.AddText(TEXTCOLOR_CHAT "TEXTCOLOR_CHAT\n" TEXTCOLOR_TEAMCHAT "TEXTCOLOR_TEAMCHAT\n");
consoleWindow.AddText("----------------------------------------------------------------\n");
#endif // _DEBUG
}
FBasicStartupScreen::~FBasicStartupScreen()
{
FConsoleWindow::GetInstance().SetProgressBar(false);
}
void FBasicStartupScreen::Progress()
{
if (CurPos < MaxPos)
{
++CurPos;
}
FConsoleWindow::GetInstance().Progress(CurPos, MaxPos);
}
void FBasicStartupScreen::NetInit(const char* const message, const int playerCount)
{
FConsoleWindow::GetInstance().NetInit(message, playerCount);
}
void FBasicStartupScreen::NetProgress(const int count)
{
FConsoleWindow::GetInstance().NetProgress(count);
}
void FBasicStartupScreen::NetMessage(const char* const format, ...)
{
va_list args;
va_start(args, format);
FString message;
message.VFormat(format, args);
va_end(args);
Printf("%s\n", message.GetChars());
}
void FBasicStartupScreen::NetDone()
{
FConsoleWindow::GetInstance().NetDone();
}
bool FBasicStartupScreen::NetLoop(bool (*timerCallback)(void*), void* const userData)
{
while (true)
{
if (timerCallback(userData))
{
break;
}
[[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
// Do not poll to often
usleep(50000);
}
return true;
}
// ---------------------------------------------------------------------------
FStartupScreen *FStartupScreen::CreateInstance(const int maxProgress)
{
return new FBasicStartupScreen(maxProgress, true);
}
// ---------------------------------------------------------------------------
void ST_Endoom()
{
extern void I_ShutdownJoysticks();
I_ShutdownJoysticks();
exit(0);
}

View File

@ -114,29 +114,23 @@ CUSTOM_CVAR(Bool, gl_es, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCA
// CODE --------------------------------------------------------------------
OculusQuestGLVideo::OculusQuestGLVideo (int parm)
NoSDLGLVideo::NoSDLGLVideo (int parm)
{
IteratorBits = 0;
//I think we have to do this still
if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
fprintf( stderr, "Video initialization failed: %s\n",
SDL_GetError( ) );
}
}
OculusQuestGLVideo::~OculusQuestGLVideo ()
NoSDLGLVideo::~NoSDLGLVideo ()
{
if (GLRenderer != NULL) GLRenderer->FlushTextures();
}
void OculusQuestGLVideo::StartModeIterator (int bits, bool fs)
void NoSDLGLVideo::StartModeIterator (int bits, bool fs)
{
IteratorMode = 0;
IteratorBits = bits;
}
bool OculusQuestGLVideo::NextMode (int *width, int *height, bool *letterbox)
bool NoSDLGLVideo::NextMode (int *width, int *height, bool *letterbox)
{
if (IteratorBits != 8)
return false;
@ -151,7 +145,7 @@ bool OculusQuestGLVideo::NextMode (int *width, int *height, bool *letterbox)
return false;
}
DFrameBuffer *OculusQuestGLVideo::CreateFrameBuffer (int width, int height, bool bgra, bool fullscreen, DFrameBuffer *old)
DFrameBuffer *NoSDLGLVideo::CreateFrameBuffer (int width, int height, bool bgra, bool fullscreen, DFrameBuffer *old)
{
static int retry = 0;
static int owidth, oheight;
@ -169,7 +163,7 @@ DFrameBuffer *OculusQuestGLVideo::CreateFrameBuffer (int width, int height, bool
// flashAmount = 0;
}
OculusQuestBaseFB *fb;
NoSDLBaseFB *fb;
const char *hwBuffers = Args->CheckValue("-hwbuffers");
int buffers = 1;
if (hwBuffers)
@ -183,11 +177,11 @@ DFrameBuffer *OculusQuestGLVideo::CreateFrameBuffer (int width, int height, bool
return fb;
}
void OculusQuestGLVideo::SetWindowedScale (float scale)
void NoSDLGLVideo::SetWindowedScale (float scale)
{
}
bool OculusQuestGLVideo::SetResolution (int width, int height, int bits)
bool NoSDLGLVideo::SetResolution (int width, int height, int bits)
{
// FIXME: Is it possible to do this without completely destroying the old
// interface?
@ -196,7 +190,7 @@ bool OculusQuestGLVideo::SetResolution (int width, int height, int bits)
if (GLRenderer != NULL) GLRenderer->FlushTextures();
I_ShutdownGraphics();
Video = new OculusQuestGLVideo(0);
Video = new NoSDLGLVideo(0);
if (Video == NULL) I_FatalError ("Failed to initialize display");
#if (defined(WINDOWS)) || defined(WIN32)
@ -219,7 +213,7 @@ bool OculusQuestGLVideo::SetResolution (int width, int height, int bits)
extern "C" extern int glesLoad;
#endif
void OculusQuestGLVideo::SetupPixelFormat(bool allowsoftware, int multisample, const int *glver)
void NoSDLGLVideo::SetupPixelFormat(bool allowsoftware, int multisample, const int *glver)
{
#ifdef __MOBILE__
@ -252,73 +246,73 @@ void OculusQuestGLVideo::SetupPixelFormat(bool allowsoftware, int multisample, c
// FrameBuffer implementation -----------------------------------------------
OculusQuestGLFB::OculusQuestGLFB (void *, int width, int height, int, int, bool fullscreen, bool bgra)
: OculusQuestBaseFB (width, height, bgra)
NoSDLGLFB::NoSDLGLFB (void *, int width, int height, int, int, bool fullscreen, bool bgra)
: NoSDLBaseFB (width, height, bgra)
{
}
OculusQuestGLFB::~OculusQuestGLFB ()
NoSDLGLFB::~NoSDLGLFB ()
{
}
void OculusQuestGLFB::InitializeState()
void NoSDLGLFB::InitializeState()
{
}
void OculusQuestGLFB::SetGammaTable(uint16_t *tbl)
void NoSDLGLFB::SetGammaTable(uint16_t *tbl)
{
}
void OculusQuestGLFB::ResetGammaTable()
void NoSDLGLFB::ResetGammaTable()
{
}
bool OculusQuestGLFB::Lock(bool buffered)
bool NoSDLGLFB::Lock(bool buffered)
{
m_Lock++;
return true;
}
bool OculusQuestGLFB::Lock ()
bool NoSDLGLFB::Lock ()
{
return Lock(false);
}
void OculusQuestGLFB::Unlock ()
void NoSDLGLFB::Unlock ()
{
--m_Lock;
}
bool OculusQuestGLFB::IsLocked ()
bool NoSDLGLFB::IsLocked ()
{
return m_Lock>0;// true;
}
bool OculusQuestGLFB::IsFullscreen ()
bool NoSDLGLFB::IsFullscreen ()
{
return true;
}
bool OculusQuestGLFB::IsValid ()
bool NoSDLGLFB::IsValid ()
{
return DFrameBuffer::IsValid() && Screen != NULL;
return DFrameBuffer::IsValid();
}
void OculusQuestGLFB::SetVSync( bool vsync )
void NoSDLGLFB::SetVSync( bool vsync )
{
}
void OculusQuestGLFB::NewRefreshRate ()
void NoSDLGLFB::NewRefreshRate ()
{
}
void OculusQuestGLFB::SwapBuffers()
void NoSDLGLFB::SwapBuffers()
{
}
int OculusQuestGLFB::GetClientWidth()
int NoSDLGLFB::GetClientWidth()
{
uint32_t w, h;
Android_GetScreenRes(&w, &h);
@ -326,7 +320,7 @@ int OculusQuestGLFB::GetClientWidth()
return width;
}
int OculusQuestGLFB::GetClientHeight()
int NoSDLGLFB::GetClientHeight()
{
uint32_t w, h;
Android_GetScreenRes(&w, &h);
@ -334,7 +328,7 @@ int OculusQuestGLFB::GetClientHeight()
return height;
}
void OculusQuestGLFB::ScaleCoordsFromWindow(int16_t &x, int16_t &y)
void NoSDLGLFB::ScaleCoordsFromWindow(int16_t &x, int16_t &y)
{
uint32_t w, h;
Android_GetScreenRes(&w, &h);

View File

@ -12,11 +12,11 @@ EXTERN_CVAR (Color, dimcolor)
struct FRenderer;
FRenderer *gl_CreateInterface();
class SDLGLVideo : public IVideo
class NoSDLGLVideo : public IVideo
{
public:
SDLGLVideo (int parm);
~SDLGLVideo ();
NoSDLGLVideo (int parm);
~NoSDLGLVideo ();
EDisplayType GetDisplayType () { return DISPLAY_Both; }
void SetWindowedScale (float scale);
@ -34,23 +34,22 @@ private:
int IteratorBits;
};
class SDLBaseFB : public DFrameBuffer
class NoSDLBaseFB : public DFrameBuffer
{
typedef DFrameBuffer Super;
public:
using DFrameBuffer::DFrameBuffer;
virtual SDL_Window *GetSDLWindow() = 0;
friend class SDLGLVideo;
friend class NoSDLGLVideo;
};
class SDLGLFB : public SDLBaseFB
class NoSDLGLFB : public NoSDLBaseFB
{
typedef SDLBaseFB Super;
typedef NoSDLBaseFB Super;
public:
// this must have the same parameters as the Windows version, even if they are not used!
SDLGLFB (void *hMonitor, int width, int height, int, int, bool fullscreen, bool bgra);
~SDLGLFB ();
NoSDLGLFB (void *hMonitor, int width, int height, int, int, bool fullscreen, bool bgra);
~NoSDLGLFB ();
void ForceBuffering (bool force);
bool Lock(bool buffered);
@ -66,14 +65,14 @@ public:
void NewRefreshRate ();
friend class SDLGLVideo;
friend class NoSDLGLVideo;
int GetClientWidth();
int GetClientHeight();
virtual void ScaleCoordsFromWindow(int16_t &x, int16_t &y);
SDL_Window *GetSDLWindow() override { return Screen; }
// SDL_Window *GetSDLWindow() override { return Screen; }
virtual int GetTrueHeight() { return GetClientHeight(); }
protected:
@ -81,13 +80,13 @@ protected:
void ResetGammaTable();
void InitializeState();
SDLGLFB () {}
NoSDLGLFB () {}
uint8_t GammaTable[3][256];
bool UpdatePending;
SDL_Window *Screen;
// SDL_Window *Screen;
SDL_GLContext GLContext;
// SDL_GLContext GLContext;
void UpdateColors ();

View File

@ -32,7 +32,6 @@
**
*/
#include <SDL.h>
#include <signal.h>
#include <time.h>
@ -100,25 +99,17 @@ void I_ShutdownGraphics ()
}
if (Video)
delete Video, Video = NULL;
SDL_QuitSubSystem (SDL_INIT_VIDEO);
}
void I_InitGraphics ()
{
if (SDL_InitSubSystem (SDL_INIT_VIDEO) < 0)
{
I_FatalError ("Could not initialize SDL video:\n%s\n", SDL_GetError());
return;
}
UCVarValue val;
val.Bool = !!Args->CheckParm ("-devparm");
ticker.SetGenericRepDefault (val, CVAR_Bool);
currentrenderer = vid_renderer;
Video = new OculusQuestGLVideo(0);
Video = new NoSDLGLVideo(0);
if (Video == NULL)
I_FatalError ("Failed to initialize display");
@ -153,28 +144,7 @@ void I_CreateRenderer()
DFrameBuffer *I_SetMode (int &width, int &height, DFrameBuffer *old)
{
bool fs = false;
switch (Video->GetDisplayType ())
{
case DISPLAY_WindowOnly:
fs = false;
break;
case DISPLAY_FullscreenOnly:
fs = true;
break;
case DISPLAY_Both:
fs = fullscreen;
break;
}
DFrameBuffer *res = Video->CreateFrameBuffer (width, height, swtruecolor, fs, old);
/* Right now, CreateFrameBuffer cannot return NULL
if (res == NULL)
{
I_FatalError ("Mode %dx%d is unavailable\n", width, height);
}
*/
return res;
return Video->CreateFrameBuffer (width, height, swtruecolor, true, old);
}
bool I_CheckResolution (int width, int height, int bits)

View File

@ -33,7 +33,7 @@
#include <string.h>
#include <SDL.h>
//#include <SDL.h>
#include "bitmap.h"
#include "v_palette.h"
@ -41,7 +41,7 @@
bool I_SetCursor(FTexture *cursorpic)
{
static SDL_Cursor *cursor;
/* static SDL_Cursor *cursor;
static SDL_Surface *cursorSurface;
if (cursorpic != NULL && cursorpic->UseType != ETextureType::Null)
@ -81,6 +81,6 @@ bool I_SetCursor(FTexture *cursorpic)
SDL_FreeSurface(cursorSurface);
cursorSurface = NULL;
}
}
}*/
return true;
}

View File

@ -1,8 +1,8 @@
/*
** i_gui.cpp
** i_joystick.cpp
**
**---------------------------------------------------------------------------
** Copyright 2008 Randy Heit
** Copyright 2005-2016 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
@ -30,57 +30,82 @@
**---------------------------------------------------------------------------
**
*/
#include "doomdef.h"
#include "version.h"
#include "templates.h"
#include "m_joy.h"
#include <string.h>
// Very small deadzone so that floating point magic doesn't happen
#define MIN_DEADZONE 0.000001f
#include <SDL.h>
#include "bitmap.h"
#include "v_palette.h"
#include "textures.h"
bool I_SetCursor(FTexture *cursorpic)
CUSTOM_CVAR(Bool, joy_background, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_NOINITCALL)
{
static SDL_Cursor *cursor;
static SDL_Surface *cursorSurface;
if (cursorpic != NULL && cursorpic->UseType != ETextureType::Null)
{
// Must be no larger than 32x32.
if (cursorpic->GetWidth() > 32 || cursorpic->GetHeight() > 32)
{
return false;
}
if (cursorSurface == NULL)
cursorSurface = SDL_CreateRGBSurface (0, 32, 32, 32, MAKEARGB(0,255,0,0), MAKEARGB(0,0,255,0), MAKEARGB(0,0,0,255), MAKEARGB(255,0,0,0));
SDL_LockSurface(cursorSurface);
uint8_t buffer[32*32*4];
memset(buffer, 0, 32*32*4);
FBitmap bmp(buffer, 32*4, 32, 32);
cursorpic->CopyTrueColorPixels(&bmp, 0, 0);
memcpy(cursorSurface->pixels, bmp.GetPixels(), 32*32*4);
SDL_UnlockSurface(cursorSurface);
if (cursor)
SDL_FreeCursor (cursor);
cursor = SDL_CreateColorCursor (cursorSurface, 0, 0);
SDL_SetCursor (cursor);
}
else
{
if (cursor)
{
SDL_SetCursor (NULL);
SDL_FreeCursor (cursor);
cursor = NULL;
}
if (cursorSurface != NULL)
{
SDL_FreeSurface(cursorSurface);
cursorSurface = NULL;
}
}
return true;
Printf("This won't take effect until " GAMENAME " is restarted.\n");
}
class NoSDLInputJoystickManager
{
public:
NoSDLInputJoystickManager()
{
}
~NoSDLInputJoystickManager()
{
}
void AddAxes(float axes[5])
{
}
void GetDevices(TArray<IJoystickConfig *> &sticks)
{
}
void ProcessInput() const
{
}
};
static NoSDLInputJoystickManager *JoystickManager;
void I_StartupJoysticks()
{
JoystickManager = new NoSDLInputJoystickManager();
}
void I_ShutdownJoysticks()
{
if(JoystickManager)
{
delete JoystickManager;
}
}
void I_GetJoysticks(TArray<IJoystickConfig *> &sticks)
{
sticks.Clear();
JoystickManager->GetDevices(sticks);
}
void I_GetAxes(float axes[NUM_JOYAXIS])
{
for (int i = 0; i < NUM_JOYAXIS; ++i)
{
axes[i] = 0;
}
if (use_joystick)
{
JoystickManager->AddAxes(axes);
}
}
void I_ProcessJoysticks()
{
if (use_joystick)
JoystickManager->ProcessInput();
}
IJoystickConfig *I_UpdateDeviceList()
{
return NULL;
}

View File

@ -34,7 +34,7 @@
// HEADER FILES ------------------------------------------------------------
#include <SDL.h>
//#include <SDL.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

View File

@ -34,7 +34,7 @@
#include <fcntl.h>
#include <signal.h>
#include <SDL.h>
//#include <SDL.h>
#include "doomerrors.h"
#include <math.h>
@ -152,7 +152,7 @@ void Mac_I_FatalError(const char* errortext);
void Linux_I_FatalError(const char* errortext)
{
// Close window or exit fullscreen and release mouse capture
SDL_Quit();
//SDL_Quit();
const char *str;
if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0)
@ -174,7 +174,7 @@ void Linux_I_FatalError(const char* errortext)
FString message;
message << GAMESIG " ";
message << GetVersionString() << ": No IWAD found";
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, message, errortext, NULL);
//SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, message, errortext, NULL);
}
}
#endif
@ -452,17 +452,17 @@ int I_FindAttr(findstate_t* const fileinfo)
void I_PutInClipboard (const char *str)
{
SDL_SetClipboardText(str);
//SDL_SetClipboardText(str);
}
FString I_GetFromClipboard (bool use_primary_selection)
{
if(char *ret = SDL_GetClipboardText())
/* if(char *ret = SDL_GetClipboardText())
{
FString text(ret);
SDL_free(ret);
return text;
}
}*/
return "";
}

View File

@ -105,15 +105,15 @@ CUSTOM_CVAR (Float, bgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static cycle_t BlitCycles;
static cycle_t SDLFlipCycles;
//static cycle_t BlitCycles;
//static cycle_t SDLFlipCycles;
// CODE --------------------------------------------------------------------
// FrameBuffer implementation -----------------------------------------------
OculusQuestFB::OculusQuestFB (int width, int height, bool bgra, bool fullscreen, SDL_Window *oldwin)
: OculusQuestBaseFB (width, height, bgra)
NoSDLFB::NoSDLFB (int width, int height, bool bgra, bool fullscreen/*, SDL_Window *oldwin*/)
: NoSDLBaseFB (width, height, bgra)
{
int i;
@ -124,8 +124,8 @@ OculusQuestFB::OculusQuestFB (int width, int height, bool bgra, bool fullscreen,
FlashAmount = 0;
Renderer = NULL;
Texture = NULL;
// Renderer = NULL;
// Texture = NULL;
for (i = 0; i < 256; i++)
{
@ -141,61 +141,61 @@ OculusQuestFB::OculusQuestFB (int width, int height, bool bgra, bool fullscreen,
}
OculusQuestFB::~OculusQuestFB ()
NoSDLFB::~NoSDLFB ()
{
}
bool OculusQuestFB::IsValid ()
bool NoSDLFB::IsValid ()
{
return DFrameBuffer::IsValid();
}
int OculusQuestFB::GetPageCount ()
int NoSDLFB::GetPageCount ()
{
return 1;
}
bool OculusQuestFB::Lock (bool buffered)
bool NoSDLFB::Lock (bool buffered)
{
return DSimpleCanvas::Lock ();
}
bool OculusQuestFB::Relock ()
bool NoSDLFB::Relock ()
{
return DSimpleCanvas::Lock ();
}
void OculusQuestFB::Unlock ()
void NoSDLFB::Unlock ()
{
--LockCount;
}
void OculusQuestFB::Update ()
void NoSDLFB::Update ()
{
}
void OculusQuestFB::UpdateColors ()
void NoSDLFB::UpdateColors ()
{
}
PalEntry *OculusQuestFB::GetPalette ()
PalEntry *NoSDLFB::GetPalette ()
{
return SourcePalette;
}
void OculusQuestFB::UpdatePalette ()
void NoSDLFB::UpdatePalette ()
{
NeedPalUpdate = true;
}
bool OculusQuestFB::SetGamma (float gamma)
bool NoSDLFB::SetGamma (float gamma)
{
Gamma = gamma;
NeedGammaUpdate = true;
return true;
}
bool OculusQuestFB::SetFlash (PalEntry rgb, int amount)
bool NoSDLFB::SetFlash (PalEntry rgb, int amount)
{
Flash = rgb;
FlashAmount = amount;
@ -203,35 +203,35 @@ bool OculusQuestFB::SetFlash (PalEntry rgb, int amount)
return true;
}
void OculusQuestFB::GetFlash (PalEntry &rgb, int &amount)
void NoSDLFB::GetFlash (PalEntry &rgb, int &amount)
{
rgb = Flash;
amount = FlashAmount;
}
// Q: Should I gamma adjust the returned palette?
void OculusQuestFB::GetFlashedPalette (PalEntry pal[256])
void NoSDLFB::GetFlashedPalette (PalEntry pal[256])
{
}
void OculusQuestFB::SetFullscreen (bool fullscreen)
void NoSDLFB::SetFullscreen (bool fullscreen)
{
}
bool OculusQuestFB::IsFullscreen ()
bool NoSDLFB::IsFullscreen ()
{
return true;
}
void OculusQuestFB::ResetSDLRenderer ()
void NoSDLFB::ResetSDLRenderer ()
{
}
void OculusQuestFB::SetVSync (bool vsync)
void NoSDLFB::SetVSync (bool vsync)
{
}
void OculusQuestFB::ScaleCoordsFromWindow(int16_t &x, int16_t &y)
void NoSDLFB::ScaleCoordsFromWindow(int16_t &x, int16_t &y)
{
uint32_t w, h;
Android_GetScreenRes(&w, &h);

View File

@ -2,12 +2,12 @@
#include "v_video.h"
#include "glvideo.h"
class OculusQuestFB : public OculusQuestBaseFB
class NoSDLFB : public NoSDLBaseFB
{
typedef OculusQuestBaseFB Super;
typedef NoSDLBaseFB Super;
public:
OculusQuestFB(int width, int height, bool bgra, bool fullscreen, SDL_Window *oldwin);
~OculusQuestFB();
NoSDLFB(int width, int height, bool bgra, bool fullscreen/*, SDL_Window *oldwin*/);
~NoSDLFB();
bool Lock(bool buffer);
void Unlock();
@ -25,12 +25,12 @@ public:
int GetPageCount();
bool IsFullscreen();
friend class OculusQuestGLVideo;
friend class NoSDLGLVideo;
virtual void SetVSync(bool vsync);
virtual void ScaleCoordsFromWindow(int16_t &x, int16_t &y);
SDL_Window *GetSDLWindow() override { return Screen; }
// SDL_Window *GetSDLWindow() override { return Screen; }
private:
PalEntry SourcePalette[256];
@ -40,13 +40,13 @@ private:
float Gamma;
bool UpdatePending;
SDL_Window *Screen;
SDL_Renderer *Renderer;
union
{
SDL_Texture *Texture;
SDL_Surface *Surface;
};
// SDL_Window *Screen;
// SDL_Renderer *Renderer;
// union
// {
// SDL_Texture *Texture;
// SDL_Surface *Surface;
// };
bool UsingRenderer;
bool NeedPalUpdate;
@ -56,5 +56,5 @@ private:
void UpdateColors();
void ResetSDLRenderer();
OculusQuestFB() {}
NoSDLFB() {}
};

View File

@ -1,98 +0,0 @@
#ifndef __SDLGLVIDEO_H__
#define __SDLGLVIDEO_H__
#include "hardware.h"
#include "v_video.h"
#include <SDL.h>
#include "gl/system/gl_system.h"
EXTERN_CVAR (Float, dimamount)
EXTERN_CVAR (Color, dimcolor)
struct FRenderer;
FRenderer *gl_CreateInterface();
class OculusQuestGLVideo : public IVideo
{
public:
OculusQuestGLVideo (int parm);
~OculusQuestGLVideo ();
EDisplayType GetDisplayType () { return DISPLAY_Both; }
void SetWindowedScale (float scale);
DFrameBuffer *CreateFrameBuffer (int width, int height, bool bgra, bool fs, DFrameBuffer *old);
void StartModeIterator (int bits, bool fs);
bool NextMode (int *width, int *height, bool *letterbox);
bool SetResolution (int width, int height, int bits);
void SetupPixelFormat(bool allowsoftware, int multisample, const int *glver);
private:
int IteratorMode;
int IteratorBits;
};
class OculusQuestBaseFB : public DFrameBuffer
{
typedef DFrameBuffer Super;
public:
using DFrameBuffer::DFrameBuffer;
virtual SDL_Window *GetSDLWindow() = 0;
friend class OculusQuestGLVideo;
};
class OculusQuestGLFB : public OculusQuestBaseFB
{
typedef OculusQuestBaseFB Super;
public:
// this must have the same parameters as the Windows version, even if they are not used!
OculusQuestGLFB (void *hMonitor, int width, int height, int, int, bool fullscreen, bool bgra);
~OculusQuestGLFB ();
void ForceBuffering (bool force);
bool Lock(bool buffered);
bool Lock ();
void Unlock();
bool IsLocked ();
bool IsValid ();
bool IsFullscreen ();
virtual void SetVSync( bool vsync );
void SwapBuffers();
void NewRefreshRate ();
friend class OculusQuestGLVideo;
int GetClientWidth();
int GetClientHeight();
virtual void ScaleCoordsFromWindow(int16_t &x, int16_t &y);
SDL_Window *GetSDLWindow() override { return Screen; }
virtual int GetTrueHeight() { return GetClientHeight(); }
protected:
void SetGammaTable(uint16_t *tbl);
void ResetGammaTable();
void InitializeState();
OculusQuestGLFB () {}
uint8_t GammaTable[3][256];
bool UpdatePending;
SDL_Window *Screen;
SDL_GLContext GLContext;
void UpdateColors ();
int m_Lock;
Uint16 m_origGamma[3][256];
bool m_supportsGamma;
};
#endif

View File

@ -1,349 +0,0 @@
/*
** i_joystick.cpp
**
**---------------------------------------------------------------------------
** Copyright 2005-2016 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <SDL.h>
#include "doomdef.h"
#include "version.h"
#include "templates.h"
#include "m_joy.h"
// Very small deadzone so that floating point magic doesn't happen
#define MIN_DEADZONE 0.000001f
CUSTOM_CVAR(Bool, joy_background, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_NOINITCALL)
{
Printf("This won't take effect until " GAMENAME " is restarted.\n");
}
class SDLInputJoystick: public IJoystickConfig
{
public:
SDLInputJoystick(int DeviceIndex) : DeviceIndex(DeviceIndex), Multiplier(1.0f)
{
Device = SDL_JoystickOpen(DeviceIndex);
if(Device != NULL)
{
NumAxes = SDL_JoystickNumAxes(Device);
NumHats = SDL_JoystickNumHats(Device);
SetDefaultConfig();
}
}
~SDLInputJoystick()
{
if(Device != NULL)
M_SaveJoystickConfig(this);
SDL_JoystickClose(Device);
}
bool IsValid() const
{
return Device != NULL;
}
FString GetName()
{
return SDL_JoystickName(Device);
}
float GetSensitivity()
{
return Multiplier;
}
void SetSensitivity(float scale)
{
Multiplier = scale;
}
int GetNumAxes()
{
return NumAxes + NumHats*2;
}
float GetAxisDeadZone(int axis)
{
return Axes[axis].DeadZone;
}
EJoyAxis GetAxisMap(int axis)
{
return Axes[axis].GameAxis;
}
const char *GetAxisName(int axis)
{
return Axes[axis].Name.GetChars();
}
float GetAxisScale(int axis)
{
return Axes[axis].Multiplier;
}
void SetAxisDeadZone(int axis, float zone)
{
Axes[axis].DeadZone = clamp(zone, MIN_DEADZONE, 1.f);
}
void SetAxisMap(int axis, EJoyAxis gameaxis)
{
Axes[axis].GameAxis = gameaxis;
}
void SetAxisScale(int axis, float scale)
{
Axes[axis].Multiplier = scale;
}
// Used by the saver to not save properties that are at their defaults.
bool IsSensitivityDefault()
{
return Multiplier == 1.0f;
}
bool IsAxisDeadZoneDefault(int axis)
{
return Axes[axis].DeadZone <= MIN_DEADZONE;
}
bool IsAxisMapDefault(int axis)
{
if(axis >= 5)
return Axes[axis].GameAxis == JOYAXIS_None;
return Axes[axis].GameAxis == DefaultAxes[axis];
}
bool IsAxisScaleDefault(int axis)
{
return Axes[axis].Multiplier == 1.0f;
}
void SetDefaultConfig()
{
for(int i = 0;i < GetNumAxes();i++)
{
AxisInfo info;
if(i < NumAxes)
info.Name.Format("Axis %d", i+1);
else
info.Name.Format("Hat %d (%c)", (i-NumAxes)/2 + 1, (i-NumAxes)%2 == 0 ? 'x' : 'y');
info.DeadZone = MIN_DEADZONE;
info.Multiplier = 1.0f;
info.Value = 0.0;
info.ButtonValue = 0;
if(i >= 5)
info.GameAxis = JOYAXIS_None;
else
info.GameAxis = DefaultAxes[i];
Axes.Push(info);
}
}
FString GetIdentifier()
{
char id[16];
mysnprintf(id, countof(id), "JS:%d", DeviceIndex);
return id;
}
void AddAxes(float axes[NUM_JOYAXIS])
{
// Add to game axes.
for (int i = 0; i < GetNumAxes(); ++i)
{
if(Axes[i].GameAxis != JOYAXIS_None)
axes[Axes[i].GameAxis] -= float(Axes[i].Value * Multiplier * Axes[i].Multiplier);
}
}
void ProcessInput()
{
uint8_t buttonstate;
for (int i = 0; i < NumAxes; ++i)
{
buttonstate = 0;
Axes[i].Value = SDL_JoystickGetAxis(Device, i)/32767.0;
Axes[i].Value = Joy_RemoveDeadZone(Axes[i].Value, Axes[i].DeadZone, &buttonstate);
// Map button to axis
// X and Y are handled differently so if we have 2 or more axes then we'll use that code instead.
if (NumAxes == 1 || (i >= 2 && i < NUM_JOYAXISBUTTONS))
{
Joy_GenerateButtonEvents(Axes[i].ButtonValue, buttonstate, 2, KEY_JOYAXIS1PLUS + i*2);
Axes[i].ButtonValue = buttonstate;
}
}
if(NumAxes > 1)
{
buttonstate = Joy_XYAxesToButtons(Axes[0].Value, Axes[1].Value);
Joy_GenerateButtonEvents(Axes[0].ButtonValue, buttonstate, 4, KEY_JOYAXIS1PLUS);
Axes[0].ButtonValue = buttonstate;
}
// Map POV hats to buttons and axes. Why axes? Well apparently I have
// a gamepad where the left control stick is a POV hat (instead of the
// d-pad like you would expect, no that's pressure sensitive). Also
// KDE's joystick dialog maps them to axes as well.
for (int i = 0; i < NumHats; ++i)
{
AxisInfo &x = Axes[NumAxes + i*2];
AxisInfo &y = Axes[NumAxes + i*2 + 1];
buttonstate = SDL_JoystickGetHat(Device, i);
// If we're going to assume that we can pass SDL's value into
// Joy_GenerateButtonEvents then we might as well assume the format here.
if(buttonstate & 0x1) // Up
y.Value = -1.0;
else if(buttonstate & 0x4) // Down
y.Value = 1.0;
else
y.Value = 0.0;
if(buttonstate & 0x2) // Left
x.Value = 1.0;
else if(buttonstate & 0x8) // Right
x.Value = -1.0;
else
x.Value = 0.0;
if(i < 4)
{
Joy_GenerateButtonEvents(x.ButtonValue, buttonstate, 4, KEY_JOYPOV1_UP + i*4);
x.ButtonValue = buttonstate;
}
}
}
protected:
struct AxisInfo
{
FString Name;
float DeadZone;
float Multiplier;
EJoyAxis GameAxis;
double Value;
uint8_t ButtonValue;
};
static const EJoyAxis DefaultAxes[5];
int DeviceIndex;
SDL_Joystick *Device;
float Multiplier;
TArray<AxisInfo> Axes;
int NumAxes;
int NumHats;
};
const EJoyAxis SDLInputJoystick::DefaultAxes[5] = {JOYAXIS_Side, JOYAXIS_Forward, JOYAXIS_Pitch, JOYAXIS_Yaw, JOYAXIS_Up};
class SDLInputJoystickManager
{
public:
SDLInputJoystickManager()
{
for(int i = 0;i < SDL_NumJoysticks();i++)
{
SDLInputJoystick *device = new SDLInputJoystick(i);
if(device->IsValid())
Joysticks.Push(device);
else
delete device;
}
}
~SDLInputJoystickManager()
{
for(unsigned int i = 0;i < Joysticks.Size();i++)
delete Joysticks[i];
}
void AddAxes(float axes[NUM_JOYAXIS])
{
for(unsigned int i = 0;i < Joysticks.Size();i++)
Joysticks[i]->AddAxes(axes);
}
void GetDevices(TArray<IJoystickConfig *> &sticks)
{
for(unsigned int i = 0;i < Joysticks.Size();i++)
{
M_LoadJoystickConfig(Joysticks[i]);
sticks.Push(Joysticks[i]);
}
}
void ProcessInput() const
{
for(unsigned int i = 0;i < Joysticks.Size();++i)
Joysticks[i]->ProcessInput();
}
protected:
TArray<SDLInputJoystick *> Joysticks;
};
static SDLInputJoystickManager *JoystickManager;
void I_StartupJoysticks()
{
if (joy_background)
SDL_SetHint("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS", "1");
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) >= 0)
JoystickManager = new SDLInputJoystickManager();
}
void I_ShutdownJoysticks()
{
if(JoystickManager)
{
delete JoystickManager;
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
}
}
void I_GetJoysticks(TArray<IJoystickConfig *> &sticks)
{
sticks.Clear();
JoystickManager->GetDevices(sticks);
}
void I_GetAxes(float axes[NUM_JOYAXIS])
{
for (int i = 0; i < NUM_JOYAXIS; ++i)
{
axes[i] = 0;
}
if (use_joystick)
{
JoystickManager->AddAxes(axes);
}
}
void I_ProcessJoysticks()
{
if (use_joystick)
JoystickManager->ProcessInput();
}
IJoystickConfig *I_UpdateDeviceList()
{
return NULL;
}

View File

@ -1,496 +0,0 @@
//-----------------------------------------------------------------------------
//
// Copyright 1993-1996 id Software
// Copyright 1999-2016 Randy Heit
//
// 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.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//-----------------------------------------------------------------------------
//
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fnmatch.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include <SDL.h>
#include "doomerrors.h"
#include <math.h>
#include "doomtype.h"
#include "doomstat.h"
#include "version.h"
#include "doomdef.h"
#include "cmdlib.h"
#include "m_argv.h"
#include "m_misc.h"
#include "i_video.h"
#include "i_sound.h"
#include "i_music.h"
#include "x86.h"
#include "d_main.h"
#include "d_net.h"
#include "g_game.h"
#include "i_system.h"
#include "c_dispatch.h"
#include "atterm.h"
#include "templates.h"
#include "v_palette.h"
#include "textures.h"
#include "bitmap.h"
#include "stats.h"
#include "hardware.h"
#include "gameconfigfile.h"
#include "m_fixed.h"
#include "g_level.h"
extern "C"
{
double SecondsPerCycle = 1e-8;
double CyclesPerSecond = 1e8;
}
#ifndef NO_GTK
bool I_GtkAvailable ();
int I_PickIWad_Gtk (WadStuff *wads, int numwads, bool showwin, int defaultiwad);
void I_FatalError_Gtk(const char* errortext);
#elif defined(__APPLE__)
int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad);
#endif
double PerfToSec, PerfToMillisec;
void I_Tactile (int /*on*/, int /*off*/, int /*total*/)
{
}
ticcmd_t emptycmd;
ticcmd_t *I_BaseTiccmd(void)
{
return &emptycmd;
}
void I_BeginRead(void)
{
}
void I_EndRead(void)
{
}
//
// I_Init
//
void I_Init (void)
{
CheckCPUID (&CPU);
DumpCPUInfo (&CPU);
atterm (I_ShutdownSound);
I_InitSound ();
}
//
// I_Quit
//
static int has_exited;
void I_Quit (void)
{
has_exited = 1; /* Prevent infinitely recursive exits -- killough */
if (demorecording)
G_CheckDemoStatus();
C_DeinitConsole();
}
//
// I_Error
//
extern FILE *Logfile;
bool gameisdead;
#ifdef __APPLE__
void Mac_I_FatalError(const char* errortext);
#endif
#ifdef __ANDROID__
#include <android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO,"Gzdoom", __VA_ARGS__))
#endif
#ifdef __linux__
void Linux_I_FatalError(const char* errortext)
{
// Close window or exit fullscreen and release mouse capture
SDL_Quit();
const char *str;
if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0)
{
FString cmd;
cmd << "kdialog --title \"" GAMESIG " ";
cmd << GetVersionString() << ": No IWAD found\" ";
cmd << "--msgbox \"" << errortext << "\"";
popen(cmd, "r");
}
#ifndef NO_GTK
else if (I_GtkAvailable())
{
I_FatalError_Gtk(errortext);
}
#endif
else
{
FString message;
message << GAMESIG " ";
message << GetVersionString() << ": No IWAD found";
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, message, errortext, NULL);
}
}
#endif
void I_FatalError (const char *error, va_list ap)
{
static bool alreadyThrown = false;
gameisdead = true;
if (!alreadyThrown) // ignore all but the first message -- killough
{
alreadyThrown = true;
char errortext[MAX_ERRORTEXT];
int index;
index = vsnprintf (errortext, MAX_ERRORTEXT, error, ap);
#ifdef __APPLE__
Mac_I_FatalError(errortext);
#endif // __APPLE__
#ifdef __ANDROID__
LOGI("FATAL ERROR: %s", errortext);
#endif
#ifdef __linux__
Linux_I_FatalError(errortext);
#endif
// Record error to log (if logging)
if (Logfile)
{
fprintf (Logfile, "\n**** DIED WITH FATAL ERROR:\n%s\n", errortext);
fflush (Logfile);
}
// throw CFatalError (errortext);
fprintf (stderr, "%s\n", errortext);
exit (-1);
}
if (!has_exited) // If it hasn't exited yet, exit now -- killough
{
has_exited = 1; // Prevent infinitely recursive exits -- killough
exit(-1);
}
}
void I_FatalError(const char* const error, ...)
{
va_list argptr;
va_start(argptr, error);
I_FatalError(error, argptr);
va_end(argptr);
}
void I_Error (const char *error, ...)
{
va_list argptr;
char errortext[MAX_ERRORTEXT];
va_start(argptr, error);
myvsnprintf (errortext, MAX_ERRORTEXT, error, argptr);
va_end (argptr);
#ifdef __ANDROID__
LOGI("ERROR: %s", errortext);
#endif
throw CRecoverableError(errortext);
}
void I_SetIWADInfo ()
{
}
void I_DebugPrint(const char *cp)
{
}
void I_PrintStr(const char *cp)
{
// Strip out any color escape sequences before writing to debug output
TArray<char> copy(strlen(cp) + 1, true);
const char * srcp = cp;
char * dstp = copy.Data();
while (*srcp != 0)
{
if (*srcp != 0x1c && *srcp != 0x1d && *srcp != 0x1e && *srcp != 0x1f)
{
*dstp++ = *srcp++;
}
else
{
if (srcp[1] != 0) srcp += 2;
else break;
}
}
*dstp = 0;
fputs(copy.Data(), stdout);
fflush(stdout);
}
int I_PickIWad (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
{
int i;
if (!showwin)
{
return defaultiwad;
}
#ifndef __APPLE__
const char *str;
if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0)
{
FString cmd("kdialog --title \"" GAMESIG " ");
cmd << GetVersionString() << ": Select an IWAD to use\""
" --menu \"" GAMENAME " found more than one IWAD\n"
"Select from the list below to determine which one to use:\"";
for(i = 0; i < numwads; ++i)
{
const char *filepart = strrchr(wads[i].Path, '/');
if(filepart == NULL)
filepart = wads[i].Path;
else
filepart++;
// Menu entries are specified in "tag" "item" pairs, where when a
// particular item is selected (and the Okay button clicked), its
// corresponding tag is printed to stdout for identification.
cmd.AppendFormat(" \"%d\" \"%s (%s)\"", i, wads[i].Name.GetChars(), filepart);
}
if(defaultiwad >= 0 && defaultiwad < numwads)
{
const char *filepart = strrchr(wads[defaultiwad].Path, '/');
if(filepart == NULL)
filepart = wads[defaultiwad].Path;
else
filepart++;
cmd.AppendFormat(" --default \"%s (%s)\"", wads[defaultiwad].Name.GetChars(), filepart);
}
FILE *f = popen(cmd, "r");
if(f != NULL)
{
char gotstr[16];
if(fgets(gotstr, sizeof(gotstr), f) == NULL ||
sscanf(gotstr, "%d", &i) != 1)
i = -1;
// Exit status = 1 means the selection was canceled (either by
// Cancel/Esc or the X button), not that there was an error running
// the program. In that case, nothing was printed so fgets will
// have failed. Other values can indicate an error running the app,
// so fall back to whatever else can be used.
int status = pclose(f);
if(WIFEXITED(status) && (WEXITSTATUS(status) == 0 || WEXITSTATUS(status) == 1))
return i;
}
}
#endif
#ifndef NO_GTK
if (I_GtkAvailable())
{
return I_PickIWad_Gtk (wads, numwads, showwin, defaultiwad);
}
#endif
#ifdef __APPLE__
return I_PickIWad_Cocoa (wads, numwads, showwin, defaultiwad);
#endif
printf ("Please select a game wad (or 0 to exit):\n");
for (i = 0; i < numwads; ++i)
{
const char *filepart = strrchr (wads[i].Path, '/');
if (filepart == NULL)
filepart = wads[i].Path;
else
filepart++;
printf ("%d. %s (%s)\n", i+1, wads[i].Name.GetChars(), filepart);
}
printf ("Which one? ");
if (scanf ("%d", &i) != 1 || i > numwads)
return -1;
return i-1;
}
bool I_WriteIniFailed ()
{
printf ("The config file %s could not be saved:\n%s\n", GameConfig->GetPathName(), strerror(errno));
return false;
// return true to retry
}
static const char *pattern;
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED < 1080
static int matchfile (struct dirent *ent)
#else
static int matchfile (const struct dirent *ent)
#endif
{
return fnmatch (pattern, ent->d_name, FNM_NOESCAPE) == 0;
}
void *I_FindFirst (const char *filespec, findstate_t *fileinfo)
{
FString dir;
const char *slash = strrchr (filespec, '/');
if (slash)
{
pattern = slash+1;
dir = FString(filespec, slash-filespec+1);
}
else
{
pattern = filespec;
dir = ".";
}
fileinfo->current = 0;
fileinfo->count = scandir (dir.GetChars(), &fileinfo->namelist,
matchfile, alphasort);
if (fileinfo->count > 0)
{
return fileinfo;
}
return (void*)-1;
}
int I_FindNext (void *handle, findstate_t *fileinfo)
{
findstate_t *state = (findstate_t *)handle;
if (state->current < fileinfo->count)
{
return ++state->current < fileinfo->count ? 0 : -1;
}
return -1;
}
int I_FindClose (void *handle)
{
findstate_t *state = (findstate_t *)handle;
if (handle != (void*)-1 && state->count > 0)
{
for(int i = 0;i < state->count;++i)
free (state->namelist[i]);
state->count = 0;
free (state->namelist);
state->namelist = NULL;
}
return 0;
}
int I_FindAttr(findstate_t* const fileinfo)
{
dirent* const ent = fileinfo->namelist[fileinfo->current];
bool isdir;
if (DirEntryExists(ent->d_name, &isdir))
{
return isdir ? FA_DIREC : 0;
}
return 0;
}
void I_PutInClipboard (const char *str)
{
SDL_SetClipboardText(str);
}
FString I_GetFromClipboard (bool use_primary_selection)
{
if(char *ret = SDL_GetClipboardText())
{
FString text(ret);
SDL_free(ret);
return text;
}
return "";
}
// Return a random seed, preferably one with lots of entropy.
unsigned int I_MakeRNGSeed()
{
unsigned int seed;
int file;
// Try reading from /dev/urandom first, then /dev/random, then
// if all else fails, use a crappy seed from time().
seed = time(NULL);
file = open("/dev/urandom", O_RDONLY);
if (file < 0)
{
file = open("/dev/random", O_RDONLY);
}
if (file >= 0)
{
read(file, &seed, sizeof(seed));
close(file);
}
return seed;
}
TArray<FString> I_GetGogPaths()
{
// GOG's Doom games are Windows only at the moment
return TArray<FString>();
}

View File

@ -1,238 +0,0 @@
/*
** i_specialpaths.mm
** Gets special system folders where data should be stored. (macOS version)
**
**---------------------------------------------------------------------------
** Copyright 2013-2016 Randy Heit
** Copyright 2016 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <CoreServices/CoreServices.h>
#include "cmdlib.h"
#include "m_misc.h"
#include "version.h" // for GAMENAME
//===========================================================================
//
// M_GetAppDataPath macOS
//
// Returns the path for the AppData folder.
//
//===========================================================================
FString M_GetAppDataPath(bool create)
{
FString path;
char pathstr[PATH_MAX];
FSRef folder;
if (noErr == FSFindFolder(kUserDomain, kApplicationSupportFolderType, create ? kCreateFolder : 0, &folder) &&
noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX))
{
path = pathstr;
}
else
{
path = progdir;
}
path += "/" GAMENAMELOWERCASE;
if (create) CreatePath(path);
return path;
}
//===========================================================================
//
// M_GetCachePath macOS
//
// Returns the path for cache GL nodes.
//
//===========================================================================
FString M_GetCachePath(bool create)
{
FString path;
char pathstr[PATH_MAX];
FSRef folder;
if (noErr == FSFindFolder(kUserDomain, kApplicationSupportFolderType, create ? kCreateFolder : 0, &folder) &&
noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX))
{
path = pathstr;
}
else
{
path = progdir;
}
path += "/zdoom/cache";
if (create) CreatePath(path);
return path;
}
//===========================================================================
//
// M_GetAutoexecPath macOS
//
// Returns the expected location of autoexec.cfg.
//
//===========================================================================
FString M_GetAutoexecPath()
{
FString path;
char cpath[PATH_MAX];
FSRef folder;
if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) &&
noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
{
path << cpath << "/" GAME_DIR "/autoexec.cfg";
}
return path;
}
//===========================================================================
//
// M_GetCajunPath macOS
//
// Returns the location of the Cajun Bot definitions.
//
//===========================================================================
FString M_GetCajunPath(const char *botfilename)
{
FString path;
// Just copies the Windows code. Should this be more Mac-specific?
path << progdir << "zcajun/" << botfilename;
if (!FileExists(path))
{
path = "";
}
return path;
}
//===========================================================================
//
// M_GetConfigPath macOS
//
// Returns the path to the config file. On Windows, this can vary for reading
// vs writing. i.e. If $PROGDIR/zdoom-<user>.ini does not exist, it will try
// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini.
//
//===========================================================================
FString M_GetConfigPath(bool for_reading)
{
char cpath[PATH_MAX];
FSRef folder;
if (noErr == FSFindFolder(kUserDomain, kPreferencesFolderType, kCreateFolder, &folder) &&
noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
{
FString path;
path << cpath << "/" GAMENAMELOWERCASE ".ini";
return path;
}
// Ungh.
return GAMENAMELOWERCASE ".ini";
}
//===========================================================================
//
// M_GetScreenshotsPath macOS
//
// Returns the path to the default screenshots directory.
//
//===========================================================================
FString M_GetScreenshotsPath()
{
FString path;
char cpath[PATH_MAX];
FSRef folder;
if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) &&
noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
{
path << cpath << "/" GAME_DIR "/Screenshots/";
}
else
{
path = "~/";
}
return path;
}
//===========================================================================
//
// M_GetSavegamesPath macOS
//
// Returns the path to the default save games directory.
//
//===========================================================================
FString M_GetSavegamesPath()
{
FString path;
char cpath[PATH_MAX];
FSRef folder;
if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) &&
noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
{
path << cpath << "/" GAME_DIR "/Savegames/";
}
return path;
}
//===========================================================================
//
// M_GetDocumentsPath Unix
//
// Returns the path to the default documents directory.
//
//===========================================================================
FString M_GetDocumentsPath()
{
FString path;
char cpath[PATH_MAX];
FSRef folder;
if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) &&
noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX))
{
path << cpath << "/" GAME_DIR "/";
}
return path;
}

View File

@ -1,470 +0,0 @@
/*
** iwadpicker_cocoa.mm
**
** Implements Mac OS X native IWAD Picker.
**
**---------------------------------------------------------------------------
** Copyright 2010 Braden Obrzut
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "cmdlib.h"
#include "d_main.h"
#include "version.h"
#include "c_cvars.h"
#include "m_argv.h"
#include "m_misc.h"
#include "gameconfigfile.h"
#include <Cocoa/Cocoa.h>
#include <wordexp.h>
#include <unistd.h>
CVAR(String, osx_additional_parameters, "", CVAR_ARCHIVE | CVAR_NOSET | CVAR_GLOBALCONFIG);
enum
{
COLUMN_IWAD,
COLUMN_GAME,
NUM_COLUMNS
};
static const char* const tableHeaders[NUM_COLUMNS] = { "IWAD", "Game" };
// Class to convert the IWAD data into a form that Cocoa can use.
@interface IWADTableData : NSObject<NSTableViewDataSource>
{
NSMutableArray *data;
}
- (void)dealloc;
- (IWADTableData *)init:(WadStuff *) wads num:(int) numwads;
- (int)numberOfRowsInTableView:(NSTableView *)aTableView;
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex;
@end
@implementation IWADTableData
- (void)dealloc
{
[data release];
[super dealloc];
}
- (IWADTableData *)init:(WadStuff *) wads num:(int) numwads
{
data = [[NSMutableArray alloc] initWithCapacity:numwads];
for(int i = 0;i < numwads;i++)
{
NSMutableDictionary *record = [[NSMutableDictionary alloc] initWithCapacity:NUM_COLUMNS];
const char* filename = strrchr(wads[i].Path, '/');
if(filename == NULL)
filename = wads[i].Path;
else
filename++;
[record setObject:[NSString stringWithUTF8String:filename] forKey:[NSString stringWithUTF8String:tableHeaders[COLUMN_IWAD]]];
[record setObject:[NSString stringWithUTF8String:wads[i].Name] forKey:[NSString stringWithUTF8String:tableHeaders[COLUMN_GAME]]];
[data addObject:record];
[record release];
}
return self;
}
- (int)numberOfRowsInTableView:(NSTableView *)aTableView
{
return [data count];
}
- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
{
NSParameterAssert(rowIndex >= 0 && (unsigned int) rowIndex < [data count]);
NSMutableDictionary *record = [data objectAtIndex:rowIndex];
return [record objectForKey:[aTableColumn identifier]];
}
@end
static NSDictionary* GetKnownFileTypes()
{
return [NSDictionary dictionaryWithObjectsAndKeys:
@"-file" , @"wad",
@"-file" , @"pk3",
@"-file" , @"zip",
@"-file" , @"pk7",
@"-file" , @"7z",
@"-deh" , @"deh",
@"-bex" , @"bex",
@"-exec" , @"cfg",
@"-playdemo", @"lmp",
nil];
}
static NSArray* GetKnownExtensions()
{
return [GetKnownFileTypes() allKeys];
}
@interface NSMutableString(AppendKnownFileType)
- (void)appendKnownFileType:(NSString *)filePath;
@end
@implementation NSMutableString(AppendKnownFileType)
- (void)appendKnownFileType:(NSString *)filePath
{
NSString* extension = [[filePath pathExtension] lowercaseString];
NSString* parameter = [GetKnownFileTypes() objectForKey:extension];
if (nil == parameter)
{
return;
}
[self appendFormat:@"%@ \"%@\" ", parameter, filePath];
}
@end
// So we can listen for button actions and such we need to have an Obj-C class.
@interface IWADPicker : NSObject
{
NSApplication *app;
NSWindow *window;
NSButton *okButton;
NSButton *cancelButton;
NSButton *browseButton;
NSTextField *parametersTextField;
bool cancelled;
}
- (void)buttonPressed:(id) sender;
- (void)browseButtonPressed:(id) sender;
- (void)doubleClicked:(id) sender;
- (void)makeLabel:(NSTextField *)label withString:(const char*) str;
- (int)pickIWad:(WadStuff *)wads num:(int) numwads showWindow:(bool) showwin defaultWad:(int) defaultiwad;
- (NSString*)commandLineParameters;
- (void)menuActionSent:(NSNotification*)notification;
@end
@implementation IWADPicker
- (void)buttonPressed:(id) sender
{
if(sender == cancelButton)
cancelled = true;
[window orderOut:self];
[app stopModal];
}
- (void)browseButtonPressed:(id) sender
{
NSOpenPanel* openPanel = [NSOpenPanel openPanel];
[openPanel setAllowsMultipleSelection:YES];
[openPanel setCanChooseFiles:YES];
[openPanel setCanChooseDirectories:YES];
[openPanel setResolvesAliases:YES];
[openPanel setAllowedFileTypes:GetKnownExtensions()];
if (NSOKButton == [openPanel runModal])
{
NSArray* files = [openPanel URLs];
NSMutableString* parameters = [NSMutableString string];
for (NSUInteger i = 0, ei = [files count]; i < ei; ++i)
{
NSString* filePath = [[files objectAtIndex:i] path];
BOOL isDirectory = false;
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:&isDirectory] && isDirectory)
{
[parameters appendFormat:@"-file \"%@\" ", filePath];
}
else
{
[parameters appendKnownFileType:filePath];
}
}
if ([parameters length] > 0)
{
NSString* newParameters = [parametersTextField stringValue];
if ([newParameters length] > 0
&& NO == [newParameters hasSuffix:@" "])
{
newParameters = [newParameters stringByAppendingString:@" "];
}
newParameters = [newParameters stringByAppendingString:parameters];
[parametersTextField setStringValue: newParameters];
}
}
}
- (void)doubleClicked:(id) sender
{
if ([sender clickedRow] >= 0)
{
[window orderOut:self];
[app stopModal];
}
}
// Apparently labels in Cocoa are uneditable text fields, so lets make this a
// little more automated.
- (void)makeLabel:(NSTextField *)label withString:(const char*) str
{
[label setStringValue:[NSString stringWithUTF8String:str]];
[label setBezeled:NO];
[label setDrawsBackground:NO];
[label setEditable:NO];
[label setSelectable:NO];
}
- (int)pickIWad:(WadStuff *)wads num:(int) numwads showWindow:(bool) showwin defaultWad:(int) defaultiwad
{
cancelled = false;
app = [NSApplication sharedApplication];
id windowTitle = [NSString stringWithFormat:@"%s %s", GAMENAME, GetVersionString()];
NSRect frame = NSMakeRect(0, 0, 440, 450);
window = [[NSWindow alloc] initWithContentRect:frame styleMask:NSTitledWindowMask backing:NSBackingStoreBuffered defer:NO];
[window setTitle:windowTitle];
NSTextField *description = [[NSTextField alloc] initWithFrame:NSMakeRect(18, 384, 402, 50)];
[self makeLabel:description withString:GAMENAME " found more than one IWAD\nSelect from the list below to determine which one to use:"];
[[window contentView] addSubview:description];
[description release];
NSScrollView *iwadScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 135, 402, 256)];
NSTableView *iwadTable = [[NSTableView alloc] initWithFrame:[iwadScroller bounds]];
IWADTableData *tableData = [[IWADTableData alloc] init:wads num:numwads];
for(int i = 0;i < NUM_COLUMNS;i++)
{
NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:[NSString stringWithUTF8String:tableHeaders[i]]];
[[column headerCell] setStringValue:[column identifier]];
if(i == 0)
[column setMaxWidth:110];
[column setEditable:NO];
[column setResizingMask:NSTableColumnAutoresizingMask];
[iwadTable addTableColumn:column];
[column release];
}
[iwadScroller setDocumentView:iwadTable];
[iwadScroller setHasVerticalScroller:YES];
[iwadTable setDataSource:tableData];
[iwadTable sizeToFit];
[iwadTable setDoubleAction:@selector(doubleClicked:)];
[iwadTable setTarget:self];
NSIndexSet *selection = [[NSIndexSet alloc] initWithIndex:defaultiwad];
[iwadTable selectRowIndexes:selection byExtendingSelection:NO];
[selection release];
[iwadTable scrollRowToVisible:defaultiwad];
[[window contentView] addSubview:iwadScroller];
[iwadTable release];
[iwadScroller release];
NSTextField *additionalParametersLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(18, 108, 144, 17)];
[self makeLabel:additionalParametersLabel withString:"Additional Parameters:"];
[[window contentView] addSubview:additionalParametersLabel];
parametersTextField = [[NSTextField alloc] initWithFrame:NSMakeRect(20, 48, 402, 54)];
[parametersTextField setStringValue:[NSString stringWithUTF8String:osx_additional_parameters]];
[[window contentView] addSubview:parametersTextField];
// Doesn't look like the SDL version implements this so lets not show it.
/*NSButton *dontAsk = [[NSButton alloc] initWithFrame:NSMakeRect(18, 18, 178, 18)];
[dontAsk setTitle:[NSString stringWithCString:"Don't ask me this again"]];
[dontAsk setButtonType:NSSwitchButton];
[dontAsk setState:(showwin ? NSOffState : NSOnState)];
[[window contentView] addSubview:dontAsk];*/
okButton = [[NSButton alloc] initWithFrame:NSMakeRect(236, 8, 96, 32)];
[okButton setTitle:@"OK"];
[okButton setBezelStyle:NSRoundedBezelStyle];
[okButton setAction:@selector(buttonPressed:)];
[okButton setTarget:self];
[okButton setKeyEquivalent:@"\r"];
[[window contentView] addSubview:okButton];
cancelButton = [[NSButton alloc] initWithFrame:NSMakeRect(332, 8, 96, 32)];
[cancelButton setTitle:@"Cancel"];
[cancelButton setBezelStyle:NSRoundedBezelStyle];
[cancelButton setAction:@selector(buttonPressed:)];
[cancelButton setTarget:self];
[cancelButton setKeyEquivalent:@"\033"];
[[window contentView] addSubview:cancelButton];
browseButton = [[NSButton alloc] initWithFrame:NSMakeRect(14, 8, 96, 32)];
[browseButton setTitle:@"Browse..."];
[browseButton setBezelStyle:NSRoundedBezelStyle];
[browseButton setAction:@selector(browseButtonPressed:)];
[browseButton setTarget:self];
[[window contentView] addSubview:browseButton];
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(menuActionSent:) name:NSMenuDidSendActionNotification object:nil];
[window center];
[app runModalForWindow:window];
[center removeObserver:self name:NSMenuDidSendActionNotification object:nil];
[window release];
[okButton release];
[cancelButton release];
[browseButton release];
return cancelled ? -1 : [iwadTable selectedRow];
}
- (NSString*)commandLineParameters
{
return [parametersTextField stringValue];
}
- (void)menuActionSent:(NSNotification*)notification
{
NSDictionary* userInfo = [notification userInfo];
NSMenuItem* menuItem = [userInfo valueForKey:@"MenuItem"];
if ( @selector(terminate:) == [menuItem action] )
{
exit(0);
}
}
@end
EXTERN_CVAR(String, defaultiwad)
static NSString* GetArchitectureString()
{
#ifdef __i386__
return @"i386";
#elif defined __x86_64__
return @"x86_64";
#endif
}
static void RestartWithParameters(const WadStuff& wad, NSString* parameters)
{
assert(nil != parameters);
defaultiwad = wad.Name;
GameConfig->DoGameSetup("Doom");
M_SaveDefaults(NULL);
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@try
{
NSString* executablePath = [NSString stringWithUTF8String:Args->GetArg(0)];
NSMutableArray* const arguments = [[NSMutableArray alloc] init];
// The following value shoud be equal to NSAppKitVersionNumber10_5
// It's hard-coded in order to build with earlier SDKs
const bool canSelectArchitecture = NSAppKitVersionNumber >= 949;
if (canSelectArchitecture)
{
[arguments addObject:@"-arch"];
[arguments addObject:GetArchitectureString()];
[arguments addObject:executablePath];
executablePath = @"/usr/bin/arch";
}
[arguments addObject:@"-iwad"];
[arguments addObject:[NSString stringWithUTF8String:wad.Path]];
for (int i = 1, count = Args->NumArgs(); i < count; ++i)
{
NSString* currentParameter = [NSString stringWithUTF8String:Args->GetArg(i)];
[arguments addObject:currentParameter];
}
wordexp_t expansion = {};
if (0 == wordexp([parameters UTF8String], &expansion, 0))
{
for (size_t i = 0; i < expansion.we_wordc; ++i)
{
NSString* argumentString = [NSString stringWithCString:expansion.we_wordv[i]
encoding:NSUTF8StringEncoding];
[arguments addObject:argumentString];
}
wordfree(&expansion);
}
[NSTask launchedTaskWithLaunchPath:executablePath
arguments:arguments];
_exit(0); // to avoid atexit()'s functions
}
@catch (NSException* e)
{
NSLog(@"Cannot restart: %@", [e reason]);
}
[pool release];
}
// Simple wrapper so we can call this from outside.
int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
IWADPicker *picker = [IWADPicker alloc];
int ret = [picker pickIWad:wads num:numwads showWindow:showwin defaultWad:defaultiwad];
NSString* parametersToAppend = [picker commandLineParameters];
osx_additional_parameters = [parametersToAppend UTF8String];
if (ret >= 0)
{
if (0 != [parametersToAppend length])
{
RestartWithParameters(wads[ret], parametersToAppend);
}
}
[pool release];
return ret;
}

View File

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string>zdoom.icns</string>
<key>CFBundleIdentifier</key>
<string>org.drdteam.gzdoom</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>GZDoom</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>Development Version</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.action-games</string>
<key>LSMinimumSystemVersion</key>
<string>10.7</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>Doom Resource File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleTypeExtensions</key>
<array>
<string>wad</string>
<string>pk3</string>
<string>zip</string>
<string>pk7</string>
<string>7z</string>
<string>iwad</string>
<string>ipk3</string>
<string>ipk7</string>
</array>
</dict>
</array>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
</dict>
</plist>

View File

@ -1,428 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#ifdef __linux__
#include <sys/prctl.h>
#ifndef PR_SET_PTRACER
#define PR_SET_PTRACER 0x59616d61
#endif
#elif defined (__APPLE__) || defined (__FreeBSD__) || defined(__OpenBSD__)
#include <signal.h>
#endif
static const char crash_switch[] = "--cc-handle-crash";
static const char fatal_err[] = "\n\n*** Fatal Error ***\n";
static const char pipe_err[] = "!!! Failed to create pipe\n";
static const char fork_err[] = "!!! Failed to fork debug process\n";
static const char exec_err[] = "!!! Failed to exec debug process\n";
static char argv0[PATH_MAX];
static char altstack[SIGSTKSZ];
static struct {
int signum;
pid_t pid;
int has_siginfo;
siginfo_t siginfo;
char buf[4096];
} crash_info;
static const struct {
const char *name;
int signum;
} signals[] = {
{ "Segmentation fault", SIGSEGV },
{ "Illegal instruction", SIGILL },
{ "FPU exception", SIGFPE },
{ "System BUS error", SIGBUS },
{ NULL, 0 }
};
static const struct {
int code;
const char *name;
} sigill_codes[] = {
#ifndef __FreeBSD__
{ ILL_ILLOPC, "Illegal opcode" },
{ ILL_ILLOPN, "Illegal operand" },
{ ILL_ILLADR, "Illegal addressing mode" },
{ ILL_ILLTRP, "Illegal trap" },
{ ILL_PRVOPC, "Privileged opcode" },
{ ILL_PRVREG, "Privileged register" },
{ ILL_COPROC, "Coprocessor error" },
{ ILL_BADSTK, "Internal stack error" },
#endif
{ 0, NULL }
};
static const struct {
int code;
const char *name;
} sigfpe_codes[] = {
{ FPE_INTDIV, "Integer divide by zero" },
{ FPE_INTOVF, "Integer overflow" },
{ FPE_FLTDIV, "Floating point divide by zero" },
{ FPE_FLTOVF, "Floating point overflow" },
{ FPE_FLTUND, "Floating point underflow" },
{ FPE_FLTRES, "Floating point inexact result" },
{ FPE_FLTINV, "Floating point invalid operation" },
{ FPE_FLTSUB, "Subscript out of range" },
{ 0, NULL }
};
static const struct {
int code;
const char *name;
} sigsegv_codes[] = {
#ifndef __FreeBSD__
{ SEGV_MAPERR, "Address not mapped to object" },
{ SEGV_ACCERR, "Invalid permissions for mapped object" },
#endif
{ 0, NULL }
};
static const struct {
int code;
const char *name;
} sigbus_codes[] = {
#ifndef __FreeBSD__
{ BUS_ADRALN, "Invalid address alignment" },
{ BUS_ADRERR, "Non-existent physical address" },
{ BUS_OBJERR, "Object specific hardware error" },
#endif
{ 0, NULL }
};
static int (*cc_user_info)(char*, char*);
static void gdb_info(pid_t pid)
{
char respfile[64];
char cmd_buf[128];
FILE *f;
int fd;
/* Create a temp file to put gdb commands into */
strcpy(respfile, "gdb-respfile-XXXXXX");
if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != NULL)
{
fprintf(f, "attach %d\n"
"shell echo \"\"\n"
"shell echo \"* Loaded Libraries\"\n"
"info sharedlibrary\n"
"shell echo \"\"\n"
"shell echo \"* Threads\"\n"
"info threads\n"
"shell echo \"\"\n"
"shell echo \"* FPU Status\"\n"
"info float\n"
"shell echo \"\"\n"
"shell echo \"* Registers\"\n"
"info registers\n"
"shell echo \"\"\n"
"shell echo \"* Backtrace\"\n"
"thread apply all backtrace full\n"
"detach\n"
"quit\n", pid);
fclose(f);
/* Run gdb and print process info. */
snprintf(cmd_buf, sizeof(cmd_buf), "gdb --quiet --batch --command=%s", respfile);
printf("Executing: %s\n", cmd_buf);
fflush(stdout);
system(cmd_buf);
/* Clean up */
remove(respfile);
}
else
{
/* Error creating temp file */
if(fd >= 0)
{
close(fd);
remove(respfile);
}
printf("!!! Could not create gdb command file\n");
}
fflush(stdout);
}
static void sys_info(void)
{
#ifdef __unix__
system("echo \"System: `uname -a`\"");
putchar('\n');
fflush(stdout);
#endif
}
static size_t safe_write(int fd, const void *buf, size_t len)
{
size_t ret = 0;
while(ret < len)
{
ssize_t rem;
if((rem=write(fd, (const char*)buf+ret, len-ret)) == -1)
{
if(errno == EINTR)
continue;
break;
}
ret += rem;
}
return ret;
}
static void crash_catcher(int signum, siginfo_t *siginfo, void *context)
{
//ucontext_t *ucontext = (ucontext_t*)context;
pid_t dbg_pid;
int fd[2];
/* Make sure the effective uid is the real uid */
if(getuid() != geteuid())
{
raise(signum);
return;
}
safe_write(STDERR_FILENO, fatal_err, sizeof(fatal_err)-1);
if(pipe(fd) == -1)
{
safe_write(STDERR_FILENO, pipe_err, sizeof(pipe_err)-1);
raise(signum);
return;
}
crash_info.signum = signum;
crash_info.pid = getpid();
crash_info.has_siginfo = !!siginfo;
if(siginfo)
crash_info.siginfo = *siginfo;
if(cc_user_info)
cc_user_info(crash_info.buf, crash_info.buf+sizeof(crash_info.buf));
/* Fork off to start a crash handler */
switch((dbg_pid=fork()))
{
/* Error */
case -1:
safe_write(STDERR_FILENO, fork_err, sizeof(fork_err)-1);
raise(signum);
return;
case 0:
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execl(argv0, argv0, crash_switch, NULL);
safe_write(STDERR_FILENO, exec_err, sizeof(exec_err)-1);
_exit(1);
default:
#ifdef __linux__
prctl(PR_SET_PTRACER, dbg_pid, 0, 0, 0);
#endif
safe_write(fd[1], &crash_info, sizeof(crash_info));
close(fd[0]);
close(fd[1]);
/* Wait; we'll be killed when gdb is done */
do {
int status;
if(waitpid(dbg_pid, &status, 0) == dbg_pid &&
(WIFEXITED(status) || WIFSIGNALED(status)))
{
/* The debug process died before it could kill us */
raise(signum);
break;
}
} while(1);
}
}
static void crash_handler(const char *logfile)
{
const char *sigdesc = "";
int i;
if(fread(&crash_info, sizeof(crash_info), 1, stdin) != 1)
{
fprintf(stderr, "!!! Failed to retrieve info from crashed process\n");
exit(1);
}
/* Get the signal description */
for(i = 0;signals[i].name;++i)
{
if(signals[i].signum == crash_info.signum)
{
sigdesc = signals[i].name;
break;
}
}
if(crash_info.has_siginfo)
{
switch(crash_info.signum)
{
case SIGSEGV:
for(i = 0;sigsegv_codes[i].name;++i)
{
if(sigsegv_codes[i].code == crash_info.siginfo.si_code)
{
sigdesc = sigsegv_codes[i].name;
break;
}
}
break;
case SIGFPE:
for(i = 0;sigfpe_codes[i].name;++i)
{
if(sigfpe_codes[i].code == crash_info.siginfo.si_code)
{
sigdesc = sigfpe_codes[i].name;
break;
}
}
break;
case SIGILL:
for(i = 0;sigill_codes[i].name;++i)
{
if(sigill_codes[i].code == crash_info.siginfo.si_code)
{
sigdesc = sigill_codes[i].name;
break;
}
}
break;
case SIGBUS:
for(i = 0;sigbus_codes[i].name;++i)
{
if(sigbus_codes[i].code == crash_info.siginfo.si_code)
{
sigdesc = sigbus_codes[i].name;
break;
}
}
break;
}
}
fprintf(stderr, "%s (signal %i)\n", sigdesc, crash_info.signum);
if(crash_info.has_siginfo)
fprintf(stderr, "Address: %p\n", crash_info.siginfo.si_addr);
fputc('\n', stderr);
if(logfile)
{
/* Create crash log file and redirect shell output to it */
if(freopen(logfile, "wa", stdout) != stdout)
{
fprintf(stderr, "!!! Could not create %s following signal\n", logfile);
exit(1);
}
fprintf(stderr, "Generating %s and killing process %d, please wait... ", logfile, crash_info.pid);
printf("*** Fatal Error ***\n"
"%s (signal %i)\n", sigdesc, crash_info.signum);
if(crash_info.has_siginfo)
printf("Address: %p\n", crash_info.siginfo.si_addr);
fputc('\n', stdout);
fflush(stdout);
}
sys_info();
crash_info.buf[sizeof(crash_info.buf)-1] = '\0';
printf("%s\n", crash_info.buf);
fflush(stdout);
if(crash_info.pid > 0)
{
gdb_info(crash_info.pid);
kill(crash_info.pid, SIGKILL);
}
if(logfile)
{
const char *str;
char buf[512];
if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0)
snprintf(buf, sizeof(buf), "kdialog --title \"Very Fatal Error\" --textbox \"%s\" 800 600", logfile);
else if((str=getenv("GNOME_DESKTOP_SESSION_ID")) && str[0] != '\0')
snprintf(buf, sizeof(buf), "gxmessage -buttons \"Okay:0\" -geometry 800x600 -title \"Very Fatal Error\" -center -file \"%s\"", logfile);
else
snprintf(buf, sizeof(buf), "xmessage -buttons \"Okay:0\" -center -file \"%s\"", logfile);
system(buf);
}
exit(0);
}
int cc_install_handlers(int argc, char **argv, int num_signals, int *signals, const char *logfile, int (*user_info)(char*, char*))
{
struct sigaction sa;
stack_t altss;
int retval;
if(argc == 2 && strcmp(argv[1], crash_switch) == 0)
crash_handler(logfile);
cc_user_info = user_info;
if(argv[0][0] == '/')
snprintf(argv0, sizeof(argv0), "%s", argv[0]);
else
{
getcwd(argv0, sizeof(argv0));
retval = strlen(argv0);
snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]);
}
/* Set an alternate signal stack so SIGSEGVs caused by stack overflows
* still run */
altss.ss_sp = altstack;
altss.ss_flags = 0;
altss.ss_size = sizeof(altstack);
sigaltstack(&altss, NULL);
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = crash_catcher;
sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_SIGINFO | SA_ONSTACK;
sigemptyset(&sa.sa_mask);
retval = 0;
while(num_signals--)
{
if((*signals != SIGSEGV && *signals != SIGILL && *signals != SIGFPE &&
*signals != SIGBUS) || sigaction(*signals, &sa, NULL) == -1)
{
*signals = 0;
retval = -1;
}
++signals;
}
return retval;
}

View File

@ -1,399 +0,0 @@
/*
** hardware.cpp
** Somewhat OS-independant interface to the screen, mouse, keyboard, and stick
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <SDL.h>
#include <signal.h>
#include <time.h>
#include "version.h"
#include "hardware.h"
#include "i_video.h"
#include "i_system.h"
#include "c_console.h"
#include "c_cvars.h"
#include "c_dispatch.h"
#include "sdlvideo.h"
#include "v_text.h"
#include "doomstat.h"
#include "m_argv.h"
#include "sdlglvideo.h"
#include "r_renderer.h"
#include "swrenderer/r_swrenderer.h"
#include "atterm.h"
EXTERN_CVAR (Bool, ticker)
EXTERN_CVAR (Bool, fullscreen)
EXTERN_CVAR (Bool, swtruecolor)
EXTERN_CVAR (Float, vid_winscale)
IVideo *Video;
extern int NewWidth, NewHeight, NewBits, DisplayBits;
bool V_DoModeSetup (int width, int height, int bits);
void I_RestartRenderer();
int currentrenderer;
// [ZDoomGL]
CUSTOM_CVAR (Int, vid_renderer, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
// 0: Software renderer
// 1: OpenGL renderer
if (self != currentrenderer)
{
switch (self)
{
case 0:
Printf("Switching to software renderer...\n");
break;
case 1:
Printf("Switching to OpenGL renderer...\n");
break;
default:
Printf("Unknown renderer (%d). Falling back to software renderer...\n", (int) vid_renderer);
self = 0; // make sure to actually switch to the software renderer
break;
}
Printf("You must restart " GAMENAME " to switch the renderer\n");
}
}
void I_ShutdownGraphics ()
{
if (screen)
{
DFrameBuffer *s = screen;
screen = NULL;
delete s;
}
if (Video)
delete Video, Video = NULL;
SDL_QuitSubSystem (SDL_INIT_VIDEO);
}
void I_InitGraphics ()
{
#ifdef __APPLE__
SDL_SetHint(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, "0");
#endif // __APPLE__
if (SDL_InitSubSystem (SDL_INIT_VIDEO) < 0)
{
I_FatalError ("Could not initialize SDL video:\n%s\n", SDL_GetError());
return;
}
Printf("Using video driver %s\n", SDL_GetCurrentVideoDriver());
UCVarValue val;
val.Bool = !!Args->CheckParm ("-devparm");
ticker.SetGenericRepDefault (val, CVAR_Bool);
//currentrenderer = vid_renderer;
Video = new SDLGLVideo(0);
if (Video == NULL)
I_FatalError ("Failed to initialize display");
atterm (I_ShutdownGraphics);
Video->SetWindowedScale (vid_winscale);
}
static void I_DeleteRenderer()
{
if (Renderer != NULL) delete Renderer;
}
void I_CreateRenderer()
{
currentrenderer = vid_renderer;
if (Renderer == NULL)
{
if (currentrenderer==1) Renderer = gl_CreateInterface();
else Renderer = new FSoftwareRenderer;
atterm(I_DeleteRenderer);
}
}
/** Remaining code is common to Win32 and Linux **/
// VIDEO WRAPPERS ---------------------------------------------------------
DFrameBuffer *I_SetMode (int &width, int &height, DFrameBuffer *old)
{
bool fs = false;
switch (Video->GetDisplayType ())
{
case DISPLAY_WindowOnly:
fs = false;
break;
case DISPLAY_FullscreenOnly:
fs = true;
break;
case DISPLAY_Both:
fs = fullscreen;
break;
}
DFrameBuffer *res = Video->CreateFrameBuffer (width, height, swtruecolor, fs, old);
/* Right now, CreateFrameBuffer cannot return NULL
if (res == NULL)
{
I_FatalError ("Mode %dx%d is unavailable\n", width, height);
}
*/
return res;
}
bool I_CheckResolution (int width, int height, int bits)
{
int twidth, theight;
Video->StartModeIterator (bits, screen ? screen->IsFullscreen() : fullscreen);
while (Video->NextMode (&twidth, &theight, NULL))
{
if (width == twidth && height == theight)
return true;
}
return false;
}
void I_ClosestResolution (int *width, int *height, int bits)
{
#ifdef __MOBILE__ // We want to always use the resolution of the device!
return;
#endif
int twidth, theight;
int cwidth = 0, cheight = 0;
int iteration;
uint32_t closest = 4294967295u;
for (iteration = 0; iteration < 2; iteration++)
{
Video->StartModeIterator (bits, screen ? screen->IsFullscreen() : fullscreen);
while (Video->NextMode (&twidth, &theight, NULL))
{
if (twidth == *width && theight == *height)
return;
if (iteration == 0 && (twidth < *width || theight < *height))
continue;
uint32_t dist = (twidth - *width) * (twidth - *width)
+ (theight - *height) * (theight - *height);
if (dist < closest)
{
closest = dist;
cwidth = twidth;
cheight = theight;
}
}
if (closest != 4294967295u)
{
*width = cwidth;
*height = cheight;
return;
}
}
}
//==========================================================================
//
// SetFPSLimit
//
// Initializes an event timer to fire at a rate of <limit>/sec. The video
// update will wait for this timer to trigger before updating.
//
// Pass 0 as the limit for unlimited.
// Pass a negative value for the limit to use the value of vid_maxfps.
//
//==========================================================================
EXTERN_CVAR(Int, vid_maxfps);
EXTERN_CVAR(Bool, cl_capfps);
#if !defined(__APPLE__) && !defined(__OpenBSD__)
Semaphore FPSLimitSemaphore;
static void FPSLimitNotify(sigval val)
{
SEMAPHORE_SIGNAL(FPSLimitSemaphore)
}
void I_SetFPSLimit(int limit)
{
static sigevent FPSLimitEvent;
static timer_t FPSLimitTimer;
static bool FPSLimitTimerEnabled = false;
static bool EventSetup = false;
if(!EventSetup)
{
EventSetup = true;
FPSLimitEvent.sigev_notify = SIGEV_THREAD;
FPSLimitEvent.sigev_signo = 0;
FPSLimitEvent.sigev_value.sival_int = 0;
FPSLimitEvent.sigev_notify_function = FPSLimitNotify;
FPSLimitEvent.sigev_notify_attributes = NULL;
SEMAPHORE_INIT(FPSLimitSemaphore, 0, 0)
}
if (limit < 0)
{
limit = vid_maxfps;
}
// Kill any leftover timer.
if (FPSLimitTimerEnabled)
{
timer_delete(FPSLimitTimer);
FPSLimitTimerEnabled = false;
}
if (limit == 0)
{ // no limit
DPrintf(DMSG_NOTIFY, "FPS timer disabled\n");
}
else
{
FPSLimitTimerEnabled = true;
if(timer_create(CLOCK_REALTIME, &FPSLimitEvent, &FPSLimitTimer) == -1)
Printf(DMSG_WARNING, "Failed to create FPS limitter event\n");
itimerspec period = { {0, 0}, {0, 0} };
period.it_value.tv_nsec = period.it_interval.tv_nsec = 1000000000 / limit;
if(timer_settime(FPSLimitTimer, 0, &period, NULL) == -1)
Printf(DMSG_WARNING, "Failed to set FPS limitter timer\n");
DPrintf(DMSG_NOTIFY, "FPS timer set to %u ms\n", (unsigned int) period.it_interval.tv_nsec / 1000000);
}
}
#else
// So Apple doesn't support POSIX timers and I can't find a good substitute short of
// having Objective-C Cocoa events or something like that.
void I_SetFPSLimit(int limit)
{
}
#endif
CUSTOM_CVAR (Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{
if (vid_maxfps < TICRATE && vid_maxfps != 0)
{
vid_maxfps = TICRATE;
}
else if (vid_maxfps > 1000)
{
vid_maxfps = 1000;
}
else if (cl_capfps == 0)
{
I_SetFPSLimit(vid_maxfps);
}
}
extern int NewWidth, NewHeight, NewBits, DisplayBits;
CUSTOM_CVAR(Bool, swtruecolor, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
{
// Strictly speaking this doesn't require a mode switch, but it is the easiest
// way to force a CreateFramebuffer call without a lot of refactoring.
if (currentrenderer == 0)
{
NewWidth = screen->VideoWidth;
NewHeight = screen->VideoHeight;
NewBits = DisplayBits;
setmodeneeded = true;
}
}
CUSTOM_CVAR (Bool, fullscreen, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_NOINITCALL)
{
NewWidth = screen->VideoWidth;
NewHeight = screen->VideoHeight;
NewBits = DisplayBits;
setmodeneeded = true;
}
CUSTOM_CVAR (Float, vid_winscale, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
if (self < 1.f)
{
self = 1.f;
}
else if (Video)
{
Video->SetWindowedScale (self);
NewWidth = screen->VideoWidth;
NewHeight = screen->VideoHeight;
NewBits = DisplayBits;
setmodeneeded = true;
}
}
CCMD (vid_listmodes)
{
static const char *ratios[7] = { "", " - 16:9", " - 16:10", "", " - 5:4", "", " - 21:9" };
int width, height, bits;
bool letterbox;
if (Video == NULL)
{
return;
}
for (bits = 1; bits <= 32; bits++)
{
Video->StartModeIterator (bits, screen->IsFullscreen());
while (Video->NextMode (&width, &height, &letterbox))
{
bool thisMode = (width == DisplayWidth && height == DisplayHeight && bits == DisplayBits);
int ratio = CheckRatio (width, height);
Printf (thisMode ? PRINT_BOLD : PRINT_HIGH,
"%s%4d x%5d x%3d%s%s\n",
thisMode || !IsRatioWidescreen(ratio) ? "" : TEXTCOLOR_GOLD,
width, height, bits,
ratios[ratio],
thisMode || !letterbox ? "" : TEXTCOLOR_BROWN " LB"
);
}
}
}
CCMD (vid_currentmode)
{
Printf ("%dx%dx%d\n", DisplayWidth, DisplayHeight, DisplayBits);
}

View File

@ -1,590 +0,0 @@
/*
** i_input.cpp
**
**---------------------------------------------------------------------------
** Copyright 2005-2016 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <SDL.h>
#include <ctype.h>
#include "doomtype.h"
#include "c_dispatch.h"
#include "doomdef.h"
#include "doomstat.h"
#include "m_argv.h"
#include "i_input.h"
#include "v_video.h"
#include "d_main.h"
#include "d_event.h"
#include "d_gui.h"
#include "c_console.h"
#include "c_cvars.h"
#include "i_system.h"
#include "c_dispatch.h"
#include "dikeys.h"
#include "templates.h"
#include "s_sound.h"
#include "events.h"
#include "utf8.h"
static void I_CheckGUICapture ();
static void I_CheckNativeMouse ();
bool GUICapture;
static bool NativeMouse = true;
extern int paused;
CVAR (Bool, use_mouse, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, m_noprescale, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, m_filter, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, i_soundinbackground, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
EXTERN_CVAR (Bool, fullscreen)
extern int WaitingForKey, chatmodeon;
extern constate_e ConsoleState;
static const SDL_Keycode DIKToKeySym[256] =
{
0, SDLK_ESCAPE, SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5, SDLK_6,
SDLK_7, SDLK_8, SDLK_9, SDLK_0,SDLK_MINUS, SDLK_EQUALS, SDLK_BACKSPACE, SDLK_TAB,
SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_t, SDLK_y, SDLK_u, SDLK_i,
SDLK_o, SDLK_p, SDLK_LEFTBRACKET, SDLK_RIGHTBRACKET, SDLK_RETURN, SDLK_LCTRL, SDLK_a, SDLK_s,
SDLK_d, SDLK_f, SDLK_g, SDLK_h, SDLK_j, SDLK_k, SDLK_l, SDLK_SEMICOLON,
SDLK_QUOTE, SDLK_BACKQUOTE, SDLK_LSHIFT, SDLK_BACKSLASH, SDLK_z, SDLK_x, SDLK_c, SDLK_v,
SDLK_b, SDLK_n, SDLK_m, SDLK_COMMA, SDLK_PERIOD, SDLK_SLASH, SDLK_RSHIFT, SDLK_KP_MULTIPLY,
SDLK_LALT, SDLK_SPACE, SDLK_CAPSLOCK, SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5,
SDLK_F6, SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_NUMLOCKCLEAR, SDLK_SCROLLLOCK, SDLK_KP_7,
SDLK_KP_8, SDLK_KP_9, SDLK_KP_MINUS, SDLK_KP_4, SDLK_KP_5, SDLK_KP_6, SDLK_KP_PLUS, SDLK_KP_1,
SDLK_KP_2, SDLK_KP_3, SDLK_KP_0, SDLK_KP_PERIOD, 0, 0, 0, SDLK_F11,
SDLK_F12, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, SDLK_F13, SDLK_F14, SDLK_F15, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, SDLK_KP_EQUALS, 0, 0,
0, SDLK_AT, SDLK_COLON, 0, 0, 0, 0, 0,
0, 0, 0, 0, SDLK_KP_ENTER, SDLK_RCTRL, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, SDLK_KP_COMMA, 0, SDLK_KP_DIVIDE, 0, SDLK_SYSREQ,
SDLK_RALT, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, SDLK_PAUSE, 0, SDLK_HOME,
SDLK_UP, SDLK_PAGEUP, 0, SDLK_LEFT, 0, SDLK_RIGHT, 0, SDLK_END,
SDLK_DOWN, SDLK_PAGEDOWN, SDLK_INSERT, SDLK_DELETE, 0, 0, 0, 0,
0, 0, 0, SDLK_LGUI, SDLK_RGUI, SDLK_MENU, SDLK_POWER, SDLK_SLEEP,
0, 0, 0, 0, 0, SDLK_AC_SEARCH, SDLK_AC_BOOKMARKS, SDLK_AC_REFRESH,
SDLK_AC_STOP, SDLK_AC_FORWARD, SDLK_AC_BACK, SDLK_COMPUTER, SDLK_MAIL, SDLK_MEDIASELECT, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
static const SDL_Scancode DIKToKeyScan[256] =
{
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_ESCAPE, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, SDL_SCANCODE_5, SDL_SCANCODE_6,
SDL_SCANCODE_7, SDL_SCANCODE_8, SDL_SCANCODE_9, SDL_SCANCODE_0 ,SDL_SCANCODE_MINUS, SDL_SCANCODE_EQUALS, SDL_SCANCODE_BACKSPACE, SDL_SCANCODE_TAB,
SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_R, SDL_SCANCODE_T, SDL_SCANCODE_Y, SDL_SCANCODE_U, SDL_SCANCODE_I,
SDL_SCANCODE_O, SDL_SCANCODE_P, SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_RIGHTBRACKET, SDL_SCANCODE_RETURN, SDL_SCANCODE_LCTRL, SDL_SCANCODE_A, SDL_SCANCODE_S,
SDL_SCANCODE_D, SDL_SCANCODE_F, SDL_SCANCODE_G, SDL_SCANCODE_H, SDL_SCANCODE_J, SDL_SCANCODE_K, SDL_SCANCODE_L, SDL_SCANCODE_SEMICOLON,
SDL_SCANCODE_APOSTROPHE, SDL_SCANCODE_GRAVE, SDL_SCANCODE_LSHIFT, SDL_SCANCODE_BACKSLASH, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_C, SDL_SCANCODE_V,
SDL_SCANCODE_B, SDL_SCANCODE_N, SDL_SCANCODE_M, SDL_SCANCODE_COMMA, SDL_SCANCODE_PERIOD, SDL_SCANCODE_SLASH, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_KP_MULTIPLY,
SDL_SCANCODE_LALT, SDL_SCANCODE_SPACE, SDL_SCANCODE_CAPSLOCK, SDL_SCANCODE_F1, SDL_SCANCODE_F2, SDL_SCANCODE_F3, SDL_SCANCODE_F4, SDL_SCANCODE_F5,
SDL_SCANCODE_F6, SDL_SCANCODE_F7, SDL_SCANCODE_F8, SDL_SCANCODE_F9, SDL_SCANCODE_F10, SDL_SCANCODE_NUMLOCKCLEAR, SDL_SCANCODE_SCROLLLOCK, SDL_SCANCODE_KP_7,
SDL_SCANCODE_KP_8, SDL_SCANCODE_KP_9, SDL_SCANCODE_KP_MINUS, SDL_SCANCODE_KP_4, SDL_SCANCODE_KP_5, SDL_SCANCODE_KP_6, SDL_SCANCODE_KP_PLUS, SDL_SCANCODE_KP_1,
SDL_SCANCODE_KP_2, SDL_SCANCODE_KP_3, SDL_SCANCODE_KP_0, SDL_SCANCODE_KP_PERIOD, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F11,
SDL_SCANCODE_F12, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F13, SDL_SCANCODE_F14, SDL_SCANCODE_F15, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_EQUALS, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_ENTER, SDL_SCANCODE_RCTRL, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_COMMA, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_DIVIDE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_SYSREQ,
SDL_SCANCODE_RALT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_PAUSE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_HOME,
SDL_SCANCODE_UP, SDL_SCANCODE_PAGEUP, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_END,
SDL_SCANCODE_DOWN, SDL_SCANCODE_PAGEDOWN, SDL_SCANCODE_INSERT, SDL_SCANCODE_DELETE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LGUI, SDL_SCANCODE_RGUI, SDL_SCANCODE_MENU, SDL_SCANCODE_POWER, SDL_SCANCODE_SLEEP,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_AC_SEARCH, SDL_SCANCODE_AC_BOOKMARKS, SDL_SCANCODE_AC_REFRESH,
SDL_SCANCODE_AC_STOP, SDL_SCANCODE_AC_FORWARD, SDL_SCANCODE_AC_BACK, SDL_SCANCODE_COMPUTER, SDL_SCANCODE_MAIL, SDL_SCANCODE_MEDIASELECT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN,
SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN
};
static TMap<SDL_Keycode, uint8_t> InitKeySymMap ()
{
TMap<SDL_Keycode, uint8_t> KeySymToDIK;
for (int i = 0; i < 256; ++i)
{
KeySymToDIK[DIKToKeySym[i]] = i;
}
KeySymToDIK[0] = 0;
KeySymToDIK[SDLK_RSHIFT] = DIK_LSHIFT;
KeySymToDIK[SDLK_RCTRL] = DIK_LCONTROL;
KeySymToDIK[SDLK_RALT] = DIK_LMENU;
// Depending on your Linux flavor, you may get SDLK_PRINT or SDLK_SYSREQ
KeySymToDIK[SDLK_PRINTSCREEN] = DIK_SYSRQ;
return KeySymToDIK;
}
static const TMap<SDL_Keycode, uint8_t> KeySymToDIK(InitKeySymMap());
static TMap<SDL_Scancode, uint8_t> InitKeyScanMap ()
{
TMap<SDL_Scancode, uint8_t> KeyScanToDIK;
for (int i = 0; i < 256; ++i)
{
KeyScanToDIK[DIKToKeyScan[i]] = i;
}
return KeyScanToDIK;
}
static const TMap<SDL_Scancode, uint8_t> KeyScanToDIK(InitKeyScanMap());
static void I_CheckGUICapture ()
{
bool wantCapt;
if (menuactive == MENU_Off)
{
wantCapt = ConsoleState == c_down || ConsoleState == c_falling || chatmodeon;
}
else
{
wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause);
}
// [ZZ] check active event handlers that want the UI processing
if (!wantCapt && E_CheckUiProcessors())
wantCapt = true;
if (wantCapt != GUICapture)
{
GUICapture = wantCapt;
ResetButtonStates();
}
}
void I_SetMouseCapture()
{
// Clear out any mouse movement.
SDL_GetRelativeMouseState (NULL, NULL);
SDL_SetRelativeMouseMode (SDL_TRUE);
#ifdef __MOBILE__
// Need to clear this again because setting mode above adds relative values
SDL_GetRelativeMouseState (NULL, NULL);
#endif
}
void I_ReleaseMouseCapture()
{
SDL_SetRelativeMouseMode (SDL_FALSE);
}
static void PostMouseMove (int x, int y)
{
static int lastx = 0, lasty = 0;
event_t ev = { 0,0,0,0,0,0,0 };
if (m_filter)
{
ev.x = (x + lastx) / 2;
ev.y = (y + lasty) / 2;
}
else
{
ev.x = x;
ev.y = y;
}
lastx = x;
lasty = y;
if (ev.x | ev.y)
{
ev.type = EV_Mouse;
D_PostEvent (&ev);
}
}
static void MouseRead ()
{
int x, y;
if (NativeMouse)
{
return;
}
SDL_GetRelativeMouseState (&x, &y);
if (!m_noprescale)
{
x *= 3;
y *= 2;
}
if (x | y)
{
PostMouseMove (x, -y);
}
}
CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE)
{
if (self < 0) self = 0;
else if (self > 2) self = 2;
}
static bool inGame()
{
switch (mouse_capturemode)
{
default:
case 0:
return gamestate == GS_LEVEL;
case 1:
return gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_FINALE;
case 2:
return true;
}
}
static void I_CheckNativeMouse ()
{
bool focus = SDL_GetKeyboardFocus() != NULL;
bool fs = screen->IsFullscreen();
bool wantNative = !focus || (!use_mouse || GUICapture || paused || demoplayback || !inGame());
if (wantNative != NativeMouse)
{
NativeMouse = wantNative;
SDL_ShowCursor (wantNative);
if (wantNative)
I_ReleaseMouseCapture ();
else
I_SetMouseCapture ();
}
}
void MessagePump (const SDL_Event &sev)
{
static int lastx = 0, lasty = 0;
int x, y;
event_t event = { 0,0,0,0,0,0,0 };
switch (sev.type)
{
case SDL_QUIT:
exit (0);
case SDL_WINDOWEVENT:
switch (sev.window.event)
{
extern bool AppActive;
case SDL_WINDOWEVENT_FOCUS_GAINED:
S_SetSoundPaused(1);
AppActive = true;
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
S_SetSoundPaused(i_soundinbackground);
AppActive = false;
break;
}
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
if (!GUICapture)
{
event.type = sev.type == SDL_MOUSEBUTTONDOWN ? EV_KeyDown : EV_KeyUp;
switch (sev.button.button)
{
case SDL_BUTTON_LEFT: event.data1 = KEY_MOUSE1; break;
case SDL_BUTTON_MIDDLE: event.data1 = KEY_MOUSE3; break;
case SDL_BUTTON_RIGHT: event.data1 = KEY_MOUSE2; break;
case SDL_BUTTON_X1: event.data1 = KEY_MOUSE4; break;
case SDL_BUTTON_X2: event.data1 = KEY_MOUSE5; break;
case 6: event.data1 = KEY_MOUSE6; break;
case 7: event.data1 = KEY_MOUSE7; break;
case 8: event.data1 = KEY_MOUSE8; break;
default: printf("SDL mouse button %s %d\n",
sev.type == SDL_MOUSEBUTTONDOWN ? "down" : "up", sev.button.button); break;
}
if (event.data1 != 0)
{
D_PostEvent(&event);
}
}
else if ((sev.button.button >= SDL_BUTTON_LEFT && sev.button.button <= SDL_BUTTON_X2))
{
int x, y;
SDL_GetMouseState(&x, &y);
event.type = EV_GUI_Event;
event.data1 = x;
event.data2 = y;
screen->ScaleCoordsFromWindow(event.data1, event.data2);
if (sev.type == SDL_MOUSEBUTTONDOWN)
{
switch(sev.button.button)
{
case SDL_BUTTON_LEFT: event.subtype = EV_GUI_LButtonDown; break;
case SDL_BUTTON_MIDDLE: event.subtype = EV_GUI_MButtonDown; break;
case SDL_BUTTON_RIGHT: event.subtype = EV_GUI_RButtonDown; break;
case SDL_BUTTON_X1: event.subtype = EV_GUI_BackButtonDown; break;
case SDL_BUTTON_X2: event.subtype = EV_GUI_FwdButtonDown; break;
default: assert(false); event.subtype = EV_GUI_None; break;
}
}
else
{
switch(sev.button.button)
{
case SDL_BUTTON_LEFT: event.subtype = EV_GUI_LButtonUp; break;
case SDL_BUTTON_MIDDLE: event.subtype = EV_GUI_MButtonUp; break;
case SDL_BUTTON_RIGHT: event.subtype = EV_GUI_RButtonUp; break;
case SDL_BUTTON_X1: event.subtype = EV_GUI_BackButtonUp; break;
case SDL_BUTTON_X2: event.subtype = EV_GUI_FwdButtonUp; break;
default: assert(false); event.subtype = EV_GUI_None; break;
}
}
SDL_Keymod kmod = SDL_GetModState();
event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
((kmod & KMOD_CTRL) ? GKM_CTRL : 0) |
((kmod & KMOD_ALT) ? GKM_ALT : 0);
D_PostEvent(&event);
}
break;
case SDL_MOUSEMOTION:
if (GUICapture)
{
event.data1 = sev.motion.x;
event.data2 = sev.motion.y;
screen->ScaleCoordsFromWindow(event.data1, event.data2);
event.type = EV_GUI_Event;
event.subtype = EV_GUI_MouseMove;
SDL_Keymod kmod = SDL_GetModState();
event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
((kmod & KMOD_CTRL) ? GKM_CTRL : 0) |
((kmod & KMOD_ALT) ? GKM_ALT : 0);
D_PostEvent(&event);
}
break;
case SDL_MOUSEWHEEL:
if (GUICapture)
{
event.type = EV_GUI_Event;
if (sev.wheel.y == 0)
event.subtype = sev.wheel.x > 0 ? EV_GUI_WheelRight : EV_GUI_WheelLeft;
else
event.subtype = sev.wheel.y > 0 ? EV_GUI_WheelUp : EV_GUI_WheelDown;
SDL_Keymod kmod = SDL_GetModState();
event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
((kmod & KMOD_CTRL) ? GKM_CTRL : 0) |
((kmod & KMOD_ALT) ? GKM_ALT : 0);
D_PostEvent (&event);
}
else
{
event.type = EV_KeyDown;
if (sev.wheel.y != 0)
event.data1 = sev.wheel.y > 0 ? KEY_MWHEELUP : KEY_MWHEELDOWN;
else
event.data1 = sev.wheel.x > 0 ? KEY_MWHEELRIGHT : KEY_MWHEELLEFT;
D_PostEvent (&event);
event.type = EV_KeyUp;
D_PostEvent (&event);
}
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
if (!GUICapture)
{
if (sev.key.repeat)
{
break;
}
event.type = sev.type == SDL_KEYDOWN ? EV_KeyDown : EV_KeyUp;
// Try to look up our key mapped key for conversion to DirectInput.
// If that fails, then we'll do a lookup against the scan code,
// which may not return the right key, but at least the key should
// work in the game.
if (const uint8_t *dik = KeySymToDIK.CheckKey (sev.key.keysym.sym))
event.data1 = *dik;
else if (const uint8_t *dik = KeyScanToDIK.CheckKey (sev.key.keysym.scancode))
event.data1 = *dik;
if (event.data1)
{
if (sev.key.keysym.sym < 256)
{
event.data2 = sev.key.keysym.sym;
}
D_PostEvent (&event);
}
}
else
{
event.type = EV_GUI_Event;
event.subtype = sev.type == SDL_KEYDOWN ? EV_GUI_KeyDown : EV_GUI_KeyUp;
SDL_Keymod kmod = SDL_GetModState();
event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
((kmod & KMOD_CTRL) ? GKM_CTRL : 0) |
((kmod & KMOD_ALT) ? GKM_ALT : 0);
if (event.subtype == EV_GUI_KeyDown && sev.key.repeat)
{
event.subtype = EV_GUI_KeyRepeat;
}
switch (sev.key.keysym.sym)
{
case SDLK_KP_ENTER: event.data1 = GK_RETURN; break;
case SDLK_PAGEUP: event.data1 = GK_PGUP; break;
case SDLK_PAGEDOWN: event.data1 = GK_PGDN; break;
case SDLK_END: event.data1 = GK_END; break;
case SDLK_HOME: event.data1 = GK_HOME; break;
case SDLK_LEFT: event.data1 = GK_LEFT; break;
case SDLK_RIGHT: event.data1 = GK_RIGHT; break;
case SDLK_UP: event.data1 = GK_UP; break;
case SDLK_DOWN: event.data1 = GK_DOWN; break;
case SDLK_DELETE: event.data1 = GK_DEL; break;
case SDLK_ESCAPE: event.data1 = GK_ESCAPE; break;
case SDLK_F1: event.data1 = GK_F1; break;
case SDLK_F2: event.data1 = GK_F2; break;
case SDLK_F3: event.data1 = GK_F3; break;
case SDLK_F4: event.data1 = GK_F4; break;
case SDLK_F5: event.data1 = GK_F5; break;
case SDLK_F6: event.data1 = GK_F6; break;
case SDLK_F7: event.data1 = GK_F7; break;
case SDLK_F8: event.data1 = GK_F8; break;
case SDLK_F9: event.data1 = GK_F9; break;
case SDLK_F10: event.data1 = GK_F10; break;
case SDLK_F11: event.data1 = GK_F11; break;
case SDLK_F12: event.data1 = GK_F12; break;
case SDLK_SYSREQ: event.data1 = GK_SYSRQ; break;
default:
if (sev.key.keysym.sym < 256)
{
event.data1 = sev.key.keysym.sym;
}
break;
}
if (event.data1 < 128)
{
event.data1 = toupper(event.data1);
D_PostEvent (&event);
}
}
break;
case SDL_TEXTINPUT:
if (GUICapture)
{
int size;
int unichar = utf8_decode((const uint8_t*)sev.text.text, &size);
if (size != 4)
{
event.type = EV_GUI_Event;
event.subtype = EV_GUI_Char;
event.data1 = (int16_t)unichar;
event.data2 = !!(SDL_GetModState() & KMOD_ALT);
D_PostEvent (&event);
}
}
break;
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
if (!GUICapture)
{
event.type = sev.type == SDL_JOYBUTTONDOWN ? EV_KeyDown : EV_KeyUp;
event.data1 = KEY_FIRSTJOYBUTTON + sev.jbutton.button;
if(event.data1 != 0)
D_PostEvent(&event);
}
break;
}
}
void I_GetEvent ()
{
SDL_Event sev;
while (SDL_PollEvent (&sev))
{
MessagePump (sev);
}
if (use_mouse)
{
MouseRead ();
}
}
void I_StartTic ()
{
I_CheckGUICapture ();
I_CheckNativeMouse ();
I_GetEvent ();
}
void I_ProcessJoysticks ();
void I_StartFrame ()
{
I_ProcessJoysticks();
}

View File

@ -1,349 +0,0 @@
/*
** i_joystick.cpp
**
**---------------------------------------------------------------------------
** Copyright 2005-2016 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <SDL.h>
#include "doomdef.h"
#include "version.h"
#include "templates.h"
#include "m_joy.h"
// Very small deadzone so that floating point magic doesn't happen
#define MIN_DEADZONE 0.000001f
CUSTOM_CVAR(Bool, joy_background, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_NOINITCALL)
{
Printf("This won't take effect until " GAMENAME " is restarted.\n");
}
class SDLInputJoystick: public IJoystickConfig
{
public:
SDLInputJoystick(int DeviceIndex) : DeviceIndex(DeviceIndex), Multiplier(1.0f)
{
Device = SDL_JoystickOpen(DeviceIndex);
if(Device != NULL)
{
NumAxes = SDL_JoystickNumAxes(Device);
NumHats = SDL_JoystickNumHats(Device);
SetDefaultConfig();
}
}
~SDLInputJoystick()
{
if(Device != NULL)
M_SaveJoystickConfig(this);
SDL_JoystickClose(Device);
}
bool IsValid() const
{
return Device != NULL;
}
FString GetName()
{
return SDL_JoystickName(Device);
}
float GetSensitivity()
{
return Multiplier;
}
void SetSensitivity(float scale)
{
Multiplier = scale;
}
int GetNumAxes()
{
return NumAxes + NumHats*2;
}
float GetAxisDeadZone(int axis)
{
return Axes[axis].DeadZone;
}
EJoyAxis GetAxisMap(int axis)
{
return Axes[axis].GameAxis;
}
const char *GetAxisName(int axis)
{
return Axes[axis].Name.GetChars();
}
float GetAxisScale(int axis)
{
return Axes[axis].Multiplier;
}
void SetAxisDeadZone(int axis, float zone)
{
Axes[axis].DeadZone = clamp(zone, MIN_DEADZONE, 1.f);
}
void SetAxisMap(int axis, EJoyAxis gameaxis)
{
Axes[axis].GameAxis = gameaxis;
}
void SetAxisScale(int axis, float scale)
{
Axes[axis].Multiplier = scale;
}
// Used by the saver to not save properties that are at their defaults.
bool IsSensitivityDefault()
{
return Multiplier == 1.0f;
}
bool IsAxisDeadZoneDefault(int axis)
{
return Axes[axis].DeadZone <= MIN_DEADZONE;
}
bool IsAxisMapDefault(int axis)
{
if(axis >= 5)
return Axes[axis].GameAxis == JOYAXIS_None;
return Axes[axis].GameAxis == DefaultAxes[axis];
}
bool IsAxisScaleDefault(int axis)
{
return Axes[axis].Multiplier == 1.0f;
}
void SetDefaultConfig()
{
for(int i = 0;i < GetNumAxes();i++)
{
AxisInfo info;
if(i < NumAxes)
info.Name.Format("Axis %d", i+1);
else
info.Name.Format("Hat %d (%c)", (i-NumAxes)/2 + 1, (i-NumAxes)%2 == 0 ? 'x' : 'y');
info.DeadZone = MIN_DEADZONE;
info.Multiplier = 1.0f;
info.Value = 0.0;
info.ButtonValue = 0;
if(i >= 5)
info.GameAxis = JOYAXIS_None;
else
info.GameAxis = DefaultAxes[i];
Axes.Push(info);
}
}
FString GetIdentifier()
{
char id[16];
mysnprintf(id, countof(id), "JS:%d", DeviceIndex);
return id;
}
void AddAxes(float axes[NUM_JOYAXIS])
{
// Add to game axes.
for (int i = 0; i < GetNumAxes(); ++i)
{
if(Axes[i].GameAxis != JOYAXIS_None)
axes[Axes[i].GameAxis] -= float(Axes[i].Value * Multiplier * Axes[i].Multiplier);
}
}
void ProcessInput()
{
uint8_t buttonstate;
for (int i = 0; i < NumAxes; ++i)
{
buttonstate = 0;
Axes[i].Value = SDL_JoystickGetAxis(Device, i)/32767.0;
Axes[i].Value = Joy_RemoveDeadZone(Axes[i].Value, Axes[i].DeadZone, &buttonstate);
// Map button to axis
// X and Y are handled differently so if we have 2 or more axes then we'll use that code instead.
if (NumAxes == 1 || (i >= 2 && i < NUM_JOYAXISBUTTONS))
{
Joy_GenerateButtonEvents(Axes[i].ButtonValue, buttonstate, 2, KEY_JOYAXIS1PLUS + i*2);
Axes[i].ButtonValue = buttonstate;
}
}
if(NumAxes > 1)
{
buttonstate = Joy_XYAxesToButtons(Axes[0].Value, Axes[1].Value);
Joy_GenerateButtonEvents(Axes[0].ButtonValue, buttonstate, 4, KEY_JOYAXIS1PLUS);
Axes[0].ButtonValue = buttonstate;
}
// Map POV hats to buttons and axes. Why axes? Well apparently I have
// a gamepad where the left control stick is a POV hat (instead of the
// d-pad like you would expect, no that's pressure sensitive). Also
// KDE's joystick dialog maps them to axes as well.
for (int i = 0; i < NumHats; ++i)
{
AxisInfo &x = Axes[NumAxes + i*2];
AxisInfo &y = Axes[NumAxes + i*2 + 1];
buttonstate = SDL_JoystickGetHat(Device, i);
// If we're going to assume that we can pass SDL's value into
// Joy_GenerateButtonEvents then we might as well assume the format here.
if(buttonstate & 0x1) // Up
y.Value = -1.0;
else if(buttonstate & 0x4) // Down
y.Value = 1.0;
else
y.Value = 0.0;
if(buttonstate & 0x2) // Left
x.Value = 1.0;
else if(buttonstate & 0x8) // Right
x.Value = -1.0;
else
x.Value = 0.0;
if(i < 4)
{
Joy_GenerateButtonEvents(x.ButtonValue, buttonstate, 4, KEY_JOYPOV1_UP + i*4);
x.ButtonValue = buttonstate;
}
}
}
protected:
struct AxisInfo
{
FString Name;
float DeadZone;
float Multiplier;
EJoyAxis GameAxis;
double Value;
uint8_t ButtonValue;
};
static const EJoyAxis DefaultAxes[5];
int DeviceIndex;
SDL_Joystick *Device;
float Multiplier;
TArray<AxisInfo> Axes;
int NumAxes;
int NumHats;
};
const EJoyAxis SDLInputJoystick::DefaultAxes[5] = {JOYAXIS_Side, JOYAXIS_Forward, JOYAXIS_Pitch, JOYAXIS_Yaw, JOYAXIS_Up};
class SDLInputJoystickManager
{
public:
SDLInputJoystickManager()
{
for(int i = 0;i < SDL_NumJoysticks();i++)
{
SDLInputJoystick *device = new SDLInputJoystick(i);
if(device->IsValid())
Joysticks.Push(device);
else
delete device;
}
}
~SDLInputJoystickManager()
{
for(unsigned int i = 0;i < Joysticks.Size();i++)
delete Joysticks[i];
}
void AddAxes(float axes[NUM_JOYAXIS])
{
for(unsigned int i = 0;i < Joysticks.Size();i++)
Joysticks[i]->AddAxes(axes);
}
void GetDevices(TArray<IJoystickConfig *> &sticks)
{
for(unsigned int i = 0;i < Joysticks.Size();i++)
{
M_LoadJoystickConfig(Joysticks[i]);
sticks.Push(Joysticks[i]);
}
}
void ProcessInput() const
{
for(unsigned int i = 0;i < Joysticks.Size();++i)
Joysticks[i]->ProcessInput();
}
protected:
TArray<SDLInputJoystick *> Joysticks;
};
static SDLInputJoystickManager *JoystickManager;
void I_StartupJoysticks()
{
if (joy_background)
SDL_SetHint("SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS", "1");
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) >= 0)
JoystickManager = new SDLInputJoystickManager();
}
void I_ShutdownJoysticks()
{
if(JoystickManager)
{
delete JoystickManager;
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
}
}
void I_GetJoysticks(TArray<IJoystickConfig *> &sticks)
{
sticks.Clear();
JoystickManager->GetDevices(sticks);
}
void I_GetAxes(float axes[NUM_JOYAXIS])
{
for (int i = 0; i < NUM_JOYAXIS; ++i)
{
axes[i] = 0;
}
if (use_joystick)
{
JoystickManager->AddAxes(axes);
}
}
void I_ProcessJoysticks()
{
if (use_joystick)
JoystickManager->ProcessInput();
}
IJoystickConfig *I_UpdateDeviceList()
{
return NULL;
}

View File

@ -1,294 +0,0 @@
/*
** i_main.cpp
** System-specific startup code. Eventually calls D_DoomMain.
**
**---------------------------------------------------------------------------
** Copyright 1998-2007 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
// HEADER FILES ------------------------------------------------------------
#include <SDL.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <new>
#include <sys/param.h>
#include <locale.h>
#include "doomerrors.h"
#include "m_argv.h"
#include "d_main.h"
#include "i_system.h"
#include "i_video.h"
#include "c_console.h"
#include "errors.h"
#include "version.h"
#include "w_wad.h"
#include "g_level.h"
#include "g_levellocals.h"
#include "r_state.h"
#include "cmdlib.h"
#include "r_utility.h"
#include "doomstat.h"
#include "vm.h"
#include "atterm.h"
// MACROS ------------------------------------------------------------------
// The maximum number of functions that can be registered with atterm.
#define MAX_TERMS 64
// TYPES -------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
extern "C" int cc_install_handlers(int, char**, int, int*, const char*, int(*)(char*, char*));
#ifdef __APPLE__
void Mac_I_FatalError(const char* errortext);
#endif
#ifdef __linux__
void Linux_I_FatalError(const char* errortext);
#endif
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern volatile int game_running;
// PUBLIC DATA DEFINITIONS -------------------------------------------------
// The command line arguments.
FArgs *Args;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
// CODE --------------------------------------------------------------------
void exit_handler(int dummy) {
game_running = 0;
}
static void NewFailure ()
{
I_FatalError ("Failed to allocate memory from system heap");
}
static int DoomSpecificInfo (char *buffer, char *end)
{
const char *arg;
int size = end-buffer-2;
int i, p;
p = 0;
p += snprintf (buffer+p, size-p, GAMENAME" version %s (%s)\n", GetVersionString(), GetGitHash());
#ifdef __VERSION__
p += snprintf (buffer+p, size-p, "Compiler version: %s\n", __VERSION__);
#endif
p += snprintf (buffer+p, size-p, "\nCommand line:");
for (i = 0; i < Args->NumArgs(); ++i)
{
p += snprintf (buffer+p, size-p, " %s", Args->GetArg(i));
}
p += snprintf (buffer+p, size-p, "\n");
for (i = 0; (arg = Wads.GetWadName (i)) != NULL; ++i)
{
p += snprintf (buffer+p, size-p, "\nWad %d: %s", i, arg);
}
if (gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL)
{
p += snprintf (buffer+p, size-p, "\n\nNot in a level.");
}
else
{
p += snprintf (buffer+p, size-p, "\n\nCurrent map: %s", level.MapName.GetChars());
if (!viewactive)
{
p += snprintf (buffer+p, size-p, "\n\nView not active.");
}
else
{
p += snprintf (buffer+p, size-p, "\n\nviewx = %f", r_viewpoint.Pos.X);
p += snprintf (buffer+p, size-p, "\nviewy = %f", r_viewpoint.Pos.Y);
p += snprintf (buffer+p, size-p, "\nviewz = %f", r_viewpoint.Pos.Z);
p += snprintf (buffer+p, size-p, "\nviewangle = %f", r_viewpoint.Angles.Yaw.Degrees);
}
}
buffer[p++] = '\n';
buffer[p++] = '\0';
return p;
}
void I_StartupJoysticks();
void I_ShutdownJoysticks();
#ifdef __ANDROID__
#include <android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO,"JNITouchControlsUtils", __VA_ARGS__))
int main_android (int argc, char **argv)
{
#else
int main (int argc, char **argv)
{
#endif
#if !defined (__APPLE__) && !defined (__ANDROID__)
{
int s[4] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS };
cc_install_handlers(argc, argv, 4, s, GAMENAMELOWERCASE "-crash.log", DoomSpecificInfo);
}
#endif // !__APPLE__
printf(GAMENAME" %s - %s - SDL version\nCompiled on %s\n",
GetVersionString(), GetGitTime(), __DATE__);
seteuid (getuid ());
std::set_new_handler (NewFailure);
// Set LC_NUMERIC environment variable in case some library decides to
// clear the setlocale call at least this will be correct.
// Note that the LANG environment variable is overridden by LC_*
setenv ("LC_NUMERIC", "C", 1);
setlocale (LC_ALL, "C");
if (SDL_Init (0) < 0)
{
fprintf (stderr, "Could not initialize SDL:\n%s\n", SDL_GetError());
return -1;
}
atterm (SDL_Quit);
printf("\n");
try
{
Args = new FArgs(argc, argv);
/*
killough 1/98:
This fixes some problems with exit handling
during abnormal situations.
The old code called I_Quit() to end program,
while now I_Quit() is installed as an exit
handler and exit() is called to exit, either
normally or abnormally. Seg faults are caught
and the error handler is used, to prevent
being left in graphics mode or having very
loud SFX noise because the sound card is
left in an unstable state.
*/
atexit (call_terms);
atterm (I_Quit);
/*
Register signal handlers to interrupt D_DoomMain and D_DoomLoop, allowing
call_terms() to be invoked at the conclusion of the main thread/quit menu
rather than at exit. The atexit() call can remain to handle edge cases
where a signal cannot be intercepted, such as Alt+F4 or closing the window
via the GUI.
Fixes segmentation fault on exit when using the KMSDRM SDL video driver.
*/
signal(SIGINT, exit_handler);
signal(SIGTERM, exit_handler);
// Should we even be doing anything with progdir on Unix systems?
char program[PATH_MAX];
if (realpath (argv[0], program) == NULL)
strcpy (program, argv[0]);
char *slash = strrchr (program, '/');
if (slash != NULL)
{
*(slash + 1) = '\0';
progdir = program;
}
else
{
progdir = "./";
}
I_StartupJoysticks();
C_InitConsole (80*8, 25*8, false);
D_DoomMain ();
}
catch (std::exception &error)
{
I_ShutdownJoysticks();
const char *const message = error.what();
if (strcmp(message, "NoRunExit"))
{
if (CVMAbortException::stacktrace.IsNotEmpty())
{
Printf("%s", CVMAbortException::stacktrace.GetChars());
}
#ifdef __ANDROID__
LOGI("FATAL ERROR: %s", message);
#endif
if (batchrun)
{
Printf("%s\n", message);
}
else
{
#ifdef __APPLE__
Mac_I_FatalError(message);
#endif // __APPLE__
#ifdef __linux__
Linux_I_FatalError(message);
#endif // __linux__
}
}
exit (-1);
}
catch (...)
{
call_terms ();
throw;
}
call_terms();
return 0;
}

View File

@ -1,19 +0,0 @@
#include <CoreFoundation/CoreFoundation.h>
#include "SDL.h"
void Mac_I_FatalError(const char* errortext)
{
// Close window or exit fullscreen and release mouse capture
SDL_Quit();
const CFStringRef errorString = CFStringCreateWithCStringNoCopy( kCFAllocatorDefault,
errortext, kCFStringEncodingASCII, kCFAllocatorNull );
if ( NULL != errorString )
{
CFOptionFlags dummy;
CFUserNotificationDisplayAlert( 0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL,
CFSTR( "Fatal Error" ), errorString, CFSTR( "Exit" ), NULL, NULL, &dummy );
CFRelease( errorString );
}
}

View File

@ -1,591 +0,0 @@
/*
** sdlglvideo.cpp
**
**---------------------------------------------------------------------------
** Copyright 2005-2016 Christoph Oelckers et.al.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
// HEADER FILES ------------------------------------------------------------
#include "doomtype.h"
#include "templates.h"
#include "i_system.h"
#include "i_video.h"
#include "m_argv.h"
#include "v_video.h"
#include "v_pfx.h"
#include "stats.h"
#include "version.h"
#include "c_console.h"
#include "videomodes.h"
#include "sdlglvideo.h"
#include "sdlvideo.h"
#include "gl/system/gl_system.h"
#include "r_defs.h"
#include "gl/gl_functions.h"
//#include "gl/gl_intern.h"
#include "gl/renderer/gl_renderer.h"
#include "gl/system/gl_framebuffer.h"
#include "gl/shaders/gl_shader.h"
#include "gl/utility/gl_templates.h"
#include "gl/textures/gl_material.h"
#include "gl/system/gl_cvars.h"
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern IVideo *Video;
// extern int vid_renderer;
EXTERN_CVAR (Float, Gamma)
EXTERN_CVAR (Int, vid_adapter)
EXTERN_CVAR (Int, vid_displaybits)
EXTERN_CVAR (Int, vid_renderer)
EXTERN_CVAR (Int, vid_maxfps)
EXTERN_CVAR (Bool, cl_capfps)
DFrameBuffer *CreateGLSWFrameBuffer(int width, int height, bool bgra, bool fullscreen);
// PUBLIC DATA DEFINITIONS -------------------------------------------------
CUSTOM_CVAR(Bool, gl_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
Printf("This won't take effect until " GAMENAME " is restarted.\n");
}
#ifdef __arm__
CUSTOM_CVAR(Bool, vid_glswfb, false, CVAR_NOINITCALL)
{
Printf("This won't take effect until " GAMENAME " is restarted.\n");
}
CUSTOM_CVAR(Bool, gl_es, false, CVAR_NOINITCALL)
{
Printf("This won't take effect until " GAMENAME " is restarted.\n");
}
#else
CUSTOM_CVAR(Bool, vid_glswfb, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
Printf("This won't take effect until " GAMENAME " is restarted.\n");
}
CUSTOM_CVAR(Bool, gl_es, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
Printf("This won't take effect until " GAMENAME " is restarted.\n");
}
#endif
// PRIVATE DATA DEFINITIONS ------------------------------------------------
// CODE --------------------------------------------------------------------
SDLGLVideo::SDLGLVideo (int parm)
{
IteratorBits = 0;
if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
fprintf( stderr, "Video initialization failed: %s\n",
SDL_GetError( ) );
}
}
SDLGLVideo::~SDLGLVideo ()
{
if (GLRenderer != NULL) GLRenderer->FlushTextures();
}
void SDLGLVideo::StartModeIterator (int bits, bool fs)
{
IteratorMode = 0;
IteratorBits = bits;
}
bool SDLGLVideo::NextMode (int *width, int *height, bool *letterbox)
{
if (IteratorBits != 8)
return false;
if ((unsigned)IteratorMode < sizeof(VideoModes)/sizeof(VideoModes[0]))
{
*width = VideoModes[IteratorMode].width;
*height = VideoModes[IteratorMode].height;
++IteratorMode;
return true;
}
return false;
}
DFrameBuffer *SDLGLVideo::CreateFrameBuffer (int width, int height, bool bgra, bool fullscreen, DFrameBuffer *old)
{
static int retry = 0;
static int owidth, oheight;
PalEntry flashColor;
// int flashAmount;
if (old != NULL)
{ // Reuse the old framebuffer if its attributes are the same
SDLBaseFB *fb = static_cast<SDLBaseFB *> (old);
if (fb->Width == width &&
fb->Height == height)
{
bool fsnow = (SDL_GetWindowFlags (fb->GetSDLWindow()) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
if (fsnow != fullscreen)
{
SDL_SetWindowFullscreen (fb->GetSDLWindow(), fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
}
return old;
}
// old->GetFlash (flashColor, flashAmount);
delete old;
}
else
{
flashColor = 0;
// flashAmount = 0;
}
SDLBaseFB *fb;
if (vid_renderer == 1)
{
#ifdef USE_GL_HW_BUFFERS
const char *hwBuffers = Args->CheckValue("-hwbuffers");
int buffers = 1;
if (hwBuffers)
{
buffers = atoi(hwBuffers);
}
Printf("HW buffers = %d\n", buffers);
fb = new OpenGLFrameBuffer(0, width, height, 32, 60, fullscreen, buffers);
#else
fb = new OpenGLFrameBuffer(0, width, height, 32, 60, fullscreen);
#endif
}
else if (vid_glswfb == 0)
{
fb = new SDLFB(width, height, bgra, fullscreen, nullptr);
}
else
{
fb = (SDLBaseFB*)CreateGLSWFrameBuffer(width, height, bgra, fullscreen);
if (!fb->IsValid())
{
delete fb;
fb = new SDLFB(width, height, bgra, fullscreen, nullptr);
}
}
retry = 0;
// If we could not create the framebuffer, try again with slightly
// different parameters in this order:
// 1. Try with the closest size
// 2. Try in the opposite screen mode with the original size
// 3. Try in the opposite screen mode with the closest size
// This is a somewhat confusing mass of recursion here.
while (fb == NULL || !fb->IsValid ())
{
if (fb != NULL)
{
delete fb;
}
switch (retry)
{
case 0:
owidth = width;
oheight = height;
case 2:
// Try a different resolution. Hopefully that will work.
I_ClosestResolution (&width, &height, 8);
break;
case 1:
// Try changing fullscreen mode. Maybe that will work.
width = owidth;
height = oheight;
fullscreen = !fullscreen;
break;
default:
// I give up!
I_FatalError ("Could not create new screen (%d x %d)", owidth, oheight);
fprintf( stderr, "!!! [SDLGLVideo::CreateFrameBuffer] Got beyond I_FatalError !!!" );
return NULL; //[C] actually this shouldn't be reached; probably should be replaced with an ASSERT
}
++retry;
fb = static_cast<SDLBaseFB *>(CreateFrameBuffer (width, height, false, fullscreen, NULL));
}
// fb->SetFlash (flashColor, flashAmount);
return fb;
}
void SDLGLVideo::SetWindowedScale (float scale)
{
}
bool SDLGLVideo::SetResolution (int width, int height, int bits)
{
// FIXME: Is it possible to do this without completely destroying the old
// interface?
#ifndef NO_GL
if (GLRenderer != NULL) GLRenderer->FlushTextures();
I_ShutdownGraphics();
Video = new SDLGLVideo(0);
if (Video == NULL) I_FatalError ("Failed to initialize display");
#if (defined(WINDOWS)) || defined(WIN32)
bits=32;
#else
bits=24;
#endif
V_DoModeSetup(width, height, bits);
#endif
return true; // We must return true because the old video context no longer exists.
}
//==========================================================================
//
//
//
//==========================================================================
#ifdef __MOBILE__
extern "C" extern int glesLoad;
#endif
void SDLGLVideo::SetupPixelFormat(bool allowsoftware, int multisample, const int *glver)
{
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
#ifdef __MOBILE__
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
#else
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
#endif
SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
if (multisample > 0) {
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, multisample );
}
if (gl_debug)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
#ifdef __MOBILE__
const char *version = Args->CheckValue("-glversion");
int major,min;
if( !strcmp(version, "gles1") )
{
glesLoad = 1;
major = 1;
min = 0;
}
else if ( !strcmp(version, "gles2") )
{
glesLoad = 2;
major = 2;
min = 0;
}
else if ( !strcmp(version, "gles3") )
{
glesLoad = 3;
major = 3;
min = 1;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, min);
return;
#endif
if (gl_es)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
}
else if (glver[0] > 2)
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, glver[0]);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, glver[1]);
}
else
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
}
}
// FrameBuffer implementation -----------------------------------------------
SDLGLFB::SDLGLFB (void *, int width, int height, int, int, bool fullscreen, bool bgra)
: SDLBaseFB (width, height, bgra)
{
// NOTE: Core profiles were added with GL 3.2, so there's no sense trying
// to set core 3.1 or 3.0. We could try a forward-compatible context
// instead, but that would be too restrictive (w.r.t. shaders).
static const int glvers[][2] = {
{ 4, 5 }, { 4, 4 }, { 4, 3 }, { 4, 2 }, { 4, 1 }, { 4, 0 },
{ 3, 3 }, { 3, 2 }, { 2, 0 },
{ 0, 0 },
};
int glveridx = 0;
int i;
m_Lock=0;
UpdatePending = false;
const char *version = Args->CheckValue("-glversion");
if (version != NULL)
{
double gl_version = strtod(version, NULL) + 0.01;
int vermaj = (int)gl_version;
int vermin = (int)(gl_version*10.0) % 10;
while (glvers[glveridx][0] > vermaj || (glvers[glveridx][0] == vermaj &&
glvers[glveridx][1] > vermin))
{
glveridx++;
if (glvers[glveridx][0] == 0)
{
glveridx = 0;
break;
}
}
}
FString caption;
caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime());
for ( ; glvers[glveridx][0] > 0; ++glveridx)
{
static_cast<SDLGLVideo*>(Video)->SetupPixelFormat(false, 0, glvers[glveridx]);
Screen = SDL_CreateWindow (caption,
SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter),
SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter),
width, height, (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)|SDL_WINDOW_OPENGL
);
if (Screen != NULL)
{
GLContext = SDL_GL_CreateContext(Screen);
if (GLContext != NULL)
{
m_supportsGamma = -1 != SDL_GetWindowGammaRamp(Screen,
m_origGamma[0], m_origGamma[1], m_origGamma[2]
);
return;
}
SDL_DestroyWindow(Screen);
Screen = NULL;
}
}
}
SDLGLFB::~SDLGLFB ()
{
if (Screen)
{
ResetGammaTable();
if (GLContext)
{
SDL_GL_DeleteContext(GLContext);
}
SDL_DestroyWindow(Screen);
}
}
void SDLGLFB::InitializeState()
{
}
void SDLGLFB::SetGammaTable(uint16_t *tbl)
{
if (m_supportsGamma)
{
SDL_SetWindowGammaRamp(Screen, &tbl[0], &tbl[256], &tbl[512]);
}
}
void SDLGLFB::ResetGammaTable()
{
if (m_supportsGamma)
{
SDL_SetWindowGammaRamp(Screen, m_origGamma[0], m_origGamma[1], m_origGamma[2]);
}
}
bool SDLGLFB::Lock(bool buffered)
{
m_Lock++;
Buffer = MemBuffer;
return true;
}
bool SDLGLFB::Lock ()
{
return Lock(false);
}
void SDLGLFB::Unlock ()
{
if (UpdatePending && m_Lock == 1)
{
Update ();
}
else if (--m_Lock <= 0)
{
m_Lock = 0;
}
}
bool SDLGLFB::IsLocked ()
{
return m_Lock>0;// true;
}
bool SDLGLFB::IsFullscreen ()
{
return (SDL_GetWindowFlags (Screen) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
}
bool SDLGLFB::IsValid ()
{
return DFrameBuffer::IsValid() && Screen != NULL;
}
void SDLGLFB::SetVSync( bool vsync )
{
#if defined (__APPLE__)
const GLint value = vsync ? 1 : 0;
CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval, &value );
#else
if (vsync)
{
if (SDL_GL_SetSwapInterval(-1) == -1)
SDL_GL_SetSwapInterval(1);
}
else
{
SDL_GL_SetSwapInterval(0);
}
#endif
}
void SDLGLFB::NewRefreshRate ()
{
}
void SDLGLFB::SwapBuffers()
{
#if !defined(__APPLE__) && !defined(__OpenBSD__)
if (vid_maxfps && !cl_capfps)
{
SEMAPHORE_WAIT(FPSLimitSemaphore)
}
#endif
SDL_GL_SwapWindow (Screen);
}
int SDLGLFB::GetClientWidth()
{
int width = 0;
SDL_GL_GetDrawableSize(Screen, &width, nullptr);
return width;
}
int SDLGLFB::GetClientHeight()
{
int height = 0;
SDL_GL_GetDrawableSize(Screen, nullptr, &height);
return height;
}
void SDLGLFB::ScaleCoordsFromWindow(int16_t &x, int16_t &y)
{
int w, h;
SDL_GetWindowSize (Screen, &w, &h);
// Detect if we're doing scaling in the Window and adjust the mouse
// coordinates accordingly. This could be more efficent, but I
// don't think performance is an issue in the menus.
if(IsFullscreen())
{
int realw = w, realh = h;
ScaleWithAspect (realw, realh, SCREENWIDTH, SCREENHEIGHT);
if (realw != SCREENWIDTH || realh != SCREENHEIGHT)
{
double xratio = (double)SCREENWIDTH/realw;
double yratio = (double)SCREENHEIGHT/realh;
if (realw < w)
{
x = (x - (w - realw)/2)*xratio;
y *= yratio;
}
else
{
y = (y - (h - realh)/2)*yratio;
x *= xratio;
}
}
}
else
{
x = (int16_t)(x*Width/w);
y = (int16_t)(y*Height/h);
}
}

View File

@ -1,580 +0,0 @@
/*
** sdlvideo.cpp
**
**---------------------------------------------------------------------------
** Copyright 2005-2016 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
// HEADER FILES ------------------------------------------------------------
#include "doomtype.h"
#include "templates.h"
#include "i_system.h"
#include "i_video.h"
#include "v_video.h"
#include "v_pfx.h"
#include "stats.h"
#include "v_palette.h"
#include "sdlvideo.h"
#include "swrenderer/r_swrenderer.h"
#include "version.h"
#include <SDL.h>
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#endif // __APPLE__
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
struct MiniModeInfo
{
uint16_t Width, Height;
};
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern IVideo *Video;
extern bool GUICapture;
EXTERN_CVAR (Float, Gamma)
EXTERN_CVAR (Int, vid_maxfps)
EXTERN_CVAR (Bool, cl_capfps)
EXTERN_CVAR (Bool, vid_vsync)
// PUBLIC DATA DEFINITIONS -------------------------------------------------
CVAR (Int, vid_adapter, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Int, vid_displaybits, 32, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR (Bool, vid_forcesurface, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR (Float, rgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
if (screen != NULL)
{
screen->SetGamma (Gamma);
}
}
CUSTOM_CVAR (Float, ggamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
if (screen != NULL)
{
screen->SetGamma (Gamma);
}
}
CUSTOM_CVAR (Float, bgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
if (screen != NULL)
{
screen->SetGamma (Gamma);
}
}
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static cycle_t BlitCycles;
static cycle_t SDLFlipCycles;
// CODE --------------------------------------------------------------------
// FrameBuffer implementation -----------------------------------------------
SDLFB::SDLFB (int width, int height, bool bgra, bool fullscreen, SDL_Window *oldwin)
: SDLBaseFB (width, height, bgra)
{
int i;
NeedPalUpdate = false;
NeedGammaUpdate = false;
UpdatePending = false;
NotPaletted = false;
FlashAmount = 0;
if (oldwin)
{
// In some cases (Mac OS X fullscreen) SDL2 doesn't like having multiple windows which
// appears to inevitably happen while compositor animations are running. So lets try
// to reuse the existing window.
Screen = oldwin;
SDL_SetWindowSize (Screen, width, height);
SetFullscreen (fullscreen);
}
else
{
FString caption;
caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime());
#ifdef __ANDROID__
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); // Defaults to 24 which is not needed and fails on old Tegras
#endif
Screen = SDL_CreateWindow (caption,
SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter), SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter),
width, height, (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)|SDL_WINDOW_RESIZABLE);
if (Screen == NULL)
return;
}
Renderer = NULL;
Texture = NULL;
ResetSDLRenderer ();
for (i = 0; i < 256; i++)
{
GammaTable[0][i] = GammaTable[1][i] = GammaTable[2][i] = i;
}
memcpy (SourcePalette, GPalette.BaseColors, sizeof(PalEntry)*256);
UpdateColors ();
#ifdef __APPLE__
SetVSync (vid_vsync);
#endif
}
SDLFB::~SDLFB ()
{
if (Renderer)
{
if (Texture)
SDL_DestroyTexture (Texture);
SDL_DestroyRenderer (Renderer);
}
if(Screen)
{
SDL_DestroyWindow (Screen);
}
}
bool SDLFB::IsValid ()
{
return DFrameBuffer::IsValid() && Screen != NULL;
}
int SDLFB::GetPageCount ()
{
return 1;
}
bool SDLFB::Lock (bool buffered)
{
return DSimpleCanvas::Lock ();
}
bool SDLFB::Relock ()
{
return DSimpleCanvas::Lock ();
}
void SDLFB::Unlock ()
{
if (UpdatePending && LockCount == 1)
{
Update ();
}
else if (--LockCount <= 0)
{
Buffer = NULL;
LockCount = 0;
}
}
void SDLFB::Update ()
{
if (LockCount != 1)
{
if (LockCount > 0)
{
UpdatePending = true;
--LockCount;
}
return;
}
DrawRateStuff ();
#if !defined(__APPLE__) && !defined(__OpenBSD__)
if(vid_maxfps && !cl_capfps)
{
SEMAPHORE_WAIT(FPSLimitSemaphore)
}
#endif
Buffer = NULL;
LockCount = 0;
UpdatePending = false;
BlitCycles.Reset();
SDLFlipCycles.Reset();
BlitCycles.Clock();
void *pixels;
int pitch;
if (UsingRenderer)
{
if (SDL_LockTexture (Texture, NULL, &pixels, &pitch))
return;
}
else
{
if (SDL_LockSurface (Surface))
return;
pixels = Surface->pixels;
pitch = Surface->pitch;
}
if (Bgra)
{
CopyWithGammaBgra(pixels, pitch, GammaTable[0], GammaTable[1], GammaTable[2], Flash, FlashAmount);
}
else if (NotPaletted)
{
GPfx.Convert (MemBuffer, Pitch,
pixels, pitch, Width, Height,
FRACUNIT, FRACUNIT, 0, 0);
}
else
{
if (pitch == Pitch)
{
memcpy (pixels, MemBuffer, Width*Height);
}
else
{
for (int y = 0; y < Height; ++y)
{
memcpy ((uint8_t *)pixels+y*pitch, MemBuffer+y*Pitch, Width);
}
}
}
if (UsingRenderer)
{
SDL_UnlockTexture (Texture);
SDLFlipCycles.Clock();
SDL_RenderClear(Renderer);
SDL_RenderCopy(Renderer, Texture, NULL, NULL);
SDL_RenderPresent(Renderer);
SDLFlipCycles.Unclock();
}
else
{
SDL_UnlockSurface (Surface);
SDLFlipCycles.Clock();
SDL_UpdateWindowSurface (Screen);
SDLFlipCycles.Unclock();
}
BlitCycles.Unclock();
if (NeedGammaUpdate)
{
bool Windowed = false;
NeedGammaUpdate = false;
CalcGamma ((Windowed || rgamma == 0.f) ? Gamma : (Gamma * rgamma), GammaTable[0]);
CalcGamma ((Windowed || ggamma == 0.f) ? Gamma : (Gamma * ggamma), GammaTable[1]);
CalcGamma ((Windowed || bgamma == 0.f) ? Gamma : (Gamma * bgamma), GammaTable[2]);
NeedPalUpdate = true;
}
if (NeedPalUpdate)
{
NeedPalUpdate = false;
UpdateColors ();
}
}
void SDLFB::UpdateColors ()
{
if (NotPaletted)
{
PalEntry palette[256];
for (int i = 0; i < 256; ++i)
{
palette[i].r = GammaTable[0][SourcePalette[i].r];
palette[i].g = GammaTable[1][SourcePalette[i].g];
palette[i].b = GammaTable[2][SourcePalette[i].b];
}
if (FlashAmount)
{
DoBlending (palette, palette,
256, GammaTable[0][Flash.r], GammaTable[1][Flash.g], GammaTable[2][Flash.b],
FlashAmount);
}
GPfx.SetPalette (palette);
}
else
{
SDL_Color colors[256];
for (int i = 0; i < 256; ++i)
{
colors[i].r = GammaTable[0][SourcePalette[i].r];
colors[i].g = GammaTable[1][SourcePalette[i].g];
colors[i].b = GammaTable[2][SourcePalette[i].b];
}
if (FlashAmount)
{
DoBlending ((PalEntry *)colors, (PalEntry *)colors,
256, GammaTable[2][Flash.b], GammaTable[1][Flash.g], GammaTable[0][Flash.r],
FlashAmount);
}
SDL_SetPaletteColors (Surface->format->palette, colors, 0, 256);
}
}
PalEntry *SDLFB::GetPalette ()
{
return SourcePalette;
}
void SDLFB::UpdatePalette ()
{
NeedPalUpdate = true;
}
bool SDLFB::SetGamma (float gamma)
{
Gamma = gamma;
NeedGammaUpdate = true;
return true;
}
bool SDLFB::SetFlash (PalEntry rgb, int amount)
{
Flash = rgb;
FlashAmount = amount;
NeedPalUpdate = true;
return true;
}
void SDLFB::GetFlash (PalEntry &rgb, int &amount)
{
rgb = Flash;
amount = FlashAmount;
}
// Q: Should I gamma adjust the returned palette?
void SDLFB::GetFlashedPalette (PalEntry pal[256])
{
memcpy (pal, SourcePalette, 256*sizeof(PalEntry));
if (FlashAmount)
{
DoBlending (pal, pal, 256, Flash.r, Flash.g, Flash.b, FlashAmount);
}
}
void SDLFB::SetFullscreen (bool fullscreen)
{
if (IsFullscreen() == fullscreen)
return;
SDL_SetWindowFullscreen (Screen, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
if (!fullscreen)
{
// Restore proper window size
SDL_SetWindowSize (Screen, Width, Height);
}
ResetSDLRenderer ();
}
bool SDLFB::IsFullscreen ()
{
return (SDL_GetWindowFlags (Screen) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
}
void SDLFB::ResetSDLRenderer ()
{
if (Renderer)
{
if (Texture)
SDL_DestroyTexture (Texture);
SDL_DestroyRenderer (Renderer);
}
UsingRenderer = !vid_forcesurface;
if (UsingRenderer)
{
#ifdef __MOBILE__
Renderer = SDL_CreateRenderer (Screen, -1,SDL_RENDERER_ACCELERATED);
#else
Renderer = SDL_CreateRenderer (Screen, -1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_TARGETTEXTURE|
(vid_vsync ? SDL_RENDERER_PRESENTVSYNC : 0));
#endif
if (!Renderer)
return;
SDL_SetRenderDrawColor(Renderer, 0, 0, 0, 255);
Uint32 fmt;
if (Bgra)
{
fmt = SDL_PIXELFORMAT_ARGB8888;
}
else
{
switch (vid_displaybits)
{
default: fmt = SDL_PIXELFORMAT_ARGB8888; break;
case 30: fmt = SDL_PIXELFORMAT_ARGB2101010; break;
case 24: fmt = SDL_PIXELFORMAT_RGB888; break;
case 16: fmt = SDL_PIXELFORMAT_RGB565; break;
case 15: fmt = SDL_PIXELFORMAT_ARGB1555; break;
}
}
Texture = SDL_CreateTexture (Renderer, fmt, SDL_TEXTUREACCESS_STREAMING, Width, Height);
{
NotPaletted = true;
Uint32 format;
SDL_QueryTexture(Texture, &format, NULL, NULL, NULL);
Uint32 Rmask, Gmask, Bmask, Amask;
int bpp;
SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask);
GPfx.SetFormat (bpp, Rmask, Gmask, Bmask);
}
}
else
{
Surface = SDL_GetWindowSurface (Screen);
if (Surface->format->palette == NULL)
{
NotPaletted = true;
GPfx.SetFormat (Surface->format->BitsPerPixel, Surface->format->Rmask, Surface->format->Gmask, Surface->format->Bmask);
}
else
NotPaletted = false;
}
// In fullscreen, set logical size according to animorphic ratio.
// Windowed modes are rendered to fill the window (usually 1:1)
if (IsFullscreen ())
{
int w, h;
SDL_GetWindowSize (Screen, &w, &h);
ScaleWithAspect (w, h, Width, Height);
#ifndef __MOBILE__
SDL_RenderSetLogicalSize (Renderer, w, h);
#endif
}
}
void SDLFB::SetVSync (bool vsync)
{
#ifdef __APPLE__
if (CGLContextObj context = CGLGetCurrentContext())
{
// Apply vsync for native backend only (where OpenGL context is set)
const GLint value = vsync ? 1 : 0;
CGLSetParameter(context, kCGLCPSwapInterval, &value);
}
#else
ResetSDLRenderer ();
#endif // __APPLE__
}
void SDLFB::ScaleCoordsFromWindow(int16_t &x, int16_t &y)
{
int w, h;
SDL_GetWindowSize (Screen, &w, &h);
// Detect if we're doing scaling in the Window and adjust the mouse
// coordinates accordingly. This could be more efficent, but I
// don't think performance is an issue in the menus.
if(IsFullscreen())
{
int realw = w, realh = h;
ScaleWithAspect (realw, realh, SCREENWIDTH, SCREENHEIGHT);
if (realw != SCREENWIDTH || realh != SCREENHEIGHT)
{
double xratio = (double)SCREENWIDTH/realw;
double yratio = (double)SCREENHEIGHT/realh;
if (realw < w)
{
x = (x - (w - realw)/2)*xratio;
y *= yratio;
}
else
{
y = (y - (h - realh)/2)*yratio;
x *= xratio;
}
}
}
else
{
x = (int16_t)(x*Width/w);
y = (int16_t)(y*Height/h);
}
}
ADD_STAT (blit)
{
FString out;
out.Format ("blit=%04.1f ms flip=%04.1f ms",
BlitCycles.TimeMS(), SDLFlipCycles.TimeMS());
return out;
}
// each platform has its own specific version of this function.
void I_SetWindowTitle(const char* caption)
{
auto Screen = static_cast<SDLFB *>(screen)->GetSDLWindow();
if (caption)
SDL_SetWindowTitle(static_cast<SDLFB *>(screen)->GetSDLWindow(), caption);
else
{
FString default_caption;
default_caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime());
SDL_SetWindowTitle(static_cast<SDLFB *>(screen)->GetSDLWindow(), default_caption);
}
}

View File

@ -1,60 +0,0 @@
#include "hardware.h"
#include "v_video.h"
#include "sdlglvideo.h"
class SDLFB : public SDLBaseFB
{
typedef SDLBaseFB Super;
public:
SDLFB(int width, int height, bool bgra, bool fullscreen, SDL_Window *oldwin);
~SDLFB();
bool Lock(bool buffer);
void Unlock();
bool Relock();
void ForceBuffering(bool force);
bool IsValid();
void Update();
PalEntry *GetPalette();
void GetFlashedPalette(PalEntry pal[256]);
void UpdatePalette();
bool SetGamma(float gamma);
bool SetFlash(PalEntry rgb, int amount);
void GetFlash(PalEntry &rgb, int &amount);
void SetFullscreen(bool fullscreen);
int GetPageCount();
bool IsFullscreen();
friend class SDLGLVideo;
virtual void SetVSync(bool vsync);
virtual void ScaleCoordsFromWindow(int16_t &x, int16_t &y);
SDL_Window *GetSDLWindow() override { return Screen; }
private:
PalEntry SourcePalette[256];
uint8_t GammaTable[3][256];
PalEntry Flash;
int FlashAmount;
float Gamma;
bool UpdatePending;
SDL_Window *Screen;
SDL_Renderer *Renderer;
union
{
SDL_Texture *Texture;
SDL_Surface *Surface;
};
bool UsingRenderer;
bool NeedPalUpdate;
bool NeedGammaUpdate;
bool NotPaletted;
void UpdateColors();
void ResetSDLRenderer();
SDLFB() {}
};

View File

@ -1,382 +0,0 @@
/*
** st_start.cpp
** Handles the startup screen.
**
**---------------------------------------------------------------------------
** Copyright 2006-2007 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
// HEADER FILES ------------------------------------------------------------
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <termios.h>
#include "st_start.h"
#include "doomdef.h"
#include "i_system.h"
#include "c_cvars.h"
#include "atterm.h"
#ifdef __ANDROID__
#include <android/log.h>
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,"NETOWRK",__VA_ARGS__)
#define fprintf my_fprintf
void my_fprintf(FILE * x, const char *format, ...)
{
FString str;
va_list argptr;
va_start (argptr, format);
str.VFormat (format, argptr);
va_end (argptr);
//fprintf (stderr, "\r%-40s\n", str.GetChars());
//addTextConsoleBox(str.GetChars());
}
#endif
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
class FTTYStartupScreen : public FStartupScreen
{
public:
FTTYStartupScreen(int max_progress);
~FTTYStartupScreen();
void Progress();
void NetInit(const char *message, int num_players);
void NetProgress(int count);
void NetMessage(const char *format, ...); // cover for printf
void NetDone();
bool NetLoop(bool (*timer_callback)(void *), void *userdata);
protected:
bool DidNetInit;
int NetMaxPos, NetCurPos;
const char *TheNetMessage;
termios OldTermIOS;
};
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
void I_ShutdownJoysticks();
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static void DeleteStartupScreen();
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
FStartupScreen *StartScreen;
CUSTOM_CVAR(Int, showendoom, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
if (self < 0) self = 0;
else if (self > 2) self=2;
}
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static const char SpinnyProgressChars[4] = { '|', '/', '-', '\\' };
// CODE --------------------------------------------------------------------
//==========================================================================
//
// FStartupScreen :: CreateInstance
//
// Initializes the startup screen for the detected game.
// Sets the size of the progress bar and displays the startup screen.
//
//==========================================================================
FStartupScreen *FStartupScreen::CreateInstance(int max_progress)
{
atterm(DeleteStartupScreen);
return new FTTYStartupScreen(max_progress);
}
//===========================================================================
//
// DeleteStartupScreen
//
// Makes sure the startup screen has been deleted before quitting.
//
//===========================================================================
void DeleteStartupScreen()
{
if (StartScreen != NULL)
{
delete StartScreen;
StartScreen = NULL;
}
}
//===========================================================================
//
// FTTYStartupScreen Constructor
//
// Sets the size of the progress bar and displays the startup screen.
//
//===========================================================================
FTTYStartupScreen::FTTYStartupScreen(int max_progress)
: FStartupScreen(max_progress)
{
DidNetInit = false;
NetMaxPos = 0;
NetCurPos = 0;
TheNetMessage = NULL;
}
//===========================================================================
//
// FTTYStartupScreen Destructor
//
// Called just before entering graphics mode to deconstruct the startup
// screen.
//
//===========================================================================
FTTYStartupScreen::~FTTYStartupScreen()
{
NetDone(); // Just in case it wasn't called yet and needs to be.
}
//===========================================================================
//
// FTTYStartupScreen :: Progress
//
// If there was a progress bar, this would move it. But the basic TTY
// startup screen doesn't have one, so this function does nothing.
//
//===========================================================================
void FTTYStartupScreen::Progress()
{
}
//===========================================================================
//
// FTTYStartupScreen :: NetInit
//
// Sets stdin for unbuffered I/O, displays the given message, and shows
// a progress meter.
//
//===========================================================================
void FTTYStartupScreen::NetInit(const char *message, int numplayers)
{
if (!DidNetInit)
{
termios rawtermios;
fprintf (stderr, "Press 'Q' to abort network game synchronization.");
// Set stdin to raw mode so we can get keypresses in ST_CheckNetAbort()
// immediately without waiting for an EOL.
tcgetattr (STDIN_FILENO, &OldTermIOS);
rawtermios = OldTermIOS;
rawtermios.c_lflag &= ~(ICANON | ECHO);
tcsetattr (STDIN_FILENO, TCSANOW, &rawtermios);
DidNetInit = true;
}
if (numplayers == 1)
{
// Status message without any real progress info.
fprintf (stderr, "\n%s.", message);
}
else
{
fprintf (stderr, "\n%s: ", message);
}
fflush (stderr);
TheNetMessage = message;
NetMaxPos = numplayers;
NetCurPos = 0;
NetProgress(1); // You always know about yourself
}
//===========================================================================
//
// FTTYStartupScreen :: NetDone
//
// Restores the old stdin tty settings.
//
//===========================================================================
void FTTYStartupScreen::NetDone()
{
// Restore stdin settings
if (DidNetInit)
{
tcsetattr (STDIN_FILENO, TCSANOW, &OldTermIOS);
printf ("\n");
DidNetInit = false;
}
}
//===========================================================================
//
// FTTYStartupScreen :: NetMessage
//
// Call this between NetInit() and NetDone() instead of Printf() to
// display messages, because the progress meter is mixed in the same output
// stream as normal messages.
//
//===========================================================================
void FTTYStartupScreen::NetMessage(const char *format, ...)
{
FString str;
va_list argptr;
va_start (argptr, format);
str.VFormat (format, argptr);
va_end (argptr);
fprintf (stderr, "\r%-40s\n", str.GetChars());
}
//===========================================================================
//
// FTTYStartupScreen :: NetProgress
//
// Sets the network progress meter. If count is 0, it gets bumped by 1.
// Otherwise, it is set to count.
//
//===========================================================================
void FTTYStartupScreen::NetProgress(int count)
{
int i;
if (count == 0)
{
NetCurPos++;
}
else if (count > 0)
{
NetCurPos = count;
}
if (NetMaxPos == 0)
{
// Spinny-type progress meter, because we're a guest waiting for the host.
fprintf (stderr, "\r%s: %c", TheNetMessage, SpinnyProgressChars[NetCurPos & 3]);
fflush (stderr);
}
else if (NetMaxPos > 1)
{
// Dotty-type progress meter.
fprintf (stderr, "\r%s: ", TheNetMessage);
for (i = 0; i < NetCurPos; ++i)
{
fputc ('.', stderr);
}
fprintf (stderr, "%*c[%2d/%2d]", NetMaxPos + 1 - NetCurPos, ' ', NetCurPos, NetMaxPos);
fflush (stderr);
}
}
//===========================================================================
//
// FTTYStartupScreen :: NetLoop
//
// The timer_callback function is called at least two times per second
// and passed the userdata value. It should return true to stop the loop and
// return control to the caller or false to continue the loop.
//
// ST_NetLoop will return true if the loop was halted by the callback and
// false if the loop was halted because the user wants to abort the
// network synchronization.
//
//===========================================================================
bool FTTYStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata)
{
fd_set rfds;
struct timeval tv;
int retval;
char k;
for (;;)
{
// Don't flood the network with packets on startup.
tv.tv_sec = 0;
tv.tv_usec = 500000;
FD_ZERO (&rfds);
FD_SET (STDIN_FILENO, &rfds);
retval = select (1, &rfds, NULL, NULL, &tv);
#ifdef __ANDROID__
usleep(1000*200);
//The select command is to wait for the console input to be ready, obv don't need this on droid
retval = 0;
#endif
if (retval == -1)
{
// Error
}
else if (retval == 0)
{
if (timer_callback (userdata))
{
fputc ('\n', stderr);
return true;
}
}
else if (read (STDIN_FILENO, &k, 1) == 1)
{
// Check input on stdin
if (k == 'q' || k == 'Q')
{
fprintf (stderr, "\nNetwork game synchronization aborted.");
return false;
}
}
}
}
void ST_Endoom()
{
I_ShutdownJoysticks();
call_terms();
exit(0);
}

View File

@ -27,18 +27,6 @@
#include <string.h>
#include <stdint.h>
#ifdef ADLMIDI_buildAsApp
#include <SDL2/SDL.h>
class MutexType
{
SDL_mutex* mut;
public:
MutexType() : mut(SDL_CreateMutex()) { }
~MutexType() { SDL_DestroyMutex(mut); }
void Lock() { SDL_mutexP(mut); }
void Unlock() { SDL_mutexV(mut); }
};
#endif
enum { opnNoteOnMaxTime = 40000 };