--- /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.
+static int /*__itimer_which*/ itimer = ITIMER_REAL;
+
+static int sig = SIGALRM;
+
+// 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 )
+{
+ // Needed for gametick clockwork.
+ struct itimerval value;
+ struct itimerval ovalue;
+ struct sigaction act;
+ struct sigaction oact;
+
+ int res;
+
+ // This sets to SA_ONESHOT and SA_NOMASK, thus we can not use it.
+ // signal( _sig, handle_SIG_TICK );
+
+ // Now we have to change this attribute for repeated calls.
+ act.sa_handler = I_HandleSoundTimer;
+#ifndef sun
+ //ac t.sa_mask = _sig;
+#endif
+ act.sa_flags = SA_RESTART;
+
+ sigaction( sig, &act, &oact );
+
+ value.it_interval.tv_sec = 0;
+ value.it_interval.tv_usec = duration_of_tick;
+ value.it_value.tv_sec = 0;
+ value.it_value.tv_usec = duration_of_tick;
+
+ // Error is -1.
+ res = -1; //setitimer( itimer, &value, &ovalue );
+
+ // Debug.
+ if ( res == -1 )
+ fprintf( stderr, "I_SoundSetTimer: interrupt n.a.\n");
+
+ return res;
+}
+
+
+// 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");
+}
--- /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:
+// 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 <stdlib.h>
+#include <unistd.h>
+
+#include <stdarg.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "doomstat.h"
+#include "i_system.h"
+#include "v_video.h"
+#include "m_argv.h"
+#include "d_main.h"
+
+#include "doomdef.h"
+
+#define POINTER_WARP_COUNTDOWN 1
+
+//Display* X_display=0;
+//Window X_mainWindow;
+//Colormap X_cmap;
+//Visual* X_visual;
+//GC X_gc;
+//XEvent X_event;
+//int X_screen;
+//XVisualInfo X_visualinfo;
+//XImage* image;
+int X_width;
+int X_height;
+
+// MIT SHared Memory extension.
+boolean doShm;
+
+//XShmSegmentInfo X_shminfo;
+int X_shmeventtype;
+
+// Fake mouse handling.
+// This cannot work properly w/o DGA.
+// Needs an invisible mouse cursor at least.
+boolean grabMouse;
+int doPointerWarp = POINTER_WARP_COUNTDOWN;
+
+// Blocky mode,
+// replace each 320x200 pixel with multiply*multiply pixels.
+// According to Dave Taylor, it still is a bonehead thing
+// to use ....
+static int multiply=1;
+
+
+//
+// Translates the key currently in X_event
+//
+
+int xlatekey(void)
+{
+
+ return 0;
+ /*
+ int rc;
+
+ switch(rc = XKeycodeToKeysym(X_display, X_event.xkey.keycode, 0))
+ {
+ case XK_Left: rc = KEY_LEFTARROW; break;
+ case XK_Right: rc = KEY_RIGHTARROW; break;
+ case XK_Down: rc = KEY_DOWNARROW; break;
+ case XK_Up: rc = KEY_UPARROW; break;
+ case XK_Escape: rc = KEY_ESCAPE; break;
+ case XK_Return: rc = KEY_ENTER; break;
+ case XK_Tab: rc = KEY_TAB; break;
+ case XK_F1: rc = KEY_F1; break;
+ case XK_F2: rc = KEY_F2; break;
+ case XK_F3: rc = KEY_F3; break;
+ case XK_F4: rc = KEY_F4; break;
+ case XK_F5: rc = KEY_F5; break;
+ case XK_F6: rc = KEY_F6; break;
+ case XK_F7: rc = KEY_F7; break;
+ case XK_F8: rc = KEY_F8; break;
+ case XK_F9: rc = KEY_F9; break;
+ case XK_F10: rc = KEY_F10; break;
+ case XK_F11: rc = KEY_F11; break;
+ case XK_F12: rc = KEY_F12; break;
+
+ case XK_BackSpace:
+ case XK_Delete: rc = KEY_BACKSPACE; break;
+
+ case XK_Pause: rc = KEY_PAUSE; break;
+
+ case XK_KP_Equal:
+ case XK_equal: rc = KEY_EQUALS; break;
+
+ case XK_KP_Subtract:
+ case XK_minus: rc = KEY_MINUS; break;
+
+ case XK_Shift_L:
+ case XK_Shift_R:
+ rc = KEY_RSHIFT;
+ break;
+
+ case XK_Control_L:
+ case XK_Control_R:
+ rc = KEY_RCTRL;
+ break;
+
+ case XK_Alt_L:
+ case XK_Meta_L:
+ case XK_Alt_R:
+ case XK_Meta_R:
+ rc = KEY_RALT;
+ break;
+
+ default:
+ if (rc >= XK_space && rc <= XK_asciitilde)
+ rc = rc - XK_space + ' ';
+ if (rc >= 'A' && rc <= 'Z')
+ rc = rc - 'A' + 'a';
+ break;
+ }
+
+ return rc;
+
+ */
+}
+
+void I_ShutdownGraphics(void)
+{
+ return;
+ /*
+ // Detach from X server
+ if (!XShmDetach(X_display, &X_shminfo))
+ I_Error("XShmDetach() failed in I_ShutdownGraphics()");
+
+ // Release shared memory.
+ shmdt(X_shminfo.shmaddr);
+ shmctl(X_shminfo.shmid, IPC_RMID, 0);
+
+ // Paranoia.
+ image->data = NULL;
+ */
+}
+
+
+
+//
+// I_StartFrame
+//
+void I_StartFrame (void)
+{
+ // er?
+
+}
+
+static int lastmousex = 0;
+static int lastmousey = 0;
+boolean mousemoved = false;
+boolean shmFinished;
+
+void I_GetEvent(void)
+{
+
+ return;
+ /*
+ event_t event;
+
+ // put event-grabbing stuff in here
+ XNextEvent(X_display, &X_event);
+ switch (X_event.type)
+ {
+ case KeyPress:
+ event.type = ev_keydown;
+ event.data1 = xlatekey();
+ D_PostEvent(&event);
+ // fprintf(stderr, "k");
+ break;
+ case KeyRelease:
+ event.type = ev_keyup;
+ event.data1 = xlatekey();
+ D_PostEvent(&event);
+ // fprintf(stderr, "ku");
+ break;
+ case ButtonPress:
+ event.type = ev_mouse;
+ event.data1 =
+ (X_event.xbutton.state & Button1Mask)
+ | (X_event.xbutton.state & Button2Mask ? 2 : 0)
+ | (X_event.xbutton.state & Button3Mask ? 4 : 0)
+ | (X_event.xbutton.button == Button1)
+ | (X_event.xbutton.button == Button2 ? 2 : 0)
+ | (X_event.xbutton.button == Button3 ? 4 : 0);
+ event.data2 = event.data3 = 0;
+ D_PostEvent(&event);
+ // fprintf(stderr, "b");
+ break;
+ case ButtonRelease:
+ event.type = ev_mouse;
+ event.data1 =
+ (X_event.xbutton.state & Button1Mask)
+ | (X_event.xbutton.state & Button2Mask ? 2 : 0)
+ | (X_event.xbutton.state & Button3Mask ? 4 : 0);
+ // suggest parentheses around arithmetic in operand of |
+ event.data1 =
+ event.data1
+ ^ (X_event.xbutton.button == Button1 ? 1 : 0)
+ ^ (X_event.xbutton.button == Button2 ? 2 : 0)
+ ^ (X_event.xbutton.button == Button3 ? 4 : 0);
+ event.data2 = event.data3 = 0;
+ D_PostEvent(&event);
+ // fprintf(stderr, "bu");
+ break;
+ case MotionNotify:
+ event.type = ev_mouse;
+ event.data1 =
+ (X_event.xmotion.state & Button1Mask)
+ | (X_event.xmotion.state & Button2Mask ? 2 : 0)
+ | (X_event.xmotion.state & Button3Mask ? 4 : 0);
+ event.data2 = (X_event.xmotion.x - lastmousex) << 2;
+ event.data3 = (lastmousey - X_event.xmotion.y) << 2;
+
+ if (event.data2 || event.data3)
+ {
+ lastmousex = X_event.xmotion.x;
+ lastmousey = X_event.xmotion.y;
+ if (X_event.xmotion.x != X_width/2 &&
+ X_event.xmotion.y != X_height/2)
+ {
+ D_PostEvent(&event);
+ // fprintf(stderr, "m");
+ mousemoved = false;
+ } else
+ {
+ mousemoved = true;
+ }
+ }
+ break;
+
+ case Expose:
+ case ConfigureNotify:
+ break;
+
+ default:
+ if (doShm && X_event.type == X_shmeventtype) shmFinished = true;
+ break;
+ }
+ */
+
+}
+
+// Cursor
+// createnullcursor
+// ( Display* display,
+// Window root )
+// {
+// Pixmap cursormask;
+// XGCValues xgc;
+// GC gc;
+// XColor dummycolour;
+// Cursor cursor;
+//
+// cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
+// xgc.function = GXclear;
+// gc = XCreateGC(display, cursormask, GCFunction, &xgc);
+// XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
+// dummycolour.pixel = 0;
+// dummycolour.red = 0;
+// dummycolour.flags = 04;
+// cursor = XCreatePixmapCursor(display, cursormask, cursormask,
+// &dummycolour,&dummycolour, 0,0);
+// XFreePixmap(display,cursormask);
+// XFreeGC(display,gc);
+// return cursor;
+// }
+
+//
+// I_StartTic
+//
+void I_StartTic (void)
+{
+
+ return 0;
+
+ /*
+
+ if (!X_display)
+ return;
+
+ while (XPending(X_display))
+ I_GetEvent();
+
+ // Warp the pointer back to the middle of the window
+ // or it will wander off - that is, the game will
+ // loose input focus within X11.
+ if (grabMouse)
+ {
+ if (!--doPointerWarp)
+ {
+ XWarpPointer( X_display,
+ None,
+ X_mainWindow,
+ 0, 0,
+ 0, 0,
+ X_width/2, X_height/2);
+
+ doPointerWarp = POINTER_WARP_COUNTDOWN;
+ }
+ }
+
+ mousemoved = false;
+ */
+
+}
+
+
+//
+// I_UpdateNoBlit
+//
+void I_UpdateNoBlit (void)
+{
+ // what is this?
+}
+
+//
+// I_FinishUpdate
+//
+void I_FinishUpdate (void)
+{
+
+ return;
+
+ /*
+ static int lasttic;
+ int tics;
+ int i;
+ // UNUSED static unsigned char *bigscreen=0;
+
+ // draws little dots on the bottom of the screen
+ if (devparm)
+ {
+
+ i = I_GetTime();
+ tics = i - lasttic;
+ lasttic = i;
+ if (tics > 20) tics = 20;
+
+ for (i=0 ; i<tics*2 ; i+=2)
+ screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff;
+ for ( ; i<20*2 ; i+=2)
+ screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0;
+
+ }
+
+ // scales the screen size before blitting it
+ if (multiply == 2)
+ {
+ unsigned int *olineptrs[2];
+ unsigned int *ilineptr;
+ int x, y, i;
+ unsigned int twoopixels;
+ unsigned int twomoreopixels;
+ unsigned int fouripixels;
+
+ ilineptr = (unsigned int *) (screens[0]);
+ for (i=0 ; i<2 ; i++)
+ olineptrs[i] = (unsigned int *) &image->data[i*X_width];
+
+ y = SCREENHEIGHT;
+ while (y--)
+ {
+ x = SCREENWIDTH;
+ do
+ {
+ fouripixels = *ilineptr++;
+ twoopixels = (fouripixels & 0xff000000)
+ | ((fouripixels>>8) & 0xffff00)
+ | ((fouripixels>>16) & 0xff);
+ twomoreopixels = ((fouripixels<<16) & 0xff000000)
+ | ((fouripixels<<8) & 0xffff00)
+ | (fouripixels & 0xff);
+#ifdef __BIG_ENDIAN__
+ *olineptrs[0]++ = twoopixels;
+ *olineptrs[1]++ = twoopixels;
+ *olineptrs[0]++ = twomoreopixels;
+ *olineptrs[1]++ = twomoreopixels;
+#else
+ *olineptrs[0]++ = twomoreopixels;
+ *olineptrs[1]++ = twomoreopixels;
+ *olineptrs[0]++ = twoopixels;
+ *olineptrs[1]++ = twoopixels;
+#endif
+ } while (x-=4);
+ olineptrs[0] += X_width/4;
+ olineptrs[1] += X_width/4;
+ }
+
+ }
+ else if (multiply == 3)
+ {
+ unsigned int *olineptrs[3];
+ unsigned int *ilineptr;
+ int x, y, i;
+ unsigned int fouropixels[3];
+ unsigned int fouripixels;
+
+ ilineptr = (unsigned int *) (screens[0]);
+ for (i=0 ; i<3 ; i++)
+ olineptrs[i] = (unsigned int *) &image->data[i*X_width];
+
+ y = SCREENHEIGHT;
+ while (y--)
+ {
+ x = SCREENWIDTH;
+ do
+ {
+ fouripixels = *ilineptr++;
+ fouropixels[0] = (fouripixels & 0xff000000)
+ | ((fouripixels>>8) & 0xff0000)
+ | ((fouripixels>>16) & 0xffff);
+ fouropixels[1] = ((fouripixels<<8) & 0xff000000)
+ | (fouripixels & 0xffff00)
+ | ((fouripixels>>8) & 0xff);
+ fouropixels[2] = ((fouripixels<<16) & 0xffff0000)
+ | ((fouripixels<<8) & 0xff00)
+ | (fouripixels & 0xff);
+#ifdef __BIG_ENDIAN__
+ *olineptrs[0]++ = fouropixels[0];
+ *olineptrs[1]++ = fouropixels[0];
+ *olineptrs[2]++ = fouropixels[0];
+ *olineptrs[0]++ = fouropixels[1];
+ *olineptrs[1]++ = fouropixels[1];
+ *olineptrs[2]++ = fouropixels[1];
+ *olineptrs[0]++ = fouropixels[2];
+ *olineptrs[1]++ = fouropixels[2];
+ *olineptrs[2]++ = fouropixels[2];
+#else
+ *olineptrs[0]++ = fouropixels[2];
+ *olineptrs[1]++ = fouropixels[2];
+ *olineptrs[2]++ = fouropixels[2];
+ *olineptrs[0]++ = fouropixels[1];
+ *olineptrs[1]++ = fouropixels[1];
+ *olineptrs[2]++ = fouropixels[1];
+ *olineptrs[0]++ = fouropixels[0];
+ *olineptrs[1]++ = fouropixels[0];
+ *olineptrs[2]++ = fouropixels[0];
+#endif
+ } while (x-=4);
+ olineptrs[0] += 2*X_width/4;
+ olineptrs[1] += 2*X_width/4;
+ olineptrs[2] += 2*X_width/4;
+ }
+
+ }
+ else if (multiply == 4)
+ {
+ // Broken. Gotta fix this some day.
+ void Expand4(unsigned *, double *);
+ Expand4 ((unsigned *)(screens[0]), (double *) (image->data));
+ }
+
+ if (doShm)
+ {
+
+ if (!XShmPutImage( X_display,
+ X_mainWindow,
+ X_gc,
+ image,
+ 0, 0,
+ 0, 0,
+ X_width, X_height,
+ True ))
+ I_Error("XShmPutImage() failed\n");
+
+ // wait for it to finish and processes all input events
+ shmFinished = false;
+ do
+ {
+ I_GetEvent();
+ } while (!shmFinished);
+
+ }
+ else
+ {
+
+ // draw the image
+ XPutImage( X_display,
+ X_mainWindow,
+ X_gc,
+ image,
+ 0, 0,
+ 0, 0,
+ X_width, X_height );
+
+ // sync up with server
+ XSync(X_display, False);
+
+ }
+
+ */
+}
+
+
+//
+// I_ReadScreen
+//
+void I_ReadScreen (byte* scr)
+{
+ //memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT);
+}
+
+
+//
+// Palette stuff.
+//
+//static XColor colors[256];
+
+//
+// I_SetPalette
+//
+void I_SetPalette (byte* palette)
+{
+ //UploadNewPalette(X_cmap, palette);
+}
+
+
+void I_InitGraphics(void)
+{
+
+ return;
+
+ /*
+ char* displayname;
+ char* d;
+ int n;
+ int pnum;
+ int x=0;
+ int y=0;
+
+ // warning: char format, different type arg
+ char xsign=' ';
+ char ysign=' ';
+
+ int oktodraw;
+ unsigned long attribmask;
+ XSetWindowAttributes attribs;
+ XGCValues xgcvalues;
+ int valuemask;
+ static int firsttime=1;
+
+ if (!firsttime)
+ return;
+ firsttime = 0;
+
+ signal(SIGINT, (void (*)(int)) I_Quit);
+
+ if (M_CheckParm("-2"))
+ multiply = 2;
+
+ if (M_CheckParm("-3"))
+ multiply = 3;
+
+ if (M_CheckParm("-4"))
+ multiply = 4;
+
+ X_width = SCREENWIDTH * multiply;
+ X_height = SCREENHEIGHT * multiply;
+
+ // check for command-line display name
+ if ( (pnum=M_CheckParm("-disp")) ) // suggest parentheses around assignment
+ displayname = myargv[pnum+1];
+ else
+ displayname = 0;
+
+ // check if the user wants to grab the mouse (quite unnice)
+ grabMouse = !!M_CheckParm("-grabmouse");
+
+ // check for command-line geometry
+ if ( (pnum=M_CheckParm("-geom")) ) // suggest parentheses around assignment
+ {
+ // warning: char format, different type arg 3,5
+ n = sscanf(myargv[pnum+1], "%c%d%c%d", &xsign, &x, &ysign, &y);
+
+ if (n==2)
+ x = y = 0;
+ else if (n==6)
+ {
+ if (xsign == '-')
+ x = -x;
+ if (ysign == '-')
+ y = -y;
+ }
+ else
+ I_Error("bad -geom parameter");
+ }
+
+ // open the display
+ X_display = XOpenDisplay(displayname);
+ if (!X_display)
+ {
+ if (displayname)
+ I_Error("Could not open display [%s]", displayname);
+ else
+ I_Error("Could not open display (DISPLAY=[%s])", getenv("DISPLAY"));
+ }
+
+ // use the default visual
+ X_screen = DefaultScreen(X_display);
+ if (!XMatchVisualInfo(X_display, X_screen, 8, PseudoColor, &X_visualinfo))
+ I_Error("xdoom currently only supports 256-color PseudoColor screens");
+ X_visual = X_visualinfo.visual;
+
+ // check for the MITSHM extension
+ doShm = XShmQueryExtension(X_display);
+
+ // even if it's available, make sure it's a local connection
+ if (doShm)
+ {
+ if (!displayname) displayname = (char *) getenv("DISPLAY");
+ if (displayname)
+ {
+ d = displayname;
+ while (*d && (*d != ':')) d++;
+ if (*d) *d = 0;
+ if (!(!strcasecmp(displayname, "unix") || !*displayname)) doShm = false;
+ }
+ }
+
+ fprintf(stderr, "Using MITSHM extension\n");
+
+ // create the colormap
+ X_cmap = XCreateColormap(X_display, RootWindow(X_display,
+ X_screen), X_visual, AllocAll);
+
+ // setup attributes for main window
+ attribmask = CWEventMask | CWColormap | CWBorderPixel;
+ attribs.event_mask =
+ KeyPressMask
+ | KeyReleaseMask
+ // | PointerMotionMask | ButtonPressMask | ButtonReleaseMask
+ | ExposureMask;
+
+ attribs.colormap = X_cmap;
+ attribs.border_pixel = 0;
+
+ // create the main window
+ X_mainWindow = XCreateWindow( X_display,
+ RootWindow(X_display, X_screen),
+ x, y,
+ X_width, X_height,
+ 0, // borderwidth
+ 8, // depth
+ InputOutput,
+ X_visual,
+ attribmask,
+ &attribs );
+
+ XDefineCursor(X_display, X_mainWindow,
+ createnullcursor( X_display, X_mainWindow ) );
+
+ // create the GC
+ valuemask = GCGraphicsExposures;
+ xgcvalues.graphics_exposures = False;
+ X_gc = XCreateGC( X_display,
+ X_mainWindow,
+ valuemask,
+ &xgcvalues );
+
+ // map the window
+ XMapWindow(X_display, X_mainWindow);
+
+ // wait until it is OK to draw
+ oktodraw = 0;
+ while (!oktodraw)
+ {
+ XNextEvent(X_display, &X_event);
+ if (X_event.type == Expose
+ && !X_event.xexpose.count)
+ {
+ oktodraw = 1;
+ }
+ }
+
+ // grabs the pointer so it is restricted to this window
+ if (grabMouse)
+ XGrabPointer(X_display, X_mainWindow, True,
+ ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
+ GrabModeAsync, GrabModeAsync,
+ X_mainWindow, None, CurrentTime);
+
+ if (doShm)
+ {
+
+ X_shmeventtype = XShmGetEventBase(X_display) + ShmCompletion;
+
+ // create the image
+ image = XShmCreateImage( X_display,
+ X_visual,
+ 8,
+ ZPixmap,
+ 0,
+ &X_shminfo,
+ X_width,
+ X_height );
+
+ grabsharedmemory(image->bytes_per_line * image->height);
+
+
+ // UNUSED
+ // create the shared memory segment
+ // X_shminfo.shmid = shmget (IPC_PRIVATE,
+ // image->bytes_per_line * image->height, IPC_CREAT | 0777);
+ // if (X_shminfo.shmid < 0)
+ // {
+ // perror("");
+ // I_Error("shmget() failed in InitGraphics()");
+ // }
+ // fprintf(stderr, "shared memory id=%d\n", X_shminfo.shmid);
+ // attach to the shared memory segment
+ // image->data = X_shminfo.shmaddr = shmat(X_shminfo.shmid, 0, 0);
+
+
+ if (!image->data)
+ {
+ perror("");
+ I_Error("shmat() failed in InitGraphics()");
+ }
+
+ // get the X server to attach to it
+ if (!XShmAttach(X_display, &X_shminfo))
+ I_Error("XShmAttach() failed in InitGraphics()");
+
+ }
+ else
+ {
+ image = XCreateImage( X_display,
+ X_visual,
+ 8,
+ ZPixmap,
+ 0,
+ (char*)malloc(X_width * X_height),
+ X_width, X_height,
+ 8,
+ X_width );
+
+ }
+
+ if (multiply == 1)
+ screens[0] = (unsigned char *) (image->data);
+ else
+ screens[0] = (unsigned char *) malloc (SCREENWIDTH * SCREENHEIGHT);
+
+ */
+}
+
+
+void InitExpand (void)
+{
+ /*
+ int i;
+
+ for (i=0 ; i<256 ; i++)
+ exptable[i] = i | (i<<8) | (i<<16) | (i<<24);
+ */
+}
+
+
+void InitExpand2 (void)
+{
+ return;
+ /*
+ int i;
+ int j;
+ // UNUSED unsigned iexp, jexp;
+ double* exp;
+ union
+ {
+ double d;
+ unsigned u[2];
+ } pixel;
+
+ printf ("building exptable2...\n");
+ exp = exptable2;
+ for (i=0 ; i<256 ; i++)
+ {
+ pixel.u[0] = i | (i<<8) | (i<<16) | (i<<24);
+ for (j=0 ; j<256 ; j++)
+ {
+ pixel.u[1] = j | (j<<8) | (j<<16) | (j<<24);
+ *exp++ = pixel.d;
+ }
+ }
+ printf ("done.\n");
+ */
+}
+
+int inited;
+
+void
+Expand4
+( unsigned* lineptr,
+ double* xline )
+{
+ return;
+ /*
+ double dpixel;
+ unsigned x;
+ unsigned y;
+ unsigned fourpixels;
+ unsigned step;
+ double* exp;
+
+ exp = exptable2;
+ if (!inited)
+ {
+ inited = 1;
+ InitExpand2 ();
+ }
+
+
+ step = 3*SCREENWIDTH/2;
+
+ y = SCREENHEIGHT-1;
+ do
+ {
+ x = SCREENWIDTH;
+
+ do
+ {
+ fourpixels = lineptr[0];
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
+ xline[0] = dpixel;
+ xline[160] = dpixel;
+ xline[320] = dpixel;
+ xline[480] = dpixel;
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
+ xline[1] = dpixel;
+ xline[161] = dpixel;
+ xline[321] = dpixel;
+ xline[481] = dpixel;
+
+ fourpixels = lineptr[1];
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
+ xline[2] = dpixel;
+ xline[162] = dpixel;
+ xline[322] = dpixel;
+ xline[482] = dpixel;
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
+ xline[3] = dpixel;
+ xline[163] = dpixel;
+ xline[323] = dpixel;
+ xline[483] = dpixel;
+
+ fourpixels = lineptr[2];
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
+ xline[4] = dpixel;
+ xline[164] = dpixel;
+ xline[324] = dpixel;
+ xline[484] = dpixel;
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
+ xline[5] = dpixel;
+ xline[165] = dpixel;
+ xline[325] = dpixel;
+ xline[485] = dpixel;
+
+ fourpixels = lineptr[3];
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff0000)>>13) );
+ xline[6] = dpixel;
+ xline[166] = dpixel;
+ xline[326] = dpixel;
+ xline[486] = dpixel;
+
+ dpixel = *(double *)( (int)exp + ( (fourpixels&0xffff)<<3 ) );
+ xline[7] = dpixel;
+ xline[167] = dpixel;
+ xline[327] = dpixel;
+ xline[487] = dpixel;
+
+ lineptr+=4;
+ xline+=8;
+ } while (x-=16);
+ xline += step;
+ } while (y--);
+ */
+}
+
+