diff --git a/dat/outfit.xml b/dat/outfit.xml index 29d0901..3dc6234 100644 --- a/dat/outfit.xml +++ b/dat/outfit.xml @@ -8,6 +8,7 @@ lasergreen + laser 500 550 300 diff --git a/src/main.c b/src/main.c index 1064d03..b2627bc 100644 --- a/src/main.c +++ b/src/main.c @@ -104,7 +104,7 @@ int main(int argc, char** argv) { // OpenAL sound. if(sound_init()) WARN("Problem setting up sound!"); music_load("Machina"); - music_play(); + //music_play(); // Input. if((indjoystick >= 0) || (namjoystick != NULL)) { @@ -170,6 +170,8 @@ int main(int argc, char** argv) { input_handle(&event); // handles all the events the player keybinds. } + sound_update(); // Do the sound stuff. + glClear(GL_COLOR_BUFFER_BIT); fps_control(); // Who doesn't love FPS control? diff --git a/src/outfit.c b/src/outfit.c index 951f890..0a8a49d 100644 --- a/src/outfit.c +++ b/src/outfit.c @@ -105,6 +105,8 @@ static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) { snprintf(str, strlen(xml_get(node))+sizeof(OUTFIT_GFX)+4, OUTFIT_GFX"%s.png", xml_get(node)); tmp->gfx_space = gl_newSprite(str, 6, 6); } + else if(xml_isNode(node, "sound")) + tmp->sound = sound_get(xml_get(node)); else if(xml_isNode(node, "damage")) { cur = node->children; do { @@ -116,6 +118,7 @@ static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent) { #define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name) if(tmp->gfx_space == NULL) WARN("Outfit '%s' missing 'gfx' element", tmp->name); + MELEMENT(tmp->sound, "sound"); MELEMENT(tmp->delay, "delay"); MELEMENT(tmp->speed, "speed"); MELEMENT(tmp->range, "range"); diff --git a/src/pilot.c b/src/pilot.c index 9450e93..5d633e2 100644 --- a/src/pilot.c +++ b/src/pilot.c @@ -252,12 +252,12 @@ static void pilot_update(Pilot* pilot, const double dt) { if(!pilot_isFlag(pilot, PILOT_HYPERSPACE) && VMOD(pilot->solid->vel) > pilot->ship->speed) // Should not go faster. - vect_pset(&pilot->solid->vel, VMOD(pilot->solid->vel) - 0.3*pilot->ship->thrust*dt, + vect_pset(&pilot->solid->vel, pilot->ship->speed, VANGLE(pilot->solid->vel)); // Update the source. - alSource3f(pilot->source, AL_POSITION, pilot->solid->pos.x, pilot->solid->pos.y, 0.); - alSource3f(pilot->source, AL_VELOCITY, pilot->solid->vel.x, pilot->solid->vel.y, 0.); + //alSource3f(pilot->source, AL_POSITION, pilot->solid->pos.x, pilot->solid->pos.y, 0.); + //alSource3f(pilot->source, AL_VELOCITY, pilot->solid->vel.x, pilot->solid->vel.y, 0.); } // Pilot is getting ready or is in, hyperspace. @@ -365,7 +365,7 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, Faction* faction, AI_Profi // Set flags and functions. if(flags & PILOT_PLAYER) { - alSourcef(pilot->source, AL_GAIN, 0.); + //alSourcef(pilot->source, AL_GAIN, 0.); pilot->think = player_think; // Players don't need to thing! :P pilot->render = NULL; // Render will be called from player_think pilot_setFlag(pilot, PILOT_PLAYER); // It's a player! diff --git a/src/player.c b/src/player.c index 01232f6..7977c98 100644 --- a/src/player.c +++ b/src/player.c @@ -174,7 +174,6 @@ void player_new(void) { d = RNG(0, 359)/180.*M_PI; pilot_create(ship, "Player", faction_get("Player"), NULL, d, &v, NULL, PILOT_PLAYER); - alSourcef(player->source, AL_GAIN, 0.5); gl_bindCamera(&player->solid->pos); // Set opengl camers. space_init(system); diff --git a/src/sound.c b/src/sound.c index 2d2e821..1b99d49 100644 --- a/src/sound.c +++ b/src/sound.c @@ -12,11 +12,17 @@ #define SOUND_PREFIX "snd/sounds/" #define SOUND_SUFFIX ".wav" +// Give the buffers a name. typedef struct { - char* name; - ALuint buffer; + char* name; // Buffers name. + ALuint buffer; // Associated OpenAL buffer. } alSound; +#define VOICE_PLAYING (1<<0) // Voice is playing. +#define VOICE_LOOPING (1<<1) // Voice is looping. +#define voice_set(v,f) ((v)->flags |= f) +#define voice_is(v,f) ((v)->flags & f) + // Gobal device and context. static ALCcontext* al_context = NULL; static ALCdevice* al_device = NULL; @@ -28,11 +34,18 @@ static SDL_Thread* music_player = NULL; static alSound* sound_list = NULL; static int nsound_list = 0; +// Current sources playing. +static alVoice** voice_stack = NULL; +static int nvoice_stack = 0; +static int mvoice_stack = 0; + static int sound_makeList(void); static int sound_load(ALuint* buffer, char* filename); static void sound_free(alSound* snd); int sound_init(void) { + const ALchar* device = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); + DEBUG("OpenAL using device '%s'", device); // Open the default device. al_device = alcOpenDevice(NULL); if(al_device == NULL) { @@ -47,6 +60,9 @@ int sound_init(void) { return -2; } + // Clear the errors. + alGetError(); + // Set active context. if(alcMakeContextCurrent(al_context)==AL_FALSE) { WARN("Failure to set default context"); @@ -166,17 +182,103 @@ static void sound_free(alSound* snd) { alDeleteBuffers(1, &snd->buffer); } -ALuint sound_dynSource(double px, double py, double vx, double vy, int looping) { - ALuint tmp; +// Update the sounds and prioritize them. +void sound_update(void) { + int i; + + // TODO: Prioritize the things. - alGenSources(1, &tmp); + for(i = 0; i < nvoice_stack; i++) { + if(voice_is(voice_stack[i], VOICE_PLAYING)) { + // Update position. + alSource3f(voice_stack[i]->source, AL_POSITION, + voice_stack[i]->px, voice_stack[i]->py, 0.); + alSource3f(voice_stack[i]->source, AL_VELOCITY, + voice_stack[i]->vx, voice_stack[i]->vy, 0.); - alSourcei(tmp, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(tmp, AL_POSITION, px, py, 0.); - alSource3f(tmp, AL_VELOCITY, vx, vy, 0.); - - if(looping) alSourcei(tmp, AL_LOOPING, AL_TRUE); - - return tmp; + } + } +} + +// Create a dynamic moving voice. +alVoice* sound_addVoice(int priority, double px, double py, double vx, double vy, + const ALuint buffer, const int looping) { + + alVoice* voc; + ALenum err; + + nvoice_stack++; + if(nvoice_stack > mvoice_stack) + voice_stack = realloc(voice_stack, ++mvoice_stack*sizeof(alVoice*)); + + voc = malloc(sizeof(alVoice)); + voice_stack[nvoice_stack-1] = voc; + + // Try and grab a source. + voc->source = 0; + alGenSources(1, &voc->source); + err = alGetError(); + if(err != AL_NO_ERROR) voc->source = 0; + + // Set the data. + voc->priority = priority; + voc->start = SDL_GetTicks(); + voc->buffer = buffer; + if(looping) voice_set(voc, VOICE_LOOPING); + voc->px = px; + voc->py = py; + voc->vx = vx; + voc->vy = vy; + + // Set the source. + if(voc->source) { + alSourcei(voc->source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcef(voc->source, AL_GAIN, 1.); + alSourcei(voc->source, AL_BUFFER, buffer); + alSource3f(voc->source, AL_POSITION, voc->px, voc->py, 0.); + alSource3f(voc->source, AL_VELOCITY, voc->vx, voc->vy, 0.); + if(voice_is(voc, VOICE_LOOPING)) + alSourcei(voc->source, AL_LOOPING, AL_TRUE); + + // Try to play the source. + alSourcePlay(voc->source); + err = alGetError(); + if(err == AL_NO_ERROR) voice_set(voc, VOICE_PLAYING); + else DEBUG("Source player failure"); + } + return voc; +} + +void sound_delVoice(alVoice* voice) { + ALint stat; + int i; + + for(i = 0; i < nvoice_stack; i++) + if(voice == voice_stack[i]) + break; + + // No match found. + if(i >= nvoice_stack) { + WARN("Unable to find voice to free from stack"); + return; + } + + if(voice->source) { + alGetSourcei(voice->source, AL_SOURCE_STATE, &stat); + if(stat == AL_PLAYING) alSourceStop(voice->source); + alDeleteSources(1, &voice->source); + voice->source = 0; + } + + nvoice_stack--; + for(; i < nvoice_stack; i++) + voice_stack[i] = voice_stack[i+1]; +} + +void voice_update(alVoice* voice, double px, double py, double vx, double vy) { + voice->px = px; + voice->py = py; + voice->vx = vx; + voice->vy = vy; } diff --git a/src/sound.h b/src/sound.h index f66cc08..b8e62b1 100644 --- a/src/sound.h +++ b/src/sound.h @@ -5,13 +5,32 @@ #define SOUND_REFERENCE_DIST 500. #define SOUND_MAX_DIST 1000. +// Virtual voice. +typedef struct { + ALuint source; // Source itself, 0 if not set. + ALuint buffer; // Buffer. + + int priority; // Base priority. + + double px, py; // Position. + double vx, vy; // Velocity. + + unsigned int start; // Time started in ms. + unsigned int flags; // Flags to set properties. +} alVoice; + // Sound subsystem. int sound_init(void); void sound_exit(void); +void sound_update(void); // Sound manupulation functions. ALuint sound_get(char* name); -// Source manipulation function. -ALuint sound_dynSource(double px, double py, double vx, double vy, int looping); +// Voice manipulation function. +alVoice* sound_addVoice(int priority, double px, double py, double vx, double vy, + const ALuint buffer, const int looping); + +void sound_delVoice(alVoice* voice); +void voice_update(alVoice* voice, double px, double py, double vx, double vy); diff --git a/src/weapon.c b/src/weapon.c index 23e096b..61956f5 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -14,6 +14,9 @@ #define weapon_isSmart(w) (w->think) +#define VOICE_PRIORITY_BOLD 10 // Default. +#define VOICE_PRIORITY_AMMP 8 // Higher. + // Some stuff from pilot. extern Pilot** pilot_stack; extern int pilots; @@ -29,7 +32,7 @@ typedef struct Weapon { const Outfit* outfit; // Related outfit that fired. unsigned int timer; // Mainly used to see when the weapon was fired. - ALuint source; // Source for sound. + //alVoice voice; // Virtual voise. // Update position and render. void(*update)(struct Weapon*, const double, WeaponLayer); // Position update and render. @@ -45,8 +48,6 @@ static Weapon** wfrontLayer = NULL; // Behind pilots. static int nwfrontLayer = 0; // Number of elements. static int mwfrontLayer = 0; // Allocated memory size. - -static void weapon_sound(Weapon* w); static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* pos, const Vec2* vel, const unsigned int parent, const unsigned int target); @@ -128,14 +129,6 @@ void weapons_update(const double dt) { weapons_updateLayer(dt, WEAPON_LAYER_FG); } -// Play the weapon sound. -static void weapon_sound(Weapon* w) { - w->source = sound_dynSource(w->solid->pos.x, w->solid->pos.y, - w->solid->vel.x, w->solid->vel.y, 0); - alSourcei(w->source, AL_BUFFER, w->outfit->sound); - alSourcePlay(w->source); -} - // Update all weapons in the layer. static void weapons_updateLayer(const double dt, const WeaponLayer layer) { Weapon** wlayer; @@ -235,8 +228,9 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) { (*w->solid->update)(w->solid, dt); // Update the sound. - alSource3f(w->source, AL_POSITION, w->solid->pos.x, w->solid->pos.y, 0.); - alSource3f(w->source, AL_VELOCITY, w->solid->vel.x, w->solid->vel.y, 0.); + /*if(w->voise) + voice_update(w->voice, w->solid->pos.x, w->solid->pos.y, + w->solid->vel.x, w->solid->vel.y);*/ } // Good shot. @@ -275,17 +269,14 @@ static Weapon* weapon_create(const Outfit* outfit, const double dir, const Vec2* vectcpy(&v, vel); vect_cadd(&v, outfit->speed*cos(rdir), outfit->speed*sin(rdir)); w->solid = solid_create(mass, rdir, pos, &v); - weapon_sound(w); break; case OUTFIT_TYPE_MISSILE_SEEK_AMMO: mass = w->outfit->mass; w->solid = solid_create(mass, dir, pos, vel); w->think = think_seeker; // Eeek!!! - weapon_sound(w); break; default: // Just dump it where the player is. - w->source = 0; w->solid = solid_create(mass, dir, pos, vel); break; } @@ -354,10 +345,6 @@ static void weapon_destroy(Weapon* w, WeaponLayer layer) { break; } for(i = 0; wlayer[i] != w; i++); // Get us to the current posision. - if(w->source) { - alSourceStop(wlayer[i]->source); - alDeleteSources(1, &wlayer[i]->source); - } weapon_free(wlayer[i]); wlayer[i] = NULL; (*nlayer)--;