diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b195c0..8050819 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,9 @@ cmake_minimum_required(VERSION 3.2) project(riko4) -if(APPLE) - set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-pagezero_size 10000 -image_base 100000000") -endif() +if (APPLE) + set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-pagezero_size 10000 -image_base 100000000") +endif () set($SDL2_gpu_PATH "${SDL2_gpu_PATH}" CACHE INTERNAL "SDL2_gpu" FORCE) @@ -13,45 +13,49 @@ file(GLOB_RECURSE SOURCE_FILES src/*.cpp src/*.c src/*.h) add_executable(riko4 ${SOURCE_FILES}) set_target_properties(riko4 PROPERTIES - CXX_STANDARD 17 - CXX_STANDARD_REQUIRED ON) + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON) find_package(SDL2 REQUIRED) -if(SDL2_FOUND) +if (SDL2_FOUND) include_directories(${SDL2_INCLUDE_DIR}) target_link_libraries(riko4 ${SDL2_LIBRARY}) -endif() +endif () find_package(LuaJIT REQUIRED) -if(LUAJIT_FOUND) +if (LUAJIT_FOUND) include_directories(${LUAJIT_INCLUDE_DIR}) target_link_libraries(riko4 ${LUAJIT_LIBRARIES}) -endif() +endif () find_package(SDL2_gpu REQUIRED) -if(SDL2_GPU_FOUND) +if (SDL2_GPU_FOUND) include_directories(${SDL2_gpu_INCLUDE_DIR}) target_link_libraries(riko4 ${SDL2_gpu_LIBRARY}) -endif() +endif () find_package(CURL REQUIRED) -if(CURL_FOUND) +if (CURL_FOUND) include_directories(${CURL_INCLUDE_DIR}) target_link_libraries(riko4 ${CURL_LIBRARY}) -endif() +endif () find_package(CURLpp REQUIRED) -if(CURLPP_FOUND) +if (CURLPP_FOUND) include_directories(${CURLPP_INCLUDE_DIR}) target_link_libraries(riko4 ${CURLPP_LIBRARY}) -endif() +endif () include_directories(${CMAKE_SOURCE_DIR}/libs/include) include_directories(${CMAKE_SOURCE_DIR}/src/include) +if (WIN32) + target_link_libraries(riko4 ${CMAKE_SOURCE_DIR}/src/resources/icon.res) +endif () + install(TARGETS riko4 RUNTIME DESTINATION bin) diff --git a/changelog.md b/changelog.md index 938880a..823caab 100644 --- a/changelog.md +++ b/changelog.md @@ -4,9 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## 0.0.1 - 2018-11-17 +## Unreleased ### Added - This CHANGELOG file +- Resource Files for Windows Build + +### Changed +- All non-vital operands in `speaker.play` are now optional ### Fixed - Windows (Build) Support diff --git a/src/engine/audio.cpp b/src/engine/audio.cpp index e8dd156..2222397 100644 --- a/src/engine/audio.cpp +++ b/src/engine/audio.cpp @@ -9,6 +9,7 @@ #include "luaIncludes.h" #include "audio.h" +#include "../util/TableInterface.h" #ifdef __WINDOWS__ #define random() rand() @@ -280,92 +281,49 @@ namespace riko::audio { #pragma clang diagnostic pop static int aud_play(lua_State *L) { - int off = lua_gettop(L); - if (off == 0) { - luaL_error(L, "Expected table as first argument"); - return 0; - } - if (lua_type(L, -off) != LUA_TTABLE) { - luaL_error(L, "Expected table as first argument"); - return 0; - } - - lua_pushstring(L, "channel"); - lua_gettable(L, -1 - off); - auto chan = (int)luaL_checkinteger(L, -1); - - if (chan <= 0 || chan > channelCount) { - luaL_error(L, "Channel must be between 1 and %d", channelCount); - } - - lua_pushstring(L, "volume"); - lua_gettable(L, -2 - off); - double vol; - if (lua_isnil(L, -1)) { - vol = 1; - } else { - vol = lua_tonumber(L, -1); - } - - lua_pushstring(L, "frequency"); - lua_gettable(L, -3 - off); - auto freq = (int)luaL_checkinteger(L, -1); - - lua_pushstring(L, "shift"); - lua_gettable(L, -4 - off); - int freqShift; - if (lua_isnil(L, -1)) { - freqShift = 0; - } else { - freqShift = (int)lua_tointeger(L, -1); - } - - lua_pushstring(L, "time"); - lua_gettable(L, -5 - off); - double time; - if (lua_type(L, -1) != LUA_TNUMBER) { - luaL_error(L, "bad argument 'time' to 'play' (number expected, got %s)", lua_typename(L, lua_type(L, -1))); - return 0; - } else { - time = lua_tonumber(L, -1); - if (time <= 0) { - luaL_error(L, "bad argument 'time' to 'play' (number must be greater than 0)"); - return 0; + try { + TableInterface interface(L, 1); + + int chan = interface.getInteger("channel"); + int freq = interface.getInteger("frequency"); + int freqShift = interface.getInteger("shift", 0); + double vol = interface.getNumber("volume", 0.1); + double time = interface.getNumber("time"); + double atK = interface.getNumber("attack", 0); + double rls = interface.getNumber("release", 0); + + if (chan <= 0 || chan > channelCount) + interface.throwError("channel must be between 1 and " + std::to_string(channelCount)); + + if (time <= 0) + interface.throwError("time must be greater than 0"); + + if (atK < 0) + interface.throwError("attack must be greater than or equal to 0"); + + if (rls < 0) + interface.throwError("release must be greater than or equal to 0"); + + auto *pulse = new Sound; + if (chan == 5) { + pulse->frequency = (110 - (12 * (log(pow(2, 1.0 / 12) * freq / 16.35) / log(2)))); + pulse->frequencyShift = ((110 - (12 * (log(pow(2, 1.0 / 12) * (freq + freqShift) / 16.35) / log(2)))) - + pulse->frequency) / (sampleRate * time); + } else { + pulse->frequency = freq; + pulse->frequencyShift = (double) freqShift / (sampleRate * time); } - } - - lua_pushstring(L, "attack"); - lua_gettable(L, -6 - off); - double atK = luaL_checknumber(L, -1); - if (atK < 0) { - luaL_error(L, "bad argument 'attack' to 'play' (number must be greater than or equal to 0)"); - return 0; - } - - lua_pushstring(L, "release"); - lua_gettable(L, -7 - off); - double rls = luaL_checknumber(L, -1); - if (rls < 0) { - luaL_error(L, "bad argument 'release' to 'play' (number must be greater than or equal to 0)"); - return 0; - } - auto* pulse = new Sound; - if (chan == 5) { - pulse->frequency = (110 - (12 * (log(pow(2, 1.0 / 12) * freq / 16.35) / log(2)))); - pulse->frequencyShift = ((110 - (12 * (log(pow(2, 1.0 / 12) * (freq + freqShift) / 16.35) / log(2)))) - pulse->frequency) / (sampleRate * time); - } else { - pulse->frequency = freq; - pulse->frequencyShift = (double)freqShift / (sampleRate * time); + pulse->volume = vol < 0 ? 0 : (vol > 1 ? 1 : (float) vol); + pulse->totalTime = time; + pulse->attack = atK; + pulse->release = rls; + pulse->remainingCycles = (unsigned long long) (time * sampleRate); + pushToQueue(audioQueues[chan - 1], pulse); + } catch (const LuaError &e) { + luaL_error(L, e.what()); } - pulse->volume = vol < 0 ? 0 : (vol > 1 ? 1 : (float)vol); - pulse->totalTime = time; - pulse->attack = atK; - pulse->release = rls; - pulse->remainingCycles = (unsigned long long)(time * sampleRate); - pushToQueue(audioQueues[chan - 1], pulse); - return 0; } diff --git a/src/resources/icon.rc b/src/resources/icon.rc new file mode 100644 index 0000000..b517af3 --- /dev/null +++ b/src/resources/icon.rc @@ -0,0 +1,24 @@ +id ICON "icon.ico" +1 VERSIONINFO +FILEVERSION 1,0,0,0 +PRODUCTVERSION 1,0,0,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", "TMPIM" + VALUE "FileDescription", "A Fantasy Console intended as a tool for pixel art game development." + VALUE "FileVersion", "1.0" + VALUE "InternalName", "riko4" + VALUE "LegalCopyright", "Bryan Becar" + VALUE "OriginalFilename", "riko4.exe" + VALUE "ProductName", "Riko4" + VALUE "ProductVersion", "0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END \ No newline at end of file diff --git a/src/resources/icon.res b/src/resources/icon.res new file mode 100644 index 0000000..0b656d1 Binary files /dev/null and b/src/resources/icon.res differ diff --git a/src/util/LuaError.h b/src/util/LuaError.h new file mode 100644 index 0000000..17895e9 --- /dev/null +++ b/src/util/LuaError.h @@ -0,0 +1,25 @@ +#ifndef RIKO4_LUAERROR_H +#define RIKO4_LUAERROR_H + + +#include +#include +#include + +class LuaError : public std::runtime_error { +public: + enum class Type { GENERIC, NIL_ARG, BAD_TYPE }; + +private: + Type errorType = Type::GENERIC; + +public: + explicit LuaError(const std::string &error) : runtime_error(error) {} + LuaError(const std::string &error, Type errorType) : runtime_error(error), errorType(errorType) {} + + Type getErrorType() const { + return errorType; + } +}; + +#endif //RIKO4_LUAERROR_H diff --git a/src/util/TableInterface.cpp b/src/util/TableInterface.cpp new file mode 100644 index 0000000..2547b63 --- /dev/null +++ b/src/util/TableInterface.cpp @@ -0,0 +1,93 @@ +#include + +#include "TableInterface.h" + +TableInterface::TableInterface(lua_State *state, int arg) : state(state), arg(arg), offset(lua_gettop(state)) { + if (offset < arg) { + throw LuaError("expected table as argument " + std::to_string(arg) + ", got nil"); + } + + int type = lua_type(state, -offset + arg - 1); + if (type != LUA_TTABLE) { + throw LuaError("expected table as argument " + std::to_string(arg) + ", got " + lua_typename(state, type), + LuaError::Type::NIL_ARG); + } +} + +void TableInterface::throwError(std::string desc) { + if (desc.empty()) { + throw LuaError("bad element '" + lastKey + "' of argument " + std::to_string(arg)); + } else { + throw LuaError("bad element '" + lastKey + "' of argument " + std::to_string(arg) + " (" + desc + ")"); + } +} + +void TableInterface::popToStack(std::string key) { + lua_pushstring(state, key.c_str()); + lua_gettable(state, -(++offset)); + lastKey = key; +} + +double TableInterface::getNumber(std::string key) { + popToStack(key); + + double value; + if (lua_isnil(state, -1)) { + throw LuaError("expected number for element '" + key + "' of argument " + std::to_string(arg) + ", got nil", + LuaError::Type::NIL_ARG); + } else { + int type = lua_type(state, -1); + + if (type == LUA_TNUMBER) { + value = lua_tonumber(state, -1); + } else { + throw LuaError("expected number for element '" + key + "' of argument " + std::to_string(arg) + ", got " + + lua_typename(state, type), LuaError::Type::BAD_TYPE); + } + } + + return value; +} + +double TableInterface::getNumber(std::string key, double defaultValue) { + try { + return getNumber(std::move(key)); + } catch (const LuaError &e) { + if (e.getErrorType() == LuaError::Type::NIL_ARG) + return defaultValue; + else + throw e; + } +} + +int TableInterface::getInteger(std::string key) { + popToStack(key); + + int value; + if (lua_isnil(state, -1)) { + throw LuaError("expected number for element '" + key + "' of argument " + std::to_string(arg) + ", got nil", + LuaError::Type::NIL_ARG); + } else { + int type = lua_type(state, -1); + + if (type == LUA_TNUMBER) { + value = static_cast(lua_tointeger(state, -1)); + } else { + throw LuaError("expected number for element '" + key + "' of argument " + std::to_string(arg) + ", got " + + lua_typename(state, type), LuaError::Type::BAD_TYPE); + } + } + + return value; +} + +int TableInterface::getInteger(std::string key, int defaultValue) { + try { + return getInteger(std::move(key)); + } catch (const LuaError &e) { + if (e.getErrorType() == LuaError::Type::NIL_ARG) + return defaultValue; + else + throw e; + } +} diff --git a/src/util/TableInterface.h b/src/util/TableInterface.h new file mode 100644 index 0000000..b3994e5 --- /dev/null +++ b/src/util/TableInterface.h @@ -0,0 +1,32 @@ +#ifndef RIKO4_TABLEINTERFACE_H +#define RIKO4_TABLEINTERFACE_H + + +#include "luaIncludes.h" + +#include "LuaError.h" + +class TableInterface { +private: + lua_State *state; + int offset; + int arg; + + std::string lastKey = "unknown"; + + void popToStack(std::string key); + +public: + TableInterface(lua_State *state, int arg); + + void throwError(std::string desc = ""); + + double getNumber(std::string key); + double getNumber(std::string key, double defaultValue); + + int getInteger(std::string key); + int getInteger(std::string key, int defaultValue); +}; + + +#endif //RIKO4_TABLEINTERFACE_H