--- /dev/null
+
+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
+++ /dev/null
-################################################################
-#
-# $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)
-
#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 ""
#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
#endif
#else
+ AddIWADDir(".");
+
AddIWADDir (FILES_DIR);
// Don't run this function again.
#include "r_local.h"
#include "statdump.h"
-
#include "d_main.h"
//
endoom = W_CacheLumpName(DEH_String("ENDOOM"), PU_STATIC);
I_Endoom(endoom);
+
+ exit(0);
}
#if ORIGCODE
--- /dev/null
+#include "doomgeneric.h"
+
+uint32_t* DG_ScreenBuffer = 0;
+
+
+void dg_Create()
+{
+ DG_ScreenBuffer = malloc(DOOMGENERIC_RESX * DOOMGENERIC_RESY * 4);
+
+ DG_Init();
+}
+
--- /dev/null
+#ifndef DOOM_GENERIC
+#define DOOM_GENERIC
+
+#include <stdint.h>
+
+#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
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>15.0</VCProjectVersion>
+ <ProjectGuid>{95A126D2-CC94-4840-BF05-80305041B5FB}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>doomgeneric</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <SDLCheck>false</SDLCheck>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>false</SDLCheck>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="am_map.c" />
+ <ClCompile Include="doomdef.c" />
+ <ClCompile Include="doomgeneric.c" />
+ <ClCompile Include="doomgeneric_win.c" />
+ <ClCompile Include="doomstat.c" />
+ <ClCompile Include="dstrings.c" />
+ <ClCompile Include="dummy.c" />
+ <ClCompile Include="d_event.c" />
+ <ClCompile Include="d_items.c" />
+ <ClCompile Include="d_iwad.c" />
+ <ClCompile Include="d_loop.c" />
+ <ClCompile Include="d_main.c" />
+ <ClCompile Include="d_mode.c" />
+ <ClCompile Include="d_net.c" />
+ <ClCompile Include="f_finale.c" />
+ <ClCompile Include="f_wipe.c" />
+ <ClCompile Include="gusconf.c" />
+ <ClCompile Include="g_game.c" />
+ <ClCompile Include="hu_lib.c" />
+ <ClCompile Include="hu_stuff.c" />
+ <ClCompile Include="icon.c" />
+ <ClCompile Include="info.c" />
+ <ClCompile Include="i_cdmus.c" />
+ <ClCompile Include="i_endoom.c" />
+ <ClCompile Include="i_input.c" />
+ <ClCompile Include="i_joystick.c" />
+ <ClCompile Include="i_main.c" />
+ <ClCompile Include="i_scale.c" />
+ <ClCompile Include="i_sound.c" />
+ <ClCompile Include="i_system.c" />
+ <ClCompile Include="i_timer.c" />
+ <ClCompile Include="i_video.c" />
+ <ClCompile Include="memio.c" />
+ <ClCompile Include="m_argv.c" />
+ <ClCompile Include="m_bbox.c" />
+ <ClCompile Include="m_cheat.c" />
+ <ClCompile Include="m_config.c" />
+ <ClCompile Include="m_controls.c" />
+ <ClCompile Include="m_fixed.c" />
+ <ClCompile Include="m_menu.c" />
+ <ClCompile Include="m_misc.c" />
+ <ClCompile Include="m_random.c" />
+ <ClCompile Include="p_ceilng.c" />
+ <ClCompile Include="p_doors.c" />
+ <ClCompile Include="p_enemy.c" />
+ <ClCompile Include="p_floor.c" />
+ <ClCompile Include="p_inter.c" />
+ <ClCompile Include="p_lights.c" />
+ <ClCompile Include="p_map.c" />
+ <ClCompile Include="p_maputl.c" />
+ <ClCompile Include="p_mobj.c" />
+ <ClCompile Include="p_plats.c" />
+ <ClCompile Include="p_pspr.c" />
+ <ClCompile Include="p_saveg.c" />
+ <ClCompile Include="p_setup.c" />
+ <ClCompile Include="p_sight.c" />
+ <ClCompile Include="p_spec.c" />
+ <ClCompile Include="p_switch.c" />
+ <ClCompile Include="p_telept.c" />
+ <ClCompile Include="p_tick.c" />
+ <ClCompile Include="p_user.c" />
+ <ClCompile Include="r_bsp.c" />
+ <ClCompile Include="r_data.c" />
+ <ClCompile Include="r_draw.c" />
+ <ClCompile Include="r_main.c" />
+ <ClCompile Include="r_plane.c" />
+ <ClCompile Include="r_segs.c" />
+ <ClCompile Include="r_sky.c" />
+ <ClCompile Include="r_things.c" />
+ <ClCompile Include="sha1.c" />
+ <ClCompile Include="sounds.c" />
+ <ClCompile Include="statdump.c" />
+ <ClCompile Include="st_lib.c" />
+ <ClCompile Include="st_stuff.c" />
+ <ClCompile Include="s_sound.c" />
+ <ClCompile Include="tables.c" />
+ <ClCompile Include="v_video.c" />
+ <ClCompile Include="wi_stuff.c" />
+ <ClCompile Include="w_checksum.c" />
+ <ClCompile Include="w_file.c" />
+ <ClCompile Include="w_file_stdc.c" />
+ <ClCompile Include="w_main.c" />
+ <ClCompile Include="w_wad.c" />
+ <ClCompile Include="z_zone.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="am_map.h" />
+ <ClInclude Include="config.h" />
+ <ClInclude Include="deh_main.h" />
+ <ClInclude Include="deh_misc.h" />
+ <ClInclude Include="deh_str.h" />
+ <ClInclude Include="doom.h" />
+ <ClInclude Include="doomdata.h" />
+ <ClInclude Include="doomdef.h" />
+ <ClInclude Include="doomfeatures.h" />
+ <ClInclude Include="doomgeneric.h" />
+ <ClInclude Include="doomkeys.h" />
+ <ClInclude Include="doomstat.h" />
+ <ClInclude Include="doomtype.h" />
+ <ClInclude Include="dstrings.h" />
+ <ClInclude Include="d_englsh.h" />
+ <ClInclude Include="d_event.h" />
+ <ClInclude Include="d_items.h" />
+ <ClInclude Include="d_iwad.h" />
+ <ClInclude Include="d_loop.h" />
+ <ClInclude Include="d_main.h" />
+ <ClInclude Include="d_mode.h" />
+ <ClInclude Include="d_player.h" />
+ <ClInclude Include="d_textur.h" />
+ <ClInclude Include="d_think.h" />
+ <ClInclude Include="d_ticcmd.h" />
+ <ClInclude Include="f_finale.h" />
+ <ClInclude Include="f_wipe.h" />
+ <ClInclude Include="gusconf.h" />
+ <ClInclude Include="g_game.h" />
+ <ClInclude Include="hu_lib.h" />
+ <ClInclude Include="hu_stuff.h" />
+ <ClInclude Include="info.h" />
+ <ClInclude Include="i_cdmus.h" />
+ <ClInclude Include="i_endoom.h" />
+ <ClInclude Include="i_joystick.h" />
+ <ClInclude Include="i_scale.h" />
+ <ClInclude Include="i_sound.h" />
+ <ClInclude Include="i_swap.h" />
+ <ClInclude Include="i_system.h" />
+ <ClInclude Include="i_timer.h" />
+ <ClInclude Include="i_video.h" />
+ <ClInclude Include="memio.h" />
+ <ClInclude Include="m_argv.h" />
+ <ClInclude Include="m_bbox.h" />
+ <ClInclude Include="m_cheat.h" />
+ <ClInclude Include="m_config.h" />
+ <ClInclude Include="m_controls.h" />
+ <ClInclude Include="m_fixed.h" />
+ <ClInclude Include="m_menu.h" />
+ <ClInclude Include="m_misc.h" />
+ <ClInclude Include="m_random.h" />
+ <ClInclude Include="net_client.h" />
+ <ClInclude Include="net_dedicated.h" />
+ <ClInclude Include="net_defs.h" />
+ <ClInclude Include="net_gui.h" />
+ <ClInclude Include="net_io.h" />
+ <ClInclude Include="net_loop.h" />
+ <ClInclude Include="net_packet.h" />
+ <ClInclude Include="net_query.h" />
+ <ClInclude Include="net_sdl.h" />
+ <ClInclude Include="net_server.h" />
+ <ClInclude Include="p_inter.h" />
+ <ClInclude Include="p_local.h" />
+ <ClInclude Include="p_mobj.h" />
+ <ClInclude Include="p_pspr.h" />
+ <ClInclude Include="p_saveg.h" />
+ <ClInclude Include="p_setup.h" />
+ <ClInclude Include="p_spec.h" />
+ <ClInclude Include="p_tick.h" />
+ <ClInclude Include="r_bsp.h" />
+ <ClInclude Include="r_data.h" />
+ <ClInclude Include="r_defs.h" />
+ <ClInclude Include="r_draw.h" />
+ <ClInclude Include="r_local.h" />
+ <ClInclude Include="r_main.h" />
+ <ClInclude Include="r_plane.h" />
+ <ClInclude Include="r_segs.h" />
+ <ClInclude Include="r_sky.h" />
+ <ClInclude Include="r_state.h" />
+ <ClInclude Include="r_things.h" />
+ <ClInclude Include="sha1.h" />
+ <ClInclude Include="sounds.h" />
+ <ClInclude Include="statdump.h" />
+ <ClInclude Include="st_lib.h" />
+ <ClInclude Include="st_stuff.h" />
+ <ClInclude Include="s_sound.h" />
+ <ClInclude Include="tables.h" />
+ <ClInclude Include="v_patch.h" />
+ <ClInclude Include="v_video.h" />
+ <ClInclude Include="wi_stuff.h" />
+ <ClInclude Include="w_checksum.h" />
+ <ClInclude Include="w_file.h" />
+ <ClInclude Include="w_main.h" />
+ <ClInclude Include="w_merge.h" />
+ <ClInclude Include="w_wad.h" />
+ <ClInclude Include="z_zone.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="am_map.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="d_event.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="d_items.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="d_iwad.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="d_loop.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="d_main.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="d_mode.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="d_net.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="doomdef.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="doomstat.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dstrings.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dummy.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="f_finale.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="f_wipe.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="g_game.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="gusconf.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="hu_lib.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="hu_stuff.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="i_cdmus.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="i_endoom.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="i_joystick.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="i_main.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="i_scale.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="i_sound.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="i_system.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="i_timer.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="icon.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="info.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="m_argv.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="m_bbox.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="m_cheat.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="m_config.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="m_controls.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="m_fixed.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="m_menu.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="m_misc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="m_random.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="memio.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_ceilng.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_doors.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_enemy.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_floor.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_inter.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_lights.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_map.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_maputl.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_mobj.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_plats.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_pspr.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_saveg.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_setup.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_sight.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_spec.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_switch.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_telept.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_tick.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="p_user.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="r_bsp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="r_data.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="r_draw.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="r_main.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="r_plane.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="r_segs.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="r_sky.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="r_things.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="s_sound.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="sha1.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="sounds.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="st_lib.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="st_stuff.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="statdump.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="tables.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="v_video.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="w_checksum.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="w_file.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="w_file_stdc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="w_main.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="w_wad.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wi_stuff.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="z_zone.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="doomgeneric.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="doomgeneric_win.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="i_input.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="i_video.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="am_map.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="config.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="d_englsh.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="d_event.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="d_items.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="d_iwad.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="d_loop.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="d_main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="d_mode.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="d_player.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="d_textur.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="d_think.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="d_ticcmd.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="deh_main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="deh_misc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="deh_str.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="doom.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="doomdata.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="doomdef.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="doomfeatures.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="doomkeys.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="doomstat.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="doomtype.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="dstrings.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="f_finale.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="f_wipe.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="g_game.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="gusconf.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="hu_lib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="hu_stuff.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="i_cdmus.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="i_endoom.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="i_joystick.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="i_scale.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="i_sound.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="i_swap.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="i_system.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="i_timer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="i_video.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="info.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_argv.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_bbox.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_cheat.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_config.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_controls.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_fixed.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_menu.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_misc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_random.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="memio.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="net_client.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="net_dedicated.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="net_defs.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="net_gui.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="net_io.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="net_loop.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="net_packet.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="net_query.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="net_sdl.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="net_server.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="p_inter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="p_local.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="p_mobj.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="p_pspr.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="p_saveg.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="p_setup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="p_spec.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="p_tick.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="r_bsp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="r_data.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="r_defs.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="r_draw.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="r_local.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="r_main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="r_plane.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="r_segs.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="r_sky.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="r_state.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="r_things.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="s_sound.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="sha1.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="sounds.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="st_lib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="st_stuff.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="statdump.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="tables.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="v_patch.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="v_video.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="w_checksum.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="w_file.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="w_main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="w_merge.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="w_wad.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="wi_stuff.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="z_zone.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="doomgeneric.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+#include "doomkeys.h"
+
+#include "doomgeneric.h"
+
+#include <stdio.h>
+
+#include <Windows.h>
+
+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
#ifdef _WIN32
-#define strcasecmp stricmp
-#define strncasecmp strnicmp
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
#else
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
-// DESCRIPTION:
-// DOOM keyboard input via linux tty
-//
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <string.h>
-#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include <linux/keyboard.h>
-#include <linux/kd.h>
#include "config.h"
#include "deh_str.h"
#include "w_wad.h"
#include "z_zone.h"
+#include "doomgeneric.h"
+
int vanilla_keyboard_mapping = 1;
// Is the shift key currently down?
'{', '|', '}', '~', 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);
change = -1;
}
- if (key == 0x2a || key == 0x36) {
+ if (key == KEY_RSHIFT) {
shiftdown += change;
}
}
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)
void I_InitInput(void)
{
- kbd_init();
-
- //UpdateFocus();
}
+++ /dev/null
-//
-// 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 <stdlib.h>
-#include <ctype.h>
-#include <math.h>
-#include <string.h>
-
-#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));
-}
-
// Main program, simply calls D_DoomMain high level loop.
//
-#include "config.h"
+//#include "config.h"
#include <stdio.h>
-#include "doomtype.h"
-#include "i_system.h"
+//#include "doomtype.h"
+//#include "i_system.h"
#include "m_argv.h"
//
void D_DoomMain (void);
+void M_FindResponseFile(void);
+
+void dg_Create();
+
+
int main(int argc, char **argv)
{
// save arguments
// start doom
printf("Starting D_DoomMain\r\n");
- D_DoomMain ();
+
+ dg_Create();
+
+ D_DoomMain ();
return 0;
}
+++ /dev/null
-//
-// 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#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; i<OPL_NUM_VOICES; ++i)
- {
- voices[i].index = i;
- voices[i].op1 = voice_operators[0][i];
- voices[i].op2 = voice_operators[1][i];
- voices[i].current_instr = NULL;
-
- // Add this voice to the freelist.
-
- ReleaseVoice(&voices[i]);
- }
-}
-
-// Set music volume (0 - 127)
-
-static void I_OPL_SetMusicVolume(int volume)
-{
- unsigned int i;
-
- // Internal state variable.
-
- current_music_volume = volume;
-
- // Update the volume of all voices.
-
- for (i=0; i<OPL_NUM_VOICES; ++i)
- {
- if (voices[i].channel != NULL)
- {
- SetVoiceVolume(&voices[i], voices[i].note_volume);
- }
- }
-}
-
-static void VoiceKeyOff(opl_voice_t *voice)
-{
- OPL_WriteRegister(OPL_REGS_FREQ_2 + voice->index, 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; i<OPL_NUM_VOICES; ++i)
- {
- if (voices[i].channel == channel && voices[i].key == key)
- {
- VoiceKeyOff(&voices[i]);
-
- // Finished with this voice now.
-
- ReleaseVoice(&voices[i]);
- }
- }
-}
-
-// Compare the priorities of channels, returning either -1, 0 or 1.
-
-static int CompareChannelPriorities(opl_channel_data_t *chan1,
- opl_channel_data_t *chan2)
-{
- // TODO ...
-
- return 1;
-}
-
-// When all voices are in use, we must discard an existing voice to
-// play a new note. Find and free an existing voice. The channel
-// passed to the function is the channel for the new note to be
-// played.
-
-static opl_voice_t *ReplaceExistingVoice(opl_channel_data_t *channel)
-{
- opl_voice_t *rover;
- opl_voice_t *result;
-
- // Check the allocated voices, if we find an instrument that is
- // of a lower priority to the new instrument, discard it.
- // If a voice is being used to play the second voice of an instrument,
- // use that, as second voices are non-essential.
- // Lower numbered MIDI channels implicitly have a higher priority
- // than higher-numbered channels, eg. MIDI channel 1 is never
- // discarded for MIDI channel 2.
-
- result = NULL;
-
- for (rover = voice_alloced_list; rover != NULL; rover = rover->next)
- {
- 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; i<OPL_NUM_VOICES; ++i)
- {
- if (voices[i].channel == channel)
- {
- SetVoiceVolume(&voices[i], voices[i].note_volume);
- }
- }
-}
-
-// Handler for the MIDI_CONTROLLER_ALL_NOTES_OFF channel event.
-static void AllNotesOff(opl_channel_data_t *channel, unsigned int param)
-{
- unsigned int i;
-
- for (i = 0; i < OPL_NUM_VOICES; ++i)
- {
- if (voices[i].channel == channel)
- {
- VoiceKeyOff(&voices[i]);
- ReleaseVoice(&voices[i]);
- }
- }
-}
-
-static void ControllerEvent(opl_track_data_t *track, midi_event_t *event)
-{
- unsigned int controller;
- unsigned int param;
- opl_channel_data_t *channel;
-
-/*
- printf("change controller: channel %i, %i, %i\n",
- event->data.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; i<OPL_NUM_VOICES; ++i)
- {
- if (voices[i].channel == channel)
- {
- UpdateVoiceFrequency(&voices[i]);
- }
- }
-}
-
-static void MetaSetTempo(unsigned int tempo)
-{
- OPL_AdjustCallbacks((float) us_per_beat / tempo);
- us_per_beat = tempo;
-}
-
-// Process a meta event.
-
-static void MetaEvent(opl_track_data_t *track, midi_event_t *event)
-{
- byte *data = event->data.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; i<num_tracks; ++i)
- {
- MIDI_RestartIterator(tracks[i].iter);
- ScheduleTrack(&tracks[i]);
- }
-}
-
-// Callback function invoked when another event needs to be read from
-// a track.
-
-static void TrackTimerCallback(void *arg)
-{
- opl_track_data_t *track = arg;
- midi_event_t *event;
-
- // Get the next event and process it.
-
- if (!MIDI_GetNextEvent(track->iter, &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; i<MIDI_CHANNELS_PER_TRACK; ++i)
- {
- InitChannel(track, &track->channels[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<num_tracks; ++i)
- {
- StartTrack(file, i);
- }
-}
-
-static void I_OPL_PauseSong(void)
-{
- unsigned int i;
-
- if (!music_initialized)
- {
- return;
- }
-
- // Pause OPL callbacks.
-
- OPL_SetPaused(1);
-
- // Turn off all main instrument voices (not percussion).
- // This is what Vanilla does.
-
- for (i=0; i<OPL_NUM_VOICES; ++i)
- {
- if (voices[i].channel != NULL
- && voices[i].current_instr < percussion_instrs)
- {
- VoiceKeyOff(&voices[i]);
- }
- }
-}
-
-static void I_OPL_ResumeSong(void)
-{
- if (!music_initialized)
- {
- return;
- }
-
- OPL_SetPaused(0);
-}
-
-static void I_OPL_StopSong(void)
-{
- unsigned int i;
-
- if (!music_initialized)
- {
- return;
- }
-
- OPL_Lock();
-
- // Stop all playback.
-
- OPL_ClearCallbacks();
-
- // Free all voices.
-
- for (i=0; i<OPL_NUM_VOICES; ++i)
- {
- if (voices[i].channel != NULL)
- {
- VoiceKeyOff(&voices[i]);
- ReleaseVoice(&voices[i]);
- }
- }
-
- // Free all track data.
-
- for (i=0; i<num_tracks; ++i)
- {
- MIDI_FreeIterator(tracks[i].iter);
- }
-
- free(tracks);
-
- tracks = NULL;
- num_tracks = 0;
-
- OPL_Unlock();
-}
-
-static void I_OPL_UnRegisterSong(void *handle)
-{
- if (!music_initialized)
- {
- return;
- }
-
- if (handle != NULL)
- {
- MIDI_FreeFile(handle);
- }
-}
-
-// 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_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);
-}
-
+++ /dev/null
-//
-// 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 <string.h>
-
-#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; i<arrlen(disabled_sounds); ++i)
- {
- if (!strcmp(sfxinfo->name, 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,
-};
-
+++ /dev/null
-//
-// 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#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 <output filename>
- //
- // 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,
-};
-
+++ /dev/null
-//
-// 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include "SDL.h"
-#include "SDL_mixer.h"
-
-#ifdef HAVE_LIBSAMPLERATE
-#include <samplerate.h>
-#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; i<length; ++i)
- {
- // Unclear whether 128 should be interpreted as "zero" or whether a
- // symmetrical range should be assumed. The following assumes a
- // symmetrical range.
- src_data.data_in[i] = data[i] / 127.5 - 1;
- }
-
- // Do the sound conversion
-
- retn = src_simple(&src_data, SRC_ConversionMode(), 1);
- assert(retn == 0);
-
- // Allocate the new chunk.
-
- alen = src_data.output_frames_gen * 4;
-
- chunk = AllocateSound(sfxinfo, src_data.output_frames_gen * 4);
-
- if (chunk == NULL)
- {
- return false;
- }
-
- expanded = (int16_t *) chunk->abuf;
-
- // Convert the result back into 16-bit integers.
-
- for (i=0; i<src_data.output_frames_gen; ++i)
- {
- // libsamplerate does not limit itself to the -1.0 .. 1.0 range on
- // output, so a multiplier less than INT16_MAX (32767) is required
- // to avoid overflows or clipping. However, the smaller the
- // multiplier, the quieter the sound effects get, and the more you
- // have to turn down the music to keep it in balance.
-
- // 22265 is the largest multiplier that can be used to resample all
- // of the Vanilla DOOM sound effects to 48 kHz without clipping
- // using SRC_SINC_BEST_QUALITY. It is close enough (only slightly
- // too conservative) for SRC_SINC_MEDIUM_QUALITY and
- // SRC_SINC_FASTEST. PWADs with interestingly different sound
- // effects or target rates other than 48 kHz might still result in
- // clipping--I don't know if there's a limit to it.
-
- // As the number of clipped samples increases, the signal is
- // gradually overtaken by noise, with the loudest parts going first.
- // However, a moderate amount of clipping is often tolerated in the
- // quest for the loudest possible sound overall. The results of
- // using INT16_MAX as the multiplier are not all that bad, but
- // artifacts are noticeable during the loudest parts.
-
- float cvtval_f =
- src_data.data_out[i] * libsamplerate_scale * INT16_MAX;
- int32_t cvtval_i = cvtval_f + (cvtval_f < 0 ? -0.5 : 0.5);
-
- // Asymmetrical sound worries me, so we won't use -32768.
- if (cvtval_i < -INT16_MAX)
- {
- cvtval_i = -INT16_MAX;
- ++clipped;
- }
- else if (cvtval_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<expanded_length; ++i)
- {
- Sint16 sample;
- int src;
-
- src = (i * expand_ratio) >> 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; i<expanded_length * 2; ++i)
- {
- expanded[i] = (Sint16) (alpha * expanded[i]
- + (1 - alpha) * expanded[i-2]);
- }
- }
-#endif /* #ifdef LOW_PASS_FILTER */
- }
-
- return true;
-}
-
-// Load and convert a sound effect
-// Returns true if successful
-
-static boolean CacheSFX(sfxinfo_t *sfxinfo)
-{
- int lumpnum;
- unsigned int lumplen;
- int samplerate;
- unsigned int length;
- byte *data;
-
- // need to load the sound
-
- lumpnum = sfxinfo->lumpnum;
- 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; i<num_sounds; ++i)
- {
- if ((i % 6) == 0)
- {
- printf(".");
- fflush(stdout);
- }
-
- GetSfxLumpName(&sounds[i], namebuf, sizeof(namebuf));
-
- sounds[i].lumpnum = W_CheckNumForName(namebuf);
-
- if (sounds[i].lumpnum != -1)
- {
- CacheSFX(&sounds[i]);
- }
- }
-
- printf("\n");
-}
-
-#else
-
-static void I_SDL_PrecacheSounds(sfxinfo_t *sounds, int num_sounds)
-{
- // no-op
-}
-
-#endif
-
-// Load a SFX chunk into memory and ensure that it is locked.
-
-static boolean LockSound(sfxinfo_t *sfxinfo)
-{
- // If the sound isn't loaded, load it now
-
- if (sfxinfo->driver_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<NUM_CHANNELS; ++i)
- {
- if (channels_playing[i] && !I_SDL_SoundIsPlaying(i))
- {
- // Sound has finished playing on this channel,
- // but sound data has not been released to cache
-
- ReleaseSoundOnChannel(i);
- }
- }
-}
-
-static void I_SDL_ShutdownSound(void)
-{
- if (!sound_initialized)
- {
- return;
- }
-
- Mix_CloseAudio();
- SDL_QuitSubSystem(SDL_INIT_AUDIO);
-
- sound_initialized = false;
-}
-
-// Calculate slice size, based on snd_maxslicetime_ms.
-// The result must be a power of two.
-
-static int GetSliceSize(void)
-{
- int limit;
- int n;
-
- limit = (snd_samplerate * snd_maxslicetime_ms) / 1000;
-
- // Try all powers of two, not exceeding the limit.
-
- for (n=0;; ++n)
- {
- // 2^n <= limit < 2^n+1 ?
-
- if ((1 << (n + 1)) > 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; i<NUM_CHANNELS; ++i)
- {
- channels_playing[i] = NULL;
- }
-
- if (SDL_Init(SDL_INIT_AUDIO) < 0)
- {
- fprintf(stderr, "Unable to set up sound.\n");
- return false;
- }
-
- if (Mix_OpenAudio(snd_samplerate, AUDIO_S16SYS, 2, GetSliceSize()) < 0)
- {
- fprintf(stderr, "Error initialising SDL_mixer: %s\n", Mix_GetError());
- return false;
- }
-
- ExpandSoundData = ExpandSoundData_SDL;
-
- Mix_QuerySpec(&mixer_freq, &mixer_format, &mixer_channels);
-
-#ifdef HAVE_LIBSAMPLERATE
- if (use_libsamplerate != 0)
- {
- if (SRC_ConversionMode() < 0)
- {
- I_Error("I_SDL_InitSound: Invalid value for use_libsamplerate: %i",
- use_libsamplerate);
- }
-
- ExpandSoundData = ExpandSoundData_SRC;
- }
-#else
- if (use_libsamplerate != 0)
- {
- fprintf(stderr, "I_SDL_InitSound: use_libsamplerate=%i, but "
- "libsamplerate support not compiled in.\n",
- use_libsamplerate);
- }
-#endif
-
- // SDL_mixer version 1.2.8 and earlier has a bug in the Mix_SetPanning
- // function that can cause the game to lock up. If we're using an old
- // version, we need to apply a workaround. But the workaround has its
- // own drawbacks ...
-
- {
- const SDL_version *mixer_version;
- int v;
-
- mixer_version = Mix_Linked_Version();
- v = SDL_VERSIONNUM(mixer_version->major,
- 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,
-};
-
+++ /dev/null
-// 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 <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#include <math.h>
-#include <errno.h>
-
-#include <sys/time.h>
-#include <sys/types.h>
-
-#ifndef LINUX
-#include <sys/filio.h>
-#endif
-
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-
-// Timer stuff. Experimental.
-#include <time.h>
-#include <signal.h>
-
-#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<paddedsize+8 ; i++)
- paddedsfx[i] = 128;
-
- // Remove the cached lump.
- Z_Free( sfx );
-
- // Preserve padded length.
- *len = paddedsize;
-
- // Return allocated padded data.
- return (void *) (paddedsfx + 8);
-}
-
-
-
-
-
-//
-// This function adds a sound to the
-// list of currently active sounds,
-// which is maintained as a given number
-// (eight, usually) of internal channels.
-// Returns a handle.
-//
-int
-addsfx
-( int sfxid,
- int volume,
- int step,
- int seperation )
-{
- static unsigned short handlenums = 0;
-
- int i;
- int rc = -1;
-
- int oldest = gametic;
- int oldestnum = 0;
- int slot;
-
- int rightvol;
- int leftvol;
-
- // Chainsaw troubles.
- // Play these sound effects only one at a time.
- if ( sfxid == sfx_sawup
- || sfxid == sfx_sawidl
- || sfxid == sfx_sawful
- || sfxid == sfx_sawhit
- || sfxid == sfx_stnmov
- || sfxid == sfx_pistol )
- {
- // Loop all channels, check.
- for (i=0 ; i<NUM_CHANNELS ; i++)
- {
- // Active, and using the same SFX?
- if ( (channels[i])
- && (channelids[i] == sfxid) )
- {
- // Reset.
- channels[i] = 0;
- // We are sure that iff,
- // there will only be one.
- break;
- }
- }
- }
-
- // Loop all channels to find oldest SFX.
- for (i=0; (i<NUM_CHANNELS) && (channels[i]); i++)
- {
- if (channelstart[i] < oldest)
- {
- oldestnum = i;
- oldest = channelstart[i];
- }
- }
-
- // Tales from the cryptic.
- // If we found a channel, fine.
- // If not, we simply overwrite the first one, 0.
- // Probably only happens at startup.
- if (i == NUM_CHANNELS)
- slot = oldestnum;
- else
- slot = i;
-
- // Okay, in the less recent channel,
- // we will handle the new SFX.
- // Set pointer to raw data.
- channels[slot] = (unsigned char *) S_sfx[sfxid].data;
- // Set pointer to end of raw data.
- channelsend[slot] = channels[slot] + lengths[sfxid];
-
- // Reset current handle number, limited to 0..100.
- if (!handlenums)
- handlenums = 100;
-
- // Assign current handle number.
- // Preserved so sounds could be stopped (unused).
- channelhandles[slot] = rc = handlenums++;
-
- // Set stepping???
- // Kinda getting the impression this is never used.
- channelstep[slot] = step;
- // ???
- channelstepremainder[slot] = 0;
- // Should be gametic, I presume.
- channelstart[slot] = gametic;
-
- // Separation, that is, orientation/stereo.
- // range is: 1 - 256
- seperation += 1;
-
- // Per left/right channel.
- // x^2 seperation,
- // adjust volume properly.
- leftvol =
- volume - ((volume*seperation*seperation) >> 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; i<NUM_CHANNELS; i++)
- {
- channels[i] = 0;
- }*/
-
- // This table provides step widths for pitch parameters.
- // I fail to see that this is currently used.
- for (i=-128 ; i<128 ; i++)
- steptablemid[i] = (int)(pow(2.0, (i/64.0))*65536.0);
-
-
- // Generates volume lookup tables
- // which also turn the unsigned samples
- // into signed samples.
- for (i=0 ; i<128 ; i++)
- for (j=0 ; j<256 ; j++)
- vol_lookup[i*256+j] = (i*(j-128)*256)/127;
-}
-
-
-void I_SetSfxVolume(int volume)
-{
- // Identical to DOS.
- // Basically, this should propagate
- // the menu/config file setting
- // to the state variable used in
- // the mixing.
- snd_SfxVolume = volume;
-}
-
-// MUSIC API - dummy. Some code from DOS version.
-void I_SetMusicVolume(int volume)
-{
- // Internal state variable.
- snd_MusicVolume = volume;
- // Now set volume on output device.
- // Whatever( snd_MusciVolume );
-}
-
-
-//
-// Retrieve the raw data lump index
-// for a given SFX name.
-//
-int I_GetSfxLumpNum(sfxinfo_t* sfx)
-{
- char namebuf[9];
- sprintf(namebuf, "ds%s", sfx->name);
- 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 ; i<NUMSFX ; i++)
- {
- // Alias? Example is the chaingun sound linked to pistol.
- if (!S_sfx[i].link)
- {
- // Load data from WAD file.
- S_sfx[i].data = getsfx( S_sfx[i].name, &lengths[i] );
- }
- else
- {
- // Previously loaded already?
- S_sfx[i].data = S_sfx[i].link->data;
- 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");
-}
#include "i_timer.h"
#include "doomtype.h"
+#include "doomgeneric.h"
+
#include <stdarg.h>
-#include <sys/time.h>
-#include <unistd.h>
+//#include <sys/time.h>
+//#include <unistd.h>
+
//
// I_GetTime
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)
void I_Sleep(int ms)
{
//SDL_Delay(ms);
- usleep (ms * 1000);
+ //usleep (ms * 1000);
+
+ DG_SleepMs(ms);
}
void I_WaitVBL(int count)
+// 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
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
+// $Log:$
+//
// DESCRIPTION:
-// DOOM graphics stuff for SDL.
+// DOOM graphics stuff for X11, UNIX.
//
+//-----------------------------------------------------------------------------
-
-#include "SDL/SDL.h"
-#include <stdlib.h>
-#include <ctype.h>
-#include <math.h>
-#include <string.h>
-
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#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:
-
-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
-};
-
-
-#define LOADING_DISK_W 16
-#define LOADING_DISK_H 16
-
-// Non aspect ratio-corrected modes (direct multiples of 320x200)
+#include "tables.h"
+#include "doomkeys.h"
-static screen_mode_t *screen_modes[] = {
- &mode_scale_1x,
- &mode_scale_2x,
- &mode_scale_3x,
- &mode_scale_4x,
- &mode_scale_5x,
-};
+#include "doomgeneric.h"
-// Aspect ratio corrected modes (4:3 ratio)
+#include <stdbool.h>
+#include <stdlib.h>
-static screen_mode_t *screen_modes_corrected[] = {
+#include <fcntl.h>
- // Vertically stretched modes (320x200 -> 320x240 and multiples)
+#include <stdarg.h>
- &mode_stretch_1x,
- &mode_stretch_2x,
- &mode_stretch_3x,
- &mode_stretch_4x,
- &mode_stretch_5x,
+#include <sys/types.h>
- // Horizontally squashed modes (320x200 -> 256x200 and multiples)
+//#define CMAP256
- &mode_squash_1x,
- &mode_squash_2x,
- &mode_squash_3x,
- &mode_squash_4x,
- &mode_squash_5x,
+struct FB_BitField
+{
+ uint32_t offset; /* beginning of bitfield */
+ uint32_t length; /* length of bitfield */
};
-// SDL video driver name
-
-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
+struct FB_ScreenInfo
+{
+ uint32_t xres; /* visible resolution */
+ uint32_t yres;
+ uint32_t xres_virtual; /* virtual resolution */
+ uint32_t yres_virtual;
-int aspect_ratio_correct = true;
+ 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 */
+};
-// Time to wait for the screen to settle on startup before starting the
-// game (ms)
+static struct FB_ScreenInfo s_Fb;
+int fb_scaling = 1;
+int usemouse = 0;
-static int startup_delay = 1000;
+struct color {
+ uint32_t b:8;
+ uint32_t g:8;
+ uint32_t r:8;
+ uint32_t a:8;
+};
-// Grab the mouse? (int type for config code)
+static struct color colors[256];
-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
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
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;
-
- // if the window doesn't have focus, never grab it
+ byte r;
+ byte g;
+ byte b;
+} col_t;
- if (!window_focused)
- return false;
+// Palette converted to RGB565
- // always grab the mouse when full screen (dont want to
- // see the mouse pointer)
+static uint16_t rgb565_palette[256];
- 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
+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 (grabmouse_callback != NULL)
- {
- return grabmouse_callback();
- }
- else
+ for (i = 0; i < in_pixels; i++)
{
- 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.
+ for (i = 0; i < in_pixels; i++)
+ {
+ 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;
-void I_DisplayFPSDots(boolean dots_on)
-{
- display_fps_dots = dots_on;
+ for (k = 0; k < fb_scaling; k++) {
+ for (j = 0; j < s_Fb.bits_per_pixel/8; j++) {
+ *out = (pix >> (j*8));
+ out++;
+ }
+ }
+ in++;
+ }
}
-// 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)
+void I_InitGraphics (void)
{
- Uint8 state;
+ int i;
- state = SDL_GetAppState();
+ 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;
+
+ s_Fb.blue.length = 8;
+ s_Fb.green.length = 8;
+ s_Fb.red.length = 8;
+ s_Fb.transp.length = 8;
+
+ s_Fb.blue.offset = 0;
+ s_Fb.green.offset = 8;
+ s_Fb.red.offset = 16;
+ s_Fb.transp.offset = 24;
+
- // We should have input (keyboard) focus and be visible
- // (not minimized)
+ 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);
- window_focused = (state & SDL_APPINPUTFOCUS) && (state & SDL_APPACTIVE);
+ 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);
- // Should the screen be grabbed?
+ printf("I_InitGraphics: DOOM screen size: w x h: %d x %d\n", SCREENWIDTH, SCREENHEIGHT);
- screenvisible = (state & SDL_APPACTIVE) != 0;
-}
-// Show or hide the mouse cursor. We have to use different techniques
-// depending on the OS.
+ 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);
+ }
-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)
- {
- SDL_SetCursor(cursors[1]);
- }
- else
- {
- SDL_SetCursor(cursors[0]);
- }
-#else
- SDL_ShowCursor(show);
-#endif
+ /* 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
- // When the cursor is hidden, grab the input.
+ screenvisible = true;
- if (!screensaver_mode)
- {
- SDL_WM_GrabInput(!show);
- }
+ extern int I_InitInput(void);
+ I_InitInput();
}
-void I_EnableLoadingDisk(void)
+void I_ShutdownGraphics (void)
{
- patch_t *disk;
- byte *tmpbuf;
- char *disk_name;
- int y;
- char buf[20];
-
- SDL_VideoDriverName(buf, 15);
-
- 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.
-
- 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);
+ Z_Free (I_VideoBuffer);
+ free(I_VideoBuffer_FB);
+}
- 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);
+void I_StartFrame (void)
+{
- for (y=0; y<LOADING_DISK_H; ++y)
- {
- memcpy(disk_image + LOADING_DISK_W * y,
- tmpbuf + SCREENWIDTH * y,
- LOADING_DISK_W);
- }
+}
- // All done - free the screen buffer and restore the normal
- // video buffer.
+void I_StartTic (void)
+{
+ I_GetEvent();
+}
- W_ReleaseLumpName(disk_name);
- V_RestoreBuffer();
- Z_Free(tmpbuf);
+void I_UpdateNoBlit (void)
+{
}
//
-// Translates the SDL key
+// I_FinishUpdate
//
-static int TranslateKey(SDL_keysym *sym)
+void I_FinishUpdate (void)
{
- 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;
+ 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 = s_Fb heigt, 200 screenheight */
+ /* 600 = s_Fb heigt, 200 screenheight */
+ /* 2048 =s_Fb width, 320 screenwidth */
+ y_offset = (((s_Fb.yres - (SCREENHEIGHT * fb_scaling)) * s_Fb.bits_per_pixel/8)) / 2;
+ x_offset = (((s_Fb.xres - (SCREENWIDTH * fb_scaling)) * s_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 = ((s_Fb.xres - (SCREENWIDTH * fb_scaling)) * s_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
-
- default:
- return tolower(sym->sym);
+ line_out += (SCREENWIDTH * fb_scaling * (s_Fb.bits_per_pixel/8)) + x_offset_end;
+ }
+ line_in += SCREENWIDTH;
}
-}
-
-void I_ShutdownGraphics(void)
-{
- if (initialized)
- {
- SetShowCursor(true);
- SDL_QuitSubSystem(SDL_INIT_VIDEO);
+ memcpy(DG_ScreenBuffer, I_VideoBuffer_FB, (SCREENHEIGHT * fb_scaling * (s_Fb.bits_per_pixel / 8)) * s_Fb.xres);
- initialized = false;
- }
+ DG_DrawFrame();
}
-
-void __attribute__ ((weak)) I_GetEvent(void)
+//
+// I_ReadScreen
+//
+void I_ReadScreen (byte* scr)
{
-
+ memcpy (scr, I_VideoBuffer, SCREENWIDTH * SCREENHEIGHT);
}
//
-// I_StartFrame
+// I_SetPalette
//
-void I_StartFrame (void)
-{
- I_GetEvent();
-}
+#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)
-static void UpdateMouseButtonState(unsigned int button, boolean on)
+void I_SetPalette (byte* palette)
{
- 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.
+ int i;
+ //col_t* c;
- switch (button)
- {
- case SDL_BUTTON_LEFT:
- button = 0;
- break;
-
- case SDL_BUTTON_RIGHT:
- button = 1;
- break;
+ //for (i = 0; i < 256; i++)
+ //{
+ // c = (col_t*)palette;
- case SDL_BUTTON_MIDDLE:
- button = 2;
- break;
+ // rgb565_palette[i] = GFX_RGB565(gammatable[usegamma][c->r],
+ // gammatable[usegamma][c->g],
+ // gammatable[usegamma][c->b]);
- default:
- // SDL buttons are indexed from 1.
- --button;
- break;
- }
+ // palette += 3;
+ //}
+
- // Turn bit representing this button on or off.
+ /* performance boost:
+ * map to the right pixel format over here! */
- if (on)
- {
- mouse_button_state |= (1 << button);
- }
- else
- {
- mouse_button_state &= ~(1 << button);
+ 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++];
}
-
- // 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)
+// Given an RGB value, find the closest matching palette index.
+
+int I_GetPaletteIndex (int r, int g, int b)
{
- if (val < 0)
- return -AccelerateMouse(-val);
+ int best, best_diff, diff;
+ int i;
+ col_t color;
- if (val > mouse_threshold)
- {
- return (int)((val - mouse_threshold) * mouse_acceleration + mouse_threshold);
- }
- else
- {
- return val;
- }
-}
+ printf("I_GetPaletteIndex\n");
-// Get the equivalent ASCII (Unicode?) character for a keypress.
+ best = 0;
+ best_diff = INT_MAX;
-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)
+ for (i = 0; i < 256; ++i)
{
- key = TranslateKey(&event->key.keysym);
+ color.r = GFX_RGB565_R(rgb565_palette[i]);
+ color.g = GFX_RGB565_G(rgb565_palette[i]);
+ color.b = GFX_RGB565_B(rgb565_palette[i]);
- // Is shift held down? If so, perform a translation.
+ diff = (r - color.r) * (r - color.r)
+ + (g - color.g) * (g - color.g)
+ + (b - color.b) * (b - color.b);
- if (shiftdown > 0)
+ if (diff < best_diff)
{
- if (key >= 0 && key < arrlen(shiftxform))
- {
- key = shiftxform[key];
- }
- else
- {
- key = 0;
- }
+ best = i;
+ best_diff = diff;
}
- return key;
+ if (diff == 0)
+ {
+ break;
+ }
}
- else
- {
- // Unicode value, from key layout.
- return tolower(event->key.keysym.unicode);
- }
+ return best;
}
-static void UpdateShiftStatus(SDL_Event *event)
+void I_BeginRead (void)
{
- 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)
+void I_EndRead (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)
+void I_SetWindowTitle (char *title)
{
- // Warp the the screen center
-
- SDL_WarpMouse(screen->w / 2, screen->h / 2);
-
- // Clear any relative movement caused by warping
+ DG_SetWindowTitle(title);
+}
- SDL_PumpEvents();
-#if SDL_VERSION_ATLEAST(1, 3, 0)
- SDL_GetRelativeMouseState(0, NULL, NULL);
-#else
- SDL_GetRelativeMouseState(NULL, NULL);
-#endif
+void I_GraphicsCheckCommandLine (void)
+{
}
-//
-// 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.
+void I_SetGrabMouseCallback (grabmouse_callback_t func)
+{
+}
-static void I_ReadMouse(void)
+void I_EnableLoadingDisk(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
+void I_BindVideoVariables (void)
+{
+}
- if (x != 0 || y != 0)
- {
- ev.type = ev_mouse;
- ev.data1 = mouse_button_state;
- ev.data2 = AccelerateMouse(x);
+void I_DisplayFPSDots (boolean dots_on)
+{
+}
- 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_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<LOADING_DISK_H; ++y)
- {
- memcpy(saved_background + y * LOADING_DISK_W,
- screenloc,
- LOADING_DISK_W);
- memcpy(screenloc,
- disk_image + y * LOADING_DISK_W,
- LOADING_DISK_W);
-
- screenloc += SCREENWIDTH;
- }
-
- UpdateRect(SCREENWIDTH - LOADING_DISK_W, SCREENHEIGHT - LOADING_DISK_H,
- SCREENWIDTH, SCREENHEIGHT);
-}
-
-void I_EndRead(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<LOADING_DISK_H; ++y)
- {
- memcpy(screenloc,
- saved_background + y * LOADING_DISK_W,
- LOADING_DISK_W);
-
- screenloc += SCREENWIDTH;
- }
-
- UpdateRect(SCREENWIDTH - LOADING_DISK_W, SCREENHEIGHT - LOADING_DISK_H,
- SCREENWIDTH, SCREENHEIGHT);
-}
-
-//
-// I_FinishUpdate
-//
-void I_FinishUpdate (void)
-{
- static int lasttic;
- int tics;
- int i;
-
- if (!initialized)
- return;
-
- if (noblit)
- return;
-
- if (need_resize && SDL_GetTicks() > last_resize_time + 500)
- {
- 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 ; i<tics*4 ; i+=4)
- I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff;
- for ( ; i<20*4 ; i+=4)
- I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
- }
-
- // draw to screen
-
- BlitArea(0, 0, SCREENWIDTH, SCREENHEIGHT);
-
- if (palette_to_set)
- {
- SDL_SetColors(screenbuffer, palette, 0, 256);
- palette_to_set = false;
-
- // In native 8-bit mode, if we have a palette to set, the act
- // of setting the palette updates the screen
-
- if (screenbuffer == screen)
- {
- return;
- }
- }
-
- // In 8in32 mode, we must blit from the fake 8-bit screen buffer
- // to the real screen before doing a screen flip.
-
- if (screenbuffer != screen)
- {
- SDL_Rect dst_rect;
-
- // Center the buffer within the full screen space.
-
- dst_rect.x = (screen->w - screenbuffer->w) / 2;
- dst_rect.y = (screen->h - screenbuffer->h) / 2;
-
- SDL_BlitSurface(screenbuffer, NULL, screen, &dst_rect);
- }
-
- SDL_Flip(screen);
-}
-
-
-//
-// I_ReadScreen
-//
-void I_ReadScreen (byte* scr)
-{
- memcpy(scr, I_VideoBuffer, SCREENWIDTH*SCREENHEIGHT);
-}
-
-
-//
-// I_SetPalette
-//
-void I_SetPalette (byte *doompalette)
-{
- int i;
-
- 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.
-
- palette[i].r = gammatable[usegamma][*doompalette++] & ~3;
- palette[i].g = gammatable[usegamma][*doompalette++] & ~3;
- palette[i].b = gammatable[usegamma][*doompalette++] & ~3;
- }
-
- palette_to_set = true;
-}
-
-// 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;
-
- 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);
-
- if (diff < best_diff)
- {
- best = i;
- best_diff = diff;
- }
-
- if (diff == 0)
- {
- break;
- }
- }
-
- return best;
-}
-
-//
-// Set the window title
-//
-
-void I_SetWindowTitle(char *title)
-{
- window_title = title;
-}
-
-//
-// Call the SDL function to set the window title, based on
-// the title set with I_SetWindowTitle.
-//
-
-void I_InitWindowTitle(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)
-{
- 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; i<icon_w * icon_h; ++i)
- {
- if (icon_data[i * 3] != 0x00
- || icon_data[i * 3 + 1] != 0x00
- || icon_data[i * 3 + 2] != 0x00)
- {
- mask[i / 8] |= 1 << (7 - i % 8);
- }
- }
-
- surface = SDL_CreateRGBSurfaceFrom(icon_data,
- icon_w,
- icon_h,
- 24,
- icon_w * 3,
- 0xff << 0,
- 0xff << 8,
- 0xff << 16,
- 0);
-
- SDL_WM_SetIcon(surface, mask);
- SDL_FreeSurface(surface);
- free(mask);
-}
-
-// Pick the modes list to use:
-
-static void GetScreenModes(screen_mode_t ***modes_list, int *num_modes)
-{
- if (aspect_ratio_correct)
- {
- *modes_list = screen_modes_corrected;
- *num_modes = arrlen(screen_modes_corrected);
- }
- else
- {
- *modes_list = screen_modes;
- *num_modes = arrlen(screen_modes);
- }
-}
-
-// Find which screen_mode_t to use for the given width and height.
-
-static screen_mode_t *I_FindScreenMode(int w, int h)
-{
- screen_mode_t **modes_list;
- screen_mode_t *best_mode;
- int modes_list_length;
- int num_pixels;
- int best_num_pixels;
- int i;
-
- // Special case: 320x200 and 640x400 are available even if aspect
- // ratio correction is turned on. These modes have non-square
- // pixels.
-
- if (fullscreen)
- {
- if (w == SCREENWIDTH && h == SCREENHEIGHT)
- {
- return &mode_scale_1x;
- }
- else if (w == SCREENWIDTH*2 && h == SCREENHEIGHT*2)
- {
- return &mode_scale_2x;
- }
- }
-
- GetScreenModes(&modes_list, &modes_list_length);
-
- // Find the biggest screen_mode_t in the list that fits within these
- // dimensions
-
- best_mode = NULL;
- best_num_pixels = 0;
-
- for (i=0; i<modes_list_length; ++i)
- {
- // Will this fit within the dimensions? If not, ignore.
-
- if (modes_list[i]->width > 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)
-{
- 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)
-{
- 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)
-{
- 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)
-{
- 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 <x>
- //
- // Specify the screen width, in pixels.
- //
-
- i = M_CheckParmWithArgs("-width", 1);
-
- if (i > 0)
- {
- screen_width = atoi(myargv[i + 1]);
- }
-
- //!
- // @category video
- // @arg <y>
- //
- // Specify the screen height, in pixels.
- //
-
- i = M_CheckParmWithArgs("-height", 1);
-
- if (i > 0)
- {
- screen_height = atoi(myargv[i + 1]);
- }
-
- //!
- // @category video
- // @arg <bpp>
- //
- // 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 <WxY>[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)
+void I_CheckIsScreensaver (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
}
+++ /dev/null
-// 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 <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <stdarg.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <linux/fb.h>
-#include <sys/ioctl.h>
-
-//#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)
-{
-}
// Blocky mode, has default, 0 = high, 1 = normal
int detailLevel = 0;
-int screenblocks = 9;
+int screenblocks = 10;
// temp for screenblocks (0-9)
int screenSize;
+++ /dev/null
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <string.h>
-
-//XXX FIXME
-in_addr_t inet_addr(const char *cp)
-{
- return (in_addr_t)NULL;
-}
-
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;
static wad_file_class_t *wad_file_classes[] =
{
+/*
#ifdef _WIN32
&win32_wad_file,
#endif
+*/
#ifdef HAVE_MMAP
&posix_wad_file,
#endif
+++ /dev/null
-//
-// 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 <stdio.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#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,
-};
-
-