mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-24 13:44:58 +00:00
sound work
This commit is contained in:
@@ -78,12 +78,14 @@ find_package(CLI11 CONFIG REQUIRED)
|
||||
find_package(rapidjson CONFIG REQUIRED)
|
||||
find_package(assimp CONFIG REQUIRED)
|
||||
find_package(Bullet CONFIG REQUIRED)
|
||||
find_package(Vorbis CONFIG REQUIRED)
|
||||
find_package(glm CONFIG REQUIRED)
|
||||
|
||||
if(BUILD_SDL3_APP)
|
||||
add_executable(sdl3_app
|
||||
src/main.cpp
|
||||
src/app/sdl3_app_core.cpp
|
||||
src/app/audio_player.cpp
|
||||
src/app/sdl3_app_device.cpp
|
||||
src/app/sdl3_app_swapchain.cpp
|
||||
src/app/sdl3_app_pipeline.cpp
|
||||
@@ -95,7 +97,7 @@ add_executable(sdl3_app
|
||||
src/script/cube_script.cpp
|
||||
)
|
||||
target_include_directories(sdl3_app PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
target_link_libraries(sdl3_app PRIVATE sdl::sdl Vulkan::Vulkan lua::lua CLI11::CLI11 rapidjson assimp::assimp Bullet::Bullet glm::glm)
|
||||
target_link_libraries(sdl3_app PRIVATE sdl::sdl Vulkan::Vulkan lua::lua CLI11::CLI11 rapidjson assimp::assimp Bullet::Bullet glm::glm Vorbis::vorbisfile Vorbis::vorbis)
|
||||
target_compile_definitions(sdl3_app PRIVATE SDL_MAIN_HANDLED)
|
||||
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/shaders" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
@@ -109,5 +111,5 @@ add_executable(cube_script_tests
|
||||
src/script/cube_script.cpp
|
||||
)
|
||||
target_include_directories(cube_script_tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
target_link_libraries(cube_script_tests PRIVATE lua::lua assimp::assimp Bullet::Bullet glm::glm)
|
||||
target_link_libraries(cube_script_tests PRIVATE lua::lua assimp::assimp Bullet::Bullet glm::glm Vorbis::vorbisfile Vorbis::vorbis)
|
||||
add_test(NAME cube_script_tests COMMAND cube_script_tests)
|
||||
|
||||
@@ -28,3 +28,4 @@ class SDL3CppConan(ConanFile):
|
||||
self.requires("box2d/3.1.1")
|
||||
self.requires("assimp/6.0.2")
|
||||
self.requires("glm/1.0.1")
|
||||
self.requires("vorbis/1.3.7")
|
||||
|
||||
59
scripts/convert_mod_to_ogg.py
Normal file
59
scripts/convert_mod_to_ogg.py
Normal file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Convert the bundled XM tracker file to an OGG so the demo can play music."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import shlex
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import imageio_ffmpeg
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Convert scripts/modmusic.xm into OGG.")
|
||||
parser.add_argument(
|
||||
"--input",
|
||||
type=Path,
|
||||
default=Path(__file__).parent / "modmusic.xm",
|
||||
help="Tracker file to render (default: scripts/modmusic.xm).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
type=Path,
|
||||
default=Path(__file__).parent / "modmusic.ogg",
|
||||
help="Path for the rendered OGG (default next to scripts/modmusic.xm).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--bitrate",
|
||||
default="192k",
|
||||
help="FFmpeg audio bitrate (default: 192k).",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
if not args.input.exists():
|
||||
raise SystemExit(f"Error: XM source {args.input} is missing")
|
||||
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
ffmpeg_path = imageio_ffmpeg.get_ffmpeg_exe()
|
||||
|
||||
ffmpeg_cmd = [
|
||||
ffmpeg_path,
|
||||
"-y",
|
||||
"-i",
|
||||
str(args.input),
|
||||
"-b:a",
|
||||
args.bitrate,
|
||||
str(args.output),
|
||||
]
|
||||
|
||||
print("Executing:", " ".join(shlex.quote(arg) for arg in ffmpeg_cmd))
|
||||
subprocess.run(ffmpeg_cmd, check=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
scripts/modmusic.ogg
Normal file
BIN
scripts/modmusic.ogg
Normal file
Binary file not shown.
125
src/app/audio_player.cpp
Normal file
125
src/app/audio_player.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#include "app/audio_player.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <vorbis/vorbisfile.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace sdl3cpp::app {
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<int16_t> DecodeOgg(const std::filesystem::path& path, int& rate, int& channels) {
|
||||
FILE* file = std::fopen(path.string().c_str(), "rb");
|
||||
if (!file) {
|
||||
throw std::runtime_error("Failed to open audio file: " + path.string());
|
||||
}
|
||||
|
||||
OggVorbis_File oggFile{};
|
||||
if (ov_open(file, &oggFile, nullptr, 0) < 0) {
|
||||
std::fclose(file);
|
||||
throw std::runtime_error("Failed to open OGG stream: " + path.string());
|
||||
}
|
||||
|
||||
vorbis_info* info = ov_info(&oggFile, -1);
|
||||
if (!info) {
|
||||
ov_clear(&oggFile);
|
||||
throw std::runtime_error("Audio metadata is missing");
|
||||
}
|
||||
channels = info->channels;
|
||||
rate = static_cast<int>(info->rate);
|
||||
|
||||
std::vector<int16_t> decoded;
|
||||
decoded.reserve(static_cast<size_t>(ov_pcm_total(&oggFile, -1)) * channels);
|
||||
int bitstream = 0;
|
||||
constexpr size_t kChunkBytes = 4096 * sizeof(int16_t);
|
||||
std::vector<char> chunk(kChunkBytes);
|
||||
|
||||
while (true) {
|
||||
long bytesRead = ov_read(&oggFile, chunk.data(), static_cast<int>(chunk.size()), 0, 2, 1, &bitstream);
|
||||
if (bytesRead == 0) {
|
||||
break;
|
||||
}
|
||||
if (bytesRead < 0) {
|
||||
ov_clear(&oggFile);
|
||||
throw std::runtime_error("Error decoding OGG stream");
|
||||
}
|
||||
size_t samples = static_cast<size_t>(bytesRead) / sizeof(int16_t);
|
||||
size_t oldSize = decoded.size();
|
||||
decoded.resize(oldSize + samples);
|
||||
std::memcpy(decoded.data() + oldSize, chunk.data(), samples * sizeof(int16_t));
|
||||
}
|
||||
|
||||
ov_clear(&oggFile);
|
||||
if (decoded.empty()) {
|
||||
throw std::runtime_error("Decoded audio is empty");
|
||||
}
|
||||
return decoded;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AudioPlayer::AudioPlayer(const std::filesystem::path& oggPath) {
|
||||
int sampleRate = 0;
|
||||
int channelCount = 0;
|
||||
buffer_ = DecodeOgg(oggPath, sampleRate, channelCount);
|
||||
bufferSizeBytes_ = buffer_.size() * sizeof(int16_t);
|
||||
|
||||
SDL_AudioSpec desired{};
|
||||
desired.freq = sampleRate;
|
||||
desired.format = SDL_AUDIO_S16;
|
||||
desired.channels = channelCount;
|
||||
|
||||
stream_ = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &desired, &AudioPlayer::AudioStreamCallback, this);
|
||||
if (!stream_) {
|
||||
throw std::runtime_error("Failed to open audio stream: " + std::string(SDL_GetError()));
|
||||
}
|
||||
if (!SDL_ResumeAudioStreamDevice(stream_)) {
|
||||
SDL_DestroyAudioStream(stream_);
|
||||
stream_ = nullptr;
|
||||
throw std::runtime_error("Failed to resume audio stream device: " + std::string(SDL_GetError()));
|
||||
}
|
||||
}
|
||||
|
||||
AudioPlayer::~AudioPlayer() {
|
||||
if (stream_) {
|
||||
SDL_PauseAudioStreamDevice(stream_);
|
||||
SDL_DestroyAudioStream(stream_);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioPlayer::AudioStreamCallback(void* userdata, SDL_AudioStream* stream, int additionalAmount, int totalAmount) {
|
||||
auto* self = static_cast<AudioPlayer*>(userdata);
|
||||
self->FeedStream(stream, totalAmount);
|
||||
}
|
||||
|
||||
void AudioPlayer::FeedStream(SDL_AudioStream* stream, int totalAmount) {
|
||||
if (totalAmount <= 0 || bufferSizeBytes_ == 0) {
|
||||
return;
|
||||
}
|
||||
const auto* source = reinterpret_cast<const uint8_t*>(buffer_.data());
|
||||
int remaining = totalAmount;
|
||||
while (remaining > 0) {
|
||||
if (positionBytes_ >= bufferSizeBytes_) {
|
||||
positionBytes_ = 0;
|
||||
}
|
||||
size_t available = bufferSizeBytes_ - positionBytes_;
|
||||
if (available == 0) {
|
||||
positionBytes_ = 0;
|
||||
continue;
|
||||
}
|
||||
size_t chunk = std::min<size_t>(available, static_cast<size_t>(remaining));
|
||||
int queued = SDL_PutAudioStreamData(stream, source + positionBytes_, static_cast<int>(chunk));
|
||||
if (queued <= 0) {
|
||||
break;
|
||||
}
|
||||
positionBytes_ += static_cast<size_t>(queued);
|
||||
remaining -= queued;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::app
|
||||
33
src/app/audio_player.hpp
Normal file
33
src/app/audio_player.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef SDL3CPP_APP_AUDIO_PLAYER_HPP
|
||||
#define SDL3CPP_APP_AUDIO_PLAYER_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
namespace sdl3cpp::app {
|
||||
|
||||
class AudioPlayer {
|
||||
public:
|
||||
explicit AudioPlayer(const std::filesystem::path& oggPath);
|
||||
~AudioPlayer();
|
||||
|
||||
AudioPlayer(const AudioPlayer&) = delete;
|
||||
AudioPlayer& operator=(const AudioPlayer&) = delete;
|
||||
|
||||
private:
|
||||
static void AudioStreamCallback(void* userdata, SDL_AudioStream* stream, int additionalAmount, int totalAmount);
|
||||
void FeedStream(SDL_AudioStream* stream, int totalAmount);
|
||||
|
||||
SDL_AudioStream* stream_ = nullptr;
|
||||
std::vector<int16_t> buffer_;
|
||||
size_t positionBytes_ = 0;
|
||||
size_t bufferSizeBytes_ = 0;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::app
|
||||
|
||||
#endif // SDL3CPP_APP_AUDIO_PLAYER_HPP
|
||||
@@ -18,10 +18,15 @@
|
||||
#include <SDL3/SDL_vulkan.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "app/audio_player.hpp"
|
||||
#include "core/vertex.hpp"
|
||||
#include "script/cube_script.hpp"
|
||||
#include "gui/gui_renderer.hpp"
|
||||
|
||||
namespace sdl3cpp::app {
|
||||
class AudioPlayer;
|
||||
}
|
||||
|
||||
namespace sdl3cpp::app {
|
||||
|
||||
namespace script = sdl3cpp::script;
|
||||
@@ -135,6 +140,8 @@ private:
|
||||
std::unique_ptr<gui::GuiRenderer> guiRenderer_;
|
||||
bool guiHasCommands_ = false;
|
||||
std::vector<RenderObject> renderObjects_;
|
||||
std::filesystem::path scriptDirectory_;
|
||||
std::unique_ptr<AudioPlayer> audioPlayer_;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::app
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "app/audio_player.hpp"
|
||||
#include "app/sdl3_app.hpp"
|
||||
#include "app/trace.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -82,7 +84,8 @@ void ThrowSdlErrorIfFailed(bool success, const char* context) {
|
||||
} // namespace
|
||||
|
||||
Sdl3App::Sdl3App(const std::filesystem::path& scriptPath, bool luaDebug)
|
||||
: cubeScript_(scriptPath, luaDebug) {
|
||||
: cubeScript_(scriptPath, luaDebug),
|
||||
scriptDirectory_(scriptPath.parent_path()) {
|
||||
TRACE_FUNCTION();
|
||||
TRACE_VAR(scriptPath);
|
||||
}
|
||||
@@ -99,7 +102,7 @@ void Sdl3App::InitSDL() {
|
||||
TRACE_FUNCTION();
|
||||
TRACE_VAR(kWidth);
|
||||
TRACE_VAR(kHeight);
|
||||
ThrowSdlErrorIfFailed(SDL_Init(SDL_INIT_VIDEO), "SDL_Init failed");
|
||||
ThrowSdlErrorIfFailed(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO), "SDL_Init failed");
|
||||
ThrowSdlErrorIfFailed(SDL_Vulkan_LoadLibrary(nullptr), "SDL_Vulkan_LoadLibrary failed");
|
||||
window_ = SDL_CreateWindow("SDL3 Vulkan Demo", kWidth, kHeight, SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE);
|
||||
if (!window_) {
|
||||
@@ -107,6 +110,11 @@ void Sdl3App::InitSDL() {
|
||||
}
|
||||
TRACE_VAR(window_);
|
||||
SDL_StartTextInput(window_);
|
||||
try {
|
||||
audioPlayer_ = std::make_unique<AudioPlayer>(scriptDirectory_ / "modmusic.ogg");
|
||||
} catch (const std::exception& exc) {
|
||||
std::cerr << "AudioPlayer: " << exc.what() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void Sdl3App::InitVulkan() {
|
||||
@@ -188,6 +196,7 @@ void Sdl3App::Cleanup() {
|
||||
}
|
||||
SDL_Vulkan_UnloadLibrary();
|
||||
SDL_StopTextInput(window_);
|
||||
audioPlayer_.reset();
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
|
||||
namespace sdl3cpp::script {
|
||||
|
||||
namespace {
|
||||
|
||||
struct PhysicsBridge {
|
||||
struct BodyRecord {
|
||||
std::unique_ptr<btCollisionShape> shape;
|
||||
@@ -137,6 +135,69 @@ bool PhysicsBridge::getRigidBodyTransform(const std::string& name,
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
std::array<float, 3> ReadVector3(lua_State* L, int index) {
|
||||
std::array<float, 3> result{};
|
||||
int absIndex = lua_absindex(L, index);
|
||||
size_t len = lua_rawlen(L, absIndex);
|
||||
if (len != 3) {
|
||||
throw std::runtime_error("Expected vector with 3 components");
|
||||
}
|
||||
for (size_t i = 1; i <= 3; ++i) {
|
||||
lua_rawgeti(L, absIndex, static_cast<int>(i));
|
||||
if (!lua_isnumber(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Vector component is not a number");
|
||||
}
|
||||
result[i - 1] = static_cast<float>(lua_tonumber(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::array<float, 16> ReadMatrix(lua_State* L, int index) {
|
||||
std::array<float, 16> result{};
|
||||
int absIndex = lua_absindex(L, index);
|
||||
size_t len = lua_rawlen(L, absIndex);
|
||||
if (len != 16) {
|
||||
throw std::runtime_error("Expected 4x4 matrix with 16 components");
|
||||
}
|
||||
for (size_t i = 1; i <= 16; ++i) {
|
||||
lua_rawgeti(L, absIndex, static_cast<int>(i));
|
||||
if (!lua_isnumber(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Matrix component is not a number");
|
||||
}
|
||||
result[i - 1] = static_cast<float>(lua_tonumber(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::array<float, 4> ReadQuaternion(lua_State* L, int index) {
|
||||
std::array<float, 4> result{};
|
||||
int absIndex = lua_absindex(L, index);
|
||||
size_t len = lua_rawlen(L, absIndex);
|
||||
if (len != 4) {
|
||||
throw std::runtime_error("Expected quaternion with 4 components");
|
||||
}
|
||||
for (size_t i = 1; i <= 4; ++i) {
|
||||
lua_rawgeti(L, absIndex, static_cast<int>(i));
|
||||
if (!lua_isnumber(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Quaternion component is not a number");
|
||||
}
|
||||
result[i - 1] = static_cast<float>(lua_tonumber(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace {
|
||||
|
||||
struct MeshPayload {
|
||||
std::vector<std::array<float, 3>> positions;
|
||||
std::vector<std::array<float, 3>> colors;
|
||||
@@ -190,9 +251,9 @@ bool TryLoadMeshPayload(const CubeScript* script,
|
||||
aiColor3D materialColor = defaultColor;
|
||||
if (mesh->mMaterialIndex < scene->mNumMaterials) {
|
||||
const aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
|
||||
aiColor3D diffuse;
|
||||
aiColor4D diffuse;
|
||||
if (material && material->Get(AI_MATKEY_COLOR_DIFFUSE, diffuse) == AI_SUCCESS) {
|
||||
materialColor = diffuse;
|
||||
materialColor = aiColor3D(diffuse.r, diffuse.g, diffuse.b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +263,8 @@ bool TryLoadMeshPayload(const CubeScript* script,
|
||||
|
||||
aiColor3D color = materialColor;
|
||||
if (mesh->HasVertexColors(0) && mesh->mColors[0]) {
|
||||
color = mesh->mColors[0][i];
|
||||
const aiColor4D& vertexColor = mesh->mColors[0][i];
|
||||
color = aiColor3D(vertexColor.r, vertexColor.g, vertexColor.b);
|
||||
}
|
||||
payload.colors.push_back({color.r, color.g, color.b});
|
||||
}
|
||||
@@ -298,10 +360,10 @@ int LuaPhysicsCreateBox(lua_State* L) {
|
||||
if (!lua_istable(L, 2) || !lua_istable(L, 4) || !lua_istable(L, 5)) {
|
||||
luaL_error(L, "physics_create_box expects vector tables for half extents, origin, and rotation");
|
||||
}
|
||||
std::array<float, 3> halfExtents = ReadVector3(L, 2);
|
||||
std::array<float, 3> halfExtents = detail::ReadVector3(L, 2);
|
||||
float mass = static_cast<float>(luaL_checknumber(L, 3));
|
||||
std::array<float, 3> origin = ReadVector3(L, 4);
|
||||
std::array<float, 4> rotation = ReadQuaternion(L, 5);
|
||||
std::array<float, 3> origin = detail::ReadVector3(L, 4);
|
||||
std::array<float, 4> rotation = detail::ReadQuaternion(L, 5);
|
||||
|
||||
btTransform transform;
|
||||
transform.setIdentity();
|
||||
@@ -370,8 +432,8 @@ int LuaPhysicsGetTransform(lua_State* L) {
|
||||
}
|
||||
|
||||
int LuaGlmMatrixFromTransform(lua_State* L) {
|
||||
std::array<float, 3> translation = CubeScript::ReadVector3(L, 1);
|
||||
std::array<float, 4> rotation = CubeScript::ReadQuaternion(L, 2);
|
||||
std::array<float, 3> translation = detail::ReadVector3(L, 1);
|
||||
std::array<float, 4> rotation = detail::ReadQuaternion(L, 2);
|
||||
glm::vec3 pos = ToVec3(translation);
|
||||
glm::quat quat = ToQuat(rotation);
|
||||
glm::mat4 matrix = glm::translate(glm::mat4(1.0f), pos) * glm::mat4_cast(quat);
|
||||
@@ -553,7 +615,7 @@ std::array<float, 16> CubeScript::ComputeModelMatrix(int functionRef, float time
|
||||
throw std::runtime_error("'compute_model_matrix' did not return a table");
|
||||
}
|
||||
|
||||
std::array<float, 16> matrix = ReadMatrix(L_, -1);
|
||||
std::array<float, 16> matrix = detail::ReadMatrix(L_, -1);
|
||||
lua_pop(L_, 1);
|
||||
return matrix;
|
||||
}
|
||||
@@ -574,7 +636,7 @@ std::array<float, 16> CubeScript::GetViewProjectionMatrix(float aspect) {
|
||||
lua_pop(L_, 1);
|
||||
throw std::runtime_error("'get_view_projection' did not return a table");
|
||||
}
|
||||
std::array<float, 16> matrix = ReadMatrix(L_, -1);
|
||||
std::array<float, 16> matrix = detail::ReadMatrix(L_, -1);
|
||||
lua_pop(L_, 1);
|
||||
return matrix;
|
||||
}
|
||||
@@ -600,11 +662,11 @@ std::vector<core::Vertex> CubeScript::ReadVertexArray(lua_State* L, int index) {
|
||||
core::Vertex vertex{};
|
||||
|
||||
lua_getfield(L, vertexIndex, "position");
|
||||
vertex.position = ReadVector3(L, -1);
|
||||
vertex.position = detail::ReadVector3(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_getfield(L, vertexIndex, "color");
|
||||
vertex.color = ReadVector3(L, -1);
|
||||
vertex.color = detail::ReadVector3(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_pop(L, 1);
|
||||
@@ -697,63 +759,6 @@ CubeScript::ShaderPaths CubeScript::ReadShaderPathsTable(lua_State* L, int index
|
||||
return paths;
|
||||
}
|
||||
|
||||
std::array<float, 3> CubeScript::ReadVector3(lua_State* L, int index) {
|
||||
std::array<float, 3> result{};
|
||||
int absIndex = lua_absindex(L, index);
|
||||
size_t len = lua_rawlen(L, absIndex);
|
||||
if (len != 3) {
|
||||
throw std::runtime_error("Expected vector with 3 components");
|
||||
}
|
||||
for (size_t i = 1; i <= 3; ++i) {
|
||||
lua_rawgeti(L, absIndex, static_cast<int>(i));
|
||||
if (!lua_isnumber(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Vector component is not a number");
|
||||
}
|
||||
result[i - 1] = static_cast<float>(lua_tonumber(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::array<float, 16> CubeScript::ReadMatrix(lua_State* L, int index) {
|
||||
std::array<float, 16> result{};
|
||||
int absIndex = lua_absindex(L, index);
|
||||
size_t len = lua_rawlen(L, absIndex);
|
||||
if (len != 16) {
|
||||
throw std::runtime_error("Expected 4x4 matrix with 16 components");
|
||||
}
|
||||
for (size_t i = 1; i <= 16; ++i) {
|
||||
lua_rawgeti(L, absIndex, static_cast<int>(i));
|
||||
if (!lua_isnumber(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Matrix component is not a number");
|
||||
}
|
||||
result[i - 1] = static_cast<float>(lua_tonumber(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::array<float, 4> CubeScript::ReadQuaternion(lua_State* L, int index) {
|
||||
std::array<float, 4> result{};
|
||||
int absIndex = lua_absindex(L, index);
|
||||
size_t len = lua_rawlen(L, absIndex);
|
||||
if (len != 4) {
|
||||
throw std::runtime_error("Expected quaternion with 4 components");
|
||||
}
|
||||
for (size_t i = 1; i <= 4; ++i) {
|
||||
lua_rawgeti(L, absIndex, static_cast<int>(i));
|
||||
if (!lua_isnumber(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
throw std::runtime_error("Quaternion component is not a number");
|
||||
}
|
||||
result[i - 1] = static_cast<float>(lua_tonumber(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string CubeScript::LuaErrorMessage(lua_State* L) {
|
||||
const char* message = lua_tostring(L, -1);
|
||||
return message ? message : "unknown lua error";
|
||||
|
||||
@@ -97,9 +97,6 @@ public:
|
||||
PhysicsBridge& GetPhysicsBridge();
|
||||
|
||||
private:
|
||||
static std::array<float, 3> ReadVector3(lua_State* L, int index);
|
||||
static std::array<float, 16> ReadMatrix(lua_State* L, int index);
|
||||
static std::array<float, 4> ReadQuaternion(lua_State* L, int index);
|
||||
static std::vector<core::Vertex> ReadVertexArray(lua_State* L, int index);
|
||||
static std::vector<uint16_t> ReadIndexArray(lua_State* L, int index);
|
||||
static std::string LuaErrorMessage(lua_State* L);
|
||||
|
||||
Reference in New Issue
Block a user