diff --git a/doomgeneric.sln b/doomgeneric.sln new file mode 100644 index 0000000..1591a78 --- /dev/null +++ b/doomgeneric.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2003 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doomgeneric", "doomgeneric\doomgeneric.vcxproj", "{95A126D2-CC94-4840-BF05-80305041B5FB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {95A126D2-CC94-4840-BF05-80305041B5FB}.Debug|x64.ActiveCfg = Debug|x64 + {95A126D2-CC94-4840-BF05-80305041B5FB}.Debug|x64.Build.0 = Debug|x64 + {95A126D2-CC94-4840-BF05-80305041B5FB}.Debug|x86.ActiveCfg = Debug|Win32 + {95A126D2-CC94-4840-BF05-80305041B5FB}.Debug|x86.Build.0 = Debug|Win32 + {95A126D2-CC94-4840-BF05-80305041B5FB}.Release|x64.ActiveCfg = Release|x64 + {95A126D2-CC94-4840-BF05-80305041B5FB}.Release|x64.Build.0 = Release|x64 + {95A126D2-CC94-4840-BF05-80305041B5FB}.Release|x86.ActiveCfg = Release|Win32 + {95A126D2-CC94-4840-BF05-80305041B5FB}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E444537A-F1DB-44A6-8720-C7DC7BB2C74A} + EndGlobalSection +EndGlobal diff --git a/doomgeneric/Makefile b/doomgeneric/Makefile deleted file mode 100644 index cb88745..0000000 --- a/doomgeneric/Makefile +++ /dev/null @@ -1,61 +0,0 @@ -################################################################ -# -# $Id:$ -# -# $Log:$ -# - -CROSS_COMPILE ?= #arm-linux-gnueabihf- - -ifeq ($(V),1) - VB='' -else - VB=@ -endif - -#LIBS+=-lXext -lX11 -lnsl -lm -lSDL -#CFLAGS+=-Wunused-const-variable=0 -#CFLAGS+=-fsanitize=address -OBJS+=$(OBJDIR)/i_video_fbdev.o -OBJS+=$(OBJDIR)/i_input_tty.o - -CC=$(CROSS_COMPILE)gcc # gcc or g++ -CFLAGS+=-ggdb3 -Os -LDFLAGS+=-Wl,--gc-sections -CFLAGS+=-ggdb3 -Wall -DNORMALUNIX -DLINUX -DSNDSERV # -DUSEASM -LIBS+=-lm -lc -lSDL - -# subdirectory for objects -OBJDIR=build -OUTPUT=fbdoom - -SRC_DOOM = i_main.o dummy.o am_map.o doomdef.o doomstat.o dstrings.o d_event.o d_items.o d_iwad.o d_loop.o d_main.o d_mode.o d_net.o f_finale.o f_wipe.o g_game.o hu_lib.o hu_stuff.o info.o i_cdmus.o i_endoom.o i_joystick.o i_scale.o i_sound.o i_system.o i_timer.o memio.o m_argv.o m_bbox.o m_cheat.o m_config.o m_controls.o m_fixed.o m_menu.o m_misc.o m_random.o p_ceilng.o p_doors.o p_enemy.o p_floor.o p_inter.o p_lights.o p_map.o p_maputl.o p_mobj.o p_plats.o p_pspr.o p_saveg.o p_setup.o p_sight.o p_spec.o p_switch.o p_telept.o p_tick.o p_user.o r_bsp.o r_data.o r_draw.o r_main.o r_plane.o r_segs.o r_sky.o r_things.o sha1.o sounds.o statdump.o st_lib.o st_stuff.o s_sound.o tables.o v_video.o wi_stuff.o w_checksum.o w_file.o w_file_stdc_unbuffered.o w_main.o w_wad.o z_zone.o -OBJS += $(addprefix $(OBJDIR)/, $(SRC_DOOM)) - -all: $(OUTPUT) - -clean: - rm -rf $(OBJDIR) - rm -f $(OUTPUT) - rm -f $(OUTPUT).gdb - rm -f $(OUTPUT).map - -$(OUTPUT): $(OBJS) - @echo [Linking $@] - $(VB)$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) \ - -o $(OUTPUT) $(LIBS) -Wl,-Map,$(OUTPUT).map - @echo [Size] - -$(CROSS_COMPILE)size $(OUTPUT) - -$(OBJS): | $(OBJDIR) - -$(OBJDIR): - mkdir -p $(OBJDIR) - -$(OBJDIR)/%.o: %.c - @echo [Compiling $<] - $(VB)$(CC) $(CFLAGS) -c $< -o $@ - -print: - @echo OBJS: $(OBJS) - diff --git a/doomgeneric/config.h b/doomgeneric/config.h index 6c68fca..6fe8481 100644 --- a/doomgeneric/config.h +++ b/doomgeneric/config.h @@ -70,13 +70,13 @@ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ -#define PACKAGE_NAME "FDoom" +#define PACKAGE_NAME "Doom Generic" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "FDoom 0.1" +#define PACKAGE_STRING "Doom Generic 0.1" /* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "fdoom.tar" +#define PACKAGE_TARNAME "doomgeneric.tar" /* Define to the home page for this package. */ #define PACKAGE_URL "" @@ -85,7 +85,7 @@ #define PACKAGE_VERSION 0.1 /* Change this when you create your awesome forked version */ -#define PROGRAM_PREFIX "fdoom" +#define PROGRAM_PREFIX "doomgeneric" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 diff --git a/doomgeneric/d_iwad.c b/doomgeneric/d_iwad.c index 6a51ea8..04389a9 100644 --- a/doomgeneric/d_iwad.c +++ b/doomgeneric/d_iwad.c @@ -611,6 +611,8 @@ static void BuildIWADDirList(void) #endif #else + AddIWADDir("."); + AddIWADDir (FILES_DIR); // Don't run this function again. diff --git a/doomgeneric/d_main.c b/doomgeneric/d_main.c index 59f67d9..c7cf977 100644 --- a/doomgeneric/d_main.c +++ b/doomgeneric/d_main.c @@ -72,7 +72,6 @@ #include "r_local.h" #include "statdump.h" - #include "d_main.h" // @@ -1080,6 +1079,8 @@ static void D_Endoom(void) endoom = W_CacheLumpName(DEH_String("ENDOOM"), PU_STATIC); I_Endoom(endoom); + + exit(0); } #if ORIGCODE diff --git a/doomgeneric/doomgeneric.c b/doomgeneric/doomgeneric.c new file mode 100644 index 0000000..25675ab --- /dev/null +++ b/doomgeneric/doomgeneric.c @@ -0,0 +1,12 @@ +#include "doomgeneric.h" + +uint32_t* DG_ScreenBuffer = 0; + + +void dg_Create() +{ + DG_ScreenBuffer = malloc(DOOMGENERIC_RESX * DOOMGENERIC_RESY * 4); + + DG_Init(); +} + diff --git a/doomgeneric/doomgeneric.h b/doomgeneric/doomgeneric.h new file mode 100644 index 0000000..97f00e2 --- /dev/null +++ b/doomgeneric/doomgeneric.h @@ -0,0 +1,20 @@ +#ifndef DOOM_GENERIC +#define DOOM_GENERIC + +#include + +#define DOOMGENERIC_RESX 640 +#define DOOMGENERIC_RESY 400 + + +extern uint32_t* DG_ScreenBuffer; + + +void DG_Init(); +void DG_DrawFrame(); +void DG_SleepMs(uint32_t ms); +uint32_t DG_GetTicksMs(); +int DG_GetKey(int* pressed, unsigned char* key); +void DG_SetWindowTitle(const char * title); + +#endif //DOOM_GENERIC \ No newline at end of file diff --git a/doomgeneric/doomgeneric.vcxproj b/doomgeneric/doomgeneric.vcxproj new file mode 100644 index 0000000..20c32c1 --- /dev/null +++ b/doomgeneric/doomgeneric.vcxproj @@ -0,0 +1,336 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {95A126D2-CC94-4840-BF05-80305041B5FB} + Win32Proj + doomgeneric + 10.0.17763.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + NotUsing + Level3 + Disabled + false + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Use + Level3 + Disabled + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + NotUsing + Level3 + MaxSpeed + true + true + false + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Use + Level3 + MaxSpeed + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doomgeneric/doomgeneric.vcxproj.filters b/doomgeneric/doomgeneric.vcxproj.filters new file mode 100644 index 0000000..5c65ee4 --- /dev/null +++ b/doomgeneric/doomgeneric.vcxproj.filters @@ -0,0 +1,561 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/doomgeneric/doomgeneric_win.c b/doomgeneric/doomgeneric_win.c new file mode 100644 index 0000000..271cabd --- /dev/null +++ b/doomgeneric/doomgeneric_win.c @@ -0,0 +1,197 @@ +#include "doomkeys.h" + +#include "doomgeneric.h" + +#include + +#include + +static BITMAPINFO s_Bmi = { sizeof(BITMAPINFOHEADER), DOOMGENERIC_RESX, -DOOMGENERIC_RESY, 1, 32 }; +static HWND s_Hwnd = 0; +static HDC s_Hdc = 0; + + +#define KEYQUEUE_SIZE 16 + +static unsigned short s_KeyQueue[KEYQUEUE_SIZE]; +static unsigned int s_KeyQueueWriteIndex = 0; +static unsigned int s_KeyQueueReadIndex = 0; + +static unsigned char convertToDoomKey(unsigned char key) +{ + switch (key) + { + case VK_RETURN: + key = KEY_ENTER; + break; + case VK_ESCAPE: + key = KEY_ESCAPE; + break; + case VK_LEFT: + key = KEY_LEFTARROW; + break; + case VK_RIGHT: + key = KEY_RIGHTARROW; + break; + case VK_UP: + key = KEY_UPARROW; + break; + case VK_DOWN: + key = KEY_DOWNARROW; + break; + case VK_CONTROL: + key = KEY_FIRE; + break; + case VK_SPACE: + key = KEY_USE; + break; + case VK_SHIFT: + key = KEY_RSHIFT; + break; + default: + key = tolower(key); + break; + } + + return key; +} + +static void addKeyToQueue(int pressed, unsigned char keyCode) +{ + unsigned char key = convertToDoomKey(keyCode); + + unsigned short keyData = (pressed << 8) | key; + + s_KeyQueue[s_KeyQueueWriteIndex] = keyData; + s_KeyQueueWriteIndex++; + s_KeyQueueWriteIndex %= KEYQUEUE_SIZE; +} + +static LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_CLOSE: + DestroyWindow(hwnd); + break; + case WM_DESTROY: + PostQuitMessage(0); + ExitProcess(0); + break; + case WM_KEYDOWN: + addKeyToQueue(1, wParam); + break; + case WM_KEYUP: + addKeyToQueue(0, wParam); + break; + default: + return DefWindowProcA(hwnd, msg, wParam, lParam); + } + return 0; +} + +void DG_Init() +{ + // window creation + const char windowClassName[] = "DoomWindowClass"; + const char windowTitle[] = "Doom"; + WNDCLASSEXA wc; + + wc.cbSize = sizeof(WNDCLASSEXA); + wc.style = 0; + wc.lpfnWndProc = wndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = 0; + wc.hIcon = 0; + wc.hCursor = 0; + wc.hbrBackground = 0; + wc.lpszMenuName = 0; + wc.lpszClassName = windowClassName; + wc.hIconSm = 0; + + if (!RegisterClassExA(&wc)) + { + printf("Window Registration Failed!"); + + exit(-1); + } + + RECT rect; + rect.left = rect.top = 0; + rect.right = DOOMGENERIC_RESX; + rect.bottom = DOOMGENERIC_RESY; + AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); + + HWND hwnd = CreateWindowExA(0, windowClassName, windowTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, 0, 0, 0, 0); + if (hwnd) + { + s_Hwnd = hwnd; + + s_Hdc = GetDC(hwnd); + ShowWindow(hwnd, SW_SHOW); + } + else + { + printf("Window Creation Failed!"); + + exit(-1); + } + + memset(s_KeyQueue, 0, KEYQUEUE_SIZE * sizeof(unsigned short)); +} + +void DG_DrawFrame() +{ + MSG msg; + memset(&msg, 0, sizeof(msg)); + + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE) > 0) + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + + StretchDIBits(s_Hdc, 0, 0, DOOMGENERIC_RESX, DOOMGENERIC_RESY, 0, 0, DOOMGENERIC_RESX, DOOMGENERIC_RESY, DG_ScreenBuffer, &s_Bmi, 0, SRCCOPY); + + SwapBuffers(s_Hdc); +} + +void DG_SleepMs(uint32_t ms) +{ + Sleep(ms); +} + +uint32_t DG_GetTicksMs() +{ + return GetTickCount(); +} + +int DG_GetKey(int* pressed, unsigned char* doomKey) +{ + if (s_KeyQueueReadIndex == s_KeyQueueWriteIndex) + { + //key queue is empty + + return 0; + } + else + { + unsigned short keyData = s_KeyQueue[s_KeyQueueReadIndex]; + s_KeyQueueReadIndex++; + s_KeyQueueReadIndex %= KEYQUEUE_SIZE; + + *pressed = keyData >> 8; + *doomKey = keyData & 0xFF; + + return 1; + } +} + +void DG_SetWindowTitle(const char * title) +{ + if (s_Hwnd) + { + SetWindowTextA(s_Hwnd, title); + } +} \ No newline at end of file diff --git a/doomgeneric/doomtype.h b/doomgeneric/doomtype.h index b5298eb..aab7cbe 100644 --- a/doomgeneric/doomtype.h +++ b/doomgeneric/doomtype.h @@ -27,8 +27,8 @@ #ifdef _WIN32 -#define strcasecmp stricmp -#define strncasecmp strnicmp +#define strcasecmp _stricmp +#define strncasecmp _strnicmp #else diff --git a/doomgeneric/i_input_tty.c b/doomgeneric/i_input.c similarity index 64% rename from doomgeneric/i_input_tty.c rename to doomgeneric/i_input.c index e66e17b..7ec4b63 100644 --- a/doomgeneric/i_input_tty.c +++ b/doomgeneric/i_input.c @@ -12,22 +12,14 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // -// DESCRIPTION: -// DOOM keyboard input via linux tty -// #include #include #include #include -#include #include #include -#include -#include -#include -#include #include "config.h" #include "deh_str.h" @@ -47,6 +39,8 @@ #include "w_wad.h" #include "z_zone.h" +#include "doomgeneric.h" + int vanilla_keyboard_mapping = 1; // Is the shift key currently down? @@ -227,153 +221,17 @@ static const char shiftxform[] = '{', '|', '}', '~', 127 }; -/* Checks whether or not the given file descriptor is associated - with a local keyboard. - Returns 1 if it is, 0 if not (or if something prevented us from - checking). */ - -int tty_is_kbd(int fd) -{ - int data = 0; - - if (ioctl(fd, KDGKBTYPE, &data) != 0) - return 0; - - if (data == KB_84) { - printf("84-key keyboard found.\n"); - return 1; - } else if (data == KB_101) { - printf("101-key keyboard found.\n"); - return 1; - } else { - printf("KDGKBTYPE = 0x%x.\n", data); - return 0; - } -} - -static int old_mode = -1; -static struct termios old_term; -static int kb = -1; /* keyboard file descriptor */ - -void kbd_shutdown(void) -{ - /* Shut down nicely. */ - - printf("Cleaning up.\n"); - fflush(stdout); - - printf("Exiting normally.\n"); - if (old_mode != -1) { - ioctl(kb, KDSKBMODE, old_mode); - tcsetattr(kb, 0, &old_term); - } - - if (kb > 3) - close(kb); - - exit(0); -} - -static int kbd_init(void) -{ - struct termios new_term; - char *files_to_try[] = {"/dev/tty", "/dev/console", NULL}; - int i; - int flags; - - /* First we need to find a file descriptor that represents the - system's keyboard. This should be /dev/tty, /dev/console, - stdin, stdout, or stderr. We'll try them in that order. - If none are acceptable, we're probably not being run - from a VT. */ - for (i = 0; files_to_try[i] != NULL; i++) { - /* Try to open the file. */ - kb = open(files_to_try[i], O_RDONLY); - if (kb < 0) continue; - /* See if this is valid for our purposes. */ - if (tty_is_kbd(kb)) { - printf("Using keyboard on %s.\n", files_to_try[i]); - break; - } - close(kb); - } - - /* If those didn't work, not all is lost. We can try the - 3 standard file descriptors, in hopes that one of them - might point to a console. This is not especially likely. */ - if (files_to_try[i] == NULL) { - for (kb = 0; kb < 3; kb++) { - if (tty_is_kbd(i)) break; - } - printf("Unable to find a file descriptor associated with "\ - "the keyboard.\n" \ - "Perhaps you're not using a virtual terminal?\n"); - return 1; - } - - /* Find the keyboard's mode so we can restore it later. */ - if (ioctl(kb, KDGKBMODE, &old_mode) != 0) { - printf("Unable to query keyboard mode.\n"); - kbd_shutdown(); - } - - /* Adjust the terminal's settings. In particular, disable - echoing, signal generation, and line buffering. Any of - these could cause trouble. Save the old settings first. */ - if (tcgetattr(kb, &old_term) != 0) { - printf("Unable to query terminal settings.\n"); - kbd_shutdown(); - } - - new_term = old_term; - new_term.c_iflag = 0; - new_term.c_lflag &= ~(ECHO | ICANON | ISIG); - - /* TCSAFLUSH discards unread input before making the change. - A good idea. */ - if (tcsetattr(kb, TCSAFLUSH, &new_term) != 0) { - printf("Unable to change terminal settings.\n"); - } - - /* Put the keyboard in mediumraw mode. */ - if (ioctl(kb, KDSKBMODE, K_MEDIUMRAW) != 0) { - printf("Unable to set mediumraw mode.\n"); - kbd_shutdown(); - } - - /* Put in non-blocking mode */ - flags = fcntl(kb, F_GETFL, 0); - fcntl(kb, F_SETFL, flags | O_NONBLOCK); - - printf("Ready to read keycodes. Press Backspace to exit.\n"); - - return 0; -} - -int kbd_read(int *pressed, unsigned char *key) -{ - unsigned char data; - - if (read(kb, &data, 1) < 1) { - return 0; - } - - *pressed = (data & 0x80) == 0x80; - *key = data & 0x7F; - - /* Print the keycode. The top bit is the pressed/released - flag, and the lower seven are the keycode. */ - //printf("%s: 0x%2X (%i)\n", *pressed ? "Released" : " Pressed", (unsigned int)*key, (unsigned int)*key); - - return 1; -} static unsigned char TranslateKey(unsigned char key) { + return key; + + /* if (key < sizeof(at_to_doom)) return at_to_doom[key]; else return 0x0; + */ //default: // return tolower(key); @@ -412,7 +270,7 @@ static void UpdateShiftStatus(int pressed, unsigned char key) change = -1; } - if (key == 0x2a || key == 0x36) { + if (key == KEY_RSHIFT) { shiftdown += change; } } @@ -424,20 +282,14 @@ void I_GetEvent(void) int pressed; unsigned char key; - // put event-grabbing stuff in here - while (kbd_read(&pressed, &key)) + while (DG_GetKey(&pressed, &key)) { - if (key == 0x0E) { - kbd_shutdown(); - I_Quit(); - } - UpdateShiftStatus(pressed, key); // process event - if (!pressed) + if (pressed) { // data1 has the key pressed, data2 has the character // (shift-translated, etc) @@ -485,8 +337,5 @@ void I_GetEvent(void) void I_InitInput(void) { - kbd_init(); - - //UpdateFocus(); } diff --git a/doomgeneric/i_input_sdl.c b/doomgeneric/i_input_sdl.c deleted file mode 100644 index 49794ba..0000000 --- a/doomgeneric/i_input_sdl.c +++ /dev/null @@ -1,407 +0,0 @@ -// -// Copyright(C) 1993-1996 Id Software, Inc. -// Copyright(C) 2005-2014 Simon Howard -// -// 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: -// DOOM graphics stuff for SDL. -// - - -#include "SDL/SDL.h" -#include -#include -#include -#include - -#include "config.h" -#include "deh_str.h" -#include "doomtype.h" -#include "doomkeys.h" -#include "i_joystick.h" -#include "i_system.h" -#include "i_swap.h" -#include "i_timer.h" -#include "i_video.h" -#include "i_scale.h" -#include "m_argv.h" -#include "m_config.h" -#include "m_misc.h" -#include "tables.h" -#include "v_video.h" -#include "w_wad.h" -#include "z_zone.h" - -// SDL surface for the screen. - -static SDL_Surface *screen; - -// If true, keyboard mapping is ignored, like in Vanilla Doom. -// The sensible thing to do is to disable this if you have a non-US -// keyboard. - -int vanilla_keyboard_mapping = true; - -// Is the shift key currently down? - -static int shiftdown = 0; -// Lookup table for mapping ASCII characters to their equivalent when -// shift is pressed on an American layout keyboard: - -static const char shiftxform[] = -{ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, ' ', '!', '"', '#', '$', '%', '&', - '"', // shift-' - '(', ')', '*', '+', - '<', // shift-, - '_', // shift-- - '>', // shift-. - '?', // shift-/ - ')', // shift-0 - '!', // shift-1 - '@', // shift-2 - '#', // shift-3 - '$', // shift-4 - '%', // shift-5 - '^', // shift-6 - '&', // shift-7 - '*', // shift-8 - '(', // shift-9 - ':', - ':', // shift-; - '<', - '+', // shift-= - '>', '?', '@', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '[', // shift-[ - '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK - ']', // shift-] - '"', '_', - '\'', // shift-` - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '{', '|', '}', '~', 127 -}; - - -// -// Translates the SDL key -// - -static int TranslateKey(SDL_keysym *sym) -{ - switch(sym->sym) - { - case SDLK_LEFT: return KEY_LEFTARROW; - case SDLK_RIGHT: return KEY_RIGHTARROW; - case SDLK_DOWN: return KEY_DOWNARROW; - case SDLK_UP: return KEY_UPARROW; - case SDLK_ESCAPE: return KEY_ESCAPE; - case SDLK_RETURN: return KEY_ENTER; - case SDLK_TAB: return KEY_TAB; - case SDLK_F1: return KEY_F1; - case SDLK_F2: return KEY_F2; - case SDLK_F3: return KEY_F3; - case SDLK_F4: return KEY_F4; - case SDLK_F5: return KEY_F5; - case SDLK_F6: return KEY_F6; - case SDLK_F7: return KEY_F7; - case SDLK_F8: return KEY_F8; - case SDLK_F9: return KEY_F9; - case SDLK_F10: return KEY_F10; - case SDLK_F11: return KEY_F11; - case SDLK_F12: return KEY_F12; - case SDLK_PRINT: return KEY_PRTSCR; - - case SDLK_BACKSPACE: return KEY_BACKSPACE; - case SDLK_DELETE: return KEY_DEL; - - case SDLK_PAUSE: return KEY_PAUSE; - -#if !SDL_VERSION_ATLEAST(1, 3, 0) - case SDLK_EQUALS: return KEY_EQUALS; -#endif - - case SDLK_MINUS: return KEY_MINUS; - - case SDLK_LSHIFT: - case SDLK_RSHIFT: - return KEY_RSHIFT; - - case SDLK_LCTRL: - case SDLK_RCTRL: - return KEY_RCTRL; - - case SDLK_LALT: - case SDLK_RALT: -#if !SDL_VERSION_ATLEAST(1, 3, 0) - case SDLK_LMETA: - case SDLK_RMETA: -#endif - return KEY_RALT; - - case SDLK_CAPSLOCK: return KEY_CAPSLOCK; - case SDLK_SCROLLOCK: return KEY_SCRLCK; - case SDLK_NUMLOCK: return KEY_NUMLOCK; - - case SDLK_KP0: return KEYP_0; - case SDLK_KP1: return KEYP_1; - case SDLK_KP2: return KEYP_2; - case SDLK_KP3: return KEYP_3; - case SDLK_KP4: return KEYP_4; - case SDLK_KP5: return KEYP_5; - case SDLK_KP6: return KEYP_6; - case SDLK_KP7: return KEYP_7; - case SDLK_KP8: return KEYP_8; - case SDLK_KP9: return KEYP_9; - - case SDLK_KP_PERIOD: return KEYP_PERIOD; - case SDLK_KP_MULTIPLY: return KEYP_MULTIPLY; - case SDLK_KP_PLUS: return KEYP_PLUS; - case SDLK_KP_MINUS: return KEYP_MINUS; - case SDLK_KP_DIVIDE: return KEYP_DIVIDE; - case SDLK_KP_EQUALS: return KEYP_EQUALS; - case SDLK_KP_ENTER: return KEYP_ENTER; - - case SDLK_HOME: return KEY_HOME; - case SDLK_INSERT: return KEY_INS; - case SDLK_END: return KEY_END; - case SDLK_PAGEUP: return KEY_PGUP; - case SDLK_PAGEDOWN: return KEY_PGDN; - -#ifdef SDL_HAVE_APP_KEYS - case SDLK_APP1: return KEY_F1; - case SDLK_APP2: return KEY_F2; - case SDLK_APP3: return KEY_F3; - case SDLK_APP4: return KEY_F4; - case SDLK_APP5: return KEY_F5; - case SDLK_APP6: return KEY_F6; -#endif - - default: - return tolower(sym->sym); - } -} - -// Get the equivalent ASCII (Unicode?) character for a keypress. - -static int GetTypedChar(SDL_Event *event) -{ - int key; - - // If Vanilla keyboard mapping enabled, the keyboard - // scan code is used to give the character typed. - // This does not change depending on keyboard layout. - // If you have a German keyboard, pressing 'z' will - // give 'y', for example. It is desirable to be able - // to fix this so that people with non-standard - // keyboard mappings can type properly. If vanilla - // mode is disabled, use the properly translated - // version. - - if (vanilla_keyboard_mapping) - { - key = TranslateKey(&event->key.keysym); - - // Is shift held down? If so, perform a translation. - - if (shiftdown > 0) - { - if (key >= 0 && key < arrlen(shiftxform)) - { - key = shiftxform[key]; - } - else - { - key = 0; - } - } - - return key; - } - else - { - // Unicode value, from key layout. - - return tolower(event->key.keysym.unicode); - } -} - -static void UpdateShiftStatus(SDL_Event *event) -{ - int change; - - if (event->type == SDL_KEYDOWN) - { - change = 1; - } - else if (event->type == SDL_KEYUP) - { - change = -1; - } - else - { - return; - } - - if (event->key.keysym.sym == SDLK_LSHIFT - || event->key.keysym.sym == SDLK_RSHIFT) - { - shiftdown += change; - } -} - - -void I_GetEvent(void) -{ - SDL_Event sdlevent; - event_t event; - - // possibly not needed - - SDL_PumpEvents(); - - // put event-grabbing stuff in here - - while (SDL_PollEvent(&sdlevent)) - { - if (sdlevent.type == SDL_QUIT) - { - I_Quit(); - } - - UpdateShiftStatus(&sdlevent); - - // process event - - switch (sdlevent.type) - { - case SDL_KEYDOWN: - // data1 has the key pressed, data2 has the character - // (shift-translated, etc) - event.type = ev_keydown; - event.data1 = TranslateKey(&sdlevent.key.keysym); - event.data2 = GetTypedChar(&sdlevent); - - if (event.data1 != 0) - { - D_PostEvent(&event); - } - break; - - case SDL_KEYUP: - event.type = ev_keyup; - event.data1 = TranslateKey(&sdlevent.key.keysym); - - // data2 is just initialized to zero for ev_keyup. - // For ev_keydown it's the shifted Unicode character - // that was typed, but if something wants to detect - // key releases it should do so based on data1 - // (key ID), not the printable char. - - event.data2 = 0; - - if (event.data1 != 0) - { - D_PostEvent(&event); - } - break; - - /* - case SDL_MOUSEMOTION: - event.type = ev_mouse; - event.data1 = mouse_button_state; - event.data2 = AccelerateMouse(sdlevent.motion.xrel); - event.data3 = -AccelerateMouse(sdlevent.motion.yrel); - D_PostEvent(&event); - break; - */ - - case SDL_QUIT: - event.type = ev_quit; - D_PostEvent(&event); - break; - - case SDL_ACTIVEEVENT: - // need to update our focus state - //UpdateFocus(); - break; - - default: - break; - } - } -} - - -//void I_ShutdownGraphics(void) -//{ -// //SDL_QuitSubSystem(SDL_INIT_VIDEO); -//} - -// -// I_StartTic -// -void I_StartTic (void) -{ - I_GetEvent(); -} - -void I_InitInput(void) -{ - SDL_Event dummy; - byte *doompal; - char *env; - - // Pass through the XSCREENSAVER_WINDOW environment variable to - // SDL_WINDOWID, to embed the SDL window into the Xscreensaver - // window. - - env = getenv("XSCREENSAVER_WINDOW"); - - if (env != NULL) - { - char winenv[30]; - int winid; - - sscanf(env, "0x%x", &winid); - M_snprintf(winenv, sizeof(winenv), "SDL_WINDOWID=%i", winid); - - putenv(winenv); - } - - if (SDL_Init(SDL_INIT_VIDEO) < 0) - { - I_Error("Failed to initialize video: %s", SDL_GetError()); - } - - //UpdateFocus(); - - // We need SDL to give us translated versions of keys as well - - SDL_EnableUNICODE(1); - - // Repeat key presses - this is what Vanilla Doom does - // Not sure about repeat rate - probably dependent on which DOS - // driver is used. This is good enough though. - - SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); - - // clear out any events waiting at the start and center the mouse - - while (SDL_PollEvent(&dummy)); -} - diff --git a/doomgeneric/i_main.c b/doomgeneric/i_main.c index bb481eb..b192227 100644 --- a/doomgeneric/i_main.c +++ b/doomgeneric/i_main.c @@ -16,12 +16,12 @@ // Main program, simply calls D_DoomMain high level loop. // -#include "config.h" +//#include "config.h" #include -#include "doomtype.h" -#include "i_system.h" +//#include "doomtype.h" +//#include "i_system.h" #include "m_argv.h" // @@ -32,6 +32,11 @@ void D_DoomMain (void); +void M_FindResponseFile(void); + +void dg_Create(); + + int main(int argc, char **argv) { // save arguments @@ -43,7 +48,10 @@ int main(int argc, char **argv) // start doom printf("Starting D_DoomMain\r\n"); - D_DoomMain (); + + dg_Create(); + + D_DoomMain (); return 0; } diff --git a/doomgeneric/i_oplmusic.c b/doomgeneric/i_oplmusic.c deleted file mode 100644 index a1e9050..0000000 --- a/doomgeneric/i_oplmusic.c +++ /dev/null @@ -1,1616 +0,0 @@ -// -// Copyright(C) 1993-1996 Id Software, Inc. -// Copyright(C) 2005-2014 Simon Howard -// -// 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: -// System interface for music. -// - - -#include -#include -#include - -#include "memio.h" -#include "mus2mid.h" - -#include "deh_main.h" -#include "i_sound.h" -#include "i_swap.h" -#include "m_misc.h" -#include "w_wad.h" -#include "z_zone.h" - -#include "opl.h" -#include "midifile.h" - -// #define OPL_MIDI_DEBUG - -#define MAXMIDLENGTH (96 * 1024) -#define GENMIDI_NUM_INSTRS 128 -#define GENMIDI_NUM_PERCUSSION 47 - -#define GENMIDI_HEADER "#OPL_II#" -#define GENMIDI_FLAG_FIXED 0x0001 /* fixed pitch */ -#define GENMIDI_FLAG_2VOICE 0x0004 /* double voice (OPL3) */ - -#define PERCUSSION_LOG_LEN 16 - -typedef struct -{ - byte tremolo; - byte attack; - byte sustain; - byte waveform; - byte scale; - byte level; -} PACKEDATTR genmidi_op_t; - -typedef struct -{ - genmidi_op_t modulator; - byte feedback; - genmidi_op_t carrier; - byte unused; - short base_note_offset; -} PACKEDATTR genmidi_voice_t; - -typedef struct -{ - unsigned short flags; - byte fine_tuning; - byte fixed_note; - - genmidi_voice_t voices[2]; -} PACKEDATTR genmidi_instr_t; - -// Data associated with a channel of a track that is currently playing. - -typedef struct -{ - // The instrument currently used for this track. - - genmidi_instr_t *instrument; - - // Volume level - - int volume; - - // Pitch bend value: - - int bend; - -} opl_channel_data_t; - -// Data associated with a track that is currently playing. - -typedef struct -{ - // Data for each channel. - - opl_channel_data_t channels[MIDI_CHANNELS_PER_TRACK]; - - // Track iterator used to read new events. - - midi_track_iter_t *iter; -} opl_track_data_t; - -typedef struct opl_voice_s opl_voice_t; - -struct opl_voice_s -{ - // Index of this voice: - int index; - - // The operators used by this voice: - int op1, op2; - - // Currently-loaded instrument data - genmidi_instr_t *current_instr; - - // The voice number in the instrument to use. - // This is normally set to zero; if this is a double voice - // instrument, it may be one. - unsigned int current_instr_voice; - - // The channel currently using this voice. - opl_channel_data_t *channel; - - // The midi key that this voice is playing. - unsigned int key; - - // The note being played. This is normally the same as - // the key, but if the instrument is a fixed pitch - // instrument, it is different. - unsigned int note; - - // The frequency value being used. - unsigned int freq; - - // The volume of the note being played on this channel. - unsigned int note_volume; - - // The current volume (register value) that has been set for this channel. - unsigned int reg_volume; - - // Next in linked list; a voice is always either in the - // free list or the allocated list. - opl_voice_t *next; -}; - -// Operators used by the different voices. - -static const int voice_operators[2][OPL_NUM_VOICES] = { - { 0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12 }, - { 0x03, 0x04, 0x05, 0x0b, 0x0c, 0x0d, 0x13, 0x14, 0x15 } -}; - -// Frequency values to use for each note. - -static const unsigned short frequency_curve[] = { - - 0x133, 0x133, 0x134, 0x134, 0x135, 0x136, 0x136, 0x137, // -1 - 0x137, 0x138, 0x138, 0x139, 0x139, 0x13a, 0x13b, 0x13b, - 0x13c, 0x13c, 0x13d, 0x13d, 0x13e, 0x13f, 0x13f, 0x140, - 0x140, 0x141, 0x142, 0x142, 0x143, 0x143, 0x144, 0x144, - - 0x145, 0x146, 0x146, 0x147, 0x147, 0x148, 0x149, 0x149, // -2 - 0x14a, 0x14a, 0x14b, 0x14c, 0x14c, 0x14d, 0x14d, 0x14e, - 0x14f, 0x14f, 0x150, 0x150, 0x151, 0x152, 0x152, 0x153, - 0x153, 0x154, 0x155, 0x155, 0x156, 0x157, 0x157, 0x158, - - // These are used for the first seven MIDI note values: - - 0x158, 0x159, 0x15a, 0x15a, 0x15b, 0x15b, 0x15c, 0x15d, // 0 - 0x15d, 0x15e, 0x15f, 0x15f, 0x160, 0x161, 0x161, 0x162, - 0x162, 0x163, 0x164, 0x164, 0x165, 0x166, 0x166, 0x167, - 0x168, 0x168, 0x169, 0x16a, 0x16a, 0x16b, 0x16c, 0x16c, - - 0x16d, 0x16e, 0x16e, 0x16f, 0x170, 0x170, 0x171, 0x172, // 1 - 0x172, 0x173, 0x174, 0x174, 0x175, 0x176, 0x176, 0x177, - 0x178, 0x178, 0x179, 0x17a, 0x17a, 0x17b, 0x17c, 0x17c, - 0x17d, 0x17e, 0x17e, 0x17f, 0x180, 0x181, 0x181, 0x182, - - 0x183, 0x183, 0x184, 0x185, 0x185, 0x186, 0x187, 0x188, // 2 - 0x188, 0x189, 0x18a, 0x18a, 0x18b, 0x18c, 0x18d, 0x18d, - 0x18e, 0x18f, 0x18f, 0x190, 0x191, 0x192, 0x192, 0x193, - 0x194, 0x194, 0x195, 0x196, 0x197, 0x197, 0x198, 0x199, - - 0x19a, 0x19a, 0x19b, 0x19c, 0x19d, 0x19d, 0x19e, 0x19f, // 3 - 0x1a0, 0x1a0, 0x1a1, 0x1a2, 0x1a3, 0x1a3, 0x1a4, 0x1a5, - 0x1a6, 0x1a6, 0x1a7, 0x1a8, 0x1a9, 0x1a9, 0x1aa, 0x1ab, - 0x1ac, 0x1ad, 0x1ad, 0x1ae, 0x1af, 0x1b0, 0x1b0, 0x1b1, - - 0x1b2, 0x1b3, 0x1b4, 0x1b4, 0x1b5, 0x1b6, 0x1b7, 0x1b8, // 4 - 0x1b8, 0x1b9, 0x1ba, 0x1bb, 0x1bc, 0x1bc, 0x1bd, 0x1be, - 0x1bf, 0x1c0, 0x1c0, 0x1c1, 0x1c2, 0x1c3, 0x1c4, 0x1c4, - 0x1c5, 0x1c6, 0x1c7, 0x1c8, 0x1c9, 0x1c9, 0x1ca, 0x1cb, - - 0x1cc, 0x1cd, 0x1ce, 0x1ce, 0x1cf, 0x1d0, 0x1d1, 0x1d2, // 5 - 0x1d3, 0x1d3, 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d8, 0x1d8, - 0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1de, 0x1df, - 0x1e0, 0x1e1, 0x1e2, 0x1e3, 0x1e4, 0x1e5, 0x1e5, 0x1e6, - - 0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ed, // 6 - 0x1ee, 0x1ef, 0x1f0, 0x1f1, 0x1f2, 0x1f3, 0x1f4, 0x1f5, - 0x1f6, 0x1f6, 0x1f7, 0x1f8, 0x1f9, 0x1fa, 0x1fb, 0x1fc, - 0x1fd, 0x1fe, 0x1ff, 0x200, 0x201, 0x201, 0x202, 0x203, - - // First note of looped range used for all octaves: - - 0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b, // 7 - 0x20c, 0x20d, 0x20e, 0x20f, 0x210, 0x210, 0x211, 0x212, - 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a, - 0x21b, 0x21c, 0x21d, 0x21e, 0x21f, 0x220, 0x221, 0x222, - - 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22a, // 8 - 0x22b, 0x22c, 0x22d, 0x22e, 0x22f, 0x230, 0x231, 0x232, - 0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a, - 0x23b, 0x23c, 0x23d, 0x23e, 0x23f, 0x240, 0x241, 0x242, - - 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24a, 0x24b, // 9 - 0x24c, 0x24d, 0x24e, 0x24f, 0x250, 0x251, 0x252, 0x253, - 0x254, 0x256, 0x257, 0x258, 0x259, 0x25a, 0x25b, 0x25c, - 0x25d, 0x25e, 0x25f, 0x260, 0x262, 0x263, 0x264, 0x265, - - 0x266, 0x267, 0x268, 0x269, 0x26a, 0x26c, 0x26d, 0x26e, // 10 - 0x26f, 0x270, 0x271, 0x272, 0x273, 0x275, 0x276, 0x277, - 0x278, 0x279, 0x27a, 0x27b, 0x27d, 0x27e, 0x27f, 0x280, - 0x281, 0x282, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, - - 0x28b, 0x28c, 0x28d, 0x28e, 0x28f, 0x290, 0x292, 0x293, // 11 - 0x294, 0x295, 0x296, 0x298, 0x299, 0x29a, 0x29b, 0x29c, - 0x29e, 0x29f, 0x2a0, 0x2a1, 0x2a2, 0x2a4, 0x2a5, 0x2a6, - 0x2a7, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ae, 0x2af, 0x2b0, - - 0x2b1, 0x2b2, 0x2b4, 0x2b5, 0x2b6, 0x2b7, 0x2b9, 0x2ba, // 12 - 0x2bb, 0x2bd, 0x2be, 0x2bf, 0x2c0, 0x2c2, 0x2c3, 0x2c4, - 0x2c5, 0x2c7, 0x2c8, 0x2c9, 0x2cb, 0x2cc, 0x2cd, 0x2ce, - 0x2d0, 0x2d1, 0x2d2, 0x2d4, 0x2d5, 0x2d6, 0x2d8, 0x2d9, - - 0x2da, 0x2dc, 0x2dd, 0x2de, 0x2e0, 0x2e1, 0x2e2, 0x2e4, // 13 - 0x2e5, 0x2e6, 0x2e8, 0x2e9, 0x2ea, 0x2ec, 0x2ed, 0x2ee, - 0x2f0, 0x2f1, 0x2f2, 0x2f4, 0x2f5, 0x2f6, 0x2f8, 0x2f9, - 0x2fb, 0x2fc, 0x2fd, 0x2ff, 0x300, 0x302, 0x303, 0x304, - - 0x306, 0x307, 0x309, 0x30a, 0x30b, 0x30d, 0x30e, 0x310, // 14 - 0x311, 0x312, 0x314, 0x315, 0x317, 0x318, 0x31a, 0x31b, - 0x31c, 0x31e, 0x31f, 0x321, 0x322, 0x324, 0x325, 0x327, - 0x328, 0x329, 0x32b, 0x32c, 0x32e, 0x32f, 0x331, 0x332, - - 0x334, 0x335, 0x337, 0x338, 0x33a, 0x33b, 0x33d, 0x33e, // 15 - 0x340, 0x341, 0x343, 0x344, 0x346, 0x347, 0x349, 0x34a, - 0x34c, 0x34d, 0x34f, 0x350, 0x352, 0x353, 0x355, 0x357, - 0x358, 0x35a, 0x35b, 0x35d, 0x35e, 0x360, 0x361, 0x363, - - 0x365, 0x366, 0x368, 0x369, 0x36b, 0x36c, 0x36e, 0x370, // 16 - 0x371, 0x373, 0x374, 0x376, 0x378, 0x379, 0x37b, 0x37c, - 0x37e, 0x380, 0x381, 0x383, 0x384, 0x386, 0x388, 0x389, - 0x38b, 0x38d, 0x38e, 0x390, 0x392, 0x393, 0x395, 0x397, - - 0x398, 0x39a, 0x39c, 0x39d, 0x39f, 0x3a1, 0x3a2, 0x3a4, // 17 - 0x3a6, 0x3a7, 0x3a9, 0x3ab, 0x3ac, 0x3ae, 0x3b0, 0x3b1, - 0x3b3, 0x3b5, 0x3b7, 0x3b8, 0x3ba, 0x3bc, 0x3bd, 0x3bf, - 0x3c1, 0x3c3, 0x3c4, 0x3c6, 0x3c8, 0x3ca, 0x3cb, 0x3cd, - - // The last note has an incomplete range, and loops round back to - // the start. Note that the last value is actually a buffer overrun - // and does not fit with the other values. - - 0x3cf, 0x3d1, 0x3d2, 0x3d4, 0x3d6, 0x3d8, 0x3da, 0x3db, // 18 - 0x3dd, 0x3df, 0x3e1, 0x3e3, 0x3e4, 0x3e6, 0x3e8, 0x3ea, - 0x3ec, 0x3ed, 0x3ef, 0x3f1, 0x3f3, 0x3f5, 0x3f6, 0x3f8, - 0x3fa, 0x3fc, 0x3fe, 0x36c, -}; - -// Mapping from MIDI volume level to OPL level value. - -static const unsigned int volume_mapping_table[] = { - 0, 1, 3, 5, 6, 8, 10, 11, - 13, 14, 16, 17, 19, 20, 22, 23, - 25, 26, 27, 29, 30, 32, 33, 34, - 36, 37, 39, 41, 43, 45, 47, 49, - 50, 52, 54, 55, 57, 59, 60, 61, - 63, 64, 66, 67, 68, 69, 71, 72, - 73, 74, 75, 76, 77, 79, 80, 81, - 82, 83, 84, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 92, 93, 94, 95, - 96, 96, 97, 98, 99, 99, 100, 101, - 101, 102, 103, 103, 104, 105, 105, 106, - 107, 107, 108, 109, 109, 110, 110, 111, - 112, 112, 113, 113, 114, 114, 115, 115, - 116, 117, 117, 118, 118, 119, 119, 120, - 120, 121, 121, 122, 122, 123, 123, 123, - 124, 124, 125, 125, 126, 126, 127, 127 -}; - -static boolean music_initialized = false; - -//static boolean musicpaused = false; -static int current_music_volume; - -// GENMIDI lump instrument data: - -static genmidi_instr_t *main_instrs; -static genmidi_instr_t *percussion_instrs; -static char (*main_instr_names)[32]; -static char (*percussion_names)[32]; - -// Voices: - -static opl_voice_t voices[OPL_NUM_VOICES]; -static opl_voice_t *voice_free_list; -static opl_voice_t *voice_alloced_list; - -// Track data for playing tracks: - -static opl_track_data_t *tracks; -static unsigned int num_tracks = 0; -static unsigned int running_tracks = 0; -static boolean song_looping; - -// Tempo control variables - -static unsigned int ticks_per_beat; -static unsigned int us_per_beat; - -// Mini-log of recently played percussion instruments: - -static uint8_t last_perc[PERCUSSION_LOG_LEN]; -static unsigned int last_perc_count; - -// Configuration file variable, containing the port number for the -// adlib chip. - -int opl_io_port = 0x388; - -// Load instrument table from GENMIDI lump: - -static boolean LoadInstrumentTable(void) -{ - byte *lump; - - lump = W_CacheLumpName("GENMIDI", PU_STATIC); - - // Check header - - if (strncmp((char *) lump, GENMIDI_HEADER, strlen(GENMIDI_HEADER)) != 0) - { - W_ReleaseLumpName("GENMIDI"); - - return false; - } - - main_instrs = (genmidi_instr_t *) (lump + strlen(GENMIDI_HEADER)); - percussion_instrs = main_instrs + GENMIDI_NUM_INSTRS; - main_instr_names = (char (*)[32]) (percussion_instrs + GENMIDI_NUM_PERCUSSION); - percussion_names = main_instr_names + GENMIDI_NUM_INSTRS; - - return true; -} - -// Get the next available voice from the freelist. - -static opl_voice_t *GetFreeVoice(void) -{ - opl_voice_t *result; - - // None available? - - if (voice_free_list == NULL) - { - return NULL; - } - - // Remove from free list - - result = voice_free_list; - voice_free_list = voice_free_list->next; - - // Add to allocated list - - result->next = voice_alloced_list; - voice_alloced_list = result; - - return result; -} - -// Remove a voice from the allocated voices list. - -static void RemoveVoiceFromAllocedList(opl_voice_t *voice) -{ - opl_voice_t **rover; - - rover = &voice_alloced_list; - - // Search the list until we find the voice, then remove it. - - while (*rover != NULL) - { - if (*rover == voice) - { - *rover = voice->next; - voice->next = NULL; - break; - } - - rover = &(*rover)->next; - } -} - -// Release a voice back to the freelist. - -static void ReleaseVoice(opl_voice_t *voice) -{ - opl_voice_t **rover; - - voice->channel = NULL; - voice->note = 0; - - // Remove from alloced list. - - RemoveVoiceFromAllocedList(voice); - - // Search to the end of the freelist (This is how Doom behaves!) - - rover = &voice_free_list; - - while (*rover != NULL) - { - rover = &(*rover)->next; - } - - *rover = voice; - voice->next = NULL; -} - -// Load data to the specified operator - -static void LoadOperatorData(int operator, genmidi_op_t *data, - boolean max_level) -{ - int level; - - // The scale and level fields must be combined for the level register. - // For the carrier wave we always set the maximum level. - - level = (data->scale & 0xc0) | (data->level & 0x3f); - - if (max_level) - { - level |= 0x3f; - } - - OPL_WriteRegister(OPL_REGS_LEVEL + operator, level); - OPL_WriteRegister(OPL_REGS_TREMOLO + operator, data->tremolo); - OPL_WriteRegister(OPL_REGS_ATTACK + operator, data->attack); - OPL_WriteRegister(OPL_REGS_SUSTAIN + operator, data->sustain); - OPL_WriteRegister(OPL_REGS_WAVEFORM + operator, data->waveform); -} - -// Set the instrument for a particular voice. - -static void SetVoiceInstrument(opl_voice_t *voice, - genmidi_instr_t *instr, - unsigned int instr_voice) -{ - genmidi_voice_t *data; - unsigned int modulating; - - // Instrument already set for this channel? - - if (voice->current_instr == instr - && voice->current_instr_voice == instr_voice) - { - return; - } - - voice->current_instr = instr; - voice->current_instr_voice = instr_voice; - - data = &instr->voices[instr_voice]; - - // Are we usind modulated feedback mode? - - modulating = (data->feedback & 0x01) == 0; - - // Doom loads the second operator first, then the first. - // The carrier is set to minimum volume until the voice volume - // is set in SetVoiceVolume (below). If we are not using - // modulating mode, we must set both to minimum volume. - - LoadOperatorData(voice->op2, &data->carrier, true); - LoadOperatorData(voice->op1, &data->modulator, !modulating); - - // Set feedback register that control the connection between the - // two operators. Turn on bits in the upper nybble; I think this - // is for OPL3, where it turns on channel A/B. - - OPL_WriteRegister(OPL_REGS_FEEDBACK + voice->index, - data->feedback | 0x30); - - // Hack to force a volume update. - - voice->reg_volume = 999; -} - -static void SetVoiceVolume(opl_voice_t *voice, unsigned int volume) -{ - genmidi_voice_t *opl_voice; - unsigned int full_volume; - unsigned int op_volume; - unsigned int reg_volume; - - voice->note_volume = volume; - - opl_voice = &voice->current_instr->voices[voice->current_instr_voice]; - - // Multiply note volume and channel volume to get the actual volume. - - full_volume = (volume_mapping_table[voice->note_volume] - * volume_mapping_table[voice->channel->volume] - * volume_mapping_table[current_music_volume]) / (127 * 127); - - // The volume of each instrument can be controlled via GENMIDI: - - op_volume = 0x3f - opl_voice->carrier.level; - - // The volume value to use in the register: - - reg_volume = (op_volume * full_volume) / 128; - reg_volume = (0x3f - reg_volume) | opl_voice->carrier.scale; - - // Update the volume register(s) if necessary. - - if (reg_volume != voice->reg_volume) - { - voice->reg_volume = reg_volume; - - OPL_WriteRegister(OPL_REGS_LEVEL + voice->op2, reg_volume); - - // If we are using non-modulated feedback mode, we must set the - // volume for both voices. - // Note that the same register volume value is written for - // both voices, always calculated from the carrier's level - // value. - - if ((opl_voice->feedback & 0x01) != 0) - { - OPL_WriteRegister(OPL_REGS_LEVEL + voice->op1, reg_volume); - } - } -} - -// Initialize the voice table and freelist - -static void InitVoices(void) -{ - int i; - - // Start with an empty free list. - - voice_free_list = NULL; - - // Initialize each voice. - - for (i=0; iindex, voice->freq >> 8); -} - -// Get the frequency that we should be using for a voice. - -static void KeyOffEvent(opl_track_data_t *track, midi_event_t *event) -{ - opl_channel_data_t *channel; - unsigned int key; - unsigned int i; - -/* - printf("note off: channel %i, %i, %i\n", - event->data.channel.channel, - event->data.channel.param1, - event->data.channel.param2); -*/ - - channel = &track->channels[event->data.channel.channel]; - key = event->data.channel.param1; - - // Turn off voices being used to play this key. - // If it is a double voice instrument there will be two. - - for (i=0; inext) - { - if (rover->current_instr_voice != 0 - || (rover->channel > channel - && CompareChannelPriorities(channel, rover->channel) > 0)) - { - result = rover; - break; - } - } - - // If we didn't find a voice, find an existing voice being used to - // play a note on the same channel, and use that. - - if (result == NULL) - { - for (rover = voice_alloced_list; rover != NULL; rover = rover->next) - { - if (rover->channel == channel) - { - result = rover; - break; - } - } - } - - // Still nothing found? Give up and just use the first voice in - // the list. - - if (result == NULL) - { - result = voice_alloced_list; - } - - // Stop playing this voice playing and release it back to the free - // list. - - VoiceKeyOff(result); - ReleaseVoice(result); - - // Re-allocate the voice again and return it. - - return GetFreeVoice(); -} - - -static unsigned int FrequencyForVoice(opl_voice_t *voice) -{ - genmidi_voice_t *gm_voice; - unsigned int freq_index; - unsigned int octave; - unsigned int sub_index; - unsigned int note; - - note = voice->note; - - // Apply note offset. - // Don't apply offset if the instrument is a fixed note instrument. - - gm_voice = &voice->current_instr->voices[voice->current_instr_voice]; - - if ((SHORT(voice->current_instr->flags) & GENMIDI_FLAG_FIXED) == 0) - { - note += (signed short) SHORT(gm_voice->base_note_offset); - } - - // Avoid possible overflow due to base note offset: - - if (note > 0x7f) - { - note = voice->note; - } - - freq_index = 64 + 32 * note + voice->channel->bend; - - // If this is the second voice of a double voice instrument, the - // frequency index can be adjusted by the fine tuning field. - - if (voice->current_instr_voice != 0) - { - freq_index += (voice->current_instr->fine_tuning / 2) - 64; - } - - // The first 7 notes use the start of the table, while - // consecutive notes loop around the latter part. - - if (freq_index < 284) - { - return frequency_curve[freq_index]; - } - - sub_index = (freq_index - 284) % (12 * 32); - octave = (freq_index - 284) / (12 * 32); - - // Once the seventh octave is reached, things break down. - // We can only go up to octave 7 as a maximum anyway (the OPL - // register only has three bits for octave number), but for the - // notes in octave 7, the first five bits have octave=7, the - // following notes have octave=6. This 7/6 pattern repeats in - // following octaves (which are technically impossible to - // represent anyway). - - if (octave >= 7) - { - if (sub_index < 5) - { - octave = 7; - } - else - { - octave = 6; - } - } - - // Calculate the resulting register value to use for the frequency. - - return frequency_curve[sub_index + 284] | (octave << 10); -} - -// Update the frequency that a voice is programmed to use. - -static void UpdateVoiceFrequency(opl_voice_t *voice) -{ - unsigned int freq; - - // Calculate the frequency to use for this voice and update it - // if neccessary. - - freq = FrequencyForVoice(voice); - - if (voice->freq != freq) - { - OPL_WriteRegister(OPL_REGS_FREQ_1 + voice->index, freq & 0xff); - OPL_WriteRegister(OPL_REGS_FREQ_2 + voice->index, (freq >> 8) | 0x20); - - voice->freq = freq; - } -} - -// Program a single voice for an instrument. For a double voice -// instrument (GENMIDI_FLAG_2VOICE), this is called twice for each -// key on event. - -static void VoiceKeyOn(opl_channel_data_t *channel, - genmidi_instr_t *instrument, - unsigned int instrument_voice, - unsigned int key, - unsigned int volume) -{ - opl_voice_t *voice; - - // Find a voice to use for this new note. - - voice = GetFreeVoice(); - - // If there are no more voices left, we must decide what to do. - // If this is the first voice of the instrument, free an existing - // voice and use that. Otherwise, if this is the second voice, - // it isn't as important; just discard it. - - if (voice == NULL) - { - if (instrument_voice == 0) - { - voice = ReplaceExistingVoice(channel); - } - else - { - return; - } - } - - voice->channel = channel; - voice->key = key; - - // Work out the note to use. This is normally the same as - // the key, unless it is a fixed pitch instrument. - - if ((SHORT(instrument->flags) & GENMIDI_FLAG_FIXED) != 0) - { - voice->note = instrument->fixed_note; - } - else - { - voice->note = key; - } - - // Program the voice with the instrument data: - - SetVoiceInstrument(voice, instrument, instrument_voice); - - // Set the volume level. - - SetVoiceVolume(voice, volume); - - // Write the frequency value to turn the note on. - - voice->freq = 0; - UpdateVoiceFrequency(voice); -} - -static void KeyOnEvent(opl_track_data_t *track, midi_event_t *event) -{ - genmidi_instr_t *instrument; - opl_channel_data_t *channel; - unsigned int key; - unsigned int volume; - -/* - printf("note on: channel %i, %i, %i\n", - event->data.channel.channel, - event->data.channel.param1, - event->data.channel.param2); -*/ - - key = event->data.channel.param1; - volume = event->data.channel.param2; - - // A volume of zero means key off. Some MIDI tracks, eg. the ones - // in AV.wad, use a second key on with a volume of zero to mean - // key off. - if (volume <= 0) - { - KeyOffEvent(track, event); - return; - } - - // The channel. - channel = &track->channels[event->data.channel.channel]; - - // Percussion channel (10) is treated differently. - - if (event->data.channel.channel == 9) - { - if (key < 35 || key > 81) - { - return; - } - - instrument = &percussion_instrs[key - 35]; - - last_perc[last_perc_count] = key; - last_perc_count = (last_perc_count + 1) % PERCUSSION_LOG_LEN; - } - else - { - instrument = channel->instrument; - } - - // Find and program a voice for this instrument. If this - // is a double voice instrument, we must do this twice. - - VoiceKeyOn(channel, instrument, 0, key, volume); - - if ((SHORT(instrument->flags) & GENMIDI_FLAG_2VOICE) != 0) - { - VoiceKeyOn(channel, instrument, 1, key, volume); - } -} - -static void ProgramChangeEvent(opl_track_data_t *track, midi_event_t *event) -{ - int channel; - int instrument; - - // Set the instrument used on this channel. - - channel = event->data.channel.channel; - instrument = event->data.channel.param1; - track->channels[channel].instrument = &main_instrs[instrument]; - - // TODO: Look through existing voices that are turned on on this - // channel, and change the instrument. -} - -static void SetChannelVolume(opl_channel_data_t *channel, unsigned int volume) -{ - unsigned int i; - - channel->volume = volume; - - // Update all voices that this channel is using. - - for (i=0; idata.channel.channel, - event->data.channel.param1, - event->data.channel.param2); -*/ - - channel = &track->channels[event->data.channel.channel]; - controller = event->data.channel.param1; - param = event->data.channel.param2; - - switch (controller) - { - case MIDI_CONTROLLER_MAIN_VOLUME: - SetChannelVolume(channel, param); - break; - - case MIDI_CONTROLLER_ALL_NOTES_OFF: - AllNotesOff(channel, param); - break; - - default: -#ifdef OPL_MIDI_DEBUG - fprintf(stderr, "Unknown MIDI controller type: %i\n", controller); -#endif - break; - } -} - -// Process a pitch bend event. - -static void PitchBendEvent(opl_track_data_t *track, midi_event_t *event) -{ - opl_channel_data_t *channel; - unsigned int i; - - // Update the channel bend value. Only the MSB of the pitch bend - // value is considered: this is what Doom does. - - channel = &track->channels[event->data.channel.channel]; - channel->bend = event->data.channel.param2 - 64; - - // Update all voices for this channel. - - for (i=0; idata.meta.data; - unsigned int data_len = event->data.meta.length; - - switch (event->data.meta.type) - { - // Things we can just ignore. - - case MIDI_META_SEQUENCE_NUMBER: - case MIDI_META_TEXT: - case MIDI_META_COPYRIGHT: - case MIDI_META_TRACK_NAME: - case MIDI_META_INSTR_NAME: - case MIDI_META_LYRICS: - case MIDI_META_MARKER: - case MIDI_META_CUE_POINT: - case MIDI_META_SEQUENCER_SPECIFIC: - break; - - case MIDI_META_SET_TEMPO: - if (data_len == 3) - { - MetaSetTempo((data[0] << 16) | (data[1] << 8) | data[2]); - } - break; - - // End of track - actually handled when we run out of events - // in the track, see below. - - case MIDI_META_END_OF_TRACK: - break; - - default: -#ifdef OPL_MIDI_DEBUG - fprintf(stderr, "Unknown MIDI meta event type: %i\n", - event->data.meta.type); -#endif - break; - } -} - -// Process a MIDI event from a track. - -static void ProcessEvent(opl_track_data_t *track, midi_event_t *event) -{ - switch (event->event_type) - { - case MIDI_EVENT_NOTE_OFF: - KeyOffEvent(track, event); - break; - - case MIDI_EVENT_NOTE_ON: - KeyOnEvent(track, event); - break; - - case MIDI_EVENT_CONTROLLER: - ControllerEvent(track, event); - break; - - case MIDI_EVENT_PROGRAM_CHANGE: - ProgramChangeEvent(track, event); - break; - - case MIDI_EVENT_PITCH_BEND: - PitchBendEvent(track, event); - break; - - case MIDI_EVENT_META: - MetaEvent(track, event); - break; - - // SysEx events can be ignored. - - case MIDI_EVENT_SYSEX: - case MIDI_EVENT_SYSEX_SPLIT: - break; - - default: -#ifdef OPL_MIDI_DEBUG - fprintf(stderr, "Unknown MIDI event type %i\n", event->event_type); -#endif - break; - } -} - -static void ScheduleTrack(opl_track_data_t *track); - -// Restart a song from the beginning. - -static void RestartSong(void *unused) -{ - unsigned int i; - - running_tracks = num_tracks; - - for (i=0; iiter, &event)) - { - return; - } - - ProcessEvent(track, event); - - // End of track? - - if (event->event_type == MIDI_EVENT_META - && event->data.meta.type == MIDI_META_END_OF_TRACK) - { - --running_tracks; - - // When all tracks have finished, restart the song. - // Don't restart the song immediately, but wait for 5ms - // before triggering a restart. Otherwise it is possible - // to construct an empty MIDI file that causes the game - // to lock up in an infinite loop. (5ms should be short - // enough not to be noticeable by the listener). - - if (running_tracks <= 0 && song_looping) - { - OPL_SetCallback(5000, RestartSong, NULL); - } - - return; - } - - // Reschedule the callback for the next event in the track. - - ScheduleTrack(track); -} - -static void ScheduleTrack(opl_track_data_t *track) -{ - unsigned int nticks; - uint64_t us; - - // Get the number of microseconds until the next event. - - nticks = MIDI_GetDeltaTime(track->iter); - us = ((uint64_t) nticks * us_per_beat) / ticks_per_beat; - - // Set a timer to be invoked when the next event is - // ready to play. - - OPL_SetCallback(us, TrackTimerCallback, track); -} - -// Initialize a channel. - -static void InitChannel(opl_track_data_t *track, opl_channel_data_t *channel) -{ - // TODO: Work out sensible defaults? - - channel->instrument = &main_instrs[0]; - channel->volume = 127; - channel->bend = 0; -} - -// Start a MIDI track playing: - -static void StartTrack(midi_file_t *file, unsigned int track_num) -{ - opl_track_data_t *track; - unsigned int i; - - track = &tracks[track_num]; - track->iter = MIDI_IterateTrack(file, track_num); - - for (i=0; ichannels[i]); - } - - // Schedule the first event. - - ScheduleTrack(track); -} - -// Start playing a mid - -static void I_OPL_PlaySong(void *handle, boolean looping) -{ - midi_file_t *file; - unsigned int i; - - if (!music_initialized || handle == NULL) - { - return; - } - - file = handle; - - // Allocate track data. - - tracks = malloc(MIDI_NumTracks(file) * sizeof(opl_track_data_t)); - - num_tracks = MIDI_NumTracks(file); - running_tracks = num_tracks; - song_looping = looping; - - ticks_per_beat = MIDI_GetFileTimeDivision(file); - - // Default is 120 bpm. - // TODO: this is wrong - - us_per_beat = 500 * 1000; - - for (i=0; i 4 && !memcmp(mem, "MThd", 4); -} - -static boolean ConvertMus(byte *musdata, int len, char *filename) -{ - MEMFILE *instream; - MEMFILE *outstream; - void *outbuf; - size_t outbuf_len; - int result; - - instream = mem_fopen_read(musdata, len); - outstream = mem_fopen_write(); - - result = mus2mid(instream, outstream); - - if (result == 0) - { - mem_get_buf(outstream, &outbuf, &outbuf_len); - - M_WriteFile(filename, outbuf, outbuf_len); - } - - mem_fclose(instream); - mem_fclose(outstream); - - return result; -} - -static void *I_OPL_RegisterSong(void *data, int len) -{ - midi_file_t *result; - char *filename; - - if (!music_initialized) - { - return NULL; - } - - // MUS files begin with "MUS" - // Reject anything which doesnt have this signature - - filename = M_TempFile("doom.mid"); - - if (IsMid(data, len) && len < MAXMIDLENGTH) - { - M_WriteFile(filename, data, len); - } - else - { - // Assume a MUS file and try to convert - - ConvertMus(data, len, filename); - } - - result = MIDI_LoadFile(filename); - - if (result == NULL) - { - fprintf(stderr, "I_OPL_RegisterSong: Failed to load MID.\n"); - } - - // remove file now - - remove(filename); - free(filename); - - return result; -} - -// Is the song playing? - -static boolean I_OPL_MusicIsPlaying(void) -{ - if (!music_initialized) - { - return false; - } - - return num_tracks > 0; -} - -// Shutdown music - -static void I_OPL_ShutdownMusic(void) -{ - if (music_initialized) - { - // Stop currently-playing track, if there is one: - - I_OPL_StopSong(); - - OPL_Shutdown(); - - // Release GENMIDI lump - - W_ReleaseLumpName("GENMIDI"); - - music_initialized = false; - } -} - -// Initialize music subsystem - -static boolean I_OPL_InitMusic(void) -{ - OPL_SetSampleRate(snd_samplerate); - - if (!OPL_Init(opl_io_port)) - { - printf("Dude. The Adlib isn't responding.\n"); - return false; - } - - // Load instruments from GENMIDI lump: - - if (!LoadInstrumentTable()) - { - OPL_Shutdown(); - return false; - } - - InitVoices(); - - tracks = NULL; - num_tracks = 0; - music_initialized = true; - - return true; -} - -static snddevice_t music_opl_devices[] = -{ - SNDDEVICE_ADLIB, - SNDDEVICE_SB, -}; - -music_module_t music_opl_module = -{ - music_opl_devices, - arrlen(music_opl_devices), - I_OPL_InitMusic, - I_OPL_ShutdownMusic, - I_OPL_SetMusicVolume, - I_OPL_PauseSong, - I_OPL_ResumeSong, - I_OPL_RegisterSong, - I_OPL_UnRegisterSong, - I_OPL_PlaySong, - I_OPL_StopSong, - I_OPL_MusicIsPlaying, - NULL, // Poll -}; - -//---------------------------------------------------------------------- -// -// Development / debug message generation, to help developing GENMIDI -// lumps. -// -//---------------------------------------------------------------------- - -static int NumActiveChannels(void) -{ - int i; - - for (i = MIDI_CHANNELS_PER_TRACK - 1; i >= 0; --i) - { - if (tracks[0].channels[i].instrument != &main_instrs[0]) - { - return i + 1; - } - } - - return 0; -} - -static int ChannelInUse(opl_channel_data_t *channel) -{ - opl_voice_t *voice; - - for (voice = voice_alloced_list; voice != NULL; voice = voice->next) - { - if (voice->channel == channel) - { - return 1; - } - } - - return 0; -} - -void I_OPL_DevMessages(char *result, size_t result_len) -{ - char tmp[80]; - int instr_num; - int lines; - int i; - - if (num_tracks == 0) - { - M_snprintf(result, result_len, "No OPL track!"); - return; - } - - M_snprintf(result, result_len, "Tracks:\n"); - lines = 1; - - for (i = 0; i < NumActiveChannels(); ++i) - { - if (tracks[0].channels[i].instrument == NULL) - { - continue; - } - - instr_num = tracks[0].channels[i].instrument - main_instrs; - - M_snprintf(tmp, sizeof(tmp), - "chan %i: %c i#%i (%s)\n", - i, - ChannelInUse(&tracks[0].channels[i]) ? '\'' : ' ', - instr_num + 1, - main_instr_names[instr_num]); - M_StringConcat(result, tmp, result_len); - - ++lines; - } - - M_snprintf(tmp, sizeof(tmp), "\nLast percussion:\n"); - M_StringConcat(result, tmp, result_len); - lines += 2; - - i = (last_perc_count + PERCUSSION_LOG_LEN - 1) % PERCUSSION_LOG_LEN; - - do { - if (last_perc[i] == 0) - { - break; - } - - M_snprintf(tmp, sizeof(tmp), - "%cp#%i (%s)\n", - i == 0 ? '\'' : ' ', - last_perc[i], - percussion_names[last_perc[i] - 35]); - M_StringConcat(result, tmp, result_len); - ++lines; - - i = (i + PERCUSSION_LOG_LEN - 1) % PERCUSSION_LOG_LEN; - } while (lines < 25 && i != last_perc_count); -} - diff --git a/doomgeneric/i_pcsound.c b/doomgeneric/i_pcsound.c deleted file mode 100644 index a7a8381..0000000 --- a/doomgeneric/i_pcsound.c +++ /dev/null @@ -1,330 +0,0 @@ -// -// Copyright(C) 2005-2014 Simon Howard -// -// 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: -// System interface for PC speaker sound. -// - -#include "SDL.h" -#include - -#include "doomtype.h" - -#include "deh_str.h" -#include "i_sound.h" -#include "m_misc.h" -#include "w_wad.h" -#include "z_zone.h" - -#include "pcsound.h" - -#define TIMER_FREQ 1193181 /* hz */ - -static boolean pcs_initialized = false; - -static SDL_mutex *sound_lock; -static boolean use_sfx_prefix; - -static uint8_t *current_sound_lump = NULL; -static uint8_t *current_sound_pos = NULL; -static unsigned int current_sound_remaining = 0; -static int current_sound_handle = 0; -static int current_sound_lump_num = -1; - -static const uint16_t divisors[] = { - 0, - 6818, 6628, 6449, 6279, 6087, 5906, 5736, 5575, - 5423, 5279, 5120, 4971, 4830, 4697, 4554, 4435, - 4307, 4186, 4058, 3950, 3836, 3728, 3615, 3519, - 3418, 3323, 3224, 3131, 3043, 2960, 2875, 2794, - 2711, 2633, 2560, 2485, 2415, 2348, 2281, 2213, - 2153, 2089, 2032, 1975, 1918, 1864, 1810, 1757, - 1709, 1659, 1612, 1565, 1521, 1478, 1435, 1395, - 1355, 1316, 1280, 1242, 1207, 1173, 1140, 1107, - 1075, 1045, 1015, 986, 959, 931, 905, 879, - 854, 829, 806, 783, 760, 739, 718, 697, - 677, 658, 640, 621, 604, 586, 570, 553, - 538, 522, 507, 493, 479, 465, 452, 439, - 427, 415, 403, 391, 380, 369, 359, 348, - 339, 329, 319, 310, 302, 293, 285, 276, - 269, 261, 253, 246, 239, 232, 226, 219, - 213, 207, 201, 195, 190, 184, 179, -}; - -static void PCSCallbackFunc(int *duration, int *freq) -{ - unsigned int tone; - - *duration = 1000 / 140; - - if (SDL_LockMutex(sound_lock) < 0) - { - *freq = 0; - return; - } - - if (current_sound_lump != NULL && current_sound_remaining > 0) - { - // Read the next tone - - tone = *current_sound_pos; - - // Use the tone -> frequency lookup table. See pcspkr10.zip - // for a full discussion of this. - // Check we don't overflow the frequency table. - - if (tone < arrlen(divisors) && divisors[tone] != 0) - { - *freq = (int) (TIMER_FREQ / divisors[tone]); - } - else - { - *freq = 0; - } - - ++current_sound_pos; - --current_sound_remaining; - } - else - { - *freq = 0; - } - - SDL_UnlockMutex(sound_lock); -} - -static boolean CachePCSLump(sfxinfo_t *sfxinfo) -{ - int lumplen; - int headerlen; - - // Free the current sound lump back to the cache - - if (current_sound_lump != NULL) - { - W_ReleaseLumpNum(current_sound_lump_num); - current_sound_lump = NULL; - } - - // Load from WAD - - current_sound_lump = W_CacheLumpNum(sfxinfo->lumpnum, PU_STATIC); - lumplen = W_LumpLength(sfxinfo->lumpnum); - - // Read header - - if (current_sound_lump[0] != 0x00 || current_sound_lump[1] != 0x00) - { - return false; - } - - headerlen = (current_sound_lump[3] << 8) | current_sound_lump[2]; - - if (headerlen > lumplen - 4) - { - return false; - } - - // Header checks out ok - - current_sound_remaining = headerlen; - current_sound_pos = current_sound_lump + 4; - current_sound_lump_num = sfxinfo->lumpnum; - - return true; -} - -// These Doom PC speaker sounds are not played - this can be seen in the -// Heretic source code, where there are remnants of this left over -// from Doom. - -static boolean IsDisabledSound(sfxinfo_t *sfxinfo) -{ - int i; - const char *disabled_sounds[] = { - "posact", - "bgact", - "dmact", - "dmpain", - "popain", - "sawidl", - }; - - for (i=0; iname, disabled_sounds[i])) - { - return true; - } - } - - return false; -} - -static int I_PCS_StartSound(sfxinfo_t *sfxinfo, - int channel, - int vol, - int sep) -{ - int result; - - if (!pcs_initialized) - { - return -1; - } - - if (IsDisabledSound(sfxinfo)) - { - return -1; - } - - if (SDL_LockMutex(sound_lock) < 0) - { - return -1; - } - - result = CachePCSLump(sfxinfo); - - if (result) - { - current_sound_handle = channel; - } - - SDL_UnlockMutex(sound_lock); - - if (result) - { - return channel; - } - else - { - return -1; - } -} - -static void I_PCS_StopSound(int handle) -{ - if (!pcs_initialized) - { - return; - } - - if (SDL_LockMutex(sound_lock) < 0) - { - return; - } - - // If this is the channel currently playing, immediately end it. - - if (current_sound_handle == handle) - { - current_sound_remaining = 0; - } - - SDL_UnlockMutex(sound_lock); -} - -// -// Retrieve the raw data lump index -// for a given SFX name. -// - -static int I_PCS_GetSfxLumpNum(sfxinfo_t* sfx) -{ - char namebuf[9]; - - if (use_sfx_prefix) - { - M_snprintf(namebuf, sizeof(namebuf), "dp%s", DEH_String(sfx->name)); - } - else - { - M_StringCopy(namebuf, DEH_String(sfx->name), sizeof(namebuf)); - } - - return W_GetNumForName(namebuf); -} - - -static boolean I_PCS_SoundIsPlaying(int handle) -{ - if (!pcs_initialized) - { - return false; - } - - if (handle != current_sound_handle) - { - return false; - } - - return current_sound_lump != NULL && current_sound_remaining > 0; -} - -static boolean I_PCS_InitSound(boolean _use_sfx_prefix) -{ - use_sfx_prefix = _use_sfx_prefix; - - // Use the sample rate from the configuration file - - PCSound_SetSampleRate(snd_samplerate); - - // Initialize the PC speaker subsystem. - - pcs_initialized = PCSound_Init(PCSCallbackFunc); - - if (pcs_initialized) - { - sound_lock = SDL_CreateMutex(); - } - - return pcs_initialized; -} - -static void I_PCS_ShutdownSound(void) -{ - if (pcs_initialized) - { - PCSound_Shutdown(); - } -} - -static void I_PCS_UpdateSound(void) -{ - // no-op. -} - -void I_PCS_UpdateSoundParams(int channel, int vol, int sep) -{ - // no-op. -} - -static snddevice_t sound_pcsound_devices[] = -{ - SNDDEVICE_PCSPEAKER, -}; - -sound_module_t sound_pcsound_module = -{ - sound_pcsound_devices, - arrlen(sound_pcsound_devices), - I_PCS_InitSound, - I_PCS_ShutdownSound, - I_PCS_GetSfxLumpNum, - I_PCS_UpdateSound, - I_PCS_UpdateSoundParams, - I_PCS_StartSound, - I_PCS_StopSound, - I_PCS_SoundIsPlaying, -}; - diff --git a/doomgeneric/i_sdlmusic.c b/doomgeneric/i_sdlmusic.c deleted file mode 100644 index cca4132..0000000 --- a/doomgeneric/i_sdlmusic.c +++ /dev/null @@ -1,1322 +0,0 @@ -// -// Copyright(C) 1993-1996 Id Software, Inc. -// Copyright(C) 2005-2014 Simon Howard -// -// 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: -// System interface for music. -// - - -#include -#include -#include -#include "SDL.h" -#include "SDL_mixer.h" - -#include "config.h" -#include "doomtype.h" -#include "memio.h" -#include "mus2mid.h" - -#include "deh_str.h" -#include "gusconf.h" -#include "i_sound.h" -#include "i_system.h" -#include "i_swap.h" -#include "m_argv.h" -#include "m_config.h" -#include "m_misc.h" -#include "sha1.h" -#include "w_wad.h" -#include "z_zone.h" - -#define MAXMIDLENGTH (96 * 1024) -#define MID_HEADER_MAGIC "MThd" -#define MUS_HEADER_MAGIC "MUS\x1a" - -#define FLAC_HEADER "fLaC" -#define OGG_HEADER "OggS" - -// Looping Vorbis metadata tag names. These have been defined by ZDoom -// for specifying the start and end positions for looping music tracks -// in .ogg and .flac files. -// More information is here: http://zdoom.org/wiki/Audio_loop -#define LOOP_START_TAG "LOOP_START" -#define LOOP_END_TAG "LOOP_END" - -// FLAC metadata headers that we care about. -#define FLAC_STREAMINFO 0 -#define FLAC_VORBIS_COMMENT 4 - -// Ogg metadata headers that we care about. -#define OGG_ID_HEADER 1 -#define OGG_COMMENT_HEADER 3 - -// Structure for music substitution. -// We store a mapping based on SHA1 checksum -> filename of substitute music -// file to play, so that substitution occurs based on content rather than -// lump name. This has some inherent advantages: -// * Music for Plutonia (reused from Doom 1) works automatically. -// * If a PWAD replaces music, the replacement music is used rather than -// the substitute music for the IWAD. -// * If a PWAD reuses music from an IWAD (even from a different game), we get -// the high quality version of the music automatically (neat!) - -typedef struct -{ - sha1_digest_t hash; - char *filename; -} subst_music_t; - -// Structure containing parsed metadata read from a digital music track: -typedef struct -{ - boolean valid; - unsigned int samplerate_hz; - int start_time, end_time; -} file_metadata_t; - -static subst_music_t *subst_music = NULL; -static unsigned int subst_music_len = 0; - -static const char *subst_config_filenames[] = -{ - "doom1-music.cfg", - "doom2-music.cfg", - "tnt-music.cfg", - "heretic-music.cfg", - "hexen-music.cfg", - "strife-music.cfg", -}; - -static boolean music_initialized = false; - -// If this is true, this module initialized SDL sound and has the -// responsibility to shut it down - -static boolean sdl_was_initialized = false; - -static boolean musicpaused = false; -static int current_music_volume; - -char *timidity_cfg_path = ""; - -static char *temp_timidity_cfg = NULL; - -// If true, we are playing a substitute digital track rather than in-WAD -// MIDI/MUS track, and file_metadata contains loop metadata. -static boolean playing_substitute = false; -static file_metadata_t file_metadata; - -// Position (in samples) that we have reached in the current track. -// This is updated by the TrackPositionCallback function. -static unsigned int current_track_pos; - -// Currently playing music track. -static Mix_Music *current_track_music = NULL; - -// If true, the currently playing track is being played on loop. -static boolean current_track_loop; - -// Given a time string (for LOOP_START/LOOP_END), parse it and return -// the time (in # samples since start of track) it represents. -static unsigned int ParseVorbisTime(unsigned int samplerate_hz, char *value) -{ - char *num_start, *p; - unsigned int result = 0; - char c; - - if (strchr(value, ':') == NULL) - { - return atoi(value); - } - - result = 0; - num_start = value; - - for (p = value; *p != '\0'; ++p) - { - if (*p == '.' || *p == ':') - { - c = *p; *p = '\0'; - result = result * 60 + atoi(num_start); - num_start = p + 1; - *p = c; - } - - if (*p == '.') - { - return result * samplerate_hz - + (unsigned int) (atof(p) * samplerate_hz); - } - } - - return (result * 60 + atoi(num_start)) * samplerate_hz; -} - -// Given a vorbis comment string (eg. "LOOP_START=12345"), set fields -// in the metadata structure as appropriate. -static void ParseVorbisComment(file_metadata_t *metadata, char *comment) -{ - char *eq, *key, *value; - - eq = strchr(comment, '='); - - if (eq == NULL) - { - return; - } - - key = comment; - *eq = '\0'; - value = eq + 1; - - if (!strcmp(key, LOOP_START_TAG)) - { - metadata->start_time = ParseVorbisTime(metadata->samplerate_hz, value); - } - else if (!strcmp(key, LOOP_END_TAG)) - { - metadata->end_time = ParseVorbisTime(metadata->samplerate_hz, value); - } -} - -// Parse a vorbis comments structure, reading from the given file. -static void ParseVorbisComments(file_metadata_t *metadata, FILE *fs) -{ - uint32_t buf; - unsigned int num_comments, i, comment_len; - char *comment; - - // We must have read the sample rate already from an earlier header. - if (metadata->samplerate_hz == 0) - { - return; - } - - // Skip the starting part we don't care about. - if (fread(&buf, 4, 1, fs) < 1) - { - return; - } - if (fseek(fs, LONG(buf), SEEK_CUR) != 0) - { - return; - } - - // Read count field for number of comments. - if (fread(&buf, 4, 1, fs) < 1) - { - return; - } - num_comments = LONG(buf); - - // Read each individual comment. - for (i = 0; i < num_comments; ++i) - { - // Read length of comment. - if (fread(&buf, 4, 1, fs) < 1) - { - return; - } - - comment_len = LONG(buf); - - // Read actual comment data into string buffer. - comment = calloc(1, comment_len + 1); - if (comment == NULL - || fread(comment, 1, comment_len, fs) < comment_len) - { - free(comment); - break; - } - - // Parse comment string. - ParseVorbisComment(metadata, comment); - free(comment); - } -} - -static void ParseFlacStreaminfo(file_metadata_t *metadata, FILE *fs) -{ - byte buf[34]; - - // Read block data. - if (fread(buf, sizeof(buf), 1, fs) < 1) - { - return; - } - - // We only care about sample rate and song length. - metadata->samplerate_hz = (buf[10] << 12) | (buf[11] << 4) - | (buf[12] >> 4); - // Song length is actually a 36 bit field, but 32 bits should be - // enough for everybody. - //metadata->song_length = (buf[14] << 24) | (buf[15] << 16) - // | (buf[16] << 8) | buf[17]; -} - -static void ParseFlacFile(file_metadata_t *metadata, FILE *fs) -{ - byte header[4]; - unsigned int block_type; - size_t block_len; - boolean last_block; - - for (;;) - { - long pos = -1; - - // Read METADATA_BLOCK_HEADER: - if (fread(header, 4, 1, fs) < 1) - { - return; - } - - block_type = header[0] & ~0x80; - last_block = (header[0] & 0x80) != 0; - block_len = (header[1] << 16) | (header[2] << 8) | header[3]; - - pos = ftell(fs); - if (pos < 0) - { - return; - } - - if (block_type == FLAC_STREAMINFO) - { - ParseFlacStreaminfo(metadata, fs); - } - else if (block_type == FLAC_VORBIS_COMMENT) - { - ParseVorbisComments(metadata, fs); - } - - if (last_block) - { - break; - } - - // Seek to start of next block. - if (fseek(fs, pos + block_len, SEEK_SET) != 0) - { - return; - } - } -} - -static void ParseOggIdHeader(file_metadata_t *metadata, FILE *fs) -{ - byte buf[21]; - - if (fread(buf, sizeof(buf), 1, fs) < 1) - { - return; - } - - metadata->samplerate_hz = (buf[8] << 24) | (buf[7] << 16) - | (buf[6] << 8) | buf[5]; -} - -static void ParseOggFile(file_metadata_t *metadata, FILE *fs) -{ - byte buf[7]; - unsigned int offset; - - // Scan through the start of the file looking for headers. They - // begin '[byte]vorbis' where the byte value indicates header type. - memset(buf, 0, sizeof(buf)); - - for (offset = 0; offset < 100 * 1024; ++offset) - { - // buf[] is used as a sliding window. Each iteration, we - // move the buffer one byte to the left and read an extra - // byte onto the end. - memmove(buf, buf + 1, sizeof(buf) - 1); - - if (fread(&buf[6], 1, 1, fs) < 1) - { - return; - } - - if (!memcmp(buf + 1, "vorbis", 6)) - { - switch (buf[0]) - { - case OGG_ID_HEADER: - ParseOggIdHeader(metadata, fs); - break; - case OGG_COMMENT_HEADER: - ParseVorbisComments(metadata, fs); - break; - default: - break; - } - } - } -} - -static void ReadLoopPoints(char *filename, file_metadata_t *metadata) -{ - FILE *fs; - char header[4]; - - metadata->valid = false; - metadata->samplerate_hz = 0; - metadata->start_time = 0; - metadata->end_time = -1; - - fs = fopen(filename, "r"); - - if (fs == NULL) - { - return; - } - - // Check for a recognized file format; use the first four bytes - // of the file. - - if (fread(header, 4, 1, fs) < 1) - { - fclose(fs); - return; - } - - if (memcmp(header, FLAC_HEADER, 4) == 0) - { - ParseFlacFile(metadata, fs); - } - else if (memcmp(header, OGG_HEADER, 4) == 0) - { - ParseOggFile(metadata, fs); - } - - fclose(fs); - - // Only valid if at the very least we read the sample rate. - metadata->valid = metadata->samplerate_hz > 0; -} - -// Given a MUS lump, look up a substitute MUS file to play instead -// (or NULL to just use normal MIDI playback). - -static char *GetSubstituteMusicFile(void *data, size_t data_len) -{ - sha1_context_t context; - sha1_digest_t hash; - char *filename; - int i; - - // Don't bother doing a hash if we're never going to find anything. - if (subst_music_len == 0) - { - return NULL; - } - - SHA1_Init(&context); - SHA1_Update(&context, data, data_len); - SHA1_Final(hash, &context); - - // Look for a hash that matches. - // The substitute mapping list can (intentionally) contain multiple - // filename mappings for the same hash. This allows us to try - // different files and fall back if our first choice isn't found. - - filename = NULL; - - for (i = 0; i < subst_music_len; ++i) - { - if (memcmp(hash, subst_music[i].hash, sizeof(hash)) == 0) - { - filename = subst_music[i].filename; - - // If the file exists, then use this file in preference to - // any fallbacks. But we always return a filename if it's - // in the list, even if it's just so we can print an error - // message to the user saying it doesn't exist. - if (M_FileExists(filename)) - { - break; - } - } - } - - return filename; -} - -// Add a substitute music file to the lookup list. - -static void AddSubstituteMusic(subst_music_t *subst) -{ - ++subst_music_len; - subst_music = - realloc(subst_music, sizeof(subst_music_t) * subst_music_len); - memcpy(&subst_music[subst_music_len - 1], subst, sizeof(subst_music_t)); -} - -static int ParseHexDigit(char c) -{ - c = tolower(c); - - if (c >= '0' && c <= '9') - { - return c - '0'; - } - else if (c >= 'a' && c <= 'f') - { - return 10 + (c - 'a'); - } - else - { - return -1; - } -} - -static char *GetFullPath(char *base_filename, char *path) -{ - char *basedir, *result; - char *p; - - // Starting with directory separator means we have an absolute path, - // so just return it. - if (path[0] == DIR_SEPARATOR) - { - return strdup(path); - } - -#ifdef _WIN32 - // d:\path\... - if (isalpha(path[0]) && path[1] == ':' && path[2] == DIR_SEPARATOR) - { - return strdup(path); - } -#endif - - // Paths in the substitute filenames can contain Unix-style / - // path separators, but we should convert this to the separator - // for the native platform. - path = M_StringReplace(path, "/", DIR_SEPARATOR_S); - - // Copy config filename and cut off the filename to just get the - // parent dir. - basedir = strdup(base_filename); - p = strrchr(basedir, DIR_SEPARATOR); - if (p != NULL) - { - p[1] = '\0'; - result = M_StringJoin(basedir, path, NULL); - } - else - { - result = strdup(path); - } - free(basedir); - free(path); - - return result; -} - -// Parse a line from substitute music configuration file; returns error -// message or NULL for no error. - -static char *ParseSubstituteLine(char *filename, char *line) -{ - subst_music_t subst; - char *p; - int hash_index; - - // Strip out comments if present. - p = strchr(line, '#'); - if (p != NULL) - { - while (p > line && isspace(*(p - 1))) - { - --p; - } - *p = '\0'; - } - - // Skip leading spaces. - for (p = line; *p != '\0' && isspace(*p); ++p); - - // Empty line? This includes comment lines now that comments have - // been stripped. - if (*p == '\0') - { - return NULL; - } - - // Read hash. - hash_index = 0; - while (*p != '\0' && *p != '=' && !isspace(*p)) - { - int d1, d2; - - d1 = ParseHexDigit(p[0]); - d2 = ParseHexDigit(p[1]); - - if (d1 < 0 || d2 < 0) - { - return "Invalid hex digit in SHA1 hash"; - } - else if (hash_index >= sizeof(sha1_digest_t)) - { - return "SHA1 hash too long"; - } - - subst.hash[hash_index] = (d1 << 4) | d2; - ++hash_index; - - p += 2; - } - - if (hash_index != sizeof(sha1_digest_t)) - { - return "SHA1 hash too short"; - } - - // Skip spaces. - for (; *p != '\0' && isspace(*p); ++p); - - if (*p != '=') - { - return "Expected '='"; - } - - ++p; - - // Skip spaces. - for (; *p != '\0' && isspace(*p); ++p); - - // We're now at the filename. Cut off trailing space characters. - while (strlen(p) > 0 && isspace(p[strlen(p) - 1])) - { - p[strlen(p) - 1] = '\0'; - } - - if (strlen(p) == 0) - { - return "No filename specified for music substitution"; - } - - // Expand full path and add to our database of substitutes. - subst.filename = GetFullPath(filename, p); - AddSubstituteMusic(&subst); - - return NULL; -} - -// Read a substitute music configuration file. - -static boolean ReadSubstituteConfig(char *filename) -{ - char line[128]; - FILE *fs; - char *error; - int linenum = 1; - int old_subst_music_len; - - fs = fopen(filename, "r"); - - if (fs == NULL) - { - return false; - } - - old_subst_music_len = subst_music_len; - - while (!feof(fs)) - { - M_StringCopy(line, "", sizeof(line)); - fgets(line, sizeof(line), fs); - - error = ParseSubstituteLine(filename, line); - - if (error != NULL) - { - fprintf(stderr, "%s:%i: Error: %s\n", filename, linenum, error); - } - - ++linenum; - } - - fclose(fs); - - return true; -} - -// Find substitute configs and try to load them. - -static void LoadSubstituteConfigs(void) -{ - char *musicdir; - char *path; - unsigned int i; - - if (!strcmp(configdir, "")) - { - musicdir = strdup(""); - } - else - { - musicdir = M_StringJoin(configdir, "music", DIR_SEPARATOR_S, NULL); - } - - // Load all music packs. We always load all music substitution packs for - // all games. Why? Suppose we have a Doom PWAD that reuses some music from - // Heretic. If we have the Heretic music pack loaded, then we get an - // automatic substitution. - for (i = 0; i < arrlen(subst_config_filenames); ++i) - { - path = M_StringJoin(musicdir, subst_config_filenames[i], NULL); - ReadSubstituteConfig(path); - free(path); - } - - free(musicdir); - - if (subst_music_len > 0) - { - printf("Loaded %i music substitutions from config files.\n", - subst_music_len); - } -} - -// Returns true if the given lump number is a music lump that should -// be included in substitute configs. -// Identifying music lumps by name is not feasible; some games (eg. -// Heretic, Hexen) don't have a common naming pattern for music lumps. - -static boolean IsMusicLump(int lumpnum) -{ - byte *data; - boolean result; - - if (W_LumpLength(lumpnum) < 4) - { - return false; - } - - data = W_CacheLumpNum(lumpnum, PU_STATIC); - - result = memcmp(data, MUS_HEADER_MAGIC, 4) == 0 - || memcmp(data, MID_HEADER_MAGIC, 4) == 0; - - W_ReleaseLumpNum(lumpnum); - - return result; -} - -// Dump an example config file containing checksums for all MIDI music -// found in the WAD directory. - -static void DumpSubstituteConfig(char *filename) -{ - sha1_context_t context; - sha1_digest_t digest; - char name[9]; - byte *data; - FILE *fs; - int lumpnum, h; - - fs = fopen(filename, "w"); - - if (fs == NULL) - { - I_Error("Failed to open %s for writing", filename); - return; - } - - fprintf(fs, "# Example %s substitute MIDI file.\n\n", PACKAGE_NAME); - fprintf(fs, "# SHA1 hash = filename\n"); - - for (lumpnum = 0; lumpnum < numlumps; ++lumpnum) - { - strncpy(name, lumpinfo[lumpnum].name, 8); - name[8] = '\0'; - - if (!IsMusicLump(lumpnum)) - { - continue; - } - - // Calculate hash. - data = W_CacheLumpNum(lumpnum, PU_STATIC); - SHA1_Init(&context); - SHA1_Update(&context, data, W_LumpLength(lumpnum)); - SHA1_Final(digest, &context); - W_ReleaseLumpNum(lumpnum); - - // Print line. - for (h = 0; h < sizeof(sha1_digest_t); ++h) - { - fprintf(fs, "%02x", digest[h]); - } - - fprintf(fs, " = %s.ogg\n", name); - } - - fprintf(fs, "\n"); - fclose(fs); - - printf("Substitute MIDI config file written to %s.\n", filename); - I_Quit(); -} - -// If the temp_timidity_cfg config variable is set, generate a "wrapper" -// config file for Timidity to point to the actual config file. This -// is needed to inject a "dir" command so that the patches are read -// relative to the actual config file. - -static boolean WriteWrapperTimidityConfig(char *write_path) -{ - char *p, *path; - FILE *fstream; - - if (!strcmp(timidity_cfg_path, "")) - { - return false; - } - - fstream = fopen(write_path, "w"); - - if (fstream == NULL) - { - return false; - } - - p = strrchr(timidity_cfg_path, DIR_SEPARATOR); - if (p != NULL) - { - path = strdup(timidity_cfg_path); - path[p - timidity_cfg_path] = '\0'; - fprintf(fstream, "dir %s\n", path); - free(path); - } - - fprintf(fstream, "source %s\n", timidity_cfg_path); - fclose(fstream); - - return true; -} - -void I_InitTimidityConfig(void) -{ - char *env_string; - boolean success; - - temp_timidity_cfg = M_TempFile("timidity.cfg"); - - if (snd_musicdevice == SNDDEVICE_GUS) - { - success = GUS_WriteConfig(temp_timidity_cfg); - } - else - { - success = WriteWrapperTimidityConfig(temp_timidity_cfg); - } - - // Set the TIMIDITY_CFG environment variable to point to the temporary - // config file. - - if (success) - { - env_string = M_StringJoin("TIMIDITY_CFG=", temp_timidity_cfg, NULL); - putenv(env_string); - } - else - { - free(temp_timidity_cfg); - temp_timidity_cfg = NULL; - } -} - -// Remove the temporary config file generated by I_InitTimidityConfig(). - -static void RemoveTimidityConfig(void) -{ - if (temp_timidity_cfg != NULL) - { - remove(temp_timidity_cfg); - free(temp_timidity_cfg); - } -} - -// Shutdown music - -static void I_SDL_ShutdownMusic(void) -{ - if (music_initialized) - { - Mix_HaltMusic(); - music_initialized = false; - - if (sdl_was_initialized) - { - Mix_CloseAudio(); - SDL_QuitSubSystem(SDL_INIT_AUDIO); - sdl_was_initialized = false; - } - } -} - -static boolean SDLIsInitialized(void) -{ - int freq, channels; - Uint16 format; - - return Mix_QuerySpec(&freq, &format, &channels) != 0; -} - -// Callback function that is invoked to track current track position. -void TrackPositionCallback(int chan, void *stream, int len, void *udata) -{ - // Position is doubled up twice: for 16-bit samples and for stereo. - current_track_pos += len / 4; -} - -// Initialize music subsystem -static boolean I_SDL_InitMusic(void) -{ - int i; - - // SDL_mixer prior to v1.2.11 has a bug that causes crashes - // with MIDI playback. Print a warning message if we are - // using an old version. - -#ifdef __MACOSX__ - { - const SDL_version *v = Mix_Linked_Version(); - - if (SDL_VERSIONNUM(v->major, v->minor, v->patch) - < SDL_VERSIONNUM(1, 2, 11)) - { - printf("\n" - " *** WARNING ***\n" - " You are using an old version of SDL_mixer.\n" - " Music playback on this version may cause crashes\n" - " under OS X and is disabled by default.\n" - "\n"); - } - } -#endif - - //! - // @arg - // - // Read all MIDI files from loaded WAD files, dump an example substitution - // music config file to the specified filename and quit. - // - - i = M_CheckParmWithArgs("-dumpsubstconfig", 1); - - if (i > 0) - { - DumpSubstituteConfig(myargv[i + 1]); - } - - // If SDL_mixer is not initialized, we have to initialize it - // and have the responsibility to shut it down later on. - - if (SDLIsInitialized()) - { - music_initialized = true; - } - else - { - if (SDL_Init(SDL_INIT_AUDIO) < 0) - { - fprintf(stderr, "Unable to set up sound.\n"); - } - else if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, 1024) < 0) - { - fprintf(stderr, "Error initializing SDL_mixer: %s\n", - Mix_GetError()); - SDL_QuitSubSystem(SDL_INIT_AUDIO); - } - else - { - SDL_PauseAudio(0); - - sdl_was_initialized = true; - music_initialized = true; - } - } - - // Once initialization is complete, the temporary Timidity config - // file can be removed. - - RemoveTimidityConfig(); - - // If snd_musiccmd is set, we need to call Mix_SetMusicCMD to - // configure an external music playback program. - - if (strlen(snd_musiccmd) > 0) - { - Mix_SetMusicCMD(snd_musiccmd); - } - - // Register an effect function to track the music position. - Mix_RegisterEffect(MIX_CHANNEL_POST, TrackPositionCallback, NULL, NULL); - - // If we're in GENMIDI mode, try to load sound packs. - if (snd_musicdevice == SNDDEVICE_GENMIDI) - { - LoadSubstituteConfigs(); - } - - return music_initialized; -} - -// -// SDL_mixer's native MIDI music playing does not pause properly. -// As a workaround, set the volume to 0 when paused. -// - -static void UpdateMusicVolume(void) -{ - int vol; - - if (musicpaused) - { - vol = 0; - } - else - { - vol = (current_music_volume * MIX_MAX_VOLUME) / 127; - } - - Mix_VolumeMusic(vol); -} - -// Set music volume (0 - 127) - -static void I_SDL_SetMusicVolume(int volume) -{ - // Internal state variable. - current_music_volume = volume; - - UpdateMusicVolume(); -} - -// Start playing a mid - -static void I_SDL_PlaySong(void *handle, boolean looping) -{ - int loops; - - if (!music_initialized) - { - return; - } - - if (handle == NULL) - { - return; - } - - current_track_music = (Mix_Music *) handle; - current_track_loop = looping; - - if (looping) - { - loops = -1; - } - else - { - loops = 1; - } - - // Don't loop when playing substitute music, as we do it - // ourselves instead. - if (playing_substitute && file_metadata.valid) - { - loops = 1; - SDL_LockAudio(); - current_track_pos = 0; // start of track - SDL_UnlockAudio(); - } - - Mix_PlayMusic(current_track_music, loops); -} - -static void I_SDL_PauseSong(void) -{ - if (!music_initialized) - { - return; - } - - musicpaused = true; - - UpdateMusicVolume(); -} - -static void I_SDL_ResumeSong(void) -{ - if (!music_initialized) - { - return; - } - - musicpaused = false; - - UpdateMusicVolume(); -} - -static void I_SDL_StopSong(void) -{ - if (!music_initialized) - { - return; - } - - Mix_HaltMusic(); - playing_substitute = false; - current_track_music = NULL; -} - -static void I_SDL_UnRegisterSong(void *handle) -{ - Mix_Music *music = (Mix_Music *) handle; - - if (!music_initialized) - { - return; - } - - if (handle == NULL) - { - return; - } - - Mix_FreeMusic(music); -} - -// Determine whether memory block is a .mid file - -static boolean IsMid(byte *mem, int len) -{ - return len > 4 && !memcmp(mem, "MThd", 4); -} - -static boolean ConvertMus(byte *musdata, int len, char *filename) -{ - MEMFILE *instream; - MEMFILE *outstream; - void *outbuf; - size_t outbuf_len; - int result; - - instream = mem_fopen_read(musdata, len); - outstream = mem_fopen_write(); - - result = mus2mid(instream, outstream); - - if (result == 0) - { - mem_get_buf(outstream, &outbuf, &outbuf_len); - - M_WriteFile(filename, outbuf, outbuf_len); - } - - mem_fclose(instream); - mem_fclose(outstream); - - return result; -} - -static void *I_SDL_RegisterSong(void *data, int len) -{ - char *filename; - Mix_Music *music; - - if (!music_initialized) - { - return NULL; - } - - playing_substitute = false; - - // See if we're substituting this MUS for a high-quality replacement. - filename = GetSubstituteMusicFile(data, len); - - if (filename != NULL) - { - music = Mix_LoadMUS(filename); - - if (music == NULL) - { - // Fall through and play MIDI normally, but print an error - // message. - fprintf(stderr, "Failed to load substitute music file: %s: %s\n", - filename, Mix_GetError()); - } - else - { - // Read loop point metadata from the file so that we know where - // to loop the music. - playing_substitute = true; - ReadLoopPoints(filename, &file_metadata); - return music; - } - } - - // MUS files begin with "MUS" - // Reject anything which doesnt have this signature - - filename = M_TempFile("doom.mid"); - - if (IsMid(data, len) && len < MAXMIDLENGTH) - { - M_WriteFile(filename, data, len); - } - else - { - // Assume a MUS file and try to convert - - ConvertMus(data, len, filename); - } - - // Load the MIDI. In an ideal world we'd be using Mix_LoadMUS_RW() - // by now, but Mix_SetMusicCMD() only works with Mix_LoadMUS(), so - // we have to generate a temporary file. - - music = Mix_LoadMUS(filename); - - if (music == NULL) - { - // Failed to load - - fprintf(stderr, "Error loading midi: %s\n", Mix_GetError()); - } - - // Remove the temporary MIDI file; however, when using an external - // MIDI program we can't delete the file. Otherwise, the program - // won't find the file to play. This means we leave a mess on - // disk :( - - if (strlen(snd_musiccmd) == 0) - { - remove(filename); - } - - free(filename); - - return music; -} - -// Is the song playing? -static boolean I_SDL_MusicIsPlaying(void) -{ - if (!music_initialized) - { - return false; - } - - return Mix_PlayingMusic(); -} - -// Get position in substitute music track, in seconds since start of track. -static double GetMusicPosition(void) -{ - unsigned int music_pos; - int freq; - - Mix_QuerySpec(&freq, NULL, NULL); - - SDL_LockAudio(); - music_pos = current_track_pos; - SDL_UnlockAudio(); - - return (double) music_pos / freq; -} - -static void RestartCurrentTrack(void) -{ - double start = (double) file_metadata.start_time - / file_metadata.samplerate_hz; - - // If the track is playing on loop then reset to the start point. - // Otherwise we need to stop the track. - if (current_track_loop) - { - // If the track finished we need to restart it. - if (current_track_music != NULL) - { - Mix_PlayMusic(current_track_music, 1); - } - - Mix_SetMusicPosition(start); - SDL_LockAudio(); - current_track_pos = file_metadata.start_time; - SDL_UnlockAudio(); - } - else - { - Mix_HaltMusic(); - current_track_music = NULL; - playing_substitute = false; - } -} - -// Poll music position; if we have passed the loop point end position -// then we need to go back. -static void I_SDL_PollMusic(void) -{ - if (playing_substitute && file_metadata.valid) - { - double end = (double) file_metadata.end_time - / file_metadata.samplerate_hz; - - // If we have reached the loop end point then we have to take action. - if (file_metadata.end_time >= 0 && GetMusicPosition() >= end) - { - RestartCurrentTrack(); - } - - // Have we reached the actual end of track (not loop end)? - if (!Mix_PlayingMusic() && current_track_loop) - { - RestartCurrentTrack(); - } - } -} - -static snddevice_t music_sdl_devices[] = -{ - SNDDEVICE_PAS, - SNDDEVICE_GUS, - SNDDEVICE_WAVEBLASTER, - SNDDEVICE_SOUNDCANVAS, - SNDDEVICE_GENMIDI, - SNDDEVICE_AWE32, -}; - -music_module_t music_sdl_module = -{ - music_sdl_devices, - arrlen(music_sdl_devices), - I_SDL_InitMusic, - I_SDL_ShutdownMusic, - I_SDL_SetMusicVolume, - I_SDL_PauseSong, - I_SDL_ResumeSong, - I_SDL_RegisterSong, - I_SDL_UnRegisterSong, - I_SDL_PlaySong, - I_SDL_StopSong, - I_SDL_MusicIsPlaying, - I_SDL_PollMusic, -}; - diff --git a/doomgeneric/i_sdlsound.c b/doomgeneric/i_sdlsound.c deleted file mode 100644 index 7089378..0000000 --- a/doomgeneric/i_sdlsound.c +++ /dev/null @@ -1,1092 +0,0 @@ -// -// Copyright(C) 1993-1996 Id Software, Inc. -// Copyright(C) 2005-2014 Simon Howard -// Copyright(C) 2008 David Flater -// -// 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: -// System interface for sound. -// - -#include "config.h" - -#include -#include -#include -#include -#include "SDL.h" -#include "SDL_mixer.h" - -#ifdef HAVE_LIBSAMPLERATE -#include -#endif - -#include "deh_str.h" -#include "i_sound.h" -#include "i_system.h" -#include "i_swap.h" -#include "m_argv.h" -#include "m_misc.h" -#include "w_wad.h" -#include "z_zone.h" - -#include "doomtype.h" - -#define LOW_PASS_FILTER -//#define DEBUG_DUMP_WAVS -#define NUM_CHANNELS 16 - -typedef struct allocated_sound_s allocated_sound_t; - -struct allocated_sound_s -{ - sfxinfo_t *sfxinfo; - Mix_Chunk chunk; - int use_count; - allocated_sound_t *prev, *next; -}; - -static boolean setpanning_workaround = false; - -static boolean sound_initialized = false; - -static sfxinfo_t *channels_playing[NUM_CHANNELS]; - -static int mixer_freq; -static Uint16 mixer_format; -static int mixer_channels; -static boolean use_sfx_prefix; -static boolean (*ExpandSoundData)(sfxinfo_t *sfxinfo, - byte *data, - int samplerate, - int length) = NULL; - -// Doubly-linked list of allocated sounds. -// When a sound is played, it is moved to the head, so that the oldest -// sounds not used recently are at the tail. - -static allocated_sound_t *allocated_sounds_head = NULL; -static allocated_sound_t *allocated_sounds_tail = NULL; -static int allocated_sounds_size = 0; - -int use_libsamplerate = 0; - -// Scale factor used when converting libsamplerate floating point numbers -// to integers. Too high means the sounds can clip; too low means they -// will be too quiet. This is an amount that should avoid clipping most -// of the time: with all the Doom IWAD sound effects, at least. If a PWAD -// is used, clipping might occur. - -float libsamplerate_scale = 0.65f; - -// Hook a sound into the linked list at the head. - -static void AllocatedSoundLink(allocated_sound_t *snd) -{ - snd->prev = NULL; - - snd->next = allocated_sounds_head; - allocated_sounds_head = snd; - - if (allocated_sounds_tail == NULL) - { - allocated_sounds_tail = snd; - } - else - { - snd->next->prev = snd; - } -} - -// Unlink a sound from the linked list. - -static void AllocatedSoundUnlink(allocated_sound_t *snd) -{ - if (snd->prev == NULL) - { - allocated_sounds_head = snd->next; - } - else - { - snd->prev->next = snd->next; - } - - if (snd->next == NULL) - { - allocated_sounds_tail = snd->prev; - } - else - { - snd->next->prev = snd->prev; - } -} - -static void FreeAllocatedSound(allocated_sound_t *snd) -{ - // Unlink from linked list. - - AllocatedSoundUnlink(snd); - - // Unlink from higher-level code. - - snd->sfxinfo->driver_data = NULL; - - // Keep track of the amount of allocated sound data: - - allocated_sounds_size -= snd->chunk.alen; - - free(snd); -} - -// Search from the tail backwards along the allocated sounds list, find -// and free a sound that is not in use, to free up memory. Return true -// for success. - -static boolean FindAndFreeSound(void) -{ - allocated_sound_t *snd; - - snd = allocated_sounds_tail; - - while (snd != NULL) - { - if (snd->use_count == 0) - { - FreeAllocatedSound(snd); - return true; - } - - snd = snd->prev; - } - - // No available sounds to free... - - return false; -} - -// Enforce SFX cache size limit. We are just about to allocate "len" -// bytes on the heap for a new sound effect, so free up some space -// so that we keep allocated_sounds_size < snd_cachesize - -static void ReserveCacheSpace(size_t len) -{ - if (snd_cachesize <= 0) - { - return; - } - - // Keep freeing sound effects that aren't currently being played, - // until there is enough space for the new sound. - - while (allocated_sounds_size + len > snd_cachesize) - { - // Free a sound. If there is nothing more to free, stop. - - if (!FindAndFreeSound()) - { - break; - } - } -} - -// Allocate a block for a new sound effect. - -static Mix_Chunk *AllocateSound(sfxinfo_t *sfxinfo, size_t len) -{ - allocated_sound_t *snd; - - // Keep allocated sounds within the cache size. - - ReserveCacheSpace(len); - - // Allocate the sound structure and data. The data will immediately - // follow the structure, which acts as a header. - - do - { - snd = malloc(sizeof(allocated_sound_t) + len); - - // Out of memory? Try to free an old sound, then loop round - // and try again. - - if (snd == NULL && !FindAndFreeSound()) - { - return NULL; - } - - } while (snd == NULL); - - // Skip past the chunk structure for the audio buffer - - snd->chunk.abuf = (byte *) (snd + 1); - snd->chunk.alen = len; - snd->chunk.allocated = 1; - snd->chunk.volume = MIX_MAX_VOLUME; - - snd->sfxinfo = sfxinfo; - snd->use_count = 0; - - // driver_data pointer points to the allocated_sound structure. - - sfxinfo->driver_data = snd; - - // Keep track of how much memory all these cached sounds are using... - - allocated_sounds_size += len; - - AllocatedSoundLink(snd); - - return &snd->chunk; -} - -// Lock a sound, to indicate that it may not be freed. - -static void LockAllocatedSound(allocated_sound_t *snd) -{ - // Increase use count, to stop the sound being freed. - - ++snd->use_count; - - //printf("++ %s: Use count=%i\n", snd->sfxinfo->name, snd->use_count); - - // When we use a sound, re-link it into the list at the head, so - // that the oldest sounds fall to the end of the list for freeing. - - AllocatedSoundUnlink(snd); - AllocatedSoundLink(snd); -} - -// Unlock a sound to indicate that it may now be freed. - -static void UnlockAllocatedSound(allocated_sound_t *snd) -{ - if (snd->use_count <= 0) - { - I_Error("Sound effect released more times than it was locked..."); - } - - --snd->use_count; - - //printf("-- %s: Use count=%i\n", snd->sfxinfo->name, snd->use_count); -} - -// When a sound stops, check if it is still playing. If it is not, -// we can mark the sound data as CACHE to be freed back for other -// means. - -static void ReleaseSoundOnChannel(int channel) -{ - sfxinfo_t *sfxinfo = channels_playing[channel]; - - if (sfxinfo == NULL) - { - return; - } - - channels_playing[channel] = NULL; - - UnlockAllocatedSound(sfxinfo->driver_data); -} - -#ifdef HAVE_LIBSAMPLERATE - -// Returns the conversion mode for libsamplerate to use. - -static int SRC_ConversionMode(void) -{ - switch (use_libsamplerate) - { - // 0 = disabled - - default: - case 0: - return -1; - - // Ascending numbers give higher quality - - case 1: - return SRC_LINEAR; - case 2: - return SRC_ZERO_ORDER_HOLD; - case 3: - return SRC_SINC_FASTEST; - case 4: - return SRC_SINC_MEDIUM_QUALITY; - case 5: - return SRC_SINC_BEST_QUALITY; - } -} - -// libsamplerate-based generic sound expansion function for any sample rate -// unsigned 8 bits --> signed 16 bits -// mono --> stereo -// samplerate --> mixer_freq -// Returns number of clipped samples. -// DWF 2008-02-10 with cleanups by Simon Howard. - -static boolean ExpandSoundData_SRC(sfxinfo_t *sfxinfo, - byte *data, - int samplerate, - int length) -{ - SRC_DATA src_data; - uint32_t i, abuf_index=0, clipped=0; - uint32_t alen; - int retn; - int16_t *expanded; - Mix_Chunk *chunk; - - src_data.input_frames = length; - src_data.data_in = malloc(length * sizeof(float)); - src_data.src_ratio = (double)mixer_freq / samplerate; - - // We include some extra space here in case of rounding-up. - src_data.output_frames = src_data.src_ratio * length + (mixer_freq / 4); - src_data.data_out = malloc(src_data.output_frames * sizeof(float)); - - assert(src_data.data_in != NULL && src_data.data_out != NULL); - - // Convert input data to floats - - for (i=0; iabuf; - - // Convert the result back into 16-bit integers. - - for (i=0; i INT16_MAX) - { - cvtval_i = INT16_MAX; - ++clipped; - } - - // Left and right channels - - expanded[abuf_index++] = cvtval_i; - expanded[abuf_index++] = cvtval_i; - } - - free(src_data.data_in); - free(src_data.data_out); - - if (clipped > 0) - { - fprintf(stderr, "Sound '%s': clipped %u samples (%0.2f %%)\n", - sfxinfo->name, clipped, - 400.0 * clipped / chunk->alen); - } - - return true; -} - -#endif - -static boolean ConvertibleRatio(int freq1, int freq2) -{ - int ratio; - - if (freq1 > freq2) - { - return ConvertibleRatio(freq2, freq1); - } - else if ((freq2 % freq1) != 0) - { - // Not in a direct ratio - - return false; - } - else - { - // Check the ratio is a power of 2 - - ratio = freq2 / freq1; - - while ((ratio & 1) == 0) - { - ratio = ratio >> 1; - } - - return ratio == 1; - } -} - -#ifdef DEBUG_DUMP_WAVS - -// Debug code to dump resampled sound effects to WAV files for analysis. - -static void WriteWAV(char *filename, byte *data, - uint32_t length, int samplerate) -{ - FILE *wav; - unsigned int i; - unsigned short s; - - wav = fopen(filename, "wb"); - - // Header - - fwrite("RIFF", 1, 4, wav); - i = LONG(36 + samplerate); - fwrite(&i, 4, 1, wav); - fwrite("WAVE", 1, 4, wav); - - // Subchunk 1 - - fwrite("fmt ", 1, 4, wav); - i = LONG(16); - fwrite(&i, 4, 1, wav); // Length - s = SHORT(1); - fwrite(&s, 2, 1, wav); // Format (PCM) - s = SHORT(2); - fwrite(&s, 2, 1, wav); // Channels (2=stereo) - i = LONG(samplerate); - fwrite(&i, 4, 1, wav); // Sample rate - i = LONG(samplerate * 2 * 2); - fwrite(&i, 4, 1, wav); // Byte rate (samplerate * stereo * 16 bit) - s = SHORT(2 * 2); - fwrite(&s, 2, 1, wav); // Block align (stereo * 16 bit) - s = SHORT(16); - fwrite(&s, 2, 1, wav); // Bits per sample (16 bit) - - // Data subchunk - - fwrite("data", 1, 4, wav); - i = LONG(length); - fwrite(&i, 4, 1, wav); // Data length - fwrite(data, 1, length, wav); // Data - - fclose(wav); -} - -#endif - -// Generic sound expansion function for any sample rate. -// Returns number of clipped samples (always 0). - -static boolean ExpandSoundData_SDL(sfxinfo_t *sfxinfo, - byte *data, - int samplerate, - int length) -{ - SDL_AudioCVT convertor; - Mix_Chunk *chunk; - uint32_t expanded_length; - - // Calculate the length of the expanded version of the sample. - - expanded_length = (uint32_t) ((((uint64_t) length) * mixer_freq) / samplerate); - - // Double up twice: 8 -> 16 bit and mono -> stereo - - expanded_length *= 4; - - // Allocate a chunk in which to expand the sound - - chunk = AllocateSound(sfxinfo, expanded_length); - - if (chunk == NULL) - { - return false; - } - - // If we can, use the standard / optimized SDL conversion routines. - - if (samplerate <= mixer_freq - && ConvertibleRatio(samplerate, mixer_freq) - && SDL_BuildAudioCVT(&convertor, - AUDIO_U8, 1, samplerate, - mixer_format, mixer_channels, mixer_freq)) - { - convertor.buf = chunk->abuf; - convertor.len = length; - memcpy(convertor.buf, data, length); - - SDL_ConvertAudio(&convertor); - } - else - { - Sint16 *expanded = (Sint16 *) chunk->abuf; - int expanded_length; - int expand_ratio; - int i; - - // Generic expansion if conversion does not work: - // - // SDL's audio conversion only works for rate conversions that are - // powers of 2; if the two formats are not in a direct power of 2 - // ratio, do this naive conversion instead. - - // number of samples in the converted sound - - expanded_length = ((uint64_t) length * mixer_freq) / samplerate; - expand_ratio = (length << 8) / expanded_length; - - for (i=0; i> 8; - - sample = data[src] | (data[src] << 8); - sample -= 32768; - - // expand 8->16 bits, mono->stereo - - expanded[i * 2] = expanded[i * 2 + 1] = sample; - } - -#ifdef LOW_PASS_FILTER - // Perform a low-pass filter on the upscaled sound to filter - // out high-frequency noise from the conversion process. - - { - float rc, dt, alpha; - - // Low-pass filter for cutoff frequency f: - // - // For sampling rate r, dt = 1 / r - // rc = 1 / 2*pi*f - // alpha = dt / (rc + dt) - - // Filter to the half sample rate of the original sound effect - // (maximum frequency, by nyquist) - - dt = 1.0f / mixer_freq; - rc = 1.0f / (3.14f * samplerate); - alpha = dt / (rc + dt); - - // Both channels are processed in parallel, hence [i-2]: - - for (i=2; ilumpnum; - data = W_CacheLumpNum(lumpnum, PU_STATIC); - lumplen = W_LumpLength(lumpnum); - - // Check the header, and ensure this is a valid sound - - if (lumplen < 8 - || data[0] != 0x03 || data[1] != 0x00) - { - // Invalid sound - - return false; - } - - // 16 bit sample rate field, 32 bit length field - - samplerate = (data[3] << 8) | data[2]; - length = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4]; - - // If the header specifies that the length of the sound is greater than - // the length of the lump itself, this is an invalid sound lump - - // We also discard sound lumps that are less than 49 samples long, - // as this is how DMX behaves - although the actual cut-off length - // seems to vary slightly depending on the sample rate. This needs - // further investigation to better understand the correct - // behavior. - - if (length > lumplen - 8 || length <= 48) - { - return false; - } - - // The DMX sound library seems to skip the first 16 and last 16 - // bytes of the lump - reason unknown. - - data += 16; - length -= 32; - - // Sample rate conversion - - if (!ExpandSoundData(sfxinfo, data + 8, samplerate, length)) - { - return false; - } - -#ifdef DEBUG_DUMP_WAVS - { - char filename[16]; - - M_snprintf(filename, sizeof(filename), "%s.wav", - DEH_String(S_sfx[sound].name)); - WriteWAV(filename, sound_chunks[sound].abuf, - sound_chunks[sound].alen, mixer_freq); - } -#endif - - // don't need the original lump any more - - W_ReleaseLumpNum(lumpnum); - - return true; -} - -static void GetSfxLumpName(sfxinfo_t *sfx, char *buf, size_t buf_len) -{ - // Linked sfx lumps? Get the lump number for the sound linked to. - - if (sfx->link != NULL) - { - sfx = sfx->link; - } - - // Doom adds a DS* prefix to sound lumps; Heretic and Hexen don't - // do this. - - if (use_sfx_prefix) - { - M_snprintf(buf, buf_len, "ds%s", DEH_String(sfx->name)); - } - else - { - M_StringCopy(buf, DEH_String(sfx->name), buf_len); - } -} - -#ifdef HAVE_LIBSAMPLERATE - -// Preload all the sound effects - stops nasty ingame freezes - -static void I_SDL_PrecacheSounds(sfxinfo_t *sounds, int num_sounds) -{ - char namebuf[9]; - int i; - - // Don't need to precache the sounds unless we are using libsamplerate. - - if (use_libsamplerate == 0) - { - return; - } - - printf("I_SDL_PrecacheSounds: Precaching all sound effects.."); - - for (i=0; idriver_data == NULL) - { - if (!CacheSFX(sfxinfo)) - { - return false; - } - } - - LockAllocatedSound(sfxinfo->driver_data); - - return true; -} - -// -// Retrieve the raw data lump index -// for a given SFX name. -// - -static int I_SDL_GetSfxLumpNum(sfxinfo_t *sfx) -{ - char namebuf[9]; - - GetSfxLumpName(sfx, namebuf, sizeof(namebuf)); - - return W_GetNumForName(namebuf); -} - -static void I_SDL_UpdateSoundParams(int handle, int vol, int sep) -{ - int left, right; - - if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS) - { - return; - } - - left = ((254 - sep) * vol) / 127; - right = ((sep) * vol) / 127; - - if (left < 0) left = 0; - else if ( left > 255) left = 255; - if (right < 0) right = 0; - else if (right > 255) right = 255; - - // SDL_mixer version 1.2.8 and earlier has a bug in the Mix_SetPanning - // function. A workaround is to call Mix_UnregisterAllEffects for - // the channel before calling it. This is undesirable as it may lead - // to the channel volumes resetting briefly. - - if (setpanning_workaround) - { - Mix_UnregisterAllEffects(handle); - } - - Mix_SetPanning(handle, left, right); -} - -// -// Starting a sound means adding it -// to the current list of active sounds -// in the internal channels. -// As the SFX info struct contains -// e.g. a pointer to the raw data, -// it is ignored. -// As our sound handling does not handle -// priority, it is ignored. -// Pitching (that is, increased speed of playback) -// is set, but currently not used by mixing. -// - -static int I_SDL_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep) -{ - allocated_sound_t *snd; - - if (!sound_initialized || channel < 0 || channel >= NUM_CHANNELS) - { - return -1; - } - - // Release a sound effect if there is already one playing - // on this channel - - ReleaseSoundOnChannel(channel); - - // Get the sound data - - if (!LockSound(sfxinfo)) - { - return -1; - } - - snd = sfxinfo->driver_data; - - // play sound - - Mix_PlayChannelTimed(channel, &snd->chunk, 0, -1); - - channels_playing[channel] = sfxinfo; - - // set separation, etc. - - I_SDL_UpdateSoundParams(channel, vol, sep); - - return channel; -} - -static void I_SDL_StopSound(int handle) -{ - if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS) - { - return; - } - - Mix_HaltChannel(handle); - - // Sound data is no longer needed; release the - // sound data being used for this channel - - ReleaseSoundOnChannel(handle); -} - - -static boolean I_SDL_SoundIsPlaying(int handle) -{ - if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS) - { - return false; - } - - return Mix_Playing(handle); -} - -// -// Periodically called to update the sound system -// - -static void I_SDL_UpdateSound(void) -{ - int i; - - // Check all channels to see if a sound has finished - - for (i=0; i limit) - { - return (1 << n); - } - } - - // Should never happen? - - return 1024; -} - -static boolean I_SDL_InitSound(boolean _use_sfx_prefix) -{ - int i; - - use_sfx_prefix = _use_sfx_prefix; - - // No sounds yet - - for (i=0; imajor, - mixer_version->minor, - mixer_version->patch); - - if (v <= SDL_VERSIONNUM(1, 2, 8)) - { - setpanning_workaround = true; - fprintf(stderr, "\n" - "ATTENTION: You are using an old version of SDL_mixer!\n" - " This version has a bug that may cause " - "your sound to stutter.\n" - " Please upgrade to a newer version!\n" - "\n"); - } - } - - Mix_AllocateChannels(NUM_CHANNELS); - - SDL_PauseAudio(0); - - sound_initialized = true; - - return true; -} - -static snddevice_t sound_sdl_devices[] = -{ - SNDDEVICE_SB, - SNDDEVICE_PAS, - SNDDEVICE_GUS, - SNDDEVICE_WAVEBLASTER, - SNDDEVICE_SOUNDCANVAS, - SNDDEVICE_AWE32, -}; - -sound_module_t sound_sdl_module = -{ - sound_sdl_devices, - arrlen(sound_sdl_devices), - I_SDL_InitSound, - I_SDL_ShutdownSound, - I_SDL_GetSfxLumpNum, - I_SDL_UpdateSound, - I_SDL_UpdateSoundParams, - I_SDL_StartSound, - I_SDL_StopSound, - I_SDL_SoundIsPlaying, - I_SDL_PrecacheSounds, -}; - diff --git a/doomgeneric/i_sound_dummy.c b/doomgeneric/i_sound_dummy.c deleted file mode 100644 index 97b6bf9..0000000 --- a/doomgeneric/i_sound_dummy.c +++ /dev/null @@ -1,947 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// $Log:$ -// -// DESCRIPTION: -// System interface for sound. -// -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: i_unix.c,v 1.5 1997/02/03 22:45:10 b1 Exp $"; - -#include -#include -#include - -#include -#include - -#include -#include - -#ifndef LINUX -#include -#endif - -#include -#include -#include - -// Timer stuff. Experimental. -#include -#include - -#include "z_zone.h" - -#include "i_system.h" -#include "i_sound.h" -#include "m_argv.h" -#include "m_misc.h" -#include "w_wad.h" - -#include "doomdef.h" - -// UNIX hack, to be removed. -#ifdef SNDSERV -// Separate sound server process. -FILE* sndserver=0; -char* sndserver_filename = "./sndserver "; -#elif SNDINTR - -// Update all 30 millisecs, approx. 30fps synchronized. -// Linux resolution is allegedly 10 millisecs, -// scale is microseconds. -#define SOUND_INTERVAL 500 - -// Get the interrupt. Set duration in millisecs. -int I_SoundSetTimer( int duration_of_tick ); -void I_SoundDelTimer( void ); -#else -// None? -#endif - - -// A quick hack to establish a protocol between -// synchronous mix buffer updates and asynchronous -// audio writes. Probably redundant with gametic. -static int flag = 0; - -// The number of internal mixing channels, -// the samples calculated for each mixing step, -// the size of the 16bit, 2 hardware channel (stereo) -// mixing buffer, and the samplerate of the raw data. - - -// Needed for calling the actual sound output. -#define SAMPLECOUNT 512 -#define NUM_CHANNELS 8 -// It is 2 for 16bit, and 2 for two channels. -#define BUFMUL 4 -#define MIXBUFFERSIZE (SAMPLECOUNT*BUFMUL) - -#define SAMPLERATE 11025 // Hz -#define SAMPLESIZE 2 // 16bit - -// The actual lengths of all sound effects. -int lengths[NUMSFX]; - -// The actual output device. -int audio_fd; - -// The global mixing buffer. -// Basically, samples from all active internal channels -// are modifed and added, and stored in the buffer -// that is submitted to the audio device. -signed short mixbuffer[MIXBUFFERSIZE]; - - -// The channel step amount... -unsigned int channelstep[NUM_CHANNELS]; -// ... and a 0.16 bit remainder of last step. -unsigned int channelstepremainder[NUM_CHANNELS]; - - -// The channel data pointers, start and end. -unsigned char* channels[NUM_CHANNELS]; -unsigned char* channelsend[NUM_CHANNELS]; - - -// Time/gametic that the channel started playing, -// used to determine oldest, which automatically -// has lowest priority. -// In case number of active sounds exceeds -// available channels. -int channelstart[NUM_CHANNELS]; - -// The sound in channel handles, -// determined on registration, -// might be used to unregister/stop/modify, -// currently unused. -int channelhandles[NUM_CHANNELS]; - -// SFX id of the playing sound effect. -// Used to catch duplicates (like chainsaw). -int channelids[NUM_CHANNELS]; - -// Pitch to stepping lookup, unused. -int steptable[256]; - -// Volume lookups. -int vol_lookup[128*256]; - -// Hardware left and right channel volume lookup. -int* channelleftvol_lookup[NUM_CHANNELS]; -int* channelrightvol_lookup[NUM_CHANNELS]; - - - - -// -// Safe ioctl, convenience. -// -void -myioctl -( int fd, - int command, - int* arg ) -{ - int rc; - - rc = ioctl(fd, command, arg); - if (rc < 0) - { - fprintf(stderr, "ioctl(dsp,%d,arg) failed\n", command); - fprintf(stderr, "errno=%d\n", errno); - exit(-1); - } -} - - - - - -// -// This function loads the sound data from the WAD lump, -// for single sound. -// -void* -getsfx -( char* sfxname, - int* len ) -{ - unsigned char* sfx; - unsigned char* paddedsfx; - int i; - int size; - int paddedsize; - char name[20]; - int sfxlump; - - - // Get the sound data from the WAD, allocate lump - // in zone memory. - sprintf(name, "ds%s", sfxname); - - // Now, there is a severe problem with the - // sound handling, in it is not (yet/anymore) - // gamemode aware. That means, sounds from - // DOOM II will be requested even with DOOM - // shareware. - // The sound list is wired into sounds.c, - // which sets the external variable. - // I do not do runtime patches to that - // variable. Instead, we will use a - // default sound for replacement. - if ( W_CheckNumForName(name) == -1 ) - sfxlump = W_GetNumForName("dspistol"); - else - sfxlump = W_GetNumForName(name); - - size = W_LumpLength( sfxlump ); - - // Debug. - // fprintf( stderr, "." ); - //fprintf( stderr, " -loading %s (lump %d, %d bytes)\n", - // sfxname, sfxlump, size ); - //fflush( stderr ); - - sfx = (unsigned char*)W_CacheLumpNum( sfxlump, PU_STATIC ); - - // Pads the sound effect out to the mixing buffer size. - // The original realloc would interfere with zone memory. - paddedsize = ((size-8 + (SAMPLECOUNT-1)) / SAMPLECOUNT) * SAMPLECOUNT; - - // Allocate from zone memory. - paddedsfx = (unsigned char*)Z_Malloc( paddedsize+8, PU_STATIC, 0 ); - // ddt: (unsigned char *) realloc(sfx, paddedsize+8); - // This should interfere with zone memory handling, - // which does not kick in in the soundserver. - - // Now copy and pad. - memcpy( paddedsfx, sfx, size ); - for (i=size ; i> 16); ///(256*256); - seperation = seperation - 257; - rightvol = - volume - ((volume*seperation*seperation) >> 16); - - // Sanity check, clamp volume. - if (rightvol < 0 || rightvol > 127) - I_Error("rightvol out of bounds"); - - if (leftvol < 0 || leftvol > 127) - I_Error("leftvol out of bounds"); - - // Get the proper lookup table piece - // for this volume level??? - channelleftvol_lookup[slot] = &vol_lookup[leftvol*256]; - channelrightvol_lookup[slot] = &vol_lookup[rightvol*256]; - - // Preserve sound SFX id, - // e.g. for avoiding duplicates of chainsaw. - channelids[slot] = sfxid; - - // You tell me. - return rc; -} - - - - - -// -// SFX API -// Note: this was called by S_Init. -// However, whatever they did in the -// old DPMS based DOS version, this -// were simply dummies in the Linux -// version. -// See soundserver initdata(). -// -void I_SetChannels() -{ - // Init internal lookups (raw data, mixing buffer, channels). - // This function sets up internal lookups used during - // the mixing process. - int i; - int j; - - int* steptablemid = steptable + 128; - - // Okay, reset internal mixing channels to zero. - /*for (i=0; iname); - return W_GetNumForName(namebuf); -} - -// -// Starting a sound means adding it -// to the current list of active sounds -// in the internal channels. -// As the SFX info struct contains -// e.g. a pointer to the raw data, -// it is ignored. -// As our sound handling does not handle -// priority, it is ignored. -// Pitching (that is, increased speed of playback) -// is set, but currently not used by mixing. -// -int -I_StartSound -( int id, - int vol, - int sep, - int pitch, - int priority ) -{ - - // UNUSED - priority = 0; - -#ifdef SNDSERV - if (sndserver) - { - fprintf(sndserver, "p%2.2x%2.2x%2.2x%2.2x\n", id, pitch, vol, sep); - fflush(sndserver); - } - // warning: control reaches end of non-void function. - return id; -#else - // Debug. - //fprintf( stderr, "starting sound %d", id ); - - // Returns a handle (not used). - id = addsfx( id, vol, steptable[pitch], sep ); - - // fprintf( stderr, "/handle is %d\n", id ); - - return id; -#endif -} - - - -void I_StopSound (int handle) -{ - // You need the handle returned by StartSound. - // Would be looping all channels, - // tracking down the handle, - // an setting the channel to zero. - - // UNUSED. - handle = 0; -} - - -int I_SoundIsPlaying(int handle) -{ - // Ouch. - return gametic < handle; -} - - - - -// -// This function loops all active (internal) sound -// channels, retrieves a given number of samples -// from the raw sound data, modifies it according -// to the current (internal) channel parameters, -// mixes the per channel samples into the global -// mixbuffer, clamping it to the allowed range, -// and sets up everything for transferring the -// contents of the mixbuffer to the (two) -// hardware channels (left and right, that is). -// -// This function currently supports only 16bit. -// -void I_UpdateSound( void ) -{ -#ifdef SNDINTR - // Debug. Count buffer misses with interrupt. - static int misses = 0; -#endif - - - // Mix current sound data. - // Data, from raw sound, for right and left. - register unsigned int sample; - register int dl; - register int dr; - - // Pointers in global mixbuffer, left, right, end. - signed short* leftout; - signed short* rightout; - signed short* leftend; - // Step in mixbuffer, left and right, thus two. - int step; - - // Mixing channel index. - int chan; - - // Left and right channel - // are in global mixbuffer, alternating. - leftout = mixbuffer; - rightout = mixbuffer+1; - step = 2; - - // Determine end, for left channel only - // (right channel is implicit). - leftend = mixbuffer + SAMPLECOUNT*step; - - // Mix sounds into the mixing buffer. - // Loop over step*SAMPLECOUNT, - // that is 512 values for two channels. - while (leftout != leftend) - { - // Reset left/right value. - dl = 0; - dr = 0; - - // Love thy L2 chache - made this a loop. - // Now more channels could be set at compile time - // as well. Thus loop those channels. - for ( chan = 0; chan < NUM_CHANNELS; chan++ ) - { - // Check channel, if active. - if (channels[ chan ]) - { - // Get the raw data from the channel. - sample = *channels[ chan ]; - // Add left and right part - // for this channel (sound) - // to the current data. - // Adjust volume accordingly. - dl += channelleftvol_lookup[ chan ][sample]; - dr += channelrightvol_lookup[ chan ][sample]; - // Increment index ??? - channelstepremainder[ chan ] += channelstep[ chan ]; - // MSB is next sample??? - channels[ chan ] += channelstepremainder[ chan ] >> 16; - // Limit to LSB??? - channelstepremainder[ chan ] &= 65536-1; - - // Check whether we are done. - if (channels[ chan ] >= channelsend[ chan ]) - channels[ chan ] = 0; - } - } - - // Clamp to range. Left hardware channel. - // Has been char instead of short. - // if (dl > 127) *leftout = 127; - // else if (dl < -128) *leftout = -128; - // else *leftout = dl; - - if (dl > 0x7fff) - *leftout = 0x7fff; - else if (dl < -0x8000) - *leftout = -0x8000; - else - *leftout = dl; - - // Same for right hardware channel. - if (dr > 0x7fff) - *rightout = 0x7fff; - else if (dr < -0x8000) - *rightout = -0x8000; - else - *rightout = dr; - - // Increment current pointers in mixbuffer. - leftout += step; - rightout += step; - } - -#ifdef SNDINTR - // Debug check. - if ( flag ) - { - misses += flag; - flag = 0; - } - - if ( misses > 10 ) - { - fprintf( stderr, "I_SoundUpdate: missed 10 buffer writes\n"); - misses = 0; - } - - // Increment flag for update. - flag++; -#endif -} - - -// -// This would be used to write out the mixbuffer -// during each game loop update. -// Updates sound buffer and audio device at runtime. -// It is called during Timer interrupt with SNDINTR. -// Mixing now done synchronous, and -// only output be done asynchronous? -// -void -I_SubmitSound(void) -{ - // Write it to DSP device. - write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL); -} - - - -void -I_UpdateSoundParams -( int handle, - int vol, - int sep, - int pitch) -{ - // I fail too see that this is used. - // Would be using the handle to identify - // on which channel the sound might be active, - // and resetting the channel parameters. - - // UNUSED. - handle = vol = sep = pitch = 0; -} - - - - -void I_ShutdownSound(void) -{ -#ifdef SNDSERV - if (sndserver) - { - // Send a "quit" command. - fprintf(sndserver, "q\n"); - fflush(sndserver); - } -#else - // Wait till all pending sounds are finished. - int done = 0; - int i; - - - // FIXME (below). - fprintf( stderr, "I_ShutdownSound: NOT finishing pending sounds\n"); - fflush( stderr ); - - while ( !done ) - { - for( i=0 ; i<8 && !channels[i] ; i++); - - // FIXME. No proper channel output. - //if (i==8) - done=1; - } -#ifdef SNDINTR - I_SoundDelTimer(); -#endif - - // Cleaning up -releasing the DSP device. - close ( audio_fd ); -#endif - - // Done. - return; -} - - - - - - -void -I_InitSound() -{ -#ifdef SNDSERV - char buffer[256]; - - if (getenv("DOOMWADDIR")) - sprintf(buffer, "%s/%s", - getenv("DOOMWADDIR"), - sndserver_filename); - else - sprintf(buffer, "%s", sndserver_filename); - - // start sound process - if ( !access(buffer, X_OK) ) - { - strcat(buffer, " -quiet"); - sndserver = NULL; //popen(buffer, "w"); - } - else - fprintf(stderr, "Could not start sound server [%s]\n", buffer); -#else - - int i; - -#ifdef SNDINTR - fprintf( stderr, "I_SoundSetTimer: %d microsecs\n", SOUND_INTERVAL ); - I_SoundSetTimer( SOUND_INTERVAL ); -#endif - - // Secure and configure sound device first. - fprintf( stderr, "I_InitSound: "); - - audio_fd = open("/dev/dsp", O_WRONLY); - if (audio_fd<0) - fprintf(stderr, "Could not open /dev/dsp\n"); - - - i = 11 | (2<<16); - myioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i); - myioctl(audio_fd, SNDCTL_DSP_RESET, 0); - - i=SAMPLERATE; - - myioctl(audio_fd, SNDCTL_DSP_SPEED, &i); - - i=1; - myioctl(audio_fd, SNDCTL_DSP_STEREO, &i); - - myioctl(audio_fd, SNDCTL_DSP_GETFMTS, &i); - - if (i&=AFMT_S16_LE) - myioctl(audio_fd, SNDCTL_DSP_SETFMT, &i); - else - fprintf(stderr, "Could not play signed 16 data\n"); - - fprintf(stderr, " configured audio device\n" ); - - - // Initialize external data (all sounds) at start, keep static. - fprintf( stderr, "I_InitSound: "); - - for (i=1 ; idata; - lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)]; - } - } - - fprintf( stderr, " pre-cached all sound data\n"); - - // Now initialize mixbuffer with zero. - for ( i = 0; i< MIXBUFFERSIZE; i++ ) - mixbuffer[i] = 0; - - // Finished initialization. - fprintf(stderr, "I_InitSound: sound module ready\n"); - -#endif -} - - - - -// -// MUSIC API. -// Still no music done. -// Remains. Dummies. -// -void I_InitMusic(void) { } -void I_ShutdownMusic(void) { } - -static int looping=0; -static int musicdies=-1; - -void I_PlaySong(int handle, int looping) -{ - // UNUSED. - handle = looping = 0; - musicdies = gametic + TICRATE*30; -} - -void I_PauseSong (int handle) -{ - // UNUSED. - handle = 0; -} - -void I_ResumeSong (int handle) -{ - // UNUSED. - handle = 0; -} - -void I_StopSong(int handle) -{ - // UNUSED. - handle = 0; - - looping = 0; - musicdies = 0; -} - -void I_UnRegisterSong(int handle) -{ - // UNUSED. - handle = 0; -} - -int I_RegisterSong(void* data) -{ - // UNUSED. - data = NULL; - - return 1; -} - -// Is the song playing? -int I_QrySongPlaying(int handle) -{ - // UNUSED. - handle = 0; - return looping || musicdies > gametic; -} - - - -// -// Experimental stuff. -// A Linux timer interrupt, for asynchronous -// sound output. -// I ripped this out of the Timer class in -// our Difference Engine, including a few -// SUN remains... -// -#ifdef sun - typedef sigset_t tSigSet; -#else - typedef int tSigSet; -#endif - - -// We might use SIGVTALRM and ITIMER_VIRTUAL, if the process -// time independend timer happens to get lost due to heavy load. -// SIGALRM and ITIMER_REAL doesn't really work well. -// There are issues with profiling as well. - -// Interrupt handler. -void I_HandleSoundTimer( int ignore ) -{ - // Debug. - //fprintf( stderr, "%c", '+' ); fflush( stderr ); - - // Feed sound device if necesary. - if ( flag ) - { - // See I_SubmitSound(). - // Write it to DSP device. - write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL); - - // Reset flag counter. - flag = 0; - } - else - return; - - // UNUSED, but required. - ignore = 0; - return; -} - -// Get the interrupt. Set duration in millisecs. -int I_SoundSetTimer( int duration_of_tick ) -{ - return -1; -} - - -// Remove the interrupt. Set duration to zero. -void I_SoundDelTimer() -{ - // Debug. - if ( I_SoundSetTimer( 0 ) == -1) - fprintf( stderr, "I_SoundDelTimer: failed to remove interrupt. Doh!\n"); -} diff --git a/doomgeneric/i_timer.c b/doomgeneric/i_timer.c index 081b38e..2d6a7cf 100644 --- a/doomgeneric/i_timer.c +++ b/doomgeneric/i_timer.c @@ -19,9 +19,12 @@ #include "i_timer.h" #include "doomtype.h" +#include "doomgeneric.h" + #include -#include -#include +//#include +//#include + // // I_GetTime @@ -30,13 +33,10 @@ static uint32_t basetime = 0; + int I_GetTicks(void) { - struct timeval tp; - struct timezone tzp; - - gettimeofday(&tp, &tzp); - return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); /* return milliseconds */ + return DG_GetTicksMs(); } int I_GetTime (void) @@ -75,7 +75,9 @@ int I_GetTimeMS(void) void I_Sleep(int ms) { //SDL_Delay(ms); - usleep (ms * 1000); + //usleep (ms * 1000); + + DG_SleepMs(ms); } void I_WaitVBL(int count) diff --git a/doomgeneric/i_video.c b/doomgeneric/i_video.c index 26b9f7a..cd4cd5b 100644 --- a/doomgeneric/i_video.c +++ b/doomgeneric/i_video.c @@ -1,6 +1,9 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- // -// Copyright(C) 1993-1996 Id Software, Inc. -// Copyright(C) 2005-2014 Simon Howard +// $Id:$ +// +// Copyright (C) 1993-1996 by id Software, Inc. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -12,207 +15,81 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // -// DESCRIPTION: -// DOOM graphics stuff for SDL. +// $Log:$ // +// DESCRIPTION: +// DOOM graphics stuff for X11, UNIX. +// +//----------------------------------------------------------------------------- - -#include "SDL/SDL.h" -#include -#include -#include -#include - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#endif - -#include "icon.c" +static const char +rcsid[] = "$Id: i_x.c,v 1.6 1997/02/03 22:45:10 b1 Exp $"; #include "config.h" -#include "deh_str.h" -#include "doomtype.h" -#include "doomkeys.h" -#include "i_joystick.h" -#include "i_system.h" -#include "i_swap.h" -#include "i_timer.h" -#include "i_video.h" -#include "i_scale.h" -#include "m_argv.h" -#include "m_config.h" -#include "m_misc.h" -#include "tables.h" #include "v_video.h" -#include "w_wad.h" +#include "m_argv.h" +#include "d_event.h" +#include "d_main.h" +#include "i_video.h" #include "z_zone.h" -// Lookup table for mapping ASCII characters to their equivalent when -// shift is pressed on an American layout keyboard: +#include "tables.h" +#include "doomkeys.h" -static const char shiftxform[] = +#include "doomgeneric.h" + +#include +#include + +#include + +#include + +#include + +//#define CMAP256 + +struct FB_BitField { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, ' ', '!', '"', '#', '$', '%', '&', - '"', // shift-' - '(', ')', '*', '+', - '<', // shift-, - '_', // shift-- - '>', // shift-. - '?', // shift-/ - ')', // shift-0 - '!', // shift-1 - '@', // shift-2 - '#', // shift-3 - '$', // shift-4 - '%', // shift-5 - '^', // shift-6 - '&', // shift-7 - '*', // shift-8 - '(', // shift-9 - ':', - ':', // shift-; - '<', - '+', // shift-= - '>', '?', '@', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '[', // shift-[ - '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK - ']', // shift-] - '"', '_', - '\'', // shift-` - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '{', '|', '}', '~', 127 + uint32_t offset; /* beginning of bitfield */ + uint32_t length; /* length of bitfield */ }; +struct FB_ScreenInfo +{ + uint32_t xres; /* visible resolution */ + uint32_t yres; + uint32_t xres_virtual; /* virtual resolution */ + uint32_t yres_virtual; -#define LOADING_DISK_W 16 -#define LOADING_DISK_H 16 - -// Non aspect ratio-corrected modes (direct multiples of 320x200) - -static screen_mode_t *screen_modes[] = { - &mode_scale_1x, - &mode_scale_2x, - &mode_scale_3x, - &mode_scale_4x, - &mode_scale_5x, + uint32_t bits_per_pixel; /* guess what */ + + /* >1 = FOURCC */ + struct FB_BitField red; /* bitfield in s_Fb mem if true color, */ + struct FB_BitField green; /* else only length is significant */ + struct FB_BitField blue; + struct FB_BitField transp; /* transparency */ }; -// Aspect ratio corrected modes (4:3 ratio) +static struct FB_ScreenInfo s_Fb; +int fb_scaling = 1; +int usemouse = 0; -static screen_mode_t *screen_modes_corrected[] = { - - // Vertically stretched modes (320x200 -> 320x240 and multiples) - - &mode_stretch_1x, - &mode_stretch_2x, - &mode_stretch_3x, - &mode_stretch_4x, - &mode_stretch_5x, - - // Horizontally squashed modes (320x200 -> 256x200 and multiples) - - &mode_squash_1x, - &mode_squash_2x, - &mode_squash_3x, - &mode_squash_4x, - &mode_squash_5x, +struct color { + uint32_t b:8; + uint32_t g:8; + uint32_t r:8; + uint32_t a:8; }; -// SDL video driver name +static struct color colors[256]; -char *video_driver = ""; - -// Window position: - -static char *window_position = ""; - -// SDL surface for the screen. - -static SDL_Surface *screen; - -// Window title - -static char *window_title = ""; - -// Intermediate 8-bit buffer that we draw to instead of 'screen'. -// This is used when we are rendering in 32-bit screen mode. -// When in a real 8-bit screen mode, screenbuffer == screen. - -static SDL_Surface *screenbuffer = NULL; - -// palette - -static SDL_Color palette[256]; -static boolean palette_to_set; - -// display has been set up? - -static boolean initialized = false; - -// disable mouse? - -static boolean nomouse = false; -int usemouse = 1; - -// Bit mask of mouse button state. - -static unsigned int mouse_button_state = 0; - -// Disallow mouse and joystick movement to cause forward/backward -// motion. Specified with the '-novert' command line parameter. -// This is an int to allow saving to config file - -int novert = 0; - -// Save screenshots in PNG format. - -int png_screenshots = 0; - -// if true, I_VideoBuffer is screen->pixels - -static boolean native_surface; - -// Screen width and height, from configuration file. - -int screen_width = SCREENWIDTH; -int screen_height = SCREENHEIGHT; - -// Color depth. - -int screen_bpp = 0; - -// Automatically adjust video settings if the selected mode is -// not a valid video mode. - -static int autoadjust_video_settings = 1; - -// Run in full screen mode? (int type for config code) - -int fullscreen = true; - -// Aspect ratio correction mode - -int aspect_ratio_correct = true; - -// Time to wait for the screen to settle on startup before starting the -// game (ms) - -static int startup_delay = 1000; - -// Grab the mouse? (int type for config code) - -static int grabmouse = true; +void I_GetEvent(void); // The screen buffer; this is modified to draw things to the screen byte *I_VideoBuffer = NULL; +byte *I_VideoBuffer_FB = NULL; // If true, game is running as a screensaver @@ -223,52 +100,6 @@ boolean screensaver_mode = false; boolean screenvisible; -// If true, we display dots at the bottom of the screen to -// indicate FPS. - -static boolean display_fps_dots; - -// If this is true, the screen is rendered but not blitted to the -// video buffer. - -static boolean noblit; - -// Callback function to invoke to determine whether to grab the -// mouse pointer. - -static grabmouse_callback_t grabmouse_callback = NULL; - -// disk image data and background overwritten by the disk to be -// restored by EndRead - -static byte *disk_image = NULL; -static byte *saved_background; -static boolean window_focused; - -// Empty mouse cursor - -static SDL_Cursor *cursors[2]; - -// The screen mode and scale functions being used - -static screen_mode_t *screen_mode; - -// Window resize state. - -static boolean need_resize = false; -static unsigned int resize_w, resize_h; -static unsigned int last_resize_time; - -// If true, keyboard mapping is ignored, like in Vanilla Doom. -// The sensible thing to do is to disable this if you have a non-US -// keyboard. - -int vanilla_keyboard_mapping = true; - -// Is the shift key currently down? - -static int shiftdown = 0; - // Mouse acceleration // // This emulates some of the behavior of DOS mouse drivers by increasing @@ -285,907 +116,255 @@ int mouse_threshold = 10; int usegamma = 0; -static void ApplyWindowResize(unsigned int w, unsigned int h); - -static boolean MouseShouldBeGrabbed() +typedef struct { - // never grab the mouse when in screensaver mode - - if (screensaver_mode) - return false; + byte r; + byte g; + byte b; +} col_t; - // if the window doesn't have focus, never grab it +// Palette converted to RGB565 - if (!window_focused) - return false; +static uint16_t rgb565_palette[256]; - // always grab the mouse when full screen (dont want to - // see the mouse pointer) +void cmap_to_rgb565(uint16_t * out, uint8_t * in, int in_pixels) +{ + int i, j; + struct color c; + uint16_t r, g, b; - if (fullscreen) - return true; - - // Don't grab the mouse if mouse input is disabled - - if (!usemouse || nomouse) - return false; - - // if we specify not to grab the mouse, never grab - - if (!grabmouse) - return false; - - // Invoke the grabmouse callback function to determine whether - // the mouse should be grabbed - - if (grabmouse_callback != NULL) + for (i = 0; i < in_pixels; i++) { - return grabmouse_callback(); - } - else - { - return true; + c = colors[*in]; + r = ((uint16_t)(c.r >> 3)) << 11; + g = ((uint16_t)(c.g >> 2)) << 5; + b = ((uint16_t)(c.b >> 3)) << 0; + *out = (r | g | b); + + in++; + for (j = 0; j < fb_scaling; j++) { + out++; + } } } -void I_SetGrabMouseCallback(grabmouse_callback_t func) +void cmap_to_fb(uint8_t * out, uint8_t * in, int in_pixels) { - grabmouse_callback = func; -} + int i, j, k; + struct color c; + uint32_t pix; + uint16_t r, g, b; -// Set the variable controlling FPS dots. - -void I_DisplayFPSDots(boolean dots_on) -{ - display_fps_dots = dots_on; -} - -// Update the value of window_focused when we get a focus event -// -// We try to make ourselves be well-behaved: the grab on the mouse -// is removed if we lose focus (such as a popup window appearing), -// and we dont move the mouse around if we aren't focused either. - -static void UpdateFocus(void) -{ - Uint8 state; - - state = SDL_GetAppState(); - - // We should have input (keyboard) focus and be visible - // (not minimized) - - window_focused = (state & SDL_APPINPUTFOCUS) && (state & SDL_APPACTIVE); - - // Should the screen be grabbed? - - screenvisible = (state & SDL_APPACTIVE) != 0; -} - -// Show or hide the mouse cursor. We have to use different techniques -// depending on the OS. - -static void SetShowCursor(boolean show) -{ - // On Windows, using SDL_ShowCursor() adds lag to the mouse input, - // so work around this by setting an invisible cursor instead. On - // other systems, it isn't possible to change the cursor, so this - // hack has to be Windows-only. (Thanks to entryway for this) - -#ifdef _WIN32 - if (show) + for (i = 0; i < in_pixels; i++) { - SDL_SetCursor(cursors[1]); - } - else - { - SDL_SetCursor(cursors[0]); - } -#else - SDL_ShowCursor(show); -#endif + c = colors[*in]; /* R:8 G:8 B:8 format! */ + r = (uint16_t)(c.r >> (8 - s_Fb.red.length)); + g = (uint16_t)(c.g >> (8 - s_Fb.green.length)); + b = (uint16_t)(c.b >> (8 - s_Fb.blue.length)); + pix = r << s_Fb.red.offset; + pix |= g << s_Fb.green.offset; + pix |= b << s_Fb.blue.offset; - // When the cursor is hidden, grab the input. - - if (!screensaver_mode) - { - SDL_WM_GrabInput(!show); + for (k = 0; k < fb_scaling; k++) { + for (j = 0; j < s_Fb.bits_per_pixel/8; j++) { + *out = (pix >> (j*8)); + out++; + } + } + in++; } } -void I_EnableLoadingDisk(void) +void I_InitGraphics (void) { - patch_t *disk; - byte *tmpbuf; - char *disk_name; - int y; - char buf[20]; + int i; - SDL_VideoDriverName(buf, 15); + memset(&s_Fb, 0, sizeof(struct FB_ScreenInfo)); + s_Fb.xres = DOOMGENERIC_RESX; + s_Fb.yres = DOOMGENERIC_RESY; + s_Fb.xres_virtual = s_Fb.xres; + s_Fb.yres_virtual = s_Fb.yres; + s_Fb.bits_per_pixel = 32; - if (!strcmp(buf, "Quartz")) - { - // MacOS Quartz gives us pageflipped graphics that screw up the - // display when we use the loading disk. Disable it. - // This is a gross hack. + s_Fb.blue.length = 8; + s_Fb.green.length = 8; + s_Fb.red.length = 8; + s_Fb.transp.length = 8; - return; - } - - if (M_CheckParm("-cdrom") > 0) - disk_name = DEH_String("STCDROM"); - else - disk_name = DEH_String("STDISK"); - - disk = W_CacheLumpName(disk_name, PU_STATIC); - - // Draw the patch into a temporary buffer - - tmpbuf = Z_Malloc(SCREENWIDTH * (disk->height + 1), PU_STATIC, NULL); - V_UseBuffer(tmpbuf); - - // Draw the disk to the screen: - - V_DrawPatch(0, 0, disk); - - disk_image = Z_Malloc(LOADING_DISK_W * LOADING_DISK_H, PU_STATIC, NULL); - saved_background = Z_Malloc(LOADING_DISK_W * LOADING_DISK_H, PU_STATIC, NULL); - - for (y=0; ysym) - { - case SDLK_LEFT: return KEY_LEFTARROW; - case SDLK_RIGHT: return KEY_RIGHTARROW; - case SDLK_DOWN: return KEY_DOWNARROW; - case SDLK_UP: return KEY_UPARROW; - case SDLK_ESCAPE: return KEY_ESCAPE; - case SDLK_RETURN: return KEY_ENTER; - case SDLK_TAB: return KEY_TAB; - case SDLK_F1: return KEY_F1; - case SDLK_F2: return KEY_F2; - case SDLK_F3: return KEY_F3; - case SDLK_F4: return KEY_F4; - case SDLK_F5: return KEY_F5; - case SDLK_F6: return KEY_F6; - case SDLK_F7: return KEY_F7; - case SDLK_F8: return KEY_F8; - case SDLK_F9: return KEY_F9; - case SDLK_F10: return KEY_F10; - case SDLK_F11: return KEY_F11; - case SDLK_F12: return KEY_F12; - case SDLK_PRINT: return KEY_PRTSCR; - - case SDLK_BACKSPACE: return KEY_BACKSPACE; - case SDLK_DELETE: return KEY_DEL; - - case SDLK_PAUSE: return KEY_PAUSE; - -#if !SDL_VERSION_ATLEAST(1, 3, 0) - case SDLK_EQUALS: return KEY_EQUALS; -#endif - - case SDLK_MINUS: return KEY_MINUS; - - case SDLK_LSHIFT: - case SDLK_RSHIFT: - return KEY_RSHIFT; + s_Fb.blue.offset = 0; + s_Fb.green.offset = 8; + s_Fb.red.offset = 16; + s_Fb.transp.offset = 24; - case SDLK_LCTRL: - case SDLK_RCTRL: - return KEY_RCTRL; - - case SDLK_LALT: - case SDLK_RALT: -#if !SDL_VERSION_ATLEAST(1, 3, 0) - case SDLK_LMETA: - case SDLK_RMETA: -#endif - return KEY_RALT; - case SDLK_CAPSLOCK: return KEY_CAPSLOCK; - case SDLK_SCROLLOCK: return KEY_SCRLCK; - case SDLK_NUMLOCK: return KEY_NUMLOCK; + printf("I_InitGraphics: framebuffer: x_res: %d, y_res: %d, x_virtual: %d, y_virtual: %d, bpp: %d\n", + s_Fb.xres, s_Fb.yres, s_Fb.xres_virtual, s_Fb.yres_virtual, s_Fb.bits_per_pixel); - case SDLK_KP0: return KEYP_0; - case SDLK_KP1: return KEYP_1; - case SDLK_KP2: return KEYP_2; - case SDLK_KP3: return KEYP_3; - case SDLK_KP4: return KEYP_4; - case SDLK_KP5: return KEYP_5; - case SDLK_KP6: return KEYP_6; - case SDLK_KP7: return KEYP_7; - case SDLK_KP8: return KEYP_8; - case SDLK_KP9: return KEYP_9; + printf("I_InitGraphics: framebuffer: RGBA: %d%d%d%d, red_off: %d, green_off: %d, blue_off: %d, transp_off: %d\n", + s_Fb.red.length, s_Fb.green.length, s_Fb.blue.length, s_Fb.transp.length, s_Fb.red.offset, s_Fb.green.offset, s_Fb.blue.offset, s_Fb.transp.offset); - case SDLK_KP_PERIOD: return KEYP_PERIOD; - case SDLK_KP_MULTIPLY: return KEYP_MULTIPLY; - case SDLK_KP_PLUS: return KEYP_PLUS; - case SDLK_KP_MINUS: return KEYP_MINUS; - case SDLK_KP_DIVIDE: return KEYP_DIVIDE; - case SDLK_KP_EQUALS: return KEYP_EQUALS; - case SDLK_KP_ENTER: return KEYP_ENTER; + printf("I_InitGraphics: DOOM screen size: w x h: %d x %d\n", SCREENWIDTH, SCREENHEIGHT); - case SDLK_HOME: return KEY_HOME; - case SDLK_INSERT: return KEY_INS; - case SDLK_END: return KEY_END; - case SDLK_PAGEUP: return KEY_PGUP; - case SDLK_PAGEDOWN: return KEY_PGDN; -#ifdef SDL_HAVE_APP_KEYS - case SDLK_APP1: return KEY_F1; - case SDLK_APP2: return KEY_F2; - case SDLK_APP3: return KEY_F3; - case SDLK_APP4: return KEY_F4; - case SDLK_APP5: return KEY_F5; - case SDLK_APP6: return KEY_F6; -#endif - - default: - return tolower(sym->sym); + i = M_CheckParmWithArgs("-scaling", 1); + if (i > 0) { + i = atoi(myargv[i + 1]); + fb_scaling = i; + printf("I_InitGraphics: Scaling factor: %d\n", fb_scaling); + } else { + fb_scaling = s_Fb.xres / SCREENWIDTH; + if (s_Fb.yres / SCREENHEIGHT < fb_scaling) + fb_scaling = s_Fb.yres / SCREENHEIGHT; + printf("I_InitGraphics: Auto-scaling factor: %d\n", fb_scaling); } + + + /* Allocate screen to draw to */ + I_VideoBuffer = (byte*)Z_Malloc (SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL); // For DOOM to draw on + I_VideoBuffer_FB = (byte*)malloc(s_Fb.xres * s_Fb.yres * (s_Fb.bits_per_pixel/8)); // For a single write() syscall to fbdev + + screenvisible = true; + + extern int I_InitInput(void); + I_InitInput(); } -void I_ShutdownGraphics(void) +void I_ShutdownGraphics (void) { - if (initialized) - { - SetShowCursor(true); - - SDL_QuitSubSystem(SDL_INIT_VIDEO); - - initialized = false; - } + Z_Free (I_VideoBuffer); + free(I_VideoBuffer_FB); } - -void __attribute__ ((weak)) I_GetEvent(void) -{ - -} - -// -// I_StartFrame -// void I_StartFrame (void) { - I_GetEvent(); + } -static void UpdateMouseButtonState(unsigned int button, boolean on) -{ - event_t event; - - if (button < SDL_BUTTON_LEFT || button > MAX_MOUSE_BUTTONS) - { - return; - } - - // Note: button "0" is left, button "1" is right, - // button "2" is middle for Doom. This is different - // to how SDL sees things. - - switch (button) - { - case SDL_BUTTON_LEFT: - button = 0; - break; - - case SDL_BUTTON_RIGHT: - button = 1; - break; - - case SDL_BUTTON_MIDDLE: - button = 2; - break; - - default: - // SDL buttons are indexed from 1. - --button; - break; - } - - // Turn bit representing this button on or off. - - if (on) - { - mouse_button_state |= (1 << button); - } - else - { - mouse_button_state &= ~(1 << button); - } - - // Post an event with the new button state. - - event.type = ev_mouse; - event.data1 = mouse_button_state; - event.data2 = event.data3 = 0; - D_PostEvent(&event); -} - -static int AccelerateMouse(int val) -{ - if (val < 0) - return -AccelerateMouse(-val); - - if (val > mouse_threshold) - { - return (int)((val - mouse_threshold) * mouse_acceleration + mouse_threshold); - } - else - { - return val; - } -} - -// Get the equivalent ASCII (Unicode?) character for a keypress. - -static int GetTypedChar(SDL_Event *event) -{ - int key; - - // If Vanilla keyboard mapping enabled, the keyboard - // scan code is used to give the character typed. - // This does not change depending on keyboard layout. - // If you have a German keyboard, pressing 'z' will - // give 'y', for example. It is desirable to be able - // to fix this so that people with non-standard - // keyboard mappings can type properly. If vanilla - // mode is disabled, use the properly translated - // version. - - if (vanilla_keyboard_mapping) - { - key = TranslateKey(&event->key.keysym); - - // Is shift held down? If so, perform a translation. - - if (shiftdown > 0) - { - if (key >= 0 && key < arrlen(shiftxform)) - { - key = shiftxform[key]; - } - else - { - key = 0; - } - } - - return key; - } - else - { - // Unicode value, from key layout. - - return tolower(event->key.keysym.unicode); - } -} - -static void UpdateShiftStatus(SDL_Event *event) -{ - int change; - - if (event->type == SDL_KEYDOWN) - { - change = 1; - } - else if (event->type == SDL_KEYUP) - { - change = -1; - } - else - { - return; - } - - if (event->key.keysym.sym == SDLK_LSHIFT - || event->key.keysym.sym == SDLK_RSHIFT) - { - shiftdown += change; - } -} - -void I_GetEvent(void) -{ - SDL_Event sdlevent; - event_t event; - - // possibly not needed - - SDL_PumpEvents(); - - // put event-grabbing stuff in here - - while (SDL_PollEvent(&sdlevent)) - { - // ignore mouse events when the window is not focused - - if (!window_focused - && (sdlevent.type == SDL_MOUSEMOTION - || sdlevent.type == SDL_MOUSEBUTTONDOWN - || sdlevent.type == SDL_MOUSEBUTTONUP)) - { - continue; - } - - if (screensaver_mode && sdlevent.type == SDL_QUIT) - { - I_Quit(); - } - - UpdateShiftStatus(&sdlevent); - - // process event - - switch (sdlevent.type) - { - case SDL_KEYDOWN: - // data1 has the key pressed, data2 has the character - // (shift-translated, etc) - event.type = ev_keydown; - event.data1 = TranslateKey(&sdlevent.key.keysym); - event.data2 = GetTypedChar(&sdlevent); - - if (event.data1 != 0) - { - D_PostEvent(&event); - } - break; - - case SDL_KEYUP: - event.type = ev_keyup; - event.data1 = TranslateKey(&sdlevent.key.keysym); - - // data2 is just initialized to zero for ev_keyup. - // For ev_keydown it's the shifted Unicode character - // that was typed, but if something wants to detect - // key releases it should do so based on data1 - // (key ID), not the printable char. - - event.data2 = 0; - - if (event.data1 != 0) - { - D_PostEvent(&event); - } - break; - - /* - case SDL_MOUSEMOTION: - event.type = ev_mouse; - event.data1 = mouse_button_state; - event.data2 = AccelerateMouse(sdlevent.motion.xrel); - event.data3 = -AccelerateMouse(sdlevent.motion.yrel); - D_PostEvent(&event); - break; - */ - - case SDL_MOUSEBUTTONDOWN: - if (usemouse && !nomouse) - { - UpdateMouseButtonState(sdlevent.button.button, true); - } - break; - - case SDL_MOUSEBUTTONUP: - if (usemouse && !nomouse) - { - UpdateMouseButtonState(sdlevent.button.button, false); - } - break; - - case SDL_QUIT: - event.type = ev_quit; - D_PostEvent(&event); - break; - - case SDL_ACTIVEEVENT: - // need to update our focus state - UpdateFocus(); - break; - - case SDL_VIDEOEXPOSE: - palette_to_set = true; - break; - - case SDL_RESIZABLE: - need_resize = true; - resize_w = sdlevent.resize.w; - resize_h = sdlevent.resize.h; - last_resize_time = SDL_GetTicks(); - break; - - default: - break; - } - } -} - -// Warp the mouse back to the middle of the screen - -static void CenterMouse(void) -{ - // Warp the the screen center - - SDL_WarpMouse(screen->w / 2, screen->h / 2); - - // Clear any relative movement caused by warping - - SDL_PumpEvents(); -#if SDL_VERSION_ATLEAST(1, 3, 0) - SDL_GetRelativeMouseState(0, NULL, NULL); -#else - SDL_GetRelativeMouseState(NULL, NULL); -#endif -} - -// -// Read the change in mouse state to generate mouse motion events -// -// This is to combine all mouse movement for a tic into one mouse -// motion event. - -static void I_ReadMouse(void) -{ - int x, y; - event_t ev; - -#if SDL_VERSION_ATLEAST(1, 3, 0) - SDL_GetRelativeMouseState(0, &x, &y); -#else - SDL_GetRelativeMouseState(&x, &y); -#endif - - if (x != 0 || y != 0) - { - ev.type = ev_mouse; - ev.data1 = mouse_button_state; - ev.data2 = AccelerateMouse(x); - - if (!novert) - { - ev.data3 = -AccelerateMouse(y); - } - else - { - ev.data3 = 0; - } - - D_PostEvent(&ev); - } - - if (MouseShouldBeGrabbed()) - { - CenterMouse(); - } -} - -// -// I_StartTic -// void I_StartTic (void) { - if (!initialized) - { - return; - } - - I_GetEvent(); - - if (usemouse && !nomouse) - { - I_ReadMouse(); - } - - I_UpdateJoystick(); + I_GetEvent(); } - -// -// I_UpdateNoBlit -// void I_UpdateNoBlit (void) { - // what is this? -} - -static void UpdateGrab(void) -{ - static boolean currently_grabbed = false; - boolean grab; - - grab = MouseShouldBeGrabbed(); - - if (screensaver_mode) - { - // Hide the cursor in screensaver mode - - SetShowCursor(false); - } - else if (grab && !currently_grabbed) - { - SetShowCursor(false); - CenterMouse(); - } - else if (!grab && currently_grabbed) - { - SetShowCursor(true); - - // When releasing the mouse from grab, warp the mouse cursor to - // the bottom-right of the screen. This is a minimally distracting - // place for it to appear - we may only have released the grab - // because we're at an end of level intermission screen, for - // example. - - SDL_WarpMouse(screen->w - 16, screen->h - 16); - SDL_GetRelativeMouseState(NULL, NULL); - } - - currently_grabbed = grab; - -} - -// Update a small portion of the screen -// -// Does stretching and buffer blitting if neccessary -// -// Return true if blit was successful. - -static boolean BlitArea(int x1, int y1, int x2, int y2) -{ - int x_offset, y_offset; - boolean result; - - // No blit needed on native surface - - if (native_surface) - { - return true; - } - - x_offset = (screenbuffer->w - screen_mode->width) / 2; - y_offset = (screenbuffer->h - screen_mode->height) / 2; - - if (SDL_LockSurface(screenbuffer) >= 0) - { - I_InitScale(I_VideoBuffer, - (byte *) screenbuffer->pixels - + (y_offset * screenbuffer->pitch) - + x_offset, - screenbuffer->pitch); - result = screen_mode->DrawScreen(x1, y1, x2, y2); - SDL_UnlockSurface(screenbuffer); - } - else - { - result = false; - } - - return result; -} - -static void UpdateRect(int x1, int y1, int x2, int y2) -{ - int x1_scaled, x2_scaled, y1_scaled, y2_scaled; - - // Do stretching and blitting - - if (BlitArea(x1, y1, x2, y2)) - { - // Update the area - - x1_scaled = (x1 * screen_mode->width) / SCREENWIDTH; - y1_scaled = (y1 * screen_mode->height) / SCREENHEIGHT; - x2_scaled = (x2 * screen_mode->width) / SCREENWIDTH; - y2_scaled = (y2 * screen_mode->height) / SCREENHEIGHT; - - SDL_UpdateRect(screen, - x1_scaled, y1_scaled, - x2_scaled - x1_scaled, - y2_scaled - y1_scaled); - } -} - -void I_BeginRead(void) -{ - byte *screenloc = I_VideoBuffer - + (SCREENHEIGHT - LOADING_DISK_H) * SCREENWIDTH - + (SCREENWIDTH - LOADING_DISK_W); - int y; - - if (!initialized || disk_image == NULL) - return; - - // save background and copy the disk image in - - for (y=0; y last_resize_time + 500) + y = SCREENHEIGHT; + + while (y--) { - ApplyWindowResize(resize_w, resize_h); - need_resize = false; - palette_to_set = true; - } - - UpdateGrab(); - - // Don't update the screen if the window isn't visible. - // Not doing this breaks under Windows when we alt-tab away - // while fullscreen. - - if (!(SDL_GetAppState() & SDL_APPACTIVE)) - return; - - // draws little dots on the bottom of the screen - - if (display_fps_dots) - { - i = I_GetTime(); - tics = i - lasttic; - lasttic = i; - if (tics > 20) tics = 20; - - for (i=0 ; iw - screenbuffer->w) / 2; - dst_rect.y = (screen->h - screenbuffer->h) / 2; - - SDL_BlitSurface(screenbuffer, NULL, screen, &dst_rect); - } - - SDL_Flip(screen); + DG_DrawFrame(); } - // // I_ReadScreen // void I_ReadScreen (byte* scr) { - memcpy(scr, I_VideoBuffer, SCREENWIDTH*SCREENHEIGHT); + memcpy (scr, I_VideoBuffer, SCREENWIDTH * SCREENHEIGHT); } - // // I_SetPalette // -void I_SetPalette (byte *doompalette) +#define GFX_RGB565(r, g, b) ((((r & 0xF8) >> 3) << 11) | (((g & 0xFC) >> 2) << 5) | ((b & 0xF8) >> 3)) +#define GFX_RGB565_R(color) ((0xF800 & color) >> 11) +#define GFX_RGB565_G(color) ((0x07E0 & color) >> 5) +#define GFX_RGB565_B(color) (0x001F & color) + +void I_SetPalette (byte* palette) { - int i; + int i; + //col_t* c; - for (i=0; i<256; ++i) - { - // Zero out the bottom two bits of each channel - the PC VGA - // controller only supports 6 bits of accuracy. + //for (i = 0; i < 256; i++) + //{ + // c = (col_t*)palette; - palette[i].r = gammatable[usegamma][*doompalette++] & ~3; - palette[i].g = gammatable[usegamma][*doompalette++] & ~3; - palette[i].b = gammatable[usegamma][*doompalette++] & ~3; + // rgb565_palette[i] = GFX_RGB565(gammatable[usegamma][c->r], + // gammatable[usegamma][c->g], + // gammatable[usegamma][c->b]); + + // palette += 3; + //} + + + /* performance boost: + * map to the right pixel format over here! */ + + for (i=0; i<256; ++i ) { + colors[i].a = 0; + colors[i].r = gammatable[usegamma][*palette++]; + colors[i].g = gammatable[usegamma][*palette++]; + colors[i].b = gammatable[usegamma][*palette++]; } - - palette_to_set = true; } // Given an RGB value, find the closest matching palette index. -int I_GetPaletteIndex(int r, int g, int b) +int I_GetPaletteIndex (int r, int g, int b) { int best, best_diff, diff; int i; + col_t color; - best = 0; best_diff = INT_MAX; + printf("I_GetPaletteIndex\n"); + + best = 0; + best_diff = INT_MAX; for (i = 0; i < 256; ++i) { - diff = (r - palette[i].r) * (r - palette[i].r) - + (g - palette[i].g) * (g - palette[i].g) - + (b - palette[i].b) * (b - palette[i].b); + color.r = GFX_RGB565_R(rgb565_palette[i]); + color.g = GFX_RGB565_G(rgb565_palette[i]); + color.b = GFX_RGB565_B(rgb565_palette[i]); + + diff = (r - color.r) * (r - color.r) + + (g - color.g) * (g - color.g) + + (b - color.b) * (b - color.b); if (diff < best_diff) { @@ -1202,1014 +381,39 @@ int I_GetPaletteIndex(int r, int g, int b) return best; } -// -// Set the window title -// - -void I_SetWindowTitle(char *title) +void I_BeginRead (void) { - window_title = title; } -// -// Call the SDL function to set the window title, based on -// the title set with I_SetWindowTitle. -// - -void I_InitWindowTitle(void) +void I_EndRead (void) { - char *buf; - - buf = M_StringJoin(window_title, " - ", PACKAGE_STRING, NULL); - SDL_WM_SetCaption(buf, NULL); - free(buf); } -// Set the application icon - -void I_InitWindowIcon(void) +void I_SetWindowTitle (char *title) { - SDL_Surface *surface; - Uint8 *mask; - int i; - - // Generate the mask - - mask = malloc(icon_w * icon_h / 8); - memset(mask, 0, icon_w * icon_h / 8); - - for (i=0; iwidth > w || modes_list[i]->height > h) - { - continue; - } - - num_pixels = modes_list[i]->width * modes_list[i]->height; - - if (num_pixels > best_num_pixels) - { - // This is a better mode than the current one - - best_mode = modes_list[i]; - best_num_pixels = num_pixels; - } - } - - return best_mode; } -// Adjust to an appropriate fullscreen mode. -// Returns true if successful. - -static boolean AutoAdjustFullscreen(void) +void I_EnableLoadingDisk(void) { - SDL_Rect **modes; - SDL_Rect *best_mode; - screen_mode_t *screen_mode; - int diff, best_diff; - int i; - - modes = SDL_ListModes(NULL, SDL_FULLSCREEN); - - // No fullscreen modes available at all? - - if (modes == NULL || modes == (SDL_Rect **) -1 || *modes == NULL) - { - return false; - } - - // Find the best mode that matches the mode specified in the - // configuration file - - best_mode = NULL; - best_diff = INT_MAX; - - for (i=0; modes[i] != NULL; ++i) - { - //printf("%ix%i?\n", modes[i]->w, modes[i]->h); - - // What screen_mode_t would be used for this video mode? - - screen_mode = I_FindScreenMode(modes[i]->w, modes[i]->h); - - // Never choose a screen mode that we cannot run in, or - // is poor quality for fullscreen - - if (screen_mode == NULL || screen_mode->poor_quality) - { - // printf("\tUnsupported / poor quality\n"); - continue; - } - - // Do we have the exact mode? - // If so, no autoadjust needed - - if (screen_width == modes[i]->w && screen_height == modes[i]->h) - { - // printf("\tExact mode!\n"); - return true; - } - - // Is this mode better than the current mode? - - diff = (screen_width - modes[i]->w) * (screen_width - modes[i]->w) - + (screen_height - modes[i]->h) * (screen_height - modes[i]->h); - - if (diff < best_diff) - { - // printf("\tA valid mode\n"); - best_mode = modes[i]; - best_diff = diff; - } - } - - if (best_mode == NULL) - { - // Unable to find a valid mode! - - return false; - } - - printf("I_InitGraphics: %ix%i mode not supported on this machine.\n", - screen_width, screen_height); - - screen_width = best_mode->w; - screen_height = best_mode->h; - - return true; } -// Auto-adjust to a valid windowed mode. - -static void AutoAdjustWindowed(void) +void I_BindVideoVariables (void) { - screen_mode_t *best_mode; - - // Find a screen_mode_t to fit within the current settings - - best_mode = I_FindScreenMode(screen_width, screen_height); - - if (best_mode == NULL) - { - // Nothing fits within the current settings. - // Pick the closest to 320x200 possible. - - best_mode = I_FindScreenMode(SCREENWIDTH, SCREENHEIGHT_4_3); - } - - // Switch to the best mode if necessary. - - if (best_mode->width != screen_width || best_mode->height != screen_height) - { - printf("I_InitGraphics: Cannot run at specified mode: %ix%i\n", - screen_width, screen_height); - - screen_width = best_mode->width; - screen_height = best_mode->height; - } } -// Auto-adjust to a valid color depth. - -static void AutoAdjustColorDepth(void) +void I_DisplayFPSDots (boolean dots_on) { - SDL_Rect **modes; - SDL_PixelFormat format; - const SDL_VideoInfo *info; - int flags; - - // If screen_bpp=0, we should use the current (default) pixel depth. - // Fetch it from SDL. - - if (screen_bpp == 0) - { - info = SDL_GetVideoInfo(); - - if (info != NULL && info->vfmt != NULL) - { - screen_bpp = info->vfmt->BitsPerPixel; - } - } - - if (fullscreen) - { - flags = SDL_FULLSCREEN; - } - else - { - flags = 0; - } - - format.BitsPerPixel = screen_bpp; - format.BytesPerPixel = (screen_bpp + 7) / 8; - - // Are any screen modes supported at the configured color depth? - - modes = SDL_ListModes(&format, flags); - - // If not, we must autoadjust to something sensible. - - if (modes == NULL) - { - printf("I_InitGraphics: %ibpp color depth not supported.\n", - screen_bpp); - - info = SDL_GetVideoInfo(); - - if (info != NULL && info->vfmt != NULL) - { - screen_bpp = info->vfmt->BitsPerPixel; - } - } } -// If the video mode set in the configuration file is not available, -// try to choose a different mode. - -static void I_AutoAdjustSettings(void) +void I_CheckIsScreensaver (void) { - int old_screen_w, old_screen_h, old_screen_bpp; - - old_screen_w = screen_width; - old_screen_h = screen_height; - old_screen_bpp = screen_bpp; - - // Possibly adjust color depth. - - AutoAdjustColorDepth(); - - // If we are running fullscreen, try to autoadjust to a valid fullscreen - // mode. If this is impossible, switch to windowed. - - if (fullscreen && !AutoAdjustFullscreen()) - { - fullscreen = 0; - } - - // If we are running windowed, pick a valid window size. - - if (!fullscreen) - { - AutoAdjustWindowed(); - } - - // Have the settings changed? Show a message. - - if (screen_width != old_screen_w || screen_height != old_screen_h - || screen_bpp != old_screen_bpp) - { - printf("I_InitGraphics: Auto-adjusted to %ix%ix%ibpp.\n", - screen_width, screen_height, screen_bpp); - - printf("NOTE: Your video settings have been adjusted. " - "To disable this behavior,\n" - "set autoadjust_video_settings to 0 in your " - "configuration file.\n"); - } -} - -// Set video size to a particular scale factor (1x, 2x, 3x, etc.) - -static void SetScaleFactor(int factor) -{ - int w, h; - - // Pick 320x200 or 320x240, depending on aspect ratio correct - - if (aspect_ratio_correct) - { - w = SCREENWIDTH; - h = SCREENHEIGHT_4_3; - } - else - { - w = SCREENWIDTH; - h = SCREENHEIGHT; - } - - screen_width = w * factor; - screen_height = h * factor; -} - -void I_GraphicsCheckCommandLine(void) -{ - int i; - - //! - // @vanilla - // - // Disable blitting the screen. - // - - noblit = M_CheckParm ("-noblit"); - - //! - // @category video - // - // Grab the mouse when running in windowed mode. - // - - if (M_CheckParm("-grabmouse")) - { - grabmouse = true; - } - - //! - // @category video - // - // Don't grab the mouse when running in windowed mode. - // - - if (M_CheckParm("-nograbmouse")) - { - grabmouse = false; - } - - // default to fullscreen mode, allow override with command line - // nofullscreen because we love prboom - - //! - // @category video - // - // Run in a window. - // - - if (M_CheckParm("-window") || M_CheckParm("-nofullscreen")) - { - fullscreen = false; - } - - //! - // @category video - // - // Run in fullscreen mode. - // - - if (M_CheckParm("-fullscreen")) - { - fullscreen = true; - } - - //! - // @category video - // - // Disable the mouse. - // - - nomouse = M_CheckParm("-nomouse") > 0; - - //! - // @category video - // @arg - // - // Specify the screen width, in pixels. - // - - i = M_CheckParmWithArgs("-width", 1); - - if (i > 0) - { - screen_width = atoi(myargv[i + 1]); - } - - //! - // @category video - // @arg - // - // Specify the screen height, in pixels. - // - - i = M_CheckParmWithArgs("-height", 1); - - if (i > 0) - { - screen_height = atoi(myargv[i + 1]); - } - - //! - // @category video - // @arg - // - // Specify the color depth of the screen, in bits per pixel. - // - - i = M_CheckParmWithArgs("-bpp", 1); - - if (i > 0) - { - screen_bpp = atoi(myargv[i + 1]); - } - - // Because we love Eternity: - - //! - // @category video - // - // Set the color depth of the screen to 32 bits per pixel. - // - - if (M_CheckParm("-8in32")) - { - screen_bpp = 32; - } - - //! - // @category video - // @arg [wf] - // - // Specify the dimensions of the window or fullscreen mode. An - // optional letter of w or f appended to the dimensions selects - // windowed or fullscreen mode. - - i = M_CheckParmWithArgs("-geometry", 1); - - if (i > 0) - { - int w, h, s; - char f; - - s = sscanf(myargv[i + 1], "%ix%i%1c", &w, &h, &f); - if (s == 2 || s == 3) - { - screen_width = w; - screen_height = h; - - if (s == 3 && f == 'f') - { - fullscreen = true; - } - else if (s == 3 && f == 'w') - { - fullscreen = false; - } - } - } - - //! - // @category video - // - // Don't scale up the screen. - // - - if (M_CheckParm("-1")) - { - SetScaleFactor(1); - } - - //! - // @category video - // - // Double up the screen to 2x its normal size. - // - - if (M_CheckParm("-2")) - { - SetScaleFactor(2); - } - - //! - // @category video - // - // Double up the screen to 3x its normal size. - // - - if (M_CheckParm("-3")) - { - SetScaleFactor(3); - } - - //! - // @category video - // - // Disable vertical mouse movement. - // - - if (M_CheckParm("-novert")) - { - novert = true; - } - - //! - // @category video - // - // Enable vertical mouse movement. - // - - if (M_CheckParm("-nonovert")) - { - novert = false; - } -} - -// Check if we have been invoked as a screensaver by xscreensaver. - -void I_CheckIsScreensaver(void) -{ - char *env; - - env = getenv("XSCREENSAVER_WINDOW"); - - if (env != NULL) - { - screensaver_mode = true; - } -} - -static void CreateCursors(void) -{ - static Uint8 empty_cursor_data = 0; - - // Save the default cursor so it can be recalled later - - cursors[1] = SDL_GetCursor(); - - // Create an empty cursor - - cursors[0] = SDL_CreateCursor(&empty_cursor_data, - &empty_cursor_data, - 1, 1, 0, 0); -} - -static void SetSDLVideoDriver(void) -{ - // Allow a default value for the SDL video driver to be specified - // in the configuration file. - - if (strcmp(video_driver, "") != 0) - { - char *env_string; - - env_string = M_StringJoin("SDL_VIDEODRIVER=", video_driver, NULL); - putenv(env_string); - free(env_string); - } -} - -static void SetWindowPositionVars(void) -{ - char buf[64]; - int x, y; - - if (window_position == NULL || !strcmp(window_position, "")) - { - return; - } - - if (!strcmp(window_position, "center")) - { - putenv("SDL_VIDEO_CENTERED=1"); - } - else if (sscanf(window_position, "%i,%i", &x, &y) == 2) - { - M_snprintf(buf, sizeof(buf), "SDL_VIDEO_WINDOW_POS=%i,%i", x, y); - putenv(buf); - } -} - -static char *WindowBoxType(screen_mode_t *mode, int w, int h) -{ - if (mode->width != w && mode->height != h) - { - return "Windowboxed"; - } - else if (mode->width == w) - { - return "Letterboxed"; - } - else if (mode->height == h) - { - return "Pillarboxed"; - } - else - { - return "..."; - } -} - -static void SetVideoMode(screen_mode_t *mode, int w, int h) -{ - byte *doompal; - int flags = 0; - - doompal = W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE); - - // If we are already running and in a true color mode, we need - // to free the screenbuffer surface before setting the new mode. - - if (screenbuffer != NULL && screen != screenbuffer) - { - SDL_FreeSurface(screenbuffer); - } - - // Generate lookup tables before setting the video mode. - - if (mode != NULL && mode->InitMode != NULL) - { - mode->InitMode(doompal); - } - - // Set the video mode. - - flags |= SDL_SWSURFACE | SDL_DOUBLEBUF; - - if (screen_bpp == 8) - { - flags |= SDL_HWPALETTE; - } - - if (fullscreen) - { - flags |= SDL_FULLSCREEN; - } - else - { - // In windowed mode, the window can be resized while the game is - // running. This feature is disabled on OS X, as it adds an ugly - // scroll handle to the corner of the screen. - -#ifndef __MACOSX__ - flags |= SDL_RESIZABLE; -#endif - } - - screen = SDL_SetVideoMode(w, h, screen_bpp, flags); - - if (screen == NULL) - { - I_Error("Error setting video mode %ix%ix%ibpp: %s\n", - w, h, screen_bpp, SDL_GetError()); - } - - // Blank out the full screen area in case there is any junk in - // the borders that won't otherwise be overwritten. - - SDL_FillRect(screen, NULL, 0); - - // If mode was not set, it must be set now that we know the - // screen size. - - if (mode == NULL) - { - mode = I_FindScreenMode(screen->w, screen->h); - - if (mode == NULL) - { - I_Error("I_InitGraphics: Unable to find a screen mode small " - "enough for %ix%i", screen->w, screen->h); - } - - // Generate lookup tables before setting the video mode. - - if (mode->InitMode != NULL) - { - mode->InitMode(doompal); - } - } - - // Create the screenbuffer surface; if we have a real 8-bit palettized - // screen, then we can use the screen as the screenbuffer. - - if (screen->format->BitsPerPixel == 8) - { - screenbuffer = screen; - } - else - { - screenbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, - mode->width, mode->height, 8, - 0, 0, 0, 0); - - SDL_FillRect(screenbuffer, NULL, 0); - } - - // Save screen mode. - - screen_mode = mode; -} - -static void ApplyWindowResize(unsigned int w, unsigned int h) -{ - screen_mode_t *mode; - - // Find the biggest screen mode that will fall within these - // dimensions, falling back to the smallest mode possible if - // none is found. - - mode = I_FindScreenMode(w, h); - - if (mode == NULL) - { - mode = I_FindScreenMode(SCREENWIDTH, SCREENHEIGHT); - } - - // Reset mode to resize window. - - printf("Resize to %ix%i\n", mode->width, mode->height); - SetVideoMode(mode, mode->width, mode->height); - - // Save settings. - - screen_width = mode->width; - screen_height = mode->height; -} - -void I_InitGraphics(void) -{ - SDL_Event dummy; - byte *doompal; - char *env; - - // Pass through the XSCREENSAVER_WINDOW environment variable to - // SDL_WINDOWID, to embed the SDL window into the Xscreensaver - // window. - - env = getenv("XSCREENSAVER_WINDOW"); - - if (env != NULL) - { - char winenv[30]; - int winid; - - sscanf(env, "0x%x", &winid); - M_snprintf(winenv, sizeof(winenv), "SDL_WINDOWID=%i", winid); - - putenv(winenv); - } - - SetSDLVideoDriver(); - SetWindowPositionVars(); - - if (SDL_Init(SDL_INIT_VIDEO) < 0) - { - I_Error("Failed to initialize video: %s", SDL_GetError()); - } - - // Set up title and icon. Windows cares about the ordering; this - // has to be done before the call to SDL_SetVideoMode. - - I_InitWindowTitle(); -#if !SDL_VERSION_ATLEAST(1, 3, 0) - I_InitWindowIcon(); -#endif - - // Warning to OS X users... though they might never see it :( -#ifdef __MACOSX__ - if (fullscreen) - { - printf("Some old versions of OS X might crash in fullscreen mode.\n" - "If this happens to you, switch back to windowed mode.\n"); - } -#endif - - // - // Enter into graphics mode. - // - // When in screensaver mode, run full screen and auto detect - // screen dimensions (don't change video mode) - // - - if (screensaver_mode) - { - SetVideoMode(NULL, 0, 0); - } - else - { - int w, h; - - if (autoadjust_video_settings) - { - I_AutoAdjustSettings(); - } - - w = screen_width; - h = screen_height; - - screen_mode = I_FindScreenMode(w, h); - - if (screen_mode == NULL) - { - I_Error("I_InitGraphics: Unable to find a screen mode small " - "enough for %ix%i", w, h); - } - - if (w != screen_mode->width || h != screen_mode->height) - { - printf("I_InitGraphics: %s (%ix%i within %ix%i)\n", - WindowBoxType(screen_mode, w, h), - screen_mode->width, screen_mode->height, w, h); - } - - SetVideoMode(screen_mode, w, h); - } - - // Start with a clear black screen - // (screen will be flipped after we set the palette) - - SDL_FillRect(screenbuffer, NULL, 0); - - // Set the palette - - doompal = W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE); - I_SetPalette(doompal); - SDL_SetColors(screenbuffer, palette, 0, 256); - - CreateCursors(); - - UpdateFocus(); - UpdateGrab(); - - // On some systems, it takes a second or so for the screen to settle - // after changing modes. We include the option to add a delay when - // setting the screen mode, so that the game doesn't start immediately - // with the player unable to see anything. - - if (fullscreen && !screensaver_mode) - { - SDL_Delay(startup_delay); - } - - // Check if we have a native surface we can use - // If we have to lock the screen, draw to a buffer and copy - // Likewise if the screen pitch is not the same as the width - // If we have to multiply, drawing is done to a separate 320x200 buf - - native_surface = screen == screenbuffer - && !SDL_MUSTLOCK(screen) - && screen_mode == &mode_scale_1x - && screen->pitch == SCREENWIDTH - && aspect_ratio_correct; - - // If not, allocate a buffer and copy from that buffer to the - // screen when we do an update - - if (native_surface) - { - I_VideoBuffer = (unsigned char *) screen->pixels; - - I_VideoBuffer += (screen->h - SCREENHEIGHT) / 2; - } - else - { - I_VideoBuffer = (unsigned char *) Z_Malloc (SCREENWIDTH * SCREENHEIGHT, - PU_STATIC, NULL); - } - - V_RestoreBuffer(); - - // Clear the screen to black. - - memset(I_VideoBuffer, 0, SCREENWIDTH * SCREENHEIGHT); - - // We need SDL to give us translated versions of keys as well - - SDL_EnableUNICODE(1); - - // Repeat key presses - this is what Vanilla Doom does - // Not sure about repeat rate - probably dependent on which DOS - // driver is used. This is good enough though. - - SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); - - // clear out any events waiting at the start and center the mouse - - while (SDL_PollEvent(&dummy)); - - initialized = true; - - // Call I_ShutdownGraphics on quit - - I_AtExit(I_ShutdownGraphics, true); -} - -// Bind all variables controlling video options into the configuration -// file system. - -void I_BindVideoVariables(void) -{ - M_BindVariable("use_mouse", &usemouse); - M_BindVariable("autoadjust_video_settings", &autoadjust_video_settings); - M_BindVariable("fullscreen", &fullscreen); - M_BindVariable("aspect_ratio_correct", &aspect_ratio_correct); - M_BindVariable("startup_delay", &startup_delay); - M_BindVariable("screen_width", &screen_width); - M_BindVariable("screen_height", &screen_height); - M_BindVariable("screen_bpp", &screen_bpp); - M_BindVariable("grabmouse", &grabmouse); - M_BindVariable("mouse_acceleration", &mouse_acceleration); - M_BindVariable("mouse_threshold", &mouse_threshold); - M_BindVariable("video_driver", &video_driver); - M_BindVariable("window_position", &window_position); - M_BindVariable("usegamma", &usegamma); - M_BindVariable("vanilla_keyboard_mapping", &vanilla_keyboard_mapping); - M_BindVariable("novert", &novert); - M_BindVariable("png_screenshots", &png_screenshots); - - // Windows Vista or later? Set screen color depth to - // 32 bits per pixel, as 8-bit palettized screen modes - // don't work properly in recent versions. - -#if defined(_WIN32) && !defined(_WIN32_WCE) - { - OSVERSIONINFOEX version_info; - - ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX)); - version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - - GetVersionEx((OSVERSIONINFO *) &version_info); - - if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT - && version_info.dwMajorVersion >= 6) - { - screen_bpp = 32; - } - } -#endif - - // Disable fullscreen by default on OS X, as there is an SDL bug - // where some old versions of OS X (<= Snow Leopard) crash. - -#ifdef __MACOSX__ - fullscreen = 0; - screen_width = 800; - screen_height = 600; -#endif } diff --git a/doomgeneric/i_video_fbdev.c b/doomgeneric/i_video_fbdev.c deleted file mode 100644 index c6e5925..0000000 --- a/doomgeneric/i_video_fbdev.c +++ /dev/null @@ -1,568 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// 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. -// -// $Log:$ -// -// DESCRIPTION: -// DOOM graphics stuff for X11, UNIX. -// -//----------------------------------------------------------------------------- - -static const char -rcsid[] = "$Id: i_x.c,v 1.6 1997/02/03 22:45:10 b1 Exp $"; - -#include "config.h" -#include "v_video.h" -#include "m_argv.h" -#include "d_event.h" -#include "d_main.h" -#include "i_video.h" -#include "z_zone.h" - -#include "tables.h" -#include "doomkeys.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -//#define CMAP256 - -struct fb_var_screeninfo fb = {}; -int fb_scaling = 1; -int usemouse = 0; - -struct color { - uint32_t b:8; - uint32_t g:8; - uint32_t r:8; - uint32_t a:8; -}; - -static struct color colors[256]; - -// The screen buffer; this is modified to draw things to the screen - -byte *I_VideoBuffer = NULL; -byte *I_VideoBuffer_FB = NULL; - -/* framebuffer file descriptor */ -int fd_fb = 0; - -int X_width; -int X_height; - -// If true, game is running as a screensaver - -boolean screensaver_mode = false; - -// Flag indicating whether the screen is currently visible: -// when the screen isnt visible, don't render the screen - -boolean screenvisible; - -// Mouse acceleration -// -// This emulates some of the behavior of DOS mouse drivers by increasing -// the speed when the mouse is moved fast. -// -// The mouse input values are input directly to the game, but when -// the values exceed the value of mouse_threshold, they are multiplied -// by mouse_acceleration to increase the speed. - -float mouse_acceleration = 2.0; -int mouse_threshold = 10; - -// Gamma correction level to use - -int usegamma = 0; - -typedef struct -{ - byte r; - byte g; - byte b; -} col_t; - -// Palette converted to RGB565 - -static uint16_t rgb565_palette[256]; - -void cmap_to_rgb565(uint16_t * out, uint8_t * in, int in_pixels) -{ - int i, j; - struct color c; - uint16_t r, g, b; - - for (i = 0; i < in_pixels; i++) - { - c = colors[*in]; - r = ((uint16_t)(c.r >> 3)) << 11; - g = ((uint16_t)(c.g >> 2)) << 5; - b = ((uint16_t)(c.b >> 3)) << 0; - *out = (r | g | b); - - in++; - for (j = 0; j < fb_scaling; j++) { - out++; - } - } -} - -void cmap_to_fb(uint8_t * out, uint8_t * in, int in_pixels) -{ - int i, j, k; - struct color c; - uint32_t pix; - uint16_t r, g, b; - - for (i = 0; i < in_pixels; i++) - { - c = colors[*in]; /* R:8 G:8 B:8 format! */ - r = (uint16_t)(c.r >> (8 - fb.red.length)); - g = (uint16_t)(c.g >> (8 - fb.green.length)); - b = (uint16_t)(c.b >> (8 - fb.blue.length)); - pix = r << fb.red.offset; - pix |= g << fb.green.offset; - pix |= b << fb.blue.offset; - - for (k = 0; k < fb_scaling; k++) { - for (j = 0; j < fb.bits_per_pixel/8; j++) { - *out = (pix >> (j*8)); - out++; - } - } - in++; - } -} - -void I_InitGraphics (void) -{ - int i; - - /* Open fbdev file descriptor */ - fd_fb = open("/dev/fb0", O_RDWR); - if (fd_fb < 0) - { - printf("Could not open /dev/fb0"); - exit(-1); - } - - /* fetch framebuffer info */ - ioctl(fd_fb, FBIOGET_VSCREENINFO, &fb); - /* change params if needed */ - //ioctl(fd_fb, FBIOPUT_VSCREENINFO, &fb); - printf("I_InitGraphics: framebuffer: x_res: %d, y_res: %d, x_virtual: %d, y_virtual: %d, bpp: %d, grayscale: %d\n", - fb.xres, fb.yres, fb.xres_virtual, fb.yres_virtual, fb.bits_per_pixel, fb.grayscale); - - printf("I_InitGraphics: framebuffer: RGBA: %d%d%d%d, red_off: %d, green_off: %d, blue_off: %d, transp_off: %d\n", - fb.red.length, fb.green.length, fb.blue.length, fb.transp.length, fb.red.offset, fb.green.offset, fb.blue.offset, fb.transp.offset); - - printf("I_InitGraphics: DOOM screen size: w x h: %d x %d\n", SCREENWIDTH, SCREENHEIGHT); - - - i = M_CheckParmWithArgs("-scaling", 1); - if (i > 0) { - i = atoi(myargv[i + 1]); - fb_scaling = i; - printf("I_InitGraphics: Scaling factor: %d\n", fb_scaling); - } else { - fb_scaling = fb.xres / SCREENWIDTH; - if (fb.yres / SCREENHEIGHT < fb_scaling) - fb_scaling = fb.yres / SCREENHEIGHT; - printf("I_InitGraphics: Auto-scaling factor: %d\n", fb_scaling); - } - - - /* Allocate screen to draw to */ - I_VideoBuffer = (byte*)Z_Malloc (SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL); // For DOOM to draw on - I_VideoBuffer_FB = (byte*)malloc(fb.xres * fb.yres * (fb.bits_per_pixel/8)); // For a single write() syscall to fbdev - - screenvisible = true; - - extern int I_InitInput(void); - I_InitInput(); -} - -void I_ShutdownGraphics (void) -{ - Z_Free (I_VideoBuffer); - free(I_VideoBuffer_FB); -} - -void I_StartFrame (void) -{ - -} - -__attribute__ ((weak)) void I_GetEvent (void) -{ -// event_t event; -// bool button_state; -// -// button_state = button_read (); -// -// if (last_button_state != button_state) -// { -// last_button_state = button_state; -// -// event.type = last_button_state ? ev_keydown : ev_keyup; -// event.data1 = KEY_FIRE; -// event.data2 = -1; -// event.data3 = -1; -// -// D_PostEvent (&event); -// } -// -// touch_main (); -// -// if ((touch_state.x != last_touch_state.x) || (touch_state.y != last_touch_state.y) || (touch_state.status != last_touch_state.status)) -// { -// last_touch_state = touch_state; -// -// event.type = (touch_state.status == TOUCH_PRESSED) ? ev_keydown : ev_keyup; -// event.data1 = -1; -// event.data2 = -1; -// event.data3 = -1; -// -// if ((touch_state.x > 49) -// && (touch_state.x < 72) -// && (touch_state.y > 104) -// && (touch_state.y < 143)) -// { -// // select weapon -// if (touch_state.x < 60) -// { -// // lower row (5-7) -// if (touch_state.y < 119) -// { -// event.data1 = '5'; -// } -// else if (touch_state.y < 131) -// { -// event.data1 = '6'; -// } -// else -// { -// event.data1 = '1'; -// } -// } -// else -// { -// // upper row (2-4) -// if (touch_state.y < 119) -// { -// event.data1 = '2'; -// } -// else if (touch_state.y < 131) -// { -// event.data1 = '3'; -// } -// else -// { -// event.data1 = '4'; -// } -// } -// } -// else if (touch_state.x < 40) -// { -// // button bar at bottom screen -// if (touch_state.y < 40) -// { -// // enter -// event.data1 = KEY_ENTER; -// } -// else if (touch_state.y < 80) -// { -// // escape -// event.data1 = KEY_ESCAPE; -// } -// else if (touch_state.y < 120) -// { -// // use -// event.data1 = KEY_USE; -// } -// else if (touch_state.y < 160) -// { -// // map -// event.data1 = KEY_TAB; -// } -// else if (touch_state.y < 200) -// { -// // pause -// event.data1 = KEY_PAUSE; -// } -// else if (touch_state.y < 240) -// { -// // toggle run -// if (touch_state.status == TOUCH_PRESSED) -// { -// run = !run; -// -// event.data1 = KEY_RSHIFT; -// -// if (run) -// { -// event.type = ev_keydown; -// } -// else -// { -// event.type = ev_keyup; -// } -// } -// else -// { -// return; -// } -// } -// else if (touch_state.y < 280) -// { -// // save -// event.data1 = KEY_F2; -// } -// else if (touch_state.y < 320) -// { -// // load -// event.data1 = KEY_F3; -// } -// } -// else -// { -// // movement/menu navigation -// if (touch_state.x < 100) -// { -// if (touch_state.y < 100) -// { -// event.data1 = KEY_STRAFE_L; -// } -// else if (touch_state.y < 220) -// { -// event.data1 = KEY_DOWNARROW; -// } -// else -// { -// event.data1 = KEY_STRAFE_R; -// } -// } -// else if (touch_state.x < 180) -// { -// if (touch_state.y < 160) -// { -// event.data1 = KEY_LEFTARROW; -// } -// else -// { -// event.data1 = KEY_RIGHTARROW; -// } -// } -// else -// { -// event.data1 = KEY_UPARROW; -// } -// } -// -// D_PostEvent (&event); -// } -} - -__attribute__ ((weak)) void I_StartTic (void) -{ - I_GetEvent(); -} - -void I_UpdateNoBlit (void) -{ -} - -// -// I_FinishUpdate -// - -void I_FinishUpdate (void) -{ - int y; - int x_offset, y_offset, x_offset_end; - unsigned char *line_in, *line_out; - - /* Offsets in case FB is bigger than DOOM */ - /* 600 = fb heigt, 200 screenheight */ - /* 600 = fb heigt, 200 screenheight */ - /* 2048 =fb width, 320 screenwidth */ - y_offset = (((fb.yres - (SCREENHEIGHT * fb_scaling)) * fb.bits_per_pixel/8)) / 2; - x_offset = (((fb.xres - (SCREENWIDTH * fb_scaling)) * fb.bits_per_pixel/8)) / 2; // XXX: siglent FB hack: /4 instead of /2, since it seems to handle the resolution in a funny way - //x_offset = 0; - x_offset_end = ((fb.xres - (SCREENWIDTH * fb_scaling)) * fb.bits_per_pixel/8) - x_offset; - - /* DRAW SCREEN */ - line_in = (unsigned char *) I_VideoBuffer; - line_out = (unsigned char *) I_VideoBuffer_FB; - - y = SCREENHEIGHT; - - while (y--) - { - int i; - for (i = 0; i < fb_scaling; i++) { - line_out += x_offset; -#ifdef CMAP256 - for (fb_scaling == 1) { - memcpy(line_out, line_in, SCREENWIDTH); /* fb_width is bigger than Doom SCREENWIDTH... */ - } else { - //XXX FIXME fb_scaling support! - } -#else - //cmap_to_rgb565((void*)line_out, (void*)line_in, SCREENWIDTH); - cmap_to_fb((void*)line_out, (void*)line_in, SCREENWIDTH); -#endif - line_out += (SCREENWIDTH * fb_scaling * (fb.bits_per_pixel/8)) + x_offset_end; - } - line_in += SCREENWIDTH; - } - - /* Start drawing from y-offset */ - lseek(fd_fb, y_offset * fb.xres, SEEK_SET); - write(fd_fb, I_VideoBuffer_FB, (SCREENHEIGHT * fb_scaling * (fb.bits_per_pixel/8)) * fb.xres); /* draw only portion used by doom + x-offsets */ -} - -// -// I_ReadScreen -// -void I_ReadScreen (byte* scr) -{ - memcpy (scr, I_VideoBuffer, SCREENWIDTH * SCREENHEIGHT); -} - -// -// I_SetPalette -// -#define GFX_RGB565(r, g, b) ((((r & 0xF8) >> 3) << 11) | (((g & 0xFC) >> 2) << 5) | ((b & 0xF8) >> 3)) -#define GFX_RGB565_R(color) ((0xF800 & color) >> 11) -#define GFX_RGB565_G(color) ((0x07E0 & color) >> 5) -#define GFX_RGB565_B(color) (0x001F & color) - -void I_SetPalette (byte* palette) -{ - int i; - //col_t* c; - - //for (i = 0; i < 256; i++) - //{ - // c = (col_t*)palette; - - // rgb565_palette[i] = GFX_RGB565(gammatable[usegamma][c->r], - // gammatable[usegamma][c->g], - // gammatable[usegamma][c->b]); - - // palette += 3; - //} - - - /* performance boost: - * map to the right pixel format over here! */ - - for (i=0; i<256; ++i ) { - colors[i].a = 0; - colors[i].r = gammatable[usegamma][*palette++]; - colors[i].g = gammatable[usegamma][*palette++]; - colors[i].b = gammatable[usegamma][*palette++]; - } - - /* Set new color map in kernel framebuffer driver */ - //XXX FIXME ioctl(fd_fb, IOCTL_FB_PUTCMAP, colors); -} - -// Given an RGB value, find the closest matching palette index. - -int I_GetPaletteIndex (int r, int g, int b) -{ - int best, best_diff, diff; - int i; - col_t color; - - printf("I_GetPaletteIndex\n"); - - best = 0; - best_diff = INT_MAX; - - for (i = 0; i < 256; ++i) - { - color.r = GFX_RGB565_R(rgb565_palette[i]); - color.g = GFX_RGB565_G(rgb565_palette[i]); - color.b = GFX_RGB565_B(rgb565_palette[i]); - - diff = (r - color.r) * (r - color.r) - + (g - color.g) * (g - color.g) - + (b - color.b) * (b - color.b); - - if (diff < best_diff) - { - best = i; - best_diff = diff; - } - - if (diff == 0) - { - break; - } - } - - return best; -} - -void I_BeginRead (void) -{ -} - -void I_EndRead (void) -{ -} - -void I_SetWindowTitle (char *title) -{ -} - -void I_GraphicsCheckCommandLine (void) -{ -} - -void I_SetGrabMouseCallback (grabmouse_callback_t func) -{ -} - -void I_EnableLoadingDisk(void) -{ -} - -void I_BindVideoVariables (void) -{ -} - -void I_DisplayFPSDots (boolean dots_on) -{ -} - -void I_CheckIsScreensaver (void) -{ -} diff --git a/doomgeneric/m_menu.c b/doomgeneric/m_menu.c index 5347522..6df9655 100644 --- a/doomgeneric/m_menu.c +++ b/doomgeneric/m_menu.c @@ -75,7 +75,7 @@ int showMessages = 1; // Blocky mode, has default, 0 = high, 1 = normal int detailLevel = 0; -int screenblocks = 9; +int screenblocks = 10; // temp for screenblocks (0-9) int screenSize; diff --git a/doomgeneric/stubs.c b/doomgeneric/stubs.c deleted file mode 100644 index afaaecf..0000000 --- a/doomgeneric/stubs.c +++ /dev/null @@ -1,12 +0,0 @@ - -#include -#include -#include -#include - -//XXX FIXME -in_addr_t inet_addr(const char *cp) -{ - return (in_addr_t)NULL; -} - diff --git a/doomgeneric/w_file.c b/doomgeneric/w_file.c index 891e095..cce3737 100644 --- a/doomgeneric/w_file.c +++ b/doomgeneric/w_file.c @@ -27,9 +27,11 @@ extern wad_file_class_t stdc_wad_file; +/* #ifdef _WIN32 extern wad_file_class_t win32_wad_file; #endif +*/ #ifdef HAVE_MMAP extern wad_file_class_t posix_wad_file; @@ -37,9 +39,11 @@ extern wad_file_class_t posix_wad_file; static wad_file_class_t *wad_file_classes[] = { +/* #ifdef _WIN32 &win32_wad_file, #endif +*/ #ifdef HAVE_MMAP &posix_wad_file, #endif diff --git a/doomgeneric/w_file_stdc_unbuffered.c b/doomgeneric/w_file_stdc_unbuffered.c deleted file mode 100644 index e59e63b..0000000 --- a/doomgeneric/w_file_stdc_unbuffered.c +++ /dev/null @@ -1,118 +0,0 @@ -// -// Copyright(C) 1993-1996 Id Software, Inc. -// Copyright(C) 2005-2014 Simon Howard -// -// 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: -// WAD I/O functions. -// - -#include -#include -#include -#include -#include -#include - -#include "m_misc.h" -#include "w_file.h" -#include "z_zone.h" - -typedef struct -{ - wad_file_t wad; - int fd; -} stdc_wad_file_t; - -extern wad_file_class_t stdc_wad_file; - -static unsigned int W_StdC_FileLength(int fd) -{ - long savedpos; - long length; - - // save the current position in the file - savedpos = lseek(fd, 0, SEEK_CUR); - - // jump to the end and find the length - length = lseek(fd, 0, SEEK_END); - - // go back to the old location - lseek(fd, savedpos, SEEK_SET); - - return length; -} - -static wad_file_t *W_StdC_OpenFile(char *path) -{ - stdc_wad_file_t *result; - int fd; - - fd = open(path, O_RDONLY); - - if (fd <= 0) - { - return NULL; - } - - // Create a new stdc_wad_file_t to hold the file handle. - - result = Z_Malloc(sizeof(stdc_wad_file_t), PU_STATIC, 0); - result->wad.file_class = &stdc_wad_file; - result->wad.mapped = NULL; - result->wad.length = W_StdC_FileLength(fd); - result->fd = fd; - - return &result->wad; -} - -static void W_StdC_CloseFile(wad_file_t *wad) -{ - stdc_wad_file_t *stdc_wad; - - stdc_wad = (stdc_wad_file_t *) wad; - - close(stdc_wad->fd); - Z_Free(stdc_wad); -} - -// Read data from the specified position in the file into the -// provided buffer. Returns the number of bytes read. - -size_t W_StdC_Read(wad_file_t *wad, unsigned int offset, - void *buffer, size_t buffer_len) -{ - stdc_wad_file_t *stdc_wad; - size_t result; - - stdc_wad = (stdc_wad_file_t *) wad; - - // Jump to the specified position in the file. - - lseek(stdc_wad->fd, offset, SEEK_SET); - - // Read into the buffer. - - result = read(stdc_wad->fd, buffer, buffer_len); - - return result; -} - - -wad_file_class_t stdc_wad_file = -{ - W_StdC_OpenFile, - W_StdC_CloseFile, - W_StdC_Read, -}; - -