mirror of
https://github.com/DrBeef/QuestZDoom.git
synced 2024-11-10 15:01:48 +00:00
Removing SDL - Doom now starts!
This commit is contained in:
parent
779178f798
commit
5f41c55468
58 changed files with 302 additions and 11695 deletions
|
@ -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,34 +1622,82 @@ 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};
|
||||
|
||||
//Need to replicate this code in gl_oculusquest.cpp
|
||||
void vr_main()
|
||||
{/*
|
||||
if (!destroyed)
|
||||
if (!useScreenLayer()) {
|
||||
|
||||
ovrLayerProjection2 layer = vrapi_DefaultLayerProjection2();
|
||||
layer.HeadPose = (*tracking).HeadPose;
|
||||
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
|
||||
{
|
||||
processHaptics();
|
||||
ovrFramebuffer * frameBuffer = &gAppState.Renderer.FrameBuffer[gAppState.Renderer.NumBuffers == 1 ? 0 : eye];
|
||||
layer.Textures[eye].ColorSwapChain = frameBuffer->ColorTextureSwapChain;
|
||||
layer.Textures[eye].SwapChainIndex = frameBuffer->ReadyTextureSwapChainIndex;
|
||||
|
||||
ovrTracking2 tracking;
|
||||
getHMDOrientation(&tracking);
|
||||
getTrackedRemotesOrientation();
|
||||
ovrMatrix4f projectionMatrix;
|
||||
projectionMatrix = ovrMatrix4f_CreateProjectionFov(vrFOV, vrFOV,
|
||||
0.0f, 0.0f, 0.1f, 0.0f);
|
||||
|
||||
ovrSubmitFrameDescription2 frameDesc = setupFrameDescriptor(&tracking);
|
||||
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection(&projectionMatrix);
|
||||
|
||||
//Call the game drawing code
|
||||
RenderFrame();
|
||||
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.
|
||||
submitFrame(&frameDesc);
|
||||
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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
static void ovrAppThread_Create( ovrAppThread * appThread, JNIEnv * env, jobject activityObject, jclass activityClass )
|
||||
{
|
||||
(*env)->GetJavaVM( env, &appThread->JavaVm );
|
||||
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -59,7 +59,8 @@ typedef struct
|
|||
int Height;
|
||||
int Multisamples;
|
||||
int TextureSwapChainLength;
|
||||
int TextureSwapChainIndex;
|
||||
int ProcessingTextureSwapChainIndex;
|
||||
int ReadyTextureSwapChainIndex;
|
||||
ovrTextureSwapChain * ColorTextureSwapChain;
|
||||
GLuint * DepthBuffers;
|
||||
GLuint * FrameBuffers;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 +=
|
||||
|
||||
|
|
|
@ -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/";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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>();
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -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 ();
|
||||
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
// HEADER FILES ------------------------------------------------------------
|
||||
|
||||
#include <SDL.h>
|
||||
//#include <SDL.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
|
@ -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 "";
|
||||
}
|
||||
|
|
@ -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);
|
|
@ -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() {}
|
||||
};
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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>();
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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>
|
Binary file not shown.
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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() {}
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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 };
|
||||
|
||||
|
|
Loading…
Reference in a new issue