Switched scene update to state event
This commit is contained in:
@ -36,8 +36,8 @@ void Scene::update() {
|
|||||||
// TODO: Cleanup old scene items
|
// TODO: Cleanup old scene items
|
||||||
|
|
||||||
// TODO: Tick scene items(?)
|
// TODO: Tick scene items(?)
|
||||||
this->eventSceneUpdate.invoke();
|
this->eventSceneUpdate.invoke(game->timeManager.delta);
|
||||||
if(!this->game->timeManager.isPaused) this->eventSceneUnpausedUpdate.invoke();
|
if(!this->game->timeManager.isPaused) this->eventSceneUnpausedUpdate.invoke(game->timeManager.delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneItem * Scene::createSceneItem() {
|
SceneItem * Scene::createSceneItem() {
|
||||||
|
@ -21,7 +21,7 @@ namespace Dawn {
|
|||||||
template<class T>
|
template<class T>
|
||||||
T * _sceneForwardGetComponent(SceneItem *item);
|
T * _sceneForwardGetComponent(SceneItem *item);
|
||||||
|
|
||||||
class Scene : public StateOwner {
|
class Scene {
|
||||||
private:
|
private:
|
||||||
sceneitemid_t nextId;
|
sceneitemid_t nextId;
|
||||||
std::map<sceneitemid_t, SceneItem*> items;
|
std::map<sceneitemid_t, SceneItem*> items;
|
||||||
@ -30,8 +30,8 @@ namespace Dawn {
|
|||||||
public:
|
public:
|
||||||
DawnGame *game;
|
DawnGame *game;
|
||||||
ScenePhysicsManager *physics;
|
ScenePhysicsManager *physics;
|
||||||
Event<> eventSceneUpdate;
|
StateEvent<float_t> eventSceneUpdate;
|
||||||
Event<> eventSceneUnpausedUpdate;
|
StateEvent<float_t> eventSceneUnpausedUpdate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new Scene instance.
|
* Construct a new Scene instance.
|
||||||
|
@ -22,10 +22,10 @@ void AnimationController::addAnimation(Animation *animation) {
|
|||||||
void AnimationController::onStart() {
|
void AnimationController::onStart() {
|
||||||
SceneItemComponent::onStart();
|
SceneItemComponent::onStart();
|
||||||
|
|
||||||
useEventLegacy([&]{
|
useEvent([&](float_t delta){
|
||||||
auto it = this->animations.begin();
|
auto it = this->animations.begin();
|
||||||
while(it != this->animations.end()) {
|
while(it != this->animations.end()) {
|
||||||
(*it)->tick(this->getGame()->timeManager.delta);
|
(*it)->tick(delta);
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}, getScene()->eventSceneUnpausedUpdate);
|
}, getScene()->eventSceneUnpausedUpdate);
|
||||||
|
@ -28,11 +28,11 @@ ExampleSpin::ExampleSpin(SceneItem *item) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ExampleSpin::onStart() {
|
void ExampleSpin::onStart() {
|
||||||
useEventLegacy([&]{
|
useEvent([&](float_t delta){
|
||||||
auto quat = this->transform->getLocalRotation();
|
auto quat = this->transform->getLocalRotation();
|
||||||
quat = glm::rotate(quat, getGame()->timeManager.delta, glm::vec3(0, 1, 0));
|
quat = glm::rotate(quat, delta, glm::vec3(0, 1, 0));
|
||||||
quat = glm::rotate(quat, getGame()->timeManager.delta / 2.0f, glm::vec3(1, 0, 0));
|
quat = glm::rotate(quat, delta / 2.0f, glm::vec3(1, 0, 0));
|
||||||
quat = glm::rotate(quat, getGame()->timeManager.delta / 4.0f, glm::vec3(0, 0, 1));
|
quat = glm::rotate(quat, delta / 4.0f, glm::vec3(0, 0, 1));
|
||||||
this->transform->setLocalRotation(quat);
|
this->transform->setLocalRotation(quat);
|
||||||
}, getScene()->eventSceneUnpausedUpdate);
|
}, getScene()->eventSceneUnpausedUpdate);
|
||||||
}
|
}
|
@ -14,13 +14,13 @@ SubSceneController::SubSceneController(SceneItem *i) : SceneItemComponent(i) {
|
|||||||
void SubSceneController::onStart() {
|
void SubSceneController::onStart() {
|
||||||
auto myScene = this->getScene();
|
auto myScene = this->getScene();
|
||||||
|
|
||||||
useEventLegacy([&]{
|
useEvent([&](float_t d){
|
||||||
if(!this->onlyUpdateUnpaused) return;
|
if(!this->onlyUpdateUnpaused) return;
|
||||||
if(this->subScene == nullptr) return;
|
if(this->subScene == nullptr) return;
|
||||||
this->subScene->update();
|
this->subScene->update();
|
||||||
}, myScene->eventSceneUnpausedUpdate);
|
}, myScene->eventSceneUnpausedUpdate);
|
||||||
|
|
||||||
useEventLegacy([&]{
|
useEvent([&](float_t d){
|
||||||
if(this->onlyUpdateUnpaused) return;
|
if(this->onlyUpdateUnpaused) return;
|
||||||
if(this->subScene == nullptr) return;
|
if(this->subScene == nullptr) return;
|
||||||
this->subScene->update();
|
this->subScene->update();
|
||||||
|
@ -67,7 +67,7 @@ void UICanvas::onStart() {
|
|||||||
}, this->currentMenu);
|
}, this->currentMenu);
|
||||||
|
|
||||||
// Scene Update
|
// Scene Update
|
||||||
useEventLegacy([&]{
|
useEvent([&](float_t delta){
|
||||||
if(this->currentMenu == nullptr) return;
|
if(this->currentMenu == nullptr) return;
|
||||||
this->currentMenu->onTick();
|
this->currentMenu->onTick();
|
||||||
}, getScene()->eventSceneUpdate);
|
}, getScene()->eventSceneUpdate);
|
||||||
|
@ -1,268 +1,257 @@
|
|||||||
// Copyright (c) 2023 Dominic Masters
|
// Copyright (c) 2023 Dominic Masters
|
||||||
//
|
//
|
||||||
// This software is released under the MIT License.
|
// This software is released under the MIT License.
|
||||||
// https://opensource.org/licenses/MIT
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
#include "AudioSource.hpp"
|
#include "AudioSource.hpp"
|
||||||
#include "game/DawnGame.hpp"
|
#include "game/DawnGame.hpp"
|
||||||
|
|
||||||
using namespace Dawn;
|
using namespace Dawn;
|
||||||
|
|
||||||
AudioSource::AudioSource(SceneItem *i) : SceneItemComponent(i) {
|
AudioSource::AudioSource(SceneItem *i) :
|
||||||
|
SceneItemComponent(i),
|
||||||
}
|
playMode(AUDIO_PLAY_MODE_UNPAUSED)
|
||||||
|
{
|
||||||
|
|
||||||
void AudioSource::fillBuffer(ALuint buffer) {
|
}
|
||||||
// Read in some data
|
|
||||||
uint8_t *temporaryBuffer = (uint8_t*)memoryAllocate(AUDIO_SOURCE_BUFFER_SIZE);
|
|
||||||
/*
|
void AudioSource::fillBuffer(ALuint buffer) {
|
||||||
OK A big writeup here because things get complicated and I am sure that I
|
// Read in some data
|
||||||
will need to revist this.
|
uint8_t *temporaryBuffer = (uint8_t*)memoryAllocate(AUDIO_SOURCE_BUFFER_SIZE);
|
||||||
|
/*
|
||||||
First thing to note is that OpenAL requires that the data buffered is a
|
OK A big writeup here because things get complicated and I am sure that I
|
||||||
multiple of the frame size. Frame Size from what I can tell is;
|
will need to revist this.
|
||||||
dataSize * channelCount
|
|
||||||
e.g. sizeof(int16_t) * stereo = 4
|
First thing to note is that OpenAL requires that the data buffered is a
|
||||||
|
multiple of the frame size. Frame Size from what I can tell is;
|
||||||
EDIT 23017 - Something about how OpenAL handles things means the following
|
dataSize * channelCount
|
||||||
statement is probably false, I'm leaving it here but DON'T READ IT PLEASE
|
e.g. sizeof(int16_t) * stereo = 4
|
||||||
|
|
||||||
Additionally, we need to handle cases where the buffer "wraps around". So
|
EDIT 23017 - Something about how OpenAL handles things means the following
|
||||||
let's say we are at 8179/8192 bytes, we go to read "128 bytes", we need to
|
statement is probably false, I'm leaving it here but DON'T READ IT PLEASE
|
||||||
first read the remaining 13 bytes and then the remaining (128-13)bytes.
|
|
||||||
|
Additionally, we need to handle cases where the buffer "wraps around". So
|
||||||
After that we need to do our frame size division, and make sure we only
|
let's say we are at 8179/8192 bytes, we go to read "128 bytes", we need to
|
||||||
advance our buffer by that many bytes, so that the next buffer can pick up
|
first read the remaining 13 bytes and then the remaining (128-13)bytes.
|
||||||
exactly where this buffer left off.
|
|
||||||
*/
|
After that we need to do our frame size division, and make sure we only
|
||||||
|
advance our buffer by that many bytes, so that the next buffer can pick up
|
||||||
// Try to read the entire buffer
|
exactly where this buffer left off.
|
||||||
this->data->loader.setPosition(this->data->bufferStart + bufferPosition);
|
*/
|
||||||
size_t readLength = this->data->loader.read(
|
|
||||||
temporaryBuffer, AUDIO_SOURCE_BUFFER_SIZE
|
// Try to read the entire buffer
|
||||||
);
|
this->data->loader.setPosition(this->data->bufferStart + bufferPosition);
|
||||||
|
size_t readLength = this->data->loader.read(
|
||||||
size_t bufferLength = (readLength / this->data->frameSize) * this->data->frameSize;
|
temporaryBuffer, AUDIO_SOURCE_BUFFER_SIZE
|
||||||
|
);
|
||||||
// Did we run out of data?
|
|
||||||
size_t newPosition;
|
size_t bufferLength = (readLength / this->data->frameSize) * this->data->frameSize;
|
||||||
if(readLength < AUDIO_SOURCE_BUFFER_SIZE) {
|
|
||||||
newPosition = 0;
|
// Did we run out of data?
|
||||||
} else {
|
size_t newPosition;
|
||||||
newPosition = bufferPosition + bufferLength;
|
if(readLength < AUDIO_SOURCE_BUFFER_SIZE) {
|
||||||
}
|
newPosition = 0;
|
||||||
|
} else {
|
||||||
// Determine format, may do this somewhere else for efficiency sake.
|
newPosition = bufferPosition + bufferLength;
|
||||||
ALenum format;
|
}
|
||||||
switch(this->data->channelCount) {
|
|
||||||
case 2:
|
// Determine format, may do this somewhere else for efficiency sake.
|
||||||
format = AL_FORMAT_STEREO16;
|
ALenum format;
|
||||||
break;
|
switch(this->data->channelCount) {
|
||||||
case 1:
|
case 2:
|
||||||
format = AL_FORMAT_MONO16;
|
format = AL_FORMAT_STEREO16;
|
||||||
break;
|
break;
|
||||||
default:
|
case 1:
|
||||||
assertUnreachable();
|
format = AL_FORMAT_MONO16;
|
||||||
}
|
break;
|
||||||
|
default:
|
||||||
// Buffer data
|
assertUnreachable();
|
||||||
alBufferData(
|
}
|
||||||
buffer, format, temporaryBuffer, bufferLength, (ALsizei)this->data->sampleRate
|
|
||||||
);
|
// Buffer data
|
||||||
|
alBufferData(
|
||||||
// Cleanup
|
buffer, format, temporaryBuffer, bufferLength, (ALsizei)this->data->sampleRate
|
||||||
memoryFree(temporaryBuffer);
|
);
|
||||||
bufferPosition = newPosition;
|
|
||||||
}
|
// Cleanup
|
||||||
|
memoryFree(temporaryBuffer);
|
||||||
void AudioSource::detatchBuffers() {
|
bufferPosition = newPosition;
|
||||||
ALint buffersQueued;
|
}
|
||||||
ALuint buffersUnqueued[AUDIO_SOURCE_BUFFER_COUNT];
|
|
||||||
alGetSourcei(this->source, AL_BUFFERS_QUEUED, &buffersQueued);
|
void AudioSource::detatchBuffers() {
|
||||||
if(buffersQueued > 0) {
|
ALint buffersQueued;
|
||||||
alSourceUnqueueBuffers(this->source, buffersQueued, buffersUnqueued);
|
ALuint buffersUnqueued[AUDIO_SOURCE_BUFFER_COUNT];
|
||||||
}
|
alGetSourcei(this->source, AL_BUFFERS_QUEUED, &buffersQueued);
|
||||||
}
|
if(buffersQueued > 0) {
|
||||||
|
alSourceUnqueueBuffers(this->source, buffersQueued, buffersUnqueued);
|
||||||
void AudioSource::attachBuffers() {
|
}
|
||||||
alSourceQueueBuffers(this->source, AUDIO_SOURCE_BUFFER_COUNT, this->buffers);
|
}
|
||||||
}
|
|
||||||
|
void AudioSource::attachBuffers() {
|
||||||
void AudioSource::onStart() {
|
alSourceQueueBuffers(this->source, AUDIO_SOURCE_BUFFER_COUNT, this->buffers);
|
||||||
// Create source and buffers
|
}
|
||||||
alGenSources((ALuint)1, &this->source);
|
|
||||||
alGenBuffers((ALuint)AUDIO_SOURCE_BUFFER_COUNT, this->buffers);
|
void AudioSource::onStart() {
|
||||||
|
// Create source and buffers
|
||||||
// Set up the source positions
|
alGenSources((ALuint)1, &this->source);
|
||||||
glm::vec3 position = this->transform->getWorldPosition();
|
alGenBuffers((ALuint)AUDIO_SOURCE_BUFFER_COUNT, this->buffers);
|
||||||
alSource3f(this->source, AL_POSITION, position.x, position.y, position.z);
|
|
||||||
alSource3f(this->source, AL_VELOCITY, 0, 0, 0);
|
// Set up the source positions
|
||||||
|
glm::vec3 position = this->transform->getWorldPosition();
|
||||||
// In future these will probably be tied to the layer
|
alSource3f(this->source, AL_POSITION, position.x, position.y, position.z);
|
||||||
alSourcef(this->source, AL_PITCH, 1);
|
alSource3f(this->source, AL_VELOCITY, 0, 0, 0);
|
||||||
alSourcef(this->source, AL_GAIN, 1);
|
|
||||||
|
// In future these will probably be tied to the layer
|
||||||
// Mark as ready.
|
alSourcef(this->source, AL_PITCH, 1);
|
||||||
this->ready = true;
|
alSourcef(this->source, AL_GAIN, 1);
|
||||||
|
|
||||||
// Listen for events
|
// Mark as ready.
|
||||||
this->transform->eventTransformUpdated.addListener(this, &AudioSource::onTransformUpdate);
|
this->ready = true;
|
||||||
this->getScene()->eventSceneUpdate.addListener(this, &AudioSource::onSceneUpdate);
|
|
||||||
}
|
// Listen for events
|
||||||
|
useEventLegacy([&]{
|
||||||
AudioSourceState AudioSource::getRealState() {
|
glm::vec3 position = this->transform->getWorldPosition();
|
||||||
return this->internalState;
|
alSource3f(this->source, AL_POSITION, position.x, position.y, position.z);
|
||||||
}
|
}, this->transform->eventTransformUpdated);
|
||||||
|
|
||||||
void AudioSource::rewind() {
|
useEvent([&](float_t delta){
|
||||||
this->bufferPosition = 0;
|
ALuint bufferId;
|
||||||
}
|
ALint buffersProcessed;
|
||||||
|
|
||||||
AudioAsset * AudioSource::getAudioData() {
|
assertTrue(this->ready);
|
||||||
return this->data;
|
|
||||||
}
|
// What is the user trying to do?
|
||||||
|
if(this->state == AUDIO_SOURCE_STATE_PLAYING) {
|
||||||
void AudioSource::setAudioData(AudioAsset *data) {
|
assertTrue(this->data != nullptr);
|
||||||
this->data = data;
|
assertTrue(this->data->loaded);
|
||||||
this->rewind();
|
|
||||||
}
|
// Handle the special game-paused music-paused state.
|
||||||
|
if(this->playMode == AUDIO_PLAY_MODE_UNPAUSED && this->getGame()->timeManager.isPaused) {
|
||||||
enum AudioSourcePlayMode AudioSource::getPlayMode() {
|
if(this->internalState == AUDIO_SOURCE_STATE_PLAYING) {
|
||||||
return this->playMode;
|
// Functionally, this is the same as pausing
|
||||||
}
|
alSourcePause(this->source);
|
||||||
|
this->internalState = AUDIO_SOURCE_STATE_PAUSED;
|
||||||
void AudioSource::setPlayMode(enum AudioSourcePlayMode playMode) {
|
}
|
||||||
this->playMode = playMode;
|
return;// Do nothing else, at all.
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSource::stop() {
|
// They are trying to play. We need to check if we are already playing
|
||||||
this->state = AUDIO_SOURCE_STATE_STOPPED;
|
if(this->internalState == AUDIO_SOURCE_STATE_PLAYING) {
|
||||||
}
|
// We are good to continue buffering audio data.
|
||||||
|
buffersProcessed = 0;
|
||||||
void AudioSource::play() {
|
alGetSourcei(this->source, AL_BUFFERS_PROCESSED, &buffersProcessed);
|
||||||
this->state = AUDIO_SOURCE_STATE_PLAYING;
|
|
||||||
}
|
while(buffersProcessed > 0) {
|
||||||
|
alSourceUnqueueBuffers(this->source, 1, &bufferId);
|
||||||
void AudioSource::pause() {
|
this->fillBuffer(bufferId);
|
||||||
this->state = AUDIO_SOURCE_STATE_PAUSED;
|
alSourceQueueBuffers(this->source, 1, &bufferId);
|
||||||
}
|
buffersProcessed--;
|
||||||
|
|
||||||
void AudioSource::onDispose() {
|
// Now, before we go to the next buffer let's see if we need to
|
||||||
assertTrue(this->ready);
|
// update the internal state
|
||||||
this->ready = false;
|
if(this->bufferPosition != 0) continue;
|
||||||
|
|
||||||
this->getScene()->eventSceneUpdate.removeListener(this, &AudioSource::onSceneUpdate);
|
// We reached the end of the buffer whilst filling. What to do now?
|
||||||
this->transform->eventTransformUpdated.removeListener(this, &AudioSource::onTransformUpdate);
|
if(this->loop) {
|
||||||
|
// We're looping so it's fine
|
||||||
alDeleteSources((ALuint)1, &this->source);
|
this->eventLooped.invoke();
|
||||||
alDeleteBuffers((ALuint)AUDIO_SOURCE_BUFFER_COUNT, this->buffers);
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSource::onSceneUpdate() {
|
// We are NOT looping, so we need to finish here.
|
||||||
ALuint bufferId;
|
this->state = AUDIO_SOURCE_STATE_STOPPED;
|
||||||
ALint buffersProcessed;
|
this->eventFinished.invoke();
|
||||||
|
this->bufferPosition = 0;
|
||||||
assertTrue(this->ready);
|
buffersProcessed = 0;
|
||||||
|
}
|
||||||
// What is the user trying to do?
|
} else if(this->internalState == AUDIO_SOURCE_STATE_STOPPED) {
|
||||||
if(this->state == AUDIO_SOURCE_STATE_PLAYING) {
|
// Not yet playing. First thing we need to do is fill the buffers.
|
||||||
assertTrue(this->data != nullptr);
|
for(int32_t i = 0; i < AUDIO_SOURCE_BUFFER_COUNT; i++) {
|
||||||
assertTrue(this->data->loaded);
|
this->fillBuffer(this->buffers[i]);
|
||||||
|
}
|
||||||
// Handle the special game-paused music-paused state.
|
|
||||||
if(this->playMode == AUDIO_PLAY_MODE_UNPAUSED && this->getGame()->timeManager.isPaused) {
|
// Now attach the buffers
|
||||||
if(this->internalState == AUDIO_SOURCE_STATE_PLAYING) {
|
this->attachBuffers();
|
||||||
// Functionally, this is the same as pausing
|
|
||||||
alSourcePause(this->source);
|
// And begin playing
|
||||||
this->internalState = AUDIO_SOURCE_STATE_PAUSED;
|
alSourcePlay(this->source);
|
||||||
}
|
this->internalState = AUDIO_SOURCE_STATE_PLAYING;
|
||||||
return;// Do nothing else, at all.
|
this->eventPlaying.invoke();
|
||||||
}
|
|
||||||
|
} else if(AUDIO_SOURCE_STATE_PAUSED) {
|
||||||
// They are trying to play. We need to check if we are already playing
|
// Request to resume
|
||||||
if(this->internalState == AUDIO_SOURCE_STATE_PLAYING) {
|
alSourcePlay(this->source);
|
||||||
// We are good to continue buffering audio data.
|
this->eventResumed.invoke();
|
||||||
buffersProcessed = 0;
|
this->internalState = AUDIO_SOURCE_STATE_PLAYING;
|
||||||
alGetSourcei(this->source, AL_BUFFERS_PROCESSED, &buffersProcessed);
|
|
||||||
|
} else {
|
||||||
while(buffersProcessed > 0) {
|
assertUnreachable();
|
||||||
alSourceUnqueueBuffers(this->source, 1, &bufferId);
|
}
|
||||||
this->fillBuffer(bufferId);
|
} else if(this->state == AUDIO_SOURCE_STATE_PAUSED) {
|
||||||
alSourceQueueBuffers(this->source, 1, &bufferId);
|
assertTrue(this->data != nullptr);
|
||||||
buffersProcessed--;
|
assertTrue(this->data->loaded);
|
||||||
|
|
||||||
// Now, before we go to the next buffer let's see if we need to
|
// Pause has been requested.
|
||||||
// update the internal state
|
if(this->internalState != AUDIO_SOURCE_STATE_PLAYING) return;
|
||||||
if(this->bufferPosition != 0) continue;
|
|
||||||
|
// We are playing something, pause it
|
||||||
// We reached the end of the buffer whilst filling. What to do now?
|
alSourcePause(this->source);
|
||||||
if(this->loop) {
|
this->internalState = AUDIO_SOURCE_STATE_PAUSED;
|
||||||
// We're looping so it's fine
|
this->eventPaused.invoke();
|
||||||
this->eventLooped.invoke();
|
|
||||||
continue;
|
} else if(this->state == AUDIO_SOURCE_STATE_STOPPED) {
|
||||||
}
|
if(this->internalState == AUDIO_SOURCE_STATE_STOPPED) return;
|
||||||
|
|
||||||
// We are NOT looping, so we need to finish here.
|
assertTrue(this->data != nullptr);
|
||||||
this->state = AUDIO_SOURCE_STATE_STOPPED;
|
assertTrue(this->data->loaded);
|
||||||
this->eventFinished.invoke();
|
|
||||||
this->bufferPosition = 0;
|
// Release the buffers
|
||||||
buffersProcessed = 0;
|
alSourceStop(this->source);
|
||||||
}
|
this->detatchBuffers();
|
||||||
} else if(this->internalState == AUDIO_SOURCE_STATE_STOPPED) {
|
this->internalState = AUDIO_SOURCE_STATE_STOPPED;
|
||||||
// Not yet playing. First thing we need to do is fill the buffers.
|
this->eventStopped.invoke();
|
||||||
for(int32_t i = 0; i < AUDIO_SOURCE_BUFFER_COUNT; i++) {
|
this->bufferPosition = 0;
|
||||||
this->fillBuffer(this->buffers[i]);
|
|
||||||
}
|
} else {
|
||||||
|
assertUnreachable();
|
||||||
// Now attach the buffers
|
}
|
||||||
this->attachBuffers();
|
}, getScene()->eventSceneUpdate);
|
||||||
|
}
|
||||||
// And begin playing
|
|
||||||
alSourcePlay(this->source);
|
AudioSourceState AudioSource::getRealState() {
|
||||||
this->internalState = AUDIO_SOURCE_STATE_PLAYING;
|
return this->internalState;
|
||||||
this->eventPlaying.invoke();
|
}
|
||||||
|
|
||||||
} else if(AUDIO_SOURCE_STATE_PAUSED) {
|
void AudioSource::rewind() {
|
||||||
// Request to resume
|
this->bufferPosition = 0;
|
||||||
alSourcePlay(this->source);
|
}
|
||||||
this->eventResumed.invoke();
|
|
||||||
this->internalState = AUDIO_SOURCE_STATE_PLAYING;
|
AudioAsset * AudioSource::getAudioData() {
|
||||||
|
return this->data;
|
||||||
} else {
|
}
|
||||||
assertUnreachable();
|
|
||||||
}
|
void AudioSource::setAudioData(AudioAsset *data) {
|
||||||
} else if(this->state == AUDIO_SOURCE_STATE_PAUSED) {
|
this->data = data;
|
||||||
assertTrue(this->data != nullptr);
|
this->rewind();
|
||||||
assertTrue(this->data->loaded);
|
}
|
||||||
|
|
||||||
// Pause has been requested.
|
void AudioSource::stop() {
|
||||||
if(this->internalState != AUDIO_SOURCE_STATE_PLAYING) return;
|
this->state = AUDIO_SOURCE_STATE_STOPPED;
|
||||||
|
}
|
||||||
// We are playing something, pause it
|
|
||||||
alSourcePause(this->source);
|
void AudioSource::play() {
|
||||||
this->internalState = AUDIO_SOURCE_STATE_PAUSED;
|
this->state = AUDIO_SOURCE_STATE_PLAYING;
|
||||||
this->eventPaused.invoke();
|
}
|
||||||
|
|
||||||
} else if(this->state == AUDIO_SOURCE_STATE_STOPPED) {
|
void AudioSource::pause() {
|
||||||
if(this->internalState == AUDIO_SOURCE_STATE_STOPPED) return;
|
this->state = AUDIO_SOURCE_STATE_PAUSED;
|
||||||
|
}
|
||||||
assertTrue(this->data != nullptr);
|
|
||||||
assertTrue(this->data->loaded);
|
void AudioSource::onDispose() {
|
||||||
|
assertTrue(this->ready);
|
||||||
// Release the buffers
|
this->ready = false;
|
||||||
alSourceStop(this->source);
|
|
||||||
this->detatchBuffers();
|
alDeleteSources((ALuint)1, &this->source);
|
||||||
this->internalState = AUDIO_SOURCE_STATE_STOPPED;
|
alDeleteBuffers((ALuint)AUDIO_SOURCE_BUFFER_COUNT, this->buffers);
|
||||||
this->eventStopped.invoke();
|
|
||||||
this->bufferPosition = 0;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
assertUnreachable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioSource::onTransformUpdate() {
|
|
||||||
glm::vec3 position = this->transform->getWorldPosition();
|
|
||||||
alSource3f(this->source, AL_POSITION, position.x, position.y, position.z);
|
|
||||||
}
|
}
|
@ -1,133 +1,118 @@
|
|||||||
// Copyright (c) 2023 Dominic Masters
|
// Copyright (c) 2023 Dominic Masters
|
||||||
//
|
//
|
||||||
// This software is released under the MIT License.
|
// This software is released under the MIT License.
|
||||||
// https://opensource.org/licenses/MIT
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "dawnopenal.hpp"
|
#include "dawnopenal.hpp"
|
||||||
#include "scene/SceneItemComponent.hpp"
|
#include "scene/SceneItemComponent.hpp"
|
||||||
#include "asset/assets/AudioAsset.hpp"
|
#include "asset/assets/AudioAsset.hpp"
|
||||||
|
|
||||||
#define AUDIO_SOURCE_BUFFER_COUNT 3
|
#define AUDIO_SOURCE_BUFFER_COUNT 3
|
||||||
#define AUDIO_SOURCE_BUFFER_SIZE 8192
|
#define AUDIO_SOURCE_BUFFER_SIZE 8192
|
||||||
|
|
||||||
namespace Dawn {
|
namespace Dawn {
|
||||||
enum AudioSourceState {
|
enum AudioSourceState {
|
||||||
AUDIO_SOURCE_STATE_STOPPED,
|
AUDIO_SOURCE_STATE_STOPPED,
|
||||||
AUDIO_SOURCE_STATE_PLAYING,
|
AUDIO_SOURCE_STATE_PLAYING,
|
||||||
AUDIO_SOURCE_STATE_PAUSED
|
AUDIO_SOURCE_STATE_PAUSED
|
||||||
};
|
};
|
||||||
|
|
||||||
enum AudioSourcePlayMode {
|
enum AudioSourcePlayMode {
|
||||||
AUDIO_PLAY_MODE_ALWAYS,
|
AUDIO_PLAY_MODE_ALWAYS,
|
||||||
AUDIO_PLAY_MODE_UNPAUSED
|
AUDIO_PLAY_MODE_UNPAUSED
|
||||||
};
|
};
|
||||||
|
|
||||||
class AudioSource : public SceneItemComponent {
|
class AudioSource : public SceneItemComponent {
|
||||||
private:
|
private:
|
||||||
ALuint source;
|
ALuint source;
|
||||||
bool_t ready = false;
|
bool_t ready = false;
|
||||||
ALuint buffers[AUDIO_SOURCE_BUFFER_COUNT];
|
ALuint buffers[AUDIO_SOURCE_BUFFER_COUNT];
|
||||||
size_t bufferPosition = 0;
|
size_t bufferPosition = 0;
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
enum AudioSourceState internalState = AUDIO_SOURCE_STATE_STOPPED;
|
enum AudioSourceState internalState = AUDIO_SOURCE_STATE_STOPPED;
|
||||||
int32_t layer = 0;
|
int32_t layer = 0;
|
||||||
AudioAsset *data = nullptr;
|
AudioAsset *data = nullptr;
|
||||||
AudioSourcePlayMode playMode = AUDIO_PLAY_MODE_UNPAUSED;
|
|
||||||
|
/**
|
||||||
/**
|
* Internally update the audio's state based on the current settings.
|
||||||
* Internally update the audio's state based on the current settings.
|
*/
|
||||||
*/
|
void updateAudioSource();
|
||||||
void updateAudioSource();
|
|
||||||
|
void fillBuffer(ALuint buffer);
|
||||||
void fillBuffer(ALuint buffer);
|
void detatchBuffers();
|
||||||
void detatchBuffers();
|
void attachBuffers();
|
||||||
void attachBuffers();
|
|
||||||
|
// Events
|
||||||
// Events
|
void onSceneUpdate();
|
||||||
void onSceneUpdate();
|
|
||||||
void onTransformUpdate();
|
public:
|
||||||
|
bool_t loop = false;
|
||||||
public:
|
enum AudioSourceState state = AUDIO_SOURCE_STATE_STOPPED;
|
||||||
bool_t loop = false;
|
AudioSourcePlayMode playMode;
|
||||||
enum AudioSourceState state = AUDIO_SOURCE_STATE_STOPPED;
|
|
||||||
|
Event<> eventPlaying;
|
||||||
Event<> eventPlaying;
|
Event<> eventResumed;
|
||||||
Event<> eventResumed;
|
Event<> eventPaused;
|
||||||
Event<> eventPaused;
|
Event<> eventStopped;
|
||||||
Event<> eventStopped;
|
Event<> eventFinished;
|
||||||
Event<> eventFinished;
|
Event<> eventLooped;
|
||||||
Event<> eventLooped;
|
|
||||||
|
/**
|
||||||
/**
|
* Creates an Audio Source item component.
|
||||||
* Creates an Audio Source item component.
|
*
|
||||||
*
|
* @param item SceneItem that this audio source is attached to.
|
||||||
* @param item SceneItem that this audio source is attached to.
|
*/
|
||||||
*/
|
AudioSource(SceneItem *item);
|
||||||
AudioSource(SceneItem *item);
|
|
||||||
|
/**
|
||||||
/**
|
* Returns the real current state of the sound. Refer to getPlayingState
|
||||||
* Returns the real current state of the sound. Refer to getPlayingState
|
* but basically the actually requested play state and what the hardware
|
||||||
* but basically the actually requested play state and what the hardware
|
* and internal logic is doing may result in the actual state being a
|
||||||
* and internal logic is doing may result in the actual state being a
|
* little different. You cannot control this, but you can read it.
|
||||||
* little different. You cannot control this, but you can read it.
|
*
|
||||||
*
|
* @return The actual current playing state.
|
||||||
* @return The actual current playing state.
|
*/
|
||||||
*/
|
AudioSourceState getRealState();
|
||||||
AudioSourceState getRealState();
|
|
||||||
|
/**
|
||||||
/**
|
* Rewinds the audio source. At the time of writing this comment (23017) I
|
||||||
* Rewinds the audio source. At the time of writing this comment (23017) I
|
* am unsure of the behaviour when rewinding whilst the source is active.
|
||||||
* am unsure of the behaviour when rewinding whilst the source is active.
|
*/
|
||||||
*/
|
void rewind();
|
||||||
void rewind();
|
|
||||||
|
/**
|
||||||
/**
|
* Returns the current audio data for this source.
|
||||||
* Returns the current audio data for this source.
|
*
|
||||||
*
|
* @return Audio data that is atached to this source.
|
||||||
* @return Audio data that is atached to this source.
|
*/
|
||||||
*/
|
AudioAsset * getAudioData();
|
||||||
AudioAsset * getAudioData();
|
|
||||||
|
/**
|
||||||
/**
|
* Sets the audio data for this source. Currently switching between the
|
||||||
* Sets the audio data for this source. Currently switching between the
|
* audio data during playback may have undefined behavior.
|
||||||
* audio data during playback may have undefined behavior.
|
*
|
||||||
*
|
* @param data Data to set.
|
||||||
* @param data Data to set.
|
*/
|
||||||
*/
|
void setAudioData(AudioAsset *data);
|
||||||
void setAudioData(AudioAsset *data);
|
|
||||||
|
/**
|
||||||
/**
|
* Stop playing this audio source. Shorthand for setting the state.
|
||||||
* Returns the play mode for the source.
|
*/
|
||||||
*
|
void stop();
|
||||||
* @return Current play mode.
|
|
||||||
*/
|
/**
|
||||||
enum AudioSourcePlayMode getPlayMode();
|
* Play this audio source. Shorthand for state setting.
|
||||||
|
*/
|
||||||
/**
|
void play();
|
||||||
* Sets the play mode for the source.
|
|
||||||
*
|
/**
|
||||||
* @param mode Play Mode to use.
|
* Pause this audio source. Shorthand for state setting.
|
||||||
*/
|
*/
|
||||||
void setPlayMode(enum AudioSourcePlayMode mode);
|
void pause();
|
||||||
|
|
||||||
/**
|
void onStart() override;
|
||||||
* Stop playing this audio source. Shorthand for setting the state.
|
void onDispose() override;
|
||||||
*/
|
};
|
||||||
void stop();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Play this audio source. Shorthand for state setting.
|
|
||||||
*/
|
|
||||||
void play();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pause this audio source. Shorthand for state setting.
|
|
||||||
*/
|
|
||||||
void pause();
|
|
||||||
|
|
||||||
void onStart() override;
|
|
||||||
void onDispose() override;
|
|
||||||
};
|
|
||||||
}
|
}
|
@ -14,73 +14,67 @@ TicTacToeGame::TicTacToeGame(SceneItem *item) : SceneItemComponent(item) {}
|
|||||||
|
|
||||||
void TicTacToeGame::onStart() {
|
void TicTacToeGame::onStart() {
|
||||||
// Map tiles by tile number = tile
|
// Map tiles by tile number = tile
|
||||||
auto tiles = getScene()->findComponents<TicTacToeTile>();
|
auto ts = getScene()->findComponents<TicTacToeTile>();
|
||||||
auto itTiles = tiles.begin();
|
auto itTiles = ts.begin();
|
||||||
while(itTiles != tiles.end()) {
|
while(itTiles != ts.end()) {
|
||||||
this->tiles[(*itTiles)->tile] = *itTiles;
|
this->tiles[(*itTiles)->tile] = *itTiles;
|
||||||
++itTiles;
|
++itTiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen
|
// Listen
|
||||||
getScene()->eventSceneUpdate.addListener(this, &TicTacToeGame::onSceneUpdate);
|
useEvent([&](float_t delta) {
|
||||||
}
|
// Get mouse in screen space.
|
||||||
|
auto mouse = getGame()->inputManager.getAxis2D(INPUT_BIND_MOUSE_X, INPUT_BIND_MOUSE_Y);
|
||||||
|
mouse *= 2.0f;
|
||||||
|
mouse -= glm::vec2(1, 1);
|
||||||
|
|
||||||
void TicTacToeGame::onDispose() {
|
Camera *camera = getScene()->findComponent<Camera>();
|
||||||
getScene()->eventSceneUpdate.removeListener(this, &TicTacToeGame::onSceneUpdate);
|
if(camera == nullptr) return;
|
||||||
}
|
|
||||||
|
|
||||||
void TicTacToeGame::onSceneUpdate() {
|
struct Ray3D ray;
|
||||||
// Get mouse in screen space.
|
ray.origin = camera->transform->getWorldPosition();
|
||||||
auto mouse = getGame()->inputManager.getAxis2D(INPUT_BIND_MOUSE_X, INPUT_BIND_MOUSE_Y);
|
ray.direction = camera->getRayDirectionFromScreenSpace(mouse);
|
||||||
mouse *= 2.0f;
|
|
||||||
mouse -= glm::vec2(1, 1);
|
|
||||||
|
|
||||||
Camera *camera = getScene()->findComponent<Camera>();
|
|
||||||
if(camera == nullptr) return;
|
|
||||||
|
|
||||||
struct Ray3D ray;
|
|
||||||
ray.origin = camera->transform->getWorldPosition();
|
|
||||||
ray.direction = camera->getRayDirectionFromScreenSpace(mouse);
|
|
||||||
|
|
||||||
|
|
||||||
// Find the hovered tile (if any)
|
|
||||||
TicTacToeTile *hovered = nullptr;
|
|
||||||
auto results = getPhysics()->raycast3DAll(ray);
|
|
||||||
auto itResult = results.begin();
|
|
||||||
while(itResult != results.end()) {
|
|
||||||
auto result = *itResult;
|
|
||||||
auto tile = result.collider->item->getComponent<TicTacToeTile>();
|
|
||||||
if(tile == nullptr) {
|
|
||||||
++itResult;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
hovered = tile;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now update the state of each tile, also get the state while we are at it
|
// Find the hovered tile (if any)
|
||||||
std::map<uint8_t, enum TicTacToeTileState> tileMap;
|
TicTacToeTile *hovered = nullptr;
|
||||||
|
auto results = getPhysics()->raycast3DAll(ray);
|
||||||
auto itTiles = tiles.begin();
|
auto itResult = results.begin();
|
||||||
while(itTiles != tiles.end()) {
|
while(itResult != results.end()) {
|
||||||
auto t = itTiles->second;
|
auto result = *itResult;
|
||||||
|
auto tile = result.collider->item->getComponent<TicTacToeTile>();
|
||||||
if(t == hovered) {
|
if(tile == nullptr) {
|
||||||
if(t->tileState == TIC_TAC_TOE_EMPTY && getGame()->inputManager.isPressed(INPUT_BIND_MOUSE_CLICK)) {
|
++itResult;
|
||||||
t->tileState = nextMove;
|
continue;
|
||||||
nextMove = nextMove == TIC_TAC_TOE_NOUGHT ? TIC_TAC_TOE_CROSS : TIC_TAC_TOE_NOUGHT;
|
|
||||||
} else if(t->tileState == TIC_TAC_TOE_EMPTY) {
|
|
||||||
t->hovered = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
t->hovered = false;
|
hovered = tile;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
tileMap[itTiles->second->tile] = itTiles->second->tileState;
|
|
||||||
++itTiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine winner
|
// Now update the state of each tile, also get the state while we are at it
|
||||||
std::vector<uint8_t> winningCombo;
|
std::map<uint8_t, enum TicTacToeTileState> tileMap;
|
||||||
auto winner = ticTacToeDetermineWinner(tileMap, &winningCombo);
|
|
||||||
|
auto itTiles = tiles.begin();
|
||||||
|
while(itTiles != tiles.end()) {
|
||||||
|
auto t = itTiles->second;
|
||||||
|
|
||||||
|
if(t == hovered) {
|
||||||
|
if(t->tileState == TIC_TAC_TOE_EMPTY && getGame()->inputManager.isPressed(INPUT_BIND_MOUSE_CLICK)) {
|
||||||
|
t->tileState = nextMove;
|
||||||
|
nextMove = nextMove == TIC_TAC_TOE_NOUGHT ? TIC_TAC_TOE_CROSS : TIC_TAC_TOE_NOUGHT;
|
||||||
|
} else if(t->tileState == TIC_TAC_TOE_EMPTY) {
|
||||||
|
t->hovered = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t->hovered = false;
|
||||||
|
}
|
||||||
|
tileMap[itTiles->second->tile] = itTiles->second->tileState;
|
||||||
|
++itTiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine winner
|
||||||
|
std::vector<uint8_t> winningCombo;
|
||||||
|
auto winner = ticTacToeDetermineWinner(tileMap, &winningCombo);
|
||||||
|
}, getScene()->eventSceneUpdate);
|
||||||
}
|
}
|
@ -17,8 +17,5 @@ namespace Dawn {
|
|||||||
TicTacToeGame(SceneItem *item);
|
TicTacToeGame(SceneItem *item);
|
||||||
|
|
||||||
void onStart() override;
|
void onStart() override;
|
||||||
void onDispose() override;
|
|
||||||
|
|
||||||
void onSceneUpdate();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
Reference in New Issue
Block a user