Dawn/src/dawnglfw/host/DawnGLFWHost.cpp

270 lines
6.9 KiB
C++

/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "DawnGLFWHost.hpp"
#include "game/DawnGame.hpp"
#include "dawnopengl.hpp"
#include "display/BackBufferRenderTarget.hpp"
#include <AL/al.h>
#include <AL/alc.h>
#include "AudioFile.h"
using namespace Dawn;
// Static declaration of the host, needed due to GLFW events being C-like
DawnHost *DAWN_HOST = nullptr;
// Host
DawnHost::DawnHost() {
this->data = new DawnHostData();
this->data->window = nullptr;
}
int32_t DawnHost::init(DawnGame *game) {
AudioFile<double> audioFile;
audioFile.load ("C:\\sample.wav");
audioFile.printSummary();
ALCdevice* device = alcOpenDevice(nullptr);
if(!device) assertUnreachable();
ALCcontext *context;
context = alcCreateContext(device, NULL);
if(!alcMakeContextCurrent(context)) assertUnreachable();
ALfloat listenerOri[] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f };
alListener3f(AL_POSITION, 0, 0, 1.0f);
alListener3f(AL_VELOCITY, 0, 0, 0);
alListenerfv(AL_ORIENTATION, listenerOri);
ALuint source;
alGenSources((ALuint)1, &source);
alSourcef(source, AL_PITCH, 1);
alSourcef(source, AL_GAIN, 1);
alSource3f(source, AL_POSITION, 0, 0, 0);
alSource3f(source, AL_VELOCITY, 0, 0, 0);
alSourcei(source, AL_LOOPING, AL_FALSE);
ALuint buffer;
alGenBuffers((ALuint)1, &buffer);
ALenum format;
switch(audioFile.getBitDepth()) {
case 16:
switch(audioFile.getNumChannels()) {
case 2:
format = AL_FORMAT_STEREO16;
break;
case 1:
format = AL_FORMAT_MONO16;
break;
default:
assertUnreachable();
}
break;
case 8:
switch(audioFile.getNumChannels()) {
case 2:
format = AL_FORMAT_STEREO8;
break;
case 1:
format = AL_FORMAT_MONO8;
break;
default:
assertUnreachable();
}
break;
default:
assertUnreachable();
}
std::vector<uint8_t> data;
for (int i = 0; i < audioFile.getNumSamplesPerChannel(); i++) {
for(int y = 0; y < audioFile.getNumChannels(); y++) {
double sample = audioFile.samples[y][i];
sample = mathClamp(sample, -1., 1.);
auto q = static_cast<int16_t> (sample * 32767.);
uint8_t bytes[2];
bytes[0] = (q >> 8) & 0xFF;
bytes[1] = q & 0xFF;
data.push_back(bytes[1]);
data.push_back(bytes[0]);
}
}
alBufferData(buffer, format, &data[0], data.size(), audioFile.getSampleRate());
ALint source_state;
alSourcei(source, AL_BUFFER, buffer);
alSourcePlay(source);
alGetSourcei(source, AL_SOURCE_STATE, &source_state);
while (source_state == AL_PLAYING) {
alGetSourcei(source, AL_SOURCE_STATE, &source_state);
}
return DAWN_HOST_INIT_RESULT_SUCCESS;
// Update values
this->game = game;
DAWN_HOST = this;
// Init GLFW
if(!glfwInit()) return DAWN_GLFW_INIT_RESULT_INIT_FAILED;
glfwSetErrorCallback(&glfwOnError);
// Setup window hints
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, false);
// Create Window
this->data->window = glfwCreateWindow(
DAWN_GLFW_WINDOW_WIDTH_DEFAULT,
DAWN_GLFW_WINDOW_HEIGHT_DEFAULT,
"Dawn", NULL, NULL
);
if(this->data->window == nullptr) {
glfwTerminate();
return DAWN_GLFW_INIT_RESULT_WINDOW_CREATE_FAILED;
}
// Load GLAD
glfwMakeContextCurrent(this->data->window);
glfwSwapInterval(0);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
// Override the defaults
game->renderManager.backBuffer.setSize(
DAWN_GLFW_WINDOW_WIDTH_DEFAULT,
DAWN_GLFW_WINDOW_HEIGHT_DEFAULT
);
// Default keybinds
game->inputManager.bind(INPUT_BIND_ACCEPT, GLFW_KEY_ENTER);
game->inputManager.bind(INPUT_BIND_ACCEPT, GLFW_KEY_E);
game->inputManager.bind(INPUT_BIND_ACCEPT, GLFW_KEY_SPACE);
// game->inputManager.bind(INPUT_BIND_NEGATIVE_X, GLFW_KEY_A);
// game->inputManager.bind(INPUT_BIND_POSITIVE_X, GLFW_KEY_D);
// game->inputManager.bind(INPUT_BIND_NEGATIVE_Y, GLFW_KEY_S);
// game->inputManager.bind(INPUT_BIND_POSITIVE_Y, GLFW_KEY_W);
// Initialize the game
auto result = game->init();
if(result != DAWN_GAME_INIT_RESULT_SUCCESS) return result;
// Hard-Load the first scene assets.
if(game->scene != nullptr) {
auto assets = game->scene->getRequiredAssets();
game->assetManager.queueLoad(assets);
game->assetManager.syncLoad();
game->scene->stage();
}
// Set up event listeners
glfwSetFramebufferSizeCallback(this->data->window, &glfwOnResize);
glfwSetKeyCallback(this->data->window, &glfwOnKey);
return DAWN_HOST_INIT_RESULT_SUCCESS;
}
int32_t DawnHost::start(DawnGame *game) {
double_t time, newTime;
float_t fDelta;
int32_t updateResult;
// Main Render Loop
time = 0.0f;
while(!glfwWindowShouldClose(this->data->window)) {
// Determine the delta.
newTime = glfwGetTime();
fDelta = (float_t)(newTime - time);
time = newTime;
// Perform update
updateResult = this->update(game, fDelta);
// Did the update complete successfully?
if(updateResult == DAWN_HOST_UPDATE_RESULT_EXIT) {
break;
} else if(updateResult != DAWN_HOST_UPDATE_RESULT_SUCCESS) {
return DAWN_GLFW_START_RESULT_UPDATE_FAILED;
}
// Tick the engine.
glfwSwapBuffers(this->data->window);
// Update events
glfwPollEvents();
}
return DAWN_HOST_START_RESULT_EXIT_SUCCESS;
}
int32_t DawnHost::update(DawnGame *game, float_t delta) {
// Tick game.
auto ret = game->update(delta);
switch(ret) {
case DAWN_GAME_UPDATE_RESULT_SUCCESS:
return DAWN_HOST_UPDATE_RESULT_SUCCESS;
case DAWN_GAME_UPDATE_RESULT_EXIT:
return DAWN_HOST_UPDATE_RESULT_EXIT;
default:
return ret;
}
}
void DawnHost::unload(DawnGame *game) {
glfwDestroyWindow(this->data->window);
this->data->window = nullptr;
glfwTerminate();
}
DawnHost::~DawnHost() {
delete this->data;
DAWN_HOST = nullptr;
}
// GLFW Callbacks
void glfwOnError(int error, const char* description) {
fputs(description, stderr);
}
void glfwOnResize(GLFWwindow *window, int32_t w, int32_t h) {
if(DAWN_HOST == nullptr) return;
// TODO: I may throttle this, it calls for every frame the window's resized.
DAWN_HOST->game->renderManager.backBuffer.setSize((float_t)w, (float_t)h);
}
void glfwOnKey(
GLFWwindow *window,
int32_t key,
int32_t scancode,
int32_t action,
int32_t mods
) {
if(DAWN_HOST == nullptr) return;
// Determine Value
float_t value;
if(action == GLFW_PRESS) {
value = 1.0f;
} else if(action == GLFW_RELEASE) {
value = 0.0f;
} else {
return;
}
// Determine the input axis
DAWN_HOST->game->inputManager.rawInputValues[key] = value;
}