mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 11:28:56 +00:00
Remove unused DirectX-related files
This commit is contained in:
parent
89515e25c3
commit
99a39d645d
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Descent 3
|
||||
* Copyright (C) 2024 Parallax Software
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/* SDLMain.m - main entry point for our Cocoa-ized SDL app
|
||||
Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
|
||||
Non-NIB-Code & other changes: Max Horn <max@quendi.de>
|
||||
|
||||
Feel free to customize this file to suit your needs
|
||||
*/
|
||||
|
||||
#ifndef _SDLMain_h_
|
||||
#define _SDLMain_h_
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface SDLMain : NSObject
|
||||
@end
|
||||
|
||||
#endif /* _SDLMain_h_ */
|
@ -1,381 +0,0 @@
|
||||
/* SDLMain.m - main entry point for our Cocoa-ized SDL app
|
||||
Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
|
||||
Non-NIB-Code & other changes: Max Horn <max@quendi.de>
|
||||
|
||||
Feel free to customize this file to suit your needs
|
||||
*/
|
||||
|
||||
#include "SDL.h"
|
||||
#include "SDLMain.h"
|
||||
#include <sys/param.h> /* for MAXPATHLEN */
|
||||
#include <unistd.h>
|
||||
|
||||
/* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
|
||||
but the method still is there and works. To avoid warnings, we declare
|
||||
it ourselves here. */
|
||||
@interface NSApplication(SDL_Missing_Methods)
|
||||
- (void)setAppleMenu:(NSMenu *)menu;
|
||||
@end
|
||||
|
||||
/* Use this flag to determine whether we use SDLMain.nib or not */
|
||||
#define SDL_USE_NIB_FILE 0
|
||||
|
||||
/* Use this flag to determine whether we use CPS (docking) or not */
|
||||
#define SDL_USE_CPS 1
|
||||
#ifdef SDL_USE_CPS
|
||||
/* Portions of CPS.h */
|
||||
typedef struct CPSProcessSerNum
|
||||
{
|
||||
UInt32 lo;
|
||||
UInt32 hi;
|
||||
} CPSProcessSerNum;
|
||||
|
||||
extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
|
||||
extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
|
||||
extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
|
||||
|
||||
#endif /* SDL_USE_CPS */
|
||||
|
||||
static int gArgc;
|
||||
static char **gArgv;
|
||||
static BOOL gFinderLaunch;
|
||||
static BOOL gCalledAppMainline = FALSE;
|
||||
|
||||
static NSString *getApplicationName(void)
|
||||
{
|
||||
const NSDictionary *dict;
|
||||
NSString *appName = 0;
|
||||
|
||||
/* Determine the application name */
|
||||
dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
|
||||
if (dict)
|
||||
appName = [dict objectForKey: @"CFBundleName"];
|
||||
|
||||
if (![appName length])
|
||||
appName = [[NSProcessInfo processInfo] processName];
|
||||
|
||||
return appName;
|
||||
}
|
||||
|
||||
#if SDL_USE_NIB_FILE
|
||||
/* A helper category for NSString */
|
||||
@interface NSString (ReplaceSubString)
|
||||
- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
|
||||
@end
|
||||
#endif
|
||||
|
||||
@interface NSApplication (SDLApplication)
|
||||
@end
|
||||
|
||||
@implementation NSApplication (SDLApplication)
|
||||
/* Invoked from the Quit menu item */
|
||||
- (void)terminate:(id)sender
|
||||
{
|
||||
/* Post a SDL_QUIT event */
|
||||
SDL_Event event;
|
||||
event.type = SDL_QUIT;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
@end
|
||||
|
||||
/* The main class of the application, the application's delegate */
|
||||
@implementation SDLMain
|
||||
|
||||
/* Set the working directory to the .app's parent directory */
|
||||
- (void) setupWorkingDirectory:(BOOL)shouldChdir
|
||||
{
|
||||
if (shouldChdir)
|
||||
{
|
||||
char parentdir[MAXPATHLEN];
|
||||
CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
|
||||
CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
|
||||
if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8 *)parentdir, MAXPATHLEN)) {
|
||||
chdir(parentdir); /* chdir to the binary app's parent */
|
||||
}
|
||||
CFRelease(url);
|
||||
CFRelease(url2);
|
||||
}
|
||||
}
|
||||
|
||||
#if SDL_USE_NIB_FILE
|
||||
|
||||
/* Fix menu to contain the real app name instead of "SDL App" */
|
||||
- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
|
||||
{
|
||||
NSRange aRange;
|
||||
NSEnumerator *enumerator;
|
||||
NSMenuItem *menuItem;
|
||||
|
||||
aRange = [[aMenu title] rangeOfString:@"SDL App"];
|
||||
if (aRange.length != 0)
|
||||
[aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
|
||||
|
||||
enumerator = [[aMenu itemArray] objectEnumerator];
|
||||
while ((menuItem = [enumerator nextObject]))
|
||||
{
|
||||
aRange = [[menuItem title] rangeOfString:@"SDL App"];
|
||||
if (aRange.length != 0)
|
||||
[menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
|
||||
if ([menuItem hasSubmenu])
|
||||
[self fixMenu:[menuItem submenu] withAppName:appName];
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void setApplicationMenu(void)
|
||||
{
|
||||
/* warning: this code is very odd */
|
||||
NSMenu *appleMenu;
|
||||
NSMenuItem *menuItem;
|
||||
NSString *title;
|
||||
NSString *appName;
|
||||
|
||||
appName = getApplicationName();
|
||||
appleMenu = [[NSMenu alloc] initWithTitle:@""];
|
||||
|
||||
/* Add menu items */
|
||||
title = [@"About " stringByAppendingString:appName];
|
||||
[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
|
||||
|
||||
[appleMenu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
title = [@"Hide " stringByAppendingString:appName];
|
||||
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
|
||||
|
||||
menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
|
||||
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
|
||||
|
||||
[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
|
||||
|
||||
[appleMenu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
title = [@"Quit " stringByAppendingString:appName];
|
||||
[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
|
||||
|
||||
|
||||
/* Put menu into the menubar */
|
||||
menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
|
||||
[menuItem setSubmenu:appleMenu];
|
||||
[[NSApp mainMenu] addItem:menuItem];
|
||||
|
||||
/* Tell the application object that this is now the application menu */
|
||||
[NSApp setAppleMenu:appleMenu];
|
||||
|
||||
/* Finally give up our references to the objects */
|
||||
[appleMenu release];
|
||||
[menuItem release];
|
||||
}
|
||||
|
||||
/* Create a window menu */
|
||||
static void setupWindowMenu(void)
|
||||
{
|
||||
NSMenu *windowMenu;
|
||||
NSMenuItem *windowMenuItem;
|
||||
NSMenuItem *menuItem;
|
||||
|
||||
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
|
||||
|
||||
/* "Minimize" item */
|
||||
menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
|
||||
[windowMenu addItem:menuItem];
|
||||
[menuItem release];
|
||||
|
||||
/* Put menu into the menubar */
|
||||
windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
|
||||
[windowMenuItem setSubmenu:windowMenu];
|
||||
[[NSApp mainMenu] addItem:windowMenuItem];
|
||||
|
||||
/* Tell the application object that this is now the window menu */
|
||||
[NSApp setWindowsMenu:windowMenu];
|
||||
|
||||
/* Finally give up our references to the objects */
|
||||
[windowMenu release];
|
||||
[windowMenuItem release];
|
||||
}
|
||||
|
||||
/* Replacement for NSApplicationMain */
|
||||
static void CustomApplicationMain (int argc, char **argv)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
SDLMain *sdlMain;
|
||||
|
||||
/* Ensure the application object is initialised */
|
||||
[NSApplication sharedApplication];
|
||||
|
||||
#ifdef SDL_USE_CPS
|
||||
{
|
||||
CPSProcessSerNum PSN;
|
||||
/* Tell the dock about us */
|
||||
if (!CPSGetCurrentProcess(&PSN))
|
||||
if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
|
||||
if (!CPSSetFrontProcess(&PSN))
|
||||
[NSApplication sharedApplication];
|
||||
}
|
||||
#endif /* SDL_USE_CPS */
|
||||
|
||||
/* Set up the menubar */
|
||||
[NSApp setMainMenu:[[NSMenu alloc] init]];
|
||||
setApplicationMenu();
|
||||
setupWindowMenu();
|
||||
|
||||
/* Create SDLMain and make it the app delegate */
|
||||
sdlMain = [[SDLMain alloc] init];
|
||||
[NSApp setDelegate:sdlMain];
|
||||
|
||||
/* Start the main event loop */
|
||||
[NSApp run];
|
||||
|
||||
[sdlMain release];
|
||||
[pool release];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Catch document open requests...this lets us notice files when the app
|
||||
* was launched by double-clicking a document, or when a document was
|
||||
* dragged/dropped on the app's icon. You need to have a
|
||||
* CFBundleDocumentsType section in your Info.plist to get this message,
|
||||
* apparently.
|
||||
*
|
||||
* Files are added to gArgv, so to the app, they'll look like command line
|
||||
* arguments. Previously, apps launched from the finder had nothing but
|
||||
* an argv[0].
|
||||
*
|
||||
* This message may be received multiple times to open several docs on launch.
|
||||
*
|
||||
* This message is ignored once the app's mainline has been called.
|
||||
*/
|
||||
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
|
||||
{
|
||||
const char *temparg;
|
||||
size_t arglen;
|
||||
char *arg;
|
||||
char **newargv;
|
||||
|
||||
if (!gFinderLaunch) /* MacOS is passing command line args. */
|
||||
return FALSE;
|
||||
|
||||
if (gCalledAppMainline) /* app has started, ignore this document. */
|
||||
return FALSE;
|
||||
|
||||
temparg = [filename UTF8String];
|
||||
arglen = SDL_strlen(temparg) + 1;
|
||||
arg = (char *) SDL_malloc(arglen);
|
||||
if (arg == NULL)
|
||||
return FALSE;
|
||||
|
||||
newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
|
||||
if (newargv == NULL)
|
||||
{
|
||||
SDL_free(arg);
|
||||
return FALSE;
|
||||
}
|
||||
gArgv = newargv;
|
||||
|
||||
SDL_strlcpy(arg, temparg, arglen);
|
||||
gArgv[gArgc++] = arg;
|
||||
gArgv[gArgc] = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Called when the internal event loop has just started running */
|
||||
- (void) applicationDidFinishLaunching: (NSNotification *) note
|
||||
{
|
||||
int status;
|
||||
|
||||
/* Set the working directory to the .app's parent directory */
|
||||
[self setupWorkingDirectory:gFinderLaunch];
|
||||
|
||||
#if SDL_USE_NIB_FILE
|
||||
/* Set the main menu to contain the real app name instead of "SDL App" */
|
||||
[self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
|
||||
#endif
|
||||
|
||||
/* Hand off to main application code */
|
||||
gCalledAppMainline = TRUE;
|
||||
status = SDL_main (gArgc, gArgv);
|
||||
|
||||
/* We're done, thank you for playing */
|
||||
exit(status);
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation NSString (ReplaceSubString)
|
||||
|
||||
- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
|
||||
{
|
||||
unsigned int bufferSize;
|
||||
unsigned int selfLen = [self length];
|
||||
unsigned int aStringLen = [aString length];
|
||||
unichar *buffer;
|
||||
NSRange localRange;
|
||||
NSString *result;
|
||||
|
||||
bufferSize = selfLen + aStringLen - aRange.length;
|
||||
buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar));
|
||||
|
||||
/* Get first part into buffer */
|
||||
localRange.location = 0;
|
||||
localRange.length = aRange.location;
|
||||
[self getCharacters:buffer range:localRange];
|
||||
|
||||
/* Get middle part into buffer */
|
||||
localRange.location = 0;
|
||||
localRange.length = aStringLen;
|
||||
[aString getCharacters:(buffer+aRange.location) range:localRange];
|
||||
|
||||
/* Get last part into buffer */
|
||||
localRange.location = aRange.location + aRange.length;
|
||||
localRange.length = selfLen - localRange.location;
|
||||
[self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
|
||||
|
||||
/* Build output string */
|
||||
result = [NSString stringWithCharacters:buffer length:bufferSize];
|
||||
|
||||
NSDeallocateMemoryPages(buffer, bufferSize);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
#ifdef main
|
||||
# undef main
|
||||
#endif
|
||||
|
||||
|
||||
/* Main entry point to executable - should *not* be SDL_main! */
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
/* Copy the arguments into a global variable */
|
||||
/* This is passed if we are launched by double-clicking */
|
||||
if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
|
||||
gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
|
||||
gArgv[0] = argv[0];
|
||||
gArgv[1] = NULL;
|
||||
gArgc = 1;
|
||||
gFinderLaunch = YES;
|
||||
} else {
|
||||
int i;
|
||||
gArgc = argc;
|
||||
gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
|
||||
for (i = 0; i <= argc; i++)
|
||||
gArgv[i] = argv[i];
|
||||
gFinderLaunch = NO;
|
||||
}
|
||||
|
||||
#if SDL_USE_NIB_FILE
|
||||
NSApplicationMain (argc, argv);
|
||||
#else
|
||||
CustomApplicationMain (argc, argv);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,640 +0,0 @@
|
||||
/*
|
||||
* Descent 3
|
||||
* Copyright (C) 2024 Parallax Software
|
||||
*
|
||||
* 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/>.
|
||||
|
||||
--- HISTORICAL COMMENTS FOLLOW ---
|
||||
|
||||
*
|
||||
* Linux Main and any Linux specific code that MUST be in the main application
|
||||
* goes here.
|
||||
* $NoKeywords: $
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <csignal>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "program.h"
|
||||
#include "descent.h"
|
||||
#include "application.h"
|
||||
#include "appdatabase.h"
|
||||
#include "args.h"
|
||||
#include "init.h"
|
||||
|
||||
#include "osiris_dll.h"
|
||||
#include "loki_utils.h"
|
||||
|
||||
|
||||
#include "log.h"
|
||||
|
||||
extern bool ddio_mouseGrabbed;
|
||||
const char *DMFCGetString(int d);
|
||||
// void *x = (void *) DMFCGetString; // just force a reference to dmfc.so ...
|
||||
|
||||
char *__orig_pwd = NULL;
|
||||
|
||||
bool linux_permit_gamma = false;
|
||||
|
||||
struct cmdLineArg {
|
||||
const char *lng;
|
||||
char sht;
|
||||
const char *comment;
|
||||
};
|
||||
|
||||
static cmdLineArg d3ArgTable[] = {
|
||||
#ifdef __PERMIT_LINUX_GLIDE
|
||||
{"rend_opengl", 'G', "Use OpenGL for 3D rendering."},
|
||||
{"rend_glide", 'L', "Use Glide for 3D rendering."},
|
||||
#endif
|
||||
|
||||
#ifdef __PERMIT_PLAYMVE
|
||||
{"playmve", 'p', "Play a specified movie."},
|
||||
#endif
|
||||
|
||||
{"glidelibrary", 'l', "Select Glide rendering library."},
|
||||
{"gllibrary", 'g', "Select OpenGL rendering library."},
|
||||
{"cobra", 'R', "Enable Cobra chair support."},
|
||||
|
||||
#if (!defined(DEMO))
|
||||
{"dedicated", 'd', "Run as a dedicated netgame server."},
|
||||
{"nointro", 'n', "Skip intro movie."},
|
||||
#endif
|
||||
|
||||
{"joystick", 'j', "Specify a joystick (number)."},
|
||||
{"nomousegrab", 'm', "Don't grab the mouse."},
|
||||
|
||||
{"deadzone0", 'D', "Specify a joystick deadzone (0.0 to 1.0)"},
|
||||
|
||||
{"gspyfile", 'S', "Specify a GameSpy config file."},
|
||||
{"fastdemo", 'Q', "Run demos as fast as possible."},
|
||||
{"framecap", 'F', "Specify a framecap (for dedicated server)."},
|
||||
|
||||
{"tempdir", 'P', "Specify directory for temporary files."},
|
||||
|
||||
#if (defined(_USE_OGL_LISTS_OPTIONAL))
|
||||
{"gllists", '\0', "Use OpenGL lists."},
|
||||
#endif
|
||||
|
||||
#ifdef __PERMIT_GL_LOGGING
|
||||
{"gllogging", '\0', "to be removed."},
|
||||
#endif
|
||||
|
||||
{"nomultitexture", 't', "Disable multitexturing."},
|
||||
{"nopackedpixels", 'x', "Disable packed pixels."},
|
||||
{"glfog", 'o', "Enable OpenGL fog."},
|
||||
{"nogamma", 'M', "Disable gamma support."},
|
||||
{"glinfo", 'I', "Display info about OpenGL library."}
|
||||
};
|
||||
|
||||
static volatile char already_tried_signal_cleanup = 0;
|
||||
|
||||
#if (defined DEMO)
|
||||
#define GAME_NAME_EXT "_demo"
|
||||
#define GAME_VERS_EXT " Demo"
|
||||
#elif (defined OEM)
|
||||
#define GAME_NAME_EXT "_limited"
|
||||
#define GAME_VERS_EXT " Limited Edition"
|
||||
#else
|
||||
#define GAME_NAME_EXT ""
|
||||
#define GAME_VERS_EXT ""
|
||||
#endif
|
||||
|
||||
// #define DEDICATED
|
||||
namespace {
|
||||
extern "C" {
|
||||
char game_version_buffer[150];
|
||||
char *game_version = game_version_buffer;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void ddio_InternalClose(); // needed for emergency cleanup.
|
||||
|
||||
#ifdef __PERMIT_LINUX_GLIDE
|
||||
void glide_Close(void);
|
||||
#endif
|
||||
|
||||
void just_exit(void) {
|
||||
ddio_InternalClose(); // try to reset serial port.
|
||||
|
||||
#ifdef __PERMIT_LINUX_GLIDE
|
||||
if (Renderer_type == RENDERER_GLIDE)
|
||||
glide_Close();
|
||||
#endif
|
||||
|
||||
SDL_Quit();
|
||||
#ifdef __LINUX__
|
||||
sync(); // just in case.
|
||||
#endif
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
#ifdef __LINUX__
|
||||
void fatal_signal_handler(int signum) {
|
||||
switch (signum) {
|
||||
case SIGHUP:
|
||||
case SIGTRAP:
|
||||
case SIGABRT:
|
||||
case SIGBUS:
|
||||
case SIGFPE:
|
||||
case SIGILL:
|
||||
case SIGQUIT:
|
||||
case SIGSEGV:
|
||||
case SIGTERM:
|
||||
case SIGVTALRM:
|
||||
case SIGINT:
|
||||
if (already_tried_signal_cleanup)
|
||||
fprintf(stderr, "Recursive signal cleanup! Hard exit! AHHGGGG!\n");
|
||||
else {
|
||||
already_tried_signal_cleanup = 1;
|
||||
fprintf(stderr, "SIGNAL %d caught, aborting\n", signum);
|
||||
just_exit();
|
||||
} // else
|
||||
break;
|
||||
case SIGXCPU:
|
||||
case SIGXFSZ:
|
||||
break;
|
||||
}
|
||||
|
||||
_exit(-10);
|
||||
}
|
||||
|
||||
void safe_signal_handler(int signum) {}
|
||||
|
||||
void install_signal_handlers() {
|
||||
struct sigaction sact, fact;
|
||||
|
||||
memset(&sact, 0, sizeof(sact));
|
||||
memset(&fact, 0, sizeof(fact));
|
||||
sact.sa_handler = safe_signal_handler;
|
||||
fact.sa_handler = fatal_signal_handler;
|
||||
|
||||
if (sigaction(SIGHUP, &fact, NULL))
|
||||
fprintf(stderr, "SIG: Unable to install SIGHUP\n");
|
||||
if (sigaction(SIGABRT, &fact, NULL))
|
||||
fprintf(stderr, "SIG: Unable to install SIGABRT\n");
|
||||
if (sigaction(SIGINT, &fact, NULL))
|
||||
fprintf(stderr, "SIG: Unable to install SIGINT\n");
|
||||
if (sigaction(SIGBUS, &fact, NULL))
|
||||
fprintf(stderr, "SIG: Unable to install SIGBUS\n");
|
||||
if (sigaction(SIGFPE, &fact, NULL))
|
||||
fprintf(stderr, "SIG: Unable to install SIGFPE\n");
|
||||
if (sigaction(SIGILL, &fact, NULL))
|
||||
fprintf(stderr, "SIG: Unable to install SIGILL\n");
|
||||
if (sigaction(SIGQUIT, &fact, NULL))
|
||||
fprintf(stderr, "SIG: Unable to install SIGQUIT\n");
|
||||
if (sigaction(SIGSEGV, &fact, NULL))
|
||||
fprintf(stderr, "SIG: Unable to install SIGSEGV\n");
|
||||
if (sigaction(SIGTERM, &fact, NULL))
|
||||
fprintf(stderr, "SIG: Unable to install SIGTERM\n");
|
||||
if (sigaction(SIGXCPU, &fact, NULL))
|
||||
fprintf(stderr, "SIG: Unable to install SIGXCPU\n");
|
||||
if (sigaction(SIGXFSZ, &fact, NULL))
|
||||
fprintf(stderr, "SIG: Unable to install SIGXFSZ\n");
|
||||
if (sigaction(SIGVTALRM, &fact, NULL))
|
||||
fprintf(stderr, "SIG: Unable to install SIGVTALRM\n");
|
||||
if (sigaction(SIGTRAP, &fact, NULL))
|
||||
fprintf(stderr, "SIG: Unable to install SIGTRAP\n");
|
||||
}
|
||||
#else
|
||||
void install_signal_handlers() {}
|
||||
#endif
|
||||
// ---------------------------------------------------------------------------
|
||||
// Define our operating system specific extensions to the gameos system
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class oeD3LnxApp : public oeLnxApplication {
|
||||
bool shutdown, final_shutdown;
|
||||
int old_screen_mode;
|
||||
|
||||
public:
|
||||
oeD3LnxApp(unsigned flags);
|
||||
virtual ~oeD3LnxApp() { final_shutdown = true; };
|
||||
|
||||
void run() { Descent3(); };
|
||||
};
|
||||
|
||||
oeD3LnxApp::oeD3LnxApp(unsigned flags) : oeLnxApplication(flags) {
|
||||
Descent = this;
|
||||
shutdown = false;
|
||||
final_shutdown = false;
|
||||
}
|
||||
|
||||
class oeD3LnxDatabase : public oeLnxAppDatabase {
|
||||
public:
|
||||
oeD3LnxDatabase();
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// D3LnxDatabase operating system specific initialization
|
||||
oeD3LnxDatabase::oeD3LnxDatabase() : oeLnxAppDatabase() {
|
||||
char path[_MAX_PATH];
|
||||
char netpath[_MAX_PATH];
|
||||
|
||||
// put directories into database
|
||||
|
||||
#ifdef EDITOR
|
||||
create_record("D3Edit");
|
||||
#else
|
||||
create_record("Descent3");
|
||||
#endif
|
||||
|
||||
char *dir = getenv("D3_LOCAL");
|
||||
char *netdir = getenv("D3_DIR");
|
||||
|
||||
if (!dir)
|
||||
strcpy(path, loki_getdatapath()); //"/usr/local/games/descent3");
|
||||
else
|
||||
strcpy(path, dir);
|
||||
|
||||
if (!netdir)
|
||||
strcpy(netpath, "");
|
||||
else
|
||||
strcpy(netpath, netdir);
|
||||
|
||||
write("local directory", path, strlen(path) + 1);
|
||||
write("net directory", netpath, strlen(netpath) + 1);
|
||||
Database = this;
|
||||
}
|
||||
|
||||
static void register_d3_args() {
|
||||
loki_register_stdoptions();
|
||||
|
||||
for (int i = 0; i < sizeof(d3ArgTable) / sizeof(d3ArgTable[0]); i++) {
|
||||
loki_registeroption(d3ArgTable[i].lng, d3ArgTable[i].sht, d3ArgTable[i].comment);
|
||||
} // for
|
||||
} // register_d3_args
|
||||
|
||||
int sdlKeyFilter(const SDL_Event *event);
|
||||
int sdlMouseButtonUpFilter(const SDL_Event *event);
|
||||
int sdlMouseButtonDownFilter(const SDL_Event *event);
|
||||
int sdlMouseWheelFilter(const SDL_Event *event);
|
||||
int sdlMouseMotionFilter(const SDL_Event *event);
|
||||
|
||||
int SDLCALL d3SDLEventFilter(void *userdata, SDL_Event *event) {
|
||||
switch (event->type) {
|
||||
case SDL_KEYUP:
|
||||
case SDL_KEYDOWN:
|
||||
return (sdlKeyFilter(event));
|
||||
case SDL_JOYBALLMOTION:
|
||||
case SDL_MOUSEMOTION:
|
||||
return (sdlMouseMotionFilter(event));
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
return (sdlMouseButtonUpFilter(event));
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
return (sdlMouseButtonDownFilter(event));
|
||||
case SDL_MOUSEWHEEL:
|
||||
return (sdlMouseWheelFilter(event));
|
||||
case SDL_QUIT:
|
||||
SDL_Quit();
|
||||
_exit(0);
|
||||
break;
|
||||
default: break;
|
||||
} // switch
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
void StartDedicatedServer();
|
||||
|
||||
#ifdef BETAEXPIRE
|
||||
static void check_beta() {
|
||||
fprintf(stderr, "\n\n\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
|
||||
if (time(NULL) > (BETAEXPIRE + 30 * 24 * 60 * 60)) {
|
||||
fprintf(stderr, "Thanks for participating in the Descent 3 beta test!\n"
|
||||
"This beta copy has now expired.\n"
|
||||
"Please visit http://www.lokigames.com/ for a non-beta release.\n");
|
||||
_exit(0);
|
||||
} // if
|
||||
else {
|
||||
fprintf(stderr, "Warning: This is a beta version of DESCENT 3.\n"
|
||||
"Please report any bugs in fenris: http://fenris.lokigames.com/\n");
|
||||
} // else
|
||||
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "\n\n\n");
|
||||
} // check_beta
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Main
|
||||
// creates all the OS objects and then runs Descent 3.
|
||||
// this is all this function should do.
|
||||
// ---------------------------------------------------------------------------
|
||||
#ifdef WIN32
|
||||
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szCmdLine, int nCmdShow) {
|
||||
strupr(szCmdLine);
|
||||
GatherArgs(szCmdLine);
|
||||
#else
|
||||
int main(int argc, char *argv[]) {
|
||||
__orig_pwd = getcwd(NULL, 0);
|
||||
GatherArgs(argv);
|
||||
#endif
|
||||
|
||||
/* Setup the logging system */
|
||||
InitLog();
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
setbuf(stderr, NULL);
|
||||
|
||||
#ifdef BETAEXPIRE
|
||||
// IMPORTANT - TAKE ME OUT - FIXME -------------------------------
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "**** Please remove -DBETAEXPIRE from the Makefile! ******"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
check_beta();
|
||||
#endif
|
||||
|
||||
#ifdef __DUMP_MVE_TO_DISK
|
||||
// IMPORTANT - TAKE ME OUT - FIXME -------------------------------
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "** Please remove -D__DUMP_MVE_TO_DISK from the Makefile! **"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
#warning "***********************************************************"
|
||||
|
||||
fprintf(stderr, "\n\n\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, " Warning, this binary dumps movies to disk. This is BAD.\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "***************************************************************************\n");
|
||||
fprintf(stderr, "\n\n\n");
|
||||
#endif
|
||||
|
||||
/*
|
||||
if ( (argv[1] != NULL) && (strcasecmp(argv[1], "--nettest")) )
|
||||
_exit(nettest_Main(argc, argv));
|
||||
*/
|
||||
|
||||
// rcg01152000 need this for mpeg playback currently.
|
||||
// rcg02232004 probably don't need this anymore.
|
||||
// if (getenv("SDL_VIDEO_YUV_HWACCEL") == NULL)
|
||||
// putenv("SDL_VIDEO_YUV_HWACCEL=0");
|
||||
|
||||
|
||||
snprintf(game_version_buffer, sizeof(game_version_buffer), "%d.%d.%d%s %s", D3_MAJORVER, D3_MINORVER, D3_BUILD,
|
||||
D3_GIT_HASH, GAME_VERS_EXT);
|
||||
|
||||
loki_setgamename("descent3" GAME_NAME_EXT, game_version_buffer, "Descent 3");
|
||||
|
||||
snprintf(game_version_buffer, sizeof(game_version_buffer),
|
||||
"\n\n"
|
||||
"Descent 3 %s %s v%d.%d.%d %s\n"
|
||||
"Copyright (C) 1999 Outrage Entertainment, Inc.\n",
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
"macOS",
|
||||
#else
|
||||
"Linux",
|
||||
#endif
|
||||
|
||||
#ifdef DEDICATED
|
||||
"Dedicated Server",
|
||||
#elif DEMO
|
||||
"Demo",
|
||||
#else
|
||||
"Client",
|
||||
#endif
|
||||
D3_MAJORVER, D3_MINORVER, D3_BUILD, D3_GIT_HASH);
|
||||
|
||||
game_version += 2; // skip those first newlines for loki_initialize.
|
||||
|
||||
register_d3_args();
|
||||
loki_initialize();
|
||||
|
||||
int x;
|
||||
|
||||
/*
|
||||
x = FindArg("-nettest");
|
||||
if (x)
|
||||
{
|
||||
if (x != 1)
|
||||
printf(" --nettest must be first command if you use it.\n");
|
||||
_exit(0);
|
||||
} // if
|
||||
*/
|
||||
|
||||
#ifdef DEDICATED
|
||||
setenv("SDL_VIDEODRIVER", "dummy", 1);
|
||||
#endif
|
||||
|
||||
int rc = SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "SDL: SDL_Init() failed! rc == (%d).\n", rc);
|
||||
fprintf(stderr, "SDL_GetError() reports \"%s\".\n", SDL_GetError());
|
||||
return (0);
|
||||
} // if
|
||||
|
||||
// atexit(SDL_Quit);
|
||||
|
||||
// !!! FIXME: Don't use an event filter!
|
||||
SDL_SetEventFilter(d3SDLEventFilter, NULL);
|
||||
install_signal_handlers();
|
||||
|
||||
// build the command line as one long string, seperated by spaces...
|
||||
/*
|
||||
char commandline[256];
|
||||
strcpy(commandline,"");
|
||||
for(int i=0;i<argc;i++){
|
||||
strcat(commandline,argv[i]);
|
||||
strcat(commandline," ");
|
||||
}
|
||||
|
||||
GatherArgs (commandline);
|
||||
*/
|
||||
int winArg = FindArgChar("-windowed", 'w');
|
||||
int fsArg = FindArgChar("-fullscreen", 'f');
|
||||
|
||||
if ((fsArg) && (winArg)) {
|
||||
fprintf(stderr, "ERROR: %s AND %s specified!\n", GameArgs[winArg], GameArgs[fsArg]);
|
||||
return (0);
|
||||
} // if
|
||||
|
||||
if (FindArg("-game_checksum")) {
|
||||
extern tOSIRISModuleInit Osiris_module_init;
|
||||
extern void Osiris_CreateModuleInitStruct(tOSIRISModuleInit * st);
|
||||
extern uint32_t Osiris_CreateGameChecksum(void);
|
||||
|
||||
Osiris_CreateModuleInitStruct(&Osiris_module_init);
|
||||
uint32_t checksum = Osiris_CreateGameChecksum();
|
||||
printf("Descent 3\n");
|
||||
printf("Game Checksum: %u\n", checksum);
|
||||
return (0);
|
||||
} else {
|
||||
/*initialize our OS Object. This could be a game dependant OS object, or a default OS object.
|
||||
once we create it, if successful, we can start the game.
|
||||
*/
|
||||
int flags = 0;
|
||||
|
||||
if (!FindArgChar("-dedicated", 'd')) {
|
||||
#ifndef DEDICATED
|
||||
// check for a renderer
|
||||
|
||||
if ((FindArgChar("-windowed", 'w')) && (FindArgChar("-fullscreen", 'f'))) {
|
||||
fprintf(stderr, "Error: Both windowed and fullscreen mode requested.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __PERMIT_LINUX_GLIDE
|
||||
int opengl_rend = (FindArgChar("+rend_opengl", 'G')) ? 1 : 0;
|
||||
int glide_rend = (FindArgChar("+rend_glide", 'L')) ? 1 : 0;
|
||||
|
||||
if (!glide_rend && !opengl_rend) {
|
||||
// fprintf(stderr,"Error: --dedicated or renderer flag required\n");
|
||||
// return 0;
|
||||
|
||||
// ryan sez: Glide by default, beeyatch.
|
||||
glide_rend = 1;
|
||||
}
|
||||
|
||||
// check for multiple renderers defined
|
||||
if (glide_rend + opengl_rend > 1) {
|
||||
fprintf(stderr, "Error: Too many renderer's defined, use only one\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
//print out renderer
|
||||
if(glide_rend)
|
||||
{
|
||||
fprintf(stderr,"Renderer: GLiDE\n");
|
||||
}
|
||||
if(opengl_rend)
|
||||
{
|
||||
fprintf(stderr,"Renderer: OpenGL\n");
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
if (FindArgChar("-nomousegrab", 'm')) {
|
||||
flags |= APPFLAG_NOMOUSECAPTURE;
|
||||
}
|
||||
|
||||
ddio_mouseGrabbed = (FindArgChar("-nomousegrab", 'm') == 0);
|
||||
|
||||
if (!FindArg("-sharedmemory")) {
|
||||
flags |= APPFLAG_NOSHAREDMEMORY;
|
||||
}
|
||||
|
||||
#ifdef __PERMIT_LINUX_GLIDE
|
||||
if (FindArgChar("+rend_opengl", 'G')) {
|
||||
flags |= APPFLAG_WINDOWEDMODE;
|
||||
}
|
||||
#else
|
||||
flags |= APPFLAG_WINDOWEDMODE;
|
||||
#endif
|
||||
|
||||
if (!FindArg("-nodgamouse")) {
|
||||
flags |= APPFLAG_DGAMOUSE;
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "Error: \"--dedicated\" or \"-d\" flag required\n");
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
} else {
|
||||
// Dedicated Server Mode
|
||||
flags |= OEAPP_CONSOLE;
|
||||
|
||||
// service flag overrides others here in the group
|
||||
if (FindArg("-service")) {
|
||||
flags |= APPFLAG_USESERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
bool run_d3 = true;
|
||||
#ifdef __LINUX__
|
||||
if (flags & APPFLAG_USESERVICE) {
|
||||
run_d3 = false;
|
||||
pid_t np = fork();
|
||||
if (np == -1) {
|
||||
fprintf(stderr, "Unable to fork process\n");
|
||||
}
|
||||
if (np == 0) {
|
||||
run_d3 = true;
|
||||
np = setsid();
|
||||
pid_t pp = getpid();
|
||||
printf("Successfully forked process [new sid=%d pid=%d]\n", np, pp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (run_d3) {
|
||||
oeD3LnxApp d3(flags);
|
||||
oeD3LnxDatabase dbase;
|
||||
StartDedicatedServer();
|
||||
PreInitD3Systems();
|
||||
|
||||
d3.init();
|
||||
d3.run();
|
||||
}
|
||||
}
|
||||
|
||||
just_exit();
|
||||
return 0;
|
||||
}
|
@ -1,541 +0,0 @@
|
||||
/*
|
||||
* Descent 3
|
||||
* Copyright (C) 2024 Parallax Software
|
||||
*
|
||||
* 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 <windows.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "mono.h"
|
||||
#include "descent.h"
|
||||
#include "texture.h"
|
||||
#include "application.h"
|
||||
#include "appdatabase.h"
|
||||
#include "pserror.h"
|
||||
#include "args.h"
|
||||
#include "init.h"
|
||||
#include "dedicated_server.h"
|
||||
#include "resource.h"
|
||||
#include "log.h"
|
||||
|
||||
const char *English_strings[] = {"Descent 3 under Windows NT requires version 4.0 or greater of NT to run.",
|
||||
"Descent 3 requires Windows 9x, NT 4.0 or greater to run.",
|
||||
"",
|
||||
"You must install DirectX through the Descent 3 Launcher before continuing.",
|
||||
"You must install at least Service Pack 3 to run Descent 3 under Windows NT 4.0.",
|
||||
"Failed to retrieve DirectX version.",
|
||||
"Descent 3 requires DirectX 3 or greater on this machine.",
|
||||
"This version of Windows NT doesn't have DirectX 3 or greater installed.",
|
||||
"Your processor and system must support Katmai to run this game."};
|
||||
|
||||
const char *French_strings[] = {
|
||||
"L'exécution de Descent 3 sous Windows NT nécessite la version 4.0 ou ultérieure de NT.",
|
||||
"L'exécution de Descent 3 nécessite Windows 9x, NT 4.0 ou ultérieur.",
|
||||
"",
|
||||
"Vous devez installer DirectX a partir de l'installateur Descent 3 avant de continuer.",
|
||||
"Vous devez installer au moins Service Pack 3 pour exécuter Descent 3 sous Windows NT 4.0.",
|
||||
"+chec de la récupération de DirectX.",
|
||||
"Descent 3 nécessite DirectX 3 ou ultérieur sur ce système.",
|
||||
"Cette version de Windows NT n'est pas munie de DirectX 3 ou ultérieur.",
|
||||
"Votre processeur et votre système doivent prendre en charge Katmai pour exécuter ce jeu."};
|
||||
|
||||
const char *German_strings[] = {
|
||||
"Descent3 unter Windows NT benötigt fnr die Ausführung die NT-Version 4.0 oder höher",
|
||||
"Descent 3 benötigt fnr die Ausführung Windows 9x, NT 4.0 oder höher.",
|
||||
"",
|
||||
"Sie müssen DirectX über den Descent 3 Starter installieren, bevor Sie fortsetzen.",
|
||||
"Sie müssen mindestens Service Paket 3 installieren, um Descent 3 unter Windows NT 4.0 ausführen zu können.",
|
||||
"Die DirectX Version konnte nicht abgerufen werden.",
|
||||
"Descent 3 benötigt DirectX 3 oder höher auf diesem Computer.",
|
||||
"In dieser Windows NT Version ist DirectX 3 oder höher nicht installiert.",
|
||||
"Ihr Prozessor und System mu¯ Katmai unterstützen, um dieses Spiel auszuführen."};
|
||||
|
||||
const char *Italian_strings[] = {
|
||||
"Descent 3 per Windows NT richiede la versione NT 4.0 o superiore.",
|
||||
"Descent 3 funziona solo con Windows 9x, NT 4.0 o superiore.",
|
||||
"",
|
||||
"Prima di prosegure installare DirectX per mezzo di Descent 3 Launcher.",
|
||||
"Per utilizzare Descent 3 sotto Windows NT 4.0 occorre installare Service Pack 3 o sup.",
|
||||
"Versione di DirectX non trovata.",
|
||||
"Descent 3 richiede l'installazione di DirectX 3 o superiore.",
|
||||
"DirectX 3 o superiore non trovato in questa versione di Windows NT.",
|
||||
"Per questo gioco occorrono un processore e un sistema che supportino Katmai."};
|
||||
|
||||
const char *Spanish_strings[] = {"Descent 3 bajo Windows NT requiere version 4.0 o mejor para correr.",
|
||||
"Descent 3 requiere Windows 9x, NT 4.0 o mejor para correr.",
|
||||
"",
|
||||
"Debe instalar DirectX desde el lanzador de Descent 3 antes de continuar.",
|
||||
"Debe instalar por lo menos Service Pack 3 para correr Descent 3 bajo Windows NT 4.0.",
|
||||
"Falla en la detección de la versión de DirectX.",
|
||||
"Descent 3 requiere DirectX 3 o mejor en el ordenador.",
|
||||
"Esta versión de Windows NT no tiene DirectX 3 o mejor instalado.",
|
||||
"Vuestro procesador y ordenador deben soportar Katmai para correr este juego."};
|
||||
|
||||
#if 0
|
||||
const char *Polish_strings[] = {
|
||||
"Aby uruchomić grę Descent 3 potrzebujesz Windows NT w wersji 4.0 lub nowszej.",
|
||||
"Descent 3 wymaga Windows 9x albo Windows NT w wersji 4.0 lub nowszej.",
|
||||
"",
|
||||
"Zanim uruchomisz grę, musisz zainstalować DirectX przy u¨yciu programu startowego.",
|
||||
"Musisz zainstalować co najmniej Service Pack 3, aby uruchomić grę Descent 3 pod Windows NT 4.0.",
|
||||
"Nie udało siˆ odczytać numeru wersji sterowników DirectX.",
|
||||
"Descent 3 wymaga sterowników DirectX 3 lub nowszych.",
|
||||
"Ta wersja Windows NT nie ma zainstalowanych sterownik¢w DirectX 3 lub nowszych.",
|
||||
"Twój procesor musi obsługiwać rozkazy Katmai, aby uruchomić grę."
|
||||
};
|
||||
#endif
|
||||
|
||||
static int m_resource_language = 0;
|
||||
|
||||
#define VENDOR_INTEL 0
|
||||
#define VENDOR_AMD 1
|
||||
#define VENDOR_CYRIX 2
|
||||
#define VENDOR_UMC 3
|
||||
#define VENDOR_CENTAUR 4
|
||||
#define VENDOR_NEXGEN 5
|
||||
#define VENDOR_UNKNOWN 6
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Define our operating system specific extensions to the gameos system
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
class oeD3Win32App : public oeWin32Application {
|
||||
bool shutdown, final_shutdown;
|
||||
int old_screen_mode;
|
||||
HANDLE hAppMutex;
|
||||
|
||||
public:
|
||||
oeD3Win32App(unsigned flags, HInstance hinst) : oeWin32Application(PRODUCT_NAME, flags, hinst) {
|
||||
Descent = this;
|
||||
shutdown = false;
|
||||
final_shutdown = false;
|
||||
hAppMutex = CreateMutex(NULL, FALSE, "D3MainMutexName");
|
||||
if (!hAppMutex) {
|
||||
exit(1);
|
||||
}
|
||||
win32_SetResourceDLL(NULL);
|
||||
};
|
||||
|
||||
virtual ~oeD3Win32App() {
|
||||
win32_SetResourceDLL(NULL);
|
||||
if (hAppMutex) {
|
||||
CloseHandle(hAppMutex);
|
||||
hAppMutex = NULL;
|
||||
}
|
||||
|
||||
final_shutdown = true;
|
||||
};
|
||||
|
||||
void run() { Descent3(); }
|
||||
|
||||
// returns 0 if we pass to default window handler.
|
||||
virtual LResult WndProc(HWnd hwnd, unsigned msg, WParam wParam, LParam lParam) override {
|
||||
if (final_shutdown) {
|
||||
return oeWin32Application::WndProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
switch (msg) {
|
||||
case WM_ACTIVATEAPP: {
|
||||
if (wParam == FALSE) {
|
||||
this->deactivate();
|
||||
|
||||
if (!shutdown) {
|
||||
ShutdownD3();
|
||||
shutdown = true;
|
||||
if (m_Flags & OEAPP_FULLSCREEN) {
|
||||
ShowWindow((HWND)hwnd, SW_MINIMIZE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this->activate();
|
||||
|
||||
if (shutdown) {
|
||||
ShowWindow((HWND)hwnd, SW_RESTORE);
|
||||
RestartD3();
|
||||
shutdown = false;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
return oeWin32Application::WndProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
};
|
||||
|
||||
class oeD3Win32Database : public oeWin32AppDatabase {
|
||||
public:
|
||||
oeD3Win32Database();
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// D3WinDatabase operating system specific initialization
|
||||
|
||||
oeD3Win32Database::oeD3Win32Database() : oeWin32AppDatabase() {
|
||||
char path[_MAX_PATH];
|
||||
bool res;
|
||||
|
||||
// create descent III entry if it doesn't exit.
|
||||
|
||||
#if defined(EDITOR)
|
||||
lstrcat(m_Basepath, "\\D3Edit");
|
||||
#elif defined(DEMO)
|
||||
lstrcat(m_Basepath, "\\Descent3Demo2");
|
||||
#elif defined(OEM_V3)
|
||||
lstrcat(m_Basepath, "\\Descent3_OEM_V3");
|
||||
#elif defined(OEM_KATMAI)
|
||||
lstrcat(m_Basepath, "\\Descent3_OEM_KM");
|
||||
#elif defined(OEM)
|
||||
lstrcat(m_Basepath, "\\Descent3_OEM");
|
||||
#else
|
||||
lstrcat(m_Basepath, "\\Descent3");
|
||||
#endif
|
||||
|
||||
res = lookup_record(m_Basepath);
|
||||
if (!res) {
|
||||
res = create_record(m_Basepath);
|
||||
if (!res) {
|
||||
Error("Failed to create registry key for %s", PRODUCT_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
// create version key.
|
||||
lstrcpy(path, m_Basepath);
|
||||
lstrcat(path, "\\Version");
|
||||
res = lookup_record(path);
|
||||
if (!res) {
|
||||
res = create_record(path);
|
||||
if (!res) {
|
||||
Error("Failed to create registry key for %s", PRODUCT_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EDITOR // Maybe this code should be in the editor startup
|
||||
lstrcpy(path, m_Basepath);
|
||||
lstrcat(path, "\\editor");
|
||||
res = lookup_record(path);
|
||||
if (!res) {
|
||||
res = create_record(path);
|
||||
if (!res) {
|
||||
Error("Failed to create registry key for %s.", PRODUCT_NAME);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
res = lookup_record(m_Basepath);
|
||||
|
||||
// Get net directory for manage system
|
||||
char netpath[_MAX_PATH];
|
||||
lstrcpy(netpath, "");
|
||||
#ifndef EDITOR
|
||||
if (FindArg("-update")) // For the game-only build, require -update to update data
|
||||
#endif
|
||||
// NOTE LINK TO ABOVE IF
|
||||
{
|
||||
char *netdir = getenv("D3_DIR");
|
||||
if (netdir)
|
||||
lstrcpy(netpath, netdir);
|
||||
}
|
||||
write("net directory", netpath, lstrlen(netpath) + 1);
|
||||
|
||||
Database = this;
|
||||
}
|
||||
|
||||
bool Win32JoystickCalibrate() {
|
||||
// sorry.
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFO si;
|
||||
BOOL flag;
|
||||
// DWORD dwval;
|
||||
|
||||
memset(&si, 0, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
si.dwFlags = STARTF_USESHOWWINDOW;
|
||||
si.wShowWindow = SW_SHOW;
|
||||
|
||||
flag = CreateProcess(NULL, "rundll32.exe shell32.dll,Control_RunDLL joy.cpl", NULL, NULL, FALSE,
|
||||
NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
|
||||
if (!flag) {
|
||||
return false;
|
||||
} else {
|
||||
tWin32AppInfo appinfo;
|
||||
HWND hWnd;
|
||||
|
||||
Descent->get_info(&appinfo);
|
||||
hWnd = (HWND)appinfo.hwnd;
|
||||
|
||||
WaitForInputIdle(pi.hProcess, INFINITE);
|
||||
ShowWindow(hWnd, SW_MINIMIZE);
|
||||
Descent->delay(0.5f);
|
||||
|
||||
while (WaitForSingleObject(pi.hProcess, 0) != WAIT_OBJECT_0) {
|
||||
extern void D3DeferHandler(bool is_active);
|
||||
D3DeferHandler(false);
|
||||
}
|
||||
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
ShowWindow(hWnd, SW_MAXIMIZE);
|
||||
Descent->delay(0.5f);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef EDITOR
|
||||
// ---------------------------------------------------------------------------
|
||||
// WinMainInitEditor
|
||||
// creates all the App objects for the editor.
|
||||
// this is all this function should do.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#pragma message("Compiling editor WinMain substitute function.")
|
||||
|
||||
void WinMainInitEditor(unsigned hwnd, unsigned hinst) {
|
||||
tWin32AppInfo appinfo;
|
||||
|
||||
appinfo.hwnd = (HWnd)hwnd;
|
||||
appinfo.hinst = (HInstance)hinst;
|
||||
appinfo.flags = OEAPP_WINDOWED;
|
||||
|
||||
Descent = new oeWin32Application(&appinfo);
|
||||
Database = new oeD3Win32Database;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void D3End() {
|
||||
if (Descent) {
|
||||
delete Descent;
|
||||
}
|
||||
}
|
||||
|
||||
// Localization defines
|
||||
#define LANGUAGE_ENGLISH 0
|
||||
#define LANGUAGE_GERMAN 1
|
||||
#define LANGUAGE_SPANISH 2
|
||||
#define LANGUAGE_ITALIAN 3
|
||||
#define LANGUAGE_FRENCH 4
|
||||
|
||||
inline void MessageBoxStr(int id) {
|
||||
const char *txt = "Unknown string";
|
||||
|
||||
id--;
|
||||
if (id >= 0 && id <= 8) {
|
||||
switch (m_resource_language) {
|
||||
case LANGUAGE_FRENCH:
|
||||
txt = French_strings[id];
|
||||
break;
|
||||
case LANGUAGE_GERMAN:
|
||||
txt = German_strings[id];
|
||||
break;
|
||||
case LANGUAGE_ITALIAN:
|
||||
txt = Italian_strings[id];
|
||||
break;
|
||||
case LANGUAGE_SPANISH:
|
||||
txt = Spanish_strings[id];
|
||||
break;
|
||||
default:
|
||||
txt = English_strings[id];
|
||||
}
|
||||
}
|
||||
|
||||
// win32_GetStringResource(id, str, sizeof(str));
|
||||
|
||||
MessageBox(NULL, txt, "Outrage Error", MB_OK);
|
||||
}
|
||||
|
||||
// Returns true if this machine can support katmai instructions
|
||||
bool SupportsKatmai() {
|
||||
// Note: we don't do anything Katmai specific -- just always enable it.
|
||||
return true;
|
||||
}
|
||||
|
||||
// DirectX check, NT 4.0, 5.0, Win95 check.
|
||||
bool Win32SystemCheck(HINSTANCE hInst) {
|
||||
tWin32OS os;
|
||||
int major, minor, build;
|
||||
bool retval;
|
||||
|
||||
os = oeWin32Application::version(&major, &minor, &build);
|
||||
|
||||
if (os == WinNT) {
|
||||
if (major < 4) {
|
||||
MessageBoxStr(ID_TXT_WINNT);
|
||||
return false;
|
||||
}
|
||||
} else if (os != Win9x) {
|
||||
MessageBoxStr(ID_TXT_WIN32);
|
||||
return false;
|
||||
}
|
||||
|
||||
// perform DirectX system check.
|
||||
retval = false;
|
||||
|
||||
// This function simply returns the interger version value of DirectX
|
||||
// installed on the user's system
|
||||
LONG lResult;
|
||||
HKEY hKey = NULL;
|
||||
int version_num = 0;
|
||||
|
||||
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectX", NULL, KEY_QUERY_VALUE, &hKey);
|
||||
if (lResult == ERROR_SUCCESS) {
|
||||
char version[32];
|
||||
DWORD dwType, dwLen = 32;
|
||||
lResult = RegQueryValueEx(hKey, "Version", NULL, &dwType, (uint8_t *)version, &dwLen);
|
||||
if (lResult == ERROR_SUCCESS) {
|
||||
version_num = atoi(strstr(version, ".") + 1);
|
||||
} else {
|
||||
int val;
|
||||
DWORD dwType, dwLen = 4;
|
||||
|
||||
lResult = RegQueryValueEx(hKey, "InstalledVersion", NULL, &dwType, (uint8_t *)&val, &dwLen);
|
||||
if (lResult == ERROR_SUCCESS) {
|
||||
version_num = val;
|
||||
}
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
} else {
|
||||
// if we don't have DSETUP.DLL and we are under Win95, then we're in trouble.
|
||||
if (os == Win9x) {
|
||||
MessageBoxStr(ID_TXT_DXVER);
|
||||
MessageBoxStr(ID_TXT_DX95);
|
||||
goto end_win32_check;
|
||||
}
|
||||
}
|
||||
|
||||
// we should be either under NT 4 or greater, or 95
|
||||
if (version_num < 3) {
|
||||
if (os == WinNT) {
|
||||
if (major == 4) {
|
||||
MessageBoxStr(ID_TXT_DXNT4);
|
||||
} else {
|
||||
MessageBoxStr(ID_TXT_DXNTERR);
|
||||
}
|
||||
goto end_win32_check;
|
||||
} else {
|
||||
// Win95
|
||||
MessageBoxStr(ID_TXT_DX95);
|
||||
goto end_win32_check;
|
||||
}
|
||||
}
|
||||
|
||||
if ((!SupportsKatmai()) || FindArg("-nopentium3")) {
|
||||
mprintf(0, "No Katmai detected.\n");
|
||||
Katmai = false;
|
||||
} else {
|
||||
mprintf(0, "Katmai detected!\n");
|
||||
Katmai = true;
|
||||
}
|
||||
|
||||
retval = true;
|
||||
|
||||
end_win32_check:
|
||||
return retval;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// WinMain
|
||||
// creates all the OS objects and then runs Descent 3.
|
||||
// this is all this function should do.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// See below for real WinMain
|
||||
|
||||
int PASCAL HandledWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szCmdLine, int nCmdShow) {
|
||||
/* initialize our OS Object. This could be a game dependant OS object, or a default OS object.
|
||||
once we create it, if successful, we can start the game.
|
||||
*/
|
||||
oeD3Win32App *d3;
|
||||
extern bool w32_mouseman_hack; // from winapp.cpp
|
||||
extern bool joy_chpro_hack; // located in winjoy.cpp
|
||||
|
||||
InitLog();
|
||||
|
||||
strupr(szCmdLine);
|
||||
GatherArgs(szCmdLine);
|
||||
|
||||
// This must come AFTER the GatherArgs() call, because its constructer used FindArg()
|
||||
oeD3Win32Database dbase;
|
||||
|
||||
no_debug_dialog = FindArg("-nocrashbox");
|
||||
|
||||
// If this is a dedicated server, then start one!
|
||||
if (FindArg("-dedicated"))
|
||||
StartDedicatedServer();
|
||||
#ifdef DEDICATED_ONLY
|
||||
else {
|
||||
MessageBox(NULL, "Error: -dedicated command line required", PRODUCT_NAME " Error", MB_OK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (Dedicated_server) {
|
||||
d3 = new oeD3Win32App(OEAPP_CONSOLE, (HInstance)hInst);
|
||||
} else {
|
||||
uint32_t flags = OEAPP_FULLSCREEN;
|
||||
#ifndef RELEASE // TODO: remove #ifndef when window mode is ready for primetime
|
||||
if (FindArg("-windowed")) {
|
||||
// switch to windowed mode instead
|
||||
flags = OEAPP_WINDOWED;
|
||||
}
|
||||
#endif
|
||||
|
||||
d3 = new oeD3Win32App(flags, (HInstance)hInst);
|
||||
}
|
||||
atexit(D3End);
|
||||
|
||||
w32_mouseman_hack = false;
|
||||
joy_chpro_hack = false;
|
||||
|
||||
if (FindArg("-mouseman")) {
|
||||
w32_mouseman_hack = true;
|
||||
}
|
||||
if (FindArg("-chpro")) {
|
||||
joy_chpro_hack = true;
|
||||
}
|
||||
|
||||
// determine preinit language for resource strings
|
||||
int language = 0;
|
||||
dbase.read_int("LanguageType", &language);
|
||||
m_resource_language = language;
|
||||
|
||||
if (!Win32SystemCheck(hInst))
|
||||
return 0;
|
||||
|
||||
PreInitD3Systems();
|
||||
|
||||
d3->init();
|
||||
d3->run();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// This is the winmain that tests for exceptions..
|
||||
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szCmdLine, int nCmdShow) {
|
||||
|
||||
int result = -1;
|
||||
|
||||
__try {
|
||||
result = HandledWinMain(hInst, hPrevInst, szCmdLine, nCmdShow);
|
||||
} __except (RecordExceptionInfo(GetExceptionInformation(), "WinMain()")) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Descent 3
|
||||
* Copyright (C) 2024 Parallax Software
|
||||
*
|
||||
* 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/>.
|
||||
|
||||
--- HISTORICAL COMMENTS FOLLOW ---
|
||||
|
||||
* $Logfile: /DescentIII/Main/ddvid_win32/ddvidlib.h $
|
||||
* $Revision: 4 $
|
||||
* $Date: 3/06/98 2:22p $
|
||||
* $Author: Samir $
|
||||
*
|
||||
* Video library internal header
|
||||
*
|
||||
* $Log: /DescentIII/Main/ddvid_win32/ddvidlib.h $
|
||||
*
|
||||
* 4 3/06/98 2:22p Samir
|
||||
* Added fullscreen windowed version.
|
||||
*
|
||||
* 3 2/03/98 3:12p Samir
|
||||
* Enable access to directdraw object by DDAccess libraries.
|
||||
*
|
||||
* 2 12/30/97 1:54p Samir
|
||||
* Upped max modes.
|
||||
*
|
||||
* 1 12/23/97 5:46p Samir
|
||||
* Initial revision
|
||||
*
|
||||
* $NoKeywords: $
|
||||
*/
|
||||
|
||||
#ifndef DDVIDLIB_H
|
||||
#define DDVIDLIB_H
|
||||
|
||||
#include "ddvid.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <ddraw.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define VM_MAX_MODES 96
|
||||
|
||||
const int VID_GDIF_SUBSYSTEM = 0, // GDI fullscreen subsystem
|
||||
VID_GDI_SUBSYSTEM = 1, // GDI subsystem
|
||||
VID_GDIX_SUBSYSTEM = 2, // GDIX subsystem (GDI+DirectX)
|
||||
VID_DX_SUBSYSTEM = 3; // DIRECTX subsystem
|
||||
|
||||
class oeWin32Application;
|
||||
|
||||
struct tDDVideoInfo {
|
||||
oeWin32Application *app;
|
||||
HWND hWnd;
|
||||
HWND hVidWnd;
|
||||
int subsystem;
|
||||
|
||||
LPDIRECTDRAW lpDD;
|
||||
LPDIRECTDRAWSURFACE lpDDSFront;
|
||||
LPDIRECTDRAWSURFACE lpDDSBack;
|
||||
DDSURFACEDESC DDModes[VM_MAX_MODES];
|
||||
int nDDModes;
|
||||
int curmode;
|
||||
char *surf_data;
|
||||
|
||||
struct {
|
||||
HBITMAP hBackBmp;
|
||||
HDC hBackDC;
|
||||
char *data;
|
||||
int pitch;
|
||||
int w, h, color_depth;
|
||||
int ndevmodes;
|
||||
int olddevmode;
|
||||
int curdevmode;
|
||||
} gdi;
|
||||
};
|
||||
|
||||
// driver info.
|
||||
extern tDDVideoInfo DDVideo_info;
|
||||
|
||||
// inits fullscreen system
|
||||
bool ddvidfs_Init();
|
||||
|
||||
// closes fullscreen system
|
||||
void ddvidfs_Close();
|
||||
|
||||
// uses direct draw. if paged, allows frame buffer access.
|
||||
bool ddvidfs_SetVideoMode(int w, int h, int color_depth, bool paged);
|
||||
|
||||
// closes video mode for fs
|
||||
void ddvidfs_CloseVideo();
|
||||
|
||||
// flips screen if there's a back buffer
|
||||
void ddvidfs_VideoFlip();
|
||||
|
||||
// returns the directdraw object
|
||||
uint32_t ddvidfs_GetDirectDrawObject();
|
||||
|
||||
// inits windowed system
|
||||
bool ddvidwin_Init();
|
||||
|
||||
// closes windowed system
|
||||
void ddvidwin_Close();
|
||||
|
||||
// creates an offscreen back bitmap if needed. otherwise doesn't do a thing really.
|
||||
bool ddvidwin_SetVideoMode(int w, int h, int color_depth, bool paged, bool reschange = false);
|
||||
|
||||
// closes video mode for fs
|
||||
void ddvidwin_CloseVideo();
|
||||
|
||||
// flips screen if there's a back buffer
|
||||
void ddvidwin_VideoFlip();
|
||||
|
||||
#endif
|
@ -1,212 +0,0 @@
|
||||
/*
|
||||
* Descent 3
|
||||
* Copyright (C) 2024 Parallax Software
|
||||
*
|
||||
* 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/>.
|
||||
|
||||
--- HISTORICAL COMMENTS FOLLOW ---
|
||||
|
||||
* $Logfile: /DescentIII/Main/ddvid_win32/vidWin32FS.cpp $
|
||||
* $Revision: 7 $
|
||||
* $Date: 7/15/98 5:56p $
|
||||
* $Author: Samir $
|
||||
*
|
||||
* Fullscreen version of Win32 library
|
||||
*
|
||||
* $Log: /DescentIII/Main/ddvid_win32/vidWin32FS.cpp $
|
||||
*
|
||||
* 7 7/15/98 5:56p Samir
|
||||
* commented out GDIX subsystem.
|
||||
*
|
||||
* 6 6/04/98 7:04p Samir
|
||||
* assert res-switch to be at least 16bpp.
|
||||
*
|
||||
* 5 3/04/98 5:01p Samir
|
||||
* May have fixed problem with restoring old display modes.
|
||||
*
|
||||
* 4 2/03/98 3:12p Samir
|
||||
* Enable access to directdraw object by DDAccess libraries.
|
||||
*
|
||||
* 3 12/30/97 3:35p Samir
|
||||
* Added dummy mode to help in mode selection.
|
||||
*
|
||||
* 2 12/30/97 2:31p Jason
|
||||
* Fixed mode finder. (samir)
|
||||
*
|
||||
* 1 12/23/97 5:46p Samir
|
||||
* Initial revision
|
||||
*
|
||||
* $NoKeywords: $
|
||||
*/
|
||||
|
||||
#include "ddvidlib.h"
|
||||
#include "pserror.h"
|
||||
|
||||
// DirectDraw Display mode enumeration callback
|
||||
HRESULT WINAPI DDEnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext);
|
||||
|
||||
// inits fullscreen system
|
||||
bool ddvidfs_Init() {
|
||||
HRESULT hres;
|
||||
|
||||
hres = DirectDrawCreate(NULL, &DDVideo_info.lpDD, NULL);
|
||||
|
||||
if (hres != DD_OK) {
|
||||
Error("Failure to initialize DirectDraw driver. (%d)", LOWORD(hres));
|
||||
}
|
||||
|
||||
hres =
|
||||
DDVideo_info.lpDD->SetCooperativeLevel(DDVideo_info.hWnd, DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
|
||||
if (hres != DD_OK) {
|
||||
Error("Failed to set access mode for DirectDraw driver. (%d)", LOWORD(hres));
|
||||
}
|
||||
|
||||
// dummy mode
|
||||
DDVideo_info.DDModes[DDVideo_info.nDDModes].ddpfPixelFormat.dwRGBBitCount = 0;
|
||||
DDVideo_info.DDModes[DDVideo_info.nDDModes].dwWidth = 0;
|
||||
DDVideo_info.DDModes[DDVideo_info.nDDModes].dwHeight = 0;
|
||||
DDVideo_info.nDDModes++;
|
||||
|
||||
// enumerate all display modes.
|
||||
if (DDVideo_info.lpDD->EnumDisplayModes(0, NULL, NULL, DDEnumModesCallback) != DD_OK) {
|
||||
mprintf(0, "DDVID error: Error enumerating display modes.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
mprintf(0, "Video fullscreen system initialized.\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// closes fullscreen system
|
||||
void ddvidfs_Close() {
|
||||
if (DDVideo_info.lpDDSFront)
|
||||
DDVideo_info.lpDDSFront->Release();
|
||||
|
||||
if (DDVideo_info.lpDD) {
|
||||
DDVideo_info.lpDD->RestoreDisplayMode();
|
||||
DDVideo_info.lpDD->SetCooperativeLevel(NULL, DDSCL_NORMAL);
|
||||
DDVideo_info.lpDD->Release();
|
||||
DDVideo_info.lpDD = NULL;
|
||||
}
|
||||
|
||||
DDVideo_info.lpDDSFront = NULL;
|
||||
DDVideo_info.lpDDSBack = NULL;
|
||||
DDVideo_info.hWnd = NULL;
|
||||
DDVideo_info.nDDModes = 0;
|
||||
}
|
||||
|
||||
// uses direct draw. if paged, allows frame buffer access.
|
||||
bool ddvidfs_SetVideoMode(int w, int h, int color_depth, bool paged) {
|
||||
HRESULT hres;
|
||||
DDSCAPS ddscaps;
|
||||
DDSURFACEDESC ddsd;
|
||||
int i, mode;
|
||||
bool found_mode;
|
||||
|
||||
mode = 0;
|
||||
found_mode = false;
|
||||
|
||||
// find closest match for video mode.
|
||||
for (i = 0; i < DDVideo_info.nDDModes; i++) {
|
||||
if (color_depth == (int)DDVideo_info.DDModes[i].ddpfPixelFormat.dwRGBBitCount) {
|
||||
if (DDVideo_info.DDModes[i].dwWidth >= (DWORD)w && DDVideo_info.DDModes[mode].dwWidth < (DWORD)w)
|
||||
if (DDVideo_info.DDModes[i].dwHeight >= (DWORD)h && DDVideo_info.DDModes[mode].dwHeight < (DWORD)h) {
|
||||
mode = i;
|
||||
found_mode = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_mode) {
|
||||
// we couldn't find a mode, error!
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DDVideo_info.curmode != mode) {
|
||||
|
||||
// mode should contain the video mode.
|
||||
hres = DDVideo_info.lpDD->SetDisplayMode(DDVideo_info.DDModes[mode].dwWidth, DDVideo_info.DDModes[mode].dwHeight,
|
||||
DDVideo_info.DDModes[mode].ddpfPixelFormat.dwRGBBitCount);
|
||||
ASSERT(DDVideo_info.DDModes[mode].ddpfPixelFormat.dwRGBBitCount >= BPP_16);
|
||||
if (hres != DD_OK)
|
||||
Error("Unable to set DirectDraw display mode. (%d)", LOWORD(hres));
|
||||
}
|
||||
|
||||
DDVideo_info.curmode = mode;
|
||||
|
||||
// if not paged, then this is a single paged system (no lfb access, good for opengl)
|
||||
if (!paged)
|
||||
return true;
|
||||
|
||||
// now create surface, dependant on whether an extra page was requested
|
||||
memset(&ddsd, 0, sizeof(ddsd));
|
||||
ddsd.dwSize = sizeof(ddsd);
|
||||
|
||||
if (paged) {
|
||||
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
|
||||
ddsd.dwBackBufferCount = 1;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
|
||||
} else {
|
||||
ddsd.dwFlags = DDSD_CAPS;
|
||||
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
||||
}
|
||||
|
||||
hres = DDVideo_info.lpDD->CreateSurface(&ddsd, &DDVideo_info.lpDDSFront, NULL);
|
||||
if (hres != DD_OK)
|
||||
Error("Unable to capture DirectDraw display surface. (%d)", LOWORD(hres));
|
||||
|
||||
if (paged) {
|
||||
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
|
||||
|
||||
hres = DDVideo_info.lpDDSFront->GetAttachedSurface(&ddscaps, &DDVideo_info.lpDDSBack);
|
||||
if (hres != DD_OK) {
|
||||
mprintf(0, "Unable to capture DirectDraw display back surface (%d)", LOWORD(hres));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
DDVideo_info.lpDDSBack = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// closes video mode for fs
|
||||
void ddvidfs_CloseVideo() {
|
||||
// uninitialize old screen
|
||||
if (DDVideo_info.lpDDSFront) {
|
||||
DDVideo_info.lpDDSFront->Release();
|
||||
DDVideo_info.lpDDSFront = NULL;
|
||||
DDVideo_info.lpDDSBack = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// flips screen if there's a back buffer
|
||||
void ddvidfs_VideoFlip() {
|
||||
if (DDVideo_info.lpDDSBack)
|
||||
DDVideo_info.lpDDSFront->Flip(NULL, DDFLIP_WAIT);
|
||||
}
|
||||
|
||||
// returns the directdraw object
|
||||
uint32_t ddvidfs_GetDirectDrawObject() { return (uint32_t)DDVideo_info.lpDD; }
|
||||
|
||||
// DirectDraw Display mode enumeration callback
|
||||
HRESULT WINAPI DDEnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext) {
|
||||
if (DDVideo_info.nDDModes < VM_MAX_MODES) {
|
||||
memcpy(&DDVideo_info.DDModes[DDVideo_info.nDDModes], lpDDSurfaceDesc, sizeof(DDSURFACEDESC));
|
||||
DDVideo_info.nDDModes++;
|
||||
}
|
||||
|
||||
return DDENUMRET_OK;
|
||||
}
|
@ -1,270 +0,0 @@
|
||||
/*
|
||||
* Descent 3
|
||||
* Copyright (C) 2024 Parallax Software
|
||||
*
|
||||
* 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/>.
|
||||
|
||||
--- HISTORICAL COMMENTS FOLLOW ---
|
||||
|
||||
* $Logfile: /DescentIII/Main/ddvid_win32/vidWin32Win.cpp $
|
||||
* $Revision: 5 $
|
||||
* $Date: 10/02/98 11:15a $
|
||||
* $Author: Jeff $
|
||||
*
|
||||
* Windowed version of video library.
|
||||
*
|
||||
* $Log: /DescentIII/Main/ddvid_win32/vidWin32Win.cpp $
|
||||
*
|
||||
* 5 10/02/98 11:15a Jeff
|
||||
* added HBITMAP, HFONT and HBRUSH type casts where needed to satisfy the
|
||||
* compiler
|
||||
*
|
||||
* 4 6/04/98 7:04p Samir
|
||||
* assert res-switch to be at least 16bpp.
|
||||
*
|
||||
* 3 4/23/98 6:38p Jason
|
||||
* made bitmaps use 1555 format
|
||||
*
|
||||
* 2 3/06/98 2:22p Samir
|
||||
* Added fullscreen windowed version.
|
||||
*
|
||||
* 1 12/23/97 5:46p Samir
|
||||
* Initial revision
|
||||
*
|
||||
* $NoKeywords: $
|
||||
*/
|
||||
|
||||
#include "ddvidlib.h"
|
||||
#include "pserror.h"
|
||||
#include "Application.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Variables
|
||||
|
||||
struct tDIBHeader // used to create and manipulate DIBs (a 16/32BPP surface only)
|
||||
{
|
||||
BITMAPINFOHEADER bmi;
|
||||
DWORD red_mask;
|
||||
DWORD green_mask;
|
||||
DWORD blue_mask;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Functions
|
||||
|
||||
// inits fullscreen system
|
||||
bool ddvidwin_Init() {
|
||||
// grab all device modes for the current display device.
|
||||
unsigned i = 0;
|
||||
DEVMODE devmode;
|
||||
|
||||
while (EnumDisplaySettings(NULL, i, &devmode)) {
|
||||
HDC hdc = CreateCompatibleDC(NULL);
|
||||
|
||||
if (devmode.dmBitsPerPel == (uint32_t)GetDeviceCaps(hdc, BITSPIXEL) &&
|
||||
devmode.dmPelsWidth == (uint32_t)GetSystemMetrics(SM_CXSCREEN) &&
|
||||
devmode.dmPelsHeight == (uint32_t)GetSystemMetrics(SM_CYSCREEN)) {
|
||||
if (DDVideo_info.app->NT() && devmode.dmDisplayFrequency == (uint32_t)GetDeviceCaps(hdc, VREFRESH))
|
||||
DDVideo_info.gdi.olddevmode = i;
|
||||
else if (!DDVideo_info.app->NT())
|
||||
DDVideo_info.gdi.olddevmode = i;
|
||||
}
|
||||
|
||||
DeleteDC(hdc);
|
||||
i++;
|
||||
}
|
||||
DDVideo_info.gdi.ndevmodes = i;
|
||||
|
||||
DDVideo_info.gdi.curdevmode = DDVideo_info.gdi.olddevmode;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// closes windowed system
|
||||
void ddvidwin_Close() {
|
||||
DEVMODE devmode;
|
||||
|
||||
if (DDVideo_info.gdi.hBackDC) {
|
||||
DeleteDC(DDVideo_info.gdi.hBackDC);
|
||||
DDVideo_info.gdi.hBackDC = NULL;
|
||||
}
|
||||
|
||||
if (DDVideo_info.gdi.hBackBmp) {
|
||||
DeleteObject(DDVideo_info.gdi.hBackBmp);
|
||||
DDVideo_info.gdi.hBackBmp = NULL;
|
||||
}
|
||||
|
||||
// if the current display mode is different than the default one, then restore default display mode
|
||||
if (DDVideo_info.gdi.olddevmode != DDVideo_info.gdi.curdevmode) {
|
||||
LONG lres;
|
||||
|
||||
EnumDisplaySettings(NULL, DDVideo_info.gdi.olddevmode, &devmode);
|
||||
|
||||
devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY;
|
||||
|
||||
lres = ChangeDisplaySettings(&devmode, 0);
|
||||
ASSERT(lres == DISP_CHANGE_SUCCESSFUL);
|
||||
}
|
||||
}
|
||||
|
||||
// creates an offscreen back bitmap if needed. otherwise doesn't do a thing really
|
||||
bool ddvidwin_SetVideoMode(int w, int h, int color_depth, bool paged, bool reschange) {
|
||||
HDC hdc;
|
||||
int i;
|
||||
|
||||
DDVideo_info.hVidWnd = DDVideo_info.hWnd;
|
||||
|
||||
// if resolution change, then do it.
|
||||
if (reschange) {
|
||||
int mode = 0;
|
||||
bool found_mode = false;
|
||||
DEVMODE devmode, curdevmode;
|
||||
|
||||
EnumDisplaySettings(NULL, mode, &curdevmode);
|
||||
curdevmode.dmPelsWidth = 0;
|
||||
curdevmode.dmPelsHeight = 0;
|
||||
curdevmode.dmBitsPerPel = 0;
|
||||
|
||||
// check for display mode query match.
|
||||
for (i = 0; i < DDVideo_info.gdi.ndevmodes; i++) {
|
||||
EnumDisplaySettings(NULL, i, &devmode);
|
||||
|
||||
if (color_depth == (int)devmode.dmBitsPerPel) {
|
||||
if ((int)devmode.dmPelsWidth >= w && (int)curdevmode.dmPelsWidth < w)
|
||||
if ((int)devmode.dmPelsHeight >= h && (int)curdevmode.dmPelsHeight < h) {
|
||||
mode = i;
|
||||
found_mode = true;
|
||||
EnumDisplaySettings(NULL, mode, &curdevmode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_mode) {
|
||||
// we couldn't find a mode, error!
|
||||
Error("Unable to set Win32 device display mode (%dx%dx%d).", w, h, color_depth);
|
||||
}
|
||||
|
||||
if (DDVideo_info.gdi.curdevmode != mode) {
|
||||
EnumDisplaySettings(NULL, mode, &devmode);
|
||||
|
||||
devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY;
|
||||
|
||||
ASSERT(devmode.dmBitsPerPel >= BPP_16);
|
||||
LONG lres = ChangeDisplaySettings(&devmode, 0);
|
||||
ASSERT(lres == DISP_CHANGE_SUCCESSFUL);
|
||||
DDVideo_info.gdi.curdevmode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
// create a DC for blting and back buffer creation.
|
||||
hdc = CreateCompatibleDC(NULL);
|
||||
if (hdc == NULL) {
|
||||
Error("Unable to create offscreen device context (%x).", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
DDVideo_info.gdi.hBackDC = hdc;
|
||||
DDVideo_info.gdi.w = w;
|
||||
DDVideo_info.gdi.h = h;
|
||||
DDVideo_info.gdi.color_depth = color_depth;
|
||||
|
||||
// create offscreen back buffer if paged mode is requested.
|
||||
if (paged) {
|
||||
int nw = w;
|
||||
if (nw % 4)
|
||||
nw = ((w / 4) * 4) + 4;
|
||||
tDIBHeader header;
|
||||
|
||||
if (color_depth == BPP_16) {
|
||||
header.bmi.biSize = sizeof(BITMAPINFOHEADER);
|
||||
header.bmi.biWidth = nw;
|
||||
header.bmi.biHeight = -h; // Always a top down bitmap!!
|
||||
header.bmi.biPlanes = 1;
|
||||
header.bmi.biBitCount = BPP_16;
|
||||
header.bmi.biCompression = BI_BITFIELDS;
|
||||
header.bmi.biSizeImage = 0;
|
||||
header.bmi.biXPelsPerMeter = 0;
|
||||
header.bmi.biYPelsPerMeter = 0;
|
||||
header.bmi.biClrUsed = 0;
|
||||
header.bmi.biClrImportant = 0;
|
||||
|
||||
// setup RGB bit masks
|
||||
header.red_mask = 0x7c00;
|
||||
header.green_mask = 0x03e0;
|
||||
header.blue_mask = 0x001f;
|
||||
DDVideo_info.gdi.pitch = nw * 2;
|
||||
}
|
||||
|
||||
DDVideo_info.gdi.hBackBmp = CreateDIBSection(DDVideo_info.gdi.hBackDC, (BITMAPINFO *)&header, DIB_RGB_COLORS,
|
||||
(void **)&DDVideo_info.gdi.data, NULL, 0);
|
||||
|
||||
if (!DDVideo_info.gdi.hBackBmp) {
|
||||
Error("CreateDIBSection failed (%x).", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// closes video mode for fs
|
||||
void ddvidwin_CloseVideo() {
|
||||
// delete DC if it exists.
|
||||
if (DDVideo_info.gdi.hBackDC) {
|
||||
DeleteDC(DDVideo_info.gdi.hBackDC);
|
||||
DDVideo_info.gdi.hBackDC = NULL;
|
||||
}
|
||||
|
||||
// destroy old back bitmap
|
||||
if (DDVideo_info.gdi.hBackBmp) {
|
||||
DeleteObject(DDVideo_info.gdi.hBackBmp);
|
||||
DDVideo_info.gdi.hBackBmp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// retrieves screen information for windowed version
|
||||
void ddvidwin_GetVideoProperties(int *w, int *h, int *color_depth) {
|
||||
*w = DDVideo_info.gdi.w;
|
||||
*h = DDVideo_info.gdi.h;
|
||||
*color_depth = DDVideo_info.gdi.color_depth;
|
||||
}
|
||||
|
||||
// flips screen if there's a back buffer
|
||||
void ddvidwin_VideoFlip() {
|
||||
HBITMAP old_bmp, h_sbm;
|
||||
HDC hdc_dest;
|
||||
RECT rect;
|
||||
int dw, dh;
|
||||
|
||||
ASSERT(DDVideo_info.hVidWnd != NULL);
|
||||
|
||||
// don't give an error if there's no backbuffer.
|
||||
if (!DDVideo_info.gdi.hBackBmp)
|
||||
return;
|
||||
|
||||
h_sbm = DDVideo_info.gdi.hBackBmp;
|
||||
|
||||
hdc_dest = GetDC(DDVideo_info.hVidWnd);
|
||||
GetClientRect(DDVideo_info.hVidWnd, &rect);
|
||||
|
||||
dw = rect.right - rect.left;
|
||||
dh = rect.bottom - rect.top;
|
||||
|
||||
old_bmp = (HBITMAP)SelectObject(DDVideo_info.gdi.hBackDC, h_sbm);
|
||||
|
||||
BOOL bltres = BitBlt(hdc_dest, 0, 0, dw, dh, DDVideo_info.gdi.hBackDC, 0, 0, SRCCOPY);
|
||||
|
||||
SelectObject(DDVideo_info.gdi.hBackDC, old_bmp);
|
||||
|
||||
ReleaseDC(DDVideo_info.hVidWnd, hdc_dest);
|
||||
}
|
@ -1,189 +0,0 @@
|
||||
/*
|
||||
* Descent 3
|
||||
* Copyright (C) 2024 Parallax Software
|
||||
*
|
||||
* 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/>.
|
||||
|
||||
--- HISTORICAL COMMENTS FOLLOW ---
|
||||
|
||||
* $Logfile: /DescentIII/Main/ddvid_win32/video_win32.cpp $
|
||||
* $Revision: 6 $
|
||||
* $Date: 8/28/98 4:20p $
|
||||
* $Author: Jeff $
|
||||
*
|
||||
* Video library.
|
||||
*
|
||||
* $Log: /DescentIII/Main/ddvid_win32/video_win32.cpp $
|
||||
*
|
||||
* 6 8/28/98 4:20p Jeff
|
||||
* fixed cinemtaics so they initialize ddraw to play the movie
|
||||
*
|
||||
* 5 7/15/98 5:56p Samir
|
||||
* commented out GDIX subsystem.
|
||||
*
|
||||
* 4 3/06/98 2:22p Samir
|
||||
* Added fullscreen windowed version.
|
||||
*
|
||||
* 3 2/03/98 3:12p Samir
|
||||
* Enable access to directdraw object by DDAccess libraries.
|
||||
*
|
||||
* 2 12/23/97 6:17p Samir
|
||||
* Added DDGR subsystem interface.
|
||||
*
|
||||
* 1 12/22/97 12:45p Samir
|
||||
* Initial revision
|
||||
*
|
||||
* $NoKeywords: $
|
||||
*/
|
||||
|
||||
|
||||
#include "ddvidlib.h"
|
||||
#include "pserror.h"
|
||||
#include "Application.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Variables
|
||||
|
||||
tDDVideoInfo DDVideo_info;
|
||||
static bool DDVideo_init = false;
|
||||
|
||||
char *DDVID_subsystem_names[] = {"GDIF", // Win32 GDI Fullscreen
|
||||
"GDI", // Standard Win32 GDI DIBs
|
||||
"GDIX", // GDI and DirectDraw for mode settings.
|
||||
"DX", // Direct X!
|
||||
NULL};
|
||||
|
||||
int DDVID_subsystems[] = {VID_GDIF_SUBSYSTEM, VID_GDI_SUBSYSTEM, VID_GDIX_SUBSYSTEM, VID_DX_SUBSYSTEM, -1};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Prototypes
|
||||
|
||||
HRESULT WINAPI DDEnumModesCallback(LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Functions
|
||||
|
||||
// called first to allow fullscreen video access
|
||||
bool ddvid_Init(oeApplication *app, char *driver) {
|
||||
int subsys_id;
|
||||
|
||||
// preinitialize system.
|
||||
if (!DDVideo_init) {
|
||||
DDVideo_info.lpDD = NULL;
|
||||
DDVideo_info.lpDDSFront = NULL;
|
||||
DDVideo_info.lpDDSBack = NULL;
|
||||
DDVideo_info.hWnd = NULL;
|
||||
DDVideo_info.nDDModes = 0;
|
||||
DDVideo_info.curmode = -1;
|
||||
DDVideo_info.surf_data = NULL;
|
||||
DDVideo_info.gdi.hBackBmp = NULL;
|
||||
DDVideo_info.gdi.hBackDC = NULL;
|
||||
DDVideo_info.gdi.data = NULL;
|
||||
DDVideo_info.gdi.pitch = 0;
|
||||
DDVideo_info.gdi.w = 0;
|
||||
DDVideo_info.gdi.h = 0;
|
||||
DDVideo_info.gdi.color_depth = 0;
|
||||
|
||||
atexit(ddvid_Close);
|
||||
} else {
|
||||
ddvid_Close();
|
||||
}
|
||||
|
||||
DDVideo_init = true;
|
||||
|
||||
DDVideo_info.app = (oeWin32Application *)app;
|
||||
|
||||
// find subsystem id based off of subsystem requested.
|
||||
for (subsys_id = 0; DDVID_subsystems[subsys_id] != -1; subsys_id++) {
|
||||
if (strcmp(DDVID_subsystem_names[subsys_id], driver) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (DDVID_subsystems[subsys_id] == -1)
|
||||
Error("Subsystem %s not found during startup.", driver);
|
||||
|
||||
DDVideo_info.subsystem = DDVID_subsystems[subsys_id];
|
||||
DDVideo_info.hWnd = (HWND)(((oeWin32Application *)app)->m_hWnd);
|
||||
|
||||
// initialize directdraw object.
|
||||
switch (DDVideo_info.subsystem) {
|
||||
case VID_GDIF_SUBSYSTEM:
|
||||
case VID_GDI_SUBSYSTEM:
|
||||
return ddvidwin_Init();
|
||||
case VID_GDIX_SUBSYSTEM:
|
||||
return true;
|
||||
case VID_DX_SUBSYSTEM:
|
||||
return ddvidfs_Init();
|
||||
default:
|
||||
Int3();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// closes ddvid system manually.
|
||||
void ddvid_Close() {
|
||||
if (!DDVideo_init)
|
||||
return;
|
||||
|
||||
switch (DDVideo_info.subsystem) {
|
||||
case VID_GDIF_SUBSYSTEM:
|
||||
case VID_GDI_SUBSYSTEM:
|
||||
ddvidwin_Close();
|
||||
break;
|
||||
case VID_GDIX_SUBSYSTEM:
|
||||
break;
|
||||
case VID_DX_SUBSYSTEM:
|
||||
ddvidfs_Close();
|
||||
break;
|
||||
default:
|
||||
Int3();
|
||||
}
|
||||
|
||||
DDVideo_init = false;
|
||||
}
|
||||
|
||||
// sets the appropriate video mode.
|
||||
bool ddvid_SetVideoMode(int w, int h, int color_depth, bool paged) {
|
||||
ASSERT(DDVideo_init);
|
||||
|
||||
switch (DDVideo_info.subsystem) {
|
||||
case VID_GDIF_SUBSYSTEM:
|
||||
ddvidwin_CloseVideo();
|
||||
return ddvidwin_SetVideoMode(w, h, color_depth, paged, true);
|
||||
|
||||
case VID_GDI_SUBSYSTEM:
|
||||
ddvidwin_CloseVideo();
|
||||
return ddvidwin_SetVideoMode(w, h, color_depth, paged);
|
||||
|
||||
case VID_GDIX_SUBSYSTEM:
|
||||
ddvidwin_CloseVideo();
|
||||
ddvidfs_CloseVideo();
|
||||
return (ddvidfs_SetVideoMode(w, h, color_depth, false) &&
|
||||
ddvidwin_SetVideoMode(DDVideo_info.DDModes[DDVideo_info.curmode].dwWidth,
|
||||
DDVideo_info.DDModes[DDVideo_info.curmode].dwHeight, color_depth, paged));
|
||||
case VID_DX_SUBSYSTEM:
|
||||
ddvidfs_CloseVideo();
|
||||
return ddvidfs_SetVideoMode(w, h, color_depth, paged);
|
||||
default:
|
||||
Int3();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// sets screen handle
|
||||
void ddvid_SetVideoHandle(unsigned handle) { DDVideo_info.hVidWnd = (HWND)handle; }
|
File diff suppressed because it is too large
Load Diff
205
ddio/winio.cpp
205
ddio/winio.cpp
@ -1,205 +0,0 @@
|
||||
/*
|
||||
* Descent 3
|
||||
* Copyright (C) 2024 Parallax Software
|
||||
*
|
||||
* 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/>.
|
||||
|
||||
--- HISTORICAL COMMENTS FOLLOW ---
|
||||
|
||||
* $Logfile: /DescentIII/Main/ddio_win/winio.cpp $
|
||||
* $Revision: 17 $
|
||||
* $Date: 7/09/01 1:55p $
|
||||
* $Author: Matt $
|
||||
*
|
||||
* <insert description of file here>
|
||||
*
|
||||
* $Log: /DescentIII/Main/ddio_win/winio.cpp $
|
||||
*
|
||||
* 17 7/09/01 1:55p Matt
|
||||
* Try opening DX5 for NT so force feedback will work.
|
||||
*
|
||||
* 16 4/09/99 12:02p Samir
|
||||
* joystick changes (Win32 DirectInput support)
|
||||
*
|
||||
* 15 1/25/99 11:02a Samir
|
||||
* revamped mouse and key controls.
|
||||
*
|
||||
* 14 11/18/98 5:50p Jeff
|
||||
* free up force feedback before unloading DI
|
||||
*
|
||||
* 13 11/03/98 6:43p Jeff
|
||||
* new low-level & high level Force Feedback system implemented, handles
|
||||
* window losing focus, etc.
|
||||
*
|
||||
* 12 11/01/98 1:58a Jeff
|
||||
* converted the vsprintf calls to use the Pvsprintf, which is a safe
|
||||
* vsprintf, no buffer overflows allowed
|
||||
*
|
||||
* 11 10/18/98 6:18p Matt
|
||||
* Turn the pointer on when shutting down. This fixes a problem where you
|
||||
* couldn't click Ok on an error message box because the pointer was off
|
||||
* for our app.
|
||||
*
|
||||
* 10 9/18/98 7:38p Jeff
|
||||
* creation of low-level forcefeedback and beginning of high-level
|
||||
* forcefeedback
|
||||
*
|
||||
* 9 9/15/98 12:25p Jeff
|
||||
* If we are in NT, then only require DX3, else require DX6 (we may need
|
||||
* to change this due to NT5)
|
||||
*
|
||||
* 8 9/15/98 12:05p Jeff
|
||||
* initial creation of low-level forcefeedback
|
||||
*
|
||||
* 7 6/29/98 6:43p Samir
|
||||
* Took out GetMsgProc and legacy keyboard variables.
|
||||
*
|
||||
* 6 5/08/98 12:54p Samir
|
||||
* newer unused mouse handler.
|
||||
*
|
||||
* 5 3/31/98 12:46p Samir
|
||||
* keyboard IO system better. uses getmsgproc windows hook.
|
||||
*
|
||||
* 4 10/23/97 2:58p Samir
|
||||
* Took out extranneous messages.
|
||||
*
|
||||
* 3 10/16/97 2:29p Samir
|
||||
* Changed DirectInput Keyboard to FOREGROUND
|
||||
*
|
||||
* 2 8/01/97 7:30p Samir
|
||||
* Better NT keyboard support.
|
||||
*
|
||||
* 10 6/11/97 1:07p Samir
|
||||
* The removal of gameos and replaced with oeApplication, oeDatabase
|
||||
*
|
||||
* 9 5/08/97 1:56p Samir
|
||||
* These functions should only be applicable to windows (no shared code)
|
||||
*
|
||||
* 8 3/18/97 11:14a Samir
|
||||
* Use real error call when DirectInput init fails.
|
||||
*
|
||||
* 7 2/28/97 11:03a Samir
|
||||
* Changes to reflect newer gameos interface.
|
||||
*
|
||||
* 6 1/30/97 6:08p Samir
|
||||
* Reflects changes in gameos.h
|
||||
*
|
||||
* 5 1/23/97 2:23p Samir
|
||||
* Preemptive flag now just affects timer.
|
||||
*
|
||||
* $NoKeywords: $
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Win32 IO System Main Library Interface
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "pserror.h"
|
||||
#include "Application.h"
|
||||
#include "ddio_win.h"
|
||||
#include "ddio.h"
|
||||
#include "dinput.h"
|
||||
|
||||
#include "forcefeedback.h"
|
||||
|
||||
bool DDIO_init = 0;
|
||||
dinput_data DInputData;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Initialization and destruction functions
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool ddio_InternalInit(ddio_init_info *init_info) {
|
||||
oeWin32Application *obj = (oeWin32Application *)init_info->obj;
|
||||
LPDIRECTINPUT lpdi;
|
||||
HRESULT dires;
|
||||
|
||||
ASSERT(!DDIO_init);
|
||||
|
||||
// Initialize DirectInput subsystem
|
||||
mprintf(0, "DI system initializing.\n");
|
||||
|
||||
// Try to open DirectX 5.00
|
||||
dires = DirectInputCreate((HINSTANCE)obj->m_hInstance, DIRECTINPUT_VERSION, &lpdi, NULL);
|
||||
|
||||
// Deal with error opening DX5
|
||||
if (dires != DI_OK) {
|
||||
|
||||
// If running NT, try DirectX 3.0
|
||||
if (obj->NT()) {
|
||||
|
||||
dires = DirectInputCreate((HINSTANCE)obj->m_hInstance, 0x0300, &lpdi, NULL);
|
||||
if (dires != DI_OK) {
|
||||
Error("Unable to DirectInput system (Requires at least DirectX 3.0 For NT) [DirectInput:%x]\n", dires);
|
||||
}
|
||||
} else { // Not running NT, so error out
|
||||
|
||||
// Couldn't open DirectX, so print error
|
||||
Error("Unable to DirectInput system (Requires at least DirectX 5.0) [DirectInput:%x]\n", dires);
|
||||
}
|
||||
}
|
||||
|
||||
DInputData.app = obj;
|
||||
DInputData.lpdi = lpdi;
|
||||
DInputData.hwnd = (HWND)obj->m_hWnd;
|
||||
|
||||
DDIO_init = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ddio_InternalClose() {
|
||||
ASSERT(DDIO_init);
|
||||
|
||||
// //Close down forcefeedback
|
||||
// ddio_ff_DetachForce();
|
||||
|
||||
DInputData.lpdi->Release();
|
||||
DInputData.lpdi = NULL;
|
||||
DDIO_init = 0;
|
||||
|
||||
mprintf(0, "DI system closed.\n");
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
void ddio_DebugMessage(unsigned err, char *fmt, ...) {
|
||||
char buf[128];
|
||||
std::va_list arglist;
|
||||
|
||||
va_start(arglist, fmt);
|
||||
std::vsnprintf(buf, 128, fmt, arglist);
|
||||
va_end(arglist);
|
||||
|
||||
mprintf(0, "DDIO: %s\n", buf);
|
||||
if (err) {
|
||||
mprintf(1, "DIERR %x.\n", err);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ddio_GetBinaryPath(char *exec_path, size_t len) {
|
||||
if (GetModuleFileName(NULL, exec_path, len) == 0) {
|
||||
DWORD error = GetLastError();
|
||||
Error("GetModuleFileName failed!");
|
||||
return false;
|
||||
}
|
||||
exec_path[len - 1] = '\0';
|
||||
return true;
|
||||
}
|
759
ddio/winjoy.cpp
759
ddio/winjoy.cpp
@ -1,759 +0,0 @@
|
||||
/*
|
||||
* Descent 3
|
||||
* Copyright (C) 2024 Parallax Software
|
||||
*
|
||||
* 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/>.
|
||||
|
||||
--- HISTORICAL COMMENTS FOLLOW ---
|
||||
|
||||
* $Logfile: /DescentIII/Main/ddio_win/winjoy.cpp $
|
||||
* $Revision: 19 $
|
||||
* $Date: 8/10/99 5:11p $
|
||||
* $Author: Jeff $
|
||||
*
|
||||
* joystick header
|
||||
*
|
||||
* $Log: /DescentIII/Main/ddio_win/winjoy.cpp $
|
||||
*
|
||||
* 19 8/10/99 5:11p Jeff
|
||||
* always call detachforce, it needs to free DLLs
|
||||
*
|
||||
* 18 7/30/99 1:06p Samir
|
||||
* fixed hat code for direct input and apply sensitivities for calibration
|
||||
* of axes.
|
||||
*
|
||||
* 17 7/26/99 11:59a Samir
|
||||
* add code to get name of joystick
|
||||
*
|
||||
* 16 7/16/99 11:14a Samir
|
||||
* multiple hat support and improved direct input support.
|
||||
*
|
||||
* 15 5/23/99 12:45a Samir
|
||||
* if joystick was never found, when returning from joygetpos, set all
|
||||
* position values to a neutral value.
|
||||
*
|
||||
* 14 5/19/99 4:38p Samir
|
||||
* trying 'centered' flag for joyGetPosEx to automatically center joystick
|
||||
* on midpoint of min and max values for axis. I don't know why this
|
||||
* isn't the case anyway, but...
|
||||
*
|
||||
* 13 5/10/99 9:22p Samir
|
||||
* added CH Flightstick Pro hack.
|
||||
*
|
||||
* 12 5/08/99 1:05a Samir
|
||||
* initialize joysticks always, but return NULL values if the joystick is
|
||||
* unplugged.
|
||||
*
|
||||
* 11 5/05/99 10:55p Samir
|
||||
* moved force feedback code so it's always initialized.
|
||||
*
|
||||
* 10 4/24/99 8:41p Samir
|
||||
* added debug code to get controller positions on mono.
|
||||
*
|
||||
* 9 4/12/99 12:12p Samir
|
||||
* took out int3.
|
||||
*
|
||||
* 8 4/09/99 12:02p Samir
|
||||
* joystick changes (Win32 DirectInput support)
|
||||
*
|
||||
* 7 2/21/99 6:38p Samir
|
||||
* mouse and key input better. buffered mouse.
|
||||
*
|
||||
* 6 2/03/99 6:47p Jeff
|
||||
* (Samir) hacked pov value, so it's always a word
|
||||
*
|
||||
* 5 10/18/98 7:25p Samir
|
||||
* made joy_GetPos safe.
|
||||
*
|
||||
* 4 6/02/98 4:37p Samir
|
||||
* multiple joysticks supported.
|
||||
*
|
||||
* 3 6/01/98 4:27p Samir
|
||||
* pov may return multiple positions.
|
||||
*
|
||||
* 2 12/03/97 7:33p Samir
|
||||
* Improved joystick interface.
|
||||
*
|
||||
* 4 6/11/97 2:40p Samir
|
||||
* fixed bools.
|
||||
*
|
||||
* 3 2/26/97 6:16p Samir
|
||||
* joy_init returns a 0 if no joysticks are present.
|
||||
*
|
||||
* 2 2/26/97 12:09p Samir
|
||||
* Added some debug and error checking.
|
||||
*
|
||||
* $NoKeywords: $
|
||||
*/
|
||||
|
||||
#include "joystick.h"
|
||||
#include "forcefeedback.h"
|
||||
#include "pserror.h"
|
||||
#include "pstypes.h"
|
||||
#include "mem.h"
|
||||
#include "ddio_win.h"
|
||||
#include "Macros.h"
|
||||
#include "logfile.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <regstr.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define loword(_v) ((_v) & 0x0000ffff)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
struct tJoystickRecord {
|
||||
uint8_t valid; // is this a valid device.
|
||||
uint8_t flags; // defined in ddio_win.h
|
||||
int16_t spad;
|
||||
|
||||
union {
|
||||
int joyid;
|
||||
tDevice ffdev;
|
||||
} joy_context; // used to identify the joystick.
|
||||
|
||||
tJoyInfo caps; // controller capabilities
|
||||
tJoyPos pos; // current position
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
static struct tJoystickLibraryData {
|
||||
int16_t init; // library initialized?
|
||||
int16_t njoy; // maximum number of joysticks supported.
|
||||
tJoystickRecord *joystick; // list of joysticks.
|
||||
|
||||
LPDIRECTINPUT lpdi; // if lpdi != NULL, we use direct input for joysticks
|
||||
} WJD = {0, 0, NULL, NULL};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool joyw_get_name(int id, char *buf, const char *regkey);
|
||||
|
||||
bool joymm_init();
|
||||
void joymm_close();
|
||||
tJoystick joymm_init_stick(int joyid);
|
||||
void joymm_close_stick(tJoystick handle);
|
||||
void joymm_get_pos(tJoystick handle, tJoyPos *pos);
|
||||
|
||||
tJoystick joydi_init_stick(int ffjoyid);
|
||||
void joydi_get_pos(tJoystick handle, tJoyPos *pos);
|
||||
|
||||
// joystick forcefeedback shares
|
||||
extern LPDIRECTINPUTDEVICE2 ddio_ff_get_joystick_obj(tDevice dev);
|
||||
|
||||
bool joy_chpro_hack = false; // flightstick pro hack for Win32 only
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// initializes joystick interface.
|
||||
|
||||
bool joy_Init(bool emulation) {
|
||||
// Can we initialize DirectInput version?
|
||||
// Try to init forcefeedback (which initializes joysticks)
|
||||
uint32_t i, n; // = joyGetNumDevs();
|
||||
|
||||
ddio_ff_AttachForce();
|
||||
|
||||
// initializes forcefeedback system?
|
||||
if (ddio_ff_Init()) {
|
||||
mprintf(0, "DDForce: Force Feedback Joystick Found\n");
|
||||
}
|
||||
|
||||
// initialize data structures.
|
||||
n = 2;
|
||||
if (n) {
|
||||
WJD.joystick = (tJoystickRecord *)mem_malloc(sizeof(tJoystickRecord) * n);
|
||||
for (i = 0; i < n; i++) {
|
||||
WJD.joystick[i].valid = 0;
|
||||
}
|
||||
} else {
|
||||
WJD.init = 0;
|
||||
return false;
|
||||
}
|
||||
WJD.njoy = n;
|
||||
|
||||
// attempt directinput initialization.
|
||||
n = (!emulation) ? ddio_ffjoy_Init() : 0;
|
||||
|
||||
if (n > 0) {
|
||||
WJD.lpdi = DInputData.lpdi;
|
||||
|
||||
// map all ffjoysticks to our joystick structure.
|
||||
for (i = 0; i < n; i++) {
|
||||
joydi_init_stick(i);
|
||||
}
|
||||
|
||||
}
|
||||
// enumerate all windows joysticks (1 and 2 only)
|
||||
else if (joymm_init()) {
|
||||
WJD.lpdi = NULL;
|
||||
} else {
|
||||
WJD.init = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
WJD.init = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void joy_Close() {
|
||||
ddio_ff_DetachForce();
|
||||
|
||||
if (!WJD.init)
|
||||
return;
|
||||
|
||||
if (!WJD.lpdi) {
|
||||
joymm_close();
|
||||
}
|
||||
|
||||
mem_free(WJD.joystick);
|
||||
WJD.joystick = NULL;
|
||||
WJD.njoy = 0;
|
||||
WJD.lpdi = NULL;
|
||||
WJD.init = 0;
|
||||
}
|
||||
|
||||
// returns true if joystick valid
|
||||
bool joy_IsValid(tJoystick handle) {
|
||||
if (!WJD.init)
|
||||
return false;
|
||||
if (handle < 0 || handle >= WJD.njoy)
|
||||
return false;
|
||||
|
||||
return WJD.joystick[handle].valid ? true : false;
|
||||
}
|
||||
|
||||
// retreive uncalibrated position of joystick
|
||||
void joy_GetRawPos(tJoystick joy, tJoyPos *pos) {
|
||||
joy_GetPos(joy, pos);
|
||||
pos->x = (pos->x + 128) * JOYAXIS_RANGE;
|
||||
pos->y = (pos->y + 128) * JOYAXIS_RANGE;
|
||||
pos->z = (pos->z + 128) * JOYAXIS_RANGE;
|
||||
pos->r = (pos->r + 128) * JOYAXIS_RANGE;
|
||||
pos->u = (pos->u + 128) * JOYAXIS_RANGE;
|
||||
pos->v = (pos->v + 128) * JOYAXIS_RANGE;
|
||||
}
|
||||
|
||||
// returns the state of a stick, remote or otherwise
|
||||
void joy_GetPos(tJoystick stick, tJoyPos *pos) {
|
||||
ASSERT(stick >= 0 || stick < WJD.njoy);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < JOYPOV_NUM; i++) {
|
||||
pos->pov[i] = JOYPOV_CENTER;
|
||||
}
|
||||
|
||||
if (stick < 0 || stick >= WJD.njoy) {
|
||||
memset(pos, 0, sizeof(tJoyPos));
|
||||
return;
|
||||
}
|
||||
if (!WJD.joystick[stick].valid) {
|
||||
memset(pos, 0, sizeof(tJoyPos));
|
||||
return;
|
||||
}
|
||||
|
||||
if (WJD.lpdi) {
|
||||
joydi_get_pos(stick, pos);
|
||||
} else {
|
||||
joymm_get_pos(stick, pos);
|
||||
}
|
||||
}
|
||||
|
||||
// retreive information about joystick.
|
||||
void joy_GetJoyInfo(tJoystick joy, tJoyInfo *info) {
|
||||
tJoyInfo *srcinfo;
|
||||
ASSERT(joy >= 0 || joy < WJD.njoy);
|
||||
|
||||
if (!WJD.init)
|
||||
return;
|
||||
if (!WJD.joystick[joy].valid)
|
||||
return;
|
||||
srcinfo = &WJD.joystick[joy].caps;
|
||||
|
||||
memcpy(info, srcinfo, sizeof(tJoyInfo));
|
||||
}
|
||||
|
||||
// hook into ddio system if joystick needs any additonal processing per frame.
|
||||
void ddio_InternalJoyFrame() {
|
||||
if (!WJD.init)
|
||||
return;
|
||||
|
||||
if (WJD.lpdi) {
|
||||
int i;
|
||||
tJoystickRecord *joystick = &WJD.joystick[0];
|
||||
for (i = 0; i < WJD.njoy; i++) {
|
||||
int try_count = 0;
|
||||
|
||||
if (joystick->valid) {
|
||||
LPDIRECTINPUTDEVICE2 lpdidev = ddio_ff_get_joystick_obj(joystick->joy_context.ffdev);
|
||||
|
||||
retry_joy_poll:
|
||||
HRESULT hr = lpdidev->Poll();
|
||||
if (hr == DIERR_INPUTLOST && try_count < 2) {
|
||||
ddio_ff_Acquire(joystick->joy_context.ffdev);
|
||||
try_count++;
|
||||
goto retry_joy_poll;
|
||||
}
|
||||
}
|
||||
joystick++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// initializes multimedia version of joystick interface.
|
||||
bool joymm_init() {
|
||||
joymm_init_stick(JOYSTICKID1);
|
||||
if (!joy_chpro_hack) {
|
||||
joymm_init_stick(JOYSTICKID2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// frees joystick library.
|
||||
void joymm_close() {
|
||||
int i;
|
||||
for (i = 0; i < WJD.njoy; i++) {
|
||||
if (WJD.joystick[i].valid) {
|
||||
joymm_close_stick(WJD.joystick[i].joy_context.joyid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// initializes one stick.
|
||||
tJoystick joymm_init_stick(int joyid) {
|
||||
int i;
|
||||
|
||||
// find free joystick slot
|
||||
for (i = 0; i < WJD.njoy; i++) {
|
||||
if (!WJD.joystick[i].valid) {
|
||||
// found slot, lets initialize it and return.
|
||||
JOYCAPS jc;
|
||||
|
||||
if (joyGetDevCaps(joyid, &jc, sizeof(jc)) == JOYERR_NOERROR) {
|
||||
tJoyInfo *caps = &WJD.joystick[i].caps;
|
||||
|
||||
WJD.joystick[i].valid = 1;
|
||||
WJD.joystick[i].joy_context.joyid = joyid;
|
||||
|
||||
memset(caps, 0, sizeof(tJoyInfo));
|
||||
caps->axes_mask =
|
||||
((jc.wCaps & JOYCAPS_HASR) ? JOYFLAG_RVALID : 0) | ((jc.wCaps & JOYCAPS_HASZ) ? JOYFLAG_ZVALID : 0) |
|
||||
((jc.wCaps & JOYCAPS_HASU) ? JOYFLAG_UVALID : 0) | ((jc.wCaps & JOYCAPS_HASV) ? JOYFLAG_VVALID : 0) |
|
||||
((jc.wCaps & JOYCAPS_HASPOV) ? JOYFLAG_POVVALID : 0) | (JOYFLAG_XVALID + JOYFLAG_YVALID);
|
||||
caps->num_btns = (joy_chpro_hack) ? 32 : jc.wNumButtons;
|
||||
caps->minx = jc.wXmin;
|
||||
caps->miny = jc.wYmin;
|
||||
caps->minz = jc.wZmin;
|
||||
caps->minr = jc.wRmin;
|
||||
caps->minu = jc.wUmin;
|
||||
caps->minv = jc.wVmin;
|
||||
caps->maxx = jc.wXmax;
|
||||
caps->maxy = jc.wYmax;
|
||||
caps->maxz = jc.wZmax;
|
||||
caps->maxr = jc.wRmax;
|
||||
caps->maxu = jc.wUmax;
|
||||
caps->maxv = jc.wVmax;
|
||||
|
||||
if (!joyw_get_name(joyid, caps->name, jc.szRegKey)) {
|
||||
sprintf(caps->name, "Joystick-%d", i);
|
||||
}
|
||||
|
||||
return (tJoystick)(i);
|
||||
} else {
|
||||
return (tJoystick)(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void joymm_close_stick(tJoystick handle) {
|
||||
if (handle < 0 || handle >= WJD.njoy)
|
||||
return;
|
||||
|
||||
WJD.joystick[handle].valid = 0;
|
||||
}
|
||||
|
||||
void joymm_get_pos(tJoystick handle, tJoyPos *pos) {
|
||||
JOYINFOEX ji;
|
||||
tJoyInfo *caps;
|
||||
|
||||
if (handle < 0 || handle >= WJD.njoy) {
|
||||
return;
|
||||
}
|
||||
if (!WJD.joystick[handle].valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
caps = &WJD.joystick[handle].caps;
|
||||
|
||||
ZeroMemory(&ji, sizeof(JOYINFOEX));
|
||||
|
||||
ji.dwSize = sizeof(JOYINFOEX);
|
||||
ji.dwFlags = JOY_RETURNCENTERED | JOY_USEDEADZONE | JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNR |
|
||||
JOY_RETURNU | JOY_RETURNV | JOY_RETURNPOV | JOY_RETURNBUTTONS;
|
||||
|
||||
if (joyGetPosEx(WJD.joystick[handle].joy_context.joyid, &ji) != JOYERR_NOERROR) {
|
||||
memset(pos, 0, sizeof(tJoyPos));
|
||||
pos->pov[0] = JOYPOV_CENTER;
|
||||
return;
|
||||
}
|
||||
|
||||
pos->x = (int)((ji.dwXpos << 8) / (caps->maxx - caps->minx)) - 128;
|
||||
pos->y = (int)((ji.dwYpos << 8) / (caps->maxy - caps->miny)) - 128;
|
||||
|
||||
if (caps->axes_mask & JOYFLAG_ZVALID) {
|
||||
pos->z = (int)((ji.dwZpos << 8) / (caps->maxz - caps->minz)) - 128;
|
||||
} else {
|
||||
pos->z = 0;
|
||||
}
|
||||
if (caps->axes_mask & JOYFLAG_RVALID) {
|
||||
pos->r = (int)((ji.dwRpos << 8) / (caps->maxr - caps->minr)) - 128;
|
||||
} else {
|
||||
pos->r = 0;
|
||||
}
|
||||
if (caps->axes_mask & JOYFLAG_UVALID) {
|
||||
pos->u = (int)((ji.dwUpos << 8) / (caps->maxu - caps->minu)) - 128;
|
||||
} else {
|
||||
pos->u = 0;
|
||||
}
|
||||
if (caps->axes_mask & JOYFLAG_VVALID) {
|
||||
pos->v = (int)((ji.dwVpos << 8) / (caps->maxv - caps->minv)) - 128;
|
||||
} else {
|
||||
pos->v = 0;
|
||||
}
|
||||
|
||||
if (caps->axes_mask & JOYFLAG_POVVALID) {
|
||||
ji.dwPOV = ji.dwPOV & 0x0000ffff;
|
||||
if (ji.dwPOV == JOY_POVCENTERED)
|
||||
pos->pov[0] = JOYPOV_CENTER;
|
||||
else
|
||||
pos->pov[0] = (unsigned)(ji.dwPOV * JOYPOV_MAXVAL / 35900.0f);
|
||||
} else {
|
||||
pos->pov[0] = JOYPOV_CENTER;
|
||||
}
|
||||
|
||||
pos->buttons = 0;
|
||||
if (joy_chpro_hack) {
|
||||
if (ji.dwButtons > 0 && ji.dwButtons <= 32) {
|
||||
pos->buttons = 1 << (ji.dwButtons - 1);
|
||||
mprintf(0, "btns=%x\n", pos->buttons);
|
||||
}
|
||||
} else {
|
||||
pos->buttons = (unsigned)ji.dwButtons;
|
||||
}
|
||||
|
||||
pos->btn = (unsigned)ji.dwButtonNumber;
|
||||
|
||||
#ifdef _DEBUG
|
||||
mprintf_at(4, handle + 1, 0, "%d:X:%04d Y:%04d Z:%04d %d:R:%04d U:%04d V:%04d", handle, pos->x, pos->y, pos->z,
|
||||
pos->r, pos->u, pos->v, pos->buttons);
|
||||
#endif
|
||||
}
|
||||
|
||||
void joydi_get_pos(tJoystick handle, tJoyPos *pos) {
|
||||
tJoyInfo *caps;
|
||||
tJoystickRecord *joystick;
|
||||
LPDIRECTINPUTDEVICE2 lpdidev2;
|
||||
DIJOYSTATE ji;
|
||||
HRESULT hr;
|
||||
int try_count = 0;
|
||||
unsigned i;
|
||||
|
||||
if (handle < 0 || handle >= WJD.njoy)
|
||||
return;
|
||||
if (!WJD.joystick[handle].valid)
|
||||
return;
|
||||
|
||||
joystick = &WJD.joystick[handle];
|
||||
caps = &joystick->caps;
|
||||
lpdidev2 = ddio_ff_get_joystick_obj(joystick->joy_context.ffdev);
|
||||
|
||||
if (!lpdidev2) {
|
||||
return;
|
||||
}
|
||||
|
||||
retry_joy_input:
|
||||
hr = lpdidev2->GetDeviceState(sizeof(ji), &ji);
|
||||
if (hr == DIERR_NOTACQUIRED && try_count < 4) {
|
||||
ddio_ff_Acquire(joystick->joy_context.ffdev);
|
||||
try_count++;
|
||||
goto retry_joy_input;
|
||||
} else if (hr != DI_OK) {
|
||||
memset(pos, 0, sizeof(pos));
|
||||
pos->pov[0] = JOYPOV_CENTER;
|
||||
}
|
||||
|
||||
// interpret data.
|
||||
if (caps->axes_mask & JOYFLAG_XVALID) {
|
||||
pos->x = (int)((ji.lX << 8) / (caps->maxx - caps->minx)) - 128;
|
||||
} else {
|
||||
pos->x = 0;
|
||||
}
|
||||
if (caps->axes_mask & JOYFLAG_YVALID) {
|
||||
pos->y = (int)((ji.lY << 8) / (caps->maxy - caps->miny)) - 128;
|
||||
} else {
|
||||
pos->y = 0;
|
||||
}
|
||||
if (caps->axes_mask & JOYFLAG_ZVALID) {
|
||||
pos->z = (int)((ji.lZ << 8) / (caps->maxz - caps->minz)) - 128;
|
||||
} else {
|
||||
pos->z = 0;
|
||||
}
|
||||
if (caps->axes_mask & JOYFLAG_RVALID) {
|
||||
pos->r = (int)((ji.lRz << 8) / (caps->maxr - caps->minr)) - 128;
|
||||
} else {
|
||||
pos->r = 0;
|
||||
}
|
||||
if (caps->axes_mask & JOYFLAG_UVALID) {
|
||||
pos->u = (int)((ji.rglSlider[0] << 8) / (caps->maxu - caps->minu)) - 128;
|
||||
} else {
|
||||
pos->u = 0;
|
||||
}
|
||||
if (caps->axes_mask & JOYFLAG_VVALID) {
|
||||
pos->v = (int)((ji.rglSlider[1] << 8) / (caps->maxv - caps->minv)) - 128;
|
||||
} else {
|
||||
pos->v = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (caps->axes_mask & (JOYFLAG_POVVALID << i)) {
|
||||
if (loword(ji.rgdwPOV[i]) == 0xffff) {
|
||||
pos->pov[i] = JOYPOV_CENTER;
|
||||
} else {
|
||||
int index = (ji.rgdwPOV[i] / 4500);
|
||||
pos->pov[i] = index * 0x20;
|
||||
//@@ switch (index)
|
||||
//@@ {
|
||||
//@@ case 0: pos->pov = JOYPOV_UP; break;
|
||||
//@@ case 1: pos->pov = JOYPOV_RIGHT; break;
|
||||
//@@ case 2: pos->pov = JOYPOV_DOWN; break;
|
||||
//@@ case 3: pos->pov = JOYPOV_LEFT; break;
|
||||
//@@ default: pos->pov = JOYPOV_CENTER;
|
||||
//@@ }
|
||||
}
|
||||
} else {
|
||||
pos->pov[i] = JOYPOV_CENTER;
|
||||
}
|
||||
}
|
||||
|
||||
pos->buttons = 0;
|
||||
for (i = 0; i < caps->num_btns; i++) {
|
||||
if (ji.rgbButtons[i] & 0x80) {
|
||||
pos->buttons |= (1 << i);
|
||||
pos->btn = i;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
mprintf_at(4, (handle * 2) + 1, 0, "J%d:X:%04d Y:%04d Z:%04d Rz:%04d S0:%04d S1:%04d", handle, pos->x, pos->y,
|
||||
pos->z, pos->r, pos->u, pos->v);
|
||||
mprintf_at(4, (handle * 2) + 2, 0, " POV0:%04d POV1:%04d POV2:%04d POV3:%04d", handle, pos->pov[0], pos->pov[1],
|
||||
pos->pov[2], pos->pov[3]);
|
||||
#endif
|
||||
}
|
||||
|
||||
// direct input implementation.
|
||||
tJoystick joydi_init_stick(int ffjoyid) {
|
||||
LPDIRECTINPUTDEVICE2 lpdidev2;
|
||||
|
||||
lpdidev2 = ddio_ff_get_joystick_obj((tDevice)ffjoyid);
|
||||
if (lpdidev2) {
|
||||
// find free joystick slot
|
||||
int i;
|
||||
|
||||
for (i = 0; i < WJD.njoy; i++) {
|
||||
if (!WJD.joystick[i].valid) {
|
||||
// found slot, lets initialize it and return.
|
||||
// get axis, and each of their ranges
|
||||
DIDEVICEOBJECTINSTANCE DIObjInst;
|
||||
DIDEVICEINSTANCE DIDevInst;
|
||||
DIPROPRANGE dirange;
|
||||
DIDEVCAPS dicaps;
|
||||
tDevice dev = (tDevice)ffjoyid;
|
||||
tJoyInfo *caps = &WJD.joystick[i].caps;
|
||||
|
||||
memset(caps, 0, sizeof(tJoyInfo));
|
||||
|
||||
WJD.joystick[i].joy_context.ffdev = dev;
|
||||
WJD.joystick[i].valid = 1;
|
||||
|
||||
// get device info
|
||||
DIDevInst.dwSize = sizeof(DIDEVICEINSTANCE);
|
||||
if (lpdidev2->GetDeviceInfo(&DIDevInst) == DI_OK) {
|
||||
strcpy(WJD.joystick[i].caps.name, DIDevInst.tszProductName);
|
||||
} else {
|
||||
sprintf(WJD.joystick[i].caps.name, "Joystick-%d", i);
|
||||
}
|
||||
|
||||
// get device object info
|
||||
ddio_ff_Acquire(dev);
|
||||
dicaps.dwSize = sizeof(DIDEVCAPS);
|
||||
|
||||
if (lpdidev2->GetCapabilities(&dicaps) != DI_OK) {
|
||||
mprintf(0, "ddio_ffjoy_Query: Failed getting device caps\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DIObjInst.dwSize = sizeof(DIDEVICEOBJECTINSTANCE);
|
||||
|
||||
if (lpdidev2->GetObjectInfo(&DIObjInst, DIJOFS_X, DIPH_BYOFFSET) == DI_OK) {
|
||||
caps->axes_mask |= JOYFLAG_XVALID;
|
||||
}
|
||||
if (lpdidev2->GetObjectInfo(&DIObjInst, DIJOFS_Y, DIPH_BYOFFSET) == DI_OK) {
|
||||
caps->axes_mask |= JOYFLAG_YVALID;
|
||||
}
|
||||
if (lpdidev2->GetObjectInfo(&DIObjInst, DIJOFS_Z, DIPH_BYOFFSET) == DI_OK) {
|
||||
caps->axes_mask |= JOYFLAG_ZVALID;
|
||||
}
|
||||
if (lpdidev2->GetObjectInfo(&DIObjInst, DIJOFS_RZ, DIPH_BYOFFSET) == DI_OK) {
|
||||
caps->axes_mask |= JOYFLAG_RVALID;
|
||||
}
|
||||
if (lpdidev2->GetObjectInfo(&DIObjInst, DIJOFS_SLIDER(0), DIPH_BYOFFSET) == DI_OK) {
|
||||
caps->axes_mask |= JOYFLAG_UVALID;
|
||||
}
|
||||
if (lpdidev2->GetObjectInfo(&DIObjInst, DIJOFS_SLIDER(1), DIPH_BYOFFSET) == DI_OK) {
|
||||
caps->axes_mask |= JOYFLAG_VVALID;
|
||||
}
|
||||
if (lpdidev2->GetObjectInfo(&DIObjInst, DIJOFS_POV(0), DIPH_BYOFFSET) == DI_OK) {
|
||||
caps->axes_mask |= JOYFLAG_POVVALID;
|
||||
}
|
||||
if (lpdidev2->GetObjectInfo(&DIObjInst, DIJOFS_POV(1), DIPH_BYOFFSET) == DI_OK) {
|
||||
caps->axes_mask |= JOYFLAG_POV2VALID;
|
||||
}
|
||||
if (lpdidev2->GetObjectInfo(&DIObjInst, DIJOFS_POV(2), DIPH_BYOFFSET) == DI_OK) {
|
||||
caps->axes_mask |= JOYFLAG_POV3VALID;
|
||||
}
|
||||
if (lpdidev2->GetObjectInfo(&DIObjInst, DIJOFS_POV(3), DIPH_BYOFFSET) == DI_OK) {
|
||||
caps->axes_mask |= JOYFLAG_POV4VALID;
|
||||
}
|
||||
|
||||
caps->num_btns = dicaps.dwButtons;
|
||||
|
||||
dirange.diph.dwSize = sizeof(DIPROPRANGE);
|
||||
dirange.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||
dirange.diph.dwHow = DIPH_BYOFFSET;
|
||||
|
||||
dirange.diph.dwObj = DIJOFS_X;
|
||||
if (lpdidev2->GetProperty(DIPROP_RANGE, (DIPROPHEADER *)&dirange) == DI_OK) {
|
||||
caps->minx = (int)dirange.lMin;
|
||||
caps->maxx = (int)dirange.lMax;
|
||||
}
|
||||
dirange.diph.dwObj = DIJOFS_Y;
|
||||
if (lpdidev2->GetProperty(DIPROP_RANGE, (DIPROPHEADER *)&dirange) == DI_OK) {
|
||||
caps->miny = (int)dirange.lMin;
|
||||
caps->maxy = (int)dirange.lMax;
|
||||
}
|
||||
dirange.diph.dwObj = DIJOFS_Z;
|
||||
if (lpdidev2->GetProperty(DIPROP_RANGE, (DIPROPHEADER *)&dirange) == DI_OK) {
|
||||
caps->minz = (int)dirange.lMin;
|
||||
caps->maxz = (int)dirange.lMax;
|
||||
}
|
||||
dirange.diph.dwObj = DIJOFS_RZ;
|
||||
if (lpdidev2->GetProperty(DIPROP_RANGE, (DIPROPHEADER *)&dirange) == DI_OK) {
|
||||
caps->minr = (int)dirange.lMin;
|
||||
caps->maxr = (int)dirange.lMax;
|
||||
}
|
||||
dirange.diph.dwObj = DIJOFS_SLIDER(0);
|
||||
if (lpdidev2->GetProperty(DIPROP_RANGE, (DIPROPHEADER *)&dirange) == DI_OK) {
|
||||
caps->minu = (int)dirange.lMin;
|
||||
caps->maxu = (int)dirange.lMax;
|
||||
}
|
||||
dirange.diph.dwObj = DIJOFS_SLIDER(1);
|
||||
if (lpdidev2->GetProperty(DIPROP_RANGE, (DIPROPHEADER *)&dirange) == DI_OK) {
|
||||
caps->minv = (int)dirange.lMin;
|
||||
caps->maxv = (int)dirange.lMax;
|
||||
}
|
||||
|
||||
lpdidev2->Poll();
|
||||
|
||||
return (tJoystick)(i);
|
||||
} else {
|
||||
return (tJoystick)(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Int3();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// JAS: Taken from Nov 1996 Game Developer, page 49.
|
||||
// Damn, that is some UGLY code! (But it works...)
|
||||
/*---------------------------------------------------------------------*/
|
||||
bool joyw_get_name(int joy_num, char *szReturnName, const char *szRegKey)
|
||||
/*
|
||||
Description : Opens the MediaResources\Joysitick\mjstick.drv<xxxx>\JoystickSettings and
|
||||
extracts Joystick%dOEMName string
|
||||
Arguments : joy_num (r/o) - Joystick Number
|
||||
szRegKey (r/o) - Registry Key of the msjstick.drv
|
||||
ReturnName (r/w) - Return String for name listed in Control Panel
|
||||
Returns : 0 for success 1 for failure
|
||||
/*-----------------------------------------------------------------------*/
|
||||
{
|
||||
BYTE KeyStr[_MAX_PATH] = REGSTR_PATH_JOYCONFIG; // found in regstr.h
|
||||
BYTE KeyJoySetStr[_MAX_PATH] = REGSTR_KEY_JOYSETTINGS; // found in Regstr.h
|
||||
BYTE szOEMName[_MAX_PATH]; // OEM name from Current Settings
|
||||
HKEY ConfigKey;
|
||||
HKEY JoyConfigKey; // Joystick Configuration
|
||||
HKEY DriverKey; // Joystick Driver Key
|
||||
HKEY OEMPropKey;
|
||||
HKEY PropKey;
|
||||
DWORD Length;
|
||||
if (ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYCONFIG, &ConfigKey))
|
||||
|
||||
{
|
||||
return (false); // It should never get here key received from Caps
|
||||
}
|
||||
|
||||
if (ERROR_SUCCESS != RegOpenKey(ConfigKey, szRegKey, &DriverKey)) {
|
||||
return (false); // It should never get here key received from Caps
|
||||
}
|
||||
// Open CurrentSettings Key
|
||||
|
||||
if (ERROR_SUCCESS != RegOpenKey(DriverKey, REGSTR_KEY_JOYCURR, &JoyConfigKey)) {
|
||||
return (false); // It should never get here always a Current Settings
|
||||
}
|
||||
sprintf((char *)KeyStr, (char *)REGSTR_VAL_JOYNOEMNAME, joy_num + 1);
|
||||
Length = sizeof(szOEMName); // Get OEMNAME Configuration
|
||||
|
||||
if (ERROR_SUCCESS !=
|
||||
RegQueryValueEx(JoyConfigKey, (char *)KeyStr, NULL, NULL, (uint8_t *)&szOEMName, &Length)) {
|
||||
return (false); // No OEM name listed return error
|
||||
}
|
||||
RegCloseKey(ConfigKey); // Closes the registry Key
|
||||
|
||||
// Open OEM Properties Key
|
||||
if (ERROR_SUCCESS != RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_JOYOEM, &PropKey)) {
|
||||
return (false); // It should never get here key received from Caps
|
||||
}
|
||||
|
||||
if (ERROR_SUCCESS != RegOpenKey(PropKey, (char *)szOEMName, &OEMPropKey)) {
|
||||
return (false); // It should never get here if device is selected
|
||||
}
|
||||
Length = _MAX_PATH; // Get Name as listed in Control Panel
|
||||
|
||||
if (ERROR_SUCCESS !=
|
||||
RegQueryValueEx(OEMPropKey, REGSTR_VAL_JOYOEMNAME, NULL, NULL, (uint8_t *)szReturnName, &Length)) {
|
||||
return (false); // No OEM name listed return error
|
||||
}
|
||||
RegCloseKey(OEMPropKey); // Closes the registry Key
|
||||
return true;
|
||||
|
||||
} /* End GetJoystickName */
|
785
ddio/winkey.cpp
785
ddio/winkey.cpp
@ -1,785 +0,0 @@
|
||||
/*
|
||||
* Descent 3
|
||||
* Copyright (C) 2024 Parallax Software
|
||||
*
|
||||
* 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/>.
|
||||
|
||||
--- HISTORICAL COMMENTS FOLLOW ---
|
||||
|
||||
* $Logfile: /DescentIII/Main/ddio_win/winkey.cpp $
|
||||
* $Revision: 36 $
|
||||
* $Date: 4/24/99 5:41p $
|
||||
* $Author: Samir $
|
||||
*
|
||||
* Keyboard IO with DirectInput 3.0
|
||||
*
|
||||
* $Log: /DescentIII/Main/ddio_win/winkey.cpp $
|
||||
*
|
||||
* 36 4/24/99 5:41p Samir
|
||||
* moved key to ascii, ascii to key to the ddio_common library.
|
||||
*
|
||||
* 35 4/22/99 2:02a Jeff
|
||||
* pass ddio_init_info through to keyboard handlers
|
||||
*
|
||||
* 34 3/05/99 3:27p Samir
|
||||
* screenshot key works properly now.
|
||||
*
|
||||
* 33 3/02/99 2:01p Samir
|
||||
* some small directinput changes. (note, for D3, we're now using emulated
|
||||
* key input because of the silly pause and numlock issue which for some
|
||||
* reason fails to work properly under DirectInput.
|
||||
*
|
||||
* 32 3/01/99 12:39a Samir
|
||||
* key ups only occur when key was initially down. because of this,
|
||||
* ddio_KeyFlush cleared the down events, but if the user released after
|
||||
* flush, the up event would leak through and cause the illusion of key
|
||||
* presses leaking through. HOPEFULLY this doesn't break anything else,
|
||||
* but I played through the game a bit and it seems to work fine.
|
||||
*
|
||||
* 31 2/25/99 10:43p Matt
|
||||
* Took out mprintf()
|
||||
*
|
||||
* 30 2/21/99 6:38p Samir
|
||||
* mouse and key input better. buffered mouse.
|
||||
*
|
||||
* 29 2/05/99 1:16p Samir
|
||||
* reset low level keys when flushing keyboard in the high level. added a
|
||||
* function to the low level to reset the status of a key, called from
|
||||
* high level key flush.
|
||||
*
|
||||
* 28 2/04/99 12:31p Samir
|
||||
* use our timer for key capture if we're using the hook method.
|
||||
*
|
||||
* 27 1/28/99 6:22p Samir
|
||||
* may fix thread issues.
|
||||
*
|
||||
* 26 1/25/99 7:27p Samir
|
||||
* fixed timing issues with emulated keyboard key down times. (Win32 sends
|
||||
* multiple keydown messages, so ignore them.)
|
||||
*
|
||||
* 25 1/25/99 6:47p Samir
|
||||
* allow slow keyboard
|
||||
*
|
||||
* 24 1/25/99 11:02a Samir
|
||||
* revamped mouse and key controls.
|
||||
*
|
||||
* 23 10/22/98 11:06a Samir
|
||||
* added numeric keypad ascii translations.
|
||||
*
|
||||
* 22 10/21/98 12:02p Samir
|
||||
* properly update odd keys when they are released throug
|
||||
* ddio_KeyGetDownTime.
|
||||
*
|
||||
* 21 10/16/98 12:15p Samir
|
||||
* took out ddio_KeyFrame
|
||||
*
|
||||
* 20 10/15/98 6:48p Samir
|
||||
* added timer hooks.
|
||||
*
|
||||
* 19 9/17/98 12:50p Samir
|
||||
* language.
|
||||
*
|
||||
* 18 6/29/98 6:43p Samir
|
||||
* Took out GetMsgProc and legacy keyboard variables.
|
||||
*
|
||||
* 17 4/09/98 6:56p Samir
|
||||
* PRINTSCREEN MUST WORK.
|
||||
*
|
||||
* 16 4/08/98 8:40p Samir
|
||||
* Screen shots work with print screen by checking VK code.
|
||||
*
|
||||
* 15 3/31/98 12:46p Samir
|
||||
* keyboard IO system better. uses getmsgproc windows hook.
|
||||
*
|
||||
* 14 3/24/98 11:21a Samir
|
||||
* redid key handler.
|
||||
*
|
||||
* 13 2/25/98 6:11p Samir
|
||||
* Added functions to better deal with key flushing.
|
||||
*
|
||||
* 12 1/21/98 6:46p Samir
|
||||
* NT and 95 should have same keyboard behavior for framed handlers.
|
||||
*
|
||||
* 11 1/02/98 12:52p Samir
|
||||
* Added ascii->keycode translation tables
|
||||
*
|
||||
* 10 12/10/97 1:12p Samir
|
||||
* Use timestamp from DirectInput Key calls.
|
||||
*
|
||||
* 9 11/07/97 6:17p Samir
|
||||
* Rollbacked some more efficient code since it slowed down some machines
|
||||
* in the editor. Sleep thread until closed a little faster.
|
||||
*
|
||||
* 8 10/23/97 2:59p Samir
|
||||
* Keyboard thread uses C runtime lib functions, and definitely ends.
|
||||
*
|
||||
* 7 10/22/97 4:37p Samir
|
||||
* Thread doesn't end if thread is still blocking, I think.
|
||||
*
|
||||
* 6 10/17/97 5:03p Samir
|
||||
* Default to preemptive keyboard handler (not under NT).
|
||||
*
|
||||
* 5 10/16/97 5:35p Samir
|
||||
* Use different cooperative level for Win95 vs. NT.
|
||||
*
|
||||
* 4 10/16/97 2:29p Samir
|
||||
* Changed DirectInput Keyboard to FOREGROUND
|
||||
*
|
||||
* 3 8/01/97 8:14p Samir
|
||||
* Fixed keyboard handler for NT to work with extended keys.
|
||||
*
|
||||
* 2 8/01/97 7:30p Samir
|
||||
* Better NT keyboard support.
|
||||
*
|
||||
* 14 5/23/97 4:09p Samir
|
||||
* Keyboard thread uses new task system.
|
||||
*
|
||||
* 13 5/09/97 6:45p Samir
|
||||
* Took out shared keyboard code from handler to ddio_common
|
||||
*
|
||||
* 12 5/08/97 1:56p Samir
|
||||
* Moved a bunch of keyboard code to ddio_common library.
|
||||
*
|
||||
* 11 3/20/97 11:08a Samir
|
||||
* Added function to peek for keys in queue without removing them.
|
||||
*
|
||||
* 10 3/13/97 3:02p Samir
|
||||
* Hopefully fixed keyboard thread problem.
|
||||
*
|
||||
* 9 2/20/97 9:58a Matt
|
||||
* Took out Int3() for directinput key buffer overflow, which would get
|
||||
* hit if you switched to another task, typed a bunch, and switched back
|
||||
* into the editor
|
||||
*
|
||||
* 8 1/23/97 2:22p Samir
|
||||
* Keyboard thread now blocks properly, and added functionality for
|
||||
* nonpreemptive keyboard polling.
|
||||
*
|
||||
* 7 1/20/97 3:46p Samir
|
||||
* RCS header check in
|
||||
*
|
||||
* $NoKeywords: $
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Keyboard Interface
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "pserror.h"
|
||||
#include "mono.h"
|
||||
#include "ddio.h"
|
||||
#include "ddio_win.h"
|
||||
#include "Application.h"
|
||||
#include "TaskSystem.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <process.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Local global data
|
||||
// ----------------------------------------------------------------------------
|
||||
#define DIKEY_BUFFER_SIZE 32
|
||||
|
||||
static struct tWinKeyData {
|
||||
LPDIRECTINPUTDEVICE lpdikey; // key device
|
||||
HANDLE evtnotify; // notify event
|
||||
HHOOK winhook; // windows hook
|
||||
uintptr_t thread; // thread id
|
||||
//osMutex keyframe_mutex; // mutex between
|
||||
// internal key frame and key thread.
|
||||
bool nextframe; // used for mutexing between keyframe and thread.
|
||||
bool acquired; // device acquired?
|
||||
bool thread_active; // used in thread.
|
||||
bool suspended;
|
||||
} WKD = {NULL, NULL, NULL, 0xffffffff, false, false, false, true};
|
||||
|
||||
volatile struct tWinKeys {
|
||||
union {
|
||||
DWORD up_ticks; // windows ticks when key went up last
|
||||
float up_time;
|
||||
};
|
||||
union {
|
||||
DWORD down_ticks; // windows ticks when key went down last
|
||||
float down_time;
|
||||
};
|
||||
bool status; // is it down?
|
||||
bool mutex_flag; // done for mutexing between ddio_Internal and KeyThread
|
||||
uint16_t mutex_data;
|
||||
} WKeys[DDIO_MAX_KEYS];
|
||||
|
||||
static int DDIO_key_language = KBLANG_AMERICAN;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Initializes DirectInputDevice keyboard if we are under Win9x or at least NT5
|
||||
// we set the cooperative level, etc.
|
||||
LPDIRECTINPUTDEVICE dikey_Init(LPDIRECTINPUT lpdi, HWND hwnd);
|
||||
|
||||
// Shutsdown DirectInputDevice keyboard if passed device is valid.
|
||||
void dikey_Shutdown(LPDIRECTINPUTDEVICE lpdikey);
|
||||
|
||||
// sets up preemptive keyboard handling.
|
||||
HANDLE dikey_EnableNotify(LPDIRECTINPUTDEVICE lpdikey);
|
||||
|
||||
// disables event based notification.
|
||||
bool dikey_DisableNotify(LPDIRECTINPUTDEVICE lpdikey, HANDLE evthandle);
|
||||
|
||||
// acquires or unacquires device
|
||||
// returns device acquisition state.
|
||||
bool dikey_Acquire(LPDIRECTINPUTDEVICE lpdikey, bool acquire);
|
||||
|
||||
// emulated keyboard functionality
|
||||
bool ddio_Win_KeyInit();
|
||||
void ddio_Win_KeyClose();
|
||||
|
||||
int ddio_KeyHandler(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
// DirectInput Keyboard Thread
|
||||
void __cdecl dikey_Thread(void *dp);
|
||||
|
||||
// translates scan code to foreign equivs.
|
||||
uint8_t xlate_scancode(uint8_t scan_code);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Initialization of keyboard device.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// this version will try to initialize a direct input keyboard device. if it fails
|
||||
// it falls back to the old keyboard hook (less reliable but works.)
|
||||
bool ddio_InternalKeyInit(ddio_init_info *init_info) {
|
||||
bool emulated = init_info->key_emulation;
|
||||
|
||||
LPDIRECTINPUTDEVICE lpdikey = NULL;
|
||||
int i;
|
||||
|
||||
// reset key list
|
||||
for (i = 0; i < DDIO_MAX_KEYS; i++) {
|
||||
WKeys[i].down_ticks = 0;
|
||||
WKeys[i].up_ticks = 0;
|
||||
WKeys[i].status = false;
|
||||
}
|
||||
|
||||
// start init.
|
||||
if (!emulated) {
|
||||
lpdikey = dikey_Init(DInputData.lpdi, (HWND)DInputData.app->m_hWnd);
|
||||
}
|
||||
|
||||
retry_key_init:
|
||||
if (lpdikey) {
|
||||
// direct input keyboard can work, so we initialize preemptive handling of the keyboard
|
||||
HANDLE hevt = dikey_EnableNotify(lpdikey);
|
||||
|
||||
if (hevt) {
|
||||
// event handling will work, so let's create the keyboard thread.
|
||||
bool acquired = dikey_Acquire(lpdikey, true);
|
||||
if (acquired) {
|
||||
// create keyboard thread
|
||||
WKD.thread_active = true;
|
||||
WKD.lpdikey = lpdikey;
|
||||
WKD.thread = 0;
|
||||
WKD.evtnotify = hevt;
|
||||
WKD.acquired = acquired;
|
||||
WKD.winhook = NULL;
|
||||
WKD.suspended = false;
|
||||
WKD.nextframe = false;
|
||||
uintptr_t thrid = _beginthread(dikey_Thread, 0, nullptr);
|
||||
if (thrid == -1) {
|
||||
mprintf(0, "DDIO: DI_Keyboard thread failed to initialize.\n");
|
||||
WKD.thread_active = false;
|
||||
WKD.lpdikey = NULL;
|
||||
WKD.thread = 0xffffffff;
|
||||
WKD.evtnotify = NULL;
|
||||
WKD.acquired = false;
|
||||
WKD.winhook = NULL;
|
||||
WKD.suspended = false;
|
||||
acquired = dikey_Acquire(lpdikey, false);
|
||||
dikey_DisableNotify(lpdikey, hevt);
|
||||
dikey_Shutdown(lpdikey);
|
||||
lpdikey = NULL;
|
||||
} else {
|
||||
// success! init data.
|
||||
// set priority of thread too.
|
||||
WKD.thread = thrid;
|
||||
if (SetThreadPriority((HANDLE)thrid, THREAD_PRIORITY_TIME_CRITICAL) == FALSE) {
|
||||
SetThreadPriority((HANDLE)thrid, THREAD_PRIORITY_HIGHEST);
|
||||
}
|
||||
mprintf(0, "DDIO: DI_Keyboard initialized.\n");
|
||||
}
|
||||
} else {
|
||||
// failed to acquire device? can't do.
|
||||
dikey_DisableNotify(lpdikey, hevt);
|
||||
dikey_Shutdown(lpdikey);
|
||||
lpdikey = NULL;
|
||||
}
|
||||
} else {
|
||||
// somehow event notification failed, can't do.
|
||||
dikey_Shutdown(lpdikey);
|
||||
lpdikey = NULL;
|
||||
}
|
||||
|
||||
if (lpdikey == NULL) {
|
||||
goto retry_key_init;
|
||||
}
|
||||
} else {
|
||||
// here, initialize hook procedure.
|
||||
return ddio_Win_KeyInit();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// this will shutdown direct input or the windows hook, whichever was chosen.
|
||||
void ddio_InternalKeyClose() {
|
||||
if (WKD.lpdikey) {
|
||||
// deactivate thread and free it, then unacquire device, disable event notification, and shutdown!
|
||||
WKD.thread_active = false;
|
||||
SetEvent(WKD.evtnotify);
|
||||
Sleep(500);
|
||||
WKD.acquired = dikey_Acquire(WKD.lpdikey, false);
|
||||
dikey_DisableNotify(WKD.lpdikey, WKD.evtnotify);
|
||||
dikey_Shutdown(WKD.lpdikey);
|
||||
WKD.thread = 0xffffffff;
|
||||
WKD.evtnotify = NULL;
|
||||
WKD.lpdikey = NULL;
|
||||
mprintf(0, "DDIO: DI_Keyboard shutdown.\n");
|
||||
}
|
||||
if (WKD.winhook) {
|
||||
ddio_Win_KeyClose();
|
||||
}
|
||||
}
|
||||
|
||||
// handled internally if keyboard system needs additional processing per frame
|
||||
void ddio_InternalKeyFrame() {}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Miscellaneous API
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// returns if key is up or down
|
||||
bool ddio_InternalKeyState(uint8_t key) { return WKeys[key].status; }
|
||||
|
||||
float ddio_InternalKeyDownTime(uint8_t key) {
|
||||
float down_time = 0.0f;
|
||||
if (WKeys[key].status) {
|
||||
if (WKD.winhook) {
|
||||
float timer = timer_GetTime();
|
||||
down_time = timer - WKeys[key].down_time;
|
||||
WKeys[key].down_time = timer;
|
||||
} else {
|
||||
DWORD curtickcount = GetTickCount();
|
||||
DWORD ticks = curtickcount - WKeys[key].down_ticks;
|
||||
if (ticks == 0) {
|
||||
// mprintf(0, "ticks=%d\n", ticks);
|
||||
}
|
||||
WKeys[key].down_ticks = curtickcount;
|
||||
down_time = (ticks / 1000.0f);
|
||||
}
|
||||
} else {
|
||||
if (WKD.winhook) {
|
||||
down_time = WKeys[key].up_time - WKeys[key].down_time;
|
||||
WKeys[key].down_time = WKeys[key].up_time = 0.0f;
|
||||
} else {
|
||||
DWORD ticks = WKeys[key].up_ticks - WKeys[key].down_ticks;
|
||||
WKeys[key].down_ticks = 0;
|
||||
WKeys[key].up_ticks = 0;
|
||||
down_time = (ticks / 1000.0f);
|
||||
}
|
||||
}
|
||||
|
||||
return down_time;
|
||||
}
|
||||
|
||||
// flush a key internally
|
||||
void ddio_InternalResetKey(uint8_t key) {
|
||||
WKeys[key].down_ticks = 0;
|
||||
WKeys[key].up_ticks = 0;
|
||||
WKeys[key].status = false;
|
||||
WKeys[key].mutex_flag = false;
|
||||
WKeys[key].mutex_data = 0;
|
||||
}
|
||||
|
||||
// sets type of keyboard to emulate
|
||||
// #define KBLANG_AMERICAN 0
|
||||
// #define KBLANG_BRITISH 1
|
||||
// #define KBLANG_FRENCH 2
|
||||
// #define KBLANG_GERMAN 3
|
||||
|
||||
void ddio_SetKeyboardLanguage(int language) { DDIO_key_language = language; }
|
||||
|
||||
// translates scan code to foreign equivs.
|
||||
uint8_t xlate_scancode(uint8_t scan_code) {
|
||||
uint8_t code = scan_code;
|
||||
|
||||
if (DDIO_key_language == KBLANG_FRENCH) {
|
||||
switch (scan_code) {
|
||||
case KEY_A:
|
||||
code = KEY_Q;
|
||||
break;
|
||||
case KEY_M:
|
||||
code = KEY_COMMA;
|
||||
break;
|
||||
case KEY_Q:
|
||||
code = KEY_A;
|
||||
break;
|
||||
case KEY_W:
|
||||
code = KEY_Z;
|
||||
break;
|
||||
case KEY_Z:
|
||||
code = KEY_W;
|
||||
break;
|
||||
case KEY_SEMICOL:
|
||||
code = KEY_M;
|
||||
break;
|
||||
case KEY_COMMA:
|
||||
code = KEY_SEMICOL;
|
||||
break;
|
||||
}
|
||||
} else if (DDIO_key_language == KBLANG_GERMAN) {
|
||||
switch (scan_code) {
|
||||
case KEY_Y:
|
||||
code = KEY_Z;
|
||||
break;
|
||||
case KEY_Z:
|
||||
code = KEY_Y;
|
||||
break;
|
||||
}
|
||||
} else if (DDIO_key_language == KBLANG_BRITISH) {
|
||||
if (scan_code == KEY_BSLASH_UK) { // KEY_SLASH_UK == 0x56
|
||||
code = KEY_SLASH; // KEY_SLASH is really the backslash, 0x2B
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// DirectInput Functions
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool IS_NT4_OR_LOWER() {
|
||||
int maj, min;
|
||||
tWin32OS os = oeWin32Application::version(&maj, &min);
|
||||
return (os == WinNT && maj < 5) ? true : false;
|
||||
}
|
||||
|
||||
// Initializes DirectInputDevice keyboard if we are under Win9x or at least NT5
|
||||
// we set the cooperative level, etc.
|
||||
LPDIRECTINPUTDEVICE dikey_Init(LPDIRECTINPUT lpdi, HWND hwnd) {
|
||||
LPDIRECTINPUTDEVICE lpdikey;
|
||||
HRESULT hr;
|
||||
|
||||
if (IS_NT4_OR_LOWER()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// see if we can get the keyboard device.
|
||||
hr = lpdi->CreateDevice(GUID_SysKeyboard, &lpdikey, NULL);
|
||||
if (hr != DI_OK) {
|
||||
DDIO_MESSAGE((hr, "DI_Keyboard initialization failed."));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hr = lpdikey->SetDataFormat(&c_dfDIKeyboard);
|
||||
if (hr != DI_OK) {
|
||||
DDIO_MESSAGE((hr, "DI_Keyboard data format specification failed."));
|
||||
lpdikey->Release();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hr = lpdikey->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND);
|
||||
if (hr != DI_OK) {
|
||||
DDIO_MESSAGE((hr, "DI_Keyboard set cooperative level failed."));
|
||||
lpdikey->Release();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return lpdikey;
|
||||
}
|
||||
|
||||
// Shutsdown DirectInputDevice keyboard if passed device is valid.
|
||||
void dikey_Shutdown(LPDIRECTINPUTDEVICE lpdikey) {
|
||||
if (lpdikey) {
|
||||
lpdikey->Release();
|
||||
}
|
||||
}
|
||||
|
||||
// sets up preemptive keyboard handling.
|
||||
HANDLE dikey_EnableNotify(LPDIRECTINPUTDEVICE lpdikey) {
|
||||
if (lpdikey) {
|
||||
HANDLE hEvt = CreateEvent(NULL, TRUE, FALSE, "DDIOKeyEvent");
|
||||
HRESULT hr;
|
||||
DIPROPDWORD dipropdw = {
|
||||
{
|
||||
sizeof(DIPROPDWORD),
|
||||
sizeof(DIPROPHEADER),
|
||||
0,
|
||||
DIPH_DEVICE,
|
||||
},
|
||||
DIKEY_BUFFER_SIZE,
|
||||
};
|
||||
|
||||
if (!hEvt) {
|
||||
DDIO_MESSAGE((0, "DI_Keyboard failed to init system event."));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// set event
|
||||
hr = lpdikey->SetEventNotification(hEvt);
|
||||
if (hr != DI_OK) {
|
||||
DDIO_MESSAGE((hr, "DI_Keyboard failed to set preemptive key event notification."));
|
||||
CloseHandle(hEvt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// set key buffer size
|
||||
hr = lpdikey->SetProperty(DIPROP_BUFFERSIZE, &dipropdw.diph);
|
||||
if (FAILED(hr)) {
|
||||
DDIO_MESSAGE((hr, "DI_keyboard buffering failed."));
|
||||
lpdikey->SetEventNotification(NULL);
|
||||
CloseHandle(hEvt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hEvt;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// disables event based notification.
|
||||
bool dikey_DisableNotify(LPDIRECTINPUTDEVICE lpdikey, HANDLE evthandle) {
|
||||
if (lpdikey) {
|
||||
lpdikey->SetEventNotification(NULL);
|
||||
CloseHandle(evthandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// acquires or unacquires device
|
||||
// returns device acquisition state.
|
||||
bool dikey_Acquire(LPDIRECTINPUTDEVICE lpdikey, bool acquire) {
|
||||
HRESULT hr = acquire ? lpdikey->Acquire() : lpdikey->Unacquire();
|
||||
|
||||
if (FAILED(hr)) {
|
||||
DDIO_MESSAGE((hr, "DI_keyboard acquire/unacquire fail."));
|
||||
return !acquire;
|
||||
}
|
||||
|
||||
return acquire;
|
||||
}
|
||||
|
||||
// DirectInput Keyboard Thread
|
||||
void __cdecl dikey_Thread(void *dp) {
|
||||
unsigned event_count = 0;
|
||||
|
||||
GetAsyncKeyState(VK_PAUSE); // this will tell if the 'pause' key is toggled
|
||||
|
||||
while (WKD.thread_active) {
|
||||
// this thread will hold until the direct input key event has been signaled by the OS.
|
||||
// after this, we will get all the keys in the io buffer and register them with the
|
||||
// key system.
|
||||
|
||||
switch (WaitForSingleObject(WKD.evtnotify, INFINITE)) {
|
||||
case WAIT_TIMEOUT: // this shouldn't happen, but if it does, no big deal.
|
||||
break;
|
||||
case WAIT_ABANDONED: // usually means calling thread quit.
|
||||
WKD.thread_active = false;
|
||||
break;
|
||||
case WAIT_OBJECT_0: // event was signalled normally
|
||||
{
|
||||
DIDEVICEOBJECTDATA diobjdata[DIKEY_BUFFER_SIZE];
|
||||
DWORD diobjitems = DIKEY_BUFFER_SIZE;
|
||||
HRESULT hr;
|
||||
// SHORT async_key_state;
|
||||
uint8_t key;
|
||||
|
||||
int i;
|
||||
|
||||
// don't read if suspended!
|
||||
if (WKD.suspended) {
|
||||
break;
|
||||
}
|
||||
|
||||
event_count++;
|
||||
|
||||
// attempt acquisition if keyboard not already acquired
|
||||
if (!WKD.acquired) {
|
||||
WKD.acquired = dikey_Acquire(WKD.lpdikey, true);
|
||||
}
|
||||
if (WKD.acquired) {
|
||||
hr = WKD.lpdikey->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), diobjdata, &diobjitems, 0);
|
||||
if (SUCCEEDED(hr)) {
|
||||
// the pause is key under Windows seems to act kinda strange. it's a toggle button
|
||||
// and USUALLY is preceeded by a KEY_LCTRL press. If a pause toggle was indicated, flush the
|
||||
// keyboard and quit.
|
||||
|
||||
// note that dwOfs is the acutal key that is either down or up, and dwData tells us if
|
||||
// it is up or down. So place on key array, and in queue.
|
||||
for (i = 0; i < (int)diobjitems; i++) {
|
||||
key = xlate_scancode((uint8_t)(diobjdata[i].dwOfs));
|
||||
if (diobjdata[i].dwData & 0x80) {
|
||||
if (WKeys[key].status) {
|
||||
WKeys[key].up_ticks = 0;
|
||||
}
|
||||
WKeys[key].down_ticks = diobjdata[i].dwTimeStamp;
|
||||
WKeys[key].status = true;
|
||||
if (key == KEY_LCTRL) {
|
||||
WKeys[key].mutex_flag = true;
|
||||
}
|
||||
mprintf(0, "dkey=%x\n", key);
|
||||
} else {
|
||||
if (WKeys[key].status) {
|
||||
WKeys[key].up_ticks = diobjdata[i].dwTimeStamp;
|
||||
WKeys[key].status = false;
|
||||
mprintf(0, "ukey=%x\n", key);
|
||||
}
|
||||
}
|
||||
|
||||
ddio_UpdateKeyState(key, WKeys[key].status);
|
||||
}
|
||||
} else {
|
||||
if (hr == DIERR_INPUTLOST) {
|
||||
WKD.acquired = dikey_Acquire(WKD.lpdikey, true);
|
||||
} else {
|
||||
DDIO_MESSAGE((hr, "DI_keyboard unable to read."));
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
ResetEvent(WKD.evtnotify);
|
||||
}
|
||||
|
||||
DDIO_MESSAGE((0, "DI_Keyboard thread ended."));
|
||||
}
|
||||
|
||||
void ddio_InternalKeySuspend() {
|
||||
if (WKD.lpdikey && WKD.acquired) {
|
||||
WKD.acquired = dikey_Acquire(WKD.lpdikey, false);
|
||||
}
|
||||
WKD.suspended = true;
|
||||
}
|
||||
|
||||
void ddio_InternalKeyResume() {
|
||||
if (WKD.lpdikey && !WKD.acquired) {
|
||||
WKD.acquired = dikey_Acquire(WKD.lpdikey, true);
|
||||
}
|
||||
WKD.suspended = false;
|
||||
}
|
||||
|
||||
// Win32 non-threaded version
|
||||
|
||||
bool ddio_Win_KeyInit() {
|
||||
/* Initialize hook handlers */
|
||||
WKD.winhook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, (HINSTANCE)DInputData.app->m_hInstance,
|
||||
GetCurrentThreadId());
|
||||
if (!WKD.winhook) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mprintf(0, "Keyboard initialized.\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ddio_Win_KeyClose() {
|
||||
/* Free up message handlers */
|
||||
if (WKD.winhook) {
|
||||
UnhookWindowsHookEx(WKD.winhook);
|
||||
WKD.winhook = NULL;
|
||||
}
|
||||
|
||||
mprintf(0, "Keyboard released.\n");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// non DirectInput keyboard handler
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
|
||||
int res;
|
||||
|
||||
if (code < 0) {
|
||||
return CallNextHookEx(WKD.winhook, code, wParam, lParam);
|
||||
}
|
||||
|
||||
if (lParam & 0x80000000)
|
||||
res = ddio_KeyHandler(0, WM_KEYUP, wParam, lParam);
|
||||
else
|
||||
res = ddio_KeyHandler(0, WM_KEYDOWN, wParam, lParam);
|
||||
|
||||
return (!res);
|
||||
}
|
||||
|
||||
int ddio_KeyHandler(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
uint8_t scan_code;
|
||||
float timer = timer_GetTime();
|
||||
|
||||
if (!WKD.winhook)
|
||||
return 1;
|
||||
|
||||
switch (msg) {
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
scan_code = (uint8_t)((lParam >> 16) & 0xff);
|
||||
if (lParam & 0x01000000)
|
||||
scan_code |= 0x80;
|
||||
|
||||
scan_code = xlate_scancode(scan_code);
|
||||
|
||||
// print screen is a weird case. only accept key ups.
|
||||
if (wParam != VK_SNAPSHOT) {
|
||||
if (!WKeys[scan_code].status) {
|
||||
WKeys[scan_code].up_time = 0;
|
||||
WKeys[scan_code].down_time = timer;
|
||||
} else {
|
||||
WKeys[scan_code].up_time = 0;
|
||||
}
|
||||
WKeys[scan_code].status = true;
|
||||
ddio_UpdateKeyState(scan_code, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
scan_code = (uint8_t)((lParam >> 16) & 0xff);
|
||||
if (lParam & 0x01000000)
|
||||
scan_code |= 0x80;
|
||||
|
||||
scan_code = xlate_scancode(scan_code);
|
||||
|
||||
// handle special keys. print screen, we will simulate the keypress.
|
||||
if (wParam == VK_SNAPSHOT) {
|
||||
scan_code = KEY_PRINT_SCREEN;
|
||||
WKeys[scan_code].down_time = timer;
|
||||
WKeys[scan_code].status = true;
|
||||
ddio_UpdateKeyState(scan_code, true);
|
||||
}
|
||||
if (WKeys[scan_code].status) {
|
||||
WKeys[scan_code].status = false;
|
||||
WKeys[scan_code].up_time = timer;
|
||||
ddio_UpdateKeyState(scan_code, false);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
@ -1,629 +0,0 @@
|
||||
/*
|
||||
* Descent 3
|
||||
* Copyright (C) 2024 Parallax Software
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Mouse Interface
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "pserror.h"
|
||||
#include "mono.h"
|
||||
#include "ddio.h"
|
||||
#include "ddio_win.h"
|
||||
#include "Application.h"
|
||||
#include "psclass.h"
|
||||
#include "Macros.h"
|
||||
|
||||
struct t_mse_button_info {
|
||||
bool is_down[N_MSEBTNS];
|
||||
uint8_t down_count[N_MSEBTNS];
|
||||
uint8_t up_count[N_MSEBTNS];
|
||||
DWORD time_down[N_MSEBTNS]; // in milliseconds windows ticks
|
||||
DWORD time_up[N_MSEBTNS];
|
||||
};
|
||||
|
||||
struct t_mse_event {
|
||||
int16_t btn;
|
||||
int16_t state;
|
||||
};
|
||||
|
||||
#define MOUSE_ZMIN 0 // mouse wheel z min and max (increments of 120 = 10 units)
|
||||
#define MOUSE_ZMAX 1200
|
||||
#define N_DIMSEBTNS 4 // # of REAL mouse buttons
|
||||
#define MSEBTN_WHL_UP (N_DIMSEBTNS) // button index for mouse wheel up
|
||||
#define MSEBTN_WHL_DOWN (N_DIMSEBTNS + 1) // button index for mouse wheel down
|
||||
|
||||
// taken from winuser.h
|
||||
#ifndef WHEEL_DELTA
|
||||
#define WHEEL_DELTA 120
|
||||
#endif
|
||||
#ifndef WM_MOUSEWHEEL
|
||||
#define WM_MOUSEWHEEL 0x20a
|
||||
#endif
|
||||
|
||||
bool rawInputOpened = false;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static bool DDIO_mouse_init = 0;
|
||||
|
||||
static struct mses_state {
|
||||
LPDIRECTINPUTDEVICE lpdimse;
|
||||
RECT brect; // limit rectangle of absolute mouse coords
|
||||
int16_t x, y, z; // current x,y,z in absolute mouse coords
|
||||
int16_t cx, cy, cz; // prior values of x,y,z from last mouse frame
|
||||
int16_t zmin, zmax; // 3 dimensional mouse devices use this
|
||||
int btn_mask, btn_flags; // btn_flags are the avaiable buttons on this device in mask form.
|
||||
float timer; // done to keep track of mouse polling. [ISB] this is in InjectD3 but not here?
|
||||
bool emulated; // are we emulating direct input?
|
||||
bool acquired;
|
||||
bool suspended;
|
||||
int8_t cursor_count;
|
||||
float x_aspect, y_aspect; // used in calculating coordinates returned from ddio_MouseGetState
|
||||
HANDLE hmseevt; // signaled if mouse input is awaiting.
|
||||
int16_t dx, dy, dz, imm_dz;
|
||||
int16_t mode; // mode of mouse operation.
|
||||
int16_t nbtns, naxis; // device caps.
|
||||
} DDIO_mouse_state;
|
||||
|
||||
// Normally mouse events use ticks, attempting to use timer_GetTime which has more accuracy to smooth over bug with
|
||||
// mouse buttons dropping.
|
||||
float localDownStart[N_MSEBTNS];
|
||||
float localUpStart[N_MSEBTNS];
|
||||
|
||||
static t_mse_button_info DIM_buttons;
|
||||
static tQueue<t_mse_event, 16> MB_queue;
|
||||
|
||||
int wheelAccum = 0;
|
||||
|
||||
void DDIOShowCursor(BOOL show) {
|
||||
if (show) {
|
||||
if (DDIO_mouse_state.cursor_count == -1) {
|
||||
ShowCursor(TRUE);
|
||||
}
|
||||
DDIO_mouse_state.cursor_count = 0;
|
||||
} else {
|
||||
if (DDIO_mouse_state.cursor_count == 0) {
|
||||
ShowCursor(FALSE);
|
||||
}
|
||||
DDIO_mouse_state.cursor_count = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void ddio_MouseMode(int mode) {
|
||||
DDIO_mouse_state.mode = mode;
|
||||
}
|
||||
|
||||
void ddio_MouseQueueFlush() {
|
||||
memset(&DIM_buttons, 0, sizeof(DIM_buttons));
|
||||
MB_queue.flush();
|
||||
|
||||
// Need to clear the new arrays, since otherwise the game will think you're holding down a button when leaving a UI
|
||||
// screen.
|
||||
memset(localDownStart, 0, sizeof(localDownStart));
|
||||
memset(localUpStart, 0, sizeof(localUpStart));
|
||||
}
|
||||
|
||||
void ddio_MouseReset() {
|
||||
// get relative window rect, 0/0 - width-1/height-1
|
||||
GetClientRect(DInputData.hwnd, &DDIO_mouse_state.brect);
|
||||
// restrict mouse cursor to actual screen coords of the window
|
||||
RECT clipRect = DDIO_mouse_state.brect;
|
||||
ClientToScreen(DInputData.hwnd, reinterpret_cast<POINT *>(&clipRect.left));
|
||||
ClientToScreen(DInputData.hwnd, reinterpret_cast<POINT *>(&clipRect.right));
|
||||
ClipCursor(&clipRect);
|
||||
|
||||
DDIO_mouse_state.zmin = MOUSE_ZMIN;
|
||||
DDIO_mouse_state.zmax = MOUSE_ZMAX;
|
||||
|
||||
// set up new coordinates for mouse pointer.
|
||||
DDIO_mouse_state.btn_mask = 0;
|
||||
DDIO_mouse_state.dx = 0;
|
||||
DDIO_mouse_state.dy = 0;
|
||||
DDIO_mouse_state.dz = 0;
|
||||
DDIO_mouse_state.imm_dz = 0;
|
||||
DDIO_mouse_state.x = (DDIO_mouse_state.brect.right + DDIO_mouse_state.brect.left) / 2;
|
||||
DDIO_mouse_state.y = (DDIO_mouse_state.brect.bottom + DDIO_mouse_state.brect.top) / 2;
|
||||
DDIO_mouse_state.z = (DDIO_mouse_state.zmax + DDIO_mouse_state.zmin) / 2;
|
||||
DDIO_mouse_state.cx = DDIO_mouse_state.x;
|
||||
DDIO_mouse_state.cy = DDIO_mouse_state.y;
|
||||
DDIO_mouse_state.cz = 0;
|
||||
DDIO_mouse_state.x_aspect = 1.0f;
|
||||
DDIO_mouse_state.y_aspect = 1.0f;
|
||||
|
||||
// reset button states
|
||||
ddio_MouseQueueFlush();
|
||||
}
|
||||
|
||||
// return mouse button down time.
|
||||
// This function has been hacked to use timer_GetTime which can be much more accurate.
|
||||
float ddio_MouseBtnDownTime(int btn) {
|
||||
// DWORD ticks, curticks = GetTickCount();
|
||||
float time, curtime = timer_GetTime();
|
||||
|
||||
// ASSERT(btn >= 0 && btn < N_MSEBTNS);
|
||||
|
||||
if (DIM_buttons.is_down[btn]) {
|
||||
time = curtime - localDownStart[btn];
|
||||
DIM_buttons.time_down[btn] = (int)(curtime * 1000);
|
||||
localDownStart[btn] = curtime;
|
||||
} else {
|
||||
time = localUpStart[btn] - localDownStart[btn];
|
||||
localUpStart[btn] = localDownStart[btn] = 0;
|
||||
DIM_buttons.time_down[btn] = DIM_buttons.time_up[btn] = 0;
|
||||
}
|
||||
|
||||
DIM_buttons.is_down[MSEBTN_WHL_UP] = false;
|
||||
DIM_buttons.is_down[MSEBTN_WHL_DOWN] = false;
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
int ddio_MouseGetState(int *x, int *y, int *dx, int *dy, int *z, int *dz) {
|
||||
// update mouse timer.
|
||||
int btn_mask = DDIO_mouse_state.btn_mask;
|
||||
|
||||
DDIO_mouse_state.timer = timer_GetTime();
|
||||
|
||||
// get return values.
|
||||
if (x)
|
||||
*x = DDIO_mouse_state.x;
|
||||
if (y)
|
||||
*y = DDIO_mouse_state.y;
|
||||
if (z)
|
||||
*z = DDIO_mouse_state.z;
|
||||
if (dx)
|
||||
*dx = DDIO_mouse_state.dx;
|
||||
if (dy)
|
||||
*dy = DDIO_mouse_state.dy;
|
||||
if (dz)
|
||||
*dz = DDIO_mouse_state.dz;
|
||||
|
||||
DDIO_mouse_state.dx = 0;
|
||||
DDIO_mouse_state.dy = 0;
|
||||
DDIO_mouse_state.dz = 0;
|
||||
DDIO_mouse_state.btn_mask = 0;
|
||||
|
||||
DIM_buttons.is_down[MSEBTN_WHL_UP] = false;
|
||||
DIM_buttons.is_down[MSEBTN_WHL_DOWN] = false;
|
||||
|
||||
return btn_mask;
|
||||
}
|
||||
|
||||
void ddio_InternalMouseFrame() {
|
||||
int btn_mask = 0;
|
||||
|
||||
// These need to be continually maintained, since a small number of inputs rely on it being set every frame.
|
||||
if (DIM_buttons.is_down[0])
|
||||
btn_mask |= MOUSE_LB;
|
||||
if (DIM_buttons.is_down[1])
|
||||
btn_mask |= MOUSE_RB;
|
||||
if (DIM_buttons.is_down[2])
|
||||
btn_mask |= MOUSE_CB;
|
||||
if (DIM_buttons.is_down[3])
|
||||
btn_mask |= MOUSE_B4;
|
||||
if (DIM_buttons.is_down[4])
|
||||
btn_mask |= MOUSE_B5;
|
||||
if (DIM_buttons.is_down[5])
|
||||
btn_mask |= MOUSE_B6;
|
||||
if (DIM_buttons.is_down[6])
|
||||
btn_mask |= MOUSE_B7;
|
||||
if (DIM_buttons.is_down[7])
|
||||
btn_mask |= MOUSE_B8;
|
||||
|
||||
DDIO_mouse_state.btn_mask = btn_mask;
|
||||
}
|
||||
|
||||
void MouseError() { MessageBoxA(nullptr, "Failed to init raw input for mouse", "Error", MB_ICONERROR); }
|
||||
|
||||
int RawInputHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
uint32_t buttons;
|
||||
t_mse_event ev;
|
||||
float curtime = timer_GetTime();
|
||||
|
||||
if (DDIO_mouse_state.suspended) {
|
||||
DDIO_mouse_state.btn_mask = 0;
|
||||
DDIO_mouse_state.dx = 0;
|
||||
DDIO_mouse_state.dy = 0;
|
||||
DDIO_mouse_state.dz = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
HRAWINPUT rawinputHandle = (HRAWINPUT)lParam;
|
||||
UINT size = 0;
|
||||
UINT result = GetRawInputData(rawinputHandle, RID_INPUT, 0, &size, sizeof(RAWINPUTHEADER));
|
||||
if (result == 0 && size > 0) {
|
||||
void *buf = malloc(size);
|
||||
if (!buf) {
|
||||
return 0;
|
||||
}
|
||||
result = GetRawInputData(rawinputHandle, RID_INPUT, buf, &size, sizeof(RAWINPUTHEADER));
|
||||
|
||||
if (result >= 0) {
|
||||
RAWINPUT *rawinput = (RAWINPUT *)buf;
|
||||
if (rawinput->header.dwType == RIM_TYPEMOUSE) {
|
||||
buttons = rawinput->data.mouse.ulButtons;
|
||||
if (buttons & RI_MOUSE_LEFT_BUTTON_DOWN && !DIM_buttons.is_down[0]) {
|
||||
DIM_buttons.down_count[0]++;
|
||||
DIM_buttons.time_down[0] = GetTickCount();
|
||||
localDownStart[0] = curtime;
|
||||
DIM_buttons.is_down[0] = true;
|
||||
DDIO_mouse_state.btn_mask |= MOUSE_LB;
|
||||
ev.btn = 0;
|
||||
ev.state = true;
|
||||
MB_queue.send(ev);
|
||||
/*if (hack)
|
||||
{
|
||||
fprintf(hack, "MB1 down at %f\n", timer_GetTime());
|
||||
}*/
|
||||
} else if (buttons & RI_MOUSE_LEFT_BUTTON_UP && DIM_buttons.is_down[0]) {
|
||||
DIM_buttons.up_count[0]++;
|
||||
DIM_buttons.is_down[0] = false;
|
||||
DIM_buttons.time_up[0] = GetTickCount();
|
||||
localUpStart[0] = curtime;
|
||||
DDIO_mouse_state.btn_mask &= ~MOUSE_LB;
|
||||
ev.btn = 0;
|
||||
ev.state = false;
|
||||
MB_queue.send(ev);
|
||||
/*if (hack)
|
||||
{
|
||||
fprintf(hack, "MB1 up at %f\n", timer_GetTime());
|
||||
}*/
|
||||
}
|
||||
if (buttons & RI_MOUSE_RIGHT_BUTTON_DOWN && !DIM_buttons.is_down[1]) {
|
||||
DIM_buttons.down_count[1]++;
|
||||
DIM_buttons.time_down[1] = GetTickCount();
|
||||
localDownStart[1] = curtime;
|
||||
DIM_buttons.is_down[1] = true;
|
||||
DDIO_mouse_state.btn_mask |= MOUSE_RB;
|
||||
ev.btn = 1;
|
||||
ev.state = true;
|
||||
MB_queue.send(ev);
|
||||
} else if (buttons & RI_MOUSE_RIGHT_BUTTON_UP && DIM_buttons.is_down[1]) {
|
||||
DIM_buttons.up_count[1]++;
|
||||
DIM_buttons.is_down[1] = false;
|
||||
DIM_buttons.time_up[1] = GetTickCount();
|
||||
localUpStart[1] = curtime;
|
||||
DDIO_mouse_state.btn_mask &= ~MOUSE_RB;
|
||||
ev.btn = 1;
|
||||
ev.state = false;
|
||||
MB_queue.send(ev);
|
||||
}
|
||||
if (buttons & RI_MOUSE_MIDDLE_BUTTON_DOWN && !DIM_buttons.is_down[2]) {
|
||||
DIM_buttons.down_count[2]++;
|
||||
DIM_buttons.time_down[2] = GetTickCount();
|
||||
localDownStart[2] = curtime;
|
||||
DIM_buttons.is_down[2] = true;
|
||||
DDIO_mouse_state.btn_mask |= MOUSE_CB;
|
||||
ev.btn = 2;
|
||||
ev.state = true;
|
||||
MB_queue.send(ev);
|
||||
} else if (buttons & RI_MOUSE_MIDDLE_BUTTON_UP && DIM_buttons.is_down[2]) {
|
||||
DIM_buttons.up_count[2]++;
|
||||
DIM_buttons.is_down[2] = false;
|
||||
DIM_buttons.time_up[2] = GetTickCount();
|
||||
localUpStart[2] = curtime;
|
||||
DDIO_mouse_state.btn_mask &= ~MOUSE_CB;
|
||||
ev.btn = 2;
|
||||
ev.state = false;
|
||||
MB_queue.send(ev);
|
||||
}
|
||||
|
||||
// JC: Imported extra mouse buttons code from Piccu Engine 2924ad2
|
||||
if (buttons & RI_MOUSE_BUTTON_4_DOWN && !DIM_buttons.is_down[3])
|
||||
{
|
||||
DIM_buttons.down_count[3]++;
|
||||
DIM_buttons.time_down[3] = curtime;
|
||||
DIM_buttons.is_down[3] = true;
|
||||
DDIO_mouse_state.btn_mask |= MOUSE_B4;
|
||||
ev.btn = 3;
|
||||
ev.state = true;
|
||||
MB_queue.send(ev);
|
||||
}
|
||||
else if (buttons & RI_MOUSE_BUTTON_4_UP && DIM_buttons.is_down[3])
|
||||
{
|
||||
DIM_buttons.up_count[3]++;
|
||||
DIM_buttons.is_down[3] = false;
|
||||
DIM_buttons.time_up[3] = curtime;
|
||||
DDIO_mouse_state.btn_mask &= ~MOUSE_B4;
|
||||
ev.btn = 3;
|
||||
ev.state = false;
|
||||
MB_queue.send(ev);
|
||||
}
|
||||
if (buttons & RI_MOUSE_BUTTON_5_DOWN && !DIM_buttons.is_down[6])
|
||||
{
|
||||
DIM_buttons.down_count[6]++;
|
||||
DIM_buttons.time_down[6] = curtime;
|
||||
DIM_buttons.is_down[6] = true;
|
||||
DDIO_mouse_state.btn_mask |= MOUSE_B7;
|
||||
ev.btn = 6;
|
||||
ev.state = true;
|
||||
MB_queue.send(ev);
|
||||
} else if (buttons & RI_MOUSE_BUTTON_5_UP && DIM_buttons.is_down[6])
|
||||
{
|
||||
DIM_buttons.up_count[6]++;
|
||||
DIM_buttons.is_down[6] = false;
|
||||
DIM_buttons.time_up[6] = curtime;
|
||||
DDIO_mouse_state.btn_mask &= ~MOUSE_B7;
|
||||
ev.btn = 6;
|
||||
ev.state = false;
|
||||
MB_queue.send(ev);
|
||||
}
|
||||
|
||||
if (buttons & RI_MOUSE_WHEEL) {
|
||||
wheelAccum += (int)(int16_t)rawinput->data.mouse.usButtonData;
|
||||
if (wheelAccum >= WHEEL_DELTA) {
|
||||
DIM_buttons.down_count[MSEBTN_WHL_UP]++;
|
||||
DIM_buttons.up_count[MSEBTN_WHL_UP]++;
|
||||
DIM_buttons.is_down[MSEBTN_WHL_UP] = true;
|
||||
DIM_buttons.time_down[MSEBTN_WHL_UP] = GetTickCount();
|
||||
DIM_buttons.time_up[MSEBTN_WHL_UP] = GetTickCount() + 100;
|
||||
localDownStart[MSEBTN_WHL_UP] = curtime;
|
||||
localUpStart[MSEBTN_WHL_UP] = curtime + .1f;
|
||||
wheelAccum = 0;
|
||||
} else if (wheelAccum <= -WHEEL_DELTA) {
|
||||
DIM_buttons.down_count[MSEBTN_WHL_DOWN]++;
|
||||
DIM_buttons.up_count[MSEBTN_WHL_DOWN]++;
|
||||
DIM_buttons.is_down[MSEBTN_WHL_DOWN] = true;
|
||||
DIM_buttons.time_down[MSEBTN_WHL_DOWN] = GetTickCount();
|
||||
DIM_buttons.time_up[MSEBTN_WHL_DOWN] = GetTickCount() + 100;
|
||||
localDownStart[MSEBTN_WHL_DOWN] = curtime;
|
||||
localUpStart[MSEBTN_WHL_DOWN] = curtime + .1f;
|
||||
wheelAccum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DDIO_mouse_state.dx += rawinput->data.mouse.lLastX;
|
||||
DDIO_mouse_state.dy += rawinput->data.mouse.lLastY;
|
||||
// DDIO_mouse_state.btn_mask = buttons;
|
||||
}
|
||||
|
||||
DDIO_mouse_state.x += rawinput->data.mouse.lLastX;
|
||||
DDIO_mouse_state.y += rawinput->data.mouse.lLastY;
|
||||
DDIO_mouse_state.z = 0;
|
||||
|
||||
// check bounds of mouse cursor.
|
||||
if (DDIO_mouse_state.x < DDIO_mouse_state.brect.left)
|
||||
DDIO_mouse_state.x = (int16_t)DDIO_mouse_state.brect.left;
|
||||
if (DDIO_mouse_state.x >= DDIO_mouse_state.brect.right)
|
||||
DDIO_mouse_state.x = (int16_t)DDIO_mouse_state.brect.right - 1;
|
||||
if (DDIO_mouse_state.y < DDIO_mouse_state.brect.top)
|
||||
DDIO_mouse_state.y = (int16_t)DDIO_mouse_state.brect.top;
|
||||
if (DDIO_mouse_state.y >= DDIO_mouse_state.brect.bottom)
|
||||
DDIO_mouse_state.y = (int16_t)DDIO_mouse_state.brect.bottom - 1;
|
||||
if (DDIO_mouse_state.z > DDIO_mouse_state.zmax)
|
||||
DDIO_mouse_state.z = (int16_t)DDIO_mouse_state.zmax;
|
||||
if (DDIO_mouse_state.z < DDIO_mouse_state.zmin)
|
||||
DDIO_mouse_state.z = (int16_t)DDIO_mouse_state.zmin;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool InitNewMouse() {
|
||||
int i;
|
||||
if (!rawInputOpened) {
|
||||
RAWINPUTDEVICE rawInputDevice = {};
|
||||
|
||||
rawInputDevice.usUsage = 0x0002;
|
||||
rawInputDevice.usUsagePage = 0x0001;
|
||||
//TODO: This code should be renabled when some solution for mouse capturing is decided on.
|
||||
// The game should free the capture when the cursor is visible, and recapture it when it isn't visible.
|
||||
// Account for the original mode.
|
||||
if (DDIO_mouse_state.mode == MOUSE_EXCLUSIVE_MODE)
|
||||
rawInputDevice.dwFlags = RIDEV_CAPTUREMOUSE | RIDEV_NOLEGACY;
|
||||
else
|
||||
rawInputDevice.dwFlags = 0;
|
||||
|
||||
rawInputDevice.hwndTarget = DInputData.hwnd;
|
||||
|
||||
if (RegisterRawInputDevices(&rawInputDevice, 1, sizeof(rawInputDevice)) == FALSE) {
|
||||
Error("InitNewMouse: HID Registration failed: %d", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// HACK: Need to flush messages for this to work.
|
||||
MSG msg;
|
||||
|
||||
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageA(&msg);
|
||||
}
|
||||
|
||||
DInputData.app->add_handler(WM_INPUT, (tOEWin32MsgCallback)&RawInputHandler);
|
||||
|
||||
DDIO_mouse_state.timer = timer_GetTime();
|
||||
DDIO_mouse_state.naxis = 2;
|
||||
DDIO_mouse_state.nbtns = N_DIMSEBTNS + 3; // always have a mousewheel. [ISB] disgusting hack: Can't change mousewheel bindings for old pilots, so make button 5 after the two mouse wheel buttons.
|
||||
for (i = 0; i < DDIO_mouse_state.nbtns; i++) {
|
||||
DDIO_mouse_state.btn_flags |= (1 << i);
|
||||
}
|
||||
|
||||
memset(&DIM_buttons, 0, sizeof(t_mse_button_info));
|
||||
rawInputOpened = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ddio_MouseInit() {
|
||||
tWin32OS os;
|
||||
int major, minor;
|
||||
|
||||
// see if we need to emulate directinput.
|
||||
os = oeWin32Application::version(&major, &minor);
|
||||
DDIO_mouse_state.emulated = true;
|
||||
DDIO_mouse_state.lpdimse = NULL;
|
||||
|
||||
InitNewMouse();
|
||||
|
||||
// standard initialization
|
||||
DDIO_mouse_state.emulated = (DDIO_mouse_state.lpdimse) ? false : true;
|
||||
DDIO_mouse_state.cursor_count = ShowCursor(TRUE); // get initial count
|
||||
while (DDIO_mouse_state.cursor_count >= 0) // hide cursor until truly hidden.
|
||||
{
|
||||
DDIO_mouse_state.cursor_count = ShowCursor(FALSE);
|
||||
}
|
||||
|
||||
DDIOShowCursor(DDIO_mouse_state.mode == MOUSE_EXCLUSIVE_MODE ? FALSE : TRUE);
|
||||
|
||||
DDIO_mouse_state.suspended = false;
|
||||
ddio_MouseReset();
|
||||
DDIO_mouse_init = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// here we deinitialize our Mouse from DirectInput.
|
||||
void ddio_MouseClose() {
|
||||
if (!DDIO_mouse_init)
|
||||
return;
|
||||
|
||||
if (rawInputOpened) {
|
||||
RAWINPUTDEVICE rawInputDevice = {};
|
||||
|
||||
rawInputDevice.usUsage = 0x0002;
|
||||
rawInputDevice.usUsagePage = 0x0001;
|
||||
rawInputDevice.dwFlags = RIDEV_REMOVE;
|
||||
rawInputDevice.hwndTarget = 0; // not sure why?
|
||||
|
||||
if (RegisterRawInputDevices(&rawInputDevice, 1, sizeof(rawInputDevice)) == FALSE) {
|
||||
rawInputOpened = false;
|
||||
DDIO_mouse_init = false;
|
||||
Error("ddio_MouseClose: HID Registration failed: %d", GetLastError());
|
||||
}
|
||||
DInputData.app->remove_handler(WM_INPUT, (tOEWin32MsgCallback)&RawInputHandler);
|
||||
rawInputOpened = false;
|
||||
}
|
||||
|
||||
DDIO_mouse_init = false;
|
||||
}
|
||||
|
||||
// used to prevent mouse input from being registered
|
||||
void ddio_InternalMouseSuspend() {
|
||||
if (!DDIO_mouse_init)
|
||||
return;
|
||||
|
||||
DDIO_mouse_state.suspended = true;
|
||||
}
|
||||
|
||||
void ddio_InternalMouseResume() {
|
||||
if (!DDIO_mouse_init)
|
||||
return;
|
||||
|
||||
DDIO_mouse_state.suspended = false;
|
||||
}
|
||||
|
||||
// return mouse button down time
|
||||
int ddio_MouseBtnDownCount(int btn) {
|
||||
if (btn < 0 || btn >= N_MSEBTNS)
|
||||
return 0;
|
||||
int n_downs = DIM_buttons.down_count[btn];
|
||||
|
||||
if (n_downs) {
|
||||
|
||||
DIM_buttons.down_count[btn] = 0;
|
||||
}
|
||||
|
||||
return n_downs;
|
||||
}
|
||||
|
||||
// return mouse button up count
|
||||
int ddio_MouseBtnUpCount(int btn) {
|
||||
if (btn < 0 || btn >= N_MSEBTNS)
|
||||
return 0;
|
||||
int n_ups = DIM_buttons.up_count[btn];
|
||||
DIM_buttons.up_count[btn] = 0;
|
||||
return n_ups;
|
||||
}
|
||||
|
||||
// get device caps
|
||||
int ddio_MouseGetCaps(int *btn, int *axis) {
|
||||
*btn = (int)DDIO_mouse_state.nbtns;
|
||||
*axis = (int)DDIO_mouse_state.naxis;
|
||||
|
||||
return DDIO_mouse_state.btn_flags;
|
||||
}
|
||||
|
||||
// gets limits on the position of the mouse cursor (or atleast what's returned from GetState)
|
||||
void ddio_MouseGetLimits(int *left, int *top, int *right, int *bottom, int *zmin, int *zmax) {
|
||||
*left = DDIO_mouse_state.brect.left;
|
||||
*top = DDIO_mouse_state.brect.top;
|
||||
*right = DDIO_mouse_state.brect.right;
|
||||
*bottom = DDIO_mouse_state.brect.bottom;
|
||||
|
||||
if (zmin)
|
||||
*zmin = DDIO_mouse_state.zmin;
|
||||
if (zmax)
|
||||
*zmax = DDIO_mouse_state.zmax;
|
||||
}
|
||||
|
||||
// sets limits on the position of the mouse cursor (or atleast what's returned from GetState)
|
||||
void ddio_MouseSetLimits(int left, int top, int right, int bottom, int zmin, int zmax) {
|
||||
bool zaxis = (DDIO_mouse_state.naxis >= 3);
|
||||
SetRect(&DDIO_mouse_state.brect, left, top, right, bottom);
|
||||
DDIO_mouse_state.zmin = (!zmin && zaxis) ? MOUSE_ZMIN : zmin;
|
||||
DDIO_mouse_state.zmax = (!zmax && zaxis) ? MOUSE_ZMAX : zmax;
|
||||
DDIO_mouse_state.cx = (right + left) / 2;
|
||||
DDIO_mouse_state.cy = (bottom + top) / 2;
|
||||
}
|
||||
|
||||
// virtual coordinate system for mouse (match to video resolution set for optimal mouse usage.
|
||||
void ddio_MouseSetVCoords(int width, int height) { ddio_MouseSetLimits(0, 0, width, height); }
|
||||
|
||||
// gets a mouse button event, returns false if none.
|
||||
bool ddio_MouseGetEvent(int *btn, bool *state) {
|
||||
t_mse_event evt;
|
||||
|
||||
if (MB_queue.recv(&evt)) {
|
||||
*btn = (int)evt.btn;
|
||||
*state = evt.state ? true : false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
char Ctltext_MseBtnBindings[N_MSEBTNS][32] = {"mse-l\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"mse-r\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"mse-c\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"mse-b4\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"msew-u\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"msew-d\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"mse-b5",
|
||||
""};
|
||||
|
||||
char Ctltext_MseAxisBindings[][32] = {"mse-X\0\0\0\0\0\0\0\0\0\0\0\0", "mse-Y\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"msewheel\0\0\0\0\0\0\0\0\0\0"};
|
||||
|
||||
// returns string to binding.
|
||||
const char *ddio_MouseGetBtnText(int btn) {
|
||||
if (btn >= N_MSEBTNS || btn < 0)
|
||||
return ("");
|
||||
return Ctltext_MseBtnBindings[btn];
|
||||
}
|
||||
|
||||
const char *ddio_MouseGetAxisText(int axis) {
|
||||
if (axis >= (sizeof(Ctltext_MseAxisBindings) / sizeof(char *)) || axis < 0)
|
||||
return ("");
|
||||
return Ctltext_MseAxisBindings[axis];
|
||||
}
|
Loading…
Reference in New Issue
Block a user