mirror of
https://github.com/DrBeef/QuestZDoom.git
synced 2025-02-21 11:31:19 +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 <src/gl/loader.h>
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
//#include <SDL2/SDL.h>
|
||||||
#include <SDL2/SDL_main.h>
|
//#include <SDL2/SDL_main.h>
|
||||||
//#include <src/client/header/client.h>
|
|
||||||
|
|
||||||
#include "VrCompositor.h"
|
#include "VrCompositor.h"
|
||||||
#include "VrInput.h"
|
#include "VrInput.h"
|
||||||
|
@ -509,7 +508,8 @@ static void ovrFramebuffer_Clear( ovrFramebuffer * frameBuffer )
|
||||||
frameBuffer->Height = 0;
|
frameBuffer->Height = 0;
|
||||||
frameBuffer->Multisamples = 0;
|
frameBuffer->Multisamples = 0;
|
||||||
frameBuffer->TextureSwapChainLength = 0;
|
frameBuffer->TextureSwapChainLength = 0;
|
||||||
frameBuffer->TextureSwapChainIndex = 0;
|
frameBuffer->ProcessingTextureSwapChainIndex = 0;
|
||||||
|
frameBuffer->ReadyTextureSwapChainIndex = 0;
|
||||||
frameBuffer->ColorTextureSwapChain = NULL;
|
frameBuffer->ColorTextureSwapChain = NULL;
|
||||||
frameBuffer->DepthBuffers = NULL;
|
frameBuffer->DepthBuffers = NULL;
|
||||||
frameBuffer->FrameBuffers = NULL;
|
frameBuffer->FrameBuffers = NULL;
|
||||||
|
@ -598,7 +598,7 @@ void ovrFramebuffer_Destroy( ovrFramebuffer * frameBuffer )
|
||||||
void ovrFramebuffer_SetCurrent( ovrFramebuffer * frameBuffer )
|
void ovrFramebuffer_SetCurrent( ovrFramebuffer * frameBuffer )
|
||||||
{
|
{
|
||||||
//LOAD_GLES2(glBindFramebuffer);
|
//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()
|
void ovrFramebuffer_SetNone()
|
||||||
|
@ -620,7 +620,8 @@ void ovrFramebuffer_Resolve( ovrFramebuffer * frameBuffer )
|
||||||
void ovrFramebuffer_Advance( ovrFramebuffer * frameBuffer )
|
void ovrFramebuffer_Advance( ovrFramebuffer * frameBuffer )
|
||||||
{
|
{
|
||||||
// Advance to the next texture from the set.
|
// 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 ovrJava java;
|
||||||
static bool destroyed = false;
|
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 )
|
void prepareEyeBuffer(int eye )
|
||||||
{
|
{
|
||||||
ovrRenderer *renderer = useScreenLayer() ? &gAppState.Scene.CylinderRenderer : &gAppState.Renderer;
|
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);
|
jclass cls = (*java.Env)->GetObjectClass(java.Env, java.ActivityObject);
|
||||||
|
|
||||||
/* This interface could expand with ABI negotiation, callbacks, etc. */
|
/* 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.
|
// Note that AttachCurrentThread will reset the thread name.
|
||||||
prctl(PR_SET_NAME, (long) "OVR::Main", 0, 0, 0);
|
prctl(PR_SET_NAME, (long) "OVR::Main", 0, 0, 0);
|
||||||
|
@ -1634,75 +1594,6 @@ void shutdownVR() {
|
||||||
vrapi_Shutdown();
|
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()
|
void incrementFrameIndex()
|
||||||
{
|
{
|
||||||
// This is the only place the frame index is incremented, right before
|
// 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.
|
ovrSubmitFrameDescription2 frameDesc = {0};
|
||||||
vrapi_SubmitFrame2(gAppState.Ovr, frameDesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Need to replicate this code in gl_oculusquest.cpp
|
if (!useScreenLayer()) {
|
||||||
void vr_main()
|
|
||||||
{/*
|
ovrLayerProjection2 layer = vrapi_DefaultLayerProjection2();
|
||||||
if (!destroyed)
|
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;
|
ovrMatrix4f projectionMatrix;
|
||||||
getHMDOrientation(&tracking);
|
projectionMatrix = ovrMatrix4f_CreateProjectionFov(vrFOV, vrFOV,
|
||||||
getTrackedRemotesOrientation();
|
0.0f, 0.0f, 0.1f, 0.0f);
|
||||||
|
|
||||||
ovrSubmitFrameDescription2 frameDesc = setupFrameDescriptor(&tracking);
|
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection(&projectionMatrix);
|
||||||
|
|
||||||
//Call the game drawing code
|
layer.Textures[eye].TextureRect.x = 0;
|
||||||
RenderFrame();
|
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.
|
// 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 )
|
static void ovrAppThread_Create( ovrAppThread * appThread, JNIEnv * env, jobject activityObject, jclass activityClass )
|
||||||
{
|
{
|
||||||
(*env)->GetJavaVM( env, &appThread->JavaVm );
|
(*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)
|
int JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||||
{
|
{
|
||||||
|
@ -1802,7 +1741,7 @@ int JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||||
return -1;
|
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,
|
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();
|
void incrementFrameIndex();
|
||||||
|
|
||||||
ovrSubmitFrameDescription2 setupFrameDescriptor(ovrTracking2 *tracking);
|
|
||||||
void prepareEyeBuffer(int eye );
|
void prepareEyeBuffer(int eye );
|
||||||
void finishEyeBuffer(int eye );
|
void finishEyeBuffer(int eye );
|
||||||
void submitFrame(ovrSubmitFrameDescription2 *frameDesc);
|
void submitFrame(ovrTracking2 *tracking);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
|
@ -465,7 +465,7 @@ ovrLayerProjection2 ovrRenderer_RenderGroundPlaneToEyeBuffer( ovrRenderer * rend
|
||||||
{
|
{
|
||||||
ovrFramebuffer * frameBuffer = &renderer->FrameBuffer[eye];
|
ovrFramebuffer * frameBuffer = &renderer->FrameBuffer[eye];
|
||||||
layer.Textures[eye].ColorSwapChain = frameBuffer->ColorTextureSwapChain;
|
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.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_TanAngleMatrixFromProjection( &tracking->Eye[eye].ProjectionMatrix );
|
||||||
}
|
}
|
||||||
layer.Header.Flags |= VRAPI_FRAME_LAYER_FLAG_CHROMATIC_ABERRATION_CORRECTION;
|
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 );
|
ovrMatrix4f modelViewMatrix = ovrMatrix4f_Multiply( &tracking->Eye[eye].ViewMatrix, &cylinderTransform );
|
||||||
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_Inverse( &modelViewMatrix );
|
layer.Textures[eye].TexCoordsFromTanAngles = ovrMatrix4f_Inverse( &modelViewMatrix );
|
||||||
layer.Textures[eye].ColorSwapChain = cylinderFrameBuffer->ColorTextureSwapChain;
|
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
|
// Texcoord scale and bias is just a representation of the aspect ratio. The positioning
|
||||||
// of the cylinder is handled entirely by the TexCoordsFromTanAngles matrix.
|
// of the cylinder is handled entirely by the TexCoordsFromTanAngles matrix.
|
||||||
|
|
|
@ -59,7 +59,8 @@ typedef struct
|
||||||
int Height;
|
int Height;
|
||||||
int Multisamples;
|
int Multisamples;
|
||||||
int TextureSwapChainLength;
|
int TextureSwapChainLength;
|
||||||
int TextureSwapChainIndex;
|
int ProcessingTextureSwapChainIndex;
|
||||||
|
int ReadyTextureSwapChainIndex;
|
||||||
ovrTextureSwapChain * ColorTextureSwapChain;
|
ovrTextureSwapChain * ColorTextureSwapChain;
|
||||||
GLuint * DepthBuffers;
|
GLuint * DepthBuffers;
|
||||||
GLuint * FrameBuffers;
|
GLuint * FrameBuffers;
|
||||||
|
|
|
@ -21,9 +21,6 @@ float positional_movementSideways;
|
||||||
float positional_movementForward;
|
float positional_movementForward;
|
||||||
float snapTurn;
|
float snapTurn;
|
||||||
|
|
||||||
void sendButtonAction(const char* action, long buttonDown);
|
|
||||||
void sendButtonActionSimple(const char* action);
|
|
||||||
|
|
||||||
void acquireTrackedRemotesData(const ovrMobile *Ovr, double displayTime);
|
void acquireTrackedRemotesData(const ovrMobile *Ovr, double displayTime);
|
||||||
|
|
||||||
void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, ovrInputStateTrackedRemote *pDominantTrackedRemoteOld, ovrTracking* pDominantTracking,
|
void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew, ovrInputStateTrackedRemote *pDominantTrackedRemoteOld, ovrTracking* pDominantTracking,
|
||||||
|
|
|
@ -81,29 +81,11 @@ float nonLinearFilter(float in)
|
||||||
return val;
|
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)
|
bool between(float min, float val, float max)
|
||||||
{
|
{
|
||||||
return (min < val) && (val < 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
|
void acquireTrackedRemotesData(const ovrMobile *Ovr, double displayTime) {//The amount of yaw changed by controller
|
||||||
for ( int i = 0; ; i++ ) {
|
for ( int i = 0; ; i++ ) {
|
||||||
ovrInputCapabilityHeader cap;
|
ovrInputCapabilityHeader cap;
|
||||||
|
|
|
@ -189,11 +189,13 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
|
||||||
if (inventoryManagementMode)
|
if (inventoryManagementMode)
|
||||||
{
|
{
|
||||||
if (firingPrimary)
|
if (firingPrimary)
|
||||||
sendButtonActionSimple("invuse");
|
{
|
||||||
|
//Select inventory item
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sendButtonAction("+attack", firingPrimary);
|
//fire primary
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,8 +204,10 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
|
||||||
if ((pDominantTrackedRemoteNew->Buttons & domButton1) !=
|
if ((pDominantTrackedRemoteNew->Buttons & domButton1) !=
|
||||||
(pDominantTrackedRemoteOld->Buttons & domButton1) &&
|
(pDominantTrackedRemoteOld->Buttons & domButton1) &&
|
||||||
ducked != DUCK_CROUCHED) {
|
ducked != DUCK_CROUCHED) {
|
||||||
|
|
||||||
ducked = (pDominantTrackedRemoteNew->Buttons & domButton1) ? DUCK_BUTTON : DUCK_NOTDUCKED;
|
ducked = (pDominantTrackedRemoteNew->Buttons & domButton1) ? DUCK_BUTTON : DUCK_NOTDUCKED;
|
||||||
sendButtonAction("+movedown", (pDominantTrackedRemoteNew->Buttons & domButton1));
|
|
||||||
|
//Trigger Duck
|
||||||
}
|
}
|
||||||
|
|
||||||
//Weapon/Inventory Chooser
|
//Weapon/Inventory Chooser
|
||||||
|
@ -217,11 +221,11 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
|
||||||
{
|
{
|
||||||
if (inventoryManagementMode)
|
if (inventoryManagementMode)
|
||||||
{
|
{
|
||||||
sendButtonActionSimple("invprev");
|
//Previous Inventory Item
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sendButtonActionSimple("weapprev");
|
//Next Inventory Item
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -229,11 +233,11 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
|
||||||
{
|
{
|
||||||
if (inventoryManagementMode)
|
if (inventoryManagementMode)
|
||||||
{
|
{
|
||||||
sendButtonActionSimple("invnext");
|
//Next Inventory Item
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sendButtonActionSimple("weapnext");
|
//Next Weapon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
itemSwitched = true;
|
itemSwitched = true;
|
||||||
|
@ -279,7 +283,8 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
|
||||||
//show help computer while X/A pressed
|
//show help computer while X/A pressed
|
||||||
if ((pOffTrackedRemoteNew->Buttons & offButton1) !=
|
if ((pOffTrackedRemoteNew->Buttons & offButton1) !=
|
||||||
(pOffTrackedRemoteOld->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 \
|
||||||
$(GZDOOM_TOP_PATH)/src/scripting/vm \
|
$(GZDOOM_TOP_PATH)/src/scripting/vm \
|
||||||
$(GZDOOM_TOP_PATH)/src/posix \
|
$(GZDOOM_TOP_PATH)/src/posix \
|
||||||
$(GZDOOM_TOP_PATH)/src/posix\oculusquest \
|
$(GZDOOM_TOP_PATH)/src/posix\nosdl \
|
||||||
$(SDL_INCLUDE_PATHS) \
|
$(SDL_INCLUDE_PATHS) \
|
||||||
$(SUPPORT_LIBS)/fluidsynth-lite/include \
|
$(SUPPORT_LIBS)/fluidsynth-lite/include \
|
||||||
$(SUPPORT_LIBS)/openal/include/AL \
|
$(SUPPORT_LIBS)/openal/include/AL \
|
||||||
|
@ -71,17 +71,15 @@ PLAT_POSIX_SOURCES = \
|
||||||
posix/i_cd.cpp \
|
posix/i_cd.cpp \
|
||||||
posix/i_steam.cpp
|
posix/i_steam.cpp
|
||||||
|
|
||||||
PLAT_OCULUSQUEST_SOURCES = \
|
PLAT_NOSDL_SOURCES = \
|
||||||
posix/oculusquest/crashcatcher.c \
|
posix/nosdl/crashcatcher.c \
|
||||||
posix/oculusquest/hardware.cpp \
|
posix/nosdl/hardware.cpp \
|
||||||
posix/oculusquest/i_gui.cpp \
|
posix/nosdl/i_gui.cpp \
|
||||||
posix/oculusquest/i_input.cpp \
|
posix/nosdl/i_joystick.cpp \
|
||||||
posix/oculusquest/i_joystick.cpp \
|
posix/nosdl/i_system.cpp \
|
||||||
posix/oculusquest/i_main.cpp \
|
posix/nosdl/glvideo.cpp \
|
||||||
posix/oculusquest/i_system.cpp \
|
posix/nosdl/video.cpp \
|
||||||
posix/oculusquest/glvideo.cpp \
|
posix/nosdl/st_start.cpp
|
||||||
posix/oculusquest/video.cpp \
|
|
||||||
posix/oculusquest/st_start.cpp
|
|
||||||
|
|
||||||
SWRENDER_SOURCES = \
|
SWRENDER_SOURCES = \
|
||||||
swrenderer/r_swcanvas.cpp \
|
swrenderer/r_swcanvas.cpp \
|
||||||
|
@ -595,7 +593,7 @@ LOCAL_SRC_FILES = \
|
||||||
$(QZDOOM_SRC) \
|
$(QZDOOM_SRC) \
|
||||||
$(ANDROID_SRC_FILES) \
|
$(ANDROID_SRC_FILES) \
|
||||||
$(PLAT_POSIX_SOURCES) \
|
$(PLAT_POSIX_SOURCES) \
|
||||||
$(PLAT_OCULUSQUEST_SOURCES) \
|
$(PLAT_NOSDL_SOURCES) \
|
||||||
$(FASTMATH_SOURCES) \
|
$(FASTMATH_SOURCES) \
|
||||||
$(PCH_SOURCES) \
|
$(PCH_SOURCES) \
|
||||||
x86.cpp \
|
x86.cpp \
|
||||||
|
@ -634,8 +632,8 @@ LOCAL_LDLIBS += -lEGL
|
||||||
# This is stop a linker warning for mp123 lib failing build
|
# This is stop a linker warning for mp123 lib failing build
|
||||||
#LOCAL_LDLIBS += -Wl,--no-warn-shared-textrel
|
#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_STATIC_LIBRARIES := sndfile mpg123 fluidsynth-static libjpeg zlib_lz lzma_lz gdtoa_lz dumb_lz gme_lz bzip2_lz
|
||||||
LOCAL_SHARED_LIBRARIES := openal SDL2 vrapi
|
LOCAL_SHARED_LIBRARIES := openal vrapi
|
||||||
|
|
||||||
LOCAL_STATIC_LIBRARIES +=
|
LOCAL_STATIC_LIBRARIES +=
|
||||||
|
|
||||||
|
|
|
@ -1064,7 +1064,7 @@ void D_DoomLoop ()
|
||||||
if (gametic > lasttic)
|
if (gametic > lasttic)
|
||||||
{
|
{
|
||||||
lasttic = gametic;
|
lasttic = gametic;
|
||||||
I_StartFrame ();
|
//I_StartFrame (); // not used
|
||||||
}
|
}
|
||||||
I_SetFrameTime();
|
I_SetFrameTime();
|
||||||
|
|
||||||
|
@ -2339,6 +2339,9 @@ static void CheckCmdLine()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
|
// The command line arguments.
|
||||||
|
FArgs *Args;
|
||||||
|
|
||||||
void VR_DoomMain(int argc, char** argv)
|
void VR_DoomMain(int argc, char** argv)
|
||||||
{
|
{
|
||||||
progdir = "/sdcard/QzDoom/";
|
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
|
#endif // NO_SEND_STATS
|
||||||
|
|
|
@ -418,7 +418,7 @@ namespace s3d
|
||||||
leftEyeView.submitFrame();
|
leftEyeView.submitFrame();
|
||||||
rightEyeView.submitFrame();
|
rightEyeView.submitFrame();
|
||||||
|
|
||||||
submitFrame(&frameDesc);
|
submitFrame(&tracking);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mAngleFromRadians(double radians)
|
static int mAngleFromRadians(double radians)
|
||||||
|
@ -639,7 +639,6 @@ namespace s3d
|
||||||
|
|
||||||
|
|
||||||
//Get controller state here
|
//Get controller state here
|
||||||
ovrTracking2 tracking;
|
|
||||||
getHMDOrientation(&tracking);
|
getHMDOrientation(&tracking);
|
||||||
|
|
||||||
//Set up stuff used in the tracking code
|
//Set up stuff used in the tracking code
|
||||||
|
@ -649,8 +648,6 @@ namespace s3d
|
||||||
doomYawDegrees = GLRenderer->mAngles.Yaw.Degrees;
|
doomYawDegrees = GLRenderer->mAngles.Yaw.Degrees;
|
||||||
getTrackedRemotesOrientation(vr_control_scheme);
|
getTrackedRemotesOrientation(vr_control_scheme);
|
||||||
|
|
||||||
frameDesc = setupFrameDescriptor(&tracking);
|
|
||||||
|
|
||||||
/* player_t* player = r_viewpoint.camera ? r_viewpoint.camera->player : nullptr;
|
/* player_t* player = r_viewpoint.camera ? r_viewpoint.camera->player : nullptr;
|
||||||
{
|
{
|
||||||
LSMatrix44 mat;
|
LSMatrix44 mat;
|
||||||
|
|
|
@ -102,7 +102,7 @@ protected:
|
||||||
mutable int cachedViewwidth, cachedViewheight, cachedViewwindowx, cachedViewwindowy;
|
mutable int cachedViewwidth, cachedViewheight, cachedViewwindowx, cachedViewwindowy;
|
||||||
mutable F2DDrawer * cached2DDrawer;
|
mutable F2DDrawer * cached2DDrawer;
|
||||||
mutable F2DDrawer * crossHairDrawer;
|
mutable F2DDrawer * crossHairDrawer;
|
||||||
mutable ovrSubmitFrameDescription2 frameDesc;
|
mutable ovrTracking2 tracking;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef Stereo3DMode super;
|
typedef Stereo3DMode super;
|
||||||
|
|
|
@ -19,9 +19,9 @@ class OpenGLFrameBuffer : public Win32GLFrameBuffer
|
||||||
typedef Win32GLFrameBuffer Super;
|
typedef Win32GLFrameBuffer Super;
|
||||||
#else
|
#else
|
||||||
//#include "sdlglvideo.h"
|
//#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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -53,17 +53,8 @@ static void CATCH(int a, int b, int c, int d, int e)
|
||||||
|
|
||||||
int glesLoad = 3; // TODO fix this!
|
int glesLoad = 3; // TODO fix this!
|
||||||
|
|
||||||
void* SDL_GL_GetProcAddress(const char* proc);
|
|
||||||
static void *MOBILE_GetProcAddress(const char* name)
|
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;
|
static void* h = NULL;
|
||||||
|
|
||||||
if (h == NULL)
|
if (h == NULL)
|
||||||
|
@ -80,7 +71,7 @@ static void *MOBILE_GetProcAddress(const char* name)
|
||||||
}
|
}
|
||||||
else if( glesLoad == 3 )
|
else if( glesLoad == 3 )
|
||||||
{
|
{
|
||||||
return SDL_GL_GetProcAddress( name );
|
h = dlopen("libGLESv3.so", RTLD_LAZY | RTLD_LOCAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h == NULL)
|
if (h == NULL)
|
||||||
|
@ -95,7 +86,7 @@ static void *MOBILE_GetProcAddress(const char* name)
|
||||||
|
|
||||||
if( glesLoad == 1 )
|
if( glesLoad == 1 )
|
||||||
sprintf(newName,"jwzgles_%s",name);
|
sprintf(newName,"jwzgles_%s",name);
|
||||||
else if( glesLoad == 2 )
|
else
|
||||||
sprintf(newName,"%s",name);
|
sprintf(newName,"%s",name);
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -117,66 +108,7 @@ static void *MOBILE_GetProcAddress(const char* name)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#define IntGetProcAddress(name) MOBILE_GetProcAddress((const char*)name)
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
int ogl_ext_ARB_buffer_storage = ogl_LOAD_FAILED;
|
int ogl_ext_ARB_buffer_storage = ogl_LOAD_FAILED;
|
||||||
int ogl_ext_ARB_shader_storage_buffer_object = 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;
|
typedef Win32GLFrameBuffer Super;
|
||||||
#else
|
#else
|
||||||
#include "glvideo.h"
|
#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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -253,8 +253,8 @@ bool DMenu::CallMenuEvent(int mkey, bool fromcontroller)
|
||||||
|
|
||||||
static void SetMouseCapture(bool on)
|
static void SetMouseCapture(bool on)
|
||||||
{
|
{
|
||||||
if (on) I_SetMouseCapture();
|
// if (on) I_SetMouseCapture();
|
||||||
else I_ReleaseMouseCapture();
|
// else I_ReleaseMouseCapture();
|
||||||
}
|
}
|
||||||
DEFINE_ACTION_FUNCTION_NATIVE(DMenu, SetMouseCapture, SetMouseCapture)
|
DEFINE_ACTION_FUNCTION_NATIVE(DMenu, SetMouseCapture, SetMouseCapture)
|
||||||
{
|
{
|
||||||
|
@ -382,7 +382,7 @@ void M_ActivateMenu(DMenu *menu)
|
||||||
if (CurrentMenu != nullptr && CurrentMenu->mMouseCapture)
|
if (CurrentMenu != nullptr && CurrentMenu->mMouseCapture)
|
||||||
{
|
{
|
||||||
CurrentMenu->mMouseCapture = false;
|
CurrentMenu->mMouseCapture = false;
|
||||||
I_ReleaseMouseCapture();
|
//I_ReleaseMouseCapture();
|
||||||
}
|
}
|
||||||
CurrentMenu = menu;
|
CurrentMenu = menu;
|
||||||
GC::WriteBarrier(CurrentMenu);
|
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 --------------------------------------------------------------------
|
// CODE --------------------------------------------------------------------
|
||||||
|
|
||||||
OculusQuestGLVideo::OculusQuestGLVideo (int parm)
|
NoSDLGLVideo::NoSDLGLVideo (int parm)
|
||||||
{
|
{
|
||||||
IteratorBits = 0;
|
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();
|
if (GLRenderer != NULL) GLRenderer->FlushTextures();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OculusQuestGLVideo::StartModeIterator (int bits, bool fs)
|
void NoSDLGLVideo::StartModeIterator (int bits, bool fs)
|
||||||
{
|
{
|
||||||
IteratorMode = 0;
|
IteratorMode = 0;
|
||||||
IteratorBits = bits;
|
IteratorBits = bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OculusQuestGLVideo::NextMode (int *width, int *height, bool *letterbox)
|
bool NoSDLGLVideo::NextMode (int *width, int *height, bool *letterbox)
|
||||||
{
|
{
|
||||||
if (IteratorBits != 8)
|
if (IteratorBits != 8)
|
||||||
return false;
|
return false;
|
||||||
|
@ -151,7 +145,7 @@ bool OculusQuestGLVideo::NextMode (int *width, int *height, bool *letterbox)
|
||||||
return false;
|
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 retry = 0;
|
||||||
static int owidth, oheight;
|
static int owidth, oheight;
|
||||||
|
@ -169,7 +163,7 @@ DFrameBuffer *OculusQuestGLVideo::CreateFrameBuffer (int width, int height, bool
|
||||||
// flashAmount = 0;
|
// flashAmount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
OculusQuestBaseFB *fb;
|
NoSDLBaseFB *fb;
|
||||||
const char *hwBuffers = Args->CheckValue("-hwbuffers");
|
const char *hwBuffers = Args->CheckValue("-hwbuffers");
|
||||||
int buffers = 1;
|
int buffers = 1;
|
||||||
if (hwBuffers)
|
if (hwBuffers)
|
||||||
|
@ -183,11 +177,11 @@ DFrameBuffer *OculusQuestGLVideo::CreateFrameBuffer (int width, int height, bool
|
||||||
return fb;
|
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
|
// FIXME: Is it possible to do this without completely destroying the old
|
||||||
// interface?
|
// interface?
|
||||||
|
@ -196,7 +190,7 @@ bool OculusQuestGLVideo::SetResolution (int width, int height, int bits)
|
||||||
if (GLRenderer != NULL) GLRenderer->FlushTextures();
|
if (GLRenderer != NULL) GLRenderer->FlushTextures();
|
||||||
I_ShutdownGraphics();
|
I_ShutdownGraphics();
|
||||||
|
|
||||||
Video = new OculusQuestGLVideo(0);
|
Video = new NoSDLGLVideo(0);
|
||||||
if (Video == NULL) I_FatalError ("Failed to initialize display");
|
if (Video == NULL) I_FatalError ("Failed to initialize display");
|
||||||
|
|
||||||
#if (defined(WINDOWS)) || defined(WIN32)
|
#if (defined(WINDOWS)) || defined(WIN32)
|
||||||
|
@ -219,7 +213,7 @@ bool OculusQuestGLVideo::SetResolution (int width, int height, int bits)
|
||||||
extern "C" extern int glesLoad;
|
extern "C" extern int glesLoad;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void OculusQuestGLVideo::SetupPixelFormat(bool allowsoftware, int multisample, const int *glver)
|
void NoSDLGLVideo::SetupPixelFormat(bool allowsoftware, int multisample, const int *glver)
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef __MOBILE__
|
#ifdef __MOBILE__
|
||||||
|
@ -252,73 +246,73 @@ void OculusQuestGLVideo::SetupPixelFormat(bool allowsoftware, int multisample, c
|
||||||
|
|
||||||
// FrameBuffer implementation -----------------------------------------------
|
// FrameBuffer implementation -----------------------------------------------
|
||||||
|
|
||||||
OculusQuestGLFB::OculusQuestGLFB (void *, int width, int height, int, int, bool fullscreen, bool bgra)
|
NoSDLGLFB::NoSDLGLFB (void *, int width, int height, int, int, bool fullscreen, bool bgra)
|
||||||
: OculusQuestBaseFB (width, height, 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++;
|
m_Lock++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OculusQuestGLFB::Lock ()
|
bool NoSDLGLFB::Lock ()
|
||||||
{
|
{
|
||||||
return Lock(false);
|
return Lock(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OculusQuestGLFB::Unlock ()
|
void NoSDLGLFB::Unlock ()
|
||||||
{
|
{
|
||||||
--m_Lock;
|
--m_Lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OculusQuestGLFB::IsLocked ()
|
bool NoSDLGLFB::IsLocked ()
|
||||||
{
|
{
|
||||||
return m_Lock>0;// true;
|
return m_Lock>0;// true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OculusQuestGLFB::IsFullscreen ()
|
bool NoSDLGLFB::IsFullscreen ()
|
||||||
{
|
{
|
||||||
return true;
|
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;
|
uint32_t w, h;
|
||||||
Android_GetScreenRes(&w, &h);
|
Android_GetScreenRes(&w, &h);
|
||||||
|
@ -326,7 +320,7 @@ int OculusQuestGLFB::GetClientWidth()
|
||||||
return width;
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
int OculusQuestGLFB::GetClientHeight()
|
int NoSDLGLFB::GetClientHeight()
|
||||||
{
|
{
|
||||||
uint32_t w, h;
|
uint32_t w, h;
|
||||||
Android_GetScreenRes(&w, &h);
|
Android_GetScreenRes(&w, &h);
|
||||||
|
@ -334,7 +328,7 @@ int OculusQuestGLFB::GetClientHeight()
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OculusQuestGLFB::ScaleCoordsFromWindow(int16_t &x, int16_t &y)
|
void NoSDLGLFB::ScaleCoordsFromWindow(int16_t &x, int16_t &y)
|
||||||
{
|
{
|
||||||
uint32_t w, h;
|
uint32_t w, h;
|
||||||
Android_GetScreenRes(&w, &h);
|
Android_GetScreenRes(&w, &h);
|
|
@ -12,11 +12,11 @@ EXTERN_CVAR (Color, dimcolor)
|
||||||
struct FRenderer;
|
struct FRenderer;
|
||||||
FRenderer *gl_CreateInterface();
|
FRenderer *gl_CreateInterface();
|
||||||
|
|
||||||
class SDLGLVideo : public IVideo
|
class NoSDLGLVideo : public IVideo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SDLGLVideo (int parm);
|
NoSDLGLVideo (int parm);
|
||||||
~SDLGLVideo ();
|
~NoSDLGLVideo ();
|
||||||
|
|
||||||
EDisplayType GetDisplayType () { return DISPLAY_Both; }
|
EDisplayType GetDisplayType () { return DISPLAY_Both; }
|
||||||
void SetWindowedScale (float scale);
|
void SetWindowedScale (float scale);
|
||||||
|
@ -34,23 +34,22 @@ private:
|
||||||
int IteratorBits;
|
int IteratorBits;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SDLBaseFB : public DFrameBuffer
|
class NoSDLBaseFB : public DFrameBuffer
|
||||||
{
|
{
|
||||||
typedef DFrameBuffer Super;
|
typedef DFrameBuffer Super;
|
||||||
public:
|
public:
|
||||||
using DFrameBuffer::DFrameBuffer;
|
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:
|
public:
|
||||||
// this must have the same parameters as the Windows version, even if they are not used!
|
// 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);
|
NoSDLGLFB (void *hMonitor, int width, int height, int, int, bool fullscreen, bool bgra);
|
||||||
~SDLGLFB ();
|
~NoSDLGLFB ();
|
||||||
|
|
||||||
void ForceBuffering (bool force);
|
void ForceBuffering (bool force);
|
||||||
bool Lock(bool buffered);
|
bool Lock(bool buffered);
|
||||||
|
@ -66,14 +65,14 @@ public:
|
||||||
|
|
||||||
void NewRefreshRate ();
|
void NewRefreshRate ();
|
||||||
|
|
||||||
friend class SDLGLVideo;
|
friend class NoSDLGLVideo;
|
||||||
|
|
||||||
int GetClientWidth();
|
int GetClientWidth();
|
||||||
int GetClientHeight();
|
int GetClientHeight();
|
||||||
|
|
||||||
virtual void ScaleCoordsFromWindow(int16_t &x, int16_t &y);
|
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(); }
|
virtual int GetTrueHeight() { return GetClientHeight(); }
|
||||||
protected:
|
protected:
|
||||||
|
@ -81,13 +80,13 @@ protected:
|
||||||
void ResetGammaTable();
|
void ResetGammaTable();
|
||||||
void InitializeState();
|
void InitializeState();
|
||||||
|
|
||||||
SDLGLFB () {}
|
NoSDLGLFB () {}
|
||||||
uint8_t GammaTable[3][256];
|
uint8_t GammaTable[3][256];
|
||||||
bool UpdatePending;
|
bool UpdatePending;
|
||||||
|
|
||||||
SDL_Window *Screen;
|
// SDL_Window *Screen;
|
||||||
|
|
||||||
SDL_GLContext GLContext;
|
// SDL_GLContext GLContext;
|
||||||
|
|
||||||
void UpdateColors ();
|
void UpdateColors ();
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <SDL.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
@ -100,25 +99,17 @@ void I_ShutdownGraphics ()
|
||||||
}
|
}
|
||||||
if (Video)
|
if (Video)
|
||||||
delete Video, Video = NULL;
|
delete Video, Video = NULL;
|
||||||
|
|
||||||
SDL_QuitSubSystem (SDL_INIT_VIDEO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void I_InitGraphics ()
|
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;
|
UCVarValue val;
|
||||||
|
|
||||||
val.Bool = !!Args->CheckParm ("-devparm");
|
val.Bool = !!Args->CheckParm ("-devparm");
|
||||||
ticker.SetGenericRepDefault (val, CVAR_Bool);
|
ticker.SetGenericRepDefault (val, CVAR_Bool);
|
||||||
|
|
||||||
currentrenderer = vid_renderer;
|
currentrenderer = vid_renderer;
|
||||||
Video = new OculusQuestGLVideo(0);
|
Video = new NoSDLGLVideo(0);
|
||||||
|
|
||||||
if (Video == NULL)
|
if (Video == NULL)
|
||||||
I_FatalError ("Failed to initialize display");
|
I_FatalError ("Failed to initialize display");
|
||||||
|
@ -153,28 +144,7 @@ void I_CreateRenderer()
|
||||||
|
|
||||||
DFrameBuffer *I_SetMode (int &width, int &height, DFrameBuffer *old)
|
DFrameBuffer *I_SetMode (int &width, int &height, DFrameBuffer *old)
|
||||||
{
|
{
|
||||||
bool fs = false;
|
return Video->CreateFrameBuffer (width, height, swtruecolor, true, old);
|
||||||
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)
|
bool I_CheckResolution (int width, int height, int bits)
|
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <SDL.h>
|
//#include <SDL.h>
|
||||||
|
|
||||||
#include "bitmap.h"
|
#include "bitmap.h"
|
||||||
#include "v_palette.h"
|
#include "v_palette.h"
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
|
|
||||||
bool I_SetCursor(FTexture *cursorpic)
|
bool I_SetCursor(FTexture *cursorpic)
|
||||||
{
|
{
|
||||||
static SDL_Cursor *cursor;
|
/* static SDL_Cursor *cursor;
|
||||||
static SDL_Surface *cursorSurface;
|
static SDL_Surface *cursorSurface;
|
||||||
|
|
||||||
if (cursorpic != NULL && cursorpic->UseType != ETextureType::Null)
|
if (cursorpic != NULL && cursorpic->UseType != ETextureType::Null)
|
||||||
|
@ -81,6 +81,6 @@ bool I_SetCursor(FTexture *cursorpic)
|
||||||
SDL_FreeSurface(cursorSurface);
|
SDL_FreeSurface(cursorSurface);
|
||||||
cursorSurface = NULL;
|
cursorSurface = NULL;
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
/*
|
/*
|
||||||
** i_gui.cpp
|
** i_joystick.cpp
|
||||||
**
|
**
|
||||||
**---------------------------------------------------------------------------
|
**---------------------------------------------------------------------------
|
||||||
** Copyright 2008 Randy Heit
|
** Copyright 2005-2016 Randy Heit
|
||||||
** All rights reserved.
|
** All rights reserved.
|
||||||
**
|
**
|
||||||
** Redistribution and use in source and binary forms, with or without
|
** 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>
|
CUSTOM_CVAR(Bool, joy_background, false, CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_NOINITCALL)
|
||||||
|
|
||||||
#include "bitmap.h"
|
|
||||||
#include "v_palette.h"
|
|
||||||
#include "textures.h"
|
|
||||||
|
|
||||||
bool I_SetCursor(FTexture *cursorpic)
|
|
||||||
{
|
{
|
||||||
static SDL_Cursor *cursor;
|
Printf("This won't take effect until " GAMENAME " is restarted.\n");
|
||||||
static SDL_Surface *cursorSurface;
|
}
|
||||||
|
|
||||||
if (cursorpic != NULL && cursorpic->UseType != ETextureType::Null)
|
class NoSDLInputJoystickManager
|
||||||
{
|
{
|
||||||
// Must be no larger than 32x32.
|
public:
|
||||||
if (cursorpic->GetWidth() > 32 || cursorpic->GetHeight() > 32)
|
NoSDLInputJoystickManager()
|
||||||
{
|
{
|
||||||
return false;
|
}
|
||||||
}
|
~NoSDLInputJoystickManager()
|
||||||
|
{
|
||||||
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));
|
|
||||||
|
void AddAxes(float axes[5])
|
||||||
SDL_LockSurface(cursorSurface);
|
{
|
||||||
uint8_t buffer[32*32*4];
|
}
|
||||||
memset(buffer, 0, 32*32*4);
|
|
||||||
FBitmap bmp(buffer, 32*4, 32, 32);
|
void GetDevices(TArray<IJoystickConfig *> &sticks)
|
||||||
cursorpic->CopyTrueColorPixels(&bmp, 0, 0);
|
{
|
||||||
memcpy(cursorSurface->pixels, bmp.GetPixels(), 32*32*4);
|
}
|
||||||
SDL_UnlockSurface(cursorSurface);
|
|
||||||
|
void ProcessInput() const
|
||||||
if (cursor)
|
{
|
||||||
SDL_FreeCursor (cursor);
|
}
|
||||||
cursor = SDL_CreateColorCursor (cursorSurface, 0, 0);
|
};
|
||||||
SDL_SetCursor (cursor);
|
|
||||||
}
|
static NoSDLInputJoystickManager *JoystickManager;
|
||||||
else
|
|
||||||
{
|
void I_StartupJoysticks()
|
||||||
if (cursor)
|
{
|
||||||
{
|
JoystickManager = new NoSDLInputJoystickManager();
|
||||||
SDL_SetCursor (NULL);
|
}
|
||||||
SDL_FreeCursor (cursor);
|
void I_ShutdownJoysticks()
|
||||||
cursor = NULL;
|
{
|
||||||
}
|
if(JoystickManager)
|
||||||
if (cursorSurface != NULL)
|
{
|
||||||
{
|
delete JoystickManager;
|
||||||
SDL_FreeSurface(cursorSurface);
|
}
|
||||||
cursorSurface = NULL;
|
}
|
||||||
}
|
|
||||||
}
|
void I_GetJoysticks(TArray<IJoystickConfig *> &sticks)
|
||||||
return true;
|
{
|
||||||
|
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 ------------------------------------------------------------
|
// HEADER FILES ------------------------------------------------------------
|
||||||
|
|
||||||
#include <SDL.h>
|
//#include <SDL.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
|
@ -34,7 +34,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#include <SDL.h>
|
//#include <SDL.h>
|
||||||
|
|
||||||
#include "doomerrors.h"
|
#include "doomerrors.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -152,7 +152,7 @@ void Mac_I_FatalError(const char* errortext);
|
||||||
void Linux_I_FatalError(const char* errortext)
|
void Linux_I_FatalError(const char* errortext)
|
||||||
{
|
{
|
||||||
// Close window or exit fullscreen and release mouse capture
|
// Close window or exit fullscreen and release mouse capture
|
||||||
SDL_Quit();
|
//SDL_Quit();
|
||||||
|
|
||||||
const char *str;
|
const char *str;
|
||||||
if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0)
|
if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0)
|
||||||
|
@ -174,7 +174,7 @@ void Linux_I_FatalError(const char* errortext)
|
||||||
FString message;
|
FString message;
|
||||||
message << GAMESIG " ";
|
message << GAMESIG " ";
|
||||||
message << GetVersionString() << ": No IWAD found";
|
message << GetVersionString() << ": No IWAD found";
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, message, errortext, NULL);
|
//SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, message, errortext, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -452,17 +452,17 @@ int I_FindAttr(findstate_t* const fileinfo)
|
||||||
|
|
||||||
void I_PutInClipboard (const char *str)
|
void I_PutInClipboard (const char *str)
|
||||||
{
|
{
|
||||||
SDL_SetClipboardText(str);
|
//SDL_SetClipboardText(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
FString I_GetFromClipboard (bool use_primary_selection)
|
FString I_GetFromClipboard (bool use_primary_selection)
|
||||||
{
|
{
|
||||||
if(char *ret = SDL_GetClipboardText())
|
/* if(char *ret = SDL_GetClipboardText())
|
||||||
{
|
{
|
||||||
FString text(ret);
|
FString text(ret);
|
||||||
SDL_free(ret);
|
SDL_free(ret);
|
||||||
return text;
|
return text;
|
||||||
}
|
}*/
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,15 +105,15 @@ CUSTOM_CVAR (Float, bgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
|
|
||||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||||
|
|
||||||
static cycle_t BlitCycles;
|
//static cycle_t BlitCycles;
|
||||||
static cycle_t SDLFlipCycles;
|
//static cycle_t SDLFlipCycles;
|
||||||
|
|
||||||
// CODE --------------------------------------------------------------------
|
// CODE --------------------------------------------------------------------
|
||||||
|
|
||||||
// FrameBuffer implementation -----------------------------------------------
|
// FrameBuffer implementation -----------------------------------------------
|
||||||
|
|
||||||
OculusQuestFB::OculusQuestFB (int width, int height, bool bgra, bool fullscreen, SDL_Window *oldwin)
|
NoSDLFB::NoSDLFB (int width, int height, bool bgra, bool fullscreen/*, SDL_Window *oldwin*/)
|
||||||
: OculusQuestBaseFB (width, height, bgra)
|
: NoSDLBaseFB (width, height, bgra)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -124,8 +124,8 @@ OculusQuestFB::OculusQuestFB (int width, int height, bool bgra, bool fullscreen,
|
||||||
FlashAmount = 0;
|
FlashAmount = 0;
|
||||||
|
|
||||||
|
|
||||||
Renderer = NULL;
|
// Renderer = NULL;
|
||||||
Texture = NULL;
|
// Texture = NULL;
|
||||||
|
|
||||||
for (i = 0; i < 256; i++)
|
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();
|
return DFrameBuffer::IsValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
int OculusQuestFB::GetPageCount ()
|
int NoSDLFB::GetPageCount ()
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OculusQuestFB::Lock (bool buffered)
|
bool NoSDLFB::Lock (bool buffered)
|
||||||
{
|
{
|
||||||
return DSimpleCanvas::Lock ();
|
return DSimpleCanvas::Lock ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OculusQuestFB::Relock ()
|
bool NoSDLFB::Relock ()
|
||||||
{
|
{
|
||||||
return DSimpleCanvas::Lock ();
|
return DSimpleCanvas::Lock ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OculusQuestFB::Unlock ()
|
void NoSDLFB::Unlock ()
|
||||||
{
|
{
|
||||||
--LockCount;
|
--LockCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OculusQuestFB::Update ()
|
void NoSDLFB::Update ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void OculusQuestFB::UpdateColors ()
|
void NoSDLFB::UpdateColors ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PalEntry *OculusQuestFB::GetPalette ()
|
PalEntry *NoSDLFB::GetPalette ()
|
||||||
{
|
{
|
||||||
return SourcePalette;
|
return SourcePalette;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OculusQuestFB::UpdatePalette ()
|
void NoSDLFB::UpdatePalette ()
|
||||||
{
|
{
|
||||||
NeedPalUpdate = true;
|
NeedPalUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OculusQuestFB::SetGamma (float gamma)
|
bool NoSDLFB::SetGamma (float gamma)
|
||||||
{
|
{
|
||||||
Gamma = gamma;
|
Gamma = gamma;
|
||||||
NeedGammaUpdate = true;
|
NeedGammaUpdate = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OculusQuestFB::SetFlash (PalEntry rgb, int amount)
|
bool NoSDLFB::SetFlash (PalEntry rgb, int amount)
|
||||||
{
|
{
|
||||||
Flash = rgb;
|
Flash = rgb;
|
||||||
FlashAmount = amount;
|
FlashAmount = amount;
|
||||||
|
@ -203,35 +203,35 @@ bool OculusQuestFB::SetFlash (PalEntry rgb, int amount)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OculusQuestFB::GetFlash (PalEntry &rgb, int &amount)
|
void NoSDLFB::GetFlash (PalEntry &rgb, int &amount)
|
||||||
{
|
{
|
||||||
rgb = Flash;
|
rgb = Flash;
|
||||||
amount = FlashAmount;
|
amount = FlashAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Q: Should I gamma adjust the returned palette?
|
// 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;
|
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;
|
uint32_t w, h;
|
||||||
Android_GetScreenRes(&w, &h);
|
Android_GetScreenRes(&w, &h);
|
|
@ -2,12 +2,12 @@
|
||||||
#include "v_video.h"
|
#include "v_video.h"
|
||||||
#include "glvideo.h"
|
#include "glvideo.h"
|
||||||
|
|
||||||
class OculusQuestFB : public OculusQuestBaseFB
|
class NoSDLFB : public NoSDLBaseFB
|
||||||
{
|
{
|
||||||
typedef OculusQuestBaseFB Super;
|
typedef NoSDLBaseFB Super;
|
||||||
public:
|
public:
|
||||||
OculusQuestFB(int width, int height, bool bgra, bool fullscreen, SDL_Window *oldwin);
|
NoSDLFB(int width, int height, bool bgra, bool fullscreen/*, SDL_Window *oldwin*/);
|
||||||
~OculusQuestFB();
|
~NoSDLFB();
|
||||||
|
|
||||||
bool Lock(bool buffer);
|
bool Lock(bool buffer);
|
||||||
void Unlock();
|
void Unlock();
|
||||||
|
@ -25,12 +25,12 @@ public:
|
||||||
int GetPageCount();
|
int GetPageCount();
|
||||||
bool IsFullscreen();
|
bool IsFullscreen();
|
||||||
|
|
||||||
friend class OculusQuestGLVideo;
|
friend class NoSDLGLVideo;
|
||||||
|
|
||||||
virtual void SetVSync(bool vsync);
|
virtual void SetVSync(bool vsync);
|
||||||
virtual void ScaleCoordsFromWindow(int16_t &x, int16_t &y);
|
virtual void ScaleCoordsFromWindow(int16_t &x, int16_t &y);
|
||||||
|
|
||||||
SDL_Window *GetSDLWindow() override { return Screen; }
|
// SDL_Window *GetSDLWindow() override { return Screen; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PalEntry SourcePalette[256];
|
PalEntry SourcePalette[256];
|
||||||
|
@ -40,13 +40,13 @@ private:
|
||||||
float Gamma;
|
float Gamma;
|
||||||
bool UpdatePending;
|
bool UpdatePending;
|
||||||
|
|
||||||
SDL_Window *Screen;
|
// SDL_Window *Screen;
|
||||||
SDL_Renderer *Renderer;
|
// SDL_Renderer *Renderer;
|
||||||
union
|
// union
|
||||||
{
|
// {
|
||||||
SDL_Texture *Texture;
|
// SDL_Texture *Texture;
|
||||||
SDL_Surface *Surface;
|
// SDL_Surface *Surface;
|
||||||
};
|
// };
|
||||||
|
|
||||||
bool UsingRenderer;
|
bool UsingRenderer;
|
||||||
bool NeedPalUpdate;
|
bool NeedPalUpdate;
|
||||||
|
@ -56,5 +56,5 @@ private:
|
||||||
void UpdateColors();
|
void UpdateColors();
|
||||||
void ResetSDLRenderer();
|
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 <string.h>
|
||||||
#include <stdint.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 };
|
enum { opnNoteOnMaxTime = 40000 };
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue