AmbientSound::AmbientSound(const std::string &filename) : Sound(filename) { //ambient sound: always position at 0 distance to listener alSourcei(getSourceId(), AL_SOURCE_RELATIVE, true); alSource3f(getSourceId(), AL_POSITION, 0.0f, 0.0f, 0.0f); }
const i32 audio_vorbisStop(MemoryArena_ *arena, AudioManager *audioManager, AudioRenderer *audioRenderer) { i32 result = 0; u32 alSourceId = getSourceId(audioManager, audioRenderer); if (alIsSource(alSourceId) == AL_TRUE) { alSourceStop(alSourceId); AL_CHECK_ERROR(); result = rendererRelease(arena, audioManager, audioRenderer); audioRenderer->state = audiostate_stopped; } else { #ifdef DENGINE_DEBUG if (audioRenderer->audio) { DEBUG_LOG( "audio_streamStopVorbis(): Tried to stop invalid source, but " "renderer has valid audio ptr"); } #endif result = -1; } return result; }
SourceId ResourceManager::getSourceId(const Resource &resource) { if (resource.isValid()) { return getSourceId(resource.getLocation()); } return InvalidSourceId; }
bool Condition::onUpdate(Creature* creature, const Condition* addCondition) { if(getName() != addCondition->getName()){ //different condition return false; } if(getSourceId() != addCondition->getSourceId()){ //different source (SlotType) return false; } if(getTicks() > addCondition->getTicks()){ return false; } mechanicType = addCondition->mechanicType; combatType = addCondition->combatType; sourceId = addCondition->sourceId; ticks = addCondition->ticks; name = addCondition->name; flags = addCondition->flags; combatSource = addCondition->combatSource; bool fullUpdate = (effectList.size() != addCondition->effectList.size()); if(!fullUpdate){ std::list<ConditionEffect>::iterator curIt = effectList.begin(); for(std::list<ConditionEffect>::const_iterator it = addCondition->effectList.begin(); it != addCondition->effectList.end(); ++it){ if(!(*curIt).onUpdate(creature, *it)){ fullUpdate = true; break; } ++curIt; } } if(fullUpdate){ //Condition has been changed, maybe from a script reload, doing a full update for(std::list<ConditionEffect>::iterator it = effectList.begin(); it != effectList.end(); ++it){ (*it).onEnd(creature, CONDITIONEND_REMOVED); } effectList.clear(); for(std::list<ConditionEffect>::const_iterator it = addCondition->effectList.begin(); it != addCondition->effectList.end(); ++it){ addEffect(*it); } } return true; }
bool GoalApproach::met() { //get coords of source and target //TODO: for met and act, DO NOT DO IT LIKE THIS! Will break if target or source is now null! Get comp* first then try for vector2d if not null Vector2d sourceCo = getCore()->getCoordsSub()->getComponent(getSourceId())->getCoords(); Vector2d targetCo = getCore()->getCoordsSub()->getComponent(getTargetId())->getCoords(); if (sourceCo.getDistance(targetCo) <= minDistToTarget_) { return true; } return false; }
INTERNAL i32 rendererAcquire(MemoryArena_ *arena, AudioManager *audioManager, AudioRenderer *audioRenderer) { #ifdef DENGINE_DEBUG ASSERT(arena && audioManager && audioRenderer); #endif u32 checkSource = getSourceId(audioManager, audioRenderer); if (alIsSource(checkSource) == AL_TRUE) { #if 0 DEBUG_LOG( "rendererAcquire(): Renderer has not been released before " "acquiring, force release by stopping stream"); #endif audio_vorbisStop(arena, audioManager, audioRenderer); } // TODO(doyle): Super bad linear O(n) search for every audio-enabled entity i32 vacantSource = AUDIO_SOURCE_UNASSIGNED; for (i32 i = 0; i < ARRAY_COUNT(audioManager->sourceList); i++) { if (audioManager->sourceList[i].isFree) { vacantSource = i; audioManager->sourceList[i].isFree = FALSE; break; } } if (vacantSource == AUDIO_SOURCE_UNASSIGNED) { DEBUG_LOG("rendererAcquire(): Failed to acquire free source, all busy"); return -1; } audioRenderer->sourceIndex = vacantSource; /* Generate audio data buffers */ alGenBuffers(ARRAY_COUNT(audioRenderer->bufferId), audioRenderer->bufferId); AL_CHECK_ERROR(); //alSourcef(audioRenderer->sourceId[0], AL_PITCH, 2.0f); return 0; }
const i32 audio_vorbisPause(AudioManager *audioManager, AudioRenderer *audioRenderer) { i32 result = 0; u32 alSourceId = getSourceId(audioManager, audioRenderer); if (alIsSource(alSourceId) == AL_TRUE) { alSourcePause(alSourceId); AL_CHECK_ERROR(); audioRenderer->state = audiostate_paused; } else { DEBUG_LOG("audio_streamPauseVorbis(): Tried to pause invalid source"); result = -1; } return result; }
const i32 audio_vorbisResume(AudioManager *audioManager, AudioRenderer *audioRenderer) { i32 result = 0; u32 alSourceId = getSourceId(audioManager, audioRenderer); if (alIsSource(alSourceId) == AL_TRUE) { alSourcePlay(alSourceId); AL_CHECK_ERROR(); audioRenderer->state = audiostate_playing; } else { #ifdef DENGINE_DEBUG DEBUG_LOG("audio_vorbisResume(): Tried to resume invalid source") #endif result = -1; } return result; }
void GoalApproach::act() { //send message to move towards target //get coordinates Vector2d targetCo = getCore()->getCoordsSub()->getComponent(getTargetId())->getCoords(); //set movement Parameters moveParameters; moveParameters.push_back("move"); moveParameters.push_back("setLocalDest"); std::stringstream xSS(""), ySS(""); xSS << targetCo.x; ySS << targetCo.y; moveParameters.push_back(xSS.str()); moveParameters.push_back(ySS.str()); //send telegram Message message(getSourceId() , getTargetId(), moveParameters); Telegram telegram(getTargetId(), getTargetId(), 0.0, message); getCore()->getMessageCentre()->addTelegram(telegram); }
const i32 audio_updateAndPlay(MemoryArena_ *arena, AudioManager *audioManager, AudioRenderer *audioRenderer) { AudioVorbis *audio = audioRenderer->audio; if (!audio) return 0; u32 alSourceId = getSourceId(audioManager, audioRenderer); if (alIsSource(alSourceId) == AL_FALSE) { DEBUG_LOG("audio_updateAndPlay(): Update failed on invalid source id"); return -1; } ALint audioState; alGetSourcei(alSourceId, AL_SOURCE_STATE, &audioState); AL_CHECK_ERROR(); if (audioState == AL_STOPPED || audioState == AL_INITIAL) { if (audioState == AL_STOPPED) { if (audioRenderer->numPlays != AUDIO_REPEAT_INFINITE) audioRenderer->numPlays--; if (audioRenderer->numPlays == AUDIO_REPEAT_INFINITE || audioRenderer->numPlays > 0) { // TODO(doyle): Delete and recreate fixes clicking when reusing // buffers alDeleteBuffers(ARRAY_COUNT(audioRenderer->bufferId), audioRenderer->bufferId); AL_CHECK_ERROR(); alGenBuffers(ARRAY_COUNT(audioRenderer->bufferId), audioRenderer->bufferId); AL_CHECK_ERROR(); } else { i32 result = rendererRelease(arena, audioManager, audioRenderer); return result; } } if (audioRenderer->isStreaming) { stb_vorbis_seek_start(audio->file); for (i32 i = 0; i < ARRAY_COUNT(audioRenderer->bufferId); i++) { i16 audioChunk[AUDIO_CHUNK_SIZE_] = {0}; stb_vorbis_get_samples_short_interleaved( audio->file, audio->info.channels, audioChunk, AUDIO_CHUNK_SIZE_); alBufferData(audioRenderer->bufferId[i], audioRenderer->format, audioChunk, AUDIO_CHUNK_SIZE_ * sizeof(i16), audio->info.sample_rate); AL_CHECK_ERROR(); } alSourceQueueBuffers(alSourceId, ARRAY_COUNT(audioRenderer->bufferId), audioRenderer->bufferId); } else { alSourceQueueBuffers(alSourceId, 1, audioRenderer->bufferId); } AL_CHECK_ERROR(); alSourcePlay(alSourceId); AL_CHECK_ERROR(); } else if (audioState == AL_PLAYING) { ALint numProcessedBuffers; alGetSourcei(alSourceId, AL_BUFFERS_PROCESSED, &numProcessedBuffers); AL_CHECK_ERROR(); if (numProcessedBuffers > 0) { // TODO(doyle): Possibly wrong, we should pass in all processed buffers? ALint numBuffersToUnqueue = 1; ALuint emptyBufferId; alSourceUnqueueBuffers(alSourceId, numBuffersToUnqueue, &emptyBufferId); AL_CHECK_ERROR(); i16 audioChunk[AUDIO_CHUNK_SIZE_] = {0}; i32 sampleCount = stb_vorbis_get_samples_short_interleaved( audio->file, audio->info.channels, audioChunk, AUDIO_CHUNK_SIZE_); /* There are still samples to play */ if (sampleCount > 0) { alBufferData(emptyBufferId, audioRenderer->format, audioChunk, sampleCount * audio->info.channels * sizeof(i16), audio->info.sample_rate); AL_CHECK_ERROR(); alSourceQueueBuffers(alSourceId, 1, &emptyBufferId); AL_CHECK_ERROR(); } } } return 0; }
INTERNAL const i32 rendererRelease(MemoryArena_ *arena, AudioManager *audioManager, AudioRenderer *audioRenderer) { i32 result = 0; u32 alSourceId = getSourceId(audioManager, audioRenderer); if (alIsSource(alSourceId) == AL_FALSE) { DEBUG_LOG( "rendererRelease(): Trying to release invalid source, early exit"); result = -1; return result; } /* NOTE(doyle): Doing an alSourceRewind will result in the source going to the AL_INITIAL state, but the properties of the source (position, velocity, etc.) will not change. */ alSourceRewind(alSourceId); AL_CHECK_ERROR(); // TODO(doyle): We can possible remove this by just attaching the null buffer .. ALint numProcessedBuffers; alGetSourcei(alSourceId, AL_BUFFERS_PROCESSED, &numProcessedBuffers); if (numProcessedBuffers > 0) { alSourceUnqueueBuffers(alSourceId, numProcessedBuffers, audioRenderer->bufferId); } AL_CHECK_ERROR(); // NOTE(doyle): Any buffer queued up that has not been played cannot be // deleted without being played once. We can set the source buffers to NULL // (0) to free up the buffer, since we still hold the reference ids for the // buffer in our audio structure we can delete it afterwards .. alSourcei(alSourceId, AL_BUFFER, 0); alDeleteBuffers(ARRAY_COUNT(audioRenderer->bufferId), audioRenderer->bufferId); AL_CHECK_ERROR(); for (i32 i = 0; i < ARRAY_COUNT(audioRenderer->bufferId); i++) { audioRenderer->bufferId[i] = 0; } if (audioRenderer->isStreaming) { stb_vorbis_close(audioRenderer->audio->file); // TODO(doyle): Mem free // PLATFORM_MEM_FREE(arena, audioRenderer->audio, sizeof(AudioVorbis)); } u32 sourceIndexToFree = audioRenderer->sourceIndex; audioRenderer->sourceIndex = AUDIO_SOURCE_UNASSIGNED; audioRenderer->audio = NULL; audioRenderer->numPlays = 0; audioRenderer->isStreaming = FALSE; audioRenderer->state = audiostate_stopped; audioManager->sourceList[sourceIndexToFree].isFree = TRUE; return result; }
ManagedVector<Node> ResourceManager::parse( ParserContext &ctx, const std::string &path, const std::string &mimetype, const std::string &rel, const RttiSet &supportedTypes, ParseMode mode) { // Some references used for convenience Registry ®istry = ctx.getRegistry(); Logger &logger = ctx.getLogger(); ParserScope &scope = ctx.getScope(); Resource relativeTo = getResource(ctx.getSourceId()); // Locate the resource relative to the old resource, abort if this did not // work ResourceRequest req{path, mimetype, rel, supportedTypes, relativeTo}; Resource resource; if (!req.deduce(registry, logger) || !req.locate(registry, logger, resource)) { return ManagedVector<Node>{}; } // initialize the output vector. ManagedVector<Node> parsedNodes; // Allocate a new SourceId handle for this Resource bool newResource = false; SourceId sourceId = getSourceId(resource); if (sourceId == InvalidSourceId) { newResource = true; sourceId = allocateSourceId(resource); } // check for cycles. GuardedSetInsertion<SourceId> cycleDetection{currentlyParsing, sourceId}; if (!cycleDetection.isSuccess()) { throw LoggableException{std::string("Detected cyclic parse of ") + resource.getLocation()}; } if (!newResource && mode == ParseMode::IMPORT) { // if a already imported resource should be imported we just use the // cached node. parsedNodes.push_back(getNode(ctx.getManager(), sourceId)); } else { // We can now try to parse the given file // Set the current source id in the logger instance. Note that this // modifies the logger instance -- the GuardedLogger is just used to // make sure the default location is popped from the stack again. GuardedLogger guardedLogger(logger, SourceLocation{sourceId}); try { // Fetch the input stream and create a char reader std::unique_ptr<std::istream> is = resource.stream(); CharReader reader(*is, sourceId); // Actually parse the input stream, distinguish the IMPORT and the // INCLUDE mode switch (mode) { case ParseMode::IMPORT: { // Create a new, empty parser scope instance and a new // parser // context with this instance in place ParserScope innerScope; ParserContext childCtx = ctx.clone(innerScope, sourceId); // Run the parser req.getParser()->parse(reader, childCtx); // Make sure the scope has been unwound and perform all // deferred resolutions innerScope.checkUnwound(logger); innerScope.performDeferredResolution(logger); // Fetch the nodes that were parsed by this parser instance // and // validate them parsedNodes = innerScope.getTopLevelNodes(); for (auto parsedNode : parsedNodes) { parsedNode->validate(logger); } // Make sure the number of elements is exactly one -- we can // only store one element per top-level node. if (parsedNodes.empty()) { throw LoggableException{"Module is empty."}; } if (parsedNodes.size() > 1) { throw LoggableException{ std::string( "Expected exactly one top-level node but " "got ") + std::to_string(parsedNodes.size())}; } // Store the parsed node along with the sourceId storeNode(sourceId, parsedNodes[0]); break; } case ParseMode::INCLUDE: { // Fork the scope instance and create a new parser context // with this instance in place ParserScope forkedScope = scope.fork(); ParserContext childCtx = ctx.clone(forkedScope, sourceId); // Run the parser req.getParser()->parse(reader, childCtx); // Join the forked scope with the outer scope scope.join(forkedScope, logger); // Fetch the nodes that were parsed by this parser instance parsedNodes = forkedScope.getTopLevelNodes(); break; } } } catch (LoggableException ex) { // Log the exception and return nullptr logger.log(ex); return ManagedVector<Node>{}; } } // Make sure the parsed nodes fulfill the "supportedTypes" constraint, // remove nodes that do not the result for (auto it = parsedNodes.begin(); it != parsedNodes.end();) { const Rtti *type = (*it)->type(); if (!type->isOneOf(supportedTypes)) { logger.error(std::string("Node of internal type ") + type->name + std::string(" not supported here"), **it); it = parsedNodes.erase(it); } else { it++; } } return parsedNodes; }
Rooted<Node> ResourceManager::getNode(Manager &mgr, const Resource &resource) { return getNode(mgr, getSourceId(resource)); }
Rooted<Node> ResourceManager::getNode(Manager &mgr, const std::string &location) { return getNode(mgr, getSourceId(location)); }