Remove unused DirectX-related files

This commit is contained in:
Louis Gombert 2024-06-23 13:16:33 +02:00
parent 89515e25c3
commit 99a39d645d
13 changed files with 0 additions and 6293 deletions

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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];
}