This commit is contained in:
Tamir Atias 2013-03-04 21:19:51 +02:00
commit b074bce927
14 changed files with 340 additions and 83 deletions

View File

@ -8,6 +8,7 @@
</general> </general>
<specific type="1"> <specific type="1">
<gfx>lasergreen</gfx> <gfx>lasergreen</gfx>
<sound>laser</sound>
<delay>500</delay> <delay>500</delay>
<speed>550</speed> <speed>550</speed>
<range>300</range> <range>300</range>

View File

@ -111,7 +111,7 @@ int main(int argc, char** argv) {
// OpenAL sound. // OpenAL sound.
if(sound_init()) WARN("Problem setting up sound!"); if(sound_init()) WARN("Problem setting up sound!");
music_load("Machina"); music_load("Machina");
music_play(); //music_play();
// Input. // Input.
if((indjoystick >= 0) || (namjoystick != NULL)) { if((indjoystick >= 0) || (namjoystick != NULL)) {
@ -177,6 +177,8 @@ int main(int argc, char** argv) {
input_handle(&event); // handles all the events the player keybinds. input_handle(&event); // handles all the events the player keybinds.
} }
sound_update(); // Do the sound stuff.
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
fps_control(); // Who doesn't love FPS control? fps_control(); // Who doesn't love FPS control?

View File

@ -153,6 +153,8 @@ void music_exit(void) {
for(i = 0; i < nmusic_selection; i++) for(i = 0; i < nmusic_selection; i++)
free(music_selection[i]); free(music_selection[i]);
free(music_selection); free(music_selection);
SDL_DestroyMutex(music_vorbis_lock);
} }
// Internal music loading ruitines. // Internal music loading ruitines.
@ -220,6 +222,10 @@ static void music_free(void) {
SDL_mutexV(music_vorbis_lock); SDL_mutexV(music_vorbis_lock);
} }
void music_volume(const double vol) {
alSourcef(music_source, AL_GAIN, (ALfloat)vol);
}
// Music control functions. // Music control functions.
void music_load(const char* name) { void music_load(const char* name) {
int i; int i;

View File

@ -9,6 +9,7 @@ int music_init(void);
void music_exit(void); void music_exit(void);
// Music control. // Music control.
void music_volume(const double vol);
void music_load(const char* name); void music_load(const char* name);
void music_play(void); void music_play(void);
void music_stop(void); void music_stop(void);

View File

@ -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)); 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); 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")) { else if(xml_isNode(node, "damage")) {
cur = node->children; cur = node->children;
do { 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) #define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name)
if(tmp->gfx_space == NULL) if(tmp->gfx_space == NULL)
WARN("Outfit '%s' missing 'gfx' element", tmp->name); WARN("Outfit '%s' missing 'gfx' element", tmp->name);
MELEMENT(tmp->sound, "sound");
MELEMENT(tmp->delay, "delay"); MELEMENT(tmp->delay, "delay");
MELEMENT(tmp->speed, "speed"); MELEMENT(tmp->speed, "speed");
MELEMENT(tmp->range, "range"); MELEMENT(tmp->range, "range");
@ -159,6 +162,8 @@ static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) {
OUTFIT_GFX"%s.png", xml_get(node)); OUTFIT_GFX"%s.png", xml_get(node));
tmp->gfx_space = gl_newSprite(str, 6, 6); 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")) { else if(xml_isNode(node, "damage")) {
cur = node->children; cur = node->children;
do { do {
@ -170,7 +175,8 @@ static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) {
#define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name) #define MELEMENT(o,s) if((o) == 0) WARN("Outfit '%s' missing '"s"' element", tmp->name)
if(tmp->gfx_space == NULL) if(tmp->gfx_space == NULL)
WARN("Outfit '%s' missing 'gfx' element", tmp->name); WARN("Outfit '%s' missing 'gfx' element", tmp->name);
MELEMENT(tmp->thrust, " thrust"); MELEMENT(tmp->sound, "sound");
MELEMENT(tmp->thrust, "thrust");
MELEMENT(tmp->turn, "turn"); MELEMENT(tmp->turn, "turn");
MELEMENT(tmp->speed, "speed"); MELEMENT(tmp->speed, "speed");
MELEMENT(tmp->range, "duration"); MELEMENT(tmp->range, "duration");

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "opengl.h" #include "opengl.h"
#include "sound.h"
#define outfit_isProp(o,p) ((o)->properties & p) #define outfit_isProp(o,p) ((o)->properties & p)
// Property flags. // Property flags.
@ -46,6 +47,7 @@ typedef struct {
double damage_armour, damage_shield; // Damage. double damage_armour, damage_shield; // Damage.
glTexture* gfx_space; glTexture* gfx_space;
ALuint sound; // Sound to play.
}; };
struct { // Launcher. struct { // Launcher.
//unsigned int delay; // Delay between shots. //unsigned int delay; // Delay between shots.

View File

@ -252,8 +252,12 @@ static void pilot_update(Pilot* pilot, const double dt) {
if(!pilot_isFlag(pilot, PILOT_HYPERSPACE) && VMOD(pilot->solid->vel) > if(!pilot_isFlag(pilot, PILOT_HYPERSPACE) && VMOD(pilot->solid->vel) >
pilot->ship->speed) pilot->ship->speed)
// Should not go faster. // 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)); 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.);
} }
// Pilot is getting ready or is in, hyperspace. // Pilot is getting ready or is in, hyperspace.
@ -356,7 +360,12 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, Faction* faction, AI_Profi
} }
} }
// Sound source.
// Eh....
// Set flags and functions.
if(flags & PILOT_PLAYER) { if(flags & PILOT_PLAYER) {
//alSourcef(pilot->source, AL_GAIN, 0.);
pilot->think = player_think; // Players don't need to thing! :P pilot->think = player_think; // Players don't need to thing! :P
pilot->render = NULL; // Render will be called from player_think pilot->render = NULL; // Render will be called from player_think
pilot_setFlag(pilot, PILOT_PLAYER); // It's a player! pilot_setFlag(pilot, PILOT_PLAYER); // It's a player!

View File

@ -4,6 +4,7 @@
#include "ai.h" #include "ai.h"
#include "outfit.h" #include "outfit.h"
#include "faction.h" #include "faction.h"
#include "sound.h"
#include "ship.h" #include "ship.h"
#define PLAYER_ID 1 #define PLAYER_ID 1
@ -66,6 +67,10 @@ typedef struct Pilot {
PilotOutfit* secondary; // Secondary weapon. PilotOutfit* secondary; // Secondary weapon.
PilotOutfit* ammo; // Secondary ammo (if needed). PilotOutfit* ammo; // Secondary ammo (if needed).
// Sound source.
ALuint source;
// Misc.
unsigned int flags; // Used for AI etc. unsigned int flags; // Used for AI etc.
unsigned int ptimer; // Generic timer for internal pilot use. unsigned int ptimer; // Generic timer for internal pilot use.

View File

@ -174,7 +174,7 @@ void player_new(void) {
d = RNG(0, 359)/180.*M_PI; d = RNG(0, 359)/180.*M_PI;
pilot_create(ship, "Player", faction_get("Player"), NULL, d, &v, NULL, PILOT_PLAYER); pilot_create(ship, "Player", faction_get("Player"), NULL, d, &v, NULL, PILOT_PLAYER);
gl_bindCamera(&player->solid->pos); gl_bindCamera(&player->solid->pos); // Set opengl camers.
space_init(system); space_init(system);
// Welcome message. // Welcome message.
@ -796,6 +796,14 @@ void player_think(Pilot* player) {
pilot_shoot(player, player_target, 1); pilot_shoot(player, player_target, 1);
vect_pset(&player->solid->force, player->ship->thrust * player_acc, player->solid->dir); vect_pset(&player->solid->force, player->ship->thrust * player_acc, player->solid->dir);
// Set the listener stuff.
ALfloat ori[] = { 0., 0., 0., 0., 0., 1. };
ori[0] = cos(player->solid->dir);
ori[1] = sin(player->solid->dir);
alListenerfv(AL_ORIENTATION, ori);
alListener3f(AL_POSITION, player->solid->pos.x, player->solid->pos.y, 0.);
alListener3f(AL_VELOCITY, player->solid->vel.x, player->solid->vel.y, 0.);
} }
// Modify the radar resolution. // Modify the radar resolution.

View File

@ -38,81 +38,83 @@ static Ship* ship_parse(xmlNodePtr parent) {
ShipOutfit* otmp, *ocur; ShipOutfit* otmp, *ocur;
char str[PATH_MAX] = "\0"; char str[PATH_MAX] = "\0";
xmlChar* xstr; char* stmp;
tmp->name = (char*)xmlGetProp(parent, (xmlChar*)"name"); tmp->name = xml_nodeProp(parent, "name");
if(tmp->name == NULL) WARN("Ship in "SHIP_DATA" has invalid or no name"); if(tmp->name == NULL) WARN("Ship in "SHIP_DATA" has invalid or no name");
node = parent->xmlChildrenNode; node = parent->xmlChildrenNode;
do { do {
// Load all the data. // Load all the data.
if(strcmp((char*)node->name, "GFX")==0) { if(xml_isNode(node,"GFX")) {
snprintf(str, strlen((char*)node->children->content)+sizeof(SHIP_GFX)+sizeof(SHIP_EXT), snprintf(str, strlen(xml_get(node)) + sizeof(SHIP_GFX) + sizeof(SHIP_EXT),
SHIP_GFX"%s"SHIP_EXT, (char*)node->children->content); SHIP_GFX"%s"SHIP_EXT, xml_get(node));
tmp->gfx_space = gl_newSprite(str, 6, 6); tmp->gfx_space = gl_newSprite(str, 6, 6);
// Target. // Target.
snprintf(str, strlen((char*)node->children->content)+sizeof(SHIP_GFX)+sizeof(SHIP_TARGET)+sizeof(SHIP_EXT), snprintf(str, strlen(xml_get(node)) + sizeof(SHIP_GFX)+sizeof(SHIP_TARGET)+sizeof(SHIP_EXT),
SHIP_GFX"%s"SHIP_TARGET SHIP_EXT, (char*)node->children->content); SHIP_GFX"%s"SHIP_TARGET SHIP_EXT, xml_get(node));
tmp->gfx_target = gl_newImage(str); tmp->gfx_target = gl_newImage(str);
} }
else if(strcmp((char*)node->name, "GUI")==0) else if(xml_isNode(node, "GUI"))
tmp->gui = strdup((char*)node->children->content); tmp->gui = strdup(xml_get(node));
else if(strcmp((char*)node->name, "class")==0) else if(xml_isNode(node, "sound"))
tmp->class = atoi((char*)node->children->content); tmp->sound = sound_get(xml_get(node));
else if(strcmp((char*)node->name, "movement")==0) { else if(xml_isNode(node, "class"))
tmp->class = atoi(xml_get(node));
else if(xml_isNode(node, "movement")) {
cur = node->children; cur = node->children;
do { do {
if(strcmp((char*)cur->name, "thrust")==0) if(xml_isNode(cur, "thrust"))
tmp->thrust = atoi((char*)cur->children->content); tmp->thrust = xml_getInt(cur);
else if(strcmp((char*)cur->name, "turn")==0) else if(xml_isNode(cur, "turn"))
tmp->turn = atoi((char*)cur->children->content); tmp->turn = xml_getInt(cur);
else if(strcmp((char*)cur->name, "speed")==0) else if(xml_isNode(cur, "speed"))
tmp->speed = atoi((char*)cur->children->content); tmp->speed = xml_getInt(cur);
} while((cur = cur->next)); } while((cur = cur->next));
} }
else if(strcmp((char*)node->name, "health")==0) { else if(xml_isNode(node, "health")) {
cur = node->children; cur = node->children;
do { do {
if(strcmp((char*)cur->name, "armour")==0) if(xml_isNode(cur, "armour"))
tmp->armour = (double)atoi((char*)cur->children->content); tmp->armour = (double)xml_getInt(cur);
else if(strcmp((char*)cur->name, "shield")==0) else if(xml_isNode(cur, "shield"))
tmp->shield = (double)atoi((char*)cur->children->content); tmp->shield = (double)xml_getInt(cur);
else if(strcmp((char*)cur->name, "energy")==0) else if(xml_isNode(cur, "energy"))
tmp->energy = (double)atoi((char*)cur->children->content); tmp->energy = (double)xml_getInt(cur);
else if(strcmp((char*)cur->name, "armour_regen")==0) else if(xml_isNode(cur, "armour_regen"))
tmp->armour_regen = (double)(atoi((char*)cur->children->content))/60.0; tmp->armour_regen = (double)(xml_getInt(cur))/60.0;
else if(strcmp((char*)cur->name, "shield_regen")==0) else if(xml_isNode(cur, "shield_regen"))
tmp->shield_regen = (double)(atoi((char*)cur->children->content))/60.0; tmp->shield_regen = (double)(xml_getInt(cur))/60.0;
else if(strcmp((char*)cur->name, "energy_regen")==0) else if(xml_isNode(cur, "energy_regen"))
tmp->energy_regen = (double)(atoi((char*)cur->children->content))/60.0; tmp->energy_regen = (double)(xml_getInt(cur))/60.0;
} while((cur = cur->next)); } while((cur = cur->next));
} }
else if(strcmp((char*)node->name, "characteristics")==0) { else if(xml_isNode(node, "characteristics")) {
cur = node->children; cur = node->children;
do { do {
if(strcmp((char*)cur->name, "crew")==0) if(xml_isNode(cur, "crew"))
tmp->crew = atoi((char*)cur->children->content); tmp->crew = xml_getInt(cur);
else if(strcmp((char*)cur->name, "mass")==0) else if(xml_isNode(cur, "mass"))
tmp->mass = (double)atoi((char*)cur->children->content); tmp->mass = (double)xml_getInt(cur);
else if(strcmp((char*)cur->name, "cap_weapon")==0) else if(xml_isNode(cur, "cap_weapon"))
tmp->cap_weapon = atoi((char*)cur->children->content); tmp->cap_weapon = xml_getInt(cur);
else if(strcmp((char*)cur->name, "cap_cargo")==0) else if(xml_isNode(cur, "cap_cargo"))
tmp->cap_cargo = atoi((char*)cur->children->content); tmp->cap_cargo = xml_getInt(cur);
} while((cur = cur->next)); } while((cur = cur->next));
} }
else if(strcmp((char*)node->name, "outfits")==0) { else if(xml_isNode(node, "outfits")) {
cur = node->children; cur = node->children;
do { do {
if(strcmp((char*)cur->name, "outfit")==0) { if(xml_isNode(cur, "outfit")) {
otmp = MALLOC_L(ShipOutfit); otmp = MALLOC_L(ShipOutfit);
otmp->data = outfit_get((char*)cur->children->content); otmp->data = outfit_get(xml_get(cur));
xstr = xmlGetProp(cur, (xmlChar*)"quantity"); stmp = xml_nodeProp(cur, "quantity");
if(!xstr) if(!stmp)
WARN("Ship '%s' is missing tag 'quantity for outfit '%s'", tmp->name, otmp->data->name); WARN("Ship '%s' is missing tag 'quantity for outfit '%s'", tmp->name, otmp->data->name);
otmp->quantity = atoi((char*)xstr); otmp->quantity = atoi(stmp);
free(xstr); free(stmp);
otmp->next = NULL; otmp->next = NULL;
if((ocur = tmp->outfit) == NULL) tmp->outfit = otmp; if((ocur = tmp->outfit) == NULL) tmp->outfit = otmp;
@ -130,17 +132,18 @@ static Ship* ship_parse(xmlNodePtr parent) {
#define MELEMENT(o,s) if(o == 0) WARN("Ship '%s' missing '"s"' element", tmp->name) #define MELEMENT(o,s) if(o == 0) WARN("Ship '%s' missing '"s"' element", tmp->name)
if(tmp->name == NULL) WARN("Ship '%s' missing 'name' tag", tmp->name); if(tmp->name == NULL) WARN("Ship '%s' missing 'name' tag", tmp->name);
if(tmp->gfx_space == NULL) WARN("Ship '%s' missing 'GFX' element", tmp->name); if(tmp->gfx_space == NULL) WARN("Ship '%s' missing 'GFX' element", tmp->name);
if(tmp->gui == NULL) WARN("Ship '%s' missing 'GUI' element", tmp->name);
MELEMENT(tmp->thrust, "thrust"); MELEMENT(tmp->thrust, "thrust");
MELEMENT(tmp->turn, "turn"); MELEMENT(tmp->turn, "turn");
MELEMENT(tmp->speed, "speed"); MELEMENT(tmp->speed, "speed");
MELEMENT(tmp->crew, "crew");
MELEMENT(tmp->mass, "mass");
MELEMENT(tmp->armour, "armour"); MELEMENT(tmp->armour, "armour");
MELEMENT(tmp->armour_regen, "armour_regen"); MELEMENT(tmp->armour_regen, "armour_regen");
MELEMENT(tmp->shield, "shield"); MELEMENT(tmp->shield, "shield");
MELEMENT(tmp->shield_regen, "shield_regen"); MELEMENT(tmp->shield_regen, "shield_regen");
MELEMENT(tmp->energy, "energy"); MELEMENT(tmp->energy, "energy");
MELEMENT(tmp->energy_regen, "energt_regen"); MELEMENT(tmp->energy_regen, "energt_regen");
MELEMENT(tmp->crew, "crew");
MELEMENT(tmp->mass, "mass");
MELEMENT(tmp->cap_cargo, "cap_cargo"); MELEMENT(tmp->cap_cargo, "cap_cargo");
MELEMENT(tmp->cap_weapon, "cap_weapon"); MELEMENT(tmp->cap_weapon, "cap_weapon");
#undef MELEMENT #undef MELEMENT

View File

@ -37,6 +37,9 @@ typedef struct {
// GUI interface. // GUI interface.
char* gui; char* gui;
// Sound.
ALuint sound;
// Characteristics. // Characteristics.
int crew; int crew;
int mass; int mass;

View File

@ -9,21 +9,43 @@
#include "music.h" #include "music.h"
#include "sound.h" #include "sound.h"
// This isn't always set? #define SOUND_PREFIX "snd/sounds/"
#ifndef AL_FORMAT_VORBIS_EXT #define SOUND_SUFFIX ".wav"
#define AL_FORMAT_VORBIS_EXT 0x10003
#endif
// Give the buffers a name.
typedef struct { typedef struct {
ALfloat x, y; char* name; // Buffers name.
} alVector; 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 ALCcontext* al_context = NULL;
static ALCdevice* al_device = NULL; static ALCdevice* al_device = NULL;
// Music player thread to assure streaming is perfect.
static SDL_Thread* music_player = NULL; static SDL_Thread* music_player = NULL;
// List of sounds available (All preloaded into a buffer).
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) { int sound_init(void) {
const ALchar* device = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
DEBUG("OpenAL using device '%s'", device);
// Open the default device. // Open the default device.
al_device = alcOpenDevice(NULL); al_device = alcOpenDevice(NULL);
if(al_device == NULL) { if(al_device == NULL) {
@ -38,11 +60,8 @@ int sound_init(void) {
return -2; return -2;
} }
// We use the vorbis extension for AL to load it easily. // Clear the errors.
if(alIsExtensionPresent("AL_EXT_vorbis") == AL_FALSE) { alGetError();
WARN("AL_EXT_vorbis not available in OpenAL context!");
return -3;
}
// Set active context. // Set active context.
if(alcMakeContextCurrent(al_context)==AL_FALSE) { if(alcMakeContextCurrent(al_context)==AL_FALSE) {
@ -50,6 +69,10 @@ int sound_init(void) {
return -4; return -4;
} }
// Load up all the sounds.
sound_makeList();
// Start the music server.
music_init(); music_init();
music_player = SDL_CreateThread(music_thread, NULL); music_player = SDL_CreateThread(music_thread, NULL);
@ -59,6 +82,16 @@ int sound_init(void) {
// Clean up after the sound system. // Clean up after the sound system.
void sound_exit(void) { void sound_exit(void) {
int i;
// Free the sounds.
for(i = 0; i < &nsound_list; i++)
sound_free(&sound_list[i]);
free(sound_list);
sound_list = NULL;
nsound_list = 0;
// Must stop the music before killing it,
// then thread should commit suicide.
music_stop(); music_stop();
music_kill(); music_kill();
SDL_WaitThread(music_player, NULL); SDL_WaitThread(music_player, NULL);
@ -71,19 +104,67 @@ void sound_exit(void) {
if(al_device) alcCloseDevice(al_device); if(al_device) alcCloseDevice(al_device);
} }
// Loads a vorbis file. // Get the buffer to sound of [name].
ALuint sound_sndCreate(char* filename) { ALuint sound_get(char* name) {
void* ovdata; int i;
for(i = 0; i < nsound_list; i++)
if(strcmp(name, sound_list[i].name)==0)
return sound_list[i].buffer;
WARN("Sound '%s' not found in sound list", name);
return 0;
}
// Make list of available sounds.
static int sound_makeList(void) {
char** files;
uint32_t nfiles, i;
char tmp[64];
int len;
// Get the file list.
files = pack_listfiles(data, &nfiles);
// Load the profiles.
for(i = 0; i < nfiles; i++)
if((strncmp(files[i], SOUND_PREFIX, strlen(SOUND_PREFIX))==0) &&
(strncmp(files[i] + strlen(files[i]) - strlen(SOUND_SUFFIX),
SOUND_SUFFIX, strlen(SOUND_SUFFIX))==0)) {
// Expand the selection size.
sound_list = realloc(sound_list, ++nsound_list * sizeof(alSound));
// Remove the prefix and suffix.
len = strlen(files[i]) - strlen(SOUND_SUFFIX SOUND_SUFFIX);
strncpy(tmp, files[i] + strlen(SOUND_PREFIX), len);
tmp[len] = '\0';
// give it the new name.
sound_list[nsound_list-1].name = strdup(tmp);
sound_load(&sound_list[nsound_list-1].buffer, files[i]);
}
// Free the char* allocated by pack.
for(i = 0; i < nfiles; i++)
free(files[i]);
free(files);
DEBUG("Loaded %d sound%c", nsound_list, (nsound_list==1)?' ':'s');
return 0;
}
// Loads a sound into the sound_list.
static int sound_load(ALuint* buffer, char* filename) {
void* wavdata;
unsigned int size; unsigned int size;
ALenum err; ALenum err;
ALuint buf;
// Get the file data buffer from the packfile. // Get the file data buffer from the packfile.
ovdata = pack_readfile(DATA, filename, &size); wavdata = pack_readfile(DATA, filename, &size);
// Bind to OpenAL buffer. // Bind to OpenAL buffer.
alGenBuffers(1, &buf); alGenBuffers(1, buffer);
alBufferData(buf, AL_FORMAT_VORBIS_EXT, ovdata, size, 44800); alBufferData(*buffer, AL_FORMAT_MONO16, wavdata, size, 22050);
// Errors? // Errors?
if((err = alGetError()) != AL_NO_ERROR) { if((err = alGetError()) != AL_NO_ERROR) {
@ -92,11 +173,112 @@ ALuint sound_sndCreate(char* filename) {
} }
// Finish up. // Finish up.
free(ovdata); free(wavdata);
return buf; return 0;
} }
void sound_sndFree(const ALuint snd) { static void sound_free(alSound* snd) {
alDeleteBuffers(1, &snd); if(snd->name) free(snd->name);
alDeleteBuffers(1, &snd->buffer);
}
// Update the sounds and prioritize them.
void sound_update(void) {
int i;
// TODO: Prioritize the things.
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.);
}
}
}
// 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;
} }

View File

@ -2,15 +2,35 @@
#include <AL/al.h> #include <AL/al.h>
#include "physics.h" #include "physics.h"
#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. // Sound subsystem.
int sound_init(void); int sound_init(void);
void sound_exit(void); void sound_exit(void);
void sound_update(void);
// Sound manupulation functions. // Sound manupulation functions.
ALuint sound_sndCreate(char* filename); ALuint sound_get(char* name);
void sound_sndFree(const ALuint snd);
// Source manipulation function. // Voice manipulation function.
#define sound_initSource(s) (alGenSources(1, &(s))) alVoice* sound_addVoice(int priority, double px, double py, double vx, double vy,
#define sound_delSource(s) (alDeleteSources(1, &(s)) const ALuint buffer, const int looping);
void sound_delVoice(alVoice* voice);
void voice_update(alVoice* voice, double px, double py, double vx, double vy);

View File

@ -14,6 +14,9 @@
#define weapon_isSmart(w) (w->think) #define weapon_isSmart(w) (w->think)
#define VOICE_PRIORITY_BOLD 10 // Default.
#define VOICE_PRIORITY_AMMP 8 // Higher.
// Some stuff from pilot. // Some stuff from pilot.
extern Pilot** pilot_stack; extern Pilot** pilot_stack;
extern int pilots; extern int pilots;
@ -29,6 +32,8 @@ typedef struct Weapon {
const Outfit* outfit; // Related outfit that fired. const Outfit* outfit; // Related outfit that fired.
unsigned int timer; // Mainly used to see when the weapon was fired. unsigned int timer; // Mainly used to see when the weapon was fired.
//alVoice voice; // Virtual voise.
// Update position and render. // Update position and render.
void(*update)(struct Weapon*, const double, WeaponLayer); // Position update and render. void(*update)(struct Weapon*, const double, WeaponLayer); // Position update and render.
void(*think)(struct Weapon*); // Some missiles need to be inteligent. void(*think)(struct Weapon*); // Some missiles need to be inteligent.
@ -43,7 +48,6 @@ static Weapon** wfrontLayer = NULL; // Behind pilots.
static int nwfrontLayer = 0; // Number of elements. static int nwfrontLayer = 0; // Number of elements.
static int mwfrontLayer = 0; // Allocated memory size. static int mwfrontLayer = 0; // Allocated memory size.
static Weapon* weapon_create(const Outfit* outfit, const double dir, static Weapon* weapon_create(const Outfit* outfit, const double dir,
const Vec2* pos, const Vec2* vel, const unsigned int parent, const Vec2* pos, const Vec2* vel, const unsigned int parent,
const unsigned int target); const unsigned int target);
@ -222,6 +226,11 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
} }
if(weapon_isSmart(w)) (*w->think)(w); if(weapon_isSmart(w)) (*w->think)(w);
(*w->solid->update)(w->solid, dt); (*w->solid->update)(w->solid, dt);
// Update the sound.
/*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. // Good shot.