From 302d0425e0c29dcad25edc3ced9515b05dd64c46 Mon Sep 17 00:00:00 2001 From: Monster Iestyn <iestynjealous@ntlworld.com> Date: Fri, 29 Sep 2017 23:25:34 +0100 Subject: [PATCH] Incinerated WinCE --- src/Makefile.cfg | 12 - src/d_clisrv.c | 2 - src/d_main.c | 21 +- src/d_netfil.c | 10 +- src/doomdef.h | 17 +- src/doomtype.h | 13 +- src/filesrch.c | 64 +- src/i_tcp.c | 7 +- src/lzf.c | 2 +- src/m_fixed.h | 5 - src/md5.c | 4 +- src/mserv.c | 16 +- src/p_setup.c | 2 +- src/p_spec.c | 4 - src/r_data.c | 2 +- src/s_sound.c | 12 +- src/screen.h | 8 +- src/sdl12/Makefile.cfg | 4 - src/sdl12/SDL_main/SDL_win32_main.c | 74 +- src/sdl12/SRB2CE/Makefile.cfg | 12 - src/sdl12/SRB2CE/SRB2CE.zip | Bin 34234 -> 0 bytes src/sdl12/SRB2CE/cehelp.c | 446 ---- src/sdl12/SRB2CE/cehelp.h | 63 - src/sdl12/endtxt.c | 2 - src/sdl12/i_cdmus.c | 4 - src/sdl12/i_main.c | 10 +- src/sdl12/i_system.c | 70 +- src/sdl12/i_video.c | 54 +- src/sdl12/sdl_sound.c | 13 +- src/w_wad.c | 4 - src/win32ce/GameX.h | 174 -- src/win32ce/SRB2CE.zip | Bin 34234 -> 0 bytes src/win32ce/Srb2win.ico | Bin 372798 -> 0 bytes src/win32ce/afxres.h | 17 - src/win32ce/gapi_c.cpp | 129 - src/win32ce/gapi_c.h | 12 - src/win32ce/gxgapilib.c | 636 ----- src/win32ce/gxgapilib.h | 81 - src/win32ce/midstuff.h | 150 -- src/win32ce/resource.h | 18 - src/win32ce/win_cd.c | 529 ---- src/win32ce/win_dbg.c | 629 ----- src/win32ce/win_dbg.h | 54 - src/win32ce/win_dll.c | 164 -- src/win32ce/win_dll.h | 31 - src/win32ce/win_file.c | 123 - src/win32ce/win_file.h | 19 - src/win32ce/win_main.c | 539 ---- src/win32ce/win_main.h | 55 - src/win32ce/win_net.c | 39 - src/win32ce/win_snd.c | 2406 ------------------ src/win32ce/win_sys.c | 3542 --------------------------- src/win32ce/win_vid.c | 865 ------- src/win32ce/wince_stuff.c | 135 - src/win32ce/wince_stuff.h | 17 - 55 files changed, 52 insertions(+), 11269 deletions(-) delete mode 100644 src/sdl12/SRB2CE/Makefile.cfg delete mode 100644 src/sdl12/SRB2CE/SRB2CE.zip delete mode 100644 src/sdl12/SRB2CE/cehelp.c delete mode 100644 src/sdl12/SRB2CE/cehelp.h delete mode 100644 src/win32ce/GameX.h delete mode 100644 src/win32ce/SRB2CE.zip delete mode 100644 src/win32ce/Srb2win.ico delete mode 100644 src/win32ce/afxres.h delete mode 100644 src/win32ce/gapi_c.cpp delete mode 100644 src/win32ce/gapi_c.h delete mode 100644 src/win32ce/gxgapilib.c delete mode 100644 src/win32ce/gxgapilib.h delete mode 100644 src/win32ce/midstuff.h delete mode 100644 src/win32ce/resource.h delete mode 100644 src/win32ce/win_cd.c delete mode 100644 src/win32ce/win_dbg.c delete mode 100644 src/win32ce/win_dbg.h delete mode 100644 src/win32ce/win_dll.c delete mode 100644 src/win32ce/win_dll.h delete mode 100644 src/win32ce/win_file.c delete mode 100644 src/win32ce/win_file.h delete mode 100644 src/win32ce/win_main.c delete mode 100644 src/win32ce/win_main.h delete mode 100644 src/win32ce/win_net.c delete mode 100644 src/win32ce/win_snd.c delete mode 100644 src/win32ce/win_sys.c delete mode 100644 src/win32ce/win_vid.c delete mode 100644 src/win32ce/wince_stuff.c delete mode 100644 src/win32ce/wince_stuff.h diff --git a/src/Makefile.cfg b/src/Makefile.cfg index 5973648a0..41c5c5238 100644 --- a/src/Makefile.cfg +++ b/src/Makefile.cfg @@ -210,7 +210,6 @@ endif #indicate platform and what interface use with -ifndef WINCE ifndef LINUX ifndef FREEBSD ifndef CYGWIN32 @@ -224,7 +223,6 @@ endif endif endif endif -endif #determine the interface directory (where you put all i_*.c) i_cdmus_o=$(OBJDIR)/i_cdmus.o @@ -317,16 +315,6 @@ ifdef MINGW NASMFORMAT=win32 OBJDIR:=$(OBJDIR)/Mingw BIN:=$(BIN)/Mingw -else -ifdef WINCE - INTERFACE=sdl12 - NONX86=1 - PREFIX?=arm-wince-pe - SDL=1 - SDL12=1 - OBJDIR:=$(OBJDIR)/WinCE - BIN:=$(BIN)/WinCE -endif endif endif endif diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 81b84a54d..df2bea972 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -10,9 +10,7 @@ /// \file d_clisrv.c /// \brief SRB2 Network game communication and protocol, all OS independent parts. -#if !defined (UNDER_CE) #include <time.h> -#endif #ifdef __GNUC__ #include <unistd.h> //for unlink #endif diff --git a/src/d_main.c b/src/d_main.c index 2b3ffc0db..5d0dfab37 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -30,14 +30,12 @@ int snprintf(char *str, size_t n, const char *fmt, ...); //int vsnprintf(char *str, size_t n, const char *fmt, va_list ap); #endif -#if defined (_WIN32) && !defined (_WIN32_WCE) +#ifdef _WIN32 #include <direct.h> #include <malloc.h> #endif -#if !defined (UNDER_CE) #include <time.h> -#endif #include "doomdef.h" #include "am_map.h" @@ -800,11 +798,9 @@ static void IdentifyVersion(void) } else { -#ifndef _WIN32_WCE if (getcwd(srb2path, 256) != NULL) srb2waddir = srb2path; else -#endif { srb2waddir = "."; } @@ -953,7 +949,7 @@ void D_SRB2Main(void) boolean autostart = false; // keep error messages until the final flush(stderr) -#if !defined (PC_DOS) && !defined (_WIN32_WCE) && !defined(NOTERMIOS) +#if !defined (PC_DOS) && !defined(NOTERMIOS) if (setvbuf(stderr, NULL, _IOFBF, 1000)) I_OutputMsg("setvbuf didnt work\n"); #endif @@ -975,11 +971,11 @@ void D_SRB2Main(void) // identify the main IWAD file to use IdentifyVersion(); -#if !defined (_WIN32_WCE) && !defined(NOTERMIOS) +#if !defined(NOTERMIOS) setbuf(stdout, NULL); // non-buffered output #endif -#if defined (_WIN32_WCE) //|| defined (_DEBUG) +#if 0 //defined (_DEBUG) devparm = M_CheckParm("-nodebug") == 0; #else devparm = M_CheckParm("-debug") != 0; @@ -1007,11 +1003,6 @@ void D_SRB2Main(void) { #if ((defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON)) && !defined (__CYGWIN__) I_Error("Please set $HOME to your home directory\n"); -#elif defined (_WIN32_WCE) && 0 - if (dedicated) - snprintf(configfile, sizeof configfile, "/Storage Card/SRB2DEMO/d"CONFIGFILENAME); - else - snprintf(configfile, sizeof configfile, "/Storage Card/SRB2DEMO/"CONFIGFILENAME); #else if (dedicated) snprintf(configfile, sizeof configfile, "d"CONFIGFILENAME); @@ -1419,14 +1410,14 @@ const char *D_Home(void) userhome = M_GetNextParm(); else { -#if !((defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON)) && !defined (__APPLE__) && !defined(_WIN32_WCE) +#if !((defined (__unix__) && !defined (MSDOS)) || defined(__APPLE__) || defined (UNIXCOMMON)) && !defined (__APPLE__) if (FIL_FileOK(CONFIGFILENAME)) usehome = false; // Let's NOT use home else #endif userhome = I_GetEnv("HOME"); //Alam: my new HOME for srb2 } -#if defined (_WIN32) && !defined(_WIN32_WCE) //Alam: only Win32 have APPDATA and USERPROFILE +#ifdef _WIN32 //Alam: only Win32 have APPDATA and USERPROFILE if (!userhome && usehome) //Alam: Still not? { char *testhome = NULL; diff --git a/src/d_netfil.c b/src/d_netfil.c index 9518433de..90e03041f 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -11,21 +11,17 @@ /// \brief Transfer a file using HSendPacket. #include <stdio.h> -#ifndef _WIN32_WCE #ifdef __OS2__ #include <sys/types.h> #endif // __OS2__ #include <sys/stat.h> -#endif -#if !defined (UNDER_CE) #include <time.h> -#endif -#if ((defined (_WIN32) && !defined (_WIN32_WCE)) || defined (__DJGPP__)) +#if defined (_WIN32) || defined (__DJGPP__) #include <io.h> #include <direct.h> -#elif !defined (_WIN32_WCE) +#else #include <sys/types.h> #include <dirent.h> #include <utime.h> @@ -34,7 +30,7 @@ #ifdef __GNUC__ #include <unistd.h> #include <limits.h> -#elif defined (_WIN32) && !defined (_WIN32_WCE) +#elif defined (_WIN32) #include <sys/utime.h> #endif #ifdef __DJGPP__ diff --git a/src/doomdef.h b/src/doomdef.h index 892130f06..a49fb0207 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -28,13 +28,11 @@ // Use Mixer interface? #ifdef HAVE_MIXER - //#if !defined(_WIN32_WCE) #define SOUND SOUND_MIXER #define NOHS // No HW3SOUND #ifdef HW3SOUND #undef HW3SOUND #endif - //#endif #endif // Use generic SDL interface. @@ -70,7 +68,7 @@ #endif #endif -#if defined (_WIN32) || defined (_WIN32_WCE) +#ifdef _WIN32 #define ASMCALL __cdecl #else #define ASMCALL @@ -87,13 +85,6 @@ // warning C4152: nonstandard extension, function/data pointer conversion in expression // warning C4213: nonstandard extension used : cast on l-value -#if defined (_WIN32_WCE) && defined (DEBUG) && defined (ARM) -#if defined (ARMV4) || defined (ARMV4I) -//#pragma warning(disable : 1166) -// warning LNK1166: cannot adjust code at offset= -#endif -#endif - #include "doomtype.h" @@ -110,13 +101,11 @@ #include <locale.h> #endif -#if !defined (_WIN32_WCE) #include <sys/types.h> #include <sys/stat.h> -#endif #include <ctype.h> -#if (defined (_WIN32) && !defined (_WIN32_WCE)) || defined (__DJGPP__) +#if defined (_WIN32) || defined (__DJGPP__) #include <io.h> #endif @@ -381,13 +370,11 @@ enum { }; // Name of local directory for config files and savegames -#if !defined(_WIN32_WCE) #if (((defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON)) && !defined (__CYGWIN__)) && !defined (__APPLE__) #define DEFAULTDIR ".srb2" #else #define DEFAULTDIR "srb2" #endif -#endif #include "g_state.h" diff --git a/src/doomtype.h b/src/doomtype.h index 796a5ca29..4af899ed0 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -17,7 +17,7 @@ #ifndef __DOOMTYPE__ #define __DOOMTYPE__ -#if defined (_WIN32) || (defined (_WIN32_WCE) && !defined (__GNUC__)) +#ifdef _WIN32 //#define WIN32_LEAN_AND_MEAN #define RPC_NO_WINDOWS_H #include <windows.h> @@ -107,15 +107,6 @@ typedef long ssize_t; #undef strnicmp #define strnicmp(x,y,n) strncasecmp(x,y,n) #endif -#ifdef _WIN32_WCE -#ifndef __GNUC__ - #define stricmp(x,y) _stricmp(x,y) - #define strnicmp _strnicmp -#endif - #define strdup _strdup - #define strupr _strupr - #define strlwr _strlwr -#endif #if defined (macintosh) //|| defined (__APPLE__) //skip all boolean/Boolean crap #define true 1 @@ -167,7 +158,7 @@ size_t strlcpy(char *dst, const char *src, size_t siz); //faB: clean that up !! #if defined( _MSC_VER) && (_MSC_VER >= 1800) // MSVC 2013 and forward #include "stdbool.h" - #elif defined (_WIN32) || (defined (_WIN32_WCE) && !defined (__GNUC__)) + #elif defined (_WIN32) #define false FALSE // use windows types #define true TRUE #define boolean BOOL diff --git a/src/filesrch.c b/src/filesrch.c index 1f159d5c0..b4a995154 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -21,11 +21,7 @@ #define RPC_NO_WINDOWS_H #include <windows.h> #endif -#ifdef _WIN32_WCE -#include "sdl12/SRB2CE/cehelp.h" -#else #include <sys/stat.h> -#endif #include <string.h> #include "filesrch.h" @@ -34,7 +30,7 @@ #include "z_zone.h" #include "m_menu.h" // Addons_option_Onchange -#if (defined (_WIN32) && !defined (_WIN32_WCE)) && defined (_MSC_VER) +#if defined (_WIN32) && defined (_MSC_VER) #include <errno.h> #include <io.h> @@ -338,63 +334,6 @@ UINT8 refreshdirmenu = 0; size_t packetsizetally = 0; size_t mainwadstally = 0; -#ifdef _WIN32_WCE -filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, - boolean completepath, int maxsearchdepth) -{ -#ifdef __GNUC__ -//NONE? - startpath = filename = NULL; - wantedmd5sum = NULL; - maxsearchdepth = 0; - completepath = false; -#else - WIN32_FIND_DATA dta; - HANDLE searchhandle = INVALID_HANDLE_VALUE; - const wchar_t wm[4] = L"*.*"; - - //if (startpath) SetCurrentDirectory(startpath); - if (FIL_ReadFileOK(filename)) - { - // checkfilemd5 returns an FS_* value, either FS_FOUND or FS_MD5SUMBAD - return checkfilemd5(filename, wantedmd5sum); - } - ZeroMemory(&dta,sizeof (dta)); - if (maxsearchdepth) - searchhandle = FindFirstFile(wm,&dta); - if (searchhandle != INVALID_HANDLE_VALUE) - { - do - { - if ((dta.cFileName[0]!='.') && (dta.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - { - //if (SetCurrentDirectory(dta.cFileName)) - { // can fail if we haven't the right - filestatus_t found; - found = filesearch(filename,NULL,wantedmd5sum,completepath,maxsearchdepth-1); - //SetCurrentDirectory(".."); - if (found == FS_FOUND || found == FS_MD5SUMBAD) - { - if (completepath) - strcatbf(filename,(char *)dta.cFileName,"\\"); - FindClose(searchhandle); - return found; - } - } - } - } while (FindNextFile(searchhandle,&dta)==0); - FindClose(searchhandle); - } -#endif - return FS_NOTFOUND; -} - -boolean preparefilemenu(boolean samedepth) -{ - (void)samedepth; - return false; -} -#else filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) { filestatus_t retval = FS_NOTFOUND; @@ -747,4 +686,3 @@ boolean preparefilemenu(boolean samedepth) return true; } -#endif diff --git a/src/i_tcp.c b/src/i_tcp.c index 9254f5b45..3bbebadf2 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -27,7 +27,7 @@ #define HAVE_IPV6 #endif -#if defined (_WIN32) || defined (_WIN32_WCE) +#ifdef _WIN32 #define USE_WINSOCK #if defined (_WIN64) || defined (HAVE_IPV6) #define USE_WINSOCK2 @@ -164,11 +164,6 @@ static UINT8 UPNP_support = TRUE; // winsock stuff (in winsock a socket is not a file) #define ioctl ioctlsocket #define close closesocket - - #ifdef _WIN32_WCE - #include "sdl12/SRB2CE/cehelp.h" - #endif - #endif #include "i_addrinfo.h" diff --git a/src/lzf.c b/src/lzf.c index ce2bdafc7..f81c3ee0a 100644 --- a/src/lzf.c +++ b/src/lzf.c @@ -157,7 +157,7 @@ typedef const u8 *LZF_STATE[1 << (HLOG)]; * lzfP.h ends here. lzf_d.c follows. */ -#if AVOID_ERRNO || defined(_WIN32_WCE) +#if AVOID_ERRNO # define SET_ERRNO(n) #else # include <errno.h> diff --git a/src/m_fixed.h b/src/m_fixed.h index 773823988..8050324db 100644 --- a/src/m_fixed.h +++ b/src/m_fixed.h @@ -20,11 +20,6 @@ #include <stdlib.h> #endif -// Was this just for the #define USEASM? -//#ifdef _WIN32_WCE -//#include "sdl12/SRB2CE/cehelp.h" -//#endif - /*! \brief bits of the fraction */ diff --git a/src/md5.c b/src/md5.c index 8031650e6..66d563666 100644 --- a/src/md5.c +++ b/src/md5.c @@ -19,9 +19,7 @@ #endif #include <string.h> -#ifndef _WIN32_WCE #include <sys/types.h> -#endif #ifdef _MSC_VER #pragma warning(disable : 4127) #endif @@ -30,7 +28,7 @@ #include <stdlib.h> #else #ifndef HAVE_MEMCPY - #if !((defined (_WIN32) || defined (_WIN32_WCE)) && !defined (__CYGWIN__)) && !defined (__APPLE__) + #if !(defined (_WIN32) && !defined (__CYGWIN__)) && !defined (__APPLE__) #define memcpy(d, s, n) bcopy ((s), (d), (n)) #endif #endif diff --git a/src/mserv.c b/src/mserv.c index deda97a5f..efbf89359 100644 --- a/src/mserv.c +++ b/src/mserv.c @@ -16,9 +16,7 @@ #include <errno.h> #endif -#if !defined (UNDER_CE) #include <time.h> -#endif #if (defined (NOMD5) || defined (NOMSERV)) && !defined (NONET) #define NONET @@ -30,7 +28,7 @@ #define HAVE_IPV6 #endif -#if defined (_WIN32) || defined (_WIN32_WCE) +#ifdef _WIN32 #define RPC_NO_WINDOWS_H #ifdef HAVE_IPV6 #include <ws2tcpip.h> @@ -55,7 +53,7 @@ #include <sys/time.h> // timeval,... (TIMEOUT) #include <errno.h> -#endif // _WIN32/_WIN32_WCE +#endif // _WIN32 #ifdef __OS2__ #include <errno.h> @@ -76,10 +74,6 @@ #include "m_argv.h" // Alam is going to kill me <3 #include "m_misc.h" // GetRevisionString() -#ifdef _WIN32_WCE -#include "sdl12/SRB2CE/cehelp.h" -#endif - #include "i_addrinfo.h" // ================================ DEFINITIONS =============================== @@ -168,13 +162,13 @@ typedef struct #endif // win32 or djgpp -#if defined (_WIN32) || defined (_WIN32_WCE) || defined (__DJGPP__) +#if defined (_WIN32) || defined (__DJGPP__) #define ioctl ioctlsocket #define close closesocket #ifdef WATTCP #define strerror strerror_s #endif -#if defined (_WIN32) || defined (_WIN32_WCE) +#ifdef _WIN32 #undef errno #define errno h_errno // some very strange things happen when not using h_error #endif @@ -200,7 +194,7 @@ static enum { MSCS_NONE, MSCS_WAITING, MSCS_REGISTERED, MSCS_FAILED } con_state static INT32 msnode = -1; UINT16 current_port = 0; -#if (defined (_WIN32) || defined (_WIN32_WCE) || defined (_WIN32)) && !defined (NONET) +#if defined (_WIN32) && !defined (NONET) typedef SOCKET SOCKET_TYPE; #define BADSOCKET INVALID_SOCKET #define ERRSOCKET (SOCKET_ERROR) diff --git a/src/p_setup.c b/src/p_setup.c index 60f456ce3..83c9348c9 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -65,7 +65,7 @@ #include "lua_script.h" #include "lua_hook.h" -#if defined (_WIN32) || defined (_WIN32_WCE) +#ifdef _WIN32 #include <malloc.h> #include <math.h> #endif diff --git a/src/p_spec.c b/src/p_spec.c index e06926f30..03643a708 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -40,11 +40,7 @@ #endif // Not sure if this is necessary, but it was in w_wad.c, so I'm putting it here too -Shadow Hog -#ifdef _WIN32_WCE -#define AVOID_ERRNO -#else #include <errno.h> -#endif mobj_t *skyboxmo[2]; // current skybox mobjs: 0 = viewpoint, 1 = centerpoint mobj_t *skyboxviewpnts[16]; // array of MT_SKYBOX viewpoint mobjs diff --git a/src/r_data.c b/src/r_data.c index 791d90d94..c578012d1 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -25,7 +25,7 @@ #include "v_video.h" // pMasterPalette #include "dehacked.h" -#if defined (_WIN32) || defined (_WIN32_WCE) +#ifdef _WIN32 #include <malloc.h> // alloca(sizeof) #endif diff --git a/src/s_sound.c b/src/s_sound.c index a34b6362f..4d041dae4 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -62,9 +62,7 @@ consvar_t sndserver_arg = {"sndserver_arg", "-quiet", CV_SAVE, NULL, 0, NULL, NU #define SURROUND #endif -#if defined (_WIN32_WCE) -consvar_t cv_samplerate = {"samplerate", "11025", 0, CV_Unsigned, NULL, 11025, NULL, NULL, 0, 0, NULL}; //Alam: For easy hacking? -#elif defined(_WINDOWS) +#ifdef _WINDOWS consvar_t cv_samplerate = {"samplerate", "44100", 0, CV_Unsigned, NULL, 44100, NULL, NULL, 0, 0, NULL}; //Alam: For easy hacking? #else consvar_t cv_samplerate = {"samplerate", "22050", 0, CV_Unsigned, NULL, 22050, NULL, NULL, 0, 0, NULL}; //Alam: For easy hacking? @@ -91,11 +89,7 @@ static void Captioning_OnChange(void) consvar_t cv_closedcaptioning = {"closedcaptioning", "Off", CV_SAVE|CV_CALL, CV_OnOff, Captioning_OnChange, 0, NULL, NULL, 0, 0, NULL}; // number of channels available -#if defined (_WIN32_WCE) -consvar_t cv_numChannels = {"snd_channels", "8", CV_SAVE|CV_CALL, CV_Unsigned, SetChannelsNum, 0, NULL, NULL, 0, 0, NULL}; -#else consvar_t cv_numChannels = {"snd_channels", "32", CV_SAVE|CV_CALL, CV_Unsigned, SetChannelsNum, 0, NULL, NULL, 0, 0, NULL}; -#endif static consvar_t surround = {"surround", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -1377,10 +1371,6 @@ static boolean S_DigMusic(const char *mname, boolean looping) void S_ChangeMusic(const char *mmusic, UINT16 mflags, boolean looping) { -#if defined (_WIN32_WCE) - S_ClearSfx(); -#endif - if ((nomidimusic || music_disabled) && (nodigimusic || digital_disabled)) return; diff --git a/src/screen.h b/src/screen.h index 80bbb4146..4d4fbb88b 100644 --- a/src/screen.h +++ b/src/screen.h @@ -15,20 +15,16 @@ #include "command.h" -#if (defined (_WIN32) || defined (_WIN32_WCE)) && !defined (__CYGWIN__) -#if defined (_WIN32_WCE) && defined (__GNUC__) -#include <sys/wcetypes.h> -#else +#if defined (_WIN32) && !defined (__CYGWIN__) #define RPC_NO_WINDOWS_H #include <windows.h> -#endif #define DNWH HWND #else #define DNWH void * // unused in DOS version #endif // quickhack for V_Init()... to be cleaned up -#if defined (_WIN32_WCE) || defined (NOPOSTPROCESSING) +#ifdef NOPOSTPROCESSING #define NUMSCREENS 2 #else #define NUMSCREENS 5 diff --git a/src/sdl12/Makefile.cfg b/src/sdl12/Makefile.cfg index a29b95d6b..2366a5ac2 100644 --- a/src/sdl12/Makefile.cfg +++ b/src/sdl12/Makefile.cfg @@ -14,10 +14,6 @@ ifdef PANDORA include sdl12/SRB2Pandora/Makefile.cfg endif #ifdef PANDORA -ifdef WINCE -include sdl12/SRB2CE/Makefile.cfg -endif #ifef WINCE - ifdef CYGWIN32 include sdl12/MakeCYG.cfg endif #ifdef CYGWIN32 diff --git a/src/sdl12/SDL_main/SDL_win32_main.c b/src/sdl12/SDL_main/SDL_win32_main.c index 46b20d0bd..6f3ae370f 100644 --- a/src/sdl12/SDL_main/SDL_win32_main.c +++ b/src/sdl12/SDL_main/SDL_win32_main.c @@ -13,17 +13,8 @@ #include <malloc.h> /* For _alloca() */ #include <tchar.h> - -#ifdef _WIN32_WCE -# define DIR_SEPERATOR TEXT("\\") -# define _tgetcwd(str,len) wcscpy(str,TEXT("")) -# define setbuf(f,b) -# define setvbuf(w,x,y,z) -# define _tremove(x) DeleteFile(x) -#else # define DIR_SEPERATOR TEXT("/") # include <direct.h> -#endif /* Include the SDL main definition header */ #ifdef _MSC_VER @@ -44,45 +35,14 @@ #endif /* main */ /* The standard output files */ -//#ifdef _WIN32_WCE -//#define STDOUT_FILE TEXT("/Storage Card/SRB2DEMO/stdout.txt") -//#define STDERR_FILE TEXT("/Storage Card/SRB2DEMO/stderr.txt") -//#else #define STDOUT_FILE TEXT("stdout.txt") #define STDERR_FILE TEXT("stderr.txt") -//#endif #ifndef NO_STDIO_REDIRECT static TCHAR stdoutPath[MAX_PATH]; static TCHAR stderrPath[MAX_PATH]; #endif -#if defined(_WIN32_WCE) && _WIN32_WCE < 300 -/* seems to be undefined in Win CE although in online help */ -#define isspace(a) (((CHAR)a == ' ') || ((CHAR)a == '\t')) - -/* seems to be undefined in Win CE although in online help */ -char *strrchr(char *str, int c) -{ - char *p; - - /* Skip to the end of the string */ - p=str; - while (*p) - p++; - - /* Look for the given character */ - while ( (p >= str) && (*p != (CHAR)c) ) - p--; - - /* Return NULL if character not found */ - if ( p < str ) { - p = NULL; - } - return p; -} -#endif /* _WIN32_WCE < 300 */ - /* Parse a command line buffer into arguments */ static int ParseCommandLine(char *cmdline, char **argv) { @@ -191,7 +151,7 @@ static void __cdecl cleanup_output(void) #endif } -#if defined(_MSC_VER) && !defined(_WIN32_WCE) +#if defined(_MSC_VER) /* The VC++ compiler needs main defined */ #define console_main main #endif @@ -268,23 +228,14 @@ int console_main(int argc, char *argv[]) } /* This is where execution begins [windowed apps] */ -#ifdef _WIN32_WCE -int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR szCmdLine, int sw) -#else int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) -#endif { HINSTANCE handle; int Result = -1; char **argv; int argc; LPSTR cmdline; -#ifdef _WIN32_WCE - size_t nLen; - LPTSTR bufp; -#else LPSTR bufp; -#endif #ifndef NO_STDIO_REDIRECT FILE *newfp; #endif @@ -307,7 +258,6 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) /* Redirect standard input and standard output */ newfp = _tfreopen(stdoutPath, TEXT("w"), stdout); -#ifndef _WIN32_WCE if ( newfp == NULL ) { /* This happens on NT */ #if !defined(stdout) stdout = _tfopen(stdoutPath, TEXT("w")); @@ -318,13 +268,11 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) } #endif } -#endif /* _WIN32_WCE */ _tgetcwd( stderrPath, sizeof( stderrPath ) ); _tcscat( stderrPath, DIR_SEPERATOR STDERR_FILE ); newfp = _tfreopen(stderrPath, TEXT("w"), stderr); -#ifndef _WIN32_WCE if ( newfp == NULL ) { /* This happens on NT */ #if !defined(stderr) stderr = _tfopen(stderrPath, TEXT("w")); @@ -335,26 +283,11 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) } #endif } -#endif /* _WIN32_WCE */ setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* Line buffered */ setbuf(stderr, NULL); /* No buffering */ #endif /* !NO_STDIO_REDIRECT */ -#ifdef _WIN32_WCE - nLen = wcslen(szCmdLine)+128+1; - bufp = (wchar_t *)alloca(nLen*2); - wcscpy (bufp, TEXT("\"")); - GetModuleFileName(NULL, bufp+1, 128-3); - wcscpy (bufp+wcslen(bufp), TEXT("\" ")); - wcsncpy(bufp+wcslen(bufp), szCmdLine,nLen-wcslen(bufp)); - nLen = wcslen(bufp)+1; - cmdline = (char *)alloca(nLen); - if ( cmdline == NULL ) { - return OutOfMemory(); - } - WideCharToMultiByte(CP_ACP, 0, bufp, -1, cmdline, nLen, NULL, NULL); -#else szCmdLine = NULL; /* Grab the command line (use alloca() on Windows) */ bufp = GetCommandLineA(); @@ -363,7 +296,6 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) return OutOfMemory(); } strcpy(cmdline, bufp); -#endif /* Parse it into argv and argc */ argc = ParseCommandLine(cmdline, NULL); @@ -382,18 +314,14 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) #endif /* Run the main program (after a little SDL initialization) */ -#ifndef _WIN32_WCE __try -#endif { Result = console_main(argc, argv); } -#ifndef _WIN32_WCE __except ( RecordExceptionInfo(GetExceptionInformation())) { SetUnhandledExceptionFilter(EXCEPTION_CONTINUE_SEARCH); //Do nothing here. } -#endif #ifdef BUGTRAP } /* BT failure clause. */ diff --git a/src/sdl12/SRB2CE/Makefile.cfg b/src/sdl12/SRB2CE/Makefile.cfg deleted file mode 100644 index 8d4ae3e48..000000000 --- a/src/sdl12/SRB2CE/Makefile.cfg +++ /dev/null @@ -1,12 +0,0 @@ -# -# Makefile.cfg for WinCE with GCC -# - -OPTS+=-D_WIN32_WCE -D_UNICODE -SDL_CFLAGS?= -SDL_LDFLAGS?= -NOHS=1 -NOHW=1 -NONET=1 -NOMIXER=1 -NOPNG=1 diff --git a/src/sdl12/SRB2CE/SRB2CE.zip b/src/sdl12/SRB2CE/SRB2CE.zip deleted file mode 100644 index 3ac8530dcb124cbda512a7d469da933c3fc974bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34234 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 CQd6)1 diff --git a/src/sdl12/SRB2CE/cehelp.c b/src/sdl12/SRB2CE/cehelp.c deleted file mode 100644 index 7c5efdee9..000000000 --- a/src/sdl12/SRB2CE/cehelp.c +++ /dev/null @@ -1,446 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 2004 by Sonic Team Jr. -// -// 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 2 -// 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. -// -// DESCRIPTION: -// stub and replacement "ANSI" C functions for use under Windows CE -// -//----------------------------------------------------------------------------- - -#include "../../doomdef.h" -#include "cehelp.h" - -#define _SEC_IN_MINUTE 60 -#define _SEC_IN_HOUR 3600 -#define _SEC_IN_DAY 86400 - -static const int DAYS_IN_MONTH[12] = -{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - -#define _DAYS_IN_MONTH(x) ((x == 1) ? days_in_feb : DAYS_IN_MONTH[x]) - -static const int _DAYS_BEFORE_MONTH[12] = -{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; - -#define _ISLEAP(y) (((y) % 4) == 0 && (((y) % 100) != 0 || (((y)+1900) % 400) == 0)) -#define _DAYS_IN_YEAR(year) (_ISLEAP(year) ? 366 : 365) - -char *strerror(int ecode) -{ - static char buff[1024 + 1]; - DWORD dwMsgLen = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, - ecode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &buff[0], 1024, NULL); - return buff; -} - -int unlink( const char *filename ) -{ - return remove(filename); -} - -int remove( const char *path ) -{ - return DeleteFileA(path)-1; -} - -int rename( const char *oldname, const char *newname ) -{ - return MoveFileA(oldname, newname)!=0; -} - -static inline void STToTM(const SYSTEMTIME *st, struct tm *tm) -{ - if (!st || !tm) return; - tm->tm_sec = st->wSecond; - tm->tm_min = st->wMinute; - tm->tm_hour = st->wHour; - tm->tm_mday = st->wDay; - tm->tm_mon = st->wMonth - 1; - tm->tm_year = st->wYear - 1900; - tm->tm_wday = st->wDayOfWeek; - tm->tm_yday = 0; - tm->tm_isdst = 0; -} - -time_t time(time_t *T) -{ - time_t returntime; - SYSTEMTIME st; - struct tm stft; - GetSystemTime(&st); - STToTM(&st,&stft); - returntime = mktime(&stft); - if (T) *T = returntime; - return returntime; -} - -static inline UINT64 TTtoFT(const time_t wt, FILETIME *ft) -{ - UINT64 temptime = wt; // FILETIME: 1/(10^7) secs since January 1, 1601 - temptime *= 10000000; // time_t : 1 secs since January 1, 1970 - // 369 years * 365 days * 24 hours * 60 mins * 60 secs * 10 - // 123 leaps days * 24 hours * 60 mins * 60 secs * 10 - temptime += 116444736000000000; - if (ft) CopyMemory(ft,&temptime,sizeof (ULARGE_INTEGER)); - return temptime; -} - -static struct tm cehelptm; - -struct tm * localtime(const time_t *CLOCK) -{ - SYSTEMTIME st; - FILETIME stft; - UINT64 ftli = 0; - if (CLOCK) ftli = TTtoFT(*CLOCK, &stft); - if (ftli) - FileTimeToSystemTime(&stft,&st); - else - GetSystemTime(&st); - STToTM(&st,&cehelptm); - if (st.wYear >= 1970) - return &cehelptm; - else - return NULL; -} - -static void validate_structure (struct tm *tim_p) // from newlib -{ - div_t res; - int days_in_feb = 28; - - /* calculate time & date to account for out of range values */ - if (tim_p->tm_sec < 0 || tim_p->tm_sec > 59) - { - res = div (tim_p->tm_sec, 60); - tim_p->tm_min += res.quot; - if ((tim_p->tm_sec = res.rem) < 0) - { - tim_p->tm_sec += 60; - --tim_p->tm_min; - } - } - - if (tim_p->tm_min < 0 || tim_p->tm_min > 59) - { - res = div (tim_p->tm_min, 60); - tim_p->tm_hour += res.quot; - if ((tim_p->tm_min = res.rem) < 0) - { - tim_p->tm_min += 60; - --tim_p->tm_hour; - } - } - - if (tim_p->tm_hour < 0 || tim_p->tm_hour > 23) - { - res = div (tim_p->tm_hour, 24); - tim_p->tm_mday += res.quot; - if ((tim_p->tm_hour = res.rem) < 0) - { - tim_p->tm_hour += 24; - --tim_p->tm_mday; - } - } - - if (tim_p->tm_mon > 11) - { - res = div (tim_p->tm_mon, 12); - tim_p->tm_year += res.quot; - if ((tim_p->tm_mon = res.rem) < 0) - { - tim_p->tm_mon += 12; - --tim_p->tm_year; - } - } - - if (_DAYS_IN_YEAR (tim_p->tm_year) == 366) - days_in_feb = 29; - - if (tim_p->tm_mday <= 0) - { - while (tim_p->tm_mday <= 0) - { - if (--tim_p->tm_mon == -1) - { - tim_p->tm_year--; - tim_p->tm_mon = 11; - days_in_feb = - ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ? - 29 : 28); - } - tim_p->tm_mday += _DAYS_IN_MONTH (tim_p->tm_mon); - } - } - else - { - while (tim_p->tm_mday > _DAYS_IN_MONTH (tim_p->tm_mon)) - { - tim_p->tm_mday -= _DAYS_IN_MONTH (tim_p->tm_mon); - if (++tim_p->tm_mon == 12) - { - tim_p->tm_year++; - tim_p->tm_mon = 0; - days_in_feb = - ((_DAYS_IN_YEAR (tim_p->tm_year) == 366) ? - 29 : 28); - } - } - } -} - -time_t mktime (struct tm *tim_p) // from newlib -{ - time_t tim = 0; - long days = 0; - int year; - - /* validate structure */ - validate_structure (tim_p); - - /* compute hours, minutes, seconds */ - tim += tim_p->tm_sec + (tim_p->tm_min * _SEC_IN_MINUTE) + - (tim_p->tm_hour * _SEC_IN_HOUR); - - /* compute days in year */ - days += tim_p->tm_mday - 1; - days += _DAYS_BEFORE_MONTH[tim_p->tm_mon]; - if (tim_p->tm_mon > 1 && _DAYS_IN_YEAR (tim_p->tm_year) == 366) - days++; - - /* compute day of the year */ - tim_p->tm_yday = days; - - if (tim_p->tm_year > 10000 - || tim_p->tm_year < -10000) - { - return (time_t) -1; - } - - /* compute days in other years */ - if (tim_p->tm_year > 70) - { - for (year = 70; year < tim_p->tm_year; year++) - days += _DAYS_IN_YEAR (year); - } - else if (tim_p->tm_year < 70) - { - for (year = 69; year > tim_p->tm_year; year--) - days -= _DAYS_IN_YEAR (year); - days -= _DAYS_IN_YEAR (year); - } - - /* compute day of the week */ - if ((tim_p->tm_wday = (days + 4) % 7) < 0) - tim_p->tm_wday += 7; - - /* compute total seconds */ - tim += (days * _SEC_IN_DAY); - - return tim; -} - -#undef WINAPI -#define WINAPI __stdcall //__delcspec(dllexport) - -#ifdef _MSC_VER -//#pragma warning(disable : 4273) -#endif - - -static __forceinline int STRtoWSTR(LPCSTR lpMultiByteStr, int cchMultiByte, - LPWSTR lpWideCharStr, int cchWideChar) -{ - return MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,lpMultiByteStr, - cchMultiByte,lpWideCharStr,cchWideChar); -} - -static __forceinline int WSTRtoSTR(LPCWSTR lpWideCharStr, int cchWideChar, - LPSTR lpMultiByteStr, int cbMultiByte) -{ - return WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK|WC_SEPCHARS, - lpWideCharStr,cchWideChar,lpMultiByteStr,cbMultiByte,NULL,NULL); -} - -DWORD WINAPI FormatMessageA( - DWORD dwFlags, - LPCVOID lpSource, - DWORD dwMessageId, - DWORD dwLanguageId, - LPSTR lpBuffer, - DWORD nSize, - va_list *Arguments) -{ - const int nSizeW = STRtoWSTR(lpBuffer,nSize,NULL,0); - int nSizeF = 0; - LPWSTR lpBufferW = alloca(sizeof (wchar_t)*nSizeW); - LPWSTR lpSourceW = NULL; - - if (!lpBufferW) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - ZeroMemory(lpBuffer,nSize); - return nSizeF; - } - - if (dwFlags & FORMAT_MESSAGE_FROM_STRING) - { - const int sLen = STRtoWSTR(lpSource, -1, NULL, 0); - lpSourceW = alloca(sizeof (wchar_t)*sLen); - - if (lpSourceW) - STRtoWSTR(lpSource, -1, lpSourceW, sLen); - else - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return nSizeF; - } - } - - if (lpSourceW) - nSizeF = FormatMessageW(dwFlags, lpSourceW, dwMessageId, dwLanguageId, - lpBufferW, nSizeW, Arguments); - else - nSizeF = FormatMessageW(dwFlags, lpSource, dwMessageId, dwLanguageId, - lpBufferW, nSizeW, Arguments); - - return WSTRtoSTR(lpBufferW, nSizeF, lpBuffer, nSize); -} - -BOOL WINAPI DeleteFileA( - LPCSTR lpFileName) -{ - const int sLen = STRtoWSTR(lpFileName, -1, NULL, 0); - LPWSTR lpFileNameW = alloca(sizeof (wchar_t)*sLen); - - if (lpFileNameW) - STRtoWSTR(lpFileName, -1, lpFileNameW, sLen); - else - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - - return DeleteFileW(lpFileNameW); -} - -BOOL WINAPI MoveFileA( - LPCSTR lpExistingFileName, - LPCSTR lpNewFileName -) -{ - const int sLen1 = STRtoWSTR(lpExistingFileName, -1, NULL, 0); - LPWSTR lpExistingFileNameW = alloca(sizeof (wchar_t)*sLen1); - - const int sLen2 = STRtoWSTR(lpNewFileName, -1, NULL, 0); - LPWSTR lpNewFileNameW = alloca(sizeof (wchar_t)*sLen2); - - - if (!lpExistingFileNameW || !lpNewFileNameW) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - - STRtoWSTR(lpExistingFileName, -1, lpExistingFileNameW, sLen1); - STRtoWSTR(lpNewFileName, -1, lpNewFileNameW, sLen2); - - return MoveFileW(lpExistingFileNameW, lpNewFileNameW); -} - - -HANDLE WINAPI CreateFileA( - LPCSTR lpFileName, - DWORD dwDesiredAccess, - DWORD dwShareMode, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, - DWORD dwFlagsAndAttributes, - HANDLE hTemplateFile) -{ - const int sLen = STRtoWSTR(lpFileName, -1, NULL, 0); - LPWSTR lpFileNameW = alloca(sizeof (wchar_t)*sLen); - - if (lpFileNameW) - STRtoWSTR(lpFileName, -1, lpFileNameW, sLen); - else - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return INVALID_HANDLE_VALUE; - } - - return CreateFileW(lpFileNameW, dwDesiredAccess, dwShareMode, - lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, - hTemplateFile); -} - -BOOL WINAPI CreateDirectoryA( - LPCSTR lpPathName, - LPSECURITY_ATTRIBUTES lpSecurityAttributes) -{ - const int sLen = STRtoWSTR(lpPathName, -1, NULL, 0); - LPWSTR lpPathNameW = alloca(sizeof (wchar_t)*sLen); - - if (lpPathNameW) - STRtoWSTR(lpPathName, -1, lpPathNameW, sLen); - else - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - - return CreateDirectoryW(lpPathNameW, lpSecurityAttributes); -} - -int WINAPI MessageBoxA( - HWND hWnd , - LPCSTR lpText, - LPCSTR lpCaption, - UINT uType) -{ - const int sLen1 = STRtoWSTR(lpText, -1, NULL, 0); - LPWSTR lpTextW = alloca(sizeof (wchar_t)*sLen1); - - const int sLen2 = STRtoWSTR(lpCaption, -1, NULL, 0); - LPWSTR lpCaptionW = alloca(sizeof (wchar_t)*sLen2); - - - if (!lpTextW || !lpCaptionW) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return 0; - } - - STRtoWSTR(lpText, -1, lpTextW, sLen1); - STRtoWSTR(lpCaption, -1, lpCaptionW, sLen2); - - return MessageBoxW(hWnd, lpTextW, lpCaptionW, uType); -} - -VOID WINAPI OutputDebugStringA( - LPCSTR lpOutputString) -{ - const int sLen = STRtoWSTR(lpOutputString, -1, NULL, 0); - LPWSTR lpOutputStringW = alloca(sizeof (wchar_t)*sLen); - - if (lpOutputStringW) - STRtoWSTR(lpOutputString, -1, lpOutputStringW, sLen); - else - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return; - } - - OutputDebugStringW(lpOutputStringW); -} diff --git a/src/sdl12/SRB2CE/cehelp.h b/src/sdl12/SRB2CE/cehelp.h deleted file mode 100644 index bc265b058..000000000 --- a/src/sdl12/SRB2CE/cehelp.h +++ /dev/null @@ -1,63 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 2004 by Sonic Team Jr. -// -// 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 2 -// 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. -// -// DESCRIPTION: -// stub and replacement "ANSI" C functions for use under Windows CE -// -//----------------------------------------------------------------------------- - -#ifndef __I_WINCE__ -#define __I_WINCE__ - -#ifdef USEASMCE -#define USEASM // Remline if NASM doesn't work on x86 targets -#endif - -char *strerror(int ecode); -int access(const char *path, int amode); -int unlink( const char *filename ); -int remove( const char *path ); -int rename( const char *oldname, const char *newname ); -//CreateDirectoryEx( const char *currectpath, const char *path,SECURITY_ATTRIBUTES) - -#ifndef _TIME_T_DEFINED -typedef long time_t; /* time value */ -#define _TIME_T_DEFINED /* avoid multiple def's of time_t */ -#endif - -time_t time(time_t *T); - -#ifndef __GNUC__ -#ifndef _TM_DEFINED -struct tm { - int tm_sec; /* seconds after the minute - [0,59] */ - int tm_min; /* minutes after the hour - [0,59] */ - int tm_hour; /* hours since midnight - [0,23] */ - int tm_mday; /* day of the month - [1,31] */ - int tm_mon; /* months since January - [0,11] */ - int tm_year; /* years since 1900 */ - int tm_wday; /* days since Sunday - [0,6] */ - int tm_yday; /* days since January 1 - [0,365] */ - int tm_isdst; /* daylight savings time flag */ - }; -#define _TM_DEFINED -#endif - -struct tm * localtime(const time_t *CLOCK); - -time_t mktime (struct tm *tim_p); -#endif - -#endif diff --git a/src/sdl12/endtxt.c b/src/sdl12/endtxt.c index f8e315591..1e72ca9a8 100644 --- a/src/sdl12/endtxt.c +++ b/src/sdl12/endtxt.c @@ -33,7 +33,6 @@ void ShowEndTxt(void) { -#ifndef _WIN32_WCE INT32 i; UINT16 j, att = 0; INT32 nlflag = 1; @@ -232,5 +231,4 @@ void ShowEndTxt(void) printf("\n"); Z_Free(data); -#endif } diff --git a/src/sdl12/i_cdmus.c b/src/sdl12/i_cdmus.c index 805e6f498..27b664887 100644 --- a/src/sdl12/i_cdmus.c +++ b/src/sdl12/i_cdmus.c @@ -19,10 +19,6 @@ #ifdef HAVE_SDL -#if defined (_WIN32_WCE) -#define NOSDLCD -#endif - #include <stdlib.h> #ifndef NOSDLCD diff --git a/src/sdl12/i_main.c b/src/sdl12/i_main.c index 2a0ea785a..7d14ca9e5 100644 --- a/src/sdl12/i_main.c +++ b/src/sdl12/i_main.c @@ -58,7 +58,7 @@ FILE *logstream = NULL; typedef BOOL (WINAPI *p_IsDebuggerPresent)(VOID); #endif -#if defined (_WIN32) && !defined (_WIN32_WCE) +#ifdef _WIN32 static inline VOID MakeCodeWritable(VOID) { #ifdef USEASM // Disable write-protection of code segment @@ -121,9 +121,7 @@ int main(int argc, char **argv) logdir = D_Home(); #ifdef LOGMESSAGES -#if defined(_WIN32_WCE) - logstream = fopen(va("%s.log",argv[0]), "a"); -#elif defined (DEFAULTDIR) +#ifdef DEFAULTDIR if (logdir) logstream = fopen(va("%s/"DEFAULTDIR"/srb2log.txt",logdir), "a"); else @@ -134,7 +132,6 @@ int main(int argc, char **argv) //I_OutputMsg("I_StartupSystem() ...\n"); I_StartupSystem(); #ifdef _WIN32 -#ifndef _WIN32_WCE { p_IsDebuggerPresent pfnIsDebuggerPresent = (p_IsDebuggerPresent)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsDebuggerPresent"); if ((!pfnIsDebuggerPresent || !pfnIsDebuggerPresent()) @@ -146,11 +143,8 @@ int main(int argc, char **argv) LoadLibraryA("exchndl.dll"); } } -#endif prevExceptionFilter = SetUnhandledExceptionFilter(RecordExceptionInfo); -#ifndef _WIN32_WCE MakeCodeWritable(); -#endif #endif // startup SRB2 CONS_Printf("%s", M_GetText("Setting up SRB2...\n")); diff --git a/src/sdl12/i_system.c b/src/sdl12/i_system.c index a907c7f90..e759449a7 100644 --- a/src/sdl12/i_system.c +++ b/src/sdl12/i_system.c @@ -20,15 +20,12 @@ /// \file /// \brief SRB2 system stuff for SDL -#ifndef _WIN32_WCE #include <signal.h> -#endif #ifdef _WIN32 #define RPC_NO_WINDOWS_H #include <windows.h> #include "../doomtype.h" -#ifndef _WIN32_WCE typedef BOOL (WINAPI *p_GetDiskFreeSpaceExA)(LPCSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER); typedef BOOL (WINAPI *p_IsProcessorFeaturePresent) (DWORD); typedef DWORD (WINAPI *p_timeGetTime) (void); @@ -39,7 +36,6 @@ typedef HANDLE (WINAPI *p_GetCurrentProcess) (VOID); typedef BOOL (WINAPI *p_GetProcessAffinityMask) (HANDLE, PDWORD_PTR, PDWORD_PTR); typedef BOOL (WINAPI *p_SetProcessAffinityMask) (HANDLE, DWORD_PTR); #endif -#endif #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -53,7 +49,7 @@ typedef BOOL (WINAPI *p_SetProcessAffinityMask) (HANDLE, DWORD_PTR); #endif #include <stdio.h> -#if defined (_WIN32) && !defined (_WIN32_WCE) +#ifdef _WIN32 #include <conio.h> #endif @@ -111,7 +107,7 @@ typedef BOOL (WINAPI *p_SetProcessAffinityMask) (HANDLE, DWORD_PTR); #include <wchar.h> #endif -#if defined (_WIN32) && !defined (_WIN32_WCE) +#ifdef _WIN32 #define HAVE_MUMBLE #define WINMUMBLE #elif defined (HAVE_SHM) @@ -119,10 +115,6 @@ typedef BOOL (WINAPI *p_SetProcessAffinityMask) (HANDLE, DWORD_PTR); #endif #endif // NOMUMBLE -#ifdef _WIN32_WCE -#include "SRB2CE/cehelp.h" -#endif - #ifndef O_BINARY #define O_BINARY 0 #endif @@ -136,11 +128,6 @@ typedef BOOL (WINAPI *p_SetProcessAffinityMask) (HANDLE, DWORD_PTR); #define DEFAULTSEARCHPATH1 "/usr/local/games" #define DEFAULTSEARCHPATH2 "/usr/games" #define DEFAULTSEARCHPATH3 "/usr/local" -#elif defined (_WIN32_WCE) -#define NOCWD -#define NOHOME -#define DEFAULTWADLOCATION1 "\\Storage Card\\SRB2DEMO" -#define DEFAULTSEARCHPATH1 "\\Storage Card" #elif defined (_WIN32) #define DEFAULTWADLOCATION1 "c:\\games\\srb2" #define DEFAULTWADLOCATION2 "\\games\\srb2" @@ -275,7 +262,7 @@ static void signal_handler(INT32 num) } #endif -#if defined (NDEBUG) && !defined (_WIN32_WCE) +#if defined (NDEBUG) FUNCNORETURN static ATTRNORETURN void quit_handler(int num) { signal(num, SIG_DFL); //default signal action @@ -495,7 +482,7 @@ void I_GetConsoleEvents(void) (void)d; } -#elif defined (_WIN32) && !defined (_WIN32_WCE) +#elif defined (_WIN32) static BOOL I_ReadyConsole(HANDLE ci) { DWORD gotinput; @@ -709,7 +696,7 @@ void I_OutputMsg(const char *fmt, ...) } #endif -#if defined (_WIN32) && !defined(_WIN32_WCE) +#ifdef _WIN32 #ifdef DEBUGFILE if (debugfile != stderr) #endif @@ -1966,7 +1953,7 @@ ticcmd_t *I_BaseTiccmd2(void) return &emptycmd2; } -#if defined (_WIN32) && !defined (_WIN32_WCE) +#ifdef _WIN32 static HMODULE winmm = NULL; static DWORD starttickcount = 0; // hack for win2k time bug static p_timeGetTime pfntimeGetTime = NULL; @@ -2045,12 +2032,7 @@ tic_t I_GetTime (void) ticks -= basetime; ticks = (ticks*TICRATE); - -#if 0 //#ifdef _WIN32_WCE - ticks = (ticks/10); -#else ticks = (ticks/1000); -#endif return (tic_t)ticks; } @@ -2061,7 +2043,7 @@ tic_t I_GetTime (void) // void I_StartupTimer(void) { -#if defined (_WIN32) && !defined (_WIN32_WCE) +#ifdef _WIN32 // for win2k time bug if (M_CheckParm("-gettickcount")) { @@ -2184,7 +2166,7 @@ static boolean shutdowning = false; void I_Error(const char *error, ...) { va_list argptr; -#if defined (MAC_ALERT) || defined (_WIN32) || (defined (_WIN32_WCE) && !defined (__GNUC__)) +#if defined (MAC_ALERT) || defined (_WIN32) char buffer[8192]; #endif @@ -2222,11 +2204,10 @@ void I_Error(const char *error, ...) va_end(argptr); // 2004-03-03 AJR Since the Mac user is most likely double clicking to run the game, give them a panel. MacShowAlert("Recursive Error", buffer, "Quit", NULL, NULL); -#elif defined (_WIN32) || (defined (_WIN32_WCE)) && !defined (__GNUC__) +#elif defined (_WIN32) va_start(argptr,error); vsprintf(buffer, error, argptr); va_end(argptr); -#ifndef _WIN32_WCE { HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE); DWORD bytesWritten; @@ -2238,7 +2219,6 @@ void I_Error(const char *error, ...) WriteFile(co, buffer, (DWORD)strlen(buffer), &bytesWritten, NULL); } } -#endif OutputDebugStringA(buffer); MessageBoxA(vid.WndParent, buffer, "SRB2 Recursive Error", MB_OK|MB_ICONERROR); #else @@ -2387,7 +2367,7 @@ void I_GetDiskFreeSpace(INT64 *freespace) } *freespace = stfs.f_bavail * stfs.f_bsize; #endif -#elif defined (_WIN32) && !defined (_WIN32_WCE) +#elif defined (_WIN32) static p_GetDiskFreeSpaceExA pfnGetDiskFreeSpaceEx = NULL; static boolean testwin95 = false; ULARGE_INTEGER usedbytes, lfreespace; @@ -2418,7 +2398,6 @@ void I_GetDiskFreeSpace(INT64 *freespace) char *I_GetUserName(void) { -#if !defined (_WIN32_WCE) static char username[MAXPLAYERNAME]; char *p; #ifdef _WIN32 @@ -2450,7 +2429,6 @@ char *I_GetUserName(void) if (strcmp(username, "") != 0) return username; -#endif return NULL; // dummy for platform independent version } @@ -2459,7 +2437,7 @@ INT32 I_mkdir(const char *dirname, INT32 unixright) //[segabor] #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) || defined (__CYGWIN__) || defined (__OS2__) return mkdir(dirname, unixright); -#elif defined (_WIN32) || (defined (_WIN32_WCE) && !defined (__GNUC__)) +#elif defined (_WIN32) UNREFERENCED_PARAMETER(unixright); /// \todo should implement ntright under nt... return CreateDirectoryA(dirname, NULL); #else @@ -2473,9 +2451,6 @@ char *I_GetEnv(const char *name) { #ifdef NEED_SDL_GETENV return SDL_getenv(name); -#elif defined(_WIN32_WCE) - (void)name; - return NULL; #else return getenv(name); #endif @@ -2485,8 +2460,6 @@ INT32 I_PutEnv(char *variable) { #ifdef NEED_SDL_GETENV return SDL_putenv(variable); -#elif defined(_WIN32_WCE) - return ((variable)?-1:0); #else return putenv(variable); #endif @@ -2597,15 +2570,6 @@ static const char *locateWad(void) if (((envstr = I_GetEnv("SRB2WADDIR")) != NULL) && isWadPathOk(envstr)) return envstr; -#if defined(_WIN32_WCE) - // examine argv[0] - strcpy(returnWadPath, myargv[0]); - pathonly(returnWadPath); - I_PutEnv(va("HOME=%s",returnWadPath)); - if (isWadPathOk(returnWadPath)) - return returnWadPath; -#endif - #ifndef NOCWD I_OutputMsg(",."); // examine current dir @@ -2703,9 +2667,9 @@ const char *I_LocateWad(void) if (waddir) { // change to the directory where we found srb2.srb -#if defined (_WIN32) && !defined (_WIN32_WCE) +#ifdef _WIN32 SetCurrentDirectoryA(waddir); -#elif !defined (_WIN32_WCE) +#else if (chdir(waddir) == -1) I_OutputMsg("Couldn't change working directory\n"); #endif @@ -2803,7 +2767,7 @@ UINT32 I_GetFreeMem(UINT32 *total) if (total) *total = totalKBytes << 10; return freeKBytes << 10; -#elif defined (_WIN32) || (defined (_WIN32_WCE) && !defined (__GNUC__)) +#elif defined (_WIN32) MEMORYSTATUS info; info.dwLength = sizeof (MEMORYSTATUS); @@ -2831,7 +2795,7 @@ UINT32 I_GetFreeMem(UINT32 *total) const CPUInfoFlags *I_CPUInfo(void) { -#if defined (_WIN32) && !defined (_WIN32_WCE) +#ifdef _WIN32 static CPUInfoFlags WIN_CPUInfo; SYSTEM_INFO SI; p_IsProcessorFeaturePresent pfnCPUID = (p_IsProcessorFeaturePresent)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsProcessorFeaturePresent"); @@ -2892,7 +2856,7 @@ const CPUInfoFlags *I_CPUInfo(void) #endif } -#if defined (_WIN32) && !defined (_WIN32_WCE) +#ifdef _WIN32 static void CPUAffinity_OnChange(void); static consvar_t cv_cpuaffinity = {"cpuaffinity", "-1", CV_SAVE | CV_CALL, NULL, CPUAffinity_OnChange, 0, NULL, NULL, 0, 0, NULL}; @@ -2935,7 +2899,7 @@ static void CPUAffinity_OnChange(void) void I_RegisterSysCommands(void) { -#if defined (_WIN32) && !defined (_WIN32_WCE) +#ifdef _WIN32 GetAffinityFuncs(); CV_RegisterVar(&cv_cpuaffinity); #endif diff --git a/src/sdl12/i_video.c b/src/sdl12/i_video.c index fa7e31e8d..1e6f76c10 100644 --- a/src/sdl12/i_video.c +++ b/src/sdl12/i_video.c @@ -18,10 +18,7 @@ /// \brief SRB2 graphics stuff for SDL #include <stdlib.h> - -#ifndef _WIN32_WCE #include <signal.h> -#endif #ifdef _MSC_VER #pragma warning(disable : 4214 4244) @@ -49,7 +46,7 @@ #ifdef HAVE_IMAGE #include "SDL_image.h" -#elseif !defined (_WIN32_WCE) +#else #define LOAD_XPM //I want XPM! #include "IMG_xpm.c" //Alam: I don't want to add SDL_Image.dll/so #define HAVE_IMAGE //I have SDL_Image, sortof @@ -94,11 +91,7 @@ #endif // maximum number of windowed modes (see windowedModes[][]) -#if defined (_WIN32_WCE) -#define MAXWINMODES (1) -#else #define MAXWINMODES (27) -#endif /** \brief */ @@ -141,25 +134,16 @@ static SDL_Rect **modeList = NULL; static Uint8 BitsPerPixel = 16; static Uint16 realwidth = BASEVIDWIDTH; static Uint16 realheight = BASEVIDHEIGHT; -#ifdef _WIN32_WCE -static const Uint32 surfaceFlagsW = SDL_HWPALETTE; //Can't handle WinCE changing sides -#else static const Uint32 surfaceFlagsW = SDL_HWPALETTE/*|SDL_RESIZABLE*/; -#endif static const Uint32 surfaceFlagsF = SDL_HWPALETTE|SDL_FULLSCREEN; static SDL_bool mousegrabok = SDL_TRUE; #define HalfWarpMouse(x,y) SDL_WarpMouse((Uint16)(x/2),(Uint16)(y/2)) -#if defined (_WIN32_WCE) -static SDL_bool videoblitok = SDL_TRUE; -#else static SDL_bool videoblitok = SDL_FALSE; -#endif static SDL_bool exposevideo = SDL_FALSE; // windowed video modes from which to choose from. static INT32 windowedModes[MAXWINMODES][2] = { -#if !defined (_WIN32_WCE) {1920,1200}, // 1.60,6.00 {1680,1050}, // 1.60,5.25 {1600,1200}, // 1.33,5.00 @@ -186,17 +170,12 @@ static INT32 windowedModes[MAXWINMODES][2] = { 416, 312}, // 1.33,1.30 { 400, 300}, // 1.33,1.25 { 320, 240}, // 1.33,1.00 -#endif { 320, 200}, // 1.60,1.00 }; static void SDLSetMode(INT32 width, INT32 height, INT32 bpp, Uint32 flags) { const char *SDLVD = I_GetEnv("SDL_VIDEODRIVER"); -#ifdef _WIN32_WCE - if (bpp < 16) - bpp = 16; // 256 mode poo -#endif #ifdef FILTERS bpp = Setupf2x(width, height, bpp); #endif @@ -233,17 +212,6 @@ static INT32 SDLatekey(SDLKey sym) { INT32 rc = sym + 0x80; -#ifdef _WIN32_WCE - if (sym == SDLK_KP8) - sym = SDLK_UP; - else if (sym == SDLK_KP4) - sym = SDLK_LEFT; - else if (sym == SDLK_KP6) - sym = SDLK_RIGHT; - else if (sym == SDLK_KP2) - sym = SDLK_DOWN; -#endif - switch (sym) { case SDLK_LEFT: @@ -586,7 +554,6 @@ static void VID_Command_Info_f (void) static void VID_Command_ModeList_f(void) { -#if !defined (_WIN32_WCE) INT32 i; #ifdef HWRENDER if (rendermode == render_opengl) @@ -620,7 +587,6 @@ static void VID_Command_ModeList_f(void) modeList[modeNum]->h); } CONS_Printf("%s", M_GetText("None\n")); -#endif } static void VID_Command_Mode_f (void) @@ -641,7 +607,7 @@ static void VID_Command_Mode_f (void) setmodeneeded = modenum+1; // request vid mode change } -#if defined(RPC_NO_WINDOWS_H) && !defined(_WIN32_WCE) +#ifdef RPC_NO_WINDOWS_H static VOID MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(hWnd); @@ -962,7 +928,6 @@ void I_GetEvent(void) SDLJoyRemap(&event); if (event.type != ev_console) D_PostEvent(&event); break; -#ifndef _WIN32_WCE case SDL_QUIT: if (!sdlquit) { @@ -970,8 +935,7 @@ void I_GetEvent(void) M_QuitResponse('y'); } break; -#endif -#if defined(RPC_NO_WINDOWS_H) && !defined(_WIN32_WCE) +#ifdef RPC_NO_WINDOWS_H case SDL_SYSWMEVENT: MainWndproc(inputEvent.syswm.msg->hwnd, inputEvent.syswm.msg->msg, @@ -1492,9 +1456,7 @@ static void SDLWMSet(void) SetFocus(vid.WndParent); ShowWindow(vid.WndParent, SW_SHOW); } -#ifndef _WIN32_WCE SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); -#endif #endif SDL_EventState(SDL_VIDEORESIZE, SDL_IGNORE); } @@ -1513,9 +1475,6 @@ static void* SDLGetDirect(void) INT32 VID_SetMode(INT32 modeNum) { -#ifdef _WIN32_WCE - (void)modeNum; -#else SDLdoUngrabMouse(); vid.recalc = true; BitsPerPixel = (Uint8)cv_scr_depth.value; @@ -1614,7 +1573,6 @@ INT32 VID_SetMode(INT32 modeNum) #if 0 // broken if (!cv_stretch.value && (float)vid.width/vid.height != ((float)BASEVIDWIDTH/BASEVIDHEIGHT)) vid.height = (INT32)(vid.width * ((float)BASEVIDHEIGHT/BASEVIDWIDTH));// Adjust the height to match -#endif #endif I_StartupMouse(); @@ -1696,11 +1654,7 @@ void I_StartupGraphics(void) #endif // Window title -#ifdef _WIN32_WCE - SDL_WM_SetCaption("SRB2 "VERSIONSTRING, "SRB2"); -#else SDL_WM_SetCaption("SRB2: Starting up", "SRB2"); -#endif // Window icon #ifdef HAVE_IMAGE @@ -1744,7 +1698,7 @@ void I_StartupGraphics(void) // check gl renderer lib if (HWD.pfnGetRenderVersion() != VERSION) I_Error("%s", M_GetText("The version of the renderer doesn't match the version of the executable\nBe sure you have installed SRB2 properly.\n")); -#if 1 //#ifdef _WIN32_WCE +#if 1 // vid.width = BASEVIDWIDTH; vid.height = BASEVIDHEIGHT; #else diff --git a/src/sdl12/sdl_sound.c b/src/sdl12/sdl_sound.c index 232c73c44..a4b3635ca 100644 --- a/src/sdl12/sdl_sound.c +++ b/src/sdl12/sdl_sound.c @@ -49,7 +49,7 @@ #define MIX_CHANNELS 8 #endif -#if defined (_WIN32) && !defined (_WIN32_WCE) +#ifdef _WIN32 #include <direct.h> #elif defined (__GNUC__) #include <unistd.h> @@ -85,19 +85,11 @@ // mixing buffer, and the samplerate of the raw data. // Needed for calling the actual sound output. -#if defined (_WIN32_WCE) -#define NUM_CHANNELS MIX_CHANNELS -#else #define NUM_CHANNELS MIX_CHANNELS*4 -#endif #define INDEXOFSFX(x) ((sfxinfo_t *)x - S_sfx) -#if defined (_WIN32_WCE) -static Uint16 samplecount = 512; //Alam: .5KB samplecount at 11025hz is 46.439909297052154195011337868481ms of buffer -#else static Uint16 samplecount = 1024; //Alam: 1KB samplecount at 22050hz is 46.439909297052154195011337868481ms of buffer -#endif typedef struct chan_struct { @@ -167,9 +159,6 @@ static SDL_bool canlooping = SDL_TRUE; #if SDL_MIXER_VERSION_ATLEAST(1,2,7) #define USE_RWOPS // ok, USE_RWOPS is in here -#if defined (_WIN32_WCE) //|| defined(_WIN32) -#undef USE_RWOPS -#endif #endif #if SDL_MIXER_VERSION_ATLEAST(1,2,10) diff --git a/src/w_wad.c b/src/w_wad.c index 22e1836c7..2aa0a6316 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -18,11 +18,7 @@ #define ZWAD #ifdef ZWAD -#ifdef _WIN32_WCE -#define AVOID_ERRNO -#else #include <errno.h> -#endif #include "lzf.h" #endif diff --git a/src/win32ce/GameX.h b/src/win32ce/GameX.h deleted file mode 100644 index 241fdd5be..000000000 --- a/src/win32ce/GameX.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - - GameX - WindowsCE Game Library for High Performance. - - Copyright (C) 1999 Hayes C. Haugen, all rights reserved. - - */ - -/* - * Need better way for host app to keep track of direct vs blit - drawing. Right now GetFBAddress() is the way to do it. - - - */ - - -#pragma once -#include <windows.h> // For VK codes. - -// Defines - -// display property flags - -const unsigned long kfDPGrey = 0x0001; -const unsigned long kfDPGrey2Bit = 0x0002; -const unsigned long kfDPGrey4Bit = 0x0004; -const unsigned long kfDPColor = 0x0008; -const unsigned long kfDPColor8Bit = 0x0010; -const unsigned long kfDPColor16Bit = 0x0020; -const unsigned long kfDPColor24Bit = 0x0040; -const unsigned long kfDPColor32Bit = 0x0080; -const unsigned long kfDPFormatNormal = 0x0100; // fb start is upper left, inc goes across -const unsigned long kfDPFormatRot270 = 0x0200; // fb start is lower left, inc goes up - -// Machine property flags - -const unsigned long kfMPPSPC = 0x0001; // Palm Sized PC - 240 x 320 -const unsigned long kfMPPSPC1 = 0x0002; // 1st gen pspc -const unsigned long kfMPPSPC2 = 0x0004; // Wyverns -const unsigned long kfMPHPC = 0x0008; // Handheld PC -const unsigned long kfMPHPC1 = 0x0010; // HPC 1, 480 x 240 -const unsigned long kfMPHPC2 = 0x0020; // HPC 2, 640 x 240 -const unsigned long kfMPHPC3 = 0x0040; // HPC Pro, 640 x 240, big keys -const unsigned long kfMPPro = 0x0080; // -const unsigned long kfMPAutoPC = 0x0100; -const unsigned long kfMPHasKeyboard = 0x0200; -const unsigned long kfMPHasMouse = 0x0400; -const unsigned long kfMPHasRumble = 0x0800; -const unsigned long kfMPHasTouch = 0x1000; - -// Rotations - -const int kiRotate0 = 0; // no rotation -const int kiRotate90 = 1; // 90 degrees clockwise -const int kiRotate180 = 2; // 180 degrees clockwise (upside down, Rotate 0 flipped) -const int kiRotate270 = 3; // 270 degrees clockwise (Rotate 1 flipped) - -class GameX { -public: - HWND SetButtonNotificationWindow(HWND hWnd); - GameX(); - ~GameX(); - - bool OpenGraphics(); - bool OpenSound(); - bool OpenButtons(HWND hwndButtonNotify); // Window that will get button messages or NULL if you just want to use GetAsyncKeyState(); - bool CloseGraphics(); - bool CloseSound(); - bool CloseButtons(); - - bool IsColor(); - bool IsPSPC(); - bool IsHPC(); - bool IsHPCPro(); - bool HasMouse(); - bool HasKeyboard(); // better than inferring from hpc/pspc/etc. - bool HasRumble(); - bool HasTouch(); // for completeness. At least 1 doesn't. - - int IsForeground(); - bool Suspend(); // release buttons, don't draw, etc. - bool Resume(); // regrab buttons, etc. - - bool BeginDraw(); - bool EndDraw(); - bool FindFrameBuffer(); - void * GetFBAddress(); // simple way to get things that makes code - long GetFBModulo(); // more readable. - long GetFBBpp(); - bool GetScreenRect(RECT * prc); - unsigned long GetDisplayProperties(); - - bool GetButton(int VK); // buttons init themselves on first button call?? - unsigned short GetDefaultButtonID(long id, long rotate); // gets the best button for use as specified by need and rotation - bool ReleaseButton(int VK); - bool BeginDetectButtons(); // grabs all buttons so user can indicate a button in a config dialog - bool EndDetectButtons(); // releases all buttons (except GetButton() ones) - - bool Rumble(); - bool Backlight(bool fOn); -private: -// LRESULT CALLBACK TaskBarWndProc(HWND hWnd, UINT message, WPARAM uParam, LPARAM lParam); - -private: - int m_iMP; // index into amp table for current machine. - void * m_pvFrameBuffer; - long m_cbFBModulo; // count of bytes to next line - unsigned long m_ffMachineProperties; - unsigned long m_ffDisplayProperties; - int m_cBitsPP; - - long m_dwPrevMode; // for Begin/EndDraw() - bool m_fActive; // true if active (resume), false if inactive (suspend). - - HWND m_hwndTaskbar; // Taskbar is official cap, change TaskBar's -}; - - -/* - -kmtCasioE10 -kmtCasioE11 -kmtCasioE15 -kmtCasioE55 -kmtCasioE100 -kmtLGPhenomII - -stuff for memory size and presence/absence of CF - -// Rotations that make sense for this device or default rotation: - -Rotate0 // no rotation -Rotate1 // 90 degrees clockwise -Rotate2 // 180 degrees clockwise (upside down, Rotate 0 flipped) -Rotate3 // 270 degrees clockwise (Rotate 1 flipped) - -kmtAccessNone // no direct framebuffer access -kmtAccess1 // write to fixed address -kmtAccess2 // find framebuffer memory aperture in GWES.EXE memory space. - -OriginUpperLeft -OriginUpperRight -OriginLowerRight -OriginLowerLeft - -MappedHorizontal // increasing fb address goes across screen -MappedVertical // increasing fb address goes up/down screen (Compaq) - -A machine entry: -=========================================== - machine kmtCasioE10, - type kmtPSPC | kmtPSPC1, - displaytype kmtGrey | kmtGrey2Bit | kmtAccess1, - pvFrameBuffer 0xAA000000, - cbFBModulo 1024 // count of bytes to next line - cbppFB 2, // bits per pixel - cxDisp 240, - cyDisp 320, - format OriginUpperLeft, MappedHorizontal - - rotate0 // for rotate mode 0, these are the best keys - vkUp VK_UP - vkDown VK_DOWN - vkLeft 0xC1 - vkRight 0xC2 - vkA 0xC3 - vkB 0 - rotate1 - vkUp 0xC1 - vkDown 0xC2 - vkLeft VK_DOWN - ... - ...*/ - diff --git a/src/win32ce/SRB2CE.zip b/src/win32ce/SRB2CE.zip deleted file mode 100644 index 3ac8530dcb124cbda512a7d469da933c3fc974bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34234 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 CQd6)1 diff --git a/src/win32ce/Srb2win.ico b/src/win32ce/Srb2win.ico deleted file mode 100644 index 700276fd4b9ac2810a6981eb054921f3708c702b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372798 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 diff --git a/src/win32ce/afxres.h b/src/win32ce/afxres.h deleted file mode 100644 index 7f5245404..000000000 --- a/src/win32ce/afxres.h +++ /dev/null @@ -1,17 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief needed if mfc not installed (if I remember well) diff --git a/src/win32ce/gapi_c.cpp b/src/win32ce/gapi_c.cpp deleted file mode 100644 index 60c7adfa2..000000000 --- a/src/win32ce/gapi_c.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include <stdlib.h> -#include <windows.h> - -#define _USE_GAPI_ - - -#ifndef _USE_GAPI_ - #include "GameX.h" - -struct GXDisplayProperties -{ - DWORD cxWidth; - DWORD cyHeight; - long cbxPitch; - long cbyPitch; - long cBPP; - DWORD ffFormat; -}; - -#define kfPalette 0x10 // Pixel values are indexes into a palette -#define kfDirect565 0x80 // 5 red bits, 6 green bits and 5 blue bits per pixel - - - GameX* gx = new GameX; -#else - #include "gx.h" -#endif - -extern "C" -{ - #include "gapi_c.h" -} - -extern "C" int GXOPENDISPLAY(HWND hWnd, DWORD dwFlags) -{ - #ifndef _USE_GAPI_ - if(!gx) - return 0; - - //gx->OpenSound(); - if(!gx->OpenGraphics()) - { - delete gx; - gx = 0; - return 0; - } - - return TRUE; - - #else - return GXOpenDisplay(hWnd,dwFlags); - #endif -} - -extern "C" int GXCLOSEDISPLAY() -{ - #ifndef _USE_GAPI_ - gx->CloseGraphics(); - return TRUE; - #else - return GXCloseDisplay(); - #endif -} - -extern "C" void * GXBEGINDRAW() -{ - #ifndef _USE_GAPI_ - if(gx->BeginDraw()) - return gx->GetFBAddress(); - - return NULL; - #else - return GXBeginDraw(); - #endif -} - -extern "C" int GXENDDRAW() -{ - #ifndef _USE_GAPI_ - return gx->EndDraw(); - #else - return GXEndDraw(); - #endif - -} - -extern "C" struct GXDisplayProperties GXGETDISPLAYPROPERTIES() -{ - #ifndef _USE_GAPI_ - RECT r; - GXDisplayProperties gxdp; - - gxdp.cbyPitch = gx->GetFBModulo(); - gxdp.cBPP = gx->GetFBBpp(); - gxdp.cbxPitch = (gxdp.cBPP >> 3); - - gx->GetScreenRect(&r); - gxdp.cxWidth = (r.right - r.left); - gxdp.cyHeight = (r.bottom - r.top); - - if(gxdp.cBPP = 16) - gxdp.ffFormat = kfDirect565; - else if(gxdp.cBPP = 8) - gxdp.ffFormat = kfPalette; - - return gxdp; - - #else - return GXGetDisplayProperties(); - #endif -} - -extern "C" int GXSUSPEND() -{ - #ifndef _USE_GAPI_ - return gx->Suspend(); - #else - return GXSuspend(); - #endif -} - -extern "C" int GXRESUME() -{ - #ifndef _USE_GAPI_ - return gx->Resume(); - #else - return GXResume(); - #endif -} \ No newline at end of file diff --git a/src/win32ce/gapi_c.h b/src/win32ce/gapi_c.h deleted file mode 100644 index 40e7799ff..000000000 --- a/src/win32ce/gapi_c.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef GAPI_H -#define GAPI_H - -int GXOPENDISPLAY(HWND hWnd, DWORD dwFlags); -int GXCLOSEDISPLAY(); -void * GXBEGINDRAW(); -int GXENDDRAW(); -struct GXDisplayProperties GXGETDISPLAYPROPERTIES(); -int GXSUSPEND(); -int GXRESUME(); - -#endif \ No newline at end of file diff --git a/src/win32ce/gxgapilib.c b/src/win32ce/gxgapilib.c deleted file mode 100644 index 8ff57092d..000000000 --- a/src/win32ce/gxgapilib.c +++ /dev/null @@ -1,636 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -// -//----------------------------------------------------------------------------- -/// \file -/// \brief Zak Larue-Buckley's GX and GAPI library v1.0 - -#include "../doomdef.h" -//#define WIN32_LEAN_AND_MEAN -#define RPC_NO_WINDOWS_H -#include <windows.h> -#include <windowsx.h> -#include "../i_system.h" -#include "dx_error.h" - -#include "fabdxlib.h" - -#define NT4COMPAT //always defined, always compatible - - -// globals - -IDirectDraw2* DDr2 = NULL; -IDirectDrawSurface* ScreenReal = NULL; // DirectDraw primary surface -IDirectDrawSurface* ScreenVirtual = NULL; // DirectDraw back surface -IDirectDrawPalette* DDPalette = NULL; // The primary surface palette -static IDirectDrawClipper *windclip = NULL; // clipper for windowed mode - -BOOL bAppFullScreen; // true for fullscreen exclusive mode, - -int windowPosX = 0; // current position in windowed mode -int windowPosY = 0; - -int ScreenWidth; -int ScreenHeight; -BOOL ScreenLocked; // Screen surface is being locked -int ScreenPitch; // offset from one line to the next -LPBYTE ScreenPtr; // memory of the surface - - -// -// CreateNewSurface -// -static inline IDirectDrawSurface* CreateNewSurface(int dwWidth, - int dwHeight, - int dwSurfaceCaps) -{ - DDSURFACEDESC ddsd; - HRESULT hr; - LPDIRECTDRAWSURFACE psurf; - - ZeroMemory(&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH; - - ddsd.ddsCaps.dwCaps = dwSurfaceCaps; - - ddsd.dwHeight = dwHeight; - ddsd.dwWidth = dwWidth; - - hr = IDirectDraw2_CreateSurface (DDr2, &ddsd, &psurf, NULL); - - if (hr == DD_OK) - { - //DDCOLORKEY ddck; - IDirectDrawSurface_Restore(psurf); - - //hr = IDirectDrawSurface_GetColorKey(DDCKEY_SRCBLT, &ddck); - //psurf->SetColorKey(DDCKEY_SRCBLT, &ddck); - } - else - psurf = NULL; - - return psurf; -} - -// -// wow! from 320x200x8 up to 1600x1200x32 thanks Banshee! :) -// -static HRESULT WINAPI myEnumModesCallback (LPDDSURFACEDESC surf, LPVOID lpContext) -{ - APPENUMMODESCALLBACK pfnContext = lpContext; - - if (pfnContext) pfnContext(surf->dwWidth, - surf->dwHeight,surf->ddpfPixelFormat. -#ifdef DUMMYUNIONNAMEN - DUMMYUNIONNAMEN(1). -#endif - dwRGBBitCount - ); - - /*CONS_Printf ("%dx%dx%d bpp %d refresh\n", - surf->dwWidth, - surf->dwHeight, - surf->ddpfPixelFormat.dwRGBBitCount, - surf->dwRefreshRate);*/ - - return DDENUMRET_OK; -} - - -// -// Application call here to enumerate display modes -// -BOOL EnumDirectDrawDisplayModes (APPENUMMODESCALLBACK appFunc) -{ - LPVOID lpappFunc = appFunc; - - if (DDr2 == NULL) - return FALSE; - - // enumerate display modes - // Carl: DirectX 3.x apparently does not support VGA modes. Who cares. :) - // faB: removed DDEDM_REFRESHRATES, detects too many modes, plus we don't care of refresh rate. - if (bDX0300) - IDirectDraw2_EnumDisplayModes (DDr2, 0 /*| DDEDM_REFRESHRATES*/, - NULL, lpappFunc, myEnumModesCallback); - else - IDirectDraw2_EnumDisplayModes (DDr2, DDEDM_STANDARDVGAMODES /*| DDEDM_REFRESHRATES*/, - NULL, lpappFunc, myEnumModesCallback); - return TRUE; -} - - -// -// Create the DirectDraw object for later -// -BOOL CreateDirectDrawInstance (VOID) -{ - HRESULT hr; - IDirectDraw* DDr; - IDirectDraw** rp = &DDr; - IDirectDraw2** rp2 = &DDr2; - LPVOID *tp = (LPVOID *)rp2; - - // - // create an instance of DirectDraw object - // - if (FAILED(hr = DirectDrawCreate(NULL, rp, NULL))) - I_Error("DirectDrawCreate FAILED: %s", DXErrorToString(hr)); - - // change interface to IDirectDraw2 - if (FAILED(hr = IDirectDraw_QueryInterface (DDr, &IID_IDirectDraw2, tp))) - I_Error("Failed to query DirectDraw2 interface: %s", DXErrorToString(hr)); - - // release the interface we don't need - IDirectDraw_Release (DDr); - return TRUE; -} - - -// -// - returns true if DirectDraw was initialized properly -// -int InitDirectDrawe (HWND appWin, int width, int height, int bpp, int fullScr) -{ - DDSURFACEDESC ddsd; // DirectDraw surface description for allocating - DDSCAPS ddscaps; - HRESULT ddrval; - - DWORD dwStyle; - RECT rect; - - // enumerate directdraw devices - //if (FAILED(DirectDrawEnumerate (myEnumDDDevicesCallback, NULL))) - // I_Error("Error with DirectDrawEnumerate"); - - if (!DDr2) - CreateDirectDrawInstance(); - - // remember what screen mode we are in - bAppFullScreen = fullScr; - ScreenHeight = height; - ScreenWidth = width; - - if (bAppFullScreen) - { - // Change window attributes - dwStyle = WS_POPUP | WS_VISIBLE; - SetWindowLong (appWin, GWL_STYLE, dwStyle); - SetWindowPos(appWin, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | - SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); - - // Get exclusive mode - ddrval = IDirectDraw2_SetCooperativeLevel(DDr2, appWin, DDSCL_EXCLUSIVE | - DDSCL_FULLSCREEN | - DDSCL_ALLOWREBOOT); - if (ddrval != DD_OK) - I_Error("SetCooperativeLevel FAILED: %s\n", DXErrorToString(ddrval)); - - // Switch from windows desktop to fullscreen - -#ifdef NT4COMPAT - ddrval = IDirectDraw2_SetDisplayMode(DDr2, width, height, bpp, 0, 0); -#else - ddrval = IDirectDraw2_SetDisplayMode(DDr2, width, height, bpp, 0, DDSDM_STANDARDVGAMODE); -#endif - if (ddrval != DD_OK) - I_Error("SetDisplayMode FAILED: %s\n", DXErrorToString(ddrval)); - - // This is not really needed, except in certain cases. One case - // is while using MFC. When the desktop is initally at 16bpp, a mode - // switch to 8bpp somehow causes the MFC window to not fully initialize - // and a CreateSurface will fail with DDERR_NOEXCLUSIVEMODE. This will - // ensure that the window is initialized properly after a mode switch. - - ShowWindow(appWin, SW_SHOW); - - // Create the primary surface with 1 back buffer. Always zero the - // DDSURFACEDESC structure and set the dwSize member! - - ZeroMemory(&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; - - // for fullscreen we use page flipping, for windowed mode, we blit the hidden surface to - // the visible surface, in both cases we have a visible (or 'real') surface, and a hidden - // (or 'virtual', or 'backbuffer') surface. - ddsd.dwBackBufferCount = 1; - - ddrval = IDirectDraw2_CreateSurface(DDr2,&ddsd, &ScreenReal, NULL); - if (ddrval != DD_OK) - I_Error("CreateSurface Primary Screen FAILED"); - - // Get a pointer to the back buffer - - ddscaps.dwCaps = DDSCAPS_BACKBUFFER; - ddrval = IDirectDrawSurface_GetAttachedSurface(ScreenReal,&ddscaps, &ScreenVirtual); - if (ddrval != DD_OK) - I_Error("GetAttachedSurface FAILED"); - } - else - { - rect.top = 0; - rect.left = 0; - rect.bottom = height-1; - rect.right = width-1; - - // Change window attributes - - dwStyle = GetWindowStyle(appWin); - dwStyle &= ~WS_POPUP; - dwStyle |= WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION; - - SetWindowLong(appWin, GWL_STYLE, dwStyle); - - // Resize the window so that the client area is the requested width/height - - AdjustWindowRectEx(&rect, GetWindowStyle(appWin), GetMenu(appWin) != NULL, - GetWindowExStyle(appWin)); - - // Just in case the window was moved off the visible area of the - // screen. - - SetWindowPos(appWin, NULL, 0, 0, rect.right-rect.left, - rect.bottom-rect.top, SWP_NOMOVE | SWP_NOZORDER | - SWP_NOACTIVATE); - - SetWindowPos(appWin, HWND_NOTOPMOST, 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); - - // Exclusive mode is normal since it's in windowed mode and needs - // to cooperate with GDI - - ddrval = IDirectDraw2_SetCooperativeLevel(DDr2,appWin, DDSCL_NORMAL); - if (ddrval != DD_OK) - I_Error("SetCooperativeLevel FAILED"); - - // Always zero the DDSURFACEDESC structure and set the dwSize member! - - ZeroMemory(&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - ddsd.dwFlags = DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - - // Create the primary surface - - ddrval = IDirectDraw2_CreateSurface(DDr2,&ddsd, &ScreenReal, NULL); - if (ddrval != DD_OK) - I_Error("CreateSurface Primary Screen FAILED"); - - // Create a back buffer for offscreen rendering, this will be used to - // blt to the primary - - ScreenVirtual = CreateNewSurface(width, height, DDSCAPS_OFFSCREENPLAIN | - DDSCAPS_SYSTEMMEMORY); - if (ScreenVirtual == NULL) - I_Error("CreateSurface Secondary Screen FAILED"); - - /// \todo get the desktop bit depth, and build a lookup table - /// for quick conversions of 8bit color indexes 0-255 to desktop colors - /// eg: 256 entries of equivalent of palette colors 0-255 in 15,16,24,32 bit format - /// when blit virtual to real, convert pixels through lookup table.. - - // Use a clipper object for clipping when in windowed mode - // (make sure our drawing doesn't affect other windows) - - ddrval = IDirectDraw2_CreateClipper (DDr2, 0, &windclip, 0); - if (ddrval != DD_OK) - I_Error("CreateClipper FAILED"); - - // Associate the clipper with the window. - ddrval = IDirectDrawClipper_SetHWnd (windclip,0, appWin); - if (ddrval != DD_OK) - I_Error("Clipper -> SetHWnd FAILED"); - - // Attach the clipper to the surface. - ddrval = IDirectDrawSurface_SetClipper (ScreenReal,windclip); - if (ddrval != DD_OK) - I_Error("PrimaryScreen -> SetClipperClipper FAILED"); - } - - return TRUE; -} - - -// -// Free all memory -// -VOID CloseDirectDraw (VOID) -{ - ReleaseChtuff(); - if (DDr2) - { - IDirectDraw2_Release(DDr2); - DDr2 = NULL; - } -} - - -// -// Release DirectDraw stuff before display mode change -// -VOID ReleaseChtuff (VOID) -{ - if (!DDr2) - return; - if (windclip) - { - IDirectDrawClipper_Release(windclip); - windclip = NULL; - } - if (DDPalette) - { - IDirectDrawPalette_Release(DDPalette); - DDPalette = NULL; - } - // If the app is fullscreen, the back buffer is attached to the - // primary. Releasing the primary buffer will also release any - // attached buffers, so explicitly releasing the back buffer is not - // necessary. - - if (!bAppFullScreen && ScreenVirtual) - { - IDirectDrawSurface_Release(ScreenVirtual); // release hidden surface - ScreenVirtual = NULL; - } - if (ScreenReal) - { - IDirectDrawSurface_Release(ScreenReal); // and attached backbuffers for bAppFullScreen mode - ScreenReal = NULL; - } -} - - -// -// Clear the surface to color -// -VOID ClearSurface(IDirectDrawSurface* surface, int color) -{ - DDBLTFX ddbltfx; - - // Use the blter to do a color fill to clear the back buffer - ddbltfx.dwSize = sizeof (ddbltfx); - ddbltfx. -#ifdef DUMMYUNIONNAMEN - DUMMYUNIONNAMEN(5). -#endif - dwFillColor = color; - IDirectDrawSurface_Blt(surface,NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); - -} - -// -// Flip the real page with virtual page -// - in bAppFullScreen mode, do page flipping -// - in windowed mode, copy the hidden surface to the visible surface -// -// waitflip : if not 0, wait for page flip to end -BOOL ScreenFlip(int waitflip) -{ - HRESULT hr; - RECT rect; - - waitflip = 0; - if (bAppFullScreen) - { - //hr = IDirectDrawSurface_GetFlipStatus (ScreenReal, DDGFS_); - - // In full-screen exclusive mode, do a hardware flip. - hr = IDirectDrawSurface_Flip(ScreenReal, NULL, DDFLIP_WAIT); //return immediately - - // If the surface was lost, restore it. - if (hr == DDERR_SURFACELOST) - { - IDirectDrawSurface_Restore(ScreenReal); - - // The restore worked, so try the flip again. - hr = IDirectDrawSurface_Flip(ScreenReal, 0, DDFLIP_WAIT); - } - } - else - { - rect.left = windowPosX; - rect.top = windowPosY; - rect.right = windowPosX + ScreenWidth - 1; - rect.bottom = windowPosY + ScreenHeight - 1; - - // Copy the back buffer to front. - hr = IDirectDrawSurface_Blt(ScreenReal, &rect, ScreenVirtual, 0, DDBLT_WAIT, 0); - - if (hr != DD_OK) - { - // If the surfaces were lost, restore them. - if (IDirectDrawSurface_IsLost(ScreenReal) == DDERR_SURFACELOST) - IDirectDrawSurface_Restore(ScreenReal); - - if (IDirectDrawSurface_IsLost(ScreenVirtual) == DDERR_SURFACELOST) - IDirectDrawSurface_Restore(ScreenVirtual); - - // Retry the copy. - hr = IDirectDrawSurface_Blt(ScreenReal,&rect, ScreenVirtual, 0, DDBLT_WAIT, 0); - } - } - - if (hr != DD_OK) - I_Error("ScreenFlip() : couldn't Flip surfaces"); - - return FALSE; -} - -// -// Print a text to the surface -// -VOID TextPrint(int x, int y, LPCSTR message) -{ - HRESULT hr; - HDC hdc = NULL; - - // Get the device context handle. - hr = IDirectDrawSurface_GetDC(ScreenVirtual,&hdc); - if (hr != DD_OK) - return; - - // Write the message. - SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, RGB(255, 255, 255)); - TextOutA(hdc, x, y, message, (int)strlen(message)); - - // Release the device context. - hr = IDirectDrawSurface_ReleaseDC(ScreenVirtual,hdc); -} - -// -// Lock surface before multiple drawings by hand, for speed -// -boolean LockScreen(VOID) -{ - DDSURFACEDESC ddsd; - HRESULT ddrval; - - ZeroMemory(&ddsd, sizeof (ddsd)); - ddsd.dwSize = sizeof (ddsd); - - // attempt to Lock the surface - ddrval = IDirectDrawSurface_Lock(ScreenVirtual, NULL, &ddsd, DDLOCK_WAIT, NULL); - - // Always, always check for errors with DirectX! - // If the surface was lost, restore it. - if (ddrval == DDERR_SURFACELOST) - { - ddrval = IDirectDrawSurface_Restore(ScreenReal); - - // now retry to get the lock - ddrval = IDirectDrawSurface_Lock(ScreenVirtual, NULL, &ddsd, DDLOCK_WAIT, NULL); - } - - if (ddrval == DD_OK) - { - ScreenLocked = TRUE; - ScreenPtr = (LPBYTE)ddsd.lpSurface; - ScreenPitch = ddsd. -#ifdef DUMMYUNIONNAMEN - DUMMYUNIONNAMEN(1). -#endif - lPitch; - } - else - { - ScreenLocked = FALSE; - ScreenPtr = NULL; - ScreenPitch = 0; - //I_Error("LockScreen() : couldn't restore the surface."); - return false; - } - return true; -} - -// -// Unlock surface -// -VOID UnlockScreen(VOID) -{ - if (DD_OK != IDirectDrawSurface_Unlock(ScreenVirtual,NULL)) - I_Error("Couldn't UnLock the renderer!"); - - ScreenLocked = FALSE; - ScreenPtr = NULL; - ScreenPitch = 0; -} - -// Blit virtual screen to real screen -//faB: note: testing 14/03/1999, see if it is faster than memcopy of virtual to -/* -static LPDIRECTDRAWSURFACE lpDDS = NULL; -VOID BlitScreen(VOID) -{ - HRESULT hr; - - if (!lpDDS) - I_Error("lpDDS NULL"); - - hr = IDirectDrawSurface_BltFast(ScreenVirtual, - 0, 0, // Upper left xy of destination - lpDDS, // Source surface - NULL, // Source rectangle = entire surface - DDBLTFAST_WAIT | DDBLTFAST_NOCOLORKEY); - if (FAILED(hr)) - I_Error("BltFast FAILED"); -} - -VOID MakeScreen(int width, int height, BYTE* lpSurface) -{ - HRESULT hr; - DDSURFACEDESC ddsd; - - // Initialize the surface description. - ZeroMemory (&ddsd, sizeof ddsd); - ZeroMemory (&ddsd.ddpfPixelFormat, sizeof (DDPIXELFORMAT)); - ddsd.dwSize = sizeof ddsd; - ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | //DDSD_LPSURFACE | - DDSD_PITCH | DDSD_PIXELFORMAT | DDSD_CAPS; - ddsd.dwWidth = width; - ddsd.dwHeight= height; - ddsd.lPitch = width; - ddsd.lpSurface = lpSurface; - ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; - - // Set up the pixel format for 8-bit - ddsd.ddpfPixelFormat.dwSize = sizeof (DDPIXELFORMAT); - ddsd.ddpfPixelFormat.dwFlags= DDPF_RGB | DDPF_PALETTEINDEXED8; - ddsd.ddpfPixelFormat.dwRGBBitCount = 8; - - // - ddsd.ddpfPixelFormat.dwRGBBitCount = (DWORD)DEPTH*8; - ddsd.ddpfPixelFormat.dwRBitMask = 0x00FF0000; - ddsd.ddpfPixelFormat.dwGBitMask = 0x0000FF00; - ddsd.ddpfPixelFormat.dwBBitMask = 0x000000FF; - - // Create the surface - hr = IDirectDraw2_CreateSurface(DDr2, &ddsd, &lpDDS, NULL); - if (FAILED(hr)) - I_Error("MakeScreen FAILED: %s",DDError(hr)); - //ddsd.lpSurface = lpSurface; -} -*/ - -// -// Create a palette object -// -VOID CreateDDPalette (PALETTEENTRY* colorTable) -{ - HRESULT ddrval; - ddrval = IDirectDraw2_CreatePalette(DDr2,DDPCAPS_8BIT|DDPCAPS_ALLOW256, colorTable, &DDPalette, NULL); - if (ddrval != DD_OK) - I_Error("couldn't CreatePalette"); -}; - - -// -// Free the palette object -// -VOID DestroyDDPalette (VOID) -{ - if (DDPalette) - { - IDirectDrawPalette_Release(DDPalette); - DDPalette = NULL; - } -} - -// -// Set a a full palette of 256 PALETTEENTRY entries -// -VOID SetDDPalette(PALETTEENTRY* pal) -{ - // create palette first time - if (DDPalette == NULL) - CreateDDPalette(pal); - else - IDirectDrawPalette_SetEntries(DDPalette, 0, 0, 256, pal); - // setting the same palette to the same surface again does not increase - // the reference count - IDirectDrawSurface_SetPalette(ScreenReal, DDPalette); -} - -// -// Wait for vsync, gross -// -VOID WaitVbl(VOID) -{ - IDirectDraw2_WaitForVerticalBlank(DDr2, DDWAITVB_BLOCKBEGIN, NULL); -} diff --git a/src/win32ce/gxgapilib.h b/src/win32ce/gxgapilib.h deleted file mode 100644 index 189cc15b8..000000000 --- a/src/win32ce/gxgapilib.h +++ /dev/null @@ -1,81 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief Zak Larue-Buckley's GX and GAPI library v1.0 - -#ifndef _H_GXGAPILIB_ -#define _H_GXGAPILIB_ - -//#define WIN32_LEAN_AND_MEAN -#define RPC_NO_WINDOWS_H -#include <windows.h> -#ifdef __MINGW32__ -//#define NONAMELESSUNION -#endif -#ifdef _MSC_VER -#pragma warning(disable : 4201) -#endif -#include <ddraw.h> -#if (defined (DIRECTDRAW_VERSION) && (DIRECTDRAW_VERSION >= 0x0700)) -#undef DUMMYUNIONNAMEN -#endif -// format of function in app called with width,height -typedef BOOL (*APPENUMMODESCALLBACK)(int width, int height, int bpp); - - -// globals -extern IDirectDraw2* DDr2; -extern IDirectDrawSurface* ScreenReal; -extern IDirectDrawSurface* ScreenVirtual; -extern IDirectDrawPalette* DDPalette; - -extern BOOL bAppFullScreen; // main code might need this to know the current - // fullscreen or windowed state - -extern int windowPosX; // current position in windowed mode -extern int windowPosY; - -extern int ScreenWidth; -extern int ScreenHeight; -extern BOOL ScreenLocked; // Screen surface is being locked -extern int ScreenPitch; // offset from one line to the next -extern LPBYTE ScreenPtr; // memory of the surface - -extern BOOL bDX0300; - -BOOL EnumDirectDrawDisplayModes (APPENUMMODESCALLBACK appFunc); -BOOL CreateDirectDrawInstance (VOID); - -int InitDirectDrawe (HWND appWin, int width, int height, int bpp, int fullScr); -VOID CloseDirectDraw (VOID); - -VOID ReleaseChtuff (VOID); - -VOID ClearSurface (IDirectDrawSurface* surface, int color); -BOOL ScreenFlip (int wait); -VOID TextPrint (int x, int y, LPCSTR message); - -VOID CreateDDPalette (PALETTEENTRY* colorTable); -VOID DestroyDDPalette (VOID); -VOID SetDDPalette (PALETTEENTRY* pal); - -VOID WaitVbl (VOID); - -boolean LockScreen (VOID); -VOID UnlockScreen (VOID); - - -#endif /* _H_FABDXLIB_ */ diff --git a/src/win32ce/midstuff.h b/src/win32ce/midstuff.h deleted file mode 100644 index 08ee80add..000000000 --- a/src/win32ce/midstuff.h +++ /dev/null @@ -1,150 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief MIDI structures and definitions -/// used by the MSTREAM sample application in -/// converting a MID file to a MIDI stream for -/// playback using the midiStream API. -/// Inpired by DirectX5 SDK examples - -#ifndef __MIDSTUFF_H__ -#define __MIDSTUFF_H__ - -// MIDI file constants -// -#define MThd 0x6468544D // Start of file -#define MTrk 0x6B72544D // Start of track - -#define MIDI_SYSEX ((BYTE)0xF0) // SysEx begin -#define MIDI_SYSEXEND ((BYTE)0xF7) // SysEx begin -#define MIDI_META ((BYTE)0xFF) // Meta event begin -#define MIDI_META_TEMPO ((BYTE)0x51) // Tempo change -#define MIDI_META_EOT ((BYTE)0x2F) // End-of-track - -#define MIDI_NOTEOFF ((BYTE)0x80) // + note + velocity -#define MIDI_NOTEON ((BYTE)0x90) // + note + velocity -#define MIDI_POLYPRESS ((BYTE)0xA0) // + pressure (2 bytes) -#define MIDI_CTRLCHANGE ((BYTE)0xB0) // + ctrlr + value -#define MIDI_PRGMCHANGE ((BYTE)0xC0) // + new patch -#define MIDI_CHANPRESS ((BYTE)0xD0) // + pressure (1 byte) -#define MIDI_PITCHBEND ((BYTE)0xE0) // + pitch bend (2 bytes) - -#define NUM_CHANNELS 16 - -#define MIDICTRL_VOLUME ((BYTE)0x07) -#define MIDICTRL_VOLUME_LSB ((BYTE)0x27) -#define MIDICTRL_PAN ((BYTE)0x0A) - -#define MIDIEVENT_CHANNEL(dw) (dw & 0x0000000F) -#define MIDIEVENT_TYPE(dw) (dw & 0x000000F0) -#define MIDIEVENT_DATA1(dw) ((dw & 0x0000FF00) >> 8) -#define MIDIEVENT_VOLUME(dw) ((dw & 0x007F0000) >> 16) - -// Macros for swapping hi/lo-endian data -// -#define WORDSWAP(w) (((w) >> 8) | \ - (((w) << 8) & 0xFF00)) - -#define DWORDSWAP(dw) (((dw) >> 24) | \ - (((dw) >> 8) & 0x0000FF00) | \ - (((dw) << 8) & 0x00FF0000) | \ - (((dw) << 24) & 0xFF000000)) - -// In debug builds, TRACKERR will show us where the parser died -// -//#define TRACKERR(p,sz) ShowTrackError(p,sz); -#define TRACKERR(p,sz) - - -// Make a little distinction here so the various structure members are a bit -// more clearly labelled -- we have offsets and byte counts to keep track of -// that deal with both in-memory buffers and the file on disk - -#define FILEOFF DWORD - - -// These structures are stored in MIDI files; they need to be byte aligned. -// -#if defined(_MSC_VER) -#pragma pack(1) -#endif - -// Chunk header. dwTag is either MTrk or MThd. -// -typedef struct -{ - DWORD dwTag; // Type - DWORD dwChunkLength; // Length (hi-lo) -} ATTRPACK MIDICHUNK; - -// Contents of MThd chunk. -typedef struct -{ - WORD wFormat; // Format (hi-lo) - WORD wTrackCount; // # tracks (hi-lo) - WORD wTimeDivision; // Time division (hi-lo) -} ATTRPACK MIDIFILEHDR; - -#if defined(_MSC_VER) -#pragma pack() // End of need for byte-aligned structures -#endif - - -// Temporary event structure which stores event data until we're ready to -// dump it into a stream buffer -// -typedef struct -{ - DWORD tkEvent; // Absolute time of event - BYTE byShortData[4]; // Event type and parameters if channel msg - DWORD dwEventLength; // Length of data which follows if meta or sysex - LPBYTE pLongData; // -> Event data if applicable -} TEMPEVENT, *PTEMPEVENT; - -#define ITS_F_ENDOFTRK 0x00000001 - -// Description of a track open for read -// -typedef struct -{ - DWORD fdwTrack; // Track status - DWORD dwTrackLength; // Total bytes in track - DWORD dwLeftInBuffer; // Bytes left unread in track buffer - LPBYTE pTrackStart; // -> start of track data buffer - LPBYTE pTrackCurrent; // -> next byte to read in buffer - DWORD tkNextEventDue; // Absolute time of next event in track - BYTE byRunningStatus;// Running status from last channel msg - - FILEOFF foTrackStart; // Start of track -- used for walking the file - FILEOFF foNextReadStart;// File offset of next read from disk - DWORD dwLeftOnDisk; // Bytes left unread on disk -#ifdef DEBUG - DWORD nTrack; // # of this track for debugging -#endif -} INTRACKSTATE, *PINTRACKSTATE; - -// Description of the input MIDI file -// -typedef struct -{ - DWORD cbFileLength; // Total bytes in file - DWORD dwTimeDivision; // Original time division - DWORD dwFormat; // Original format - DWORD dwTrackCount; // Track count (specifies pitsTracks size) - INTRACKSTATE *pitsTracks; // -> array of tracks in this file -} INFILESTATE, *PINFILESTATE; - -#endif //__MIDSTUFF_H__ diff --git a/src/win32ce/resource.h b/src/win32ce/resource.h deleted file mode 100644 index a712f14d6..000000000 --- a/src/win32ce/resource.h +++ /dev/null @@ -1,18 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by Srb2win.rc -// -#define IDI_DLICON1 101 -#define IDC_DLCURSOR1 103 -#define IDI_ICON1 106 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 114 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1000 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/src/win32ce/win_cd.c b/src/win32ce/win_cd.c deleted file mode 100644 index 2b1a8be9a..000000000 --- a/src/win32ce/win_cd.c +++ /dev/null @@ -1,529 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief cd music interface (uses MCI). - -#include "../doomdef.h" -#include "win_main.h" -#include <mmsystem.h> - -#include "../command.h" -#include "../doomtype.h" -#include "../i_sound.h" -#include "../i_system.h" - -#include "../s_sound.h" - -#define MAX_CD_TRACKS 255 - -typedef struct { - BOOL IsAudio; - DWORD Start, End; - DWORD Length; // minutes -} CDTrack; - -// ------- -// private -// ------- -static CDTrack m_nTracks[MAX_CD_TRACKS]; -static int m_nTracksCount; // up to MAX_CD_TRACKS -static MCI_STATUS_PARMS m_MCIStatus; -static MCI_OPEN_PARMS m_MCIOpen; - -// ------ -// protos -// ------ -static void Command_Cd_f (void); - - -// ------------------- -// MCIErrorMessageBox -// Retrieve error message corresponding to return value from -// mciSendCommand() or mciSenString() -// ------------------- -static VOID MCIErrorMessageBox (MCIERROR iErrorCode) -{ - char szErrorText[128]; - if (!mciGetErrorStringA (iErrorCode, szErrorText, sizeof (szErrorText))) - wsprintfA(szErrorText,"MCI CD Audio Unknow Error #%d\n", iErrorCode); - CONS_Printf (szErrorText); - /*MessageBox (GetActiveWindow(), szTemp+1, "LEGACY", - MB_OK | MB_ICONSTOP);*/ -} - - -// -------- -// CD_Reset -// -------- -static void CD_Reset (void) -{ - // no win32 equivalent - //faB: for DOS, some odd drivers like to be reset sometimes.. useless in MCI I guess -} - - -// ---------------- -// CD_ReadTrackInfo -// Read in number of tracks, and length of each track in minutes/seconds -// returns true if error -// ---------------- -static BOOL CD_ReadTrackInfo (void) -{ - int i; - int nTrackLength; - MCIERROR iErr; - - m_nTracksCount = 0; - - m_MCIStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS; - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM|MCI_WAIT, (DWORD_PTR)&m_MCIStatus); - if (iErr) - { - MCIErrorMessageBox (iErr); - return FALSE; - } - m_nTracksCount = (int)m_MCIStatus.dwReturn; - if (m_nTracksCount > MAX_CD_TRACKS) - m_nTracksCount = MAX_CD_TRACKS; - - for (i = 0; i < m_nTracksCount; i++) - { - m_MCIStatus.dwTrack = (DWORD)(i+1); - m_MCIStatus.dwItem = MCI_STATUS_LENGTH; - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_STATUS, MCI_TRACK|MCI_STATUS_ITEM|MCI_WAIT, (DWORD_PTR)&m_MCIStatus); - if (iErr) - { - MCIErrorMessageBox (iErr); - return FALSE; - } - nTrackLength = (DWORD)(MCI_MSF_MINUTE(m_MCIStatus.dwReturn)*60 + MCI_MSF_SECOND(m_MCIStatus.dwReturn)); - m_nTracks[i].Length = nTrackLength; - - m_MCIStatus.dwItem = MCI_CDA_STATUS_TYPE_TRACK; - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_STATUS, MCI_TRACK|MCI_STATUS_ITEM|MCI_WAIT, (DWORD_PTR)&m_MCIStatus); - if (iErr) - { - MCIErrorMessageBox (iErr); - return FALSE; - } - m_nTracks[i].IsAudio = (m_MCIStatus.dwReturn == MCI_CDA_TRACK_AUDIO); - } - - return TRUE; -} - - -// ------------ -// CD_TotalTime -// returns total time for all audio tracks in seconds -// ------------ -static int CD_TotalTime (void) -{ - int nTotalLength = 0; - int nTrack; - for (nTrack = 0; nTrack < m_nTracksCount; nTrack++) - { - if (m_nTracks[nTrack].IsAudio) - nTotalLength = nTotalLength + m_nTracks[nTrack].Length; - } - return nTotalLength; -} - - -//====================================================================== -// CD AUDIO MUSIC SUBSYSTEM -//====================================================================== - -UINT8 cdaudio_started = 0; // for system startup/shutdown - -static boolean cdPlaying = false; -static int cdPlayTrack; // when cdPlaying is true -static boolean cdLooping = false; -static UINT8 cdRemap[MAX_CD_TRACKS]; -static boolean cdEnabled = true; // cd info available -static boolean cdValid; // true when last cd audio info was ok -static boolean wasPlaying; -//static int cdVolume = 0; // current cd volume (0-31) - -// 0-31 like Music & Sfx, though CD hardware volume is 0-255. -consvar_t cd_volume = {"cd_volume","31",CV_SAVE,soundvolume_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; - -// allow Update for next/loop track -// some crap cd drivers take up to -// a second for a simple 'busy' check.. -// (on those Update can be disabled) -consvar_t cdUpdate = {"cd_update","1",CV_SAVE, NULL, NULL, 0, NULL, NULL, 0, 0, NULL}; - -// hour,minutes,seconds -static char *hms(int seconds) -{ - int hours, minutes; - static char s[9]; - - minutes = seconds / 60; - seconds %= 60; - hours = minutes / 60; - minutes %= 60; - if (hours > 0) - sprintf (s, "%d:%02d:%02d", hours, minutes, seconds); - else - sprintf (s, "%2d:%02d", minutes, seconds); - return s; -} - -static void Command_Cd_f (void) -{ - LPCSTR s; - int i,j; - - if (!cdaudio_started) - return; - - if (COM_Argc()<2) - { - CONS_Printf ("cd [on] [off] [remap] [reset] [open]\n" - " [info] [play <track>] [loop <track>]\n" - " [stop] [resume]\n"); - return; - } - - s = COM_Argv(1); - - // activate cd music - if (!strncmp(s,"on",2)) - { - cdEnabled = true; - return; - } - - // stop/deactivate cd music - if (!strncmp(s,"off",3)) - { - if (cdPlaying) - I_StopCD (); - cdEnabled = false; - return; - } - - // remap tracks - if (!strncmp(s,"remap",5)) - { - i = (int)COM_Argc() - 2; - if (i <= 0) - { - CONS_Printf ("CD tracks remapped in that order :\n"); - for (j = 1; j < MAX_CD_TRACKS; j++) - if (cdRemap[j] != j) - CONS_Printf (" %2d -> %2d\n", j, cdRemap[j]); - return; - } - for (j = 1; j <= i; j++) - cdRemap[j] = (UINT8)atoi (COM_Argv (j+1)); - return; - } - - // reset the CD driver, useful on some odd cd's - if (!strncmp(s,"reset",5)) - { - cdEnabled = true; - if (cdPlaying) - I_StopCD (); - for (i = 0; i < MAX_CD_TRACKS; i++) - cdRemap[i] = (UINT8)i; - CD_Reset(); - cdValid = CD_ReadTrackInfo(); - return; - } - - // any other command is not allowed until we could retrieve cd information - if (!cdValid) - { - CONS_Printf ("CD is not ready.\n"); - return; - } - - /* faB: not with MCI, didn't find it, useless anyway - if (!strncmp(s,"open",4)) - { - if (cdPlaying) - I_StopCD (); - bcd_open_door(); - cdValid = false; - return; - }*/ - - if (!strncmp(s,"info",4)) - { - if (!CD_ReadTrackInfo()) - { - cdValid = false; - return; - } - - cdValid = true; - - if (m_nTracksCount <= 0) - CONS_Printf ("No audio tracks\n"); - else - { - // display list of tracks - // highlight current playing track - for (i = 0; i < m_nTracksCount; i++) - { - CONS_Printf("%s%2d. %s %s\n", - cdPlaying && (cdPlayTrack == i) ? "\2 " : " ", - i+1, m_nTracks[i].IsAudio ? "audio" : "data ", - hms(m_nTracks[i].Length)); - } - CONS_Printf ("\2Total time : %s\n", hms(CD_TotalTime())); - } - if (cdPlaying) - { - CONS_Printf ("%s track : %d\n", cdLooping ? "looping" : "playing", - cdPlayTrack); - } - return; - } - - if (!strncmp(s,"play",4)) - { - I_PlayCD ((UINT8)atoi(COM_Argv (2)), false); - return; - } - - if (!strncmp(s,"stop",4)) - { - I_StopCD (); - return; - } - - if (!strncmp(s,"loop",4)) - { - I_PlayCD ((UINT8)atoi(COM_Argv (2)), true); - return; - } - - if (!strncmp(s,"resume",4)) - { - I_ResumeCD (); - return; - } - - CONS_Printf ("cd command '%s' unknown\n", s); -} - - -// ------------ -// I_ShutdownCD -// Shutdown CD Audio subsystem, release whatever was allocated -// ------------ -void I_ShutdownCD (void) -{ - MCIERROR iErr; - - if (!cdaudio_started) - return; - - CONS_Printf("I_ShutdownCD()\n"); - - I_StopCD(); - - // closes MCI CD - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_CLOSE, 0, 0); - if (iErr) - MCIErrorMessageBox (iErr); -} - - -// -------- -// I_InitCD -// Init CD Audio subsystem -// -------- -void I_InitCD (void) -{ - MCI_SET_PARMS mciSet; - MCIERROR iErr; - int i; - - // We don't have an open device yet - m_MCIOpen.wDeviceID = 0; - m_nTracksCount = 0; - - cdaudio_started = false; - - m_MCIOpen.lpstrDeviceType = (LPCTSTR)MCI_DEVTYPE_CD_AUDIO; - iErr = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID, (DWORD_PTR)&m_MCIOpen); - if (iErr) - { - MCIErrorMessageBox (iErr); - return; - } - - // Set the time format to track/minute/second/frame (TMSF). - mciSet.dwTimeFormat = MCI_FORMAT_TMSF; - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)&mciSet); - if (iErr) - { - MCIErrorMessageBox (iErr); - mciSendCommand(m_MCIOpen.wDeviceID, MCI_CLOSE, 0, 0); - return; - } - - I_AddExitFunc (I_ShutdownCD); - cdaudio_started = true; - - CONS_Printf("I_InitCD: Init CD audio\n"); - - // last saved in config.cfg - i = cd_volume.value; - //I_SetVolumeCD (0); // initialize to 0 for some odd cd drivers - I_SetVolumeCD (i); // now set the last saved volume - - for (i = 0; i < MAX_CD_TRACKS; i++) - cdRemap[i] = (UINT8)i; - - if (!CD_ReadTrackInfo()) - { - CONS_Printf("\2I_InitCD: no CD in player.\n"); - cdEnabled = false; - cdValid = false; - } - else - { - cdEnabled = true; - cdValid = true; - } - - COM_AddCommand ("cd", Command_Cd_f); -} - - - -// loop/go to next track when track is finished (if cd_update var is true) -// update the volume when it has changed (from console/menu) -void I_UpdateCD (void) -{ - /// \todo check for cd change and restart music ? -} - - -// -void I_PlayCD (UINT8 nTrack, UINT8 bLooping) -{ - MCI_PLAY_PARMS mciPlay; - MCIERROR iErr; - - if (!cdaudio_started || !cdEnabled) - return; - - //faB: try again if it didn't work (just free the user of typing 'cd reset' command) - if (!cdValid) - cdValid = CD_ReadTrackInfo(); - if (!cdValid) - return; - - // tracks start at 0 in the code.. - nTrack--; - if (nTrack < 0 || nTrack >= m_nTracksCount) - nTrack = nTrack % m_nTracksCount; - - nTrack = cdRemap[nTrack]; - - if (cdPlaying) - { - if (cdPlayTrack == nTrack) - return; - I_StopCD (); - } - - cdPlayTrack = nTrack; - - if (!m_nTracks[nTrack].IsAudio) - { - //CONS_Printf ("\2CD Play: not an audio track\n"); // Tails 03-25-2001 - return; - } - - cdLooping = bLooping; - - //faB: stop MIDI music, MIDI music will restart if volume is upped later - cv_digmusicvolume.value = 0; - cv_midimusicvolume.value = 0; - I_StopSong (0); - - //faB: I don't use the notify message, I'm trying to minimize the delay - mciPlay.dwCallback = (DWORD_PTR)((size_t)hWndMain); - mciPlay.dwFrom = MCI_MAKE_TMSF(nTrack+1, 0, 0, 0); - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_PLAY, MCI_FROM|MCI_NOTIFY, (DWORD_PTR)&mciPlay); - if (iErr) - { - MCIErrorMessageBox (iErr); - cdValid = false; - cdPlaying = false; - return; - } - - cdPlaying = true; -} - - -// pause cd music -void I_StopCD (void) -{ - MCIERROR iErr; - - if (!cdaudio_started || !cdEnabled) - return; - - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_PAUSE, MCI_WAIT, 0); - if (iErr) - MCIErrorMessageBox (iErr); - else - { - wasPlaying = cdPlaying; - cdPlaying = false; - } -} - - -// continue after a pause -void I_ResumeCD (void) -{ - MCIERROR iErr; - - if (!cdaudio_started || !cdEnabled) - return; - - if (!cdValid) - return; - - if (!wasPlaying) - return; - - iErr = mciSendCommand(m_MCIOpen.wDeviceID, MCI_RESUME, MCI_WAIT, 0); - if (iErr) - MCIErrorMessageBox (iErr); - else - cdPlaying = true; -} - - -// volume : logical cd audio volume 0-31 (hardware is 0-255) -int I_SetVolumeCD (int volume) -{ - (void)volume; - return 1; -} diff --git a/src/win32ce/win_dbg.c b/src/win32ce/win_dbg.c deleted file mode 100644 index 9cfe77636..000000000 --- a/src/win32ce/win_dbg.c +++ /dev/null @@ -1,629 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief Sources from GameDeveloper magazine article, January 1998, by Bruce Dawson. -/// this source file contains the exception handler for recording error -/// information after crashes. - -#include <tchar.h> -#include "win_main.h" -#include "../doomdef.h" //just for VERSION -#include "win_dbg.h" -#include "../m_argv.h" //print the parameter in the log - - -#define NumCodeBytes 16 // Number of code bytes to record. -#define MaxStackDump 2048 // Maximum number of DWORDS in stack dumps. -#define StackColumns 8 // Number of columns in stack dump. - -#define ONEK 1024 -#define SIXTYFOURK (64*ONEK) -#define ONEM (ONEK*ONEK) -#define ONEG (ONEK*ONEK*ONEK) - - -// -------------------------------------------------------------------------- -// return a description for an ExceptionCode -// -------------------------------------------------------------------------- -static LPCSTR GetExceptionDescription (DWORD ExceptionCode) -{ - unsigned int i; - - struct ExceptionNames - { - DWORD ExceptionCode; - LPCSTR ExceptionName; - }; - - struct ExceptionNames ExceptionMap[] = - { - {EXCEPTION_ACCESS_VIOLATION, "an Access Violation"}, - {EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "a Array Bounds Exceeded"}, - {EXCEPTION_BREAKPOINT, "a Breakpoint"}, - {EXCEPTION_DATATYPE_MISALIGNMENT, "a Datatype Misalignment"}, - {EXCEPTION_FLT_DENORMAL_OPERAND, "a Float Denormal Operand"}, - {EXCEPTION_FLT_DIVIDE_BY_ZERO, "a Float Divide By Zero"}, - {EXCEPTION_FLT_INEXACT_RESULT, "a Float Inexact Result"}, - {EXCEPTION_FLT_INVALID_OPERATION, "a Float Invalid Operation"}, - {EXCEPTION_FLT_OVERFLOW, "a Float Overflow"}, - {EXCEPTION_FLT_STACK_CHECK, "a Float Stack Check"}, - {EXCEPTION_FLT_UNDERFLOW, "a Float Underflow"}, - {EXCEPTION_ILLEGAL_INSTRUCTION, "an Illegal Instruction"}, - {EXCEPTION_IN_PAGE_ERROR, "an In Page Error"}, - {EXCEPTION_INT_DIVIDE_BY_ZERO, "an Integer Divide By Zero"}, - {EXCEPTION_INT_OVERFLOW, "an Integer Overflow"}, - {EXCEPTION_INVALID_DISPOSITION, "an Invalid Disposition"}, - {EXCEPTION_NONCONTINUABLE_EXCEPTION, "Noncontinuable Exception"}, - {EXCEPTION_PRIV_INSTRUCTION, "a Privileged Instruction"}, - {EXCEPTION_SINGLE_STEP, "a Single Step"}, - {EXCEPTION_STACK_OVERFLOW, "a Stack Overflow"}, - {0x40010005, "a Control-C"}, - {0x40010008, "a Control-Break"}, - {0xc0000006, "an In Page Error"}, - {0xc0000017, "a No Memory"}, - {0xc000001d, "an Illegal Instruction"}, - {0xc0000025, "a Noncontinuable Exception"}, - {0xc0000142, "a DLL Initialization Failed"}, - {0xe06d7363, "a Microsoft C++ Exception"}, - }; - - for (i = 0; i < (sizeof (ExceptionMap) / sizeof (ExceptionMap[0])); i++) - if (ExceptionCode == ExceptionMap[i].ExceptionCode) - return ExceptionMap[i].ExceptionName; - - return "Unknown exception type"; -} - - -// -------------------------------------------------------------------------- -// Directly output a formatted string to the errorlog file, using win32 funcs -// -------------------------------------------------------------------------- -static VOID FPrintf (HANDLE fileHandle, LPCSTR lpFmt, ...) -{ - CHAR str[1999]; - va_list arglist; - DWORD bytesWritten; - - va_start (arglist, lpFmt); - vsprintf (str, lpFmt, arglist); - va_end (arglist); - - WriteFile (fileHandle, str, (DWORD)strlen(str), &bytesWritten, NULL); -} - -// -------------------------------------------------------------------------- -// Print the specified FILETIME to output in a human readable format, -// without using the C run time. -// -------------------------------------------------------------------------- -static VOID PrintTime (LPSTR output, FILETIME TimeToPrint) -{ - WORD Date, Time; - if (FileTimeToLocalFileTime (&TimeToPrint, &TimeToPrint) && - FileTimeToDosDateTime (&TimeToPrint, &Date, &Time)) - { - // What a silly way to print out the file date/time. - wsprintfA(output, "%d/%d/%d %02d:%02d:%02d", - (Date / 32) & 15, Date & 31, (Date / 512) + 1980, - (Time / 2048), (Time / 32) & 63, (Time & 31) * 2); - } - else - output[0] = 0; -} - - -static LPTSTR GetFilePart(LPTSTR source) -{ - LPTSTR result = _tcsrchr(source, '\\'); - if (result) - result++; - else - result = source; - return result; -} - -// -------------------------------------------------------------------------- -// Print information about a code module (DLL or EXE) such as its size, -// location, time stamp, etc. -// -------------------------------------------------------------------------- -static VOID ShowModuleInfo(HANDLE LogFile, HMODULE ModuleHandle) -{ - CHAR ModName[MAX_PATH]; - IMAGE_DOS_HEADER *DosHeader; - IMAGE_NT_HEADERS *NTHeader; - HANDLE ModuleFile; - CHAR TimeBuffer[100] = ""; - DWORD FileSize = 0; -#ifdef NO_SEH_MINGW - __try1(EXCEPTION_EXECUTE_HANDLER) -#else - __try -#endif - { - if (GetModuleFileNameA(ModuleHandle, ModName, sizeof (ModName)) > 0) - { - // If GetModuleFileName returns greater than zero then this must - // be a valid code module address. Therefore we can try to walk - // our way through its structures to find the link time stamp. - DosHeader = (IMAGE_DOS_HEADER*)ModuleHandle; - if (IMAGE_DOS_SIGNATURE != DosHeader->e_magic) - return; - NTHeader = (IMAGE_NT_HEADERS*)((char *)DosHeader - + DosHeader->e_lfanew); - if (IMAGE_NT_SIGNATURE != NTHeader->Signature) - return; - // Open the code module file so that we can get its file date - // and size. - ModuleFile = CreateFileA(ModName, GENERIC_READ, - FILE_SHARE_READ, 0, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, 0); - if (ModuleFile != INVALID_HANDLE_VALUE) - { - FILETIME LastWriteTime; - FileSize = GetFileSize(ModuleFile, 0); - if (GetFileTime(ModuleFile, 0, 0, &LastWriteTime)) - { - wsprintfA(TimeBuffer, " - file date is "); - PrintTime(TimeBuffer + strlen(TimeBuffer), LastWriteTime); - } - CloseHandle(ModuleFile); - } - FPrintf (LogFile, "%s, loaded at 0x%08x - %d bytes - %08x%s\r\n", - ModName, ModuleHandle, FileSize, - NTHeader->FileHeader.TimeDateStamp, TimeBuffer); - } - } - // Handle any exceptions by continuing from this point. -#ifdef NO_SEH_MINGW - __except1 -#else - __except(EXCEPTION_EXECUTE_HANDLER) -#endif - { - } -} - -// -------------------------------------------------------------------------- -// Scan memory looking for code modules (DLLs or EXEs). VirtualQuery is used -// to find all the blocks of address space that were reserved or committed, -// and ShowModuleInfo will display module information if they are code -// modules. -// -------------------------------------------------------------------------- -static VOID RecordModuleList(HANDLE LogFile) -{ - SYSTEM_INFO SystemInfo; - size_t PageSize; - size_t NumPages; - size_t pageNum = 0; - LPVOID LastAllocationBase = 0; - - FPrintf (LogFile, "\r\n" - "\tModule list: names, addresses, sizes, time stamps " - "and file times:\r\n"); - - // Set NumPages to the number of pages in the 4GByte address space, - // while being careful to avoid overflowing ints. - GetSystemInfo(&SystemInfo); - PageSize = SystemInfo.dwPageSize; - NumPages = 4 * (unsigned int)(ONEG / PageSize); - while (pageNum < NumPages) - { - MEMORY_BASIC_INFORMATION MemInfo; - if (VirtualQuery((LPVOID)(pageNum * PageSize), &MemInfo, - sizeof (MemInfo))) - { - if (MemInfo.RegionSize > 0) - { - // Adjust the page number to skip over this block of memory. - pageNum += MemInfo.RegionSize / PageSize; - if (MemInfo.State == MEM_COMMIT && MemInfo.AllocationBase > - LastAllocationBase) - { - // Look for new blocks of committed memory, and try - // recording their module names - this will fail - // gracefully if they aren't code modules. - LastAllocationBase = MemInfo.AllocationBase; - ShowModuleInfo(LogFile, (HMODULE)LastAllocationBase); - } - } - else - pageNum += SIXTYFOURK / PageSize; - } - else - pageNum += SIXTYFOURK / PageSize; - // If VirtualQuery fails we advance by 64K because that is the - // granularity of address space doled out by VirtualAlloc(). - } -} - - -// -------------------------------------------------------------------------- -// Record information about the user's system, such as processor type, amount -// of memory, etc. -// -------------------------------------------------------------------------- -static VOID RecordSystemInformation(HANDLE fileHandle) -{ - FILETIME CurrentTime; - CHAR TimeBuffer[100]; - CHAR ModuleName[MAX_PATH]; - CHAR UserName[200]; - DWORD UserNameSize; - SYSTEM_INFO SystemInfo; - MEMORYSTATUS MemInfo; - - GetSystemTimeAsFileTime (&CurrentTime); - PrintTime (TimeBuffer, CurrentTime); - FPrintf(fileHandle, "Error occurred at %s.\r\n", TimeBuffer); - - if (GetModuleFileNameA(NULL, ModuleName, sizeof (ModuleName)) <= 0) - strcpy (ModuleName, "Unknown"); - UserNameSize = sizeof (UserName); - if (!GetUserNameA(UserName, &UserNameSize)) - strcpy (UserName, "Unknown"); - FPrintf(fileHandle, "%s, run by %s.\r\n", ModuleName, UserName); - - GetSystemInfo (&SystemInfo); - FPrintf (fileHandle, "%d processor(s), type %d %d.%d.\r\n" - "Program Memory from 0x%p to 0x%p\r\n", - SystemInfo.dwNumberOfProcessors, - SystemInfo.dwProcessorType, - SystemInfo.wProcessorLevel, - SystemInfo.wProcessorRevision, - SystemInfo.lpMinimumApplicationAddress, - SystemInfo.lpMaximumApplicationAddress); - - MemInfo.dwLength = sizeof (MemInfo); - GlobalMemoryStatus(&MemInfo); - // Print out the amount of physical memory, rounded up. - FPrintf(fileHandle, "%d MBytes physical memory.\r\n", (MemInfo.dwTotalPhys + - ONEM - 1) / ONEM); -} - -// -------------------------------------------------------------------------- -// What we do here is trivial : open a file, write out the register information -// from the PEXCEPTION_POINTERS structure, then return EXCEPTION_CONTINUE_SEARCH -// whose magic value tells Win32 to proceed with its normal error handling -// mechanism. This is important : an error dialog will popup if possible and -// the debugger will hopefully coexist peacefully with the structured exception -// handler. -// -------------------------------------------------------------------------- -int __cdecl RecordExceptionInfo (PEXCEPTION_POINTERS data/*, LPCSTR Message, LPSTR lpCmdLine*/) -{ - PEXCEPTION_RECORD Exception; - PCONTEXT Context; - TCHAR ModuleName[MAX_PATH]; - TCHAR FileName[MAX_PATH] = TEXT("Unknown"); - LPTSTR FilePart, lastperiod; - TCHAR CrashModulePathName[MAX_PATH]; - LPCTSTR CrashModuleFileName = TEXT("Unknown"); - MEMORY_BASIC_INFORMATION MemInfo; - static int BeenHere = false; - HANDLE fileHandle; - UINT8 *code; - int codebyte,i; - - if (data) - { - Exception = data->ExceptionRecord; - Context = data->ContextRecord; - } - else - { - return EXCEPTION_CONTINUE_SEARCH; - } - - if (BeenHere) // Going recursive! That must mean this routine crashed! - return EXCEPTION_CONTINUE_SEARCH; - BeenHere = true; - - // Create a filename to record the error information to. - // Store it in the executable directory. - if (GetModuleFileName(NULL, ModuleName, sizeof (ModuleName)) <= 0) - ModuleName[0] = 0; - FilePart = GetFilePart(ModuleName); - - // Extract the file name portion and remove it's file extension. We'll - // use that name shortly. - lstrcpy (FileName, FilePart); - lastperiod = _tcsrchr (FileName, '.'); - if (lastperiod) - lastperiod[0] = 0; - // Replace the executable filename with our error log file name. - lstrcpy (FilePart, TEXT("errorlog.txt")); - fileHandle = CreateFile (ModuleName, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL); - if (fileHandle == INVALID_HANDLE_VALUE) - { - OutputDebugString (TEXT("Error creating exception report")); - return EXCEPTION_CONTINUE_SEARCH; - } - - // Append to the error log. - SetFilePointer (fileHandle, 0, 0, FILE_END); - - // Print out some blank lines to separate this error log from any previous ones. - FPrintf (fileHandle, "Email Sonic Team Junior so we can fix the bugs\r\n"); // Tails - FPrintf (fileHandle, "Make sure you tell us what you were doing to cause the crash, and if possible, record a demo!\r\n"); // Tails - FPrintf (fileHandle, "\r\n\r\n\r\n\r\n"); - FPrintf (fileHandle, "SRB2 %s -ERROR LOG-\r\n\r\n", VERSIONSTRING); - FPrintf (fileHandle, "\r\n"); - // VirtualQuery can be used to get the allocation base associated with a - // code address, which is the same as the ModuleHandle. This can be used - // to get the filename of the module that the crash happened in. - if (VirtualQuery ((LPVOID)(size_t)Context->Eip, &MemInfo, sizeof (MemInfo)) && - GetModuleFileName ((HMODULE)MemInfo.AllocationBase, - CrashModulePathName, - sizeof (CrashModulePathName)) > 0) - CrashModuleFileName = GetFilePart(CrashModulePathName); - - // Print out the beginning of the error log in a Win95 error window - // compatible format. - FPrintf (fileHandle, "%s caused an %s in module %s at %04x:%08x.\r\n", - FileName, GetExceptionDescription(Exception->ExceptionCode), - CrashModuleFileName, Context->SegCs, Context->Eip); - //if (&Message = Null) - FPrintf (fileHandle, "Exception handler called in %s.\r\n", "main thread"); - //else - //FPrintf (fileHandle, "Exception handler called in %s.\r\n", Message); - - RecordSystemInformation (fileHandle); - - // If the exception was an access violation, print out some additional - // information, to the error log and the debugger. - if (Exception->ExceptionCode == STATUS_ACCESS_VIOLATION && - Exception->NumberParameters >= 2) - { - TCHAR DebugMessage[1000]; - LPCTSTR readwrite = TEXT("Read from"); - if (Exception->ExceptionInformation[0]) - readwrite = TEXT("Write to"); - wsprintf(DebugMessage, TEXT("%s location %08x caused an access violation.\r\n"), - readwrite, Exception->ExceptionInformation[1]); -#ifdef _DEBUG - // The VisualC++ debugger doesn't actually tell you whether a read - // or a write caused the access violation, nor does it tell what - // address was being read or written. So I fixed that. - OutputDebugString(TEXT("Exception handler: ")); - OutputDebugString(DebugMessage); -#endif - FPrintf(fileHandle, "%s", DebugMessage); - } - - FPrintf(fileHandle, "\r\n"); - - // Print out the register values in a Win95 error window compatible format. - if ((Context->ContextFlags & CONTEXT_FULL) == CONTEXT_FULL) - { - FPrintf (fileHandle, "Registers:\r\n"); - FPrintf (fileHandle, "EAX=%.8lx CS=%.4x EIP=%.8lx EFLGS=%.8lx\r\n", - Context->Eax,Context->SegCs,Context->Eip,Context->EFlags); - FPrintf (fileHandle, "EBX=%.8lx SS=%.4x ESP=%.8lx EBP=%.8lx\r\n", - Context->Ebx,Context->SegSs,Context->Esp,Context->Ebp); - FPrintf (fileHandle, "ECX=%.8lx DS=%.4x ESI=%.8lx FS=%.4x\r\n", - Context->Ecx,Context->SegDs,Context->Esi,Context->SegFs); - FPrintf (fileHandle, "EDX=%.8lx ES=%.4x EDI=%.8lx GS=%.4x\r\n", - Context->Edx,Context->SegEs,Context->Edi,Context->SegGs); - } - - // moved down because it was causing the printout to stop - FPrintf (fileHandle, "Command Line parameters: "); - for (i = 1;i < myargc;i++) - FPrintf (fileHandle, "%s ", myargv[i]); - - FPrintf (fileHandle, "Bytes at CS : EIP:\r\n"); - - // Print out the bytes of code at the instruction pointer. Since the - // crash may have been caused by an instruction pointer that was bad, - // this code needs to be wrapped in an exception handler, in case there - // is no memory to read. If the dereferencing of code[] fails, the - // exception handler will print '??'. - code = (UINT8 *)(size_t)Context->Eip; - for (codebyte = 0; codebyte < NumCodeBytes; codebyte++) - { -#ifdef NO_SEH_MINGW - __try1(EXCEPTION_EXECUTE_HANDLER) -#else - __try -#endif - { - FPrintf (fileHandle, "%02x ", code[codebyte]); - } -#ifdef NO_SEH_MINGW - __except1 -#else - __except(EXCEPTION_EXECUTE_HANDLER) -#endif - { - FPrintf (fileHandle, "?? "); - } - } - - // Time to print part or all of the stack to the error log. This allows - // us to figure out the call stack, parameters, local variables, etc. - FPrintf (fileHandle, "\r\n" - "Stack dump:\r\n"); -#ifdef NO_SEH_MINGW - __try1(EXCEPTION_EXECUTE_HANDLER) -#else - __try -#endif - { - // Esp contains the bottom of the stack, or at least the bottom of - // the currently used area. - DWORD* pStack = (DWORD *)(size_t)Context->Esp; - DWORD* pStackTop = NULL; - size_t Count = 0; - TCHAR buffer[1000] = TEXT(""); - const int safetyzone = 50; - LPTSTR nearend = buffer + sizeof (buffer) - safetyzone*sizeof (TCHAR); - LPTSTR output = buffer; - const void *Suffix; - - // Load the top (highest address) of the stack from the - // thread information block. It will be found there in - // Win9x and Windows NT. -#ifdef __GNUC__ - __asm__("movl %%fs : 4, %%eax": "=a"(pStackTop)); -#else - __asm - { - mov eax, fs:[4] - mov pStackTop, eax - } -#endif - if (pStackTop == NULL) - goto StackSkip; - else if (pStackTop > pStack + MaxStackDump) - pStackTop = pStack + MaxStackDump; - // Too many calls to WriteFile can take a long time, causing - // confusing delays when programs crash. Therefore I implemented - // simple buffering for the stack dumping code instead of calling - // FPrintf directly. - while (pStack + 1 <= pStackTop) - { - if ((Count % StackColumns) == 0) - output += wsprintf(output, TEXT("%08x: "), pStack); - if ((++Count % StackColumns) == 0 || pStack + 2 > pStackTop) - Suffix = TEXT("\r\n"); - else - Suffix = TEXT(" "); - output += wsprintf(output, TEXT("%08x%s"), *pStack, Suffix); - pStack++; - // Check for when the buffer is almost full, and flush it to disk. - if (output > nearend) - { - FPrintf (fileHandle, "%s", buffer); - buffer[0] = 0; - output = buffer; - } - } - // Print out any final characters from the cache. - StackSkip: - FPrintf (fileHandle, "%s", buffer); - } -#ifdef NO_SEH_MINGW - __except1 -#else - __except(EXCEPTION_EXECUTE_HANDLER) -#endif - { - FPrintf(fileHandle, "Exception encountered during stack dump.\r\n"); - } - - RecordModuleList (fileHandle); - - CloseHandle (fileHandle); - - // Return the magic value which tells Win32 that this handler didn't - // actually handle the exception - so that things will proceed as per - // normal. - //BP: should put message for end user to send this file to fix any bug - return EXCEPTION_CONTINUE_SEARCH; -} - - /* - // - //FPrintf ("e-mail this file to legacy@newdoom.com, so that we can fix the problem.\r\n\r\n"); - - FPrintf ("Exception handler called in %s.\r\n", Message); - - GetSystemTime (&systemTime); - FPrintf ("Error occured at %02d/%02d/%04d %02d:%02d:%02d.\r\n", - systemTime.wMonth, systemTime.wDay, systemTime.wYear, - systemTime.wHour, systemTime.wMinute, systemTime.wSecond); - - - FPrintf ("%s\r\n", filename); - FPrintf ("Cmd-line: %s\r\n", lpCmdLine); - - // Nested exceptions can occur, get info for each one - - nER = 1; - while (ER) - { - if (nER++>1) - FPrintf ("Exception Record %d.\r\n", nER); - - FPrintf ("application caused an %s", GetExceptionCodeStr(Exception->ExceptionCode)); - - if (Context->ContextFlags & CONTEXT_CONTROL) - FPrintf (" at %.4x:%.8x.\r\n", Context->SegCs, Context->Eip); - - // in case of.. - if (Context->Eip != (unsigned long)Exception->ExceptionAddress) - FPrintf ("Exception Address = %.8x\r\n", Exception->ExceptionAddress); - - if (Exception->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) - { - FPrintf ("\r\n%s location 0x%x caused an access violation.\r\n", - (Exception->ExceptionInformation[0] ? "Write to" : "Read from"), - Exception->ExceptionInformation[1]); - } - - ER = Exception->ExceptionRecord; - } - - - if (Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) - { - FPrintf ("\r\nDebug Registers:\r\n"); - FPrintf ("Dr0=%.8x Dr1=%.8x Dr2=%.8x\r\n" - "Dr3=%.8x Dr6=%.8x Dr7=%.8x\r\n", - Context->Dr0, Context->Dr1, Context->Dr2, - Context->Dr3, Context->Dr6, Context->Dr7); - } - - if (Context->ContextFlags & CONTEXT_FLOATING_POINT) - { - FPrintf ("\r\nFloating Save Area:\r\n"); - FPrintf ("ControlWord =%.8x TagWord =%.8x ErrorSelector=%.8x DataSelector =%.8x\r\n" - "StatusWord =%.8x ErrorOffset =%.8x DataOffset =%.8x Cr0NpxState =%.8x\r\n", - Context->FloatSave.ControlWord, Context->FloatSave.TagWord, Context->FloatSave.ErrorSelector, Context->FloatSave.DataSelector, - Context->FloatSave.StatusWord, Context->FloatSave.ErrorOffset, Context->FloatSave.DataOffset, Context->FloatSave.Cr0NpxState - ); - - //BYTE RegisterArea[SIZE_OF_80387_REGISTERS]; - } - - - // in case of... - if ((Context->ContextFlags & CONTEXT_FULL) != CONTEXT_FULL) - { - if (!(Context->ContextFlags & CONTEXT_SEGMENTS)) - FPrintf ("Note! GS,FS,ES,DS are unspecified\r\n"); - if (!(Context->ContextFlags & CONTEXT_INTEGER)) - FPrintf ("Note! EDI,ESI,EBX,EDX,ECX,EAX are unspecified\r\n"); - if (!(Context->ContextFlags & CONTEXT_CONTROL)) - FPrintf ("Note! EBP,CS : EIP,EFlags,SS : ESP are unspecified\r\n"); - } - - FPrintf ("\r\nBytes at CS : EIP:\r\n"); - ucptr = (UINT8 *)Context->Eip; - for (i = 0; i < 16; i++) - FPrintf ("%.2x ", *ucptr++); - - FPrintf ("\r\n\r\nStack dump:\r\n"); - ulptr = (unsigned long*)Context->Esp; - for (i = 0; i < 16; i++) - FPrintf ("%.8x ", *ulptr++); - - //FPrintf ("Bytes at CS : EIP:\r\n"); - //FPrintf ("%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x "); - - for (i = 0; i < 16; i++) - { - FPrintf ("%x - } -*/ diff --git a/src/win32ce/win_dbg.h b/src/win32ce/win_dbg.h deleted file mode 100644 index acee896e6..000000000 --- a/src/win32ce/win_dbg.h +++ /dev/null @@ -1,54 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief exception handler - -//#define WIN32_LEAN_AND_MEAN -#define RPC_NO_WINDOWS_H -#include <windows.h> - -// called in the exception filter of the __try block, writes all useful debugging information -// to a file, using only win32 functions in case the C runtime is in a bad state. -int __cdecl RecordExceptionInfo (PEXCEPTION_POINTERS data/*, LPCSTR Message, LPSTR lpCmdLine*/); - -#ifdef __MINGW32__ - -#include <excpt.h> - -#ifndef TRYLEVEL_NONE - -#define NO_SEH_MINGW //Alam:? -FUNCINLINE static ATTRINLINE struct _EXCEPTION_POINTERS *GetExceptionInformation(VOID) -{ - LPVOID SEHINFO = NULL; - //__asm__("movl -20(%%ebp), %%eax": "=a"(SEHINFO)); - return SEHINFO; -} - -//Alam_GBC: use __try1(seh) -#ifndef __try -#define __try -#endif //__try - -//#undef NO_SEH_MINGW //Alam: win_dbg's code not working with MINGW -//Alam_GBC: use __except1 -#ifndef __except -#define __except(x) if (0) -#endif //__except - -#endif // !__TRYLEVEL_NONE - -#endif // __MINGW32__ diff --git a/src/win32ce/win_dll.c b/src/win32ce/win_dll.c deleted file mode 100644 index 8b88f84dd..000000000 --- a/src/win32ce/win_dll.c +++ /dev/null @@ -1,164 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief load and initialise the 3D driver DLL - -#include "../doomdef.h" -#ifdef HWRENDER -#include "../hardware/hw_drv.h" // get the standard 3D Driver DLL exports prototypes -#endif - -#ifdef HW3SOUND -#include "../hardware/hw3dsdrv.h" // get the 3D sound driver DLL export prototypes -#endif - -#include "win_dll.h" -#include "win_main.h" // I_GetLastErrorMsgBox() - -#if defined(HWRENDER) || defined(HW3SOUND) -typedef struct loadfunc_s { - LPCSTR fnName; - LPVOID fnPointer; -} loadfunc_t; - -// -------------------------------------------------------------------------- -// Load a DLL, returns the HMODULE handle or NULL -// -------------------------------------------------------------------------- -static inline HMODULE LoadDLL (LPCSTR dllName, loadfunc_t *funcTable) -{ - LPVOID funcPtr; - loadfunc_t *loadfunc; - HMODULE hModule; - - if ((hModule = LoadLibraryA(dllName)) != NULL) - { - // get function pointers for all functions we use - for (loadfunc = funcTable; loadfunc->fnName != NULL; loadfunc++) - { - funcPtr = GetProcAddress(hModule, loadfunc->fnName); - if (!funcPtr) { - //I_GetLastErrorMsgBox (); - MessageBoxA(NULL, va("The '%s' haven't the good specification (function %s missing)\n\n" - "You must use dll from the same zip of this exe\n", dllName, loadfunc->fnName), - "Error", MB_OK|MB_ICONINFORMATION); - return FALSE; - } - // store function address - *((LPVOID*)loadfunc->fnPointer) = funcPtr; - } - } - else - { - MessageBoxA(NULL, va("LoadLibrary() FAILED : couldn't load '%s'\r\n", dllName), "Warning", MB_OK|MB_ICONINFORMATION); - //I_GetLastErrorMsgBox (); - } - - return hModule; -} - - -// -------------------------------------------------------------------------- -// Unload the DLL -// -------------------------------------------------------------------------- -static inline VOID UnloadDLL (HMODULE* pModule) -{ - if (FreeLibrary(*pModule)) - *pModule = NULL; - else - I_GetLastErrorMsgBox (); -} -#endif - -// ========================================================================== -// STANDARD 3D DRIVER DLL FOR DOOM LEGACY -// ========================================================================== - -// note : the 3D driver loading should be put somewhere else.. - -#ifdef HWRENDER -static HMODULE hwdModule = NULL; - -static loadfunc_t hwdFuncTable[] = { - {"_Init@4", &hwdriver.pfnInit}, - {"_Shutdown@0", &hwdriver.pfnShutdown}, - {"_GetModeList@8", &hwdriver.pfnGetModeList}, - {"_SetPalette@8", &hwdriver.pfnSetPalette}, - {"_FinishUpdate@4", &hwdriver.pfnFinishUpdate}, - {"_Draw2DLine@12", &hwdriver.pfnDraw2DLine}, - {"_DrawPolygon@16", &hwdriver.pfnDrawPolygon}, - {"_SetBlend@4", &hwdriver.pfnSetBlend}, - {"_ClearBuffer@12", &hwdriver.pfnClearBuffer}, - {"_SetTexture@4", &hwdriver.pfnSetTexture}, - {"_ReadRect@24", &hwdriver.pfnReadRect}, - {"_GClipRect@20", &hwdriver.pfnGClipRect}, - {"_ClearMipMapCache@0",&hwdriver.pfnClearMipMapCache}, - {"_SetSpecialState@8", &hwdriver.pfnSetSpecialState}, - {"_DrawMD2@16", &hwdriver.pfnDrawMD2}, - {"_SetTransform@4", &hwdriver.pfnSetTransform}, - {"_GetTextureUsed@0", &hwdriver.pfnGetTextureUsed}, - {"_GetRenderVersion@0",&hwdriver.pfnGetRenderVersion}, - {NULL,NULL} -}; - -BOOL Init3DDriver (LPCSTR dllName) -{ - hwdModule = LoadDLL(dllName, hwdFuncTable); - return (hwdModule != NULL); -} - -VOID Shutdown3DDriver (VOID) -{ - UnloadDLL(&hwdModule); -} -#endif - -#ifdef HW3SOUND -static HMODULE hwsModule = NULL; - -static loadfunc_t hwsFuncTable[] = { - {"_Startup@8", &hw3ds_driver.pfnStartup}, - {"_Shutdown@0", &hw3ds_driver.pfnShutdown}, - {"_AddSfx@4", &hw3ds_driver.pfnAddSfx}, - {"_AddSource@8", &hw3ds_driver.pfnAddSource}, - {"_StartSource@4", &hw3ds_driver.pfnStartSource}, - {"_StopSource@4", &hw3ds_driver.pfnStopSource}, - {"_GetHW3DSVersion@0", &hw3ds_driver.pfnGetHW3DSVersion}, - {"_BeginFrameUpdate@0", &hw3ds_driver.pfnBeginFrameUpdate}, - {"_EndFrameUpdate@0", &hw3ds_driver.pfnEndFrameUpdate}, - {"_IsPlaying@4", &hw3ds_driver.pfnIsPlaying}, - {"_UpdateListener@8", &hw3ds_driver.pfnUpdateListener}, - {"_UpdateSourceParms@12", &hw3ds_driver.pfnUpdateSourceParms}, - {"_SetCone@8", &hw3ds_driver.pfnSetCone}, - {"_SetGlobalSfxVolume@4", &hw3ds_driver.pfnSetGlobalSfxVolume}, - {"_Update3DSource@8", &hw3ds_driver.pfnUpdate3DSource}, - {"_ReloadSource@8", &hw3ds_driver.pfnReloadSource}, - {"_KillSource@4", &hw3ds_driver.pfnKillSource}, - {"_KillSfx@4", &hw3ds_driver.pfnKillSfx}, - {"_GetHW3DSTitle@8", &hw3ds_driver.pfnGetHW3DSTitle}, - {NULL, NULL} -}; - -BOOL Init3DSDriver(LPCSTR dllName) -{ - hwsModule = LoadDLL(dllName, hwsFuncTable); - return (hwsModule != NULL); -} - -VOID Shutdown3DSDriver (VOID) -{ - UnloadDLL(&hwsModule); -} -#endif diff --git a/src/win32ce/win_dll.h b/src/win32ce/win_dll.h deleted file mode 100644 index b4b259587..000000000 --- a/src/win32ce/win_dll.h +++ /dev/null @@ -1,31 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief load/unload a DLL at run-time - -//#define WIN32_LEAN_AND_MEAN -#define RPC_NO_WINDOWS_H -#include <windows.h> - -#ifdef HWRENDER -BOOL Init3DDriver (LPCSTR dllName); -VOID Shutdown3DDriver (VOID); -#endif - -#ifdef HW3SOUND -BOOL Init3DSDriver(LPCSTR dllName); -VOID Shutdown3DSDriver(VOID); -#endif diff --git a/src/win32ce/win_file.c b/src/win32ce/win_file.c deleted file mode 100644 index f9f621011..000000000 --- a/src/win32ce/win_file.c +++ /dev/null @@ -1,123 +0,0 @@ -#include <stdlib.h> -#include <windows.h> -#include "win_file.h" - - -int FileAccess(LPCTSTR FileName, DWORD mode) -{ - HANDLE hFile; - - hFile = CreateFile( FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); - - if (hFile == INVALID_HANDLE_VALUE) - return -1; - else - { - FileClose(hFile); - return 0; - } -} - -HANDLE FileCreate(LPCTSTR FileName) -{ - HANDLE hFile; - - if (FileAccess( FileName, 0) == 0) - hFile = CreateFile( FileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); - else - hFile = CreateFile( FileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); - - return hFile; -} - -void FileClose(HANDLE hFile) -{ - CloseHandle(hFile); -} - -DWORD FileLength(HANDLE hFile) -{ - return GetFileSize(hFile, NULL); -} - -HANDLE FileOpen(LPCTSTR FileName) -{ - HANDLE hFile; - - hFile = CreateFile( FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); - - return hFile; -} - -HANDLE FileAppend(LPCTSTR FileName) -{ - HANDLE hFile; - - hFile = CreateFile( FileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); - FileSeek(hFile, 0, FILE_END ); - - return hFile; -} - -DWORD FileRead(HANDLE hFile, LPVOID data, DWORD size) -{ - DWORD readin = 0; - - ReadFile(hFile, data, size, &readin, NULL); - - return readin; -} - -DWORD FileSeek(HANDLE hFile, LONG distance, DWORD method) -{ - DWORD position; - - position = SetFilePointer(hFile, distance, NULL, method); - - return position; -} - -DWORD FileWrite(HANDLE hFile, LPCVOID data, DWORD size) -{ - DWORD written = 0; - - WriteFile(hFile, data, size, &written, NULL); - - return written; -} - -//These functions are provided as CRT replacements. (missing from WinCE) - -int access(char* file,int type) -{ - FILE* file_access = 0; - - file_access = fopen(file,"rb"); - - if(file_access) - { - fclose(file_access); - return 0; - } - - return -1; -} - -unsigned int file_len(char* file) -{ - FILE* file_access; - unsigned int len = 0; - - file_access = fopen(file,"rb"); - - if(!file_access) - return 0; - - fseek(file_access,0,SEEK_END); - - len = ftell(file_access); - - fclose(file_access); - - return len; -} diff --git a/src/win32ce/win_file.h b/src/win32ce/win_file.h deleted file mode 100644 index d1dc5e9c7..000000000 --- a/src/win32ce/win_file.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef FILE_H -#define FILE_H - -// New File I/O functions - -int FileAccess(LPCTSTR, DWORD); -HANDLE FileAppend(LPCTSTR FileName); -void FileClose(HANDLE); -HANDLE FileCreate(LPCTSTR); -DWORD FileLength(HANDLE); -HANDLE FileOpen(LPCTSTR); -DWORD FileRead(HANDLE, LPCVOID, DWORD); -DWORD FileSeek(HANDLE hFile, LONG distance, DWORD method); -DWORD FileWrite(HANDLE, LPCVOID, DWORD); - -int access(char* file,int type); -unsigned int file_len(char* file); - -#endif \ No newline at end of file diff --git a/src/win32ce/win_main.c b/src/win32ce/win_main.c deleted file mode 100644 index a8a5c7cf2..000000000 --- a/src/win32ce/win_main.c +++ /dev/null @@ -1,539 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief Win32 WinMain Entry Point -/// -/// Win32 Sonic Robo Blast 2 -/// -/// NOTE: -/// To compile WINDOWS SRB2 version : define a '_WINDOWS' symbol. -/// to do this go to Project/Settings/ menu, click C/C++ tab, in -/// 'Preprocessor definitions:' add '_WINDOWS' - -#include "../doomdef.h" -#include <stdio.h> - -#include "../doomstat.h" // netgame -#include "resource.h" - -#include "../m_argv.h" -#include "../d_main.h" -#include "../i_system.h" - -#include "../keys.h" //hack quick test - -#include "../console.h" - -#include "fabdxlib.h" -#include "win_main.h" -#include "win_dbg.h" -#include "../i_sound.h" // midi pause/unpause -#include "../g_input.h" // KEY_MOUSEWHEELxxx - -// MSWheel support for Win95/NT3.51 -#include <zmouse.h> - -#ifndef WM_XBUTTONDOWN -#define WM_XBUTTONDOWN 523 -#endif -#ifndef WM_XBUTTONUP -#define WM_XBUTTONUP 524 -#endif -#ifndef MK_XBUTTON1 -#define MK_XBUTTON1 32 -#endif -#ifndef MK_XBUTTON2 -#define MK_XBUTTON2 64 -#endif - -typedef BOOL (WINAPI *MyFunc)(VOID); - -HINSTANCE myInstance = NULL; -HWND hWndMain = NULL; -static HCURSOR windowCursor = NULL; // main window cursor - -boolean appActive = false; // app window is active - -#ifdef LOGMESSAGES -// this is were I log debug text, cons_printf, I_error ect for window port debugging -HANDLE logstream; -#endif - -BOOL nodinput = FALSE; - -static LRESULT CALLBACK MainWndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - event_t ev; //Doom input event - int mouse_keys; - - // judgecutor: - // Response MSH Mouse Wheel event - - if (message == MSHWheelMessage) - { - message = WM_MOUSEWHEEL; - if (win9x) - wParam <<= 16; - } - - - switch (message) - { - case WM_CREATE: - nodinput = M_CheckParm("-nodinput"); - break; - - case WM_ACTIVATEAPP: // Handle task switching - appActive = (int)wParam; - // pause music when alt-tab - if (appActive && !paused) - I_ResumeSong(0); - else if (!paused) - I_PauseSong(0); - { - HANDLE ci = GetStdHandle(STD_INPUT_HANDLE); - if (ci != INVALID_HANDLE_VALUE && GetFileType(ci) == FILE_TYPE_CHAR) - appActive = true; - } - InvalidateRect (hWnd, NULL, TRUE); - break; - - //for MIDI music - case WM_MSTREAM_UPDATEVOLUME: - I_SetMidiChannelVolume((DWORD)wParam, dwVolumePercent); - break; - - case WM_PAINT: - if (!appActive && !bAppFullScreen && !netgame) - // app becomes inactive (if windowed) - { - // Paint "Game Paused" in the middle of the screen - PAINTSTRUCT ps; - RECT rect; - HDC hdc = BeginPaint (hWnd, &ps); - GetClientRect (hWnd, &rect); - DrawText (hdc, TEXT("Game Paused"), -1, &rect, - DT_SINGLELINE | DT_CENTER | DT_VCENTER); - EndPaint (hWnd, &ps); - return 0; - } - break; - - //case WM_RBUTTONDOWN: - //case WM_LBUTTONDOWN: - - case WM_MOVE: - if (bAppFullScreen) - { - SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE); - return 0; - } - else - { - windowPosX = (SHORT) LOWORD(lParam); // horizontal position - windowPosY = (SHORT) HIWORD(lParam); // vertical position - break; - } - break; - - // This is where switching windowed/fullscreen is handled. DirectDraw - // objects must be destroyed, recreated, and artwork reloaded. - - case WM_DISPLAYCHANGE: - case WM_SIZE: - break; - - case WM_SETCURSOR: - if (bAppFullScreen) - SetCursor(NULL); - else - SetCursor(windowCursor); - return TRUE; - - case WM_KEYUP: - ev.type = ev_keyup; - goto handleKeyDoom; - break; - - case WM_KEYDOWN: - ev.type = ev_keydown; - - handleKeyDoom: - ev.data1 = 0; - if (wParam == VK_PAUSE) - // intercept PAUSE key - { - ev.data1 = KEY_PAUSE; - } - else if (!keyboard_started) - // post some keys during the game startup - // (allow escaping from network synchronization, or pressing enter after - // an error message in the console) - { - switch (wParam) - { - case VK_ESCAPE: ev.data1 = KEY_ESCAPE; break; - case VK_RETURN: ev.data1 = KEY_ENTER; break; - default: ev.data1 = MapVirtualKey((DWORD)wParam,2); // convert in to char - } - } - - if (ev.data1) - D_PostEvent (&ev); - - return 0; - break; - - // judgecutor: - // Handle mouse events - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_XBUTTONDOWN: - case WM_XBUTTONUP: - case WM_MOUSEMOVE: - if (nodinput) - { - mouse_keys = 0; - if (wParam & MK_LBUTTON) - mouse_keys |= 1; - if (wParam & MK_RBUTTON) - mouse_keys |= 2; - if (wParam & MK_MBUTTON) - mouse_keys |= 4; - if (wParam & MK_XBUTTON1) - mouse_keys |= 8; - if (wParam & MK_XBUTTON2) - mouse_keys |= 16; - I_GetSysMouseEvents(mouse_keys); - } - break; - - - case WM_MOUSEWHEEL: - //CONS_Printf("MW_WHEEL dispatched.\n"); - ev.type = ev_keydown; - if ((INT16)HIWORD(wParam) > 0) - ev.data1 = KEY_MOUSEWHEELUP; - else - ev.data1 = KEY_MOUSEWHEELDOWN; - D_PostEvent(&ev); - break; - - case WM_SETTEXT: - COM_BufAddText((LPCSTR)lParam); - return TRUE; - break; - - case WM_CLOSE: - PostQuitMessage(0); //to quit while in-game - ev.data1 = KEY_ESCAPE; //to exit network synchronization - ev.type = ev_keydown; - D_PostEvent (&ev); - return 0; - case WM_DESTROY: - //faB: main app loop will exit the loop and proceed with I_Quit() - PostQuitMessage(0); - break; - - default: - break; - } - - return DefWindowProc(hWnd, message, wParam, lParam); -} - - -static inline VOID OpenTextConsole(void) -{ - HANDLE ci, co; - const BOOL tco = M_CheckParm("-console") != 0; - dedicated = M_CheckParm("-dedicated") != 0; - if (!(dedicated || tco)) - return; - FreeConsole(); - AllocConsole(); //Let get the real console HANDLE, because Mingw's Bash is bad! - ci = CreateFile(TEXT("CONIN$") , GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - co = CreateFile(TEXT("CONOUT$"), GENERIC_WRITE|GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (ci != (HANDLE)-1) - { - const DWORD CM = ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT; - SetStdHandle(STD_INPUT_HANDLE,ci); - if(GetFileType(ci) == FILE_TYPE_CHAR) - SetConsoleMode(ci,CM); //default mode but no ENABLE_MOUSE_INPUT - } - if(co != (HANDLE)-1) - { - SetStdHandle(STD_OUTPUT_HANDLE,co); - SetStdHandle(STD_ERROR_HANDLE,co); //maybe logstream? - } -} - -// -// Do that Windows initialization stuff... -// -static HWND OpenMainWindow (HINSTANCE hInstance, int nCmdShow, LPSTR wTitle) -{ - HWND hWnd; - WNDCLASS wc; - - // Set up and register window class - nCmdShow = 0; - wc.style = CS_HREDRAW | CS_VREDRAW /*| CS_DBLCLKS*/; - wc.lpfnWndProc = MainWndproc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = hInstance; - wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DLICON1)); - windowCursor = LoadCursor(NULL, IDC_WAIT); //LoadCursor(hInstance, MAKEINTRESOURCE(IDC_DLCURSOR1)); - wc.hCursor = windowCursor; - wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); - wc.lpszMenuName = NULL; - wc.lpszClassName = TEXT("SRB2WC"); - if (!RegisterClass(&wc)) - return (HANDLE)-1; - - // Create a window - // CreateWindowEx - seems to create just the interior, not the borders - - hWnd = CreateWindowExA( -#ifdef _DEBUG - 0, //ExStyle -#else - dedicated ? 0:WS_EX_TOPMOST, //ExStyle -#endif - "SRB2WC", //Classname - wTitle, //Windowname - WS_CAPTION|WS_POPUP|WS_SYSMENU, //dwStyle //WS_VISIBLE|WS_POPUP for bAppFullScreen - 0, - 0, - dedicated ? 0:BASEVIDWIDTH, //GetSystemMetrics(SM_CXSCREEN), - dedicated ? 0:BASEVIDHEIGHT, //GetSystemMetrics(SM_CYSCREEN), - NULL, //hWnd Parent - NULL, //hMenu Menu - hInstance, - NULL); - - return hWnd; -} - - -static inline BOOL tlErrorMessage(const TCHAR *err) -{ - /* make the cursor visible */ - SetCursor(LoadCursor(NULL, IDC_ARROW)); - - // - // warn user if there is one - // - printf("Error %s..\n", err); - fflush(stdout); - - MessageBox(hWndMain, err, TEXT("ERROR"), MB_OK); - return FALSE; -} - - -// ------------------ -// Command line stuff -// ------------------ -#define MAXCMDLINEARGS 64 -static char * myWargv[MAXCMDLINEARGS+1]; -static char myCmdline[512]; - -static VOID GetArgcArgv (LPSTR cmdline) -{ - LPSTR token; - size_t i = 0, len; - char cSep = ' '; - BOOL bCvar = FALSE, prevCvar = FALSE; - - // split arguments of command line into argv - strncpy (myCmdline, cmdline, 511); // in case window's cmdline is in protected memory..for strtok - len = strlen (myCmdline); - - myargc = 0; - while (myargc < MAXCMDLINEARGS) - { - // get token - while (myCmdline[i] == cSep) - i++; - if (i >= len) - break; - token = myCmdline + i; - if (myCmdline[i] == '"') - { - cSep = '"'; - i++; - if (!prevCvar) //cvar leave the "" in - token++; - } - else - cSep = ' '; - - //cvar - if (myCmdline[i] == '+' && cSep == ' ') //a + begins a cvarname, but not after quotes - bCvar = TRUE; - else - bCvar = FALSE; - - while (myCmdline[i] && - myCmdline[i] != cSep) - i++; - - if (myCmdline[i] == '"') - { - cSep = ' '; - if (prevCvar) - i++; // get ending " quote in arg - } - - prevCvar = bCvar; - - if (myCmdline + i > token) - { - myWargv[myargc++] = token; - } - - if (!myCmdline[i] || i >= len) - break; - - myCmdline[i++] = '\0'; - } - myWargv[myargc] = NULL; - - // m_argv.c uses myargv[], we used myWargv because we fill the arguments ourselves - // and myargv is just a pointer, so we set it to point myWargv - myargv = myWargv; -} - - -static inline VOID MakeCodeWritable(VOID) -{ -#ifdef USEASM - // Disable write-protection of code segment - DWORD OldRights; - BYTE *pBaseOfImage = (BYTE *)GetModuleHandle(NULL); - IMAGE_OPTIONAL_HEADER *pHeader = (IMAGE_OPTIONAL_HEADER *) - (pBaseOfImage + ((IMAGE_DOS_HEADER*)pBaseOfImage)->e_lfanew + - sizeof (IMAGE_NT_SIGNATURE) + sizeof (IMAGE_FILE_HEADER)); - if (!VirtualProtect(pBaseOfImage+pHeader->BaseOfCode,pHeader->SizeOfCode,PAGE_EXECUTE_READWRITE,&OldRights)) - I_Error("Could not make code writable\n"); -#endif -} - - - - -// ----------------------------------------------------------------------------- -// HandledWinMain : called by exception handler -// ----------------------------------------------------------------------------- -static int WINAPI HandledWinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) -{ - int i; - LPSTR args; - - lpCmdLine = NULL; - hPrevInstance = NULL; -#ifdef LOGMESSAGES - // DEBUG!!! - set logstream to NULL to disable debug log - logstream = INVALID_HANDLE_VALUE; - - logstream = CreateFile (TEXT("log.txt"), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); //file flag writethrough? -#endif - - // fill myargc,myargv for m_argv.c retrieval of cmdline arguments - CONS_Printf("GetArgcArgv() ...\n"); - args = GetCommandLineA(); - CONS_Printf("lpCmdLine is '%s'\n", args); - GetArgcArgv(args); - // Create a text console window - OpenTextConsole(); - - CONS_Printf("Myargc: %d\n", myargc); - for (i = 0; i < myargc; i++) - CONS_Printf("myargv[%d] : '%s'\n", i, myargv[i]); - - // store for later use, will we need it ? - myInstance = hInstance; - - // open a dummy window, both OpenGL and DirectX need one. - if ((hWndMain = OpenMainWindow(hInstance,nCmdShow, - va("SRB2 "VERSIONSTRING))) == (HANDLE)-1) - { - tlErrorMessage(TEXT("Couldn't open window")); - return FALSE; - } - - // currently starts DirectInput - CONS_Printf("I_StartupSystem() ...\n"); - I_StartupSystem(); - MakeCodeWritable(); - - // startup SRB2 - CONS_Printf("D_SRB2Main() ...\n"); - D_SRB2Main(); - CONS_Printf("Entering main app loop...\n"); - // never return - D_SRB2Loop(); - - // back to Windoze - return 0; -} - -// ----------------------------------------------------------------------------- -// Exception handler calls WinMain for catching exceptions -// ----------------------------------------------------------------------------- -int WINAPI WinMain (HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow) -{ - int Result = -1; -#if 1 - HMODULE h = GetModuleHandleA("kernel32.dll"); - MyFunc pfnIsDebuggerPresent = NULL; - if (h) - pfnIsDebuggerPresent = (MyFunc)GetProcAddress(h,"IsDebuggerPresent"); - if (!pfnIsDebuggerPresent || !pfnIsDebuggerPresent()) - LoadLibrary("exchndl.dll"); -#endif -#ifdef NO_SEH_MINGW - __try1(RecordExceptionInfo(GetExceptionInformation()/*, "main thread", lpCmdLine*/)) -#else - __try -#endif - { - Result = HandledWinMain (hInstance, hPrevInstance, lpCmdLine, nCmdShow); - } -#ifdef NO_SEH_MINGW - __except1 -#else - __except (RecordExceptionInfo(GetExceptionInformation()/*, "main thread", lpCmdLine*/)) -#endif - { - SetUnhandledExceptionFilter(EXCEPTION_CONTINUE_SEARCH); //Do nothing here. - } - - return Result; -} diff --git a/src/win32ce/win_main.h b/src/win32ce/win_main.h deleted file mode 100644 index fef25327d..000000000 --- a/src/win32ce/win_main.h +++ /dev/null @@ -1,55 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief Win32 Sharing - -//#define WIN32_LEAN_AND_MEAN -#define RPC_NO_WINDOWS_H -#include <windows.h> -#include <stdio.h> - -extern HINSTANCE myInstance; -extern HWND hWndMain; - -// debugging CONS_Printf to file -#ifdef LOGMESSAGES -extern HANDLE logstream; -#endif -extern int appActive; - -// the MIDI callback is another thread, and Midi volume is delayed here in window proc -VOID I_SetMidiChannelVolume(DWORD dwChannel, DWORD dwVolumePercent); -extern DWORD dwVolumePercent; - -VOID I_GetSysMouseEvents(int mouse_state); -extern unsigned int MSHWheelMessage; - -extern BOOL nodinput; -extern BOOL win9x; - -//faB: midi channel Volume set is delayed by the MIDI stream callback thread, see win_snd.c -#define WM_MSTREAM_UPDATEVOLUME (WM_USER + 101) - -// defined in win_sys.c -VOID I_BeginProfile(VOID); //for timing code -DWORD I_EndProfile(VOID); - -VOID I_GetLastErrorMsgBox(VOID); -VOID I_LoadingScreen (LPCSTR msg); - -void I_RestartSysMouse(void); -void I_DoStartupMouse(void); -BOOL I_SaveMemToFile(const void *pData, size_t iLength, const char *sFileName); diff --git a/src/win32ce/win_net.c b/src/win32ce/win_net.c deleted file mode 100644 index dac1bed53..000000000 --- a/src/win32ce/win_net.c +++ /dev/null @@ -1,39 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief Win32 network interface - -#include "../doomdef.h" -#include "../m_argv.h" -#include "../i_net.h" - -// -// NETWORKING -// - -// -// I_InitNetwork -// -boolean I_InitNetwork (void) -{ - if (M_CheckParm ("-net")) - { - I_Error("The Win32 version of SRB2 doesn't work with external drivers like ipxsetup, sersetup, or doomatic\n" - "Read the documentation about \"-server\" and \"-connect\" parameters or just use the launcher\n"); - } - - return false; -} diff --git a/src/win32ce/win_snd.c b/src/win32ce/win_snd.c deleted file mode 100644 index f9c652178..000000000 --- a/src/win32ce/win_snd.c +++ /dev/null @@ -1,2406 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief interface level code for sound -/// -/// Uses the midiStream* Win32 functions to play MIDI data -/// with low latency and low processor overhead. -#include "../doomdef.h" - -#include "win_main.h" -#include <mmsystem.h> -#define DIRECTSOUND_VERSION 0x0600 /* version 6.0 */ -#define DIRECTINPUT_VERSION 0x0700 -#define DXVERSION_NTCOMPATIBLE 0x0300 -#ifdef _MSC_VER -#pragma warning(disable : 4201) -#endif -#include <dsound.h> - -#include "../command.h" -#include "../i_sound.h" -#include "../s_sound.h" -#include "../i_system.h" -#include "../m_argv.h" -#include "../w_wad.h" -#include "../z_zone.h" -#include "../doomstat.h" - -#include "dx_error.h" - -#include "mid2strm.h" - -#ifdef HW3SOUND -#include "../hardware/hw3dsdrv.h" -#include "../hardware/hw3sound.h" -#include "win_dll.h" -#endif - -#ifndef SURROUND -#define SURROUND // comment out this to disable the SurroundSound code -#endif - -#ifdef SURROUND -ATTRNOINLINE static FUNCNOINLINE void CopyAndInvertMemory(void *dest, void *src, int bytes); //Can't inline ASM that haves lables -#endif - -#define FMODSOUND // comment out this to disable MOD/IT/MP3/OGG music playback - -/////////////////////////////////////////////////////////// -#ifdef FMODSOUND -#ifdef __MINGW32__ -#include <FMOD/fmod.h> -#else -#include <fmod.h> -#endif -#ifdef FSOUND_INIT_DONTLATENCYADJUST //Alam: why didn't I think about this before? :) -#define FSOUND_Stream_OpenFile(name,mode,length) FSOUND_Stream_Open(name,mode,0,length) -#else -#define FSOUND_INIT_DONTLATENCYADJUST 0 -#endif -#ifdef __MINGW32__ -#include <FMOD/fmod_errors.h> -#else -#include <fmod_errors.h> /* optional */ -#endif -//#include <conio.h> -#endif -///////////////////////////////////////////////////////// - -//#define TESTCODE // remove this for release version - -/* briefly described here for convenience: -typedef struct { - WORD wFormatTag; // WAVE_FORMAT_PCM is the only format accepted for DirectSound: - // this tag indicates Pulse Code Modulation (PCM), an uncompressed format - // in which each samples represents the amplitude of the signal at the time - // of sampling. - WORD nChannels; // either one (mono) or two (stereo) - DWORD nSamplesPerSec; // the sampling rate, or frequency, in hertz. - // Typical values are 11,025, 22,050, and 44,100 - DWORD nAvgBytesPerSec; // nAvgBytesPerSec is the product of nBlockAlign and nSamplesPerSec - WORD nBlockAlign; // the number of bytes required for each complete sample, for PCM formats - // is equal to (wBitsPerSample * nChannels / 8). - WORD wBitsPerSample; // gives the size of each sample, generally 8 or 16 bits - WORD cbSize; // cbSize gives the size of any extra fields required to describe a - // specialized wave format. This member is always zero for PCM formats. -} WAVEFORMATEX; -*/ - -// Tails 11-21-2002 -#ifdef FMODSOUND -static FMUSIC_MODULE *mod = NULL; -static int fsoundchannel = -1; -static int fsoundfreq = 0; -static int fmodvol = 127; -static FSOUND_STREAM *fmus = NULL; -#endif - -// -------------------------------------------------------------------------- -// DirectSound stuff -// -------------------------------------------------------------------------- -static LPDIRECTSOUND DSnd = NULL; -static LPDIRECTSOUNDBUFFER DSndPrimary = NULL; ; - -// Stack sounds means sounds put on top of each other, since DirectSound can't play -// the same sound buffer at different locations at the same time, we need to dupli- -// cate existing buffers to play multiple instances of the same sound in the same -// time frame. A duplicate sound is freed when it is no more used. The priority that -// comes from the s_sound engine, is kept so that the lowest priority sounds are -// stopped to make place for the new sound, unless the new sound has a lower priority -// than all playing sounds, in which case the sound is not started. -#define MAXSTACKSOUNDS 32 // this is the absolute number of sounds that - // can play simultaneously, whatever the value - // of cv_numChannels -typedef struct { - LPDIRECTSOUNDBUFFER lpSndBuf; -#ifdef SURROUND - // judgecutor: - // Need for produce surround sound - LPDIRECTSOUNDBUFFER lpSurround; -#endif - int priority; - boolean duplicate; -} StackSound_t; -static StackSound_t StackSounds[MAXSTACKSOUNDS]; - -// -------------------------------------------------------------------------- -// Fill the DirectSoundBuffer with data from a sample, made separate so that -// sound data cna be reloaded if a sound buffer was lost. -// -------------------------------------------------------------------------- -static boolean CopySoundData (LPDIRECTSOUNDBUFFER dsbuffer, LPBYTE data, DWORD length) -{ - LPVOID lpvAudio1; // receives address of lock start - DWORD dwBytes1; // receives number of bytes locked - LPVOID lpvAudio2; // receives address of lock start - DWORD dwBytes2; // receives number of bytes locked - HRESULT hr; - - // Obtain memory address of write block. - hr = IDirectSoundBuffer_Lock (dsbuffer, 0, length, &lpvAudio1, &dwBytes1, &lpvAudio2, &dwBytes2, 0); - - // If DSERR_BUFFERLOST is returned, restore and retry lock. - if (hr == DSERR_BUFFERLOST) - { - hr = IDirectSoundBuffer_Restore (dsbuffer); - if (FAILED (hr)) - I_Error("Restore fail on %x, %s\n",dsbuffer,DXErrorToString(hr)); - hr = IDirectSoundBuffer_Lock (dsbuffer, 0, length, &lpvAudio1, &dwBytes1, &lpvAudio2, &dwBytes2, 0); - if (FAILED (hr)) - I_Error("Lock fail(2) on %x, %s\n",dsbuffer,DXErrorToString(hr)); - } - else - if (FAILED (hr)) - I_Error("Lock fail(1) on %x, %s\n",dsbuffer,DXErrorToString(hr)); - - // copy wave data into the buffer (note: dwBytes1 should equal to dsbdesc->dwBufferBytes ...) - CopyMemory (lpvAudio1, data, dwBytes1); - - if (dwBytes2 && lpvAudio2) - CopyMemory(lpvAudio2, data+dwBytes1, dwBytes2); - - // finally, unlock the buffer - hr = IDirectSoundBuffer_Unlock (dsbuffer, lpvAudio1, dwBytes1, lpvAudio2, dwBytes2); - - if (FAILED (hr)) - I_Error("Unlock fail on %x, %s\n",dsbuffer,DXErrorToString(hr)); - - return true; -} - -#ifdef SURROUND -// judgecutor: -// Hmmm... May be this function is not too good... -static void CopyAndInvertMemory(void *dest, void *src, int bytes) -{ -#ifdef __GNUC__ - __asm__("CAIM:;lodsb;neg %%al;stosb;loop CAIM;"::"c"(bytes),"D"(dest),"S"(src): "memory","cc"); -#else - _asm - { - push esi - push edi - push ecx - mov ecx,bytes - mov esi,src - mov edi,dest -a: - lodsb - neg al - stosb - loop a - pop ecx - pop edi - pop esi - } -#endif -} - -// judgecutor: -// Like normal CopySoundData but sound data will be inverted -static boolean CopyAndInvertSoundData(LPDIRECTSOUNDBUFFER dsbuffer, LPBYTE data, DWORD length) -{ - LPVOID lpvAudio1 = NULL; // receives address of lock start - DWORD dwBytes1 = 0; // receives number of bytes locked - LPVOID lpvAudio2 = NULL; - DWORD dwBytes2 = 0; - HRESULT hr; - - // Obtain memory address of write block. - hr = IDirectSoundBuffer_Lock (dsbuffer, 0, length, &lpvAudio1, &dwBytes1, &lpvAudio2, &dwBytes2, 0); - - // If DSERR_BUFFERLOST is returned, restore and retry lock. - if (hr == DSERR_BUFFERLOST) - { - hr = IDirectSoundBuffer_Restore (dsbuffer); - if (FAILED (hr)) - I_Error("CopyAndInvert: Restore fail on %x, %s\n",dsbuffer,DXErrorToString(hr)); - hr = IDirectSoundBuffer_Lock (dsbuffer, 0, length, &lpvAudio1, &dwBytes1, &lpvAudio2, &dwBytes2, 0); - if (FAILED (hr)) - I_Error("CopyAndInvert: Lock fail(2) on %x, %s\n",dsbuffer,DXErrorToString(hr)); - } else if (FAILED (hr)) - I_Error("CopyAndInvetrt: Lock fail(1) on %x, %s\n",dsbuffer,DXErrorToString(hr)); - - // copy wave data into the buffer (note: dwBytes1 should equal to dsbdesc->dwBufferBytes ...) - CopyAndInvertMemory (lpvAudio1, data, dwBytes1); - - if (dwBytes2 && lpvAudio2) - CopyAndInvertMemory(lpvAudio2, data+dwBytes1, dwBytes2); - - hr = IDirectSoundBuffer_Unlock (dsbuffer, lpvAudio1, dwBytes1, lpvAudio2, dwBytes2); - if (FAILED (hr)) - I_Error("CopyAndInvert: Unlock fail on %x, %s\n",dsbuffer,DXErrorToString(hr)); - - return false; -} -#endif - -static DWORD sound_buffer_flags = DSBCAPS_CTRLPAN | - DSBCAPS_CTRLVOLUME | - DSBCAPS_STICKYFOCUS | - //DSBCAPS_LOCSOFTWARE | - DSBCAPS_STATIC; - -// -------------------------------------------------------------------------- -// raw2DS : convert a raw sound data, returns a LPDIRECTSOUNDBUFFER -// -------------------------------------------------------------------------- -// dsdata points a 4 UINT16 header: -// +0 : value 3 what does it mean? -// +2 : sample rate, either 11025 or 22050. -// +4 : number of samples, each sample is a single byte since it's 8bit -// +6 : value 0 -// -#ifdef SURROUND -// judgecutor: -// We need an another function definition for supporting the surround sound -// Invert just cause to copy an inverted sound data -static LPDIRECTSOUNDBUFFER raw2DS(LPBYTE *dsdata, size_t len, UINT8 invert) -#else -static LPDIRECTSOUNDBUFFER raw2DS(LPBYTE *dsdata, size_t len) -#endif -{ - HRESULT hr; - WAVEFORMATEX wfm; - DSBUFFERDESC dsbdesc; - LPDIRECTSOUNDBUFFER dsbuffer; - - // initialise WAVEFORMATEX structure describing the wave format - ZeroMemory (&wfm, sizeof (WAVEFORMATEX)); - wfm.wFormatTag = WAVE_FORMAT_PCM; - wfm.nChannels = 1; - wfm.nSamplesPerSec = (dsdata[3]<<8)+dsdata[2]; //mostly 11025, but some at 22050. - wfm.wBitsPerSample = 8; - wfm.nBlockAlign = (WORD)(wfm.wBitsPerSample / 8 * wfm.nChannels); - wfm.nAvgBytesPerSec = wfm.nSamplesPerSec * wfm.nBlockAlign; - - // Set up DSBUFFERDESC structure. - ZeroMemory (&dsbdesc, sizeof (DSBUFFERDESC)); - dsbdesc.dwSize = sizeof (DSBUFFERDESC); -/* dsbdesc.dwFlags = DSBCAPS_CTRLPAN | - DSBCAPS_CTRLVOLUME | - DSBCAPS_STICKYFOCUS | - //DSBCAPS_LOCSOFTWARE | - DSBCAPS_STATIC - | DSBCAPS_CTRLFREQUENCY; // This one for pitching -*/ - dsbdesc.dwFlags = sound_buffer_flags; - dsbdesc.dwBufferBytes = len-8; - dsbdesc.lpwfxFormat = &wfm; // pointer to WAVEFORMATEX structure - - // Create the sound buffer - hr = IDirectSound_CreateSoundBuffer (DSnd, &dsbdesc, &dsbuffer, NULL); - - if (hr == DSERR_CONTROLUNAVAIL) - { - CONS_Printf("\tSoundBufferCreate error - a buffer control is not available.\n\tTrying to disable frequency control.\n"); - - sound_buffer_flags &= ~DSBCAPS_CTRLFREQUENCY; - dsbdesc.dwFlags = sound_buffer_flags; - - hr = IDirectSound_CreateSoundBuffer (DSnd, &dsbdesc, &dsbuffer, NULL); - } - - if (FAILED(hr)) - I_Error("CreateSoundBuffer() FAILED: %s\n", DXErrorToString(hr)); - -#ifdef SURROUND - if (invert) - // just invert a sound data for producing the surround sound - CopyAndInvertSoundData(dsbuffer, (LPBYTE)dsdata + 8, dsbdesc.dwBufferBytes); - else - // Do a normal operation -#endif - // fill the DirectSoundBuffer waveform data - CopySoundData (dsbuffer, (LPBYTE)dsdata + 8, dsbdesc.dwBufferBytes); - - return dsbuffer; -} - - -// -------------------------------------------------------------------------- -// This function loads the sound data from the WAD lump, for single sound. -// -------------------------------------------------------------------------- -void *I_GetSfx (sfxinfo_t * sfx) -{ - LPBYTE dssfx; - - if (sfx->lumpnum < 0) - sfx->lumpnum = S_GetSfxLumpNum (sfx); - -#ifdef HW3SOUND - if (hws_mode != HWS_DEFAULT_MODE) - return HW3S_GetSfx(sfx); -#endif - - sfx->length = W_LumpLength (sfx->lumpnum); - - // PU_CACHE because the data is copied to the DIRECTSOUNDBUFFER, the one here will not be used - dssfx = (LPBYTE) W_CacheLumpNum (sfx->lumpnum, PU_CACHE); - -#ifdef SURROUND - // Make a normal (not inverted) sound buffer - return (void *)raw2DS (dssfx, sfx->length, FALSE); -#else - // return the LPDIRECTSOUNDBUFFER, which will be stored in S_sfx[].data - return (void *)raw2DS (dssfx, sfx->length); -#endif -} - - -// -------------------------------------------------------------------------- -// Free all allocated resources for a single sound -// -------------------------------------------------------------------------- -void I_FreeSfx (sfxinfo_t *sfx) -{ - LPDIRECTSOUNDBUFFER dsbuffer; - - if (sfx->lumpnum < 0) - return; - -#ifdef HW3SOUND - if (hws_mode != HWS_DEFAULT_MODE) - { - HW3S_FreeSfx(sfx); - } - else -#endif - { - //CONS_Printf("I_FreeSfx(%d)\n", sfx->lumpnum); - - // free DIRECTSOUNDBUFFER - dsbuffer = (LPDIRECTSOUNDBUFFER) sfx->data; - if (dsbuffer) - { - size_t i; - for (i = 0; i < MAXSTACKSOUNDS; i++) - { - if (StackSounds[i].lpSndBuf == dsbuffer) - { - StackSounds[i].lpSndBuf = NULL; -#ifdef SURROUND - if (StackSounds[i].lpSurround) - { - IDirectSoundBuffer_Stop(StackSounds[i].lpSurround); - IDirectSoundBuffer_Release(StackSounds[i].lpSurround); - } - StackSounds[i].lpSurround = NULL; -#endif - } - } - IDirectSoundBuffer_Stop (dsbuffer); - IDirectSoundBuffer_Release (dsbuffer); - } - } - sfx->data = NULL; - sfx->lumpnum = -1; -} - - -// -------------------------------------------------------------------------- -// Set the global volume for sound effects -// -------------------------------------------------------------------------- -void I_SetSfxVolume(INT32 volume) -{ - int vol; - HRESULT hr; - - if (nosound || !sound_started) - return; - - // use the last quarter of volume range - if (volume) - vol = (volume * ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4)) / 31 + - (DSBVOLUME_MAX - ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4)); - else - vol = DSBVOLUME_MIN; // make sure 0 is silence - //CONS_Printf("setvolume to %d\n", vol); - hr = IDirectSoundBuffer_SetVolume (DSndPrimary, vol); - //if (FAILED(hr)) - // CONS_Printf("setvolumne failed\n"); -} - - -// -------------------------------------------------------------------------- -// Update the volume for a secondary buffer, make sure it was created with -// DSBCAPS_CTRLVOLUME -// -------------------------------------------------------------------------- -static void I_UpdateSoundVolume (LPDIRECTSOUNDBUFFER lpSnd, int volume) -{ - HRESULT hr; - volume = (volume * ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4)) / 256 + - (DSBVOLUME_MAX - ((DSBVOLUME_MAX-DSBVOLUME_MIN)/4)); - hr = IDirectSoundBuffer_SetVolume (lpSnd, volume); - //if (FAILED(hr)) - // CONS_Printf("\2SetVolume FAILED\n"); -} - - -// -------------------------------------------------------------------------- -// Update the panning for a secondary buffer, make sure it was created with -// DSBCAPS_CTRLPAN -// -------------------------------------------------------------------------- -#define DSBPAN_RANGE (DSBPAN_RIGHT-(DSBPAN_LEFT)) -#define SEP_RANGE 256 //Doom sounds pan range 0-255 (128 is centre) -static void I_UpdateSoundPanning (LPDIRECTSOUNDBUFFER lpSnd, int sep) -{ - HRESULT hr; - hr = IDirectSoundBuffer_SetPan (lpSnd, (sep * DSBPAN_RANGE)/SEP_RANGE - DSBPAN_RIGHT); - //if (FAILED(hr)) - // CONS_Printf("SetPan FAILED for sep %d pan %d\n", sep, (sep * DSBPAN_RANGE)/SEP_RANGE - DSBPAN_RIGHT); -} - -// search a free slot in the stack, free it if needed -static int GetFreeStackNum(int newpriority) -{ - int lowestpri = 256,lowestprihandle = 0; - int i; - // DirectSound can't play multiple instances of the same sound buffer - // unless they are duplicated, so if the sound buffer is in use, make a duplicate - for (i = 0; i < MAXSTACKSOUNDS; i++) - { - // find a free 'playing sound slot' to use - if (StackSounds[i].lpSndBuf == NULL) - { - //CONS_Printf("\t\tfound free slot %d\n", i); - return i; - } - else if (!I_SoundIsPlaying(i)) // check for sounds that finished playing, and can be freed - { - //CONS_Printf("\t\tfinished sound in slot %d\n", i); - //stop sound and free the 'slot' - I_StopSound (i); - // we can use this one since it's now freed - return i; - } - else if (StackSounds[i].priority < lowestpri) //remember lowest priority sound - { - lowestpri = StackSounds[i].priority; - lowestprihandle = i; - } - } - - // the maximum of sounds playing at the same time is reached, if we have at least - // one sound playing with a lower priority, stop it and replace it with the new one - - //CONS_Printf("\t\tall slots occupied..\n"); - if (newpriority >= lowestpri) - { - I_StopSound (lowestprihandle); - return lowestprihandle; - //CONS_Printf(" kicking out lowest priority slot: %d pri: %d, my priority: %d\n", - // handle, lowestpri, priority); - } - - return -1; -} - -#ifdef SURROUND -static LPDIRECTSOUNDBUFFER CreateInvertedSound(int id) -{ - lumpnnum_t lumpnum; - LBYPTE dsdata; - - lumpnum = S_sfx[id].lumpnum; - if (lumpnum < 0) - lumpnum = S_GetSfxLumpNum (&S_sfx[id]); - dsdata = W_CacheLumpNum (lumpnum, PU_CACHE); - return raw2DS(dsdata, S_sfx[id].length, TRUE); -} -#endif - -// Calculate internal pitch from Doom pitch -#if 0 -static float recalc_pitch(int doom_pitch) -{ - return doom_pitch < NORMAL_PITCH ? - (float)(doom_pitch + NORMAL_PITCH) / (NORMAL_PITCH * 2) - :(float)doom_pitch / (float)NORMAL_PITCH; -} -#endif - -// -------------------------------------------------------------------------- -// Start the given S_sfx[id] sound with given properties (panning, volume..) -// -------------------------------------------------------------------------- -INT32 I_StartSound (sfxenum_t id, - INT32 vol, - INT32 sep, - INT32 pitch, - INT32 priority) -{ - HRESULT hr; - LPDIRECTSOUNDBUFFER dsbuffer; - DWORD dwStatus; - int handle; - int i; - //DWORD freq; -#ifdef SURROUND - LPDIRECTSOUNDBUFFER dssurround; -#endif - - if (nosound) - return -1; - - //CONS_Printf("I_StartSound:\n\t\tS_sfx[%d]\n", id); - handle = GetFreeStackNum(priority); - if (handle < 0) - return -1; - - //CONS_Printf("\t\tusing handle %d\n", handle); - - // if the original buffer is playing, duplicate it (DirectSound specific) - // else, use the original buffer - dsbuffer = (LPDIRECTSOUNDBUFFER) S_sfx[id].data; - IDirectSoundBuffer_GetStatus (dsbuffer, &dwStatus); - if (dwStatus & (DSBSTATUS_PLAYING | DSBSTATUS_LOOPING)) - { - //CONS_Printf("\t\toriginal sound S_sfx[%d] is playing, duplicating.. ", id); - hr = IDirectSound_DuplicateSoundBuffer(DSnd, (LPDIRECTSOUNDBUFFER) S_sfx[id].data, &dsbuffer); - if (FAILED(hr)) - { - //CONS_Printf("Cound't duplicate sound buffer\n"); - // re-use the original then.. - dsbuffer = (LPDIRECTSOUNDBUFFER) S_sfx[id].data; - // clean up stacksounds info - for (i = 0; i < MAXSTACKSOUNDS; i++) - if (handle != i && - StackSounds[i].lpSndBuf == dsbuffer) - { - StackSounds[i].lpSndBuf = NULL; - } - } - // stop the duplicate or the re-used original - IDirectSoundBuffer_Stop (dsbuffer); - } - - //judgecutor: Sound pitching -#if 0 - if (cv_rndsoundpitch.value) - { - // At first reset the buffer back to original frequency - hr = IDirectSoundBuffer_SetFrequency(dsbuffer, DSBFREQUENCY_ORIGINAL); - if (SUCCEEDED (hr)) - { - - IDirectSoundBuffer_GetFrequency(dsbuffer, &freq); - - // Now pitch it - freq *= recalc_pitch(pitch); - IDirectSoundBuffer_SetFrequency(dsbuffer, freq); - } - else - cv_rndsoundpitch = 0; - } -#else - pitch = 0; -#endif - // store information on the playing sound - StackSounds[handle].lpSndBuf = dsbuffer; - StackSounds[handle].priority = priority; - StackSounds[handle].duplicate = (dsbuffer != (LPDIRECTSOUNDBUFFER)S_sfx[id].data); - - //CONS_Printf("StackSounds[%d].lpSndBuf is %s\n", handle, StackSounds[handle].lpSndBuf == NULL ? "Null":"valid"); - //CONS_Printf("StackSounds[%d].priority is %d\n", handle, StackSounds[handle].priority); - //CONS_Printf("StackSounds[%d].duplicate is %s\n", handle, StackSounds[handle].duplicate ? "TRUE":"FALSE"); - - I_UpdateSoundVolume (dsbuffer, vol); - -#ifdef SURROUND - // Prepare the surround sound buffer - // Use a normal sound data for the left channel (with pan == 0) - // and an inverted sound data for the right channel (with pan == 255) - - dssurround = CreateInvertedSound(id); - - // Surround must be pitched too -#if 0 - if (cv_rndsoundpitch.value) - IDirectSoundBuffer_SetFrequency(dssurround, freq); -#endif - if (sep == -128) - { - I_UpdateSoundPanning(dssurround, 255); - I_UpdateSoundVolume(dssurround, vol); - I_UpdateSoundPanning(dsbuffer, 0); - IDirectSoundBuffer_SetCurrentPosition(dssurround, 0); - } - else - // Perform normal operation -#endif - - I_UpdateSoundPanning (dsbuffer, sep); - - IDirectSoundBuffer_SetCurrentPosition (dsbuffer, 0); - - hr = IDirectSoundBuffer_Play (dsbuffer, 0, 0, 0); - if (hr == DSERR_BUFFERLOST) - { - //CONS_Printf("buffer lost\n"); - // restores the buffer memory and all other settings for the buffer - hr = IDirectSoundBuffer_Restore (dsbuffer); - if (SUCCEEDED (hr)) - { - LPBYTE dsdata; - // reload sample data here - int lumpnum = S_sfx[id].lumpnum; - if (lumpnum < 0) - lumpnum = S_GetSfxLumpNum (&S_sfx[id]); - dsdata = W_CacheLumpNum (lumpnum, PU_CACHE); - - // Well... Data lenght must be -8!!! - CopySoundData (dsbuffer, dsdata + 8, S_sfx[id].length - 8); - - // play - hr = IDirectSoundBuffer_Play (dsbuffer, 0, 0, 0); - } - else - I_Error("I_StartSound : ->Restore FAILED, %s",DXErrorToString(hr)); - } - -#ifdef SURROUND - if (sep == -128) - { - hr = IDirectSoundBuffer_Play (dssurround, 0, 0, 0); - //CONS_Printf("Surround playback\n"); - if (hr == DSERR_BUFFERLOST) - { - // restores the buffer memory and all other settings for the surround buffer - hr = IDirectSoundBuffer_Restore (dssurround); - if (SUCCEEDED (hr)) - { - LPBYTE dsdata; - lumpnumt_t lumpnum = S_sfx[id].lumpnum; - - if (lumpnum < 0) - lumpnum = S_GetSfxLumpNum (&S_sfx[id]); - dsdata = W_CacheLumpNum (lumpnum, PU_CACHE); - CopyAndInvertSoundData (dssurround, (LPBYTE)dsdata + 8, S_sfx[id].length - 8); - - hr = IDirectSoundBuffer_Play (dssurround, 0, 0, 0); - } - else - I_Error("I_StartSound : ->Restore FAILED, %s",DXErrorToString(hr)); - } - } - StackSounds[handle].lpSurround = dssurround; -#endif - - // Returns a handle - return handle; -} - - -// -------------------------------------------------------------------------- -// Stop a sound if it is playing, -// free the corresponding 'playing sound slot' in StackSounds[] -// -------------------------------------------------------------------------- -void I_StopSound (INT32 handle) -{ - LPDIRECTSOUNDBUFFER dsbuffer; - HRESULT hr; - - if (nosound || handle < 0) - return; - - //CONS_Printf("I_StopSound (%d)\n", handle); - - dsbuffer = StackSounds[handle].lpSndBuf; - hr = IDirectSoundBuffer_Stop (dsbuffer); - - // free duplicates of original sound buffer (DirectSound hassles) - if (StackSounds[handle].duplicate) - { - //CONS_Printf("\t\trelease a duplicate..\n"); - IDirectSoundBuffer_Release (dsbuffer); - } - -#ifdef SURROUND - // Stop and release the surround sound buffer - dsbuffer = StackSounds[handle].lpSurround; - if (dsbuffer != NULL) - { - IDirectSoundBuffer_Stop(dsbuffer); - IDirectSoundBuffer_Release(dsbuffer); - } - StackSounds[handle].lpSurround = NULL; -#endif - - StackSounds[handle].lpSndBuf = NULL; -} - - -// -------------------------------------------------------------------------- -// Returns whether the sound is currently playing or not -// -------------------------------------------------------------------------- -INT32 I_SoundIsPlaying(INT32 handle) -{ - LPDIRECTSOUNDBUFFER dsbuffer; - DWORD dwStatus; - - if (nosound || handle == -1) - return FALSE; - - dsbuffer = StackSounds[handle].lpSndBuf; - if (dsbuffer) - { - IDirectSoundBuffer_GetStatus (dsbuffer, &dwStatus); - if (dwStatus & (DSBSTATUS_PLAYING | DSBSTATUS_LOOPING)) - return TRUE; - } - - return FALSE; -} - - -// -------------------------------------------------------------------------- -// Update properties of a sound currently playing -// -------------------------------------------------------------------------- -void I_UpdateSoundParams(INT32 handle, - INT32 vol, - INT32 sep, - INT32 pitch) -{ - LPDIRECTSOUNDBUFFER dsbuffer; -#ifdef SURROUND - LPDIRECTSOUNDBUFFER dssurround; - DWORD dwStatus; - DWORD pos; - boolean surround_inuse = FALSE; -#endif - - if (nosound) - return; - - pitch = 0; /// \todo pitch setup - dsbuffer = StackSounds[handle].lpSndBuf; - -#ifdef SURROUND - if (dsbuffer == NULL) - return; - - dssurround = StackSounds[handle].lpSurround; - if (dssurround) - { - IDirectSoundBuffer_GetStatus(dssurround, &dwStatus); - surround_inuse = (dwStatus & (DSBSTATUS_PLAYING | DSBSTATUS_LOOPING)); - } - // If pan changed to stereo... - if (sep != -128) - { - if (surround_inuse) - { - IDirectSoundBuffer_Stop(dssurround); - surround_inuse = FALSE; - } - } - else if (!surround_inuse) // Just update volumes and start the surround if need - { - I_UpdateSoundVolume(dssurround, vol); - I_UpdateSoundPanning(dsbuffer, 0); - IDirectSoundBuffer_GetCurrentPosition(dsbuffer, &pos, NULL); - IDirectSoundBuffer_SetCurrentPosition(dssurround, pos); - IDirectSoundBuffer_Play(dssurround, 0, 0, 0); - surround_inuse = TRUE; - } - else - I_UpdateSoundVolume(dssurround, vol); - I_UpdateSoundVolume(dsbuffer, vol); - - if (!surround_inuse) - I_UpdateSoundPanning(dsbuffer, sep); -#else - if (dsbuffer) - { - I_UpdateSoundVolume (dsbuffer, vol); - I_UpdateSoundPanning (dsbuffer, sep); - } -#endif -} - - -// -// Shutdown DirectSound -// -void I_ShutdownSound(void) -{ - int i; - - CONS_Printf("I_ShutdownSound()\n"); - -#ifdef HW3SOUND - if (hws_mode != HWS_DEFAULT_MODE) - { - HW3S_Shutdown(); - Shutdown3DSDriver(); - return; - } -#endif - // release any temporary 'duplicated' secondary buffers - for (i = 0; i < MAXSTACKSOUNDS; i++) - if (StackSounds[i].lpSndBuf) - // stops the sound and release it if it is a duplicate - I_StopSound (i); - - if (DSnd) - { - IDirectSound_Release(DSnd); - DSnd = NULL; - } -} - - -// ========================================================================== -// Startup DirectSound -// ========================================================================== -void I_StartupSound(void) -{ - HRESULT hr; - LPDIRECTSOUNDBUFFER lpDsb; - DSBUFFERDESC dsbdesc; - WAVEFORMATEX wfm; - int cooplevel; - int frequency; - -#ifdef HW3SOUND - const char *sdrv_name = NULL; - snddev_t snddev; -#endif - - sound_started = false; - - if (dedicated) - return; - - if (nosound) - return; - - // Secure and configure sound device first. - CONS_Printf("I_StartupSound: "); - - // frequency of primary buffer may be set at cmd-line - if (M_CheckParm ("-freq") && M_IsNextParm()) - { - frequency = atoi(M_GetNextParm()); - CONS_Printf(" requested frequency of %d hz\n", frequency); - CV_SetValue(&cv_samplerate,frequency); - } - else - frequency = cv_samplerate.value; - - // Set cooperative level - // Cooperative sound with other applications can be requested at cmd-line - if (M_CheckParm("-coopsound")) - cooplevel = DSSCL_PRIORITY; - else - cooplevel = DSSCL_EXCLUSIVE; - -#ifdef HW3SOUND - if (M_CheckParm("-ds3d")) - { - hws_mode = HWS_DS3D; - sdrv_name = "s_ds3d.dll"; - } -#if 1 - else if (M_CheckParm("-fmod3d")) - { - hws_mode = HWS_FMOD3D; - sdrv_name = "s_fmod.dll"; - } - else if (M_CheckParm("-sounddriver") && M_IsNextParm()) - { - hws_mode = HWS_OTHER; - sdrv_name = M_GetNextParm(); - } -#else - else if (M_CheckParm("-sounddriver") && M_IsNextParm()) - { - hws_mode = HWS_OTHER; - sdrv_name = M_GetNextParm(); - } - else if (!M_CheckParm("-nosd")) - { - hws_mode = HWS_FMOD3D; - sdrv_name = "s_fmod.dll"; - } -#endif - - // There must be further sound drivers (such as A3D and EAX)!!! - - if (hws_mode != HWS_DEFAULT_MODE && sdrv_name != NULL) - { - if (Init3DSDriver(sdrv_name)) - { - //nosound = true; - snddev.sample_rate = frequency; - snddev.bps = 16; - snddev.numsfxs = NUMSFX; - snddev.cooplevel = cooplevel; - snddev.hWnd = hWndMain; - if (HW3S_Init(I_Error, &snddev)) - { - CONS_Printf("Using external sound driver %s\n", sdrv_name); - I_AddExitFunc(I_ShutdownSound); - return; - } - // Falls back to default sound system - CONS_Printf("Not using external sound driver %s\n", sdrv_name); - HW3S_Shutdown(); - Shutdown3DSDriver(); - } - hws_mode = HWS_DEFAULT_MODE; - } -#endif - - // Create DirectSound, use the default sound device - hr = DirectSoundCreate(NULL, &DSnd, NULL); - if (FAILED(hr)) - { - CONS_Printf(" DirectSoundCreate FAILED\n" - " there is no sound device or the sound device is under\n" - " the control of another application\n"); - nosound = true; - return; - } - - // register exit code, now that we have at least DirectSound to close - I_AddExitFunc(I_ShutdownSound); - hr = IDirectSound_SetCooperativeLevel (DSnd, hWndMain, cooplevel); - if (FAILED(hr)) - { - CONS_Printf(" SetCooperativeLevel FAILED\n"); - nosound = true; - return; - } - - // Set up DSBUFFERDESC structure. - ZeroMemory (&dsbdesc, sizeof (DSBUFFERDESC)); - dsbdesc.dwSize = sizeof (DSBUFFERDESC); - dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER | - DSBCAPS_CTRLVOLUME; - dsbdesc.dwBufferBytes = 0; // Must be 0 for primary buffer - dsbdesc.lpwfxFormat = NULL; // Must be NULL for primary buffer - - // Set up structure for the desired format - ZeroMemory (&wfm, sizeof (WAVEFORMATEX)); - wfm.wFormatTag = WAVE_FORMAT_PCM; - wfm.nChannels = 2; //STEREO SOUND! - wfm.nSamplesPerSec = frequency; - wfm.wBitsPerSample = 16; - wfm.nBlockAlign = (WORD)(wfm.wBitsPerSample / 8 * wfm.nChannels); - wfm.nAvgBytesPerSec = wfm.nSamplesPerSec * wfm.nBlockAlign; - - // Gain access to the primary buffer - hr = IDirectSound_CreateSoundBuffer (DSnd, &dsbdesc, &lpDsb, NULL); - if (FAILED(hr)) - { - CONS_Printf("CreateSoundBuffer FAILED: %s (ErrNo %d)\n", DXErrorToString(hr), hr); - nosound = true; - return; - } - - // Set the primary buffer to the desired format, - // but only if we are allowed to do it - if (cooplevel >= DSSCL_PRIORITY) - { - if (SUCCEEDED (hr)) - { - // Set primary buffer to the desired format. If this fails, - // we'll just ignore and go with the default. - hr = IDirectSoundBuffer_SetFormat (lpDsb, &wfm); - if (FAILED(hr)) - CONS_Printf("I_StartupSound : couldn't set primary buffer format.\n"); - else - CV_SetValue(&cv_samplerate,wfm.nSamplesPerSec); - } - // move any on-board sound memory into a contiguous block - // to make the largest portion of free memory available. - - CONS_Printf(" Compacting onboard sound-memory..."); - hr = IDirectSound_Compact (DSnd); - CONS_Printf(" %s\n", SUCCEEDED(hr) ? "Done\n" : "Failed\n")); - } - - // set the primary buffer to play continuously, for performance - // "... this method will ensure that the primary buffer is playing even when no secondary - // buffers are playing; in that case, silence will be played. This can reduce processing - // overhead when sounds are started and stopped in sequence, because the primary buffer - // will be playing continuously rather than stopping and starting between secondary buffers." - hr = IDirectSoundBuffer_Play (lpDsb, 0, 0, DSBPLAY_LOOPING); - if (FAILED (hr)) - CONS_Printf(" Primary buffer continuous play FAILED\n"); - -#ifdef DEBUGSOUND - { - DSCAPS DSCaps; - DSCaps.dwSize = sizeof (DSCAPS); - hr = IDirectSound_GetCaps (DSnd, &DSCaps); - if (SUCCEEDED (hr)) - { - if (DSCaps.dwFlags & DSCAPS_CERTIFIED) - CONS_Printf("This driver has been certified by Microsoft\n"); - if (DSCaps.dwFlags & DSCAPS_EMULDRIVER) - CONS_Printf("No driver with DirectSound support installed (no hardware mixing)\n"); - if (DSCaps.dwFlags & DSCAPS_PRIMARY16BIT) - CONS_Printf("Supports 16-bit primary buffer\n"); - if (DSCaps.dwFlags & DSCAPS_PRIMARY8BIT) - CONS_Printf("Supports 8-bit primary buffer\n"); - if (DSCaps.dwFlags & DSCAPS_SECONDARY16BIT) - CONS_Printf("Supports 16-bit, hardware-mixed secondary buffers\n"); - if (DSCaps.dwFlags & DSCAPS_SECONDARY8BIT) - CONS_Printf("Supports 8-bit, hardware-mixed secondary buffers\n"); - - CONS_Printf("Maximum number of hardware buffers: %d\n", DSCaps.dwMaxHwMixingStaticBuffers); - CONS_Printf("Size of total hardware memory: %d\n", DSCaps.dwTotalHwMemBytes); - CONS_Printf("Size of free hardware memory= %d\n", DSCaps.dwFreeHwMemBytes); - CONS_Printf("Play Cpu Overhead (%% cpu cycles): %d\n", DSCaps.dwPlayCpuOverheadSwBuffers); - } - else - CONS_Printf(" couldn't get sound device caps.\n"); - } -#endif - - // save pointer to the primary DirectSound buffer for volume changes - DSndPrimary = lpDsb; - - ZeroMemory (StackSounds, sizeof (StackSounds)); - - CONS_Printf("sound initialised.\n"); - sound_started = true; -} - - -// ========================================================================== -// -// MUSIC API using MidiStream -// -// ========================================================================== - -#define SPECIAL_HANDLE_CLEANMIDI -1999 // tell I_StopSong() to do a full (slow) midiOutReset() on exit - -static BOOL bMusicStarted; - -static UINT uMIDIDeviceID, uCallbackStatus; -static HMIDISTRM hStream; -static HANDLE hBufferReturnEvent; // for synch between the callback thread and main program thread - // (we need to synch when we decide to stop/free stream buffers) - -static int nCurrentBuffer = 0, nEmptyBuffers; - -static BOOL bBuffersPrepared = FALSE; -static DWORD dwVolCache[MAX_MIDI_IN_TRACKS]; - DWORD dwVolumePercent; // accessed by win_main.c - - // this is accessed by mid2strm.c conversion code - BOOL bMidiLooped = FALSE; -static BOOL bMidiPlaying = FALSE; -static BOOL bMidiPaused = FALSE; -static CONVERTINFO ciStreamBuffers[NUM_STREAM_BUFFERS]; - -#define STATUS_KILLCALLBACK 100 // Signals that the callback should die -#define STATUS_CALLBACKDEAD 200 // Signals callback is done processing -#define STATUS_WAITINGFOREND 300 // Callback's waiting for buffers to play - -#define DEBUG_CALLBACK_TIMEOUT 2000 // Wait 2 seconds for callback - // faB: don't freeze the main code if we debug.. - -#define VOL_CACHE_INIT 127 // for dwVolCache[] - -static BOOL bMidiCanSetVolume; // midi caps - -static void Mid2StreamFreeBuffers(void); -static void CALLBACK MidiStreamCallback (HMIDIIN hMidi, UINT uMsg, DWORD dwInstance, - DWORD dwParam1, DWORD dwParam2); -static BOOL StreamBufferSetup(LPBYTE pMidiData, size_t iMidiSize); - -// ------------------- -// MidiErrorMessageBox -// Calls the midiOutGetErrorText() function and displays the text which -// corresponds to a midi subsystem error code. -// ------------------- -static void MidiErrorMessageBox(MMRESULT mmr) -{ - char szTemp[256] = ""; - - /*szTemp[0] = '\2'; //white text to stand out*/ - if((MMSYSERR_NOERROR == midiOutGetErrorTextA(mmr, szTemp/*+1*/, sizeof (szTemp))) && *szTemp) - CONS_Printf("%s\n",szTemp); - /*MessageBox (GetActiveWindow(), szTemp+1, "LEGACY", - MB_OK | MB_ICONSTOP);*/ - //wsprintf(szDebug, "Midi subsystem error: %s", szTemp); -} - - -// ---------------- -// I_InitAudioMixer -// ---------------- -#ifdef TESTCODE -void I_InitAudioMixer (void) -{ - UINT cMixerDevs = mixerGetNumDevs(); - CONS_Printf("%d mixer devices available\n", cMixerDevs); -} -#endif - -// ----------- -// I_InitDigMusic -// Startup Digital device for streaming output -// ----------- -void I_InitDigMusic(void) -{ - if (dedicated) - nodigimusic = true; - else - CONS_Printf("I_InitDigMusic()\n"); - -#ifdef FMODSOUND - if (!nodigimusic) - { - // Tails 11-21-2002 - if (FSOUND_GetVersion() < FMOD_VERSION) - { - //I_Error("FMOD Error : You are using the wrong DLL version!\nYou should be using FMOD %s\n", "FMOD_VERSION"); - CONS_Printf("FMOD Error : You are using the wrong DLL version!\nYou should be using FMOD %s\n", "FMOD_VERSION"); - nodigimusic = true; - } - - /* - INITIALIZE - */ -#if 1 - if (!FSOUND_SetHWND(hWndMain)) - { -// I_Error("FMOD(Init,FSOUND_SetHWND): %s\n", FMOD_ErrorString(FSOUND_GetError())); - //FSOUND_SetOutput(FSOUND_OUTPUT_DSOUND); - } - //else -#endif - - if (!FSOUND_Init(44100, 32, FSOUND_INIT_DONTLATENCYADJUST)) - { - //I_Error("FMOD(Init,FSOUND_Init): %s\n", FMOD_ErrorString(FSOUND_GetError())); - CONS_Printf("FMOD(Init,FSOUND_Init): %s\n", FMOD_ErrorString(FSOUND_GetError())); - nodigimusic = true; - } - else - I_AddExitFunc(I_ShutdownDigMusic); - } -#endif -} - -// ----------- -// I_InitMIDIMusic -// Startup Midi device for streaming output -// ----------- -void I_InitMIDIMusic(void) -{ - DWORD idx; - MMRESULT mmrRetVal; - UINT cMidiDevs; - MIDIOUTCAPS MidiOutCaps; - const char *szTechnology; - - bMusicStarted = false; - - if (dedicated) - nomidimusic = true; - else - CONS_Printf("I_InitMIDIMusic()\n"); - - if (nomidimusic) - return; - - // check out number of MIDI devices available - // - cMidiDevs = midiOutGetNumDevs(); - if (!cMidiDevs) - { - CONS_Printf("No MIDI devices available, music is disabled\n"); - nomidimusic = true; - return; - } -#ifdef DEBUGMIDISTREAM - else - { - CONS_Printf("%d MIDI devices available\n", cMidiDevs); - } -#endif - - if (M_CheckParm("-winmidi") && M_IsNextParm()) - uMIDIDeviceID = atoi(M_GetNextParm()); - else - uMIDIDeviceID = MIDI_MAPPER; - - // get MIDI device caps - // - if ((mmrRetVal = midiOutGetDevCaps (uMIDIDeviceID, &MidiOutCaps, sizeof (MIDIOUTCAPS))) != - MMSYSERR_NOERROR) - { - CONS_Printf("midiOutGetCaps FAILED : \n"); - MidiErrorMessageBox (mmrRetVal); - } - else - { - CONS_Printf("MIDI product name: %s\n", MidiOutCaps.szPname); - switch (MidiOutCaps.wTechnology) - { - case MOD_FMSYNTH: szTechnology = "FM Synth"; break; - case MOD_MAPPER: szTechnology = "Microsoft MIDI Mapper"; break; - case MOD_MIDIPORT: szTechnology = "MIDI hardware port"; break; - case MOD_SQSYNTH: szTechnology = "Square wave synthesizer"; break; - case MOD_SYNTH: szTechnology = "Synthesizer"; break; - default: szTechnology = "unknown"; break; - } - CONS_Printf("MIDI technology: %s\n", szTechnology); - CONS_Printf("MIDI caps:\n"); - if (MidiOutCaps.dwSupport & MIDICAPS_CACHE) - CONS_Printf("-Patch caching\n"); - if (MidiOutCaps.dwSupport & MIDICAPS_LRVOLUME) - CONS_Printf("-Separate left and right volume control\n"); - if (MidiOutCaps.dwSupport & MIDICAPS_STREAM) - CONS_Printf("-Direct support for midiStreamOut()\n"); - if (MidiOutCaps.dwSupport & MIDICAPS_VOLUME) - CONS_Printf("-Volume control\n"); - bMidiCanSetVolume = ((MidiOutCaps.dwSupport & MIDICAPS_VOLUME)!=0); - } - -#ifdef TESTCODE - I_InitAudioMixer (); -#endif - - // ---------------------------------------------------------------------- - // Midi2Stream initialization - // ---------------------------------------------------------------------- - - // create event for synch'ing the callback thread to main program thread - // when we will need it - hBufferReturnEvent = CreateEvent(NULL, FALSE, FALSE, - TEXT("SRB2 Midi Playback: Wait For Buffer Return")); - - if (!hBufferReturnEvent) - { - I_GetLastErrorMsgBox(); - nomidimusic = true; - return; - } - - if ((mmrRetVal = midiStreamOpen(&hStream, - &uMIDIDeviceID, - (DWORD)1, (DWORD_PTR)MidiStreamCallback/*NULL*/, - (DWORD)0, - CALLBACK_FUNCTION /*CALLBACK_NULL*/)) != MMSYSERR_NOERROR) - { - CONS_Printf("I_RegisterSong: midiStreamOpen FAILED\n"); - MidiErrorMessageBox(mmrRetVal); - nomidimusic = true; - return; - } - - // stream buffers are initially unallocated (set em NULL) - for (idx = 0; idx < NUM_STREAM_BUFFERS; idx++) - ZeroMemory (&ciStreamBuffers[idx].mhBuffer, sizeof (MIDIHDR)); - // ---------------------------------------------------------------------- - - // register exit code - I_AddExitFunc(I_ShutdownMIDIMusic); - - bMusicStarted = true; -} - -// --------------- -// I_InitMusic -// --------------- -void I_InitMusic(void) -{ - I_InitDigMusic(); - I_InitMIDIMusic(); -} - -// --------------- -// I_ShutdownDigMusic -// --------------- -void I_ShutdownDigMusic(void) -{ - CONS_Printf("I_ShutdownDigMusic: \n"); - -#ifdef FMODSOUND - if (!nodigimusic && FSOUND_GetError() != FMOD_ERR_UNINITIALIZED) - { - if (FSOUND_GetError() != FMOD_ERR_NONE && FSOUND_GetError() != FMOD_ERR_CHANNEL_ALLOC && FSOUND_GetError() != FMOD_ERR_MEDIAPLAYER) - if (devparm) CONS_Printf("FMOD(Shutdown,Unknown): %s\n", FMOD_ErrorString(FSOUND_GetError())); - if (mod) - { - if (FMUSIC_IsPlaying(mod)) - if (!FMUSIC_StopSong(mod)) - if (devparm) CONS_Printf("FMOD(Shutdown,FMUSIC_StopSong): %s\n", FMOD_ErrorString(FSOUND_GetError())); - if (!FMUSIC_FreeSong(mod)) - if (devparm) CONS_Printf("FMOD(Shutdown,FMUSIC_FreeSong): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - if (fmus) - { - if (FSOUND_IsPlaying(fsoundchannel)) - if (!FSOUND_Stream_Stop(fmus)) - if (devparm) CONS_Printf("FMOD(Shutdown,FSOUND_Stream_Stop): %s\n", FMOD_ErrorString(FSOUND_GetError())); - if (!FSOUND_Stream_Close(fmus)) - if (devparm) CONS_Printf("FMOD(Shutdown,FSOUND_Stream_Close): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - FSOUND_Close(); - remove("fmod.tmp"); // Delete the temp file - //if (!FSOUND_StopSound(FSOUND_ALL)) - //if (FSOUND_GetError() != FMOD_ERR_MEDIAPLAYER) CONS_Printf("FMOD(Shutdown,FSOUND_StopSound): %s\n", FMOD_ErrorString(FSOUND_GetError())); - //FMUSIC_StopAllSongs(); - //if (FSOUND_GetError() != FMOD_ERR_NONE && FSOUND_GetError() != FMOD_ERR_MEDIAPLAYER) CONS_Printf("FMOD(Shutdown,FMUSIC_StopAllSongs): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } -#endif -} - -// --------------- -// I_ShutdownMIDIMusic -// --------------- -void I_ShutdownMIDIMusic(void) -{ - DWORD idx; - MMRESULT mmrRetVal; - HGLOBAL lp = NULL; - - CONS_Printf("I_ShutdownMIDIMusic: \n"); - - if (nomidimusic) - return; - - if (!bMusicStarted) - return; - - if (hStream) - { - I_StopSong (SPECIAL_HANDLE_CLEANMIDI); - } - - Mid2StreamConverterCleanup(); - Mid2StreamFreeBuffers(); - - // Free our stream buffers - for (idx = 0; idx < NUM_STREAM_BUFFERS; idx++) - { - if (ciStreamBuffers[idx].mhBuffer.lpData) - { - //GlobalFreePtr(ciStreamBuffers[idx].mhBuffer.lpData); - lp = GlobalPtrHandle(ciStreamBuffers[idx].mhBuffer.lpData); - GlobalUnlock(lp); - GlobalFree(lp); - ciStreamBuffers[idx].mhBuffer.lpData = NULL; - } - } - - if (hStream) - { - if ((mmrRetVal = midiStreamClose(hStream)) != MMSYSERR_NOERROR) - MidiErrorMessageBox(mmrRetVal); - hStream = NULL; - } - - CloseHandle(hBufferReturnEvent); - - bMusicStarted = false; -} - -// --------------- -// I_ShutdownMusic -// --------------- -void I_ShutdownMusic(void) -{ - if (!nodigimusic) - I_ShutdownDigMusic(); - - if (!nomidimusic) - I_ShutdownMIDIMusic(); -} - -// -------------------- -// SetAllChannelVolumes -// Given a percent in tenths of a percent, sets volume on all channels to -// reflect the new value. -// -------------------- -static void SetAllChannelVolumes(DWORD dwVolumePercent) -{ - DWORD dwEvent, dwStatus, dwVol, idx; - MMRESULT mmrRetVal; - - if (!bMidiPlaying) - return; - - for (idx = 0, dwStatus = MIDI_CTRLCHANGE; idx < MAX_MIDI_IN_TRACKS; idx++, dwStatus++) - { - dwVol = (dwVolCache[idx] * dwVolumePercent) / 1000; - //CONS_Printf("channel %d vol %d\n", idx, dwVol); - dwEvent = dwStatus | ((DWORD)MIDICTRL_VOLUME << 8) - | ((DWORD)dwVol << 16); - if ((mmrRetVal = midiOutShortMsg((HMIDIOUT)hStream, dwEvent)) - != MMSYSERR_NOERROR) - { - MidiErrorMessageBox(mmrRetVal); - return; - } - } -} - - -// ---------------- -// I_SetMusicVolume -// Set the midi output volume -// ---------------- -void I_SetMIDIMusicVolume(INT32 volume) -{ - MMRESULT mmrRetVal; - int iVolume; - - if (nomidimusic) - return; - - if (bMidiCanSetVolume) - { - // method A - // current volume is 0-31, we need 0-0xFFFF in each word (left/right channel) - iVolume = (volume << 11) | (volume << 27); - if ((mmrRetVal = midiOutSetVolume ((HMIDIOUT)(size_t)uMIDIDeviceID, iVolume)) != MMSYSERR_NOERROR) - { - CONS_Printf("I_SetMusicVolume: couldn't set volume\n"); - MidiErrorMessageBox(mmrRetVal); - } - } - else - { - // method B - dwVolumePercent = (volume * 1000) / 32; - SetAllChannelVolumes (dwVolumePercent); - } -} - -void I_SetDigMusicVolume(INT32 volume) -{ -#ifdef FMODSOUND - if (volume != -1) - fmodvol = (volume<<3)+(volume>>2); - if (!nodigimusic) - { - if (FSOUND_GetError() != FMOD_ERR_NONE && FSOUND_GetError() != FMOD_ERR_CHANNEL_ALLOC && FSOUND_GetError() != FMOD_ERR_MEDIAPLAYER) - if (devparm) CONS_Printf("FMOD(Volume,Unknown): %s\n", FMOD_ErrorString(FSOUND_GetError())); - if (mod) - { - if (FMUSIC_GetType(mod) != FMUSIC_TYPE_NONE) - { - if (!FMUSIC_SetMasterVolume(mod, fmodvol) && devparm) - CONS_Printf("FMOD(Volume,FMUSIC_SetMasterVolume): %s\n", - FMOD_ErrorString(FSOUND_GetError())); - } - else if (devparm) - CONS_Printf("FMOD(Volume,FMUSIC_GetType): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - if (fmus) - { - if (!FSOUND_SetVolume(fsoundchannel, fmodvol)) - if (devparm) CONS_Printf("FMOD(Volume,FSOUND_SetVolume): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - } -#else - (void)volume; -#endif -} - - -// ---------- -// I_PlaySong -// Note: doesn't use the handle, would be useful to switch between mid's after -// some trigger (would do several RegisterSong, then PlaySong the chosen one) -// ---------- -boolean I_PlaySong(INT32 handle, INT32 bLooping) -{ - MMRESULT mmrRetVal; - - if (nomidimusic) - return false; - -#ifdef DEBUGMIDISTREAM - CONS_Printf("I_PlaySong: looping %d\n", bLooping); -#endif - - // unpause the song first if it was paused - if (bMidiPaused) - I_PauseSong(handle); - - // Clear the status of our callback so it will handle - // MOM_DONE callbacks once more - uCallbackStatus = 0; - bMidiPlaying = FALSE; - if ((mmrRetVal = midiStreamRestart(hStream)) != MMSYSERR_NOERROR) - { - MidiErrorMessageBox(mmrRetVal); - Mid2StreamConverterCleanup(); - Mid2StreamFreeBuffers(); - midiStreamClose(hStream); - //I_Error("I_PlaySong: midiStreamRestart error"); - midiStreamOpen(&hStream, &uMIDIDeviceID, (DWORD)1, - (DWORD_PTR)MidiStreamCallback/*NULL*/, - (DWORD)0, CALLBACK_FUNCTION /*CALLBACK_NULL*/); - } - else bMidiPlaying = TRUE; - bMidiLooped = bLooping; - return bMidiPlaying; -} - - -// ----------- -// I_PauseSong -// calls midiStreamPause() to pause the midi playback -// ----------- -void I_PauseSong (INT32 handle) -{ - (void)handle; -#ifdef FMODSOUND - if (!nodigimusic) - { - if (FSOUND_GetError() != FMOD_ERR_NONE && FSOUND_GetError() != FMOD_ERR_CHANNEL_ALLOC && FSOUND_GetError() != FMOD_ERR_MEDIAPLAYER) - if (devparm) CONS_Printf("FMOD(Pause,Unknown): %s\n", FMOD_ErrorString(FSOUND_GetError())); - if (mod) - { - if (!FMUSIC_GetPaused(mod)) - if (!FMUSIC_SetPaused(mod, true)) - if (devparm) CONS_Printf("FMOD(Pause,FMUSIC_SetPaused): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - if (fmus) - { - if (!FSOUND_GetPaused(fsoundchannel)) - if (!FSOUND_SetPaused(fsoundchannel, true)) - if (devparm) CONS_Printf("FMOD(Pause,FSOUND_SetPaused): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - } -#endif - - if (nomidimusic) - return; - -#ifdef DEBUGMIDISTREAM - CONS_Printf("I_PauseSong: \n"); -#endif - - if (!bMidiPaused) - { - midiStreamPause(hStream); - bMidiPaused = true; - } -} - - -// ------------ -// I_ResumeSong -// un-pause the midi song with midiStreamRestart -// ------------ -void I_ResumeSong (INT32 handle) -{ - (void)handle; -#ifdef FMODSOUND - if (!nodigimusic) - { - if (FSOUND_GetError() != FMOD_ERR_NONE && FSOUND_GetError() != FMOD_ERR_CHANNEL_ALLOC && FSOUND_GetError() != FMOD_ERR_MEDIAPLAYER) - if (devparm) CONS_Printf("FMOD(Resume,Unknown): %s\n", FMOD_ErrorString(FSOUND_GetError())); - if (mod != NULL) - { - if (FMUSIC_GetPaused(mod)) - if (!FMUSIC_SetPaused(mod, false)) - if (devparm) CONS_Printf("FMOD(Resume,FMUSIC_SetPaused): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - if (fmus != NULL) - { - if (FSOUND_GetPaused(fsoundchannel)) - if (!FSOUND_SetPaused(fsoundchannel, false)) - if (devparm) CONS_Printf("FMOD(Resume,FSOUND_SetPaused): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - } -#endif - - if (nomidimusic) - return; - -#ifdef DEBUGMIDISTREAM - CONS_Printf("I_ResumeSong: \n"); -#endif - - if (bMidiPaused) - { - midiStreamRestart(hStream); - bMidiPaused = false; - } -} - - -// ---------- -// I_StopSong -// ---------- -// faB: -1999 is a special handle here, it means we stop the midi when exiting -// Legacy, this will do a midiOutReset() for a more 'sure' midi off. -void I_StopSong(INT32 handle) -{ - MMRESULT mmrRetVal; - - if (nomidimusic) - return; - -#ifdef DEBUGMIDISTREAM - CONS_Printf("I_StopSong: \n"); -#endif - - if (bMidiPlaying || (uCallbackStatus != STATUS_CALLBACKDEAD)) - { - bMidiPlaying = bMidiPaused = FALSE; - if (uCallbackStatus != STATUS_CALLBACKDEAD && - uCallbackStatus != STATUS_WAITINGFOREND) - uCallbackStatus = STATUS_KILLCALLBACK; - - //CONS_Printf("a: %d\n",I_GetTime()); - if ((mmrRetVal = midiStreamStop(hStream)) != MMSYSERR_NOERROR) - { - MidiErrorMessageBox(mmrRetVal); - return; - } - - //faB: if we don't call midiOutReset() seems we have to stop the buffers - // ourselves (or it doesn't play anymore) - if (!bMidiPaused && (handle != SPECIAL_HANDLE_CLEANMIDI)) - { - midiStreamPause(hStream); - } - //CONS_Printf("b: %d\n",I_GetTime()); - else - //faB: this damn call takes 1 second and a half !!! still do it on exit - // to be sure everything midi is cleaned as much as possible - if (handle == SPECIAL_HANDLE_CLEANMIDI) - { - if ((mmrRetVal = midiOutReset((HMIDIOUT)hStream)) != MMSYSERR_NOERROR) - { - MidiErrorMessageBox(mmrRetVal); - return; - } - } - //CONS_Printf("c: %d\n",I_GetTime()); - - // Wait for the callback thread to release this thread, which it will do by - // calling SetEvent() once all buffers are returned to it - if ((devparm) - && (WaitForSingleObject(hBufferReturnEvent, DEBUG_CALLBACK_TIMEOUT) - == WAIT_TIMEOUT)) - { - // Note, this is a risky move because the callback may be genuinely busy, but - // when we're debugging, it's safer and faster than freezing the application, - // which leaves the MIDI device locked up and forces a system reset... - CONS_Printf("Timed out waiting for MIDI callback\n"); - uCallbackStatus = STATUS_CALLBACKDEAD; - } - //CONS_Printf("d: %d\n",I_GetTime()); - } - - if (uCallbackStatus == STATUS_CALLBACKDEAD) - { - uCallbackStatus = 0; - Mid2StreamConverterCleanup(); - Mid2StreamFreeBuffers(); - //faB: we could close the stream here and re-open later to avoid - // a little quirk in mmsystem (see DirectX6 mstream note) - midiStreamClose(hStream); - midiStreamOpen(&hStream, &uMIDIDeviceID, (DWORD)1, - (DWORD_PTR)MidiStreamCallback/*NULL*/, - (DWORD)0, CALLBACK_FUNCTION /*CALLBACK_NULL*/); - } -} - -void I_StopDigSong(void) -{ -#ifdef FMODSOUND - if (!nodigimusic) - { - if (FSOUND_GetError() != FMOD_ERR_NONE && FSOUND_GetError() != FMOD_ERR_INVALID_PARAM && FSOUND_GetError() != FMOD_ERR_CHANNEL_ALLOC && FSOUND_GetError() != FMOD_ERR_MEDIAPLAYER) - if (devparm) CONS_Printf("FMOD(Stop,Unknown): %s\n", FMOD_ErrorString(FSOUND_GetError())); - if (mod) - { - if (FMUSIC_IsPlaying(mod)) - { - if (!FMUSIC_StopSong(mod)) - if (devparm) CONS_Printf("FMOD(Stop,FMUSIC_StopSong): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - } - if (fmus) - { - if (FSOUND_IsPlaying(fsoundchannel)) - { - if (!FSOUND_Stream_Stop(fmus)) - if (devparm) CONS_Printf("FMOD(Stop,FSOUND_Stream_Stop): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - } - //if (!FSOUND_StopSound(FSOUND_ALL)) - //if (FSOUND_GetError() != FMOD_ERR_MEDIAPLAYER) CONS_Printf("FMOD(Stop,FSOUND_StopSound): %s\n", FMOD_ErrorString(FSOUND_GetError())); - //FMUSIC_StopAllSongs(); - //if (FSOUND_GetError() != FMOD_ERR_NONE && FSOUND_GetError() != FMOD_ERR_MEDIAPLAYER) CONS_Printf("FMOD(Stop,FMUSIC_StopAllSongs): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } -#endif -} - -void I_UnRegisterSong(INT32 handle) -{ - handle = 0; - if (nomidimusic) - return; - - //faB: we might free here whatever is allocated per-music - // (but we don't cause I hate malloc's) - Mid2StreamConverterCleanup(); - -#ifdef DEBUGMIDISTREAM - CONS_Printf("I_UnregisterSong: \n"); -#endif -} - -int I_SetSongSpeed(unsigned int speed) -{ -#ifdef FMODSOUND - if (music_disabled || nodigimusic) - return 0; //there no music or FMOD is not loaded - - if((!fmus || !FSOUND_IsPlaying(fsoundchannel)) && (!mod || !FMUSIC_IsPlaying(mod))) - return 0; //there no FMOD music playing - - if (speed == 0) - return 1; //yes, we can set the speed - - if (fmus) - { - if (FSOUND_IsPlaying(fsoundchannel) - && !FSOUND_SetFrequency(fsoundchannel,(int)(((float)speed*(float)fsoundfreq)/100.0f))) - { - if (devparm) - CONS_Printf("FMOD(ChangeSpeed,FSOUND_SetFrequency): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - else - return 1; - } - else if (mod) - { - if (FMUSIC_IsPlaying(mod) - && !FMUSIC_SetMasterSpeed(mod,(float)speed/100.0f)) - { - if (devparm) - CONS_Printf("FMOD(ChangeSpeed,FMUSIC_SetMasterSpeed): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - else - return 1; - } -#else - (void)speed; -#endif - return 0; -} - -// Special FMOD support Tails 11-21-2002 -boolean I_StartDigSong(const char *musicname, INT32 looping) -{ -#ifdef FMODSOUND - char filename[9]; - void *data; - int lumpnum; - - if (FSOUND_GetError() != FMOD_ERR_NONE && FSOUND_GetError() != FMOD_ERR_CHANNEL_ALLOC && - FSOUND_GetError() != FMOD_ERR_MEDIAPLAYER && FSOUND_GetError() != FMOD_ERR_INVALID_PARAM) - if (devparm) CONS_Printf("FMOD(Start,Unknown): %s\n", FMOD_ErrorString(FSOUND_GetError())); - - if (fmus) - { - if (FSOUND_IsPlaying(fsoundchannel)) - if (!FSOUND_Stream_Stop(fmus)) - if (devparm) CONS_Printf("FMOD(Start,FSOUND_Stream_Stop): %s\n", FMOD_ErrorString(FSOUND_GetError())); - if (!FSOUND_Stream_Close(fmus)) - if (devparm) CONS_Printf("FMOD(Start,FSOUND_Stream_Close): %s\n", FMOD_ErrorString(FSOUND_GetError())); - fsoundchannel = -1; - fmus = NULL; - } - if (mod) - { - if (FMUSIC_IsPlaying(mod)) - if (!FMUSIC_StopSong(mod)) - if (devparm) CONS_Printf("FMOD(Start,FMUSIC_StopSong): %s\n", FMOD_ErrorString(FSOUND_GetError())); - if (!FMUSIC_FreeSong(mod)) - if (devparm) CONS_Printf("FMOD(Start,FMUSIC_FreeSong): %s\n", FMOD_ErrorString(FSOUND_GetError())); - mod = NULL; - } - //if (!FSOUND_StopSound(FSOUND_ALL)) - //if (FSOUND_GetError() != FMOD_ERR_MEDIAPLAYER) CONS_Printf("FMOD(Start,FSOUND_StopSound): %s\n", FMOD_ErrorString(FSOUND_GetError())); - //FMUSIC_StopAllSongs(); - //if (FSOUND_GetError() != FMOD_ERR_NONE && FSOUND_GetError() != FMOD_ERR_MEDIAPLAYER) CONS_Printf("FMOD(Start,FMUSIC_StopAllSongs): %s\n", FMOD_ErrorString(FSOUND_GetError())); - - // Create the filename we need - sprintf(filename, "o_%s", musicname); - - lumpnum = W_CheckNumForName(filename); - - if (lumpnum == -1) - { - // Graue 02-29-2004: don't worry about missing music, there might still be a MIDI - return false; // No music found. Oh well! - } - - data = W_CacheLumpName (filename, PU_CACHE); - - I_SaveMemToFile (data, W_LumpLength(lumpnum), "fmod.tmp"); - - Z_Free(data); - - mod = FMUSIC_LoadSong("fmod.tmp"); - - if (FSOUND_GetError() != FMOD_ERR_NONE) - { - if (FSOUND_GetError() != FMOD_ERR_FILE_FORMAT) - if (devparm) CONS_Printf("FMOD(Start,FMUSIC_LoadSong): %s\n", FMOD_ErrorString(FSOUND_GetError())); - - if (mod) - { - if (FMUSIC_IsPlaying(mod)) - if (!FMUSIC_StopSong(mod)) - if (devparm) CONS_Printf("FMOD(Start,FMUSIC_StopSong): %s\n", FMOD_ErrorString(FSOUND_GetError())); - if (!FMUSIC_FreeSong(mod)) - if (devparm) CONS_Printf("FMOD(Start,FMUSIC_FreeSong): %s\n", FMOD_ErrorString(FSOUND_GetError())); - mod = NULL; - } - } - - if (mod) - { - if (!FMUSIC_SetLooping(mod, (signed char)looping)) - { - if (devparm) CONS_Printf("FMOD(Start,FMUSIC_SetLooping): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } -// else if (FMUSIC_GetType(mod) == FMUSIC_TYPE_MOD || FMUSIC_GetType(mod) == FMUSIC_TYPE_S3M) -// { -// if (!FMUSIC_SetPanSeperation(mod, 0.85f)) /* 15% crossover */ -// CONS_Printf("FMOD(Start,FMUSIC_SetPanSeperation): %s\n", FMOD_ErrorString(FSOUND_GetError())); -// } - else if (!FMUSIC_SetPanSeperation(mod, 0.0f)) - { - if (devparm) CONS_Printf("FMOD(Start,FMUSIC_SetPanSeperation): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - } - else - { - fmus = FSOUND_Stream_OpenFile("fmod.tmp", ((looping) ? (FSOUND_LOOP_NORMAL) : (0)),0); - if (fmus == NULL) - { - if (devparm) CONS_Printf("FMOD(Start,FSOUND_Stream_Open): %s\n", FMOD_ErrorString(FSOUND_GetError())); - return false; - } - } - - // Scan the Ogg Vorbis file for the COMMENT= field for a custom loop point - if (fmus && looping) - { - int scan; - char *dataum; - char looplength[64]; - unsigned int loopstart = 0; - int newcount = 0; - const int freq = 44100; - int lumplength = W_LumpLength(lumpnum); - int length = FSOUND_Stream_GetLengthMs(fmus); - - if (length == 0) - { - if (devparm) CONS_Printf("FMOD(Start,FSOUND_Stream_GetLengthMs): %s\n", FMOD_ErrorString(FSOUND_GetError())); - } - else - { - //freq = FSOUND_GetFrequency(fsoundchannel); - - data = W_CacheLumpName (filename, PU_CACHE); - - dataum = (char *)data; - - for (scan = 0;scan < lumplength; scan++) - { - if (*dataum++ == 'C'){ - if (*dataum++ == 'O'){ - if (*dataum++ == 'M'){ - if (*dataum++ == 'M'){ - if (*dataum++ == 'E'){ - if (*dataum++ == 'N'){ - if (*dataum++ == 'T'){ - if (*dataum++ == '='){ - if (*dataum++ == 'L'){ - if (*dataum++ == 'O'){ - if (*dataum++ == 'O'){ - if (*dataum++ == 'P'){ - if (*dataum++ == 'P'){ - if (*dataum++ == 'O'){ - if (*dataum++ == 'I'){ - if (*dataum++ == 'N'){ - if (*dataum++ == 'T'){ - if (*dataum++ == '=') - { - - while (*dataum != 1 && newcount != 63) - { - looplength[newcount++] = *dataum++; - } - - looplength[newcount] = '\n'; - - loopstart = atoi(looplength); - } - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - else - dataum--;} - } - - Z_Free(data); - } - - if (loopstart > 0) - { - const unsigned int loopend = (unsigned int)((freq/1000.0f)*length-(freq/1000.0f)); - //const unsigned int loopend = (((freq/2)*length)/500)-8; - if (!FSOUND_Stream_SetLoopPoints(fmus, loopstart, loopend) && devparm) - CONS_Printf("FMOD(Start,FSOUND_Stream_SetLoopPoints): %s\n", - FMOD_ErrorString(FSOUND_GetError())); - } - } - - /* - PLAY SONG - */ - if (mod) - { - if (FMUSIC_PlaySong(mod)) - { - fsoundchannel = -1; - I_SetDigMusicVolume(-1); - return true; - } - else - { - if (devparm) - CONS_Printf("FMOD(Start,FMUSIC_PlaySong): %s\n", - FMOD_ErrorString(FSOUND_GetError())); - return false; - } - } - if (fmus) - { - fsoundchannel = FSOUND_Stream_PlayEx(FSOUND_FREE, fmus, NULL, TRUE); - - if (fsoundchannel == -1) - { - if (devparm) - CONS_Printf("FMOD(Start,FSOUND_Stream_PlayEx): %s\n", - FMOD_ErrorString(FSOUND_GetError())); - return false; - } - else if (!FSOUND_SetPaused(fsoundchannel, FALSE)) - { - if (devparm) - CONS_Printf("FMOD(Start,FSOUND_SetPaused): %s\n", - FMOD_ErrorString(FSOUND_GetError())); - return false; - } - - I_SetDigMusicVolume(-1); - fsoundfreq = FSOUND_GetFrequency(fsoundchannel); - return true; - } -#else - (void)musicname; - (void)looping; -#endif - return false; - -///////////////////////////////////////////////////////////////////////////////// -} - -// -------------- -// I_RegisterSong -// Prepare a song for playback -// - setup midi stream buffers, and activate the callback procedure -// which will continually fill the buffers with new data -// -------------- - -INT32 I_RegisterSong(void *data, int len) -{ - char *pMidiFileData = NULL; // MIDI music buffer to be played or NULL - - if (nomidimusic) - return 1; - if (!data || !len) - return 0; - -#ifdef DEBUGMIDISTREAM - CONS_Printf("I_RegisterSong: \n"); -#endif - // check for MID format file - if (!memcmp(data, "MThd", 4)) - pMidiFileData = data; - else - { - CONS_Printf("Music lump is not MID music format\n"); - return 0; - } - -#ifdef DEBUGMIDISTREAM - I_SaveMemToFile(pMidiFileData, len, "debug.mid"); -#endif - - // setup midi stream buffer - if (StreamBufferSetup((LPBYTE)pMidiFileData, len)) - { - Mid2StreamConverterCleanup(); - I_Error("I_RegisterSong: StreamBufferSetup FAILED"); - } - - return 1; -} - -// ----------------- -// StreamBufferSetup -// This function uses the filename stored in the global character array to -// open a MIDI file. Then it goes about converting at least the first part of -// that file into a midiStream buffer for playback. -// ----------------- - -// ----------------- -// StreamBufferSetup -// - returns TRUE if a problem occurs -// ----------------- -static BOOL StreamBufferSetup(LPBYTE pMidiData, size_t iMidiSize) -{ - MMRESULT mmrRetVal; - MIDIPROPTIMEDIV mptd; - BOOL bFoundEnd = FALSE; - int dwConvertFlag, nChkErr, idx; - -#ifdef DEBUGMIDISTREAM - if (hStream == NULL) - I_Error("StreamBufferSetup: hStream is NULL!"); -#endif - - // pause midi stream before manipulating the buffers - midiStreamPause(hStream); - - // allocate the stream buffers (only once) - for (idx = 0; idx < NUM_STREAM_BUFFERS; idx++) - { - ciStreamBuffers[idx].mhBuffer.dwBufferLength = OUT_BUFFER_SIZE; - if (!ciStreamBuffers[idx].mhBuffer.lpData) - { - ciStreamBuffers[idx].mhBuffer.lpData = GlobalAllocPtr(GHND, OUT_BUFFER_SIZE); - if (!ciStreamBuffers[idx].mhBuffer.lpData) - return FALSE; - } - } - - // returns TRUE in case of conversion error - if (Mid2StreamConverterInit(pMidiData, iMidiSize)) - return TRUE; - - // Initialize the volume cache array to some pre-defined value - for (idx = 0; idx < MAX_MIDI_IN_TRACKS; idx++) - dwVolCache[idx] = VOL_CACHE_INIT; - - mptd.cbStruct = sizeof (mptd); - mptd.dwTimeDiv = ifs.dwTimeDivision; - if ((mmrRetVal = midiStreamProperty(hStream, (LPBYTE)&mptd, MIDIPROP_SET|MIDIPROP_TIMEDIV)) - != MMSYSERR_NOERROR) - { - MidiErrorMessageBox(mmrRetVal); - return TRUE; - } - - nEmptyBuffers = 0; - dwConvertFlag = CONVERTF_RESET; - - for (nCurrentBuffer = 0; nCurrentBuffer < NUM_STREAM_BUFFERS; nCurrentBuffer++) - { - // Tell the converter to convert up to one entire buffer's length of output - // data. Also, set a flag so it knows to reset any saved state variables it - // may keep from call to call. - ciStreamBuffers[nCurrentBuffer].dwStartOffset = 0; - ciStreamBuffers[nCurrentBuffer].dwMaxLength = OUT_BUFFER_SIZE; - ciStreamBuffers[nCurrentBuffer].tkStart = 0; - ciStreamBuffers[nCurrentBuffer].bTimesUp = FALSE; - - if ((nChkErr = Mid2StreamConvertToBuffer(dwConvertFlag, &ciStreamBuffers[nCurrentBuffer])) - != CONVERTERR_NOERROR) - { - if (nChkErr == CONVERTERR_DONE) - bFoundEnd = TRUE; - else - { - CONS_Printf("StreamBufferSetup: initial conversion pass failed\n"); - return TRUE; - } - } - ciStreamBuffers[nCurrentBuffer].mhBuffer.dwBytesRecorded - = ciStreamBuffers[nCurrentBuffer].dwBytesRecorded; - - if (!bBuffersPrepared) - { - if ((mmrRetVal = midiOutPrepareHeader((HMIDIOUT)hStream, - &ciStreamBuffers[nCurrentBuffer].mhBuffer, sizeof (MIDIHDR))) != MMSYSERR_NOERROR) - { - MidiErrorMessageBox(mmrRetVal); - return TRUE; - } - } - if ((mmrRetVal = midiStreamOut(hStream, &ciStreamBuffers[nCurrentBuffer].mhBuffer, - sizeof (MIDIHDR))) != MMSYSERR_NOERROR) - { - MidiErrorMessageBox(mmrRetVal); - break; - } - dwConvertFlag = 0; - - if (bFoundEnd) - break; - } - - bBuffersPrepared = TRUE; - nCurrentBuffer = 0; - - // MIDI volume - dwVolumePercent = (cv_midimusicvolume.value * 1000) / 32; - if (hStream) - SetAllChannelVolumes(dwVolumePercent); - - return FALSE; -} - -// ---------------- -// SetChannelVolume -// Call here delayed by MIDI stream callback, to adapt the volume event of the -// midi stream to our own set volume percentage. -// ---------------- -void I_SetMidiChannelVolume(DWORD dwChannel, DWORD dwVolumePercent) -{ - DWORD dwEvent, dwVol; - MMRESULT mmrRetVal; - - if (!bMidiPlaying) - return; - - dwVol = (dwVolCache[dwChannel] * dwVolumePercent) / 1000; - dwEvent = MIDI_CTRLCHANGE|dwChannel|((DWORD)MIDICTRL_VOLUME << 8)|((DWORD)dwVol << 16); - if ((mmrRetVal = midiOutShortMsg((HMIDIOUT)hStream, dwEvent)) != MMSYSERR_NOERROR) - { -#ifdef DEBUGMIDISTREAM - MidiErrorMessageBox(mmrRetVal); -#endif - return; - } -} - -// ------------------ -// MidiStreamCallback -// This is the callback handler which continually refills MIDI data buffers -// as they're returned to us from the audio subsystem. -// ------------------ -static void CALLBACK MidiStreamCallback(HMIDIIN hMidi, UINT uMsg, DWORD dwInstance, - DWORD dwParam1, DWORD dwParam2) -{ - MMRESULT mmrRetVal; - int nChkErr; - MIDIEVENT* pme; - MIDIHDR* pmh; - - hMidi = NULL; - dwParam1 = dwParam2 = dwInstance = 0; - switch (uMsg) - { - case MOM_DONE: - // dwParam1 is LPMIDIHDR - if (uCallbackStatus == STATUS_CALLBACKDEAD) - return; - - nEmptyBuffers++; - - // we reached end of song, but we wait until all the buffers are returned - if (uCallbackStatus == STATUS_WAITINGFOREND) - { - if (nEmptyBuffers < NUM_STREAM_BUFFERS) - return; - else - { - // stop the song when end reached (was not looping) - uCallbackStatus = STATUS_CALLBACKDEAD; - SetEvent(hBufferReturnEvent); - I_StopSong(0); - return; - } - } - - // This flag is set whenever the callback is waiting for all buffers to come back. - if (uCallbackStatus == STATUS_KILLCALLBACK) - { - // Count NUM_STREAM_BUFFERS-1 being returned for the last time - if (nEmptyBuffers < NUM_STREAM_BUFFERS) - return; - // Then send a stop message when we get the last buffer back... - else - { - // Change the status to callback dead - uCallbackStatus = STATUS_CALLBACKDEAD; - SetEvent(hBufferReturnEvent); - return; - } - } - - dwProgressBytes += ciStreamBuffers[nCurrentBuffer].mhBuffer.dwBytesRecorded; - - // ------------------------------------------------- - // Fill an available buffer with audio data again... - // ------------------------------------------------- - - if (bMidiPlaying && nEmptyBuffers) - { - ciStreamBuffers[nCurrentBuffer].dwStartOffset = 0; - ciStreamBuffers[nCurrentBuffer].dwMaxLength = OUT_BUFFER_SIZE; - ciStreamBuffers[nCurrentBuffer].tkStart = 0; - ciStreamBuffers[nCurrentBuffer].dwBytesRecorded = 0; - ciStreamBuffers[nCurrentBuffer].bTimesUp = FALSE; - - if ((nChkErr = Mid2StreamConvertToBuffer(0, &ciStreamBuffers[nCurrentBuffer])) - != CONVERTERR_NOERROR) - { - if (nChkErr == CONVERTERR_DONE) - { - // Don't include this one in the count - uCallbackStatus = STATUS_WAITINGFOREND; - return; - } - else - { - // We're not in the main thread, so we can't call I_Error() now. - // Log the error message out, and post exit message. - CONS_Printf("MidiStreamCallback(): conversion pass failed!\n"); - PostMessage(hWndMain, WM_CLOSE, 0, 0); - return; - } - } - - ciStreamBuffers[nCurrentBuffer].mhBuffer.dwBytesRecorded - = ciStreamBuffers[nCurrentBuffer].dwBytesRecorded; - - if ((mmrRetVal = midiStreamOut(hStream, &ciStreamBuffers[nCurrentBuffer].mhBuffer, - sizeof (MIDIHDR))) != MMSYSERR_NOERROR) - { - MidiErrorMessageBox(mmrRetVal); - Mid2StreamConverterCleanup(); - return; - } - - nCurrentBuffer = (nCurrentBuffer + 1) % NUM_STREAM_BUFFERS; - nEmptyBuffers--; - } - - break; - case MOM_POSITIONCB: - pmh = (MIDIHDR*)(size_t)dwParam1; - pme = (MIDIEVENT*)(pmh->lpData + pmh->dwOffset); - if (MIDIEVENT_TYPE(pme->dwEvent) == MIDI_CTRLCHANGE) - { -#ifdef DEBUGMIDISTREAM - if (MIDIEVENT_DATA1(pme->dwEvent) == MIDICTRL_VOLUME_LSB) - { - CONS_Printf("Got an LSB volume event\n"); - PostMessage(hWndMain, WM_CLOSE, 0, 0); // can't I_Error() here - break; - } -#endif - // this is meant to respond to our own intention, from mid2strm.c - if (MIDIEVENT_DATA1(pme->dwEvent) != MIDICTRL_VOLUME) - break; - - // Mask off the channel number and cache the volume data byte - dwVolCache[MIDIEVENT_CHANNEL(pme->dwEvent)] = MIDIEVENT_VOLUME(pme->dwEvent); - // call SetChannelVolume() later to adjust MIDI volume control message to our - // own current volume level. - PostMessage(hWndMain, WM_MSTREAM_UPDATEVOLUME, - MIDIEVENT_CHANNEL(pme->dwEvent), 0L); - } - break; - default: - break; - } - - return; -} - -// --------------------- -// Mid2StreamFreeBuffers -// This function unprepares and frees all our buffers -- something we must -// do to work around a bug in MMYSYSTEM that prevents a device from playing -// back properly unless it is closed and reopened after each stop. -// --------------------- -static void Mid2StreamFreeBuffers(void) -{ - DWORD idx; - MMRESULT mmrRetVal; - - if (bBuffersPrepared) - { - for (idx = 0; idx < NUM_STREAM_BUFFERS; idx++) - { - if ((mmrRetVal = midiOutUnprepareHeader((HMIDIOUT)hStream, - &ciStreamBuffers[idx].mhBuffer, sizeof (MIDIHDR))) != MMSYSERR_NOERROR) - { - MidiErrorMessageBox(mmrRetVal); - } - } - bBuffersPrepared = FALSE; - } - - // Don't free the stream buffers here, but rather allocate them once at startup, - // and free them at shutdown. -} diff --git a/src/win32ce/win_sys.c b/src/win32ce/win_sys.c deleted file mode 100644 index 3b6a47258..000000000 --- a/src/win32ce/win_sys.c +++ /dev/null @@ -1,3542 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief win32 system i/o -/// -/// Startup & Shutdown routines for music,sound,timer,keyboard,... -/// Signal handler to trap errors and exit cleanly. - -#include "../doomdef.h" -#include <stdlib.h> -#include <signal.h> -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <io.h> -#include <stdarg.h> -#include <direct.h> - -#include <mmsystem.h> - -#include "../m_misc.h" -#include "../i_video.h" -#include "../i_sound.h" -#include "../i_system.h" - -#include "../d_net.h" -#include "../g_game.h" - -#include "../d_main.h" - -#include "../m_argv.h" - -#include "../w_wad.h" -#include "../z_zone.h" -#include "../g_input.h" - -#include "../keys.h" - -#include "../screen.h" - -// Wheel support for Win95/WinNT3.51 -#include <zmouse.h> - -// Taken from Win98/NT4.0 -#ifndef SM_MOUSEWHEELPRESENT -#define SM_MOUSEWHEELPRESENT 75 -#endif - -#ifndef MSH_MOUSEWHEEL -#ifdef UNICODE -#define MSH_MOUSEWHEEL L"MSWHEEL_ROLLMSG" -#else -#define MSH_MOUSEWHEEL "MSWHEEL_ROLLMSG" -#endif -#endif - -#include "win_main.h" -#include "../i_joy.h" - -#define DIRECTINPUT_VERSION 0x700 -// Force dinput.h to generate old DX3 headers. -#define DXVERSION_NTCOMPATIBLE 0x0300 -#include <dinput.h> - -#include "fabdxlib.h" - -#ifdef __DEBUG__ -#undef NDEBUG -#endif - -/// \brief max number of joystick buttons -#define JOYBUTTONS_MAX 32 // rgbButtons[32] -/// \brief max number of joystick button events -#define JOYBUTTONS_MIN min((JOYBUTTONS),(JOYBUTTONS_MAX)) - -/// \brief max number of joysick axies -#define JOYAXISSET_MAX 4 // (lX, lY), (lZ,lRx), (lRy, lRz), rglSlider[2] is very diff -/// \brief max number ofjoystick axis events -#define JOYAXISSET_MIN min((JOYAXISSET),(JOYAXISSET_MAX)) - -/// \brief max number of joystick hats -#define JOYHATS_MAX 4 // rgdwPOV[4]; -/// \brief max number of joystick hat events -#define JOYHATS_MIN min((JOYHATS),(JOYHATS_MAX)) - -/// \brief max number of mouse buttons -#define MOUSEBUTTONS_MAX 8 // 8 bit of BYTE and DIMOFS_BUTTON7 -/// \brief max number of muse button events -#define MOUSEBUTTONS_MIN min((MOUSEBUTTONS),(MOUSEBUTTONS_MAX)) - -// ================== -// DIRECT INPUT STUFF -// ================== -BOOL bDX0300; // if true, we created a DirectInput 0x0300 version -static LPDIRECTINPUT lpDI = NULL; -static LPDIRECTINPUTDEVICE lpDIK = NULL; // Keyboard -static LPDIRECTINPUTDEVICE lpDIM = NULL; // mice -static LPDIRECTINPUTDEVICE lpDIJ = NULL; // joystick 1P -static LPDIRECTINPUTEFFECT lpDIE[NumberofForces]; // joystick 1Es -static LPDIRECTINPUTDEVICE2 lpDIJA = NULL; // joystick 1I -static LPDIRECTINPUTDEVICE lpDIJ2 = NULL; // joystick 2P -static LPDIRECTINPUTEFFECT lpDIE2[NumberofForces]; // joystick 1Es -static LPDIRECTINPUTDEVICE2 lpDIJ2A = NULL;// joystick 2I - -// Do not execute cleanup code more than once. See Shutdown_xxx() routines. -UINT8 graphics_started = 0; -UINT8 keyboard_started = 0; -UINT8 sound_started = 0; -static boolean mouse_enabled = false; -static boolean joystick_detected = false; -static boolean joystick2_detected = false; - -static void I_ShutdownKeyboard(void); -static void I_GetKeyboardEvents(void); -static void I_ShutdownJoystick(void); -static void I_ShutdownJoystick2 (void); - -static boolean entering_con_command = false; - -// -// Why would this be system specific?? hmmmm.... -// -// it is for virtual reality system, next incoming feature :) -static ticcmd_t emptycmd; -ticcmd_t *I_BaseTiccmd(void) -{ - return &emptycmd; -} - -static ticcmd_t emptycmd2; -ticcmd_t *I_BaseTiccmd2(void) -{ - return &emptycmd2; -} - -// Allocates the base zone memory, -// this function returns a valid pointer and size, -// else it should interrupt the program immediately. -// -// now checks if mem could be allocated, this is still -// prehistoric... there's a lot to do here: memory locking, detection -// of win95 etc... -// - -BOOL win9x; - -/** \brief WinNT system platform -*/ -static BOOL winnt; - -static void I_DetectWin9x(void) -{ - OSVERSIONINFO osvi; - - osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); - GetVersionEx(&osvi); - - winnt = (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT); - // 95 or 98 what the hell - win9x = true; -} - -// return free and total memory in the system -UINT32 I_GetFreeMem(UINT32* total) -{ - MEMORYSTATUS info; - - info.dwLength = sizeof (MEMORYSTATUS); - GlobalMemoryStatus(&info); - if (total) - *total = (ULONG)info.dwTotalPhys; - return (ULONG)info.dwAvailPhys; -} - -// --------- -// I_Profile -// Two little functions to profile our code using the high resolution timer -// --------- -static LARGE_INTEGER ProfileCount; -void I_BeginProfile(void) -{ - if (!QueryPerformanceCounter(&ProfileCount)) - I_Error("I_BeginProfile failed"); // can't profile without the high res timer -} - -// we're supposed to use this to measure very small amounts of time, -// that's why we return a DWORD and not a 64bit value -DWORD I_EndProfile(void) -{ - LARGE_INTEGER CurrTime; - DWORD ret; - if (!QueryPerformanceCounter (&CurrTime)) - I_Error("I_EndProfile failed"); - if (CurrTime.QuadPart - ProfileCount.QuadPart > (LONGLONG)0xFFFFFFFFUL) - I_Error("I_EndProfile overflow"); - ret = (DWORD)(CurrTime.QuadPart - ProfileCount.QuadPart); - // we can call I_EndProfile() several time, I_BeginProfile() need be called just once - ProfileCount = CurrTime; - - return ret; -} - -// --------- -// I_GetTime -// Use the High Resolution Timer if available, -// else use the multimedia timer which has 1 millisecond precision on Windowz 95, -// but lower precision on Windows NT -// --------- -static long hacktics = 0; // used locally for keyboard repeat keys -static DWORD starttickcount = 0; // hack for win2k time bug - -tic_t I_GetTime(void) -{ - tic_t newtics = 0; - - if (!starttickcount) // high precision timer - { - LARGE_INTEGER currtime; // use only LowPart if high resolution counter is not available - static LARGE_INTEGER basetime = {{0, 0}}; - - // use this if High Resolution timer is found - static LARGE_INTEGER frequency; - - if (!basetime.LowPart) - { - if (!QueryPerformanceFrequency(&frequency)) - frequency.QuadPart = 0; - else - QueryPerformanceCounter(&basetime); - } - - if (frequency.LowPart && QueryPerformanceCounter(&currtime)) - { - newtics = (int)((currtime.QuadPart - basetime.QuadPart) * TICRATE - / frequency.QuadPart); - } - else - { - currtime.LowPart = timeGetTime(); - if (!basetime.LowPart) - basetime.LowPart = currtime.LowPart; - newtics = ((currtime.LowPart - basetime.LowPart)/(1000/TICRATE)); - } - } - else - newtics = (GetTickCount() - starttickcount)/(1000/TICRATE); - - hacktics = newtics; // a local counter for keyboard repeat key - return newtics; -} - - -void I_Sleep(void) -{ - if (cv_sleep.value != -1) - Sleep(cv_sleep.value); -} - - -// should move to i_video -void I_WaitVBL(INT32 count) -{ - count = 0; -} - -// this is probably to activate the 'loading' disc icon -// it should set a flag, that I_FinishUpdate uses to know -// whether it draws a small 'loading' disc icon on the screen or not -// -// also it should explicitly draw the disc because the screen is -// possibly not refreshed while loading -// -void I_BeginRead(void) {} - -// see above, end the 'loading' disc icon, set the flag false -// -void I_EndRead(void) {} - -// =========================================================================================== -// EVENTS -// =========================================================================================== -static inline BOOL I_ReadyConsole(HANDLE ci) -{ - DWORD gotinput; - if (ci == (HANDLE)-1) return FALSE; - if (WaitForSingleObject(ci,0) != WAIT_OBJECT_0) return FALSE; - if (GetFileType(ci) != FILE_TYPE_CHAR) return FALSE; - return (GetNumberOfConsoleInputEvents(ci, &gotinput) && gotinput); -} - -static inline VOID I_GetConsoleEvents(VOID) -{ - event_t ev = {0,0,0,0}; - HANDLE ci = GetStdHandle(STD_INPUT_HANDLE); - HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE); - CONSOLE_SCREEN_BUFFER_INFO CSBI; - INPUT_RECORD input; - DWORD t; - - while (I_ReadyConsole(ci) && ReadConsoleInput(ci, &input, 1, &t) && t) - { - memset(&ev,0x00,sizeof (ev)); - switch (input.EventType) - { - case KEY_EVENT: - if (input.Event.KeyEvent.bKeyDown) - { - ev.type = ev_console; - entering_con_command = true; - switch (input.Event.KeyEvent.wVirtualKeyCode) - { - case VK_ESCAPE: - case VK_TAB: - ev.data1 = KEY_NULL; - break; - case VK_SHIFT: - ev.data1 = KEY_SHIFT; - break; - case VK_RETURN: - entering_con_command = false; - // Fall through. - default: - ev.data1 = MapVirtualKey(input.Event.KeyEvent.wVirtualKeyCode,2); // convert in to char - } - if (co != (HANDLE)-1 && GetFileType(co) == FILE_TYPE_CHAR) - { - if (ev.data1 && ev.data1 != KEY_SHIFT) - { -#ifdef _UNICODE - WriteConsole(co, &input.Event.KeyEvent.uChar.UnicodeChar, 1, &t, NULL); -#else - WriteConsole(co, &input.Event.KeyEvent.uChar.AsciiChar, 1, &t, NULL); -#endif - } - if (input.Event.KeyEvent.wVirtualKeyCode == VK_BACK - && GetConsoleScreenBufferInfo(co,&CSBI)) - { - WriteConsoleOutputCharacterA(co, " ",1, CSBI.dwCursorPosition, &t); - } - } - } - else - { - ev.type = ev_keyup; - switch (input.Event.KeyEvent.wVirtualKeyCode) - { - case VK_SHIFT: - ev.data1 = KEY_SHIFT; - break; - default: - break; - } - } - if (ev.data1) D_PostEvent(&ev); - break; - case MOUSE_EVENT: - case WINDOW_BUFFER_SIZE_EVENT: - case MENU_EVENT: - case FOCUS_EVENT: - break; - } - } -} - -// ---------- -// I_GetEvent -// Post new events for all sorts of user-input -// ---------- -void I_GetEvent(void) -{ - I_GetConsoleEvents(); - I_GetKeyboardEvents(); - I_GetMouseEvents(); - I_GetJoystickEvents(); - I_GetJoystick2Events(); -} - -// ---------- -// I_OsPolling -// ---------- -void I_OsPolling(void) -{ - MSG msg; - HANDLE ci = GetStdHandle(STD_INPUT_HANDLE); - - // we need to dispatch messages to the window - // so the window procedure can respond to messages and PostEvent() for keys - // during D_SRB2Main startup. - // this one replaces the main loop of windows since I_OsPolling is called in the main loop - do - { - while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) - { - if (GetMessage(&msg, NULL, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - else // winspec : this is quit message - I_Quit(); - } - if (!appActive && !netgame && !I_ReadyConsole(ci)) - WaitMessage(); - } while (!appActive && !netgame && !I_ReadyConsole(ci)); - - // this is called by the network synchronization, - // check keys and allow escaping - I_GetEvent(); - - // reset "emulated keys" - gamekeydown[KEY_MOUSEWHEELUP] = 0; - gamekeydown[KEY_MOUSEWHEELDOWN] = 0; -} - -// =========================================================================================== -// TIMER -// =========================================================================================== - -static void I_ShutdownTimer(void) -{ - timeEndPeriod(1); -} - -// -// Installs the timer interrupt handler with timer speed as TICRATE. -// -#define TIMER_ID 1 -#define TIMER_RATE (1000/TICRATE) -void I_StartupTimer(void) -{ - // for win2k time bug - if (M_CheckParm("-gettickcount")) - { - starttickcount = GetTickCount(); - CONS_Printf("Using GetTickCount()\n"); - } - timeBeginPeriod(1); - I_AddExitFunc(I_ShutdownTimer); -} - -// =========================================================================================== -// EXIT CODE, ERROR HANDLING -// =========================================================================================== - -static int errorcount = 0; // phuck recursive errors -static int shutdowning = false; - -// -// Used to trap various signals, to make sure things get shut down cleanly. -// -#ifdef NDEBUG -static void signal_handler(int num) -{ - //static char msg[] = "oh no! back to reality!\r\n"; - const char *sigmsg; - char sigdef[64]; - - D_QuitNetGame(); // Fix server freezes - I_ShutdownSystem(); - - switch (num) - { - case SIGINT: - sigmsg = "interrupt"; - break; - case SIGILL: - sigmsg = "illegal instruction - invalid function image"; - break; - case SIGFPE: - sigmsg = "floating point exception"; - break; - case SIGSEGV: - sigmsg = "segment violation"; - break; - case SIGTERM: - sigmsg = "software termination signal from kill"; - break; - case SIGBREAK: - sigmsg = "Ctrl-Break sequence"; - break; - case SIGABRT: - sigmsg = "abnormal termination triggered by abort call"; - break; - default: - sprintf(sigdef, "signal number %d", num); - sigmsg = sigdef; - } - -#ifdef LOGMESSAGES - if (logstream != INVALID_HANDLE_VALUE) - { - I_OutputMsg("signal_handler() error: %s\r\n", sigmsg); - CloseHandle(logstream); - logstream = INVALID_HANDLE_VALUE; - } -#endif - - MessageBoxA(hWndMain, va("signal_handler(): %s", sigmsg), "SRB2 error", MB_OK|MB_ICONERROR); - - signal(num, SIG_DFL); // default signal action - raise(num); -} -#endif - -// -// put an error message (with format) on stderr -// -void I_OutputMsg(const char *fmt, ...) -{ - HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD bytesWritten; - va_list argptr; - char txt[8192]; - - va_start(argptr,fmt); - vsprintf(txt, fmt, argptr); - va_end(argptr); - - OutputDebugStringA(txt); - if (co != (HANDLE)-1) - { - if (GetFileType(co) == FILE_TYPE_CHAR) - { - static COORD coordNextWrite = {0,0}; - char *oldLines = NULL; - DWORD oldLength = 0; - CONSOLE_SCREEN_BUFFER_INFO csbi; - - // Save the lines that we're going to obliterate. - GetConsoleScreenBufferInfo(co, &csbi); - oldLength = csbi.dwSize.X * (csbi.dwCursorPosition.Y - coordNextWrite.Y) + csbi.dwCursorPosition.X - coordNextWrite.X; - - if(oldLength > 0) - { - char *blank = malloc(oldLength); - oldLines = malloc(oldLength); - if(!oldLines || !blank) return; - - ReadConsoleOutputCharacterA(co, oldLines, oldLength, coordNextWrite, &bytesWritten); - - // Move to where we what to print - which is where we would've been, - // had console input not been in the way, - SetConsoleCursorPosition(co, coordNextWrite); - - // Blank out. - memset(blank, ' ', oldLength); - WriteConsoleA(co, blank, oldLength, &bytesWritten, NULL); - free(blank); - - // And back to where we want to print again. - SetConsoleCursorPosition(co, coordNextWrite); - } - - // Actually write the string now! - WriteConsoleA(co, txt, (DWORD)strlen(txt), &bytesWritten, NULL); - - // Next time, output where we left off. - GetConsoleScreenBufferInfo(co, &csbi); - coordNextWrite = csbi.dwCursorPosition; - - // Restore what was overwritten. - if(oldLines && entering_con_command) - { - WriteConsoleA(co, oldLines, oldLength, &bytesWritten, NULL); - free(oldLines); - } - } - else // Redirected to a file. - WriteFile(co, txt, (DWORD)strlen(txt), &bytesWritten, NULL); - } - -#ifdef LOGMESSAGES - if (logstream != (HANDLE)-1) - WriteFile (logstream, txt, (DWORD)strlen(txt), &bytesWritten, NULL); -#endif -} - -// display error messy after shutdowngfx -// -void I_Error(const char *error, ...) -{ - va_list argptr; - char txt[8192]; - - // added 11-2-98 recursive error detecting - if (shutdowning) - { - errorcount++; - // try to shutdown each subsystem separately - if (errorcount == 5) - I_ShutdownGraphics(); - if (errorcount == 6) - I_ShutdownSystem(); - if (errorcount == 7) - { - M_SaveConfig(NULL); - G_SaveGameData(); - } - if (errorcount > 20) - { - // Don't print garbage - va_start(argptr,error); - vsprintf(txt, error, argptr); - va_end(argptr); - - MessageBoxA(hWndMain, txt, "SRB2 Recursive Error", MB_OK|MB_ICONERROR); - exit(-1); // recursive errors detected - } - } - shutdowning = true; - - // put message to stderr - va_start(argptr, error); - wvsprintfA(txt, error, argptr); - va_end(argptr); - - CONS_Printf("I_Error(): %s\n", txt); - - // uncomment this line to print to stderr as well - //wsprintf(stderr, "I_Error(): %s\n", txt); - - // saving one time is enough! - if (!errorcount) - { - M_SaveConfig(NULL); // save game config, cvars.. - G_SaveGameData(); - } - - // save demo, could be useful for debug - // NOTE: demos are normally not saved here. - if (demorecording) - G_CheckDemoStatus(); - - D_QuitNetGame(); - - // shutdown everything that was started - I_ShutdownSystem(); - -#ifdef LOGMESSAGES - if (logstream != INVALID_HANDLE_VALUE) - { - CloseHandle(logstream); - logstream = INVALID_HANDLE_VALUE; - } -#endif - - MessageBoxA(hWndMain, txt, "SRB2 Error", MB_OK|MB_ICONERROR); - - exit(-1); -} - -static inline VOID ShowEndTxt(HANDLE co) -{ - int i; - UINT16 j, att = 0; - int nlflag = 1; - CONSOLE_SCREEN_BUFFER_INFO backupcon; - COORD resizewin = {80,-1}; - DWORD bytesWritten; - CHAR let = 0; - UINT16 *text; - void *data; - int endoomnum = W_GetNumForName("ENDOOM"); - //HANDLE ci = GetStdHandle(STD_INPUT_HANDLE); - - /* get the lump with the text */ - data = text = W_CacheLumpNum(endoomnum, PU_CACHE); - - backupcon.wAttributes = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE; // Just in case - GetConsoleScreenBufferInfo(co, &backupcon); //Store old state - resizewin.Y = backupcon.dwSize.Y; - if (backupcon.dwSize.X < resizewin.X) - SetConsoleScreenBufferSize(co, resizewin); - - for (i = 1; i <= 80*25; i++) // print 80x25 text and deal with the attributes too - { - j = (UINT16)(*text >> 8); // attribute first - if (j != att) // attribute changed? - { - att = j; // save current attribute - SetConsoleTextAttribute(co, j); //set fg and bg color for buffer - } - - let = (char)(*text++ & 0xff); // now the text - WriteConsoleA(co, &let, 1, &bytesWritten, NULL); - - if (nlflag && !(i % 80) && backupcon.dwSize.X > resizewin.X) // do we need a nl? - { - att = backupcon.wAttributes; - SetConsoleTextAttribute(co, att); // all attributes off - WriteConsoleA(co, "\n", 1, &bytesWritten, NULL); - } - } - SetConsoleTextAttribute(co, backupcon.wAttributes); // all attributes off - //if (nlflag) - // WriteConsoleA(co, "\n", 1, &bytesWritten, NULL); - - getchar(); //pause! - - Z_Free(data); -} - - -// -// I_Quit: shutdown everything cleanly, in reverse order of Startup. -// -void I_Quit(void) -{ - HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE); - // when recording a demo, should exit using 'q', - // but sometimes we forget and use Alt+F4, so save here too. - if (demorecording) - G_CheckDemoStatus(); - - M_SaveConfig(NULL); // save game config, cvars.. - G_SaveGameData(); - - // maybe it needs that the ticcount continues, - // or something else that will be finished by I_ShutdownSystem(), - // so do it before. - D_QuitNetGame(); - - // shutdown everything that was started - I_ShutdownSystem(); - - if (shutdowning || errorcount) - I_Error("Error detected (%d)", errorcount); - -#ifdef LOGMESSAGES - if (logstream != INVALID_HANDLE_VALUE) - { - I_OutputMsg("I_Quit(): end of logstream.\r\n"); - CloseHandle(logstream); - logstream = INVALID_HANDLE_VALUE; - } -#endif - if (!M_CheckParm("-noendtxt") && W_CheckNumForName("ENDOOM")!=-1 - && co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR) - { - printf("\r"); - ShowEndTxt(co); - } - fflush(stderr); - exit(0); -} - -// -------------------------------------------------------------------------- -// I_ShowLastError -// Displays a GetLastError() error message in a MessageBox -// -------------------------------------------------------------------------- -void I_GetLastErrorMsgBox(void) -{ - LPSTR lpMsgBuf = NULL; - - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, - NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - lpMsgBuf, 0, NULL); - - // Display the string. - MessageBoxA(NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION); - - // put it in console too and log if any - CONS_Printf("Error: %s\n", lpMsgBuf); - - // Free the buffer. - LocalFree(lpMsgBuf); -} - -// =========================================================================================== -// CLEAN STARTUP & SHUTDOWN HANDLING, JUST CLOSE EVERYTHING YOU OPENED. -// =========================================================================================== -// -// -static quitfuncptr quit_funcs[MAX_QUIT_FUNCS] = -{ - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; - -// Adds a function to the list that need to be called by I_SystemShutdown(). -// -void I_AddExitFunc(void (*func)()) -{ - int c; - - for (c = 0; c < MAX_QUIT_FUNCS; c++) - { - if (!quit_funcs[c]) - { - quit_funcs[c] = func; - break; - } - } -} - -// Removes a function from the list that need to be called by I_SystemShutdown(). -// -void I_RemoveExitFunc(void (*func)()) -{ - int c; - - for (c = 0; c < MAX_QUIT_FUNCS; c++) - { - if (quit_funcs[c] == func) - { - while (c < MAX_QUIT_FUNCS - 1) - { - quit_funcs[c] = quit_funcs[c+1]; - c++; - } - quit_funcs[MAX_QUIT_FUNCS-1] = NULL; - break; - } - } -} - -// =========================================================================================== -// DIRECT INPUT HELPER CODE -// =========================================================================================== - -// Create a DirectInputDevice interface, -// create a DirectInputDevice2 interface if possible -static void CreateDevice2(LPDIRECTINPUT di, REFGUID pguid, LPDIRECTINPUTDEVICE* lpDEV, - LPDIRECTINPUTDEVICE2* lpDEV2) -{ - HRESULT hr, hr2; - LPDIRECTINPUTDEVICE lpdid1; - LPDIRECTINPUTDEVICE2 lpdid2 = NULL; - - hr = IDirectInput_CreateDevice(di, pguid, &lpdid1, NULL); - - if (SUCCEEDED(hr)) - { - // get Device2 but only if we are not in DirectInput version 3 - if (!bDX0300 && lpDEV2) - { - LPDIRECTINPUTDEVICE2 *rp = &lpdid2; - LPVOID *tp = (LPVOID *)rp; - hr2 = IDirectInputDevice_QueryInterface(lpdid1, &IID_IDirectInputDevice2, tp); - if (FAILED(hr2)) - { - CONS_Printf("\2Could not create IDirectInput device 2"); - lpdid2 = NULL; - } - } - } - else - I_Error("Could not create IDirectInput device"); - - *lpDEV = lpdid1; - if (lpDEV2) // only if we requested it - *lpDEV2 = lpdid2; -} - -// =========================================================================================== -// DIRECT INPUT MOUSE -// =========================================================================================== - -#define DI_MOUSE_BUFFERSIZE 16 // number of data elements in mouse buffer - -// -// Initialise the mouse. -// -static void I_ShutdownMouse(void); - -void I_StartupMouse(void) -{ - // this gets called when cv_usemouse is initted - // for the win32 version, we want to startup the mouse later -} - -static HANDLE mouse2filehandle = INVALID_HANDLE_VALUE; - -static void I_ShutdownMouse2(void) -{ - if (mouse2filehandle != INVALID_HANDLE_VALUE) - { - event_t event; - int i; - - SetCommMask(mouse2filehandle, 0); - - EscapeCommFunction(mouse2filehandle, CLRDTR); - EscapeCommFunction(mouse2filehandle, CLRRTS); - - PurgeComm(mouse2filehandle, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); - - CloseHandle(mouse2filehandle); - - // emulate the up of all mouse buttons - for (i = 0; i < MOUSEBUTTONS; i++) - { - event.type = ev_keyup; - event.data1 = KEY_2MOUSE1 + i; - D_PostEvent(&event); - } - - mouse2filehandle = INVALID_HANDLE_VALUE; - } -} - -#define MOUSECOMBUFFERSIZE 256 -static int handlermouse2x, handlermouse2y, handlermouse2buttons; - -static void I_PoolMouse2(void) -{ - UINT8 buffer[MOUSECOMBUFFERSIZE]; - COMSTAT ComStat; - DWORD dwErrorFlags, dwLength; - char dx, dy; - - static int bytenum; - static UINT8 combytes[4]; - DWORD i; - - ClearCommError(mouse2filehandle, &dwErrorFlags, &ComStat); - dwLength = min(MOUSECOMBUFFERSIZE, ComStat.cbInQue); - - if (dwLength > 0) - { - if (!ReadFile(mouse2filehandle, buffer, dwLength, &dwLength, NULL)) - { - CONS_Printf("\2Read Error on secondary mouse port\n"); - return; - } - - // parse the mouse packets - for (i = 0; i < dwLength; i++) - { - if ((buffer[i] & 64) == 64) - bytenum = 0; - - if (bytenum < 4) - combytes[bytenum] = buffer[i]; - bytenum++; - - if (bytenum == 1) - { - handlermouse2buttons &= ~3; - handlermouse2buttons |= ((combytes[0] & (32+16)) >>4); - } - else if (bytenum == 3) - { - dx = (char)((combytes[0] & 3) << 6); - dy = (char)((combytes[0] & 12) << 4); - dx = (char)(dx + combytes[1]); - dy = (char)(dy + combytes[2]); - handlermouse2x += dx; - handlermouse2y += dy; - } - else if (bytenum == 4) // fourth byte (logitech mouses) - { - if (buffer[i] & 32) - handlermouse2buttons |= 4; - else - handlermouse2buttons &= ~4; - } - } - } -} - -// secondary mouse doesn't use DirectX, therefore forget all about grabbing, acquire, etc. -void I_StartupMouse2(void) -{ - DCB dcb; - - if (mouse2filehandle != INVALID_HANDLE_VALUE) - I_ShutdownMouse2(); - - if (!cv_usemouse2.value) - return; - - if (mouse2filehandle != INVALID_HANDLE_VALUE) - { - // COM file handle - mouse2filehandle = CreateFileA(cv_mouse2port.string, GENERIC_READ|GENERIC_WRITE, - 0, // exclusive access - NULL, // no security attrs - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (mouse2filehandle == INVALID_HANDLE_VALUE) - { - int e = GetLastError(); - if (e == 5) - CONS_Printf("\2Can't open %s: Access denied\n" - "The port is probably already used by another device (mouse, modem,...)\n", - cv_mouse2port.string); - else - CONS_Printf("\2Can't open %s: error %d\n", cv_mouse2port.string, e); - return; - } - } - - // buffers - SetupComm(mouse2filehandle, MOUSECOMBUFFERSIZE, MOUSECOMBUFFERSIZE); - - // purge buffers - PurgeComm(mouse2filehandle, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); - - // setup port to 1200 7N1 - dcb.DCBlength = sizeof (DCB); - - GetCommState(mouse2filehandle, &dcb); - - dcb.BaudRate = CBR_1200; - dcb.ByteSize = 7; - dcb.Parity = NOPARITY; - dcb.StopBits = ONESTOPBIT; - - dcb.fDtrControl = DTR_CONTROL_ENABLE; - dcb.fRtsControl = RTS_CONTROL_ENABLE; - - dcb.fBinary = dcb.fParity = TRUE; - - SetCommState(mouse2filehandle, &dcb); - - I_AddExitFunc(I_ShutdownMouse2); -} - -#define MAX_MOUSE_BTNS 5 -static int center_x, center_y; -static int old_mparms[3], new_mparms[3] = {0, 0, 1}; -static boolean restore_mouse = FALSE; -static int old_mouse_state = 0; -unsigned int MSHWheelMessage = 0; - -static void I_DoStartupSysMouse(void) -{ - boolean valid; - RECT w_rect; - - valid = SystemParametersInfo(SPI_GETMOUSE, 0, old_mparms, 0); - if (valid) - { - new_mparms[2] = old_mparms[2]; - restore_mouse = SystemParametersInfo(SPI_SETMOUSE, 0, new_mparms, 0); - } - - if (bAppFullScreen) - { - w_rect.top = 0; - w_rect.left = 0; - } - else - { - w_rect.top = windowPosY; - w_rect.left = windowPosX; - } - - w_rect.bottom = w_rect.top + VIDHEIGHT; - w_rect.right = w_rect.left + VIDWIDTH; - center_x = w_rect.left + (VIDWIDTH >> 1); - center_y = w_rect.top + (VIDHEIGHT >> 1); - SetCursor(NULL); - SetCursorPos(center_x, center_y); - SetCapture(hWndMain); - ClipCursor(&w_rect); -} - -static void I_ShutdownSysMouse(void) -{ - if (restore_mouse) - SystemParametersInfo(SPI_SETMOUSE, 0, old_mparms, 0); - ClipCursor(NULL); - ReleaseCapture(); -} - -void I_RestartSysMouse(void) -{ - if (nodinput) - { - I_ShutdownSysMouse(); - I_DoStartupSysMouse(); - } -} - -void I_GetSysMouseEvents(int mouse_state) -{ - int i; - event_t event; - int xmickeys = 0, ymickeys = 0; - POINT c_pos; - - for (i = 0; i < MAX_MOUSE_BTNS; i++) - { - // check if button pressed - if ((mouse_state & (1 << i)) && !(old_mouse_state & (1 << i))) - { - event.type = ev_keydown; - event.data1 = KEY_MOUSE1 + i; - D_PostEvent(&event); - } - // check if button released - if (!(mouse_state & (1 << i)) && (old_mouse_state & (1 << i))) - { - event.type = ev_keyup; - event.data1 = KEY_MOUSE1 + i; - D_PostEvent(&event); - } - } - old_mouse_state = mouse_state; - - // proceed mouse movements - GetCursorPos(&c_pos); - xmickeys = c_pos.x - center_x; - ymickeys = c_pos.y - center_y; - - if (xmickeys || ymickeys) - { - event.type = ev_mouse; - event.data1 = 0; - event.data2 = xmickeys; - event.data3 = -ymickeys; - D_PostEvent(&event); - SetCursorPos(center_x, center_y); - } -} - -// This is called just before entering the main game loop, -// when we are going fullscreen and the loading screen has finished. -void I_DoStartupMouse(void) -{ - DIPROPDWORD dip; - - // mouse detection may be skipped by setting usemouse false - if (!cv_usemouse.value || M_CheckParm("-nomouse")) - { - mouse_enabled = false; - return; - } - - if (nodinput) - { - CONS_Printf("\tMouse will not use DirectInput.\n"); - // System mouse input will be initiated by VID_SetMode - I_AddExitFunc(I_ShutdownMouse); - - MSHWheelMessage = RegisterWindowMessage(MSH_MOUSEWHEEL); - } - else if (!lpDIM) // acquire the mouse only once - { - CreateDevice2(lpDI, &GUID_SysMouse, &lpDIM, NULL); - - if (lpDIM) - { - if (FAILED(IDirectInputDevice_SetDataFormat(lpDIM, &c_dfDIMouse))) - I_Error("Couldn't set mouse data format"); - - // create buffer for buffered data - dip.diph.dwSize = sizeof (dip); - dip.diph.dwHeaderSize = sizeof (dip.diph); - dip.diph.dwObj = 0; - dip.diph.dwHow = DIPH_DEVICE; - dip.dwData = DI_MOUSE_BUFFERSIZE; - if (FAILED(IDirectInputDevice_SetProperty(lpDIM, DIPROP_BUFFERSIZE, &dip.diph))) - I_Error("Couldn't set mouse buffer size"); - - if (FAILED(IDirectInputDevice_SetCooperativeLevel(lpDIM, hWndMain, - DISCL_EXCLUSIVE|DISCL_FOREGROUND))) - { - I_Error("Couldn't set mouse coop level"); - } - I_AddExitFunc(I_ShutdownMouse); - } - else - I_Error("Couldn't create mouse input"); - } - - // if re-enabled while running, just set mouse_enabled true again, - // do not acquire the mouse more than once - mouse_enabled = true; -} - -// -// Shutdown Mouse DirectInput device -// -static void I_ShutdownMouse(void) -{ - int i; - event_t event; - - CONS_Printf("I_ShutdownMouse()\n"); - - if (lpDIM) - { - IDirectInputDevice_Unacquire(lpDIM); - IDirectInputDevice_Release(lpDIM); - lpDIM = NULL; - } - - // emulate the up of all mouse buttons - for (i = 0; i < MOUSEBUTTONS; i++) - { - event.type = ev_keyup; - event.data1 = KEY_MOUSE1 + i; - D_PostEvent(&event); - } - if (nodinput) - I_ShutdownSysMouse(); - - mouse_enabled = false; -} - -// -// Get buffered data from the mouse -// -void I_GetMouseEvents(void) -{ - DIDEVICEOBJECTDATA rgdod[DI_MOUSE_BUFFERSIZE]; - DWORD dwItems, d; - HRESULT hr; - - event_t event; - int xmickeys, ymickeys; - - if (mouse2filehandle != INVALID_HANDLE_VALUE) - { - //mouse movement - static UINT8 lastbuttons2 = 0; - - I_PoolMouse2(); - // post key event for buttons - if (handlermouse2buttons != lastbuttons2) - { - int i, j = 1, k; - k = handlermouse2buttons ^ lastbuttons2; // only changed bit to 1 - lastbuttons2 = (UINT8)handlermouse2buttons; - - for (i = 0; i < MOUSEBUTTONS; i++, j <<= 1) - if (k & j) - { - if (handlermouse2buttons & j) - event.type = ev_keydown; - else - event.type = ev_keyup; - event.data1 = KEY_2MOUSE1 + i; - D_PostEvent(&event); - } - } - - if (handlermouse2x || handlermouse2y) - { - event.type = ev_mouse2; - event.data1 = 0; - event.data2 = handlermouse2x<<1; - event.data3 = -handlermouse2y<<1; - handlermouse2x = 0; - handlermouse2y = 0; - - D_PostEvent(&event); - } - } - - if (!mouse_enabled || nodinput) - return; - -getBufferedData: - dwItems = DI_MOUSE_BUFFERSIZE; - hr = IDirectInputDevice_GetDeviceData(lpDIM, sizeof (DIDEVICEOBJECTDATA), rgdod, &dwItems, 0); - - // If data stream was interrupted, reacquire the device and try again. - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) - { - hr = IDirectInputDevice_Acquire(lpDIM); - if (SUCCEEDED(hr)) - goto getBufferedData; - } - - // We got buffered input, act on it - if (SUCCEEDED(hr)) - { - xmickeys = ymickeys = 0; - - // dwItems contains number of elements read (could be 0) - for (d = 0; d < dwItems; d++) - { - if (rgdod[d].dwOfs >= DIMOFS_BUTTON0 && - rgdod[d].dwOfs < DIMOFS_BUTTON0 + MOUSEBUTTONS) - { - if (rgdod[d].dwData & 0x80) // Button down - event.type = ev_keydown; - else - event.type = ev_keyup; // Button up - - event.data1 = rgdod[d].dwOfs - DIMOFS_BUTTON0 + KEY_MOUSE1; - D_PostEvent(&event); - } - else if (rgdod[d].dwOfs == DIMOFS_X) - xmickeys += rgdod[d].dwData; - else if (rgdod[d].dwOfs == DIMOFS_Y) - ymickeys += rgdod[d].dwData; - - else if (rgdod[d].dwOfs == DIMOFS_Z) - { - // z-axes the wheel - if ((int)rgdod[d].dwData > 0) - event.data1 = KEY_MOUSEWHEELUP; - else - event.data1 = KEY_MOUSEWHEELDOWN; - event.type = ev_keydown; - D_PostEvent(&event); - } - - } - - if (xmickeys || ymickeys) - { - event.type = ev_mouse; - event.data1 = 0; - event.data2 = xmickeys; - event.data3 = -ymickeys; - D_PostEvent(&event); - } - } -} - -// =========================================================================================== -// DIRECT INPUT JOYSTICK -// =========================================================================================== - -struct DIJoyInfo_s -{ - BYTE X,Y,Z,Rx,Ry,Rz,U,V; - LONG ForceAxises; -}; -typedef struct DIJoyInfo_s DIJoyInfo_t; - -// private info - static BYTE iJoyNum; // used by enumeration - static DIJoyInfo_t JoyInfo; - static BYTE iJoy2Num; - static DIJoyInfo_t JoyInfo2; - -//----------------------------------------------------------------------------- -// Name: EnumAxesCallback() -// Desc: Callback function for enumerating the axes on a joystick and counting -// each force feedback enabled axis -//----------------------------------------------------------------------------- -static BOOL CALLBACK EnumAxesCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, - VOID* pContext) -{ - DWORD* pdwNumForceFeedbackAxis = (DWORD*) pContext; - - if ((pdidoi->dwFlags & DIDOI_FFACTUATOR) != 0) - (*pdwNumForceFeedbackAxis)++; - - return DIENUM_CONTINUE; -} - - -static HRESULT SetupForceTacile(LPDIRECTINPUTDEVICE2 DJI, LPDIRECTINPUTEFFECT *DJE, DWORD FFAXIS, FFType EffectType,REFGUID EffectGUID) -{ - HRESULT hr; - DIEFFECT eff; - DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y }; - LONG rglDirection[2] = { 0, 0 }; - DICONSTANTFORCE cf = { 0 }; // LONG lMagnitude - DIRAMPFORCE rf = {0,0}; // LONG lStart, lEnd; - DIPERIODIC pf = {0,0,0,0}; - ZeroMemory(&eff, sizeof (eff)); - if (FFAXIS > 2) - FFAXIS = 2; //up to 2 FFAXIS - eff.dwSize = sizeof (DIEFFECT); - eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; // Cartesian and data format offsets - eff.dwDuration = INFINITE; - eff.dwSamplePeriod = 0; - eff.dwGain = DI_FFNOMINALMAX; - eff.dwTriggerButton = DIEB_NOTRIGGER; - eff.dwTriggerRepeatInterval = 0; - eff.cAxes = FFAXIS; - eff.rgdwAxes = rgdwAxes; - eff.rglDirection = rglDirection; - eff.lpEnvelope = NULL; - eff.lpvTypeSpecificParams = NULL; - if (EffectType == ConstantForce) - { - eff.cbTypeSpecificParams = sizeof (cf); - eff.lpvTypeSpecificParams = &cf; - } - else if (EffectType == RampForce) - { - eff.cbTypeSpecificParams = sizeof (rf); - eff.lpvTypeSpecificParams = &rf; - } - else if (EffectType >= SquareForce && SawtoothDownForce >= EffectType) - { - eff.cbTypeSpecificParams = sizeof (pf); - eff.lpvTypeSpecificParams = &pf; - } -#if (DIRECTINPUT_VERSION >= 0x0600) - //eff.dwStartDelay = 0; -#endif - - // Create the prepared effect - if (FAILED(hr = IDirectInputDevice2_CreateEffect(DJI, EffectGUID, - &eff, DJE, NULL))) - { - return hr; - } - - if (NULL == *DJE) - return E_FAIL; - - return hr; -} - -static BOOL CALLBACK DIEnumEffectsCallback1(LPCDIEFFECTINFO pdei, LPVOID pvRef) -{ - LPDIRECTINPUTEFFECT *DJE = pvRef; - if (DIEFT_GETTYPE(pdei->dwEffType) == DIEFT_CONSTANTFORCE) - { - if (SUCCEEDED(SetupForceTacile(lpDIJA,DJE, JoyInfo.ForceAxises, ConstantForce, &pdei->guid))) - return DIENUM_STOP; - } - if (DIEFT_GETTYPE(pdei->dwEffType) == DIEFT_RAMPFORCE) - { - if (SUCCEEDED(SetupForceTacile(lpDIJA,DJE, JoyInfo.ForceAxises, RampForce, &pdei->guid))) - return DIENUM_STOP; - } - return DIENUM_CONTINUE; -} - -static BOOL CALLBACK DIEnumEffectsCallback2(LPCDIEFFECTINFO pdei, LPVOID pvRef) -{ - LPDIRECTINPUTEFFECT *DJE = pvRef; - if (DIEFT_GETTYPE(pdei->dwEffType) == DIEFT_CONSTANTFORCE) - { - if (SUCCEEDED(SetupForceTacile(lpDIJ2A,DJE, JoyInfo2.ForceAxises, ConstantForce, &pdei->guid))) - return DIENUM_STOP; - } - if (DIEFT_GETTYPE(pdei->dwEffType) == DIEFT_RAMPFORCE) - { - if (SUCCEEDED(SetupForceTacile(lpDIJ2A,DJE, JoyInfo2.ForceAxises, RampForce, &pdei->guid))) - return DIENUM_STOP; - } - return DIENUM_CONTINUE; -} - -static REFGUID DIETable[] = -{ - &GUID_ConstantForce, //ConstantForce - &GUID_RampForce, //RampForce - &GUID_Square, //SquareForce - &GUID_Sine, //SineForce - &GUID_Triangle, //TriangleForce - &GUID_SawtoothUp, //SawtoothUpForce - &GUID_SawtoothDown, //SawtoothDownForce - (REFGUID)-1, //NumberofForces -}; - -static HRESULT SetupAllForces(LPDIRECTINPUTDEVICE2 DJI, LPDIRECTINPUTEFFECT DJE[], DWORD FFAXIS) -{ - FFType ForceType = EvilForce; - if (DJI == lpDIJA) - { - IDirectInputDevice2_EnumEffects(DJI,DIEnumEffectsCallback1,&DJE[ConstantForce],DIEFT_CONSTANTFORCE); - IDirectInputDevice2_EnumEffects(DJI,DIEnumEffectsCallback1,&DJE[RampForce],DIEFT_RAMPFORCE); - } - else if (DJI == lpDIJA) - { - IDirectInputDevice2_EnumEffects(DJI,DIEnumEffectsCallback2,&DJE[ConstantForce],DIEFT_CONSTANTFORCE); - IDirectInputDevice2_EnumEffects(DJI,DIEnumEffectsCallback2,&DJE[RampForce],DIEFT_RAMPFORCE); - } - for (ForceType = SquareForce; ForceType > NumberofForces && DIETable[ForceType] != (REFGUID)-1; ForceType++) - if (DIETable[ForceType]) - SetupForceTacile(DJI,&DJE[ForceType], FFAXIS, ForceType, DIETable[ForceType]); - return S_OK; -} - -static void LimitEffect(LPDIEFFECT eff, FFType EffectType) -{ - LPDICONSTANTFORCE pCF = eff->lpvTypeSpecificParams; - LPDIPERIODIC pDP= eff->lpvTypeSpecificParams; - if (eff->rglDirection) - { - } -/* if (eff->dwDuration != INFINITE && eff->dwDuration < 0) - { - eff->dwDuration = 0; - }*/ - if (eff->dwGain != 0) - { - if (eff->dwGain > DI_FFNOMINALMAX) - eff->dwGain = DI_FFNOMINALMAX; - //else if (eff->dwGain < -DI_FFNOMINALMAX) - // eff->dwGain = DI_FFNOMINALMAX; - } - if (EffectType == ConstantForce && pCF->lMagnitude) - { - } - else if (EffectType >= SquareForce && SawtoothDownForce >= EffectType && pDP) - { - } - -} - -static HRESULT SetForceTacile(LPDIRECTINPUTEFFECT SDIE, const JoyFF_t *FF,DWORD FFAXIS, FFType EffectType) -{ - DIEFFECT eff; - HRESULT hr; - LONG Magnitude; - LONG rglDirection[2] = { 0, 0 }; - DICONSTANTFORCE cf = { 0 }; // LONG lMagnitude - DIRAMPFORCE rf = {0,0}; // LONG lStart, lEnd; - DIPERIODIC pf = {0,0,0,0}; - if (!FF) - IDirectInputEffect_Stop(SDIE); - Magnitude = FF->Magnitude; - ZeroMemory(&eff, sizeof (eff)); - eff.dwSize = sizeof (eff); - //DIEP_START - eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; // Cartesian and data format offsets - //DIEP_DURATION - eff.dwDuration = FF->Duration; - //DIEP_GAIN - eff.dwGain = FF->Gain; - //DIEP_DIRECTION - eff.rglDirection = rglDirection; - //DIEP_TYPESPECIFICPARAMS - if (FFAXIS > 1) - { - double dMagnitude; - dMagnitude = (double)Magnitude; - dMagnitude = hypot(dMagnitude, dMagnitude); - Magnitude = (DWORD)dMagnitude; - rglDirection[0] = FF->ForceX; - rglDirection[1] = FF->ForceY; - } - if (EffectType == ConstantForce) - { - cf.lMagnitude = Magnitude; - eff.cbTypeSpecificParams = sizeof (cf); - eff.lpvTypeSpecificParams = &cf; - } - else if (EffectType == RampForce) - { - rf.lStart = FF->Start; - rf.lEnd = FF->End; - eff.cbTypeSpecificParams = sizeof (rf); - eff.lpvTypeSpecificParams = &rf; - } - else if (EffectType >= SquareForce && SawtoothDownForce >= EffectType) - { - pf.dwMagnitude = Magnitude; - pf.lOffset = FF->Offset; - pf.dwPhase = FF->Phase; - pf.dwPeriod = FF->Period; - eff.cbTypeSpecificParams = sizeof (pf); - eff.lpvTypeSpecificParams = &pf; - } - - LimitEffect(&eff, EffectType); - - hr = IDirectInputEffect_SetParameters(SDIE, &eff, - DIEP_START|DIEP_DURATION|DIEP_GAIN|DIEP_DIRECTION|DIEP_TYPESPECIFICPARAMS); - return hr; -} - -void I_Tactile(FFType Type, const JoyFF_t *Effect) -{ - if (!lpDIJA) return; - if (FAILED(IDirectInputDevice2_Acquire(lpDIJA))) - return; - if (Type == EvilForce) - IDirectInputDevice2_SendForceFeedbackCommand(lpDIJA,DISFFC_STOPALL); - if (Type <= EvilForce || Type > NumberofForces || !lpDIE[Type]) - return; - SetForceTacile(lpDIE[Type], Effect, JoyInfo.ForceAxises, Type); -} - -void I_Tactile2(FFType Type, const JoyFF_t *Effect) -{ - if (!lpDIJ2A) return; - if (FAILED(IDirectInputDevice2_Acquire(lpDIJ2A))) - return; - if (Type == EvilForce) - IDirectInputDevice2_SendForceFeedbackCommand(lpDIJ2A,DISFFC_STOPALL); - if (Type <= EvilForce || Type > NumberofForces || !lpDIE2[Type]) - return; - SetForceTacile(lpDIE2[Type],Effect, JoyInfo2.ForceAxises, Type); -} - -// ------------------ -// SetDIDwordProperty (HELPER) -// Set a DWORD property on a DirectInputDevice. -// ------------------ -static HRESULT SetDIDwordProperty(LPDIRECTINPUTDEVICE pdev, - REFGUID guidProperty, - DWORD dwObject, - DWORD dwHow, - DWORD dwValue) -{ - DIPROPDWORD dipdw; - - dipdw.diph.dwSize = sizeof (dipdw); - dipdw.diph.dwHeaderSize = sizeof (dipdw.diph); - dipdw.diph.dwObj = dwObject; - dipdw.diph.dwHow = dwHow; - dipdw.dwData = dwValue; - - return IDirectInputDevice_SetProperty(pdev, guidProperty, &dipdw.diph); -} - - -// --------------- -// DIEnumJoysticks -// There is no such thing as a 'system' joystick, contrary to mouse, -// we must enumerate and choose one joystick device to use -// --------------- -static BOOL CALLBACK DIEnumJoysticks (LPCDIDEVICEINSTANCE lpddi, - LPVOID pvRef) //cv_usejoystick -{ - LPDIRECTINPUTDEVICE pdev; - DIPROPRANGE diprg; - DIDEVCAPS caps; - BOOL bUseThisOne = FALSE; - - iJoyNum++; - - //faB: if cv holds a string description of joystick, the value from atoi() is 0 - // else, the value was probably set by user at console to one of the previously - // enumerated joysticks - if (((consvar_t *)pvRef)->value == iJoyNum -#ifndef _UNICODE - || !lstrcmpA(((consvar_t *)pvRef)->string, lpddi->tszProductName) -#endif - ) - bUseThisOne = TRUE; - - //CONS_Printf(" cv joy is %s\n", ((consvar_t *)pvRef)->string); - - // print out device name - CONS_Printf("%c%d: %s\n", - (bUseThisOne) ? '\2' : ' ', // show name in white if this is the one we will use - iJoyNum, - //(GET_DIDEVICE_SUBTYPE(lpddi->dwDevType) == DIDEVTYPEJOYSTICK_GAMEPAD) ? "Gamepad " : "Joystick", - lpddi->tszProductName); //, lpddi->tszInstanceName); - - // use specified joystick (cv_usejoystick.value in pvRef) - if (!bUseThisOne) - return DIENUM_CONTINUE; - - ((consvar_t *)pvRef)->value = iJoyNum; - if (IDirectInput_CreateDevice (lpDI, &lpddi->guidInstance, - &pdev, NULL) != DI_OK) - { - // if it failed, then we can't use this joystick for some - // bizarre reason. (Maybe the user unplugged it while we - // were in the middle of enumerating it.) So continue enumerating - CONS_Printf("DIEnumJoysticks(): CreateDevice FAILED\n"); - return DIENUM_CONTINUE; - } - - // get the Device capabilities - // - caps.dwSize = sizeof (DIDEVCAPS_DX3); - if (FAILED(IDirectInputDevice_GetCapabilities (pdev, &caps))) - { - CONS_Printf("DIEnumJoysticks(): GetCapabilities FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - if (!(caps.dwFlags & DIDC_ATTACHED)) // should be, since we enumerate only attached devices - return DIENUM_CONTINUE; - - Joystick.bJoyNeedPoll = ((caps.dwFlags & DIDC_POLLEDDATAFORMAT) != 0); - - if (caps.dwFlags & DIDC_FORCEFEEDBACK) - JoyInfo.ForceAxises = 0; - else - JoyInfo.ForceAxises = -1; - - Joystick.bGamepadStyle = (GET_DIDEVICE_SUBTYPE(caps.dwDevType) == DIDEVTYPEJOYSTICK_GAMEPAD); - //DEBUG CONS_Printf("Gamepad: %d\n", Joystick.bGamepadStyle); - - - CONS_Printf("Capabilities: %d axes, %d buttons, %d POVs, poll %d, Gamepad %d\n", - caps.dwAxes, caps.dwButtons, caps.dwPOVs, Joystick.bJoyNeedPoll, Joystick.bGamepadStyle); - - // Set the data format to "simple joystick" - a predefined data format - // - // A data format specifies which controls on a device we - // are interested in, and how they should be reported. - // - // This tells DirectInput that we will be passing a - // DIJOYSTATE structure to IDirectInputDevice::GetDeviceState. - if (IDirectInputDevice_SetDataFormat (pdev, &c_dfDIJoystick) != DI_OK) - { - CONS_Printf("DIEnumJoysticks(): SetDataFormat FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - - // Set the cooperativity level to let DirectInput know how - // this device should interact with the system and with other - // DirectInput applications. - if (IDirectInputDevice_SetCooperativeLevel (pdev, hWndMain, - DISCL_EXCLUSIVE | DISCL_FOREGROUND) != DI_OK) - { - CONS_Printf("DIEnumJoysticks(): SetCooperativeLevel FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - - // set the range of the joystick axis - diprg.diph.dwSize = sizeof (DIPROPRANGE); - diprg.diph.dwHeaderSize = sizeof (DIPROPHEADER); - diprg.diph.dwHow = DIPH_BYOFFSET; - diprg.lMin = -JOYAXISRANGE; // value for extreme left - diprg.lMax = +JOYAXISRANGE; // value for extreme right - - diprg.diph.dwObj = DIJOFS_X; // set the x-axis range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //goto SetPropFail; - JoyInfo.X = FALSE; - } - else JoyInfo.X = TRUE; - - diprg.diph.dwObj = DIJOFS_Y; // set the y-axis range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { -//SetPropFail: -// CONS_Printf("DIEnumJoysticks(): SetProperty FAILED\n"); -// IDirectInputDevice_Release (pdev); -// return DIENUM_CONTINUE; - JoyInfo.Y = FALSE; - } - else JoyInfo.Y = TRUE; - - diprg.diph.dwObj = DIJOFS_Z; // set the z-axis range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //CONS_Printf("DIJOFS_Z not found\n"); - JoyInfo.Z = FALSE; - } - else JoyInfo.Z = TRUE; - - diprg.diph.dwObj = DIJOFS_RX; // set the x-rudder range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //CONS_Printf("DIJOFS_RX (x-rudder) not found\n"); - JoyInfo.Rx = FALSE; - } - else JoyInfo.Rx = TRUE; - - diprg.diph.dwObj = DIJOFS_RY; // set the y-rudder range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //CONS_Printf("DIJOFS_RY (y-rudder) not found\n"); - JoyInfo.Ry = FALSE; - } - else JoyInfo.Ry = TRUE; - - diprg.diph.dwObj = DIJOFS_RZ; // set the z-rudder range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //CONS_Printf("DIJOFS_RZ (z-rudder) not found\n"); - JoyInfo.Rz = FALSE; - } - else JoyInfo.Rz = TRUE; - diprg.diph.dwObj = DIJOFS_SLIDER(0); // set the x-misc range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //CONS_Printf("DIJOFS_RZ (x-misc) not found\n"); - JoyInfo.U = FALSE; - } - else JoyInfo.U = TRUE; - - diprg.diph.dwObj = DIJOFS_SLIDER(1); // set the y-misc range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //CONS_Printf("DIJOFS_RZ (y-misc) not found\n"); - JoyInfo.V = FALSE; - } - else JoyInfo.V = TRUE; - - // set X axis dead zone to 25% (to avoid accidental turning) - if (!Joystick.bGamepadStyle) - { - if (JoyInfo.X) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_X, - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks(): couldn't SetProperty for X DEAD ZONE"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.Y) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_Y, - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks(): couldn't SetProperty for Y DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.Z) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_Z, - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks(): couldn't SetProperty for Z DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.Rx) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_RX, - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks(): couldn't SetProperty for RX DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.Ry) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_RY, - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks(): couldn't SetProperty for RY DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.Rz) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_RZ, - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks(): couldn't SetProperty for RZ DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.U) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_SLIDER(0), - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks(): couldn't SetProperty for U DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo.V) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_SLIDER(1), - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks(): couldn't SetProperty for V DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - } - - // query for IDirectInputDevice2 - we need this to poll the joystick - if (bDX0300) - { - FFType i = EvilForce; - // we won't use the poll - lpDIJA = NULL; - for (i = 0; i > NumberofForces; i++) - lpDIE[i] = NULL; - } - else - { - LPDIRECTINPUTDEVICE2 *rp = &lpDIJA; - LPVOID *tp = (LPVOID *)rp; - if (FAILED(IDirectInputDevice_QueryInterface(pdev, &IID_IDirectInputDevice2, tp))) - { - CONS_Printf("DIEnumJoysticks(): QueryInterface FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - - if (lpDIJA && JoyInfo.ForceAxises != -1) - { - // Since we will be playing force feedback effects, we should disable the - // auto-centering spring. - if (FAILED(SetDIDwordProperty(pdev, DIPROP_AUTOCENTER, 0, DIPH_DEVICE, FALSE))) - { - //NOP - } - - // Enumerate and count the axes of the joystick - if (FAILED(IDirectInputDevice_EnumObjects(pdev, EnumAxesCallback, - (VOID*)&JoyInfo.ForceAxises, DIDFT_AXIS))) - { - JoyInfo.ForceAxises = -1; - } - else - { - SetupAllForces(lpDIJA,lpDIE,JoyInfo.ForceAxises); - } - } - } - - // we successfully created an IDirectInputDevice. So stop looking - // for another one. - lpDIJ = pdev; - return DIENUM_STOP; -} - -// -------------- -// I_InitJoystick -// This is called everytime the 'use_joystick' variable changes -// It is normally called at least once at startup when the config is loaded -// -------------- -void I_InitJoystick(void) -{ - HRESULT hr; - - // cleanup - I_ShutdownJoystick(); - - //joystick detection can be skipped by setting use_joystick to 0 - if (M_CheckParm("-nojoy")) - { - CONS_Printf("Joystick disabled\n"); - return; - } - else - // don't do anything at the registration of the joystick cvar, - // until config is loaded - if (!lstrcmpA(cv_usejoystick.string, "0")) - return; - - // acquire the joystick only once - if (!lpDIJ) - { - joystick_detected = false; - - CONS_Printf("Looking for joystick devices:\n"); - iJoyNum = 0; - hr = IDirectInput_EnumDevices(lpDI, DIDEVTYPE_JOYSTICK, DIEnumJoysticks, - (void *)&cv_usejoystick, // our user parameter is joystick number - DIEDFL_ATTACHEDONLY); - if (FAILED(hr)) - { - CONS_Printf("\nI_InitJoystick(): EnumDevices FAILED\n"); - cv_usejoystick.value = 0; - return; - } - - if (!lpDIJ) - { - if (!iJoyNum) - CONS_Printf("none found\n"); - else - { - CONS_Printf("none used\n"); - if (cv_usejoystick.value > 0 && cv_usejoystick.value > iJoyNum) - { - CONS_Printf("\2Set the use_joystick variable to one of the" - " enumerated joystick numbers\n"); - } - } - cv_usejoystick.value = 0; - return; - } - - I_AddExitFunc(I_ShutdownJoystick); - - // set coop level - if (FAILED(IDirectInputDevice_SetCooperativeLevel(lpDIJ, hWndMain, - DISCL_NONEXCLUSIVE|DISCL_FOREGROUND))) - { - I_Error("I_InitJoystick: SetCooperativeLevel FAILED"); - } - } - else - CONS_Printf("Joystick already initialized\n"); - - // we don't unacquire joystick, so let's just pretend we re-acquired it - joystick_detected = true; -} -//Joystick 2 - -// --------------- -// DIEnumJoysticks2 -// There is no such thing as a 'system' joystick, contrary to mouse, -// we must enumerate and choose one joystick device to use -// --------------- -static BOOL CALLBACK DIEnumJoysticks2 (LPCDIDEVICEINSTANCE lpddi, - LPVOID pvRef) //cv_usejoystick -{ - LPDIRECTINPUTDEVICE pdev; - DIPROPRANGE diprg; - DIDEVCAPS caps; - BOOL bUseThisOne = FALSE; - - iJoy2Num++; - - //faB: if cv holds a string description of joystick, the value from atoi() is 0 - // else, the value was probably set by user at console to one of the previsouly - // enumerated joysticks - if (((consvar_t *)pvRef)->value == iJoy2Num -#ifndef _UNICODE - || !lstrcmpA(((consvar_t *)pvRef)->string, lpddi->tszProductName) -#endif - ) - bUseThisOne = TRUE; - - //CONS_Printf(" cv joy2 is %s\n", ((consvar_t *)pvRef)->string); - - // print out device name - CONS_Printf("%c%d: %s\n", - (bUseThisOne) ? '\2' : ' ', // show name in white if this is the one we will use - iJoy2Num, - //(GET_DIDEVICE_SUBTYPE(lpddi->dwDevType) == DIDEVTYPEJOYSTICK_GAMEPAD) ? "Gamepad " : "Joystick", - lpddi->tszProductName); //, lpddi->tszInstanceName); - - // use specified joystick (cv_usejoystick.value in pvRef) - if (!bUseThisOne) - return DIENUM_CONTINUE; - - ((consvar_t *)pvRef)->value = iJoy2Num; - if (IDirectInput_CreateDevice (lpDI, &lpddi->guidInstance, - &pdev, NULL) != DI_OK) - { - // if it failed, then we can't use this joystick for some - // bizarre reason. (Maybe the user unplugged it while we - // were in the middle of enumerating it.) So continue enumerating - CONS_Printf("DIEnumJoysticks2(): CreateDevice FAILED\n"); - return DIENUM_CONTINUE; - } - - - // get the Device capabilities - // - caps.dwSize = sizeof (DIDEVCAPS_DX3); - if (FAILED(IDirectInputDevice_GetCapabilities (pdev, &caps))) - { - CONS_Printf("DIEnumJoysticks2(): GetCapabilities FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - if (!(caps.dwFlags & DIDC_ATTACHED)) // should be, since we enumerate only attached devices - return DIENUM_CONTINUE; - - Joystick2.bJoyNeedPoll = ((caps.dwFlags & DIDC_POLLEDDATAFORMAT) != 0); - - if (caps.dwFlags & DIDC_FORCEFEEDBACK) - JoyInfo2.ForceAxises = 0; - else - JoyInfo2.ForceAxises = -1; - - Joystick2.bGamepadStyle = (GET_DIDEVICE_SUBTYPE(caps.dwDevType) == DIDEVTYPEJOYSTICK_GAMEPAD); - //DEBUG CONS_Printf("Gamepad: %d\n", Joystick2.bGamepadStyle); - - - CONS_Printf("Capabilities: %d axes, %d buttons, %d POVs, poll %d, Gamepad %d\n", - caps.dwAxes, caps.dwButtons, caps.dwPOVs, Joystick2.bJoyNeedPoll, Joystick2.bGamepadStyle); - - - // Set the data format to "simple joystick" - a predefined data format - // - // A data format specifies which controls on a device we - // are interested in, and how they should be reported. - // - // This tells DirectInput that we will be passing a - // DIJOYSTATE structure to IDirectInputDevice::GetDeviceState. - if (IDirectInputDevice_SetDataFormat (pdev, &c_dfDIJoystick) != DI_OK) - { - CONS_Printf("DIEnumJoysticks2(): SetDataFormat FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - - // Set the cooperativity level to let DirectInput know how - // this device should interact with the system and with other - // DirectInput applications. - if (IDirectInputDevice_SetCooperativeLevel (pdev, hWndMain, - DISCL_EXCLUSIVE | DISCL_FOREGROUND) != DI_OK) - { - CONS_Printf("DIEnumJoysticks2(): SetCooperativeLevel FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - - // set the range of the joystick axis - diprg.diph.dwSize = sizeof (DIPROPRANGE); - diprg.diph.dwHeaderSize = sizeof (DIPROPHEADER); - diprg.diph.dwHow = DIPH_BYOFFSET; - diprg.lMin = -JOYAXISRANGE; // value for extreme left - diprg.lMax = +JOYAXISRANGE; // value for extreme right - - diprg.diph.dwObj = DIJOFS_X; // set the x-axis range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //goto SetPropFail; - JoyInfo2.X = FALSE; - } - else JoyInfo2.X = TRUE; - - diprg.diph.dwObj = DIJOFS_Y; // set the y-axis range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { -//SetPropFail: -// CONS_Printf("DIEnumJoysticks(): SetProperty FAILED\n"); -// IDirectInputDevice_Release (pdev); -// return DIENUM_CONTINUE; - JoyInfo2.Y = FALSE; - } - else JoyInfo2.Y = TRUE; - - diprg.diph.dwObj = DIJOFS_Z; // set the z-axis range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //CONS_Printf("DIJOFS_Z not found\n"); - JoyInfo2.Z = FALSE; - } - else JoyInfo2.Z = TRUE; - - diprg.diph.dwObj = DIJOFS_RX; // set the x-rudder range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //CONS_Printf("DIJOFS_RX (x-rudder) not found\n"); - JoyInfo2.Rx = FALSE; - } - else JoyInfo2.Rx = TRUE; - - diprg.diph.dwObj = DIJOFS_RY; // set the y-rudder range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //CONS_Printf("DIJOFS_RY (y-rudder) not found\n"); - JoyInfo2.Ry = FALSE; - } - else JoyInfo2.Ry = TRUE; - - diprg.diph.dwObj = DIJOFS_RZ; // set the z-rudder range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //CONS_Printf("DIJOFS_RZ (z-rudder) not found\n"); - JoyInfo2.Rz = FALSE; - } - else JoyInfo2.Rz = TRUE; - diprg.diph.dwObj = DIJOFS_SLIDER(0); // set the x-misc range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //CONS_Printf("DIJOFS_RZ (x-misc) not found\n"); - JoyInfo2.U = FALSE; - } - else JoyInfo2.U = TRUE; - - diprg.diph.dwObj = DIJOFS_SLIDER(1); // set the y-misc range - if (FAILED(IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &diprg.diph))) - { - //CONS_Printf("DIJOFS_RZ (y-misc) not found\n"); - JoyInfo2.V = FALSE; - } - else JoyInfo2.V = TRUE; - - // set X axis dead zone to 25% (to avoid accidental turning) - if (!Joystick2.bGamepadStyle) - { - if (JoyInfo2.X) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_X, - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks2(): couldn't SetProperty for X DEAD ZONE"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.Y) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_Y, - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks2(): couldn't SetProperty for Y DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.Z) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_Z, - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks2(): couldn't SetProperty for Z DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.Rx) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_RX, - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks2(): couldn't SetProperty for RX DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.Ry) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_RY, - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks2(): couldn't SetProperty for RY DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.Rz) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_RZ, - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks2(): couldn't SetProperty for RZ DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.U) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_SLIDER(0), - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks2(): couldn't SetProperty for U DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - if (JoyInfo2.V) - if (FAILED(SetDIDwordProperty (pdev, DIPROP_DEADZONE, DIJOFS_SLIDER(1), - DIPH_BYOFFSET, 2500))) - { - CONS_Printf("DIEnumJoysticks2(): couldn't SetProperty for V DEAD ZONE\n"); - //IDirectInputDevice_Release (pdev); - //return DIENUM_CONTINUE; - } - } - - // query for IDirectInputDevice2 - we need this to poll the joystick - if (bDX0300) - { - FFType i = EvilForce; - // we won't use the poll - lpDIJA = NULL; - for (i = 0; i > NumberofForces; i++) - lpDIE[i] = NULL; - } - else - { - LPDIRECTINPUTDEVICE2 *rp = &lpDIJ2A; - LPVOID *tp = (LPVOID *)rp; - if (FAILED(IDirectInputDevice_QueryInterface(pdev, &IID_IDirectInputDevice2, tp))) - { - CONS_Printf("DIEnumJoysticks2(): QueryInterface FAILED\n"); - IDirectInputDevice_Release (pdev); - return DIENUM_CONTINUE; - } - - if (lpDIJ2A && JoyInfo2.ForceAxises != -1) - { - // Since we will be playing force feedback effects, we should disable the - // auto-centering spring. - if (FAILED(SetDIDwordProperty(pdev, DIPROP_AUTOCENTER, 0, DIPH_DEVICE, FALSE))) - { - //NOP - } - - // Enumerate and count the axes of the joystick - if (FAILED(IDirectInputDevice_EnumObjects(pdev, EnumAxesCallback, - (VOID*)&JoyInfo2.ForceAxises, DIDFT_AXIS))) - { - JoyInfo2.ForceAxises = -1; - } - else - { - SetupAllForces(lpDIJ2A,lpDIE2,JoyInfo2.ForceAxises); - } - } - } - - // we successfully created an IDirectInputDevice. So stop looking - // for another one. - lpDIJ2 = pdev; - return DIENUM_STOP; -} - - -// -------------- -// I_InitJoystick2 -// This is called everytime the 'use_joystick2' variable changes -// It is normally called at least once at startup when the config is loaded -// -------------- -void I_InitJoystick2 (void) -{ - HRESULT hr; - - // cleanup - I_ShutdownJoystick2 (); - - joystick2_detected = false; - - // joystick detection can be skipped by setting use_joystick to 0 - if (M_CheckParm("-nojoy")) - { - CONS_Printf("Joystick2 disabled\n"); - return; - } - else - // don't do anything at the registration of the joystick cvar, - // until config is loaded - if (!lstrcmpA(cv_usejoystick2.string, "0")) - return; - - // acquire the joystick only once - if (!lpDIJ2) - { - joystick2_detected = false; - - CONS_Printf("Looking for joystick devices:\n"); - iJoy2Num = 0; - hr = IDirectInput_EnumDevices(lpDI, DIDEVTYPE_JOYSTICK, - DIEnumJoysticks2, - (void *)&cv_usejoystick2, // our user parameter is joystick number - DIEDFL_ATTACHEDONLY); - if (FAILED(hr)) - { - CONS_Printf("\nI_InitJoystick2(): EnumDevices FAILED\n"); - cv_usejoystick2.value = 0; - return; - } - - if (!lpDIJ2) - { - if (iJoy2Num == 0) - CONS_Printf("none found\n"); - else - { - CONS_Printf("none used\n"); - if (cv_usejoystick2.value > 0 && - cv_usejoystick2.value > iJoy2Num) - { - CONS_Printf("\2Set the use_joystick2 variable to one of the" - " enumerated joysticks number\n"); - } - } - cv_usejoystick2.value = 0; - return; - } - - I_AddExitFunc (I_ShutdownJoystick2); - - // set coop level - if (FAILED(IDirectInputDevice_SetCooperativeLevel (lpDIJ2, hWndMain, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND))) - I_Error("I_InitJoystick2: SetCooperativeLevel FAILED"); - - // later - //if (FAILED(IDirectInputDevice_Acquire (lpDIJ2))) - // I_Error("Couldn't acquire Joystick2"); - - joystick2_detected = true; - } - else - CONS_Printf("Joystick2 already initialized\n"); - - //faB: we don't unacquire joystick, so let's just pretend we re-acquired it - joystick2_detected = true; -} - -/** \brief Joystick 1 buttons states -*/ -static INT64 lastjoybuttons = 0; - -/** \brief Joystick 1 hats state -*/ -static INT64 lastjoyhats = 0; - -static void I_ShutdownJoystick(void) -{ - int i; - event_t event; - - lastjoybuttons = lastjoyhats = 0; - - event.type = ev_keyup; - - // emulate the up of all joystick buttons - for (i = 0;i < JOYBUTTONS;i++) - { - event.data1 = KEY_JOY1+i; - D_PostEvent(&event); - } - - // emulate the up of all joystick hats - for (i = 0;i < JOYHATS*4;i++) - { - event.data1 = KEY_HAT1+i; - D_PostEvent(&event); - } - - // reset joystick position - event.type = ev_joystick; - for (i = 0;i < JOYAXISSET; i++) - { - event.data1 = i; - D_PostEvent(&event); - } - - if (joystick_detected) - CONS_Printf("I_ShutdownJoystick()\n"); - - for (i = 0; i > NumberofForces; i++) - { - if (lpDIE[i]) - { - IDirectInputEffect_Release(lpDIE[i]); - lpDIE[i] = NULL; - - } - } - if (lpDIJ) - { - IDirectInputDevice_Unacquire(lpDIJ); - IDirectInputDevice_Release(lpDIJ); - lpDIJ = NULL; - } - if (lpDIJA) - { - IDirectInputDevice2_Release(lpDIJA); - lpDIJA = NULL; - } - joystick_detected = false; -} - -/** \brief Joystick 2 buttons states -*/ -static INT64 lastjoy2buttons = 0; - -/** \brief Joystick 2 hats state -*/ -static INT64 lastjoy2hats = 0; - -static void I_ShutdownJoystick2(void) -{ - int i; - event_t event; - - lastjoy2buttons = lastjoy2hats = 0; - - event.type = ev_keyup; - - // emulate the up of all joystick buttons - for (i = 0;i < JOYBUTTONS;i++) - { - event.data1 = KEY_2JOY1+i; - D_PostEvent(&event); - } - - // emulate the up of all joystick hats - for (i = 0;i < JOYHATS*4;i++) - { - event.data1 = KEY_2HAT1+i; - D_PostEvent(&event); - } - - // reset joystick position - event.type = ev_joystick2; - for (i = 0;i < JOYAXISSET; i++) - { - event.data1 = i; - D_PostEvent(&event); - } - - if (joystick2_detected) - CONS_Printf("I_ShutdownJoystick2()\n"); - - for (i = 0; i > NumberofForces; i++) - { - if (lpDIE2[i]) - { - IDirectInputEffect_Release(lpDIE2[i]); - lpDIE2[i] = NULL; - } - } - if (lpDIJ2) - { - IDirectInputDevice_Unacquire(lpDIJ2); - IDirectInputDevice_Release(lpDIJ2); - lpDIJ2 = NULL; - } - if (lpDIJ2A) - { - IDirectInputDevice2_Release(lpDIJ2A); - lpDIJ2A = NULL; - } - joystick2_detected = false; -} - -// ------------------- -// I_GetJoystickEvents -// Get current joystick axis and button states -// ------------------- -void I_GetJoystickEvents(void) -{ - HRESULT hr; - DIJOYSTATE js; // DirectInput joystick state - int i; - INT64 joybuttons = 0; - INT64 joyhats = 0; - event_t event; - - if (!lpDIJ) - return; - - // if input is lost then acquire and keep trying - for (;;) - { - // poll the joystick to read the current state - // if the device doesn't require polling, this function returns almost instantly - if (lpDIJA) - { - hr = IDirectInputDevice2_Poll(lpDIJA); - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) - goto acquire; - else if (FAILED(hr)) - { - CONS_Printf("I_GetJoystickEvents(): Poll FAILED\n"); - return; - } - } - - // get the input's device state, and put the state in dims - hr = IDirectInputDevice_GetDeviceState(lpDIJ, sizeof (DIJOYSTATE), &js); - - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) - { - // DirectInput is telling us that the input stream has - // been interrupted. We aren't tracking any state - // between polls, so we don't have any special reset - // that needs to be done. We just re-acquire and - // try again. - goto acquire; - } - else if (FAILED(hr)) - { - CONS_Printf("I_GetJoystickEvents(): GetDeviceState FAILED\n"); - return; - } - - break; -acquire: - if (FAILED(IDirectInputDevice_Acquire(lpDIJ))) - return; - } - - // look for as many buttons as g_input code supports, we don't use the others - for (i = JOYBUTTONS_MIN - 1; i >= 0; i--) - { - joybuttons <<= 1; - if (js.rgbButtons[i]) - joybuttons |= 1; - } - - for (i = JOYHATS_MIN -1; i >=0; i--) - { - if (js.rgdwPOV[i] != 0xffff && js.rgdwPOV[i] != 0xffffffff) - { - if (js.rgdwPOV[i] > 270 * DI_DEGREES || js.rgdwPOV[i] < 90 * DI_DEGREES) - joyhats |= 1<<(0 + 4*i); // UP - else if (js.rgdwPOV[i] > 90 * DI_DEGREES && js.rgdwPOV[i] < 270 * DI_DEGREES) - joyhats |= 1<<(1 + 4*i); // DOWN - if (js.rgdwPOV[i] > 0 * DI_DEGREES && js.rgdwPOV[i] < 180 * DI_DEGREES) - joyhats |= 1<<(3 + 4*i); // LEFT - else if (js.rgdwPOV[i] > 180 * DI_DEGREES && js.rgdwPOV[i] < 360 * DI_DEGREES) - joyhats |= 1<<(2 + 4*i); // RIGHT - } - } - - if (joybuttons != lastjoybuttons) - { - INT64 j = 1; // keep only bits that changed since last time - INT64 newbuttons = joybuttons ^ lastjoybuttons; - lastjoybuttons = joybuttons; - - for (i = 0; i < JOYBUTTONS && i < JOYBUTTONS_MAX; i++, j <<= 1) - { - if (newbuttons & j) // button changed state? - { - if (joybuttons & j) - event.type = ev_keydown; - else - event.type = ev_keyup; - event.data1 = KEY_JOY1 + i; - D_PostEvent(&event); - } - } - } - - if (joyhats != lastjoyhats) - { - INT64 j = 1; // keep only bits that changed since last time - INT64 newhats = joyhats ^ lastjoyhats; - lastjoyhats = joyhats; - - for (i = 0; i < JOYHATS*4 && i < JOYHATS_MAX*4; i++, j <<= 1) - { - if (newhats & j) // button changed state? - { - if (joyhats & j) - event.type = ev_keydown; - else - event.type = ev_keyup; - event.data1 = KEY_HAT1 + i; - D_PostEvent(&event); - } - } - - } - - // send joystick axis positions - event.type = ev_joystick; - event.data1 = event.data2 = event.data3 = 0; - - if (Joystick.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo.X) - { - if (js.lX < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.lX > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo.Y) - { - if (js.lY < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.lY > JOYAXISRANGE/2) - event.data3 = 1; - } - } - else - { - // analog control style, just send the raw data - if (JoyInfo.X) event.data2 = js.lX; // x axis - if (JoyInfo.Y) event.data3 = js.lY; // y axis - } - - D_PostEvent(&event); -#if JOYAXISSET > 1 - event.data1 = 1; - event.data2 = event.data3 = 0; - - if (Joystick.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo.Z) - { - if (js.lZ < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.lZ > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo.Rx) - { - if (js.lRx < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.lRx > JOYAXISRANGE/2) - event.data3 = 1; - } - } - else - { - // analog control style, just send the raw data - if (JoyInfo.Z) event.data2 = js.lZ; // z axis - if (JoyInfo.Rx) event.data3 = js.lRx; // rx axis - } - - D_PostEvent(&event); -#endif -#if JOYAXISSET > 2 - event.data1 = 2; - event.data2 = event.data3 = 0; - - if (Joystick.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo.Rx) - { - if (js.lRy < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.lRy > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo.Rz) - { - if (js.lRz < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.lRz > JOYAXISRANGE/2) - event.data3 = 1; - } - } - else - { - // analog control style, just send the raw data - if (JoyInfo.Ry) event.data2 = js.lRy; // ry axis - if (JoyInfo.Rz) event.data3 = js.lRz; // rz axis - } - - D_PostEvent(&event); -#endif -#if JOYAXISSET > 3 - event.data1 = 3; - event.data2 = event.data3 = 0; - if (Joystick.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo.U) - { - if (js.rglSlider[0] < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.rglSlider[0] > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo.V) - { - if (js.rglSlider[1] < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.rglSlider[1] > JOYAXISRANGE/2) - event.data3 = 1; - } - } - else - { - // analog control style, just send the raw data - if (JoyInfo.U) event.data2 = js.rglSlider[0]; // U axis - if (JoyInfo.V) event.data3 = js.rglSlider[1]; // V axis - } - D_PostEvent(&event); -#endif -} - -// ------------------- -// I_GetJoystickEvents -// Get current joystick axis and button states -// ------------------- -void I_GetJoystick2Events(void) -{ - HRESULT hr; - DIJOYSTATE js; // DirectInput joystick state - int i; - INT64 joybuttons = 0; - INT64 joyhats = 0; - event_t event; - - if (!lpDIJ2) - return; - - // if input is lost then acquire and keep trying - for (;;) - { - // poll the joystick to read the current state - // if the device doesn't require polling, this function returns almost instantly - if (lpDIJ2A) - { - hr = IDirectInputDevice2_Poll(lpDIJ2A); - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) - goto acquire; - else if (FAILED(hr)) - { - CONS_Printf("I_GetJoystick2Events(): Poll FAILED\n"); - return; - } - } - - // get the input's device state, and put the state in dims - hr = IDirectInputDevice_GetDeviceState(lpDIJ2, sizeof (DIJOYSTATE), &js); - - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) - { - // DirectInput is telling us that the input stream has - // been interrupted. We aren't tracking any state - // between polls, so we don't have any special reset - // that needs to be done. We just re-acquire and - // try again. - goto acquire; - } - else if (FAILED(hr)) - { - CONS_Printf("I_GetJoystickEvents2(): GetDeviceState FAILED\n"); - return; - } - - break; -acquire: - if (FAILED(IDirectInputDevice_Acquire(lpDIJ2))) - return; - } - - // look for as many buttons as g_input code supports, we don't use the others - for (i = JOYBUTTONS_MIN - 1; i >= 0; i--) - { - joybuttons <<= 1; - if (js.rgbButtons[i]) - joybuttons |= 1; - } - - for (i = JOYHATS_MIN -1; i >=0; i--) - { - if (js.rgdwPOV[i] != 0xffff && js.rgdwPOV[i] != 0xffffffff) - { - if (js.rgdwPOV[i] > 270 * DI_DEGREES || js.rgdwPOV[i] < 90 * DI_DEGREES) - joyhats |= 1<<(0 + 4*i); // UP - else if (js.rgdwPOV[i] > 90 * DI_DEGREES && js.rgdwPOV[i] < 270 * DI_DEGREES) - joyhats |= 1<<(1 + 4*i); // DOWN - if (js.rgdwPOV[i] > 0 * DI_DEGREES && js.rgdwPOV[i] < 180 * DI_DEGREES) - joyhats |= 1<<(3 + 4*i); // LEFT - else if (js.rgdwPOV[i] > 180 * DI_DEGREES && js.rgdwPOV[i] < 360 * DI_DEGREES) - joyhats |= 1<<(2 + 4*i); // RIGHT - } - } - - if (joybuttons != lastjoy2buttons) - { - INT64 j = 1; // keep only bits that changed since last time - INT64 newbuttons = joybuttons ^ lastjoy2buttons; - lastjoy2buttons = joybuttons; - - for (i = 0; i < JOYBUTTONS && i < JOYBUTTONS_MAX; i++, j <<= 1) - { - if (newbuttons & j) // button changed state? - { - if (joybuttons & j) - event.type = ev_keydown; - else - event.type = ev_keyup; - event.data1 = KEY_2JOY1 + i; - D_PostEvent(&event); - } - } - } - - if (joyhats != lastjoy2hats) - { - INT64 j = 1; // keep only bits that changed since last time - INT64 newhats = joyhats ^ lastjoy2hats; - lastjoy2hats = joyhats; - - for (i = 0; i < JOYHATS*4 && i < JOYHATS_MAX*4; i++, j <<= 1) - { - if (newhats & j) // button changed state? - { - if (joyhats & j) - event.type = ev_keydown; - else - event.type = ev_keyup; - event.data1 = KEY_2HAT1 + i; - D_PostEvent(&event); - } - } - - } - - // send joystick axis positions - event.type = ev_joystick2; - event.data1 = event.data2 = event.data3 = 0; - - if (Joystick2.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo2.X) - { - if (js.lX < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.lX > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo2.Y) - { - if (js.lY < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.lY > JOYAXISRANGE/2) - event.data3 = 1; - } - } - else - { - // analog control style, just send the raw data - if (JoyInfo2.X) event.data2 = js.lX; // x axis - if (JoyInfo2.Y) event.data3 = js.lY; // y axis - } - - D_PostEvent(&event); -#if JOYAXISSET > 1 - event.data1 = 1; - event.data2 = event.data3 = 0; - - if (Joystick2.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo2.Z) - { - if (js.lZ < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.lZ > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo2.Rx) - { - if (js.lRx < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.lRx > JOYAXISRANGE/2) - event.data3 = 1; - } - } - else - { - // analog control style, just send the raw data - if (JoyInfo2.Z) event.data2 = js.lZ; // z axis - if (JoyInfo2.Rx) event.data3 = js.lRx; // rx axis - } - - D_PostEvent(&event); -#endif -#if JOYAXISSET > 2 - event.data1 = 2; - event.data2 = event.data3 = 0; - - if (Joystick2.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo2.Rx) - { - if (js.lRy < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.lRy > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo2.Rz) - { - if (js.lRz < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.lRz > JOYAXISRANGE/2) - event.data3 = 1; - } - } - else - { - // analog control style, just send the raw data - if (JoyInfo2.Ry) event.data2 = js.lRy; // ry axis - if (JoyInfo2.Rz) event.data3 = js.lRz; // rz axis - } - - D_PostEvent(&event); -#endif -#if JOYAXISSET > 3 - event.data1 = 3; - event.data2 = event.data3 = 0; - if (Joystick2.bGamepadStyle) - { - // gamepad control type, on or off, live or die - if (JoyInfo2.U) - { - if (js.rglSlider[0] < -(JOYAXISRANGE/2)) - event.data2 = -1; - else if (js.rglSlider[0] > JOYAXISRANGE/2) - event.data2 = 1; - } - if (JoyInfo2.V) - { - if (js.rglSlider[1] < -(JOYAXISRANGE/2)) - event.data3 = -1; - else if (js.rglSlider[1] > JOYAXISRANGE/2) - event.data3 = 1; - } - } - else - { - // analog control style, just send the raw data - if (JoyInfo2.U) event.data2 = js.rglSlider[0]; // U axis - if (JoyInfo2.V) event.data3 = js.rglSlider[1]; // V axis - } - D_PostEvent(&event); -#endif -} - -static int numofjoy = 0; -static char joyname[MAX_PATH]; -static int needjoy = -1; - -static BOOL CALLBACK DIEnumJoysticksCount (LPCDIDEVICEINSTANCE lpddi, - LPVOID pvRef) //joyname -{ - numofjoy++; - if (needjoy == numofjoy && pvRef && pvRef == (void *)joyname && lpddi - && lpddi->tszProductName) - { - sprintf(joyname,"%s",lpddi->tszProductName); - return DIENUM_STOP; - } - //else if (devparm) CONS_Printf("DIEnumJoysticksCount need help!"); - return DIENUM_CONTINUE; -} - -INT32 I_NumJoys(void) -{ - HRESULT hr; - needjoy = -1; - numofjoy = 0; - hr = IDirectInput_EnumDevices(lpDI, DIDEVTYPE_JOYSTICK, - DIEnumJoysticksCount, (void *)&numofjoy, DIEDFL_ATTACHEDONLY); - if (FAILED(hr)) - CONS_Printf("\nI_NumJoys(): EnumDevices FAILED\n"); - return numofjoy; - -} - -const char *I_GetJoyName(INT32 joyindex) -{ - HRESULT hr; - needjoy = joyindex; - numofjoy = 0; - ZeroMemory(joyname,sizeof (joyname)); - hr = IDirectInput_EnumDevices(lpDI, DIDEVTYPE_JOYSTICK, - DIEnumJoysticksCount, (void *)joyname, DIEDFL_ATTACHEDONLY); - if (FAILED(hr)) - CONS_Printf("\nI_GetJoyName(): EnumDevices FAILED\n"); - if (joyname[0] == 0) return NULL; - return joyname; -} - -// =========================================================================================== -// DIRECT INPUT KEYBOARD -// =========================================================================================== - -static UINT8 ASCIINames[256] = -{ - // 0 1 2 3 4 5 6 7 - // 8 9 A B C D E F - 0, 27, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', KEY_MINUS,KEY_EQUALS,KEY_BACKSPACE, KEY_TAB, - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', KEY_ENTER,KEY_CTRL,'a', 's', - 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', - '\'', '`', KEY_SHIFT, '\\', 'z', 'x', 'c', 'v', - 'b', 'n', 'm', ',', '.', '/', KEY_SHIFT, '*', - KEY_ALT,KEY_SPACE,KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, - KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10,KEY_NUMLOCK,KEY_SCROLLLOCK,KEY_KEYPAD7, - KEY_KEYPAD8,KEY_KEYPAD9,KEY_MINUSPAD,KEY_KEYPAD4,KEY_KEYPAD5,KEY_KEYPAD6,KEY_PLUSPAD,KEY_KEYPAD1, - KEY_KEYPAD2,KEY_KEYPAD3,KEY_KEYPAD0,KEY_KPADDEL,0,0,0, KEY_F11, - KEY_F12,0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - - // 0 1 2 3 4 5 6 7 - // 8 9 A B C D E F - - 0, 0, 0, 0, 0, 0, 0, 0, // 0x80 - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, KEY_ENTER,KEY_CTRL, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0 - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, KEY_KPADDEL, 0,KEY_KPADSLASH,0, 0, - KEY_ALT,0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, KEY_HOME, // 0xc0 - KEY_UPARROW,KEY_PGUP,0,KEY_LEFTARROW,0,KEY_RIGHTARROW,0,KEY_END, - KEY_DOWNARROW,KEY_PGDN, KEY_INS,KEY_DEL,0,0,0,0, - 0, 0, 0,KEY_LEFTWIN,KEY_RIGHTWIN,KEY_MENU, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, // 0xe0 - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -// Return a key that has been pushed, or 0 (replace getchar() at game startup) -// -INT32 I_GetKey(void) -{ - event_t *ev; - - if (eventtail != eventhead) - { - ev = &events[eventtail]; - eventtail = (eventtail+1) & (MAXEVENTS-1); - if (ev->type == ev_keydown || ev->type == ev_console) - return ev->data1; - else - return 0; - } - return 0; -} - -// ----------------- -// I_StartupKeyboard -// Installs DirectInput keyboard -// ----------------- -#define DI_KEYBOARD_BUFFERSIZE 32 // number of data elements in keyboard buffer - -void I_StartupKeyboard(void) -{ - DIPROPDWORD dip; - - if (dedicated) - return; - - // make sure the app window has the focus or DirectInput acquire keyboard won't work - if (hWndMain) - { - SetFocus(hWndMain); - ShowWindow(hWndMain, SW_SHOW); - UpdateWindow(hWndMain); - } - - // detect error - if (lpDIK) - { - CONS_Printf("\2I_StartupKeyboard(): called twice\n"); - return; - } - - CreateDevice2(lpDI, &GUID_SysKeyboard, &lpDIK, NULL); - - if (lpDIK) - { - if (FAILED(IDirectInputDevice_SetDataFormat(lpDIK, &c_dfDIKeyboard))) - I_Error("Couldn't set keyboard data format"); - - // create buffer for buffered data - dip.diph.dwSize = sizeof (dip); - dip.diph.dwHeaderSize = sizeof (dip.diph); - dip.diph.dwObj = 0; - dip.diph.dwHow = DIPH_DEVICE; - dip.dwData = DI_KEYBOARD_BUFFERSIZE; - if (FAILED(IDirectInputDevice_SetProperty(lpDIK, DIPROP_BUFFERSIZE, &dip.diph))) - I_Error("Couldn't set keyboard buffer size"); - - if (FAILED(IDirectInputDevice_SetCooperativeLevel(lpDIK, hWndMain, - DISCL_NONEXCLUSIVE|DISCL_FOREGROUND))) - { - I_Error("Couldn't set keyboard coop level"); - } - } - else - I_Error("Couldn't create keyboard input"); - - I_AddExitFunc(I_ShutdownKeyboard); - hacktics = 0; // see definition - keyboard_started = true; -} - -// ------------------ -// I_ShutdownKeyboard -// Release DirectInput keyboard. -// ------------------ -static void I_ShutdownKeyboard(void) -{ - if (!keyboard_started) - return; - - CONS_Printf("I_ShutdownKeyboard()\n"); - - if (lpDIK) - { - IDirectInputDevice_Unacquire(lpDIK); - IDirectInputDevice_Release(lpDIK); - lpDIK = NULL; - } - - keyboard_started = false; -} - -// ------------------- -// I_GetKeyboardEvents -// Get buffered data from the keyboard -// ------------------- -static void I_GetKeyboardEvents(void) -{ - static boolean KeyboardLost = false; - - // simply repeat the last pushed key every xx tics, - // make more user friendly input for Console and game Menus -#define KEY_REPEAT_DELAY (TICRATE/17) // TICRATE tics, repeat every 1/3 second - static long RepeatKeyTics = 0; - static int RepeatKeyCode; - - DIDEVICEOBJECTDATA rgdod[DI_KEYBOARD_BUFFERSIZE]; - DWORD dwItems, d; - HRESULT hr; - int ch; - - event_t event; - ZeroMemory(&event,sizeof (event)); - - if (!keyboard_started) - return; - - if (!appActive && RepeatKeyCode) // Stop when lost focus - { - event.type = ev_keyup; - event.data1 = RepeatKeyCode; - D_PostEvent(&event); - RepeatKeyCode = 0; - } -getBufferedData: - dwItems = DI_KEYBOARD_BUFFERSIZE; - hr = IDirectInputDevice_GetDeviceData(lpDIK, sizeof (DIDEVICEOBJECTDATA), rgdod, &dwItems, 0); - - // If data stream was interrupted, reacquire the device and try again. - if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) - { - // why it succeeds to acquire just after I don't understand.. so I set the flag BEFORE - KeyboardLost = true; - - hr = IDirectInputDevice_Acquire(lpDIK); - if (SUCCEEDED(hr)) - goto getBufferedData; - return; - } - - // we lost data, get device actual state to recover lost information - if (hr == DI_BUFFEROVERFLOW) - { - /// \note either uncomment or delete block - //I_Error("DI buffer overflow (keyboard)"); - //I_RecoverKeyboardState (); - - //hr = IDirectInputDevice_GetDeviceState (lpDIM, sizeof (keys), &diMouseState); - } - - // We got buffered input, act on it - if (SUCCEEDED(hr)) - { - // if we previously lost keyboard data, recover its current state - if (KeyboardLost) - { - /// \bug hack simply clears the keys so we don't have the last pressed keys - /// still active.. to have to re-trigger it is not much trouble for the user. - ZeroMemory(gamekeydown, NUMKEYS); - KeyboardLost = false; - } - - // dwItems contains number of elements read (could be 0) - for (d = 0; d < dwItems; d++) - { - // dwOfs member is DIK_* value - // dwData member 0x80 bit set press down, clear is release - - if (rgdod[d].dwData & 0x80) - event.type = ev_keydown; - else - event.type = ev_keyup; - - ch = rgdod[d].dwOfs & UINT8_MAX; - if (ASCIINames[ch]) - event.data1 = ASCIINames[ch]; - else - event.data1 = 0x80; - - D_PostEvent(&event); - } - - // Key Repeat - if (dwItems) - { - // new key events, so stop repeating key - RepeatKeyCode = 0; - // delay is tripled for first repeating key - RepeatKeyTics = hacktics + (KEY_REPEAT_DELAY*2); - if (event.type == ev_keydown) // use the last event! - RepeatKeyCode = event.data1; - } - else - { - // no new keys, repeat last pushed key after some time - if (RepeatKeyCode && hacktics - RepeatKeyTics > KEY_REPEAT_DELAY) - { - event.type = ev_keydown; - event.data1 = RepeatKeyCode; - D_PostEvent(&event); - - RepeatKeyTics = hacktics; - } - } - } -} - -// -// Closes DirectInput -// -static void I_ShutdownDirectInput(void) -{ - if (lpDI) - IDirectInput_Release(lpDI); - lpDI = NULL; -} - -// This stuff should get rid of the exception and page faults when -// SRB2 bugs out with an error. Now it should exit cleanly. -// -INT32 I_StartupSystem(void) -{ - HRESULT hr; - - // some 'more global than globals' things to initialize here ? - graphics_started = keyboard_started = sound_started = cdaudio_started = false; - - I_DetectWin9x(); - - // check for OS type and version here? -#ifdef NDEBUG - signal(SIGABRT, signal_handler); - signal(SIGFPE, signal_handler); - signal(SIGILL, signal_handler); - signal(SIGSEGV, signal_handler); - signal(SIGTERM, signal_handler); - signal(SIGINT, signal_handler); -#endif - - // create DirectInput - so that I_StartupKeyboard/Mouse can be called later on - // from D_SRB2Main just like DOS version - hr = DirectInputCreate(myInstance, DIRECTINPUT_VERSION, &lpDI, NULL); - - if (SUCCEEDED(hr)) - bDX0300 = FALSE; - else - { - // try opening DirectX3 interface for NT compatibility - hr = DirectInputCreate(myInstance, DXVERSION_NTCOMPATIBLE, &lpDI, NULL); - - if (FAILED(hr)) - { - const char *sErr; - switch (hr) - { - case DIERR_BETADIRECTINPUTVERSION: - sErr = "DIERR_BETADIRECTINPUTVERSION"; - break; - case DIERR_INVALIDPARAM: - sErr = "DIERR_INVALIDPARAM"; - break; - case DIERR_OLDDIRECTINPUTVERSION : - sErr = "DIERR_OLDDIRECTINPUTVERSION"; - break; - case DIERR_OUTOFMEMORY: - sErr = "DIERR_OUTOFMEMORY"; - break; - default: - sErr = "UNKNOWN"; - break; - } - I_Error("Couldn't create DirectInput (reason: %s)", sErr); - } - else - CONS_Printf("\2Using DirectX3 interface\n"); - - // only use DirectInput3 compatible structures and calls - bDX0300 = TRUE; - } - I_AddExitFunc(I_ShutdownDirectInput); - return 0; -} - -// Closes down everything. This includes restoring the initial -// palette and video mode, and removing whatever mouse, keyboard, and -// timer routines have been installed. -// -/// \bug doesn't restore wave/midi device volume -// -// Shutdown user funcs are effectively called in reverse order. -// -void I_ShutdownSystem(void) -{ - int c; - - for (c = MAX_QUIT_FUNCS - 1; c >= 0; c--) - if (quit_funcs[c]) - (*quit_funcs[c])(); -} - -// --------------- -// I_SaveMemToFile -// Save as much as iLength bytes starting at pData, to -// a new file of given name. The file is overwritten if it is present. -// --------------- -BOOL I_SaveMemToFile(const void *pData, size_t iLength, const char *sFileName) -{ - HANDLE fileHandle; - DWORD bytesWritten; - - fileHandle = CreateFileA(sFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH, NULL); - if (fileHandle == (HANDLE)-1) - { - CONS_Printf("SaveMemToFile: Error opening file %s",sFileName); - return FALSE; - } - WriteFile(fileHandle, pData, (DWORD)iLength, &bytesWritten, NULL); - CloseHandle(fileHandle); - return TRUE; -} - -// my god how win32 suck -typedef BOOL (WINAPI *MyFunc)(LPCSTR RootName, PULARGE_INTEGER pulA, PULARGE_INTEGER pulB, PULARGE_INTEGER pulFreeBytes); - -void I_GetDiskFreeSpace(INT64* freespace) -{ - static MyFunc pfnGetDiskFreeSpaceEx = NULL; - static boolean testwin95 = false; - ULARGE_INTEGER usedbytes, lfrespace; - - if (!testwin95) - { - HMODULE h = GetModuleHandleA("kernel32.dll"); - - if (h) - pfnGetDiskFreeSpaceEx = (MyFunc)GetProcAddress(h, "GetDiskFreeSpaceExA"); - testwin95 = true; - } - if (pfnGetDiskFreeSpaceEx) - { - if (pfnGetDiskFreeSpaceEx(NULL, &lfreespace, &usedbytes, NULL)) - *freespace = lfreespace.QuadPart; - else - *freespace = INT32_MAX; - } - else - { - DWORD SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters; - GetDiskFreeSpace(NULL, &SectorsPerCluster, &BytesPerSector, - &NumberOfFreeClusters, &TotalNumberOfClusters); - *freespace = BytesPerSector * SectorsPerCluster * NumberOfFreeClusters; - } -} - -char *I_GetUserName(void) -{ - static char username[MAXPLAYERNAME+1]; - char *p; - DWORD i = MAXPLAYERNAME; - - if (!GetUserNameA(username, &i)) - { - p = getenv("USER"); - if (!p) - { - p = getenv("user"); - if (!p) - { - p = getenv("USERNAME"); - if (!p) - { - p = getenv("username"); - if (!p) - { - return NULL; - } - } - } - } - strncpy(username, p, MAXPLAYERNAME); - } - - if (!strlen(username)) - return NULL; - return username; -} - -INT32 I_mkdir(const char *dirname, INT32 unixright) -{ - (void)unixright; /// \todo should implement ntright under nt... - return CreateDirectoryA(dirname, NULL); -} - -char * I_GetEnv(const char *name) -{ - return getenv(name); -} - -INT32 I_PutEnv(char *variable) -{ - return putenv(variable); -} - -INT32 I_ClipboardCopy(const char *data, size_t size) -{ - (void)data; - (void)size; - return -1; -} - -char *I_ClipboardPaste(void) -{ - return NULL; -} - -typedef BOOL (WINAPI *MyFunc3) (DWORD); - -const CPUInfoFlags *I_CPUInfo(void) -{ - static CPUInfoFlags WIN_CPUInfo; - static MyFunc3 pfnCPUID = NULL; - SYSTEM_INFO SI; - HMODULE h = GetModuleHandleA("kernel32.dll"); - - if (h) - pfnCPUID = (MyFunc3)GetProcAddress(h, "IsProcessorFeaturePresent"); - ZeroMemory(&WIN_CPUInfo,sizeof (WIN_CPUInfo)); - if(pfnCPUID) - { - WIN_CPUInfo.FPPE = pfnCPUID( 0); //PF_FLOATING_POINT_PRECISION_ERRATA - WIN_CPUInfo.FPE = pfnCPUID( 1); //PF_FLOATING_POINT_EMULATED - WIN_CPUInfo.cmpxchg = pfnCPUID( 2); //PF_COMPARE_EXCHANGE_DOUBLE - WIN_CPUInfo.MMX = pfnCPUID( 3); //PF_MMX_INSTRUCTIONS_AVAILABLE - WIN_CPUInfo.PPCMM64 = pfnCPUID( 4); //PF_PPC_MOVEMEM_64BIT_OK - WIN_CPUInfo.ALPHAbyte = pfnCPUID( 5); //PF_ALPHA_BYTE_INSTRUCTIONS - WIN_CPUInfo.SSE = pfnCPUID( 6); //PF_XMMI_INSTRUCTIONS_AVAILABLE - WIN_CPUInfo.AMD3DNow = pfnCPUID( 7); //PF_3DNOW_INSTRUCTIONS_AVAILABLE - WIN_CPUInfo.RDTSC = pfnCPUID( 8); //PF_RDTSC_INSTRUCTION_AVAILABLE - WIN_CPUInfo.PAE = pfnCPUID( 9); //PF_PAE_ENABLED - WIN_CPUInfo.SSE2 = pfnCPUID(10); //PF_XMMI64_INSTRUCTIONS_AVAILABLE - //WIN_CPUInfo.blank = pfnCPUID(11); //PF_SSE_DAZ_MODE_AVAILABLE - WIN_CPUInfo.DEP = pfnCPUID(12); //PF_NX_ENABLED - WIN_CPUInfo.SSE3 = pfnCPUID(13); //PF_SSE3_INSTRUCTIONS_AVAILABLE - WIN_CPUInfo.cmpxchg16b = pfnCPUID(14); //PF_COMPARE_EXCHANGE128 - WIN_CPUInfo.cmp8xchg16 = pfnCPUID(15); //PF_COMPARE64_EXCHANGE128 - WIN_CPUInfo.PFC = pfnCPUID(15); //PF_CHANNELS_ENABLED - } - GetSystemInfo(&SI); - WIN_CPUInfo.CPUs = SI.dwNumberOfProcessors; - WIN_CPUInfo.IA64 = (SI.dwProcessorType == 2200); // PROCESSOR_INTEL_IA64 - WIN_CPUInfo.AMD64 = (SI.dwProcessorType == 8664); // PROCESSOR_AMD_X8664 - return &WIN_CPUInfo; -} - -UINT64 I_FileSize(const char *filename) -{ - HANDLE fileHandle; - DWORD dwSizeHigh, dwSizeLow; - UINT64 fileSize = (UINT64)-1; - - fileHandle = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - 0, NULL); - if (fileHandle == (HANDLE)-1) - goto erroropening; - dwSizeLow = GetFileSize(fileHandle,&dwSizeHigh); - if (dwSizeLow == 0xFFFFFFFF && GetLastError() != NO_ERROR) - goto errorsizing; - fileSize = ((UINT64)(dwSizeHigh)<<32) + dwSizeLow; -errorsizing: - CloseHandle(fileHandle); -erroropening: - return fileSize; -} diff --git a/src/win32ce/win_vid.c b/src/win32ce/win_vid.c deleted file mode 100644 index 4724ca40d..000000000 --- a/src/win32ce/win_vid.c +++ /dev/null @@ -1,865 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// Copyright (C) 1998-2000 by DooM Legacy Team. -// -// 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 2 -// 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. -//----------------------------------------------------------------------------- -/// \file -/// \brief win32 video driver for Doom Legacy - -#include "../doomdef.h" - -#include <stdlib.h> -#include <stdarg.h> - -#include "../d_clisrv.h" -#include "../i_system.h" -#include "../m_argv.h" -#include "../v_video.h" -#include "../st_stuff.h" -#include "../i_video.h" -#include "../z_zone.h" -#include "fabdxlib.h" - -#include "win_main.h" -#include "../command.h" -#include "../screen.h" - -#ifdef HWRENDER -#include "win_dll.h" // loading the render DLL -#include "../hardware/hw_drv.h" // calling driver init & shutdown -#include "../hardware/hw_main.h" // calling HWR module init & shutdown -#endif - -// ------- -// Globals -// ------- - -// this is the CURRENT rendermode!! very important: used by w_wad, and much other code -rendermode_t rendermode = render_soft; - -// synchronize page flipping with screen refresh -consvar_t cv_vidwait = {"vid_wait", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; -static consvar_t cv_stretch = {"stretch", "On", CV_SAVE|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; - -boolean highcolor; - -static BOOL bDIBMode; // means we are using DIB instead of DirectDraw surfaces -static BITMAPINFO* bmiMain = NULL; -static HDC hDCMain = NULL; - -// ----------------- -// Video modes stuff -// ----------------- - -#define MAX_EXTRA_MODES 36 -static vmode_t extra_modes[MAX_EXTRA_MODES] = {{NULL, NULL, 0, 0, 0, 0, 0, 0, NULL, NULL, 0}}; -static char names[MAX_EXTRA_MODES][10]; - -static int numvidmodes; // total number of DirectDraw display modes -static vmode_t *pvidmodes; // start of videomodes list. -static vmode_t *pcurrentmode; // the current active videomode. -static BOOL bWinParm; -static int WINAPI VID_SetWindowedDisplayMode(viddef_t *lvid, vmode_t *pcurrentmode); - -// this holds description of the startup video mode, -// the resolution is 320x200, windowed on the desktop -#define NUMSPECIALMODES 1 -static char winmode1[] ="320x200W"; // W to make sure it's the windowed mode -static vmode_t specialmodes[NUMSPECIALMODES] = -{ - { - NULL, - winmode1, // hehe - 320, 200, //(200.0/320.0)*(320.0/240.0), - 320, 1, // rowbytes, bytes per pixel - 1, 2, // windowed (TRUE), numpages - NULL, - VID_SetWindowedDisplayMode, 0 - } -}; - -// ------ -// Protos -// ------ -static void VID_Command_NumModes_f(void); -static void VID_Command_ModeInfo_f(void); -static void VID_Command_ModeList_f(void); -static void VID_Command_Mode_f(void); -static int WINAPI VID_SetDirectDrawMode(viddef_t *lvid, vmode_t *pcurrentmode); -static vmode_t *VID_GetModePtr(int modenum); -static void VID_Init(void); -static BOOL VID_FreeAndAllocVidbuffer(viddef_t *lvid); - -// ----------------- -// I_StartupGraphics -// Initialize video mode, setup dynamic screen size variables, -// and allocate screens. -// ----------------- -void I_StartupGraphics(void) -{ - if (graphics_started) - return; - -#ifdef HWRENDER - if (M_CheckParm("-opengl")) - rendermode = render_opengl; - else - rendermode = render_soft; -#endif - - if (dedicated) - rendermode = render_none; - else - VID_Init(); - - // register exit code for graphics - I_AddExitFunc(I_ShutdownGraphics); - if (!dedicated) graphics_started = true; -} - -// ------------------ -// I_ShutdownGraphics -// Close the screen, restore previous video mode. -// ------------------ -void I_ShutdownGraphics(void) -{ - if (!graphics_started) - return; - - CONS_Printf("I_ShutdownGraphics()\n"); - - //FreeConsole(); - - // release windowed startup stuff - if (hDCMain) - { - ReleaseDC(hWndMain, hDCMain); - hDCMain = NULL; - } - if (bmiMain) - { - GlobalFree(bmiMain); - bmiMain = NULL; - } - -#ifdef HWRENDER - if (rendermode != render_soft) - { - HWR_Shutdown(); // free stuff from the hardware renderer - HWD.pfnShutdown(); // close 3d card display - Shutdown3DDriver(); // free the driver DLL - } -#endif - - // free the last video mode screen buffers - if (vid.buffer) - { - GlobalFree(vid.buffer); - vid.buffer = NULL; - } - -#ifdef HWRENDER - if (rendermode == render_soft) -#endif - CloseDirectDraw(); - - graphics_started = false; -} - -// -------------- -// I_UpdateNoBlit -// -------------- -void I_UpdateNoBlit(void) -{ - // what is this? -} - -// -------------- -// I_FinishUpdate -// -------------- -void I_FinishUpdate(void) -{ - int i; - - if (rendermode == render_none) - return; - - // draw captions if enabled - if (cv_closedcaptioning.value) - SCR_ClosedCaptions(); - - // display a graph of ticrate - if (cv_ticrate.value) - SCR_DisplayTicRate(); - - // - if (bDIBMode) - { - // paranoia - if (!hDCMain || !bmiMain || !vid.buffer) - return; - // main game loop, still in a window (-win parm) - SetDIBitsToDevice(hDCMain, 0, 0, 320, 200, 0, 0, 0, 200, vid.buffer, bmiMain, - DIB_RGB_COLORS); - } - else -#ifdef HWRENDER - if (rendermode != render_soft) - HWD.pfnFinishUpdate(cv_vidwait.value); - else -#endif - { - // DIRECT DRAW - // copy virtual screen to real screen - // can fail when not active (alt-tab) - if (LockScreen()) - { - /// \todo use directX blit here!!? a blit might use hardware with access - /// to main memory on recent hardware, and software blit of directX may be - /// optimized for p2 or mmx?? - VID_BlitLinearScreen(screens[0], ScreenPtr, vid.width*vid.bpp, vid.height, - vid.width*vid.bpp, ScreenPitch); - - UnlockScreen(); - - // swap screens - ScreenFlip(cv_vidwait.value); - } - } -} - -// -// This is meant to be called only by CONS_Printf() while game startup -// -void I_LoadingScreen(LPCSTR msg) -{ - RECT rect; - - // paranoia - if (!hDCMain || !bmiMain || !vid.buffer) - return; - - GetClientRect(vid.WndParent, &rect); - - SetDIBitsToDevice(hDCMain, 0, 0, 320, 200, 0, 0, 0, 200, vid.buffer, bmiMain, DIB_RGB_COLORS); - - if (msg) - { - if (rect.bottom - rect.top > 32) - rect.top = rect.bottom - 32; // put msg on bottom of window - SetBkMode(hDCMain, TRANSPARENT); - SetTextColor(hDCMain, RGB(0x00, 0x00, 0x00)); - DrawTextA(hDCMain, msg, -1, &rect, DT_WORDBREAK|DT_CENTER); - } -} - -// ------------ -// I_ReadScreen -// ------------ -void I_ReadScreen(UINT8 *scr) -{ - // DEBUGGING - if (rendermode != render_soft) - I_Error("I_ReadScreen: called while in non-software mode"); - VID_BlitLinearScreen(screens[0], scr, vid.width*vid.bpp, vid.height, vid.width*vid.bpp, - vid.rowbytes); -} - -// ------------ -// I_SetPalette -// ------------ -void I_SetPalette(RGBA_t *palette) -{ - int i; - - if (bDIBMode) - { - // set palette in RGBQUAD format, NOT THE SAME ORDER as PALETTEENTRY, grmpf! - RGBQUAD *pColors; - pColors = (RGBQUAD *)((char *)bmiMain + bmiMain->bmiHeader.biSize); - ZeroMemory(pColors, sizeof (RGBQUAD)*256); - for (i = 0; i < 256; i++, pColors++, palette++) - { - pColors->rgbRed = palette->s.red; - pColors->rgbGreen = palette->s.green; - pColors->rgbBlue = palette->s.blue; - } - } - else -#ifdef HWRENDER - if (rendermode == render_soft) -#endif - { - PALETTEENTRY mainpal[256]; - - // this clears the 'flag' for each color in palette - ZeroMemory(mainpal, sizeof mainpal); - - // set palette in PALETTEENTRY format - for (i = 0; i < 256; i++, palette++) - { - mainpal[i].peRed = palette->s.red; - mainpal[i].peGreen = palette->s.green; - mainpal[i].peBlue = palette->s.blue; - } - SetDDPalette(mainpal); // set DirectDraw palette - } -} - -// -// return number of video modes in pvidmodes list -// -INT32 VID_NumModes(void) -{ - return numvidmodes - NUMSPECIALMODES; //faB: dont accept the windowed mode 0 -} - -// return a video mode number from the dimensions -// returns any available video mode if the mode was not found -INT32 VID_GetModeForSize(INT32 w, INT32 h) -{ - vmode_t *pv = pvidmodes; - int modenum = 0; - - // skip the special modes so that it finds only fullscreen modes - for (; pv && modenum < NUMSPECIALMODES; pv = pv->pnext, ++modenum); - for (; pv; pv = pv->pnext, ++modenum) - if (pv->width == (unsigned)w && pv->height == (unsigned)h) - return modenum; - - // if not found, return the first mode available, - // preferably a full screen mode (all modes after the 'specialmodes') - if (numvidmodes > NUMSPECIALMODES) - return NUMSPECIALMODES; // use first full screen mode - - return 0; // no fullscreen mode, use windowed mode -} - -// -// Enumerate DirectDraw modes available -// -static int nummodes = 0; -static BOOL GetExtraModesCallback(int width, int height, int bpp) -{ - CONS_Printf("mode %d x %d x %d bpp\n", width, height, bpp); - - // skip all unwanted modes - if (highcolor && bpp != 15) - goto skip; - if (!highcolor && bpp != 8) - goto skip; - - if (bpp > 16 || width > MAXVIDWIDTH || height > MAXVIDHEIGHT) - goto skip; - - // check if we have space for this mode - if (nummodes >= MAX_EXTRA_MODES) - { - CONS_Printf("mode skipped (too many)\n"); - return FALSE; - } - - // store mode info - extra_modes[nummodes].pnext = &extra_modes[nummodes+1]; - memset(names[nummodes], 0, 10); - snprintf(names[nummodes], 9, "%dx%d", width, height); - - extra_modes[nummodes].name = names[nummodes]; - extra_modes[nummodes].width = width; - extra_modes[nummodes].height = height; - - // exactly, the current FinishUdpate() gets the rowbytes itself after locking the video buffer - // so for now we put anything here - extra_modes[nummodes].rowbytes = width; - extra_modes[nummodes].windowed = false; - extra_modes[nummodes].misc = 0; // unused - extra_modes[nummodes].pextradata = NULL; - extra_modes[nummodes].setmode = VID_SetDirectDrawMode; - - extra_modes[nummodes].numpages = 2; // double-buffer (but this value is unused) - - extra_modes[nummodes].bytesperpixel = (bpp+1)>>3; - - nummodes++; -skip: - return TRUE; -} - -// -// Collect info about DirectDraw display modes we use -// -static inline void VID_GetExtraModes(void) -{ - nummodes = 0; - EnumDirectDrawDisplayModes(GetExtraModesCallback); - - // add the extra modes (not 320x200) at the start of the mode list (if there are any) - if (nummodes) - { - extra_modes[nummodes-1].pnext = NULL; - pvidmodes = &extra_modes[0]; - numvidmodes += nummodes; - } -} - -// --------------- -// WindowMode_Init -// Add windowed modes to the start of the list, -// mode 0 is used for windowed console startup (works on all computers with no DirectX) -// --------------- -static void WindowMode_Init(void) -{ - specialmodes[NUMSPECIALMODES-1].pnext = pvidmodes; - pvidmodes = &specialmodes[0]; - numvidmodes += NUMSPECIALMODES; -} - -// ************************************************************************************* -// VID_Init -// Initialize Video modes subsystem -// ************************************************************************************* -static void VID_Init(void) -{ - vmode_t *pv; - int iMode; - - // if '-win' is specified on the command line, do not add DirectDraw modes - bWinParm = M_CheckParm("-win"); - - COM_AddCommand("vid_nummodes", VID_Command_NumModes_f); - COM_AddCommand("vid_modeinfo", VID_Command_ModeInfo_f); - COM_AddCommand("vid_modelist", VID_Command_ModeList_f); - COM_AddCommand("vid_mode", VID_Command_Mode_f); - - CV_RegisterVar(&cv_vidwait); - CV_RegisterVar(&cv_stretch); - - // setup the videmodes list, - // note that mode 0 must always be VGA mode 0x13 - pvidmodes = pcurrentmode = NULL; - numvidmodes = 0; - - // store the main window handle in viddef struct - SetWindowPos(hWndMain, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE|SWP_NOSENDCHANGING|SWP_NOSIZE|SWP_NOMOVE); - vid.WndParent = hWndMain; - vid.buffer = NULL; - - // we startup in windowed mode using DIB bitmap - // we will use DirectDraw when switching fullScreen and entering main game loop - bDIBMode = TRUE; - bAppFullScreen = FALSE; - -#ifdef HWRENDER - // initialize the appropriate display device - if (rendermode != render_soft) - { - const char *drvname = NULL; - - switch (rendermode) - { - case render_opengl: - drvname = "r_opengl.dll"; - break; - default: - I_Error("Unknown hardware render mode"); - } - - // load the DLL - if (drvname && Init3DDriver(drvname)) - { - int hwdversion = HWD.pfnGetRenderVersion(); - if (hwdversion != VERSION) - CONS_Printf("WARNING: This r_opengl version is not supported, use it at your own risk.\n"); - - // perform initialisations - HWD.pfnInit(I_Error); - // get available display modes for the device - HWD.pfnGetModeList(&pvidmodes, &numvidmodes); - } - else - { - switch (rendermode) - { - case render_opengl: - I_Error("Error initializing OpenGL"); - default: - break; - } - rendermode = render_soft; - } - } - - if (rendermode == render_soft) -#endif - if (!bWinParm) - { - if (!CreateDirectDrawInstance()) - I_Error("Error initializing DirectDraw"); - // get available display modes for the device - VID_GetExtraModes(); - } - - // the game boots in 320x200 standard VGA, but - // we need a highcolor mode to run the game in highcolor - if (highcolor && !numvidmodes) - I_Error("Cannot run in highcolor - No 15bit highcolor DirectX video mode found."); - - // add windowed mode at the start of the list, very important! - WindowMode_Init(); - - if (!numvidmodes) - I_Error("No display modes available."); - - // DEBUG - for (iMode = 0, pv = pvidmodes; pv; pv = pv->pnext, iMode++) - CONS_Printf("#%02d: %dx%dx%dbpp (desc: '%s')\n", iMode, pv->width, pv->height, - pv->bytesperpixel, pv->name); - - // set the startup screen in a window - VID_SetMode(0); -} - -// -------------------------- -// VID_SetWindowedDisplayMode -// Display the startup 320x200 console screen into a window on the desktop, -// switching to fullscreen display only when we will enter the main game loop. -// - we can display error message boxes for startup errors -// - we can set the last used resolution only once, when entering the main game loop -// -------------------------- -static int WINAPI VID_SetWindowedDisplayMode(viddef_t *lvid, vmode_t *pcurrentmode) -{ - int iScrWidth, iScrHeight, iWinWidth, iWinHeight; - - pcurrentmode = NULL; -#ifdef DEBUG - CONS_Printf("VID_SetWindowedDisplayMode()\n"); -#endif - - lvid->u.numpages = 1; // not used - lvid->direct = NULL; // DOS remains - lvid->buffer = NULL; - - // allocate screens - if (!VID_FreeAndAllocVidbuffer(lvid)) - return -1; - - // lvid->buffer should be NULL here! - - bmiMain = (void *)GlobalAlloc(GPTR, sizeof (BITMAPINFO) + (sizeof (RGBQUAD)*256)); - if (!bmiMain) - I_Error("VID_SWDM(): No mem"); - - // setup a BITMAPINFO to allow copying our video buffer to the desktop, - // with color conversion as needed - bmiMain->bmiHeader.biSize = sizeof (BITMAPINFOHEADER); - bmiMain->bmiHeader.biWidth = lvid->width; - bmiMain->bmiHeader.biHeight= -(lvid->height); - bmiMain->bmiHeader.biPlanes = 1; - bmiMain->bmiHeader.biBitCount = 8; - bmiMain->bmiHeader.biCompression = BI_RGB; - - // center window on the desktop - iScrWidth = GetSystemMetrics(SM_CXFULLSCREEN); - iScrHeight = GetSystemMetrics(SM_CYFULLSCREEN); - - iWinWidth = lvid->width; - iWinWidth += GetSystemMetrics(SM_CXFIXEDFRAME) * 2; - - iWinHeight = lvid->height; - iWinHeight += GetSystemMetrics(SM_CYCAPTION); - iWinHeight += GetSystemMetrics(SM_CYFIXEDFRAME) * 2; - - if (devparm) - MoveWindow(hWndMain, (iScrWidth - iWinWidth), (iScrHeight - iWinHeight), iWinWidth, iWinHeight, TRUE); - else - MoveWindow(hWndMain, (iScrWidth - iWinWidth)>>1, (iScrHeight - iWinHeight)>>1, iWinWidth, iWinHeight, TRUE); - - SetFocus(hWndMain); - ShowWindow(hWndMain, SW_SHOW); - - hDCMain = GetDC(hWndMain); - if (!hDCMain) - I_Error("VID_SWDM(): GetDC FAILED"); - - return 1; -} - -// ======================================================================== -// Returns a vmode_t from the video modes list, given a video mode number. -// ======================================================================== -vmode_t *VID_GetModePtr(int modenum) -{ - vmode_t *pv; - - pv = pvidmodes; - if (!pv) - I_Error("VID_error: No video mode found\n"); - - while (modenum--) - { - pv = pv->pnext; - if (!pv) - I_Error("VID_error: Mode not available\n"); - } - return pv; -} - -// -// return the name of a video mode -// -const char *VID_GetModeName(INT32 modenum) -{ - return (VID_GetModePtr(modenum))->name; -} - -// ======================================================================== -// Sets a video mode -// ======================================================================== -INT32 VID_SetMode(INT32 modenum) -{ - int stat; - vmode_t *pnewmode; - vmode_t *poldmode; - - if (dedicated) - return 0; - - CONS_Printf("VID_SetMode(%d)\n", modenum); - - // if mode 0 (windowed) we must not be fullscreen already, - // if other mode, check it is not mode 0 and existing - if (modenum >= numvidmodes) - { - if (!pcurrentmode) - modenum = 0; // revert to the default base vid mode - else - I_Error("Unknown video mode: %d\n", modenum); - } - else if (bAppFullScreen && modenum < NUMSPECIALMODES) - I_Error("Tried to switch from fullscreen back to windowed mode %d\n", modenum); - - pnewmode = VID_GetModePtr(modenum); - - // dont switch to the same display mode - if (pnewmode == pcurrentmode) - return 1; - - // initialize the new mode - poldmode = pcurrentmode; - pcurrentmode = pnewmode; - - // initialize vidbuffer size for setmode - vid.width = pcurrentmode->width; - vid.height = pcurrentmode->height; - vid.rowbytes = pcurrentmode->rowbytes; - vid.bpp = pcurrentmode->bytesperpixel; - if (modenum) // if not 320x200 windowed mode, it's actually a hack - { - if (rendermode == render_opengl) - { - // don't accept depth < 16 for OpenGL mode (too much ugly) - if (cv_scr_depth.value < 16) - CV_SetValue(&cv_scr_depth, 16); - vid.bpp = cv_scr_depth.value/8; - vid.u.windowed = (bWinParm || !cv_fullscreen.value); - pcurrentmode->bytesperpixel = vid.bpp; - pcurrentmode->windowed = vid.u.windowed; - } - } - - stat = (*pcurrentmode->setmode)(&vid, pcurrentmode); - - if (stat == -1) - I_Error("Not enough mem for VID_SetMode\n"); - else if (stat == -2) - I_Error("Couldn't set video mode because it failed the test\n"); - else if (stat == -3) - I_Error("Couldn't set video mode because it failed the change?\n"); - else if (!stat) - I_Error("Couldn't set video mode %d (%dx%d %d bits)\n", modenum, vid.width, vid.height, (vid.bpp*8));// hardware could not setup mode - else - CONS_Printf(M_GetText("Mode changed to %d (%s)\n"), modenum, pcurrentmode->name); - - vid.modenum = modenum; - - // tell game engine to recalc all tables and realloc buffers based on new values - vid.recalc = 1; - - if (modenum < NUMSPECIALMODES) - { - // we are in startup windowed mode - bAppFullScreen = FALSE; - bDIBMode = TRUE; - } - else - { - // we switch to fullscreen - bAppFullScreen = TRUE; - bDIBMode = FALSE; -#ifdef HWRENDER - if (rendermode != render_soft) - { - // purge all patch graphics stored in software format - //Z_FreeTags (PU_PURGELEVEL, PU_PURGELEVEL+100); - HWR_Startup(); - } -#endif - } - - I_RestartSysMouse(); - return 1; -} - -// ======================================================================== -// Free the video buffer of the last video mode, -// allocate a new buffer for the video mode to set. -// ======================================================================== -static BOOL VID_FreeAndAllocVidbuffer(viddef_t *lvid) -{ - const DWORD vidbuffersize = (lvid->width * lvid->height * lvid->bpp * NUMSCREENS); - - // free allocated buffer for previous video mode - if (lvid->buffer) - GlobalFree(lvid->buffer); - - // allocate & clear the new screen buffer - lvid->buffer = GlobalAlloc(GPTR, vidbuffersize); - if (!lvid->buffer) - return FALSE; - - ZeroMemory(lvid->buffer, vidbuffersize); -#ifdef DEBUG - CONS_Printf("VID_FreeAndAllocVidbuffer done, vidbuffersize: %x\n",vidbuffersize); -#endif - return TRUE; -} - -// ======================================================================== -// Set video mode routine for DirectDraw display modes -// Out: 1 ok, -// 0 hardware could not set mode, -// -1 no mem -// ======================================================================== -static int WINAPI VID_SetDirectDrawMode(viddef_t *lvid, vmode_t *pcurrentmode) -{ - pcurrentmode = NULL; -#ifdef DEBUG - CONS_Printf("VID_SetDirectDrawMode...\n"); -#endif - - // DD modes do double-buffer page flipping, but the game engine doesn't need this.. - lvid->u.numpages = 2; - - // release ddraw surfaces etc.. - ReleaseChtuff(); - - // clean up any old vid buffer lying around, alloc new if needed - if (!VID_FreeAndAllocVidbuffer(lvid)) - return -1; // no mem - - // should clear video mem here - - // note use lvid->bpp instead of 8...will this be needed? will we support other than 256color - // in software ? - if (!InitDirectDrawe(hWndMain, lvid->width, lvid->height, 8, TRUE)) // TRUE currently always full screen - return 0; // could not set mode - - // this is NOT used with DirectDraw modes, game engine should never use this directly - // but rather render to memory bitmap buffer - lvid->direct = NULL; - - if (!cv_stretch.value && (float)vid.width/vid.height != ((float)BASEVIDWIDTH/BASEVIDHEIGHT)) - vid.height = (int)(vid.width * ((float)BASEVIDHEIGHT/BASEVIDWIDTH));// Adjust the height to match - - return 1; -} - -// ======================================================================== -// VIDEO MODE CONSOLE COMMANDS -// ======================================================================== - -// vid_nummodes -// -static void VID_Command_NumModes_f(void) -{ - CONS_Printf(M_GetText("%d video mode(s) available(s)\n"), VID_NumModes()); -} - -// vid_modeinfo <modenum> -// -static void VID_Command_ModeInfo_f(void) -{ - vmode_t *pv; - int modenum; - - if (COM_Argc() != 2) - modenum = vid.modenum; // describe the current mode - else - modenum = atoi(COM_Argv(1)); // the given mode number - - if (modenum >= VID_NumModes() || modenum < NUMSPECIALMODES) // don't accept the windowed mode 0 - { - CONS_Printf(M_GetText("Video mode not present\n")); - return; - } - - pv = VID_GetModePtr(modenum); - - CONS_Printf("%s\n", VID_GetModeName(modenum)); - CONS_Printf(M_GetText("width: %d\nheight: %d\n"), - pv->width, pv->height); - if (rendermode == render_soft) - CONS_Printf(M_GetText("bytes per scanline: %d\nbytes per pixel: %d\nnumpages: %d\n"), - pv->rowbytes, pv->bytesperpixel, pv->numpages); -} - -// vid_modelist -// -static void VID_Command_ModeList_f(void) -{ - int i, nummodes; - const char *pinfo; - vmode_t *pv; - - nummodes = VID_NumModes(); - for (i = NUMSPECIALMODES; i <= nummodes; i++) - { - pv = VID_GetModePtr(i); - pinfo = VID_GetModeName(i); - - if (pv->bytesperpixel == 1) - CONS_Printf("%d: %s\n", i, pinfo); - else - CONS_Printf("%d: %s (hicolor)\n", i, pinfo); - } -} - -// vid_mode <modenum> -// -static void VID_Command_Mode_f(void) -{ - int modenum; - - if (COM_Argc() != 2) - { - CONS_Printf(M_GetText("vid_mode <modenum> : set video mode, current video mode %i\n"), vid.modenum); - return; - } - - modenum = atoi(COM_Argv(1)); - - if (modenum >= VID_NumModes() || modenum < NUMSPECIALMODES) // don't accept the windowed mode 0 - CONS_Printf(M_GetText("Video mode not present\n")); - else - setmodeneeded = modenum + 1; // request vid mode change -} diff --git a/src/win32ce/wince_stuff.c b/src/win32ce/wince_stuff.c deleted file mode 100644 index eb02e8ae2..000000000 --- a/src/win32ce/wince_stuff.c +++ /dev/null @@ -1,135 +0,0 @@ -//It's 4am and im writing replacement string functions.... - -#include <stdlib.h> -#include <Windows.h> -#include "wince_stuff.h" - -char* _strlwr( char *string ) -{ - int i; - - if(!string) - return NULL; - - for(i=0 ; i < strlen(string); i++) - { - if((*(string + i) >= 65) && (*(string + i) <= 90)) - *(string+i) = *(string+i) + 32; - } - - return string; -} - -int _strnicmp(const char *first,const char *last, size_t count ) -{ - int f, l; - - do - { - if ( ((f = (unsigned char)(*(first++))) >= 'A') && (f <= 'Z') ) - f -= 'A' - 'a'; - - if ( ((l = (unsigned char)(*(last++))) >= 'A') && (l <= 'Z') ) - l -= 'A' - 'a'; - - } while ( --count && f && (f == l) ); - - return ( f - l ); -} - - -int _stricmp( const char *dst, const char *src ) -{ - int f, l; - - do - { - if ( ((f = (unsigned char)(*(dst++))) >= 'A') && (f <= 'Z') ) - f -= 'A' - 'a'; - - if ( ((l = (unsigned char)(*(src++))) >= 'A') && (l <= 'Z') ) - l -= 'A' - 'a'; - - } while ( f && (f == l) ); - - return(f - l); -} - - -char* _strupr( char *string ) -{ - int i; - - if(!string) - return NULL; - - for(i=0 ; i < strlen(string); i++) - { - if((*(string + i) >= 97) && (*(string + i) <= 122)) - *(string + i) = *(string + i) - 32; - } - - return string; -} - - - - -int isprint( int c ) -{ - if(c <= 31) - return FALSE; - - return TRUE; -} - - - -char* _strdup (const char * string) -{ - char *memory = NULL; - - if (!string) - return(NULL); - - if (memory = malloc(strlen(string) + 1)) - return(strcpy(memory,string)); - - return(NULL); -} - - - -char* strrchr (const char * string,int ch) -{ - char *start = (char *)string; - - while (*string++) /* find end of string */ - ; - /* search towards front */ - while (--string != start && *string != (char)ch) - ; - - if (*string == (char)ch) /* char found ? */ - return( (char *)string ); - - return(NULL); -} - -char* GetMyCWD(void) -{ - TCHAR fn[MAX_PATH]; - char* my_cwd,*p; - - GetModuleFileName(NULL,fn,MAX_PATH); - - my_cwd = (char*)malloc(MAX_PATH*sizeof(char)); - - WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR | WC_SEPCHARS, fn, -1, my_cwd, MAX_PATH, NULL, NULL); - p = strrchr(my_cwd,'\\'); - - if(p) - *(p+1) = '\0'; - - return my_cwd; -} diff --git a/src/win32ce/wince_stuff.h b/src/win32ce/wince_stuff.h deleted file mode 100644 index 5eab74848..000000000 --- a/src/win32ce/wince_stuff.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef WINCE_STUFF_H -#define WINCE_STUFF_H - -/* -char* _strlwr(char *string); -int _strnicmp(const char *string1,const char *string2, size_t count ); -int _stricmp( const char *string1, const char *string2 ); -char* _strupr( char *string ); - -char *_strdup( const char *strSource ); -char *strrchr( const char *string, int c ); - -int isprint( int c ); -*/ -char* GetMyCWD(void); - -#endif \ No newline at end of file -- GitLab