From 72d9253ab2e5e0630c824c7130a40b7158323bc9 Mon Sep 17 00:00:00 2001 From: wyatt8740 Date: Sun, 1 Oct 2023 23:53:17 -0400 Subject: Got X11 QuakeWorld to build (no GLQuakeWorld yet!). Added support for 24-bit color depth (ripped out of WinQuake, which appears to have a newer version of vid_x.c). Also, added SDL audio code (almost directly translated from WinQuake/netquake code). --- QW/client/cvar.h | 6 ++ QW/client/snd_dma.c | 12 ++- QW/client/snd_sdl.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++ QW/client/sound.h | 7 +- QW/client/vid_x.c | 136 ++++++++++++++++++++++++++++----- 5 files changed, 354 insertions(+), 22 deletions(-) create mode 100644 QW/client/snd_sdl.c (limited to 'QW/client') diff --git a/QW/client/cvar.h b/QW/client/cvar.h index bc72791..58b4e41 100644 --- a/QW/client/cvar.h +++ b/QW/client/cvar.h @@ -53,6 +53,12 @@ Cvars are restricted from having the same names as commands to keep this interface from being ambiguous. */ +/* for sdl */ +#if defined(USE_SDL2) +#define CVAR_NONE 0 +#endif +/* sdl end */ + typedef struct cvar_s { char *name; diff --git a/QW/client/snd_dma.c b/QW/client/snd_dma.c index 4168315..8554836 100644 --- a/QW/client/snd_dma.c +++ b/QW/client/snd_dma.c @@ -77,6 +77,11 @@ cvar_t volume = {"volume", "0.7", true}; cvar_t nosound = {"nosound", "0"}; cvar_t precache = {"precache", "1"}; cvar_t loadas8bit = {"loadas8bit", "0"}; +/* for sdl */ +#if defined(USE_SDL2) +cvar_t sndspeed = {"sndspeed", "11025", CVAR_NONE}; +cvar_t snd_mixspeed = {"snd_mixspeed", "44100", CVAR_NONE}; +#endif cvar_t bgmbuffer = {"bgmbuffer", "4096"}; cvar_t ambient_level = {"ambient_level", "0.3"}; cvar_t ambient_fade = {"ambient_fade", "100"}; @@ -146,8 +151,13 @@ void S_Startup (void) if (!fakedma) { +#if defined(USE_SDL2) + /* Since I borrowed a lot of the SDL2 code from Quakespasm, I + found this to be the easiest way to retrofit it: */ + rc = SNDDMA_Init(&sn); +#else rc = SNDDMA_Init(); - +#endif if (!rc) { #ifndef _WIN32 diff --git a/QW/client/snd_sdl.c b/QW/client/snd_sdl.c new file mode 100644 index 0000000..a65758c --- /dev/null +++ b/QW/client/snd_sdl.c @@ -0,0 +1,215 @@ +/* + * snd_sdl.c - SDL audio driver for Hexen II: Hammer of Thyrion (uHexen2) + * based on implementations found in the quakeforge and ioquake3 projects. + * + * Copyright (C) 1999-2005 Id Software, Inc. + * Copyright (C) 2005-2012 O.Sezer + * Copyright (C) 2010-2014 QuakeSpasm developers + * + * 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 lat er version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "quakedef.h" + +#if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG) +#if defined(USE_SDL2) +#include +#else +#include +#endif +#else +#include "SDL.h" +#endif + +static int buffersize; + + +static void SDLCALL paint_audio (void *unused, Uint8 *stream, int len) +{ + int pos, tobufend; + int len1, len2; + + if (!shm) + { /* shouldn't happen, but just in case */ + memset(stream, 0, len); + return; + } + + pos = (shm->samplepos * (shm->samplebits / 8)); + if (pos >= buffersize) + shm->samplepos = pos = 0; + + tobufend = buffersize - pos; /* bytes to buffer's end. */ + len1 = len; + len2 = 0; + + if (len1 > tobufend) + { + len1 = tobufend; + len2 = len - len1; + } + + memcpy(stream, shm->buffer + pos, len1); + + if (len2 <= 0) + { + shm->samplepos += (len1 / (shm->samplebits / 8)); + } + else + { /* wraparound? */ + memcpy(stream + len1, shm->buffer, len2); + shm->samplepos = (len2 / (shm->samplebits / 8)); + } + + if (shm->samplepos >= buffersize) + shm->samplepos = 0; +} + +qboolean SNDDMA_Init (dma_t *dma) +{ + SDL_AudioSpec desired; + int tmp, val; + char drivername[128]; + + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) + { + Con_Printf("Couldn't init SDL audio: %s\n", SDL_GetError()); + return false; + } + + /* Set up the desired format */ +/* desired.freq = snd_mixspeed.value;*/ + desired.freq = 44100; + desired.format = (loadas8bit.value) ? AUDIO_U8 : AUDIO_S16SYS; + desired.channels = 2; /* = desired_channels; */ + if (desired.freq <= 11025) + desired.samples = 256; + else if (desired.freq <= 22050) + desired.samples = 512; + else if (desired.freq <= 44100) + desired.samples = 1024; + else if (desired.freq <= 56000) + desired.samples = 2048; /* for 48 kHz */ + else + desired.samples = 4096; /* for 96 kHz */ + desired.callback = paint_audio; + desired.userdata = NULL; + + /* Open the audio device */ + if (SDL_OpenAudio(&desired, NULL) == -1) + { + Con_Printf("Couldn't open SDL audio: %s\n", SDL_GetError()); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + return false; + } + /* i think i'm just zeroing dma mem here */ + memset ((void *) dma, 0, sizeof(dma_t)); + /*shm = dma;*/ + shm = &sn; + + /* Fill the audio DMA information block */ + /* Since we passed NULL as the 'obtained' spec to SDL_OpenAudio(), + * SDL will convert to hardware format for us if needed, hence we + * directly use the desired values here. */ + shm->samplebits = (desired.format & 0xFF); /* first byte of format is bits */ +/* shm->signed8 = (desired.format == AUDIO_S8);*/ + shm->speed = desired.freq; + shm->channels = desired.channels; + tmp = (desired.samples * desired.channels) * 10; + if (tmp & (tmp - 1)) + { /* make it a power of two */ + val = 1; + while (val < tmp) + val <<= 1; + + tmp = val; + } + shm->samples = tmp; + shm->samplepos = 0; + shm->submission_chunk = 1; + + Con_Printf ("SDL audio spec : %d Hz, %d samples, %d channels\n", + desired.freq, desired.samples, desired.channels); +#if defined(USE_SDL2) + { + const char *driver = SDL_GetCurrentAudioDriver(); + const char *device = SDL_GetAudioDeviceName(0, SDL_FALSE); + snprintf(drivername, sizeof(drivername), "%s - %s", + driver != NULL ? driver : "(UNKNOWN)", + device != NULL ? device : "(UNKNOWN)"); + } +#else + if (SDL_AudioDriverName(drivername, sizeof(drivername)) == NULL) + strcpy(drivername, "(UNKNOWN)"); +#endif + buffersize = shm->samples * (shm->samplebits / 8); + Con_Printf ("SDL audio driver: %s, %d bytes buffer\n", drivername, buffersize); + + shm->buffer = (unsigned char *) calloc (1, buffersize); +// if (!shm->buffer) + if (!shm->buffer || shm->buffer == (unsigned char *)-1) + { + SDL_CloseAudio(); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + shm = NULL; + Con_Printf ("Failed allocating memory for SDL audio\n"); + return false; + } + + SDL_PauseAudio(0); + + return true; +} + +int SNDDMA_GetDMAPos (void) +{ + return shm->samplepos; +} + +void SNDDMA_Shutdown (void) +{ + if (shm) + { + Con_Printf ("Shutting down SDL sound\n"); + SDL_CloseAudio(); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + if (shm->buffer) + free (shm->buffer); + shm->buffer = NULL; + shm = NULL; + } +} + +void SNDDMA_LockBuffer (void) +{ + SDL_LockAudio (); +} + +void SNDDMA_Submit (void) +{ + SDL_UnlockAudio(); +} + +void SNDDMA_BlockSound (void) +{ + SDL_PauseAudio(1); +} + +void SNDDMA_UnblockSound (void) +{ + SDL_PauseAudio(0); +} + diff --git a/QW/client/sound.h b/QW/client/sound.h index 941e620..c1e90fa 100644 --- a/QW/client/sound.h +++ b/QW/client/sound.h @@ -111,9 +111,14 @@ channel_t *SND_PickChannel(int entnum, int entchannel); // spatializes a channel void SND_Spatialize(channel_t *ch); +#if defined(USE_SDL2) +/* Probably the easiest way to retrofit quakespasm's SDL2 audio code into + Id Quake. */ +qboolean SNDDMA_Init(dma_t *dma); +#else // initializes cycling through a DMA buffer and returns information on it qboolean SNDDMA_Init(void); - +#endif // gets the current DMA position int SNDDMA_GetDMAPos(void); diff --git a/QW/client/vid_x.c b/QW/client/vid_x.c index 891fb3b..c96545c 100644 --- a/QW/client/vid_x.c +++ b/QW/client/vid_x.c @@ -21,7 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define _BSD -typedef unsigned short PIXEL; #include #include @@ -50,7 +49,6 @@ float old_windowed_mouse; int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar; byte *VGA_pagebase; - qboolean mouse_avail; int mouse_buttons=3; int mouse_oldbuttonstate; @@ -112,7 +110,10 @@ void (*vid_menudrawfn)(void); void (*vid_menukeyfn)(int key); void VID_MenuKey (int key); -static PIXEL st2d_8to16table[256]; +typedef unsigned short PIXEL16; +typedef unsigned long PIXEL24; +static PIXEL16 st2d_8to16table[256]; +static PIXEL24 st2d_8to24table[256]; static int shiftmask_fl=0; static long r_shift,g_shift,b_shift; static unsigned long r_mask,g_mask,b_mask; @@ -129,9 +130,36 @@ void shiftmask_init() shiftmask_fl=1; } -PIXEL xlib_rgb(int r,int g,int b) +PIXEL16 xlib_rgb16(int r,int g,int b) +{ + PIXEL16 p; + if(shiftmask_fl==0) shiftmask_init(); + p=0; + + if(r_shift>0) { + p=(r<<(r_shift))&r_mask; + } else if(r_shift<0) { + p=(r>>(-r_shift))&r_mask; + } else p|=(r&r_mask); + + if(g_shift>0) { + p|=(g<<(g_shift))&g_mask; + } else if(g_shift<0) { + p|=(g>>(-g_shift))&g_mask; + } else p|=(g&g_mask); + + if(b_shift>0) { + p|=(b<<(b_shift))&b_mask; + } else if(b_shift<0) { + p|=(b>>(-b_shift))&b_mask; + } else p|=(b&b_mask); + + return p; +} + +PIXEL24 xlib_rgb24(int r,int g,int b) { - PIXEL p; + PIXEL24 p; if(shiftmask_fl==0) shiftmask_init(); p=0; @@ -160,16 +188,71 @@ void st2_fixup( XImage *framebuf, int x, int y, int width, int height) { int xi,yi; unsigned char *src; - PIXEL *dest; + PIXEL16 *dest; + register int count, n; if( (x<0)||(y<0) )return; for (yi = y; yi < (y+height); yi++) { src = &framebuf->data [yi * framebuf->bytes_per_line]; - dest = (PIXEL*)src; - for(xi = (x+width-1); xi >= x; xi--) { - dest[xi] = st2d_8to16table[src[xi]]; + + // Duff's Device + count = width; + n = (count + 7) / 8; + dest = ((PIXEL16 *)src) + x+width - 1; + src += x+width - 1; + + switch (count % 8) { + case 0: do { *dest-- = st2d_8to16table[*src--]; + case 7: *dest-- = st2d_8to16table[*src--]; + case 6: *dest-- = st2d_8to16table[*src--]; + case 5: *dest-- = st2d_8to16table[*src--]; + case 4: *dest-- = st2d_8to16table[*src--]; + case 3: *dest-- = st2d_8to16table[*src--]; + case 2: *dest-- = st2d_8to16table[*src--]; + case 1: *dest-- = st2d_8to16table[*src--]; + } while (--n > 0); } + +// for(xi = (x+width-1); xi >= x; xi--) { +// dest[xi] = st2d_8to16table[src[xi]]; +// } + } +} + +void st3_fixup( XImage *framebuf, int x, int y, int width, int height) +{ + int xi,yi; + unsigned char *src; + PIXEL24 *dest; + register int count, n; + + if( (x<0)||(y<0) )return; + + for (yi = y; yi < (y+height); yi++) { + src = &framebuf->data [yi * framebuf->bytes_per_line]; + + // Duff's Device + count = width; + n = (count + 7) / 8; + dest = ((PIXEL24 *)src) + x+width - 1; + src += x+width - 1; + + switch (count % 8) { + case 0: do { *dest-- = st2d_8to24table[*src--]; + case 7: *dest-- = st2d_8to24table[*src--]; + case 6: *dest-- = st2d_8to24table[*src--]; + case 5: *dest-- = st2d_8to24table[*src--]; + case 4: *dest-- = st2d_8to24table[*src--]; + case 3: *dest-- = st2d_8to24table[*src--]; + case 2: *dest-- = st2d_8to24table[*src--]; + case 1: *dest-- = st2d_8to24table[*src--]; + } while (--n > 0); + } + +// for(xi = (x+width-1); xi >= x; xi--) { +// dest[xi] = st2d_8to16table[src[xi]]; +// } } } @@ -367,8 +450,6 @@ void VID_Init (unsigned char *palette) XVisualInfo template; int num_visuals; int template_mask; - - S_Init(); ignorenext=0; vid.width = 320; @@ -517,20 +598,17 @@ void VID_Init (unsigned char *palette) if (x_visinfo->class != TrueColor) XFreeColormap(x_disp, tmpcmap); - } if (x_visinfo->depth == 8) { - - // create and upload the palette + // create and upload the palette if (x_visinfo->class == PseudoColor) { x_cmap = XCreateColormap(x_disp, x_win, x_vis, AllocAll); VID_SetPalette(palette); XSetWindowColormap(x_disp, x_win, x_cmap); } - } // inviso cursor @@ -610,9 +688,10 @@ void VID_SetPalette(unsigned char *palette) int i; XColor colors[256]; - for(i=0;i<256;i++) - st2d_8to16table[i]= xlib_rgb(palette[i*3], - palette[i*3+1],palette[i*3+2]); + for(i=0;i<256;i++) { + st2d_8to16table[i]= xlib_rgb16(palette[i*3], palette[i*3+1],palette[i*3+2]); + st2d_8to24table[i]= xlib_rgb24(palette[i*3], palette[i*3+1],palette[i*3+2]); + } if (x_visinfo->class == PseudoColor && x_visinfo->depth == 8) { @@ -881,6 +960,7 @@ void GetEvent(void) void VID_Update (vrect_t *rects) { + vrect_t full; // if the window changes dimension, skip this frame @@ -906,15 +986,27 @@ void VID_Update (vrect_t *rects) return; } + // force full update if not 8bit + if (x_visinfo->depth != 8) { + extern int scr_fullupdate; + + scr_fullupdate = 0; + } + + if (doShm) { while (rects) { - if (x_visinfo->depth != 8) + if (x_visinfo->depth == 16) st2_fixup( x_framebuffer[current_framebuffer], rects->x, rects->y, rects->width, rects->height); + else if (x_visinfo->depth == 24) + st3_fixup( x_framebuffer[current_framebuffer], + rects->x, rects->y, rects->width, + rects->height); if (!XShmPutImage(x_disp, x_win, x_gc, x_framebuffer[current_framebuffer], rects->x, rects->y, rects->x, rects->y, rects->width, rects->height, True)) @@ -932,10 +1024,14 @@ void VID_Update (vrect_t *rects) { while (rects) { - if (x_visinfo->depth != 8) + if (x_visinfo->depth == 16) st2_fixup( x_framebuffer[current_framebuffer], rects->x, rects->y, rects->width, rects->height); + else if (x_visinfo->depth == 24) + st3_fixup( x_framebuffer[current_framebuffer], + rects->x, rects->y, rects->width, + rects->height); XPutImage(x_disp, x_win, x_gc, x_framebuffer[0], rects->x, rects->y, rects->x, rects->y, rects->width, rects->height); rects = rects->pnext; -- cgit v1.2.3