diff --git a/.gitignore b/.gitignore index b9f8674..7f39f82 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ *.o *.obj +*.exe *.DS_Store *.log *.user +*~ .vs/ Debug/ -Release/ \ No newline at end of file +Release/ diff --git a/doomgeneric/Makefile.djgpp b/doomgeneric/Makefile.djgpp new file mode 100644 index 0000000..1b85ddb --- /dev/null +++ b/doomgeneric/Makefile.djgpp @@ -0,0 +1,71 @@ +################################################################ +# +# $Id:$ +# +# $Log:$ +# + +.PHONY: all clean print + +.SUFFIXES: + +ifeq ($(V),1) + VB='' +else + VB=@ +endif + + + +CC:=i386-pc-msdosdjgpp-gcc +OPTFLAGS:=-O3 +CFLAGS+=-std=gnu89 +CFLAGS+=$(OPTFLAGS) +CFLAGS+=-Werror +CFLAGS+=-DDOOMGENERIC_RESX=320 -DDOOMGENERIC_RESY=200 +CFLAGS+=-DFEATURE_SOUND=1 +CFLAGS+=-DCMAP256 + +# link time optimization, no significant effect on performance +# CFLAGS+=-flto +# LDFLAGS+=-flto $(OPTFLAGS) + +# debug +# CFLAGS+=-g +# LDFLAGS+=-g + +LIBS+=-lalleg +#LIBS+=-lalld # debug library + +# subdirectory for objects +OBJDIR:=djgpp +OUTPUT:=doomgen.exe + +SRC_DOOM = 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_main.o w_wad.o z_zone.o w_file_stdc.o i_input.o i_video.o doomgeneric.o doomgeneric_allegro.o mus2mid.o i_allegromusic.o i_allegrosound.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) + +$(OBJS): | $(OBJDIR) + +$(OBJDIR): + mkdir -p $(OBJDIR) + +$(OBJDIR)/%.o: %.c + @echo [Compiling $<] + $(VB)$(CC) $(CFLAGS) -c $< -o $@ + +print: + @echo OBJS: $(OBJS) + diff --git a/doomgeneric/doomgeneric.c b/doomgeneric/doomgeneric.c index 782a7e7..881d700 100644 --- a/doomgeneric/doomgeneric.c +++ b/doomgeneric/doomgeneric.c @@ -4,7 +4,7 @@ #include "doomgeneric.h" -uint32_t* DG_ScreenBuffer = 0; +pixel_t* DG_ScreenBuffer = NULL; void M_FindResponseFile(void); void D_DoomMain (void); diff --git a/doomgeneric/doomgeneric.h b/doomgeneric/doomgeneric.h index 091621f..0fbbd2b 100644 --- a/doomgeneric/doomgeneric.h +++ b/doomgeneric/doomgeneric.h @@ -4,11 +4,27 @@ #include #include +#ifndef DOOMGENERIC_RESX #define DOOMGENERIC_RESX 640 +#endif // DOOMGENERIC_RESX + +#ifndef DOOMGENERIC_RESY #define DOOMGENERIC_RESY 400 +#endif // DOOMGENERIC_RESY -extern uint32_t* DG_ScreenBuffer; +#ifdef CMAP256 + +typedef uint8_t pixel_t; + +#else // CMAP256 + +typedef uint32_t pixel_t; + +#endif // CMAP256 + + +extern pixel_t* DG_ScreenBuffer; void doomgeneric_Create(int argc, char **argv); void doomgeneric_Tick(); diff --git a/doomgeneric/doomgeneric_allegro.c b/doomgeneric/doomgeneric_allegro.c new file mode 100644 index 0000000..b120366 --- /dev/null +++ b/doomgeneric/doomgeneric_allegro.c @@ -0,0 +1,453 @@ +// doomgeneric for Allegro library + +#include "doomkeys.h" +#include "i_system.h" +#include "i_video.h" +#include "m_argv.h" +#include "doomgeneric.h" + +#include +#include +#include +#include + +#define ALLEGRO_NO_KEY_DEFINES 1 +#include +#undef uint32_t // ugly hack because Allegro is Old and doesn't know modern GCC has stdint.h + + +static bool videomode_set = false; + +static BITMAP *temp_bitmap = NULL; + +static PALETTE pal; + +#define KEYQUEUE_SIZE 16 + +static volatile unsigned int s_KeyQueue[KEYQUEUE_SIZE]; +static volatile unsigned int s_KeyQueueWriteIndex = 0; +static unsigned int s_KeyQueueReadIndex = 0; + +static volatile unsigned int s_ticks = 0; + + +void key_callback(int scancode) { + // this is in interrupt context, avoid heavy processing and be careful about volatile writes + s_KeyQueue[s_KeyQueueWriteIndex] = scancode; + s_KeyQueueWriteIndex = (s_KeyQueueWriteIndex + 1) % KEYQUEUE_SIZE; +} +END_OF_FUNCTION(key_callback); + + +void timer_callback(void) { + // also in interrupt context + s_ticks++; +} +END_OF_FUNCTION(timer_callback); + + +void DG_Init() { + int result; + + printf("Initializing Allegro\n"); + + result = allegro_init(); + if (result != 0) + { + I_Error("Allegro init failed: %d %s\n", result, allegro_error); + } + + I_AtExit(allegro_exit, true); + + LOCK_FUNCTION(key_callback); + LOCK_VARIABLE(s_KeyQueue); + LOCK_VARIABLE(s_KeyQueueWriteIndex); + LOCK_VARIABLE(s_KeyQueueReadIndex); + + LOCK_FUNCTION(timer_callback); + LOCK_VARIABLE(s_ticks); + + install_keyboard(); + keyboard_lowlevel_callback = key_callback; + + install_timer(); + result = install_int(timer_callback, 1); + if (result < 0) { + I_Error("Unable to install timer: %d %s\n", result, allegro_error); + } + + // don't set video mode yet so initialization messages stay on screen +} + + +static void back_to_text_mode(void) { + set_gfx_mode(GFX_TEXT, 80, 25, 0, 0); +} + + +void DG_DrawFrame() +{ + if (!DG_ScreenBuffer) { + return; + } + + if (!videomode_set) { + int y; + int result; + +#ifdef CMAP256 + set_color_depth(8); +#else // CMAP256 + // does not seem to work on real DOS hardware + set_color_depth(32); +#endif // CMAP256 + + result = set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, DOOMGENERIC_RESX, DOOMGENERIC_RESY, 0, 0); + if (result < 0) { + I_Error("Failed to set video mode: %s\n", allegro_error); + } + + // register an exit handler to return to text mode + // while this is also done by allegro_exit handler registered earlier + // that's too late for ENDOOM screen to work correctly + I_AtExit(back_to_text_mode, true); + + if (!screen) { + I_Error("screen is null\n"); + } + + temp_bitmap = create_bitmap(DOOMGENERIC_RESX, DOOMGENERIC_RESY); + if (!temp_bitmap) { + I_Error("Failed to create temp bitmap\n"); + } + + // this is an evil hack + // replace the internal line pointers with pointers into DG_ScreenBuffer + // this avoids some copying + // it might crash when freeing the bitmap but we never do + for (y = 0; y < DOOMGENERIC_RESY; y++) { + temp_bitmap->line[y] = (unsigned char *) &DG_ScreenBuffer[y * DOOMGENERIC_RESX]; + } + + clear_bitmap(temp_bitmap); + + videomode_set = true; + palette_changed = true; + } + +#ifdef CMAP256 + + // changing palette implicitly waits for vsync + // TODO: should do it explicitly in case where we don't change palette + if (palette_changed) { + int i; + + for (i = 0; i < 256; i++) { + // allegro uses VGA range 0..63 + pal[i].r = colors[i].r >> 2; + pal[i].g = colors[i].g >> 2; + pal[i].b = colors[i].b >> 2; + } + set_palette(pal); + + palette_changed = false; + } + +#endif // CMAP256 + + blit(temp_bitmap, screen, 0, 0, 0, 0, DOOMGENERIC_RESX, DOOMGENERIC_RESY); +} + + +void DG_SleepMs(uint32_t ms) +{ + rest(ms); +} + + +uint32_t DG_GetTicksMs() +{ + return s_ticks; +} + + +int DG_GetKey(int *pressed, unsigned char *doomKey) +{ + if (s_KeyQueueReadIndex == s_KeyQueueWriteIndex){ + //key queue is empty + return 0; + } else { + bool released; + short keyData = 0; + int scancode = s_KeyQueue[s_KeyQueueReadIndex]; + s_KeyQueueReadIndex++; + s_KeyQueueReadIndex %= KEYQUEUE_SIZE; + + released = scancode & 0x80; + *pressed = !released; + + scancode = scancode & 0x7F; + + switch (scancode) { + case __allegro_KEY_RIGHT: + keyData = KEY_RIGHTARROW; + break; + + case __allegro_KEY_LEFT: + keyData = KEY_LEFTARROW; + break; + + case __allegro_KEY_UP: + keyData = KEY_UPARROW; + break; + + case __allegro_KEY_DOWN: + keyData = KEY_DOWNARROW; + break; + + case __allegro_KEY_COMMA: + keyData = KEY_STRAFE_L; + break; + + case __allegro_KEY_STOP: + keyData = KEY_STRAFE_R; + break; + + case __allegro_KEY_SPACE: + keyData = KEY_USE; + break; + + case __allegro_KEY_LCONTROL: + keyData = KEY_FIRE; + break; + + case __allegro_KEY_ESC: + keyData = KEY_ESCAPE; + break; + + case __allegro_KEY_ENTER: + keyData = KEY_ENTER; + break; + + case __allegro_KEY_TAB: + keyData = KEY_TAB; + break; + + case __allegro_KEY_F1: + keyData = KEY_F1; + break; + + case __allegro_KEY_F2: + keyData = KEY_F2; + break; + + case __allegro_KEY_F3: + keyData = KEY_F3; + break; + + case __allegro_KEY_F4: + keyData = KEY_F4; + break; + + case __allegro_KEY_F5: + keyData = KEY_F5; + break; + + case __allegro_KEY_F6: + keyData = KEY_F6; + break; + + case __allegro_KEY_F7: + keyData = KEY_F7; + break; + + case __allegro_KEY_F8: + keyData = KEY_F8; + break; + + case __allegro_KEY_F9: + keyData = KEY_F9; + break; + + case __allegro_KEY_F10: + keyData = KEY_F10; + break; + + case __allegro_KEY_F11: + keyData = KEY_F11; + break; + + case __allegro_KEY_F12: + keyData = KEY_F12; + break; + + case __allegro_KEY_BACKSPACE: + keyData = KEY_BACKSPACE; + break; + + case __allegro_KEY_PAUSE: + keyData = KEY_PAUSE; + break; + + case __allegro_KEY_EQUALS: + keyData = KEY_EQUALS; + break; + + case __allegro_KEY_MINUS: + keyData = KEY_MINUS; + break; + + case __allegro_KEY_LSHIFT: + case __allegro_KEY_RSHIFT: + keyData = KEY_RSHIFT; + break; + + case __allegro_KEY_RCONTROL: + keyData = KEY_RCTRL; + break; + + case __allegro_KEY_ALT: + keyData = KEY_RALT; + break; + + case __allegro_KEY_CAPSLOCK: + keyData = KEY_CAPSLOCK; + break; + + case __allegro_KEY_NUMLOCK: + keyData = KEY_NUMLOCK; + break; + + case __allegro_KEY_SCRLOCK: + keyData = KEY_SCRLCK; + break; + + case __allegro_KEY_PRTSCR: + keyData = KEY_PRTSCR; + break; + + case __allegro_KEY_HOME: + keyData = KEY_HOME; + break; + + case __allegro_KEY_END: + keyData = KEY_END; + break; + + case __allegro_KEY_PGUP: + keyData = KEY_PGUP; + break; + + case __allegro_KEY_PGDN: + keyData = KEY_PGDN; + break; + + case __allegro_KEY_INSERT: + keyData = KEY_INS; + break; + + case __allegro_KEY_DEL: + keyData = KEY_DEL; + break; + + case __allegro_KEY_0_PAD: + keyData = KEYP_0; + break; + + case __allegro_KEY_1_PAD: + keyData = KEYP_1; + break; + + case __allegro_KEY_2_PAD: + keyData = KEYP_2; + break; + + case __allegro_KEY_3_PAD: + keyData = KEYP_3; + break; + + case __allegro_KEY_4_PAD: + keyData = KEYP_4; + break; + + case __allegro_KEY_5_PAD: + keyData = KEYP_5; + break; + + case __allegro_KEY_6_PAD: + keyData = KEYP_6; + break; + + case __allegro_KEY_7_PAD: + keyData = KEYP_7; + break; + + case __allegro_KEY_8_PAD: + keyData = KEYP_8; + break; + + case __allegro_KEY_9_PAD: + keyData = KEYP_9; + break; + + case __allegro_KEY_SLASH_PAD: + keyData = KEYP_DIVIDE; + break; + + case __allegro_KEY_PLUS_PAD: + keyData = KEYP_PLUS; + break; + + case __allegro_KEY_MINUS_PAD: + keyData = KEYP_MINUS; + break; + + case __allegro_KEY_ASTERISK: + keyData = KEYP_MULTIPLY; + break; + + case __allegro_KEY_DEL_PAD: + keyData = KEYP_PERIOD; + break; + + case __allegro_KEY_EQUALS_PAD: + keyData = KEYP_EQUALS; + break; + + case __allegro_KEY_ENTER_PAD: + keyData = KEYP_ENTER; + break; + + default: + keyData = scancode_to_ascii(scancode); + break; + } + + if (keyData != 0) { + *doomKey = keyData & 0xFF; + } + + return 1; + } + + return 0; +} + + +void DG_SetWindowTitle(const char *title) +{ + set_window_title(title); +} + + +int main(int argc, char **argv) +{ + doomgeneric_Create(argc, argv); + + while (true) + { + doomgeneric_Tick(); + } + + return 0; +} diff --git a/doomgeneric/doomtype.h b/doomgeneric/doomtype.h index aab7cbe..a225c64 100644 --- a/doomgeneric/doomtype.h +++ b/doomgeneric/doomtype.h @@ -83,7 +83,7 @@ typedef uint8_t byte; #include -#ifdef _WIN32 +#if defined(_WIN32) || defined(__DJGPP__) #define DIR_SEPARATOR '\\' #define DIR_SEPARATOR_S "\\" diff --git a/doomgeneric/i_allegromusic.c b/doomgeneric/i_allegromusic.c new file mode 100644 index 0000000..2c6c055 --- /dev/null +++ b/doomgeneric/i_allegromusic.c @@ -0,0 +1,308 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// System interface for music. +// + + +#include +#include +#include +#include + +#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" + +#include +#include +#include +#include + + +#define MAXMIDLENGTH (96 * 1024) +#define MID_HEADER_MAGIC "MThd" +#define MUS_HEADER_MAGIC "MUS\x1a" + + +static boolean music_initialized = false; + + +static boolean musicpaused = false; +static int current_music_volume; + + +// Currently playing music track. +MIDI *current_track_music = NULL; + +// If true, the currently playing track is being played on loop. +static boolean current_track_loop; + + + +// Shutdown music +static void I_Allegro_ShutdownMusic(void) +{ + // nothing here + // TODO: stop song? +} + + +// Initialize music subsystem +static boolean I_Allegro_InitMusic(void) +{ + // nothing here, it's all done by I_Allegro_InitSound + music_initialized = true; + + return true; +} + + +// Set music volume (0 - 127) +static void I_Allegro_SetMusicVolume(int volume) +{ + int digivol = -1; + get_volume(&digivol, NULL); + // allegro range 0 - 255 + set_volume(digivol, volume * 2); +} + + +// Start playing a mid +static void I_Allegro_PlaySong(void *handle, boolean looping) +{ + int retval; + + if (!music_initialized) + { + return; + } + + if (handle == NULL) + { + return; + } + + current_track_music = (MIDI *) handle; + current_track_loop = looping; + + retval = play_midi(current_track_music, looping); + if (retval < 0) { + fprintf(stderr, "Error playing midi: %d \"%s\"\n", retval, allegro_error); + } +} + + +static void I_Allegro_PauseSong(void) +{ + if (!music_initialized) + { + return; + } + + musicpaused = true; + + midi_pause(); +} + + +static void I_Allegro_ResumeSong(void) +{ + if (!music_initialized) + { + return; + } + + musicpaused = false; + + midi_resume(); +} + + +static void I_Allegro_StopSong(void) +{ + if (!music_initialized) + { + return; + } + + stop_midi(); + + current_track_music = NULL; +} + + +static void I_Allegro_UnRegisterSong(void *handle) +{ + MIDI *midi = (MIDI *) handle; + + if (!music_initialized) + { + return; + } + + if (handle == NULL) + { + return; + } + + destroy_midi(midi); +} + + +// 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_Allegro_RegisterSong(void *data, int len) +{ + char *filename; + MIDI *music; + + if (!music_initialized) + { + return NULL; + } + + 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 load it directly from memory but Allegro + // doesn't support that so we have to generate a temporary file. + + music = load_midi(filename); + + if (music == NULL) + { + // Failed to load + fprintf(stderr, "Error loading midi: %s\n", allegro_error); + } + + // Remove the temporary MIDI file; + remove(filename); + + free(filename); + + return music; +} + + +// Is the song playing? +static boolean I_Allegro_MusicIsPlaying(void) +{ + if (!music_initialized) + { + return false; + } + + return (current_track_music != NULL) && (midi_pos > 0); +} + + +// Get position in substitute music track, in seconds since start of track. +static double GetMusicPosition(void) +{ + return midi_time; +} + + +// Poll music position; if we have passed the loop point end position +// then we need to go back. +static void I_Allegro_PollMusic(void) +{ + // nothing here, allegro takes care of it +} + + +static snddevice_t music_allegro_devices[] = +{ + SNDDEVICE_PAS, + SNDDEVICE_GUS, + SNDDEVICE_WAVEBLASTER, + SNDDEVICE_SOUNDCANVAS, + SNDDEVICE_GENMIDI, + SNDDEVICE_AWE32, +}; + + +music_module_t DG_music_module = +{ + music_allegro_devices, + arrlen(music_allegro_devices), + I_Allegro_InitMusic, + I_Allegro_ShutdownMusic, + I_Allegro_SetMusicVolume, + I_Allegro_PauseSong, + I_Allegro_ResumeSong, + I_Allegro_RegisterSong, + I_Allegro_UnRegisterSong, + I_Allegro_PlaySong, + I_Allegro_StopSong, + I_Allegro_MusicIsPlaying, + I_Allegro_PollMusic, +}; + diff --git a/doomgeneric/i_allegrosound.c b/doomgeneric/i_allegrosound.c new file mode 100644 index 0000000..d8f5714 --- /dev/null +++ b/doomgeneric/i_allegrosound.c @@ -0,0 +1,433 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// Copyright(C) 2008 David Flater +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// System interface for sound. +// + +#include "config.h" + +#include +#include +#include +#include +#include + +#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" + +#include +#include +#include + + +#define NUM_CHANNELS 16 + +#define NUM_MIDI_CHANNELS 16 + + +static boolean sound_initialized = false; + +static sfxinfo_t *channels_playing[NUM_CHANNELS]; + +static int allegro_voices[NUM_CHANNELS]; + +static SAMPLE *dummy_sample = NULL; + +static boolean use_sfx_prefix; + + +// We don't support libsamplerate with Allegro but these have to be here since +// other code requires them +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; + + +// 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; + SAMPLE *sample; + + // 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 = create_sample(8, 0, samplerate, length); + if (sample == NULL) { + return false; + } + memcpy(sample->data, data, length); + + sfxinfo->driver_data = sample; + + // 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); + } +} + + +static void I_Allegro_PrecacheSounds(sfxinfo_t *sounds, int num_sounds) +{ + char namebuf[9]; + int i; + + printf("I_Allegro_PrecacheSounds: Precaching all sound effects.."); + + for (i=0; i= NUM_CHANNELS) + { + return; + } + + if (channels_playing[handle] == NULL) { + return; + } + + voice_set_volume(allegro_voices[handle], vol); + voice_set_pan(allegro_voices[handle], sep); +} + +// +// 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_Allegro_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep) +{ + if (!sound_initialized || channel < 0 || channel >= NUM_CHANNELS) + { + return -1; + } + + // Release a sound effect if there is already one playing + // on this channel + if (channels_playing[channel]) { + voice_stop(allegro_voices[channel]); + channels_playing[channel] = NULL; + } + + // Get the sound data + if (sfxinfo->driver_data == NULL) + { + if (!CacheSFX(sfxinfo)) + { + return -1; + } + } + assert(sfxinfo->driver_data); + + // play sound + reallocate_voice(allegro_voices[channel], sfxinfo->driver_data); + voice_set_volume(allegro_voices[channel], vol); + voice_set_pan(allegro_voices[channel], sep); + voice_start(allegro_voices[channel]); + + channels_playing[channel] = sfxinfo; + + return channel; +} + + +static void I_Allegro_StopSound(int handle) +{ + if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS) + { + return; + } + + if (channels_playing[handle] == NULL) { + return; + } + + voice_stop(allegro_voices[handle]); + channels_playing[handle] = NULL; +} + + +static boolean I_Allegro_SoundIsPlaying(int handle) +{ + int position; + + if (!sound_initialized || handle < 0 || handle >= NUM_CHANNELS) + { + return false; + } + + if (channels_playing[handle] == NULL) { + return false; + } + + position = voice_get_position(allegro_voices[handle]); + if (position < 0) { + // finished + return false; + } + + // still playing + return true; +} + +// +// Periodically called to update the sound system +// + +static void I_Allegro_UpdateSound(void) +{ + int i; + + // loop through all channels which have sample, check if they're finished + for (i = 0; i < NUM_CHANNELS; i++) { + if (channels_playing[i]) { + int position = voice_get_position(allegro_voices[i]); + if (position < 0) { + // finished + channels_playing[i] = NULL; + } + } + } +} + + +static void I_Allegro_ShutdownSound(void) +{ + int i; + + if (!sound_initialized) + { + return; + } + + for (i = 0; i < NUM_CHANNELS; i++) { + if (channels_playing[i] != NULL) { + voice_stop(allegro_voices[i]); + channels_playing[i] = NULL; + } + deallocate_voice(allegro_voices[i]); + allegro_voices[i] = -1; + } + + destroy_sample(dummy_sample); + dummy_sample = NULL; + + remove_sound(); + + sound_initialized = false; +} + + +static boolean I_Allegro_InitSound(boolean _use_sfx_prefix) +{ + int i; + + use_sfx_prefix = _use_sfx_prefix; + + // No sounds yet + + for (i=0; i +#endif // __DJGPP__ + + #define ENDOOM_W 80 #define ENDOOM_H 25 @@ -76,6 +82,20 @@ void I_Endoom(byte *endoom_data) // Shut down text mode screen TXT_Shutdown(); + +#elif defined(__DJGPP__) + + int y; + + // move cursor to bottom + // there's a direct call for moving cursor somewhere but this is simpler to write + for (y = 0; y < ENDOOM_H; y++) { + puts("\n"); + } + + // allegro exit should have been run already and so we should be in text mode again + movedata(_my_ds(), (unsigned) endoom_data, _dos_ds, 0xB8000UL, ENDOOM_W * ENDOOM_H * 2); + #endif } diff --git a/doomgeneric/i_sound.c b/doomgeneric/i_sound.c index 57f7476..c80a9d1 100644 --- a/doomgeneric/i_sound.c +++ b/doomgeneric/i_sound.c @@ -18,7 +18,7 @@ #include #include -#ifdef FEATURE_SOUND +#if defined(FEATURE_SOUND) && !defined(__DJGPP__) #include #endif @@ -60,24 +60,6 @@ static music_module_t *music_module = NULL; int snd_musicdevice = SNDDEVICE_SB; int snd_sfxdevice = SNDDEVICE_SB; -// Sound modules - -extern void I_InitTimidityConfig(void); -#ifdef FEATURE_SOUND -extern sound_module_t* DG_sound_module; -extern music_module_t* DG_music_module; -#endif -extern sound_module_t sound_pcsound_module; -extern music_module_t music_opl_module; - -// For OPL module: - -extern int opl_io_port; - -// For native music module: - -extern char *timidity_cfg_path; - // DOS-specific options: These are unused but should be maintained // so that the config file can be shared between chocolate // doom and doom.exe diff --git a/doomgeneric/i_sound.h b/doomgeneric/i_sound.h index e429e96..e31b5e5 100644 --- a/doomgeneric/i_sound.h +++ b/doomgeneric/i_sound.h @@ -234,5 +234,23 @@ extern char *snd_musiccmd; void I_BindSoundVariables(void); +// Sound modules + +void I_InitTimidityConfig(void); +#ifdef FEATURE_SOUND +extern sound_module_t DG_sound_module; +extern music_module_t DG_music_module; +#endif +extern sound_module_t sound_pcsound_module; +extern music_module_t music_opl_module; + +// For OPL module: + +extern int opl_io_port; + +// For native music module: + +extern char *timidity_cfg_path; + #endif diff --git a/doomgeneric/i_swap.h b/doomgeneric/i_swap.h index d6a5b48..11135c0 100644 --- a/doomgeneric/i_swap.h +++ b/doomgeneric/i_swap.h @@ -22,6 +22,19 @@ #ifdef FEATURE_SOUND + +#ifdef __DJGPP__ + + +#define SHORT(x) ((signed short) (x)) +#define LONG(x) ((signed int) (x)) + +#define SYS_LITTLE_ENDIAN + + +#else // __DJGPP__ + + #include // Endianess handling. @@ -55,7 +68,11 @@ #define doom_wtohs(x) (short int)(x) #endif -#else + +#endif // __DJGPP__ + + +#else // FEATURE_SOUND #define SHORT(x) ((signed short) (x)) #define LONG(x) ((signed int) (x)) diff --git a/doomgeneric/i_system.c b/doomgeneric/i_system.c index 5d00091..65ab39d 100644 --- a/doomgeneric/i_system.c +++ b/doomgeneric/i_system.c @@ -264,7 +264,7 @@ void I_Quit (void) #endif } -#if !defined(_WIN32) && !defined(__MACOSX__) +#if !defined(_WIN32) && !defined(__MACOSX__) && !defined(__DJGPP__) #define ZENITY_BINARY "/usr/bin/zenity" // returns non-zero if zenity is available @@ -347,7 +347,7 @@ static int ZenityErrorBox(char *message) return result; } -#endif /* !defined(_WIN32) && !defined(__MACOSX__) */ +#endif /* !defined(_WIN32) && !defined(__MACOSX__) && !defined(__DJGPP__) */ // @@ -448,6 +448,12 @@ void I_Error (char *error, ...) message, NULL); } +#elif defined(__DJGPP__) + { + printf("%s\n", msgbuf); + exit(-1); + } + #else { ZenityErrorBox(msgbuf); diff --git a/doomgeneric/i_video.c b/doomgeneric/i_video.c index 34b6615..8a9aac6 100644 --- a/doomgeneric/i_video.c +++ b/doomgeneric/i_video.c @@ -75,15 +75,20 @@ static struct FB_ScreenInfo s_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; -}; + +#ifdef CMAP256 + +boolean palette_changed; +struct color colors[256]; + +#else // CMAP256 static struct color colors[256]; + +#endif // CMAP256 + + void I_GetEvent(void); // The screen buffer; this is modified to draw things to the screen @@ -183,6 +188,13 @@ void I_InitGraphics (void) s_Fb.yres = DOOMGENERIC_RESY; s_Fb.xres_virtual = s_Fb.xres; s_Fb.yres_virtual = s_Fb.yres; + +#ifdef CMAP256 + + s_Fb.bits_per_pixel = 8; + +#else // CMAP256 + s_Fb.bits_per_pixel = 32; s_Fb.blue.length = 8; @@ -195,6 +207,7 @@ void I_InitGraphics (void) s_Fb.red.offset = 16; s_Fb.transp.offset = 24; +#endif // CMAP256 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); @@ -277,10 +290,17 @@ void I_FinishUpdate (void) for (i = 0; i < fb_scaling; i++) { line_out += x_offset; #ifdef CMAP256 - for (fb_scaling == 1) { + if (fb_scaling == 1) { memcpy(line_out, line_in, SCREENWIDTH); /* fb_width is bigger than Doom SCREENWIDTH... */ } else { - //XXX FIXME fb_scaling support! + int j; + + for (j = 0; j < SCREENWIDTH; j++) { + int k; + for (k = 0; k < fb_scaling; k++) { + line_out[j * fb_scaling + k] = line_in[j]; + } + } } #else //cmap_to_rgb565((void*)line_out, (void*)line_in, SCREENWIDTH); @@ -336,6 +356,12 @@ void I_SetPalette (byte* palette) colors[i].g = gammatable[usegamma][*palette++]; colors[i].b = gammatable[usegamma][*palette++]; } + +#ifdef CMAP256 + + palette_changed = true; + +#endif // CMAP256 } // Given an RGB value, find the closest matching palette index. diff --git a/doomgeneric/i_video.h b/doomgeneric/i_video.h index 85d1fea..c8565f4 100644 --- a/doomgeneric/i_video.h +++ b/doomgeneric/i_video.h @@ -138,6 +138,14 @@ void I_EnableLoadingDisk(void); void I_EndRead (void); +struct color { + uint32_t b:8; + uint32_t g:8; + uint32_t r:8; + uint32_t a:8; +}; + + extern char *video_driver; extern boolean screenvisible; @@ -157,4 +165,11 @@ extern int aspect_ratio_correct; extern int show_diskicon; extern int diskicon_readbytes; +#ifdef CMAP256 + +extern boolean palette_changed; +extern struct color colors[256]; + +#endif // CMAP256 + #endif diff --git a/doomgeneric/m_misc.c b/doomgeneric/m_misc.c index 53b86db..54b2613 100644 --- a/doomgeneric/m_misc.c +++ b/doomgeneric/m_misc.c @@ -168,7 +168,7 @@ char *M_TempFile(char *s) { char *tempdir; -#ifdef _WIN32 +#if defined(_WIN32) || defined(__DJGPP__) // Check the TEMP environment variable to find the location.