audio cleanup or something (because it's lagging the dreamcast build when emitting sounds)

This commit is contained in:
ecker 2025-08-24 11:38:37 -05:00
parent 9f23e22eb3
commit 532c4054b6
28 changed files with 265 additions and 110 deletions

View File

@ -2,9 +2,9 @@ ARCH = $(shell cat "./makefiles/default/arch")
CC = $(shell cat "./makefiles/default/cc")
RENDERER = $(shell cat "./makefiles/default/renderer")
TARGET_NAME = program
TARGET_EXTENSION = exe
LIB_EXTENSION = dll
LIB_EXTENSION_A = .a
TARGET_EXTENSION = .exe
DLIB_EXTENSION = .dll
SLIB_EXTENSION = .a
PREFIX = $(ARCH).$(CC)
include makefiles/$(PREFIX).make
@ -213,10 +213,15 @@ ifneq (,$(findstring lua,$(REQ_DEPS)))
FLAGS += -DUF_USE_LUAJIT
DEPS += -lluajit-5.1
# sol directly includes <luajit.h>
ifneq (,$(findstring linux,$(ARCH)))
INCS += -I/usr/include/luajit-2.1
else
INCS += -I/mingw64/include/luajit-2.1
ifneq (,$(findstring clang,$(CC)))
INCS += -I/clang64/include/luajit-2.1
else
INCS += -I/mingw64/include/luajit-2.1
endif
endif
else
ifneq (,$(findstring dreamcast,$(ARCH)))
@ -288,8 +293,8 @@ endif
SRCS_DLL := $(shell find $(ENGINE_SRC_DIR) -name "*.cpp") $(shell find $(DEP_SRC_DIR) -name "*.cpp")
OBJS_DLL += $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_DLL))
BASE_DLL += lib$(LIB_NAME)
IM_DLL += $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL).$(LIB_EXTENSION)$(LIB_EXTENSION_A)
EX_DLL += $(BIN_DIR)/exe/lib/$(PREFIX_PATH)/$(BASE_DLL).$(LIB_EXTENSION)
IM_DLL += $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL)$(DLIB_EXTENSION)
EX_DLL += $(BIN_DIR)/exe/lib/$(PREFIX_PATH)/$(BASE_DLL)$(DLIB_EXTENSION)
# External Engine's DLL
EXT_INC_DIR += $(INC_DIR)
EXT_LB_FLAGS += $(LIB_DIR)
@ -304,13 +309,13 @@ EXT_LIBS += $(LIBS)
SRCS_EXT_DLL := $(shell find $(EXT_SRC_DIR) -name "*.cpp")
OBJS_EXT_DLL += $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS_EXT_DLL))
BASE_EXT_DLL += lib$(EXT_LIB_NAME)
EXT_IM_DLL += $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL).$(LIB_EXTENSION)$(LIB_EXTENSION_A)
EXT_EX_DLL += $(BIN_DIR)/exe/lib/$(PREFIX_PATH)/$(BASE_EXT_DLL).$(LIB_EXTENSION)
EXT_IM_DLL += $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL)$(DLIB_EXTENSION)
EXT_EX_DLL += $(BIN_DIR)/exe/lib/$(PREFIX_PATH)/$(BASE_EXT_DLL)$(DLIB_EXTENSION)
# Client EXE
#SRCS += $(wildcard $(CLIENT_SRC_DIR)/*.cpp) $(wildcard $(CLIENT_SRC_DIR)/*/*.cpp)
SRCS := $(shell find $(CLIENT_SRC_DIR) -name "*.cpp")
OBJS += $(patsubst %.cpp,%.$(PREFIX).o,$(SRCS))
TARGET += $(BIN_DIR)/exe/$(TARGET_NAME).$(PREFIX).$(TARGET_EXTENSION)
TARGET += $(BIN_DIR)/exe/$(TARGET_NAME).$(PREFIX)$(TARGET_EXTENSION)
# Shaders
#SRCS_SHADERS += $(wildcard bin/data/shaders/*.glsl) $(wildcard bin/data/shaders/*/*.glsl) $(wildcard bin/data/shaders/*/*/*.glsl)
SRCS_SHADERS := $(shell find bin/data/shaders/ -name "*.glsl")
@ -337,13 +342,13 @@ $(EX_DLL): FLAGS += -DUF_EXPORTS
$(EX_DLL): $(OBJS_DLL)
$(KOS_AR) cru $@ $^
$(KOS_RANLIB) $@
cp $@ $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL)$(LIB_EXTENSION_A)
cp $@ $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL)
$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS
$(EXT_EX_DLL): $(OBJS_EXT_DLL)
$(KOS_AR) cru $@ $^
$(KOS_RANLIB) $@
cp $@ $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL)$(LIB_EXTENSION_A)
cp $@ $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL)
./bin/dreamcast/romdisk.img:
$(KOS_GENROMFS) -f ./bin/dreamcast/romdisk.img -d ./bin/dreamcast/romdisk/ -v
@ -372,7 +377,7 @@ ifneq (,$(findstring linux,$(ARCH)))
#$(EX_DLL): FLAGS += -DUF_EXPORTS -DEXT_EXPORTS
$(EX_DLL): FLAGS += -DUF_EXPORTS
$(EX_DLL): $(OBJS_DLL)
$(CXX) $(FLAGS) -shared -Wl,-soname,$(BASE_DLL).$(LIB_EXTENSION) $(OBJS_DLL) $(LIBS) $(INCS) $(LINKS) -o $(EX_DLL)
$(CXX) $(FLAGS) -shared -Wl,-soname,$(BASE_DLL)$(DLIB_EXTENSION) $(OBJS_DLL) $(LIBS) $(INCS) $(LINKS) -o $(EX_DLL)
cp $(EX_DLL) $(IM_DLL)
@echo -n $(ARCH) > "./bin/exe/default/arch"
@echo -n $(CC) > "./bin/exe/default/cc"
@ -380,7 +385,7 @@ $(EX_DLL): $(OBJS_DLL)
@echo "Setting defaults: $(ARCH).$(CC).$(RENDERER)"
$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS
$(EXT_EX_DLL): $(OBJS_EXT_DLL)
$(CXX) $(FLAGS) -shared -Wl,-soname,$(BASE_EXT_DLL).$(LIB_EXTENSION) $(OBJS_EXT_DLL) $(EXT_LIBS) $(EXT_INCS) $(EXT_LINKS) -o $(EXT_EX_DLL)
$(CXX) $(FLAGS) -shared -Wl,-soname,$(BASE_EXT_DLL)$(DLIB_EXTENSION) $(OBJS_EXT_DLL) $(EXT_LIBS) $(EXT_INCS) $(EXT_LINKS) -o $(EXT_EX_DLL)
cp $(EXT_EX_DLL) $(EXT_IM_DLL)
else
@ -388,8 +393,7 @@ else
#$(EX_DLL): FLAGS += -DUF_EXPORTS -DEXT_EXPORTS
$(EX_DLL): FLAGS += -DUF_EXPORTS
$(EX_DLL): $(OBJS_DLL)
$(CXX) $(FLAGS) -shared -o $(EX_DLL) -Wl,--out-implib=$(IM_DLL) $(OBJS_DLL) $(LIBS) $(INCS) $(LINKS)
cp $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL).$(LIB_EXTENSION).a $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_DLL).a
$(CXX) $(FLAGS) -shared -o $(EX_DLL) -Wl,--out-implib=$(IM_DLL)$(SLIB_EXTENSION) $(OBJS_DLL) $(LIBS) $(INCS) $(LINKS)
@echo -n $(ARCH) > "./bin/exe/default/arch"
@echo -n $(CC) > "./bin/exe/default/cc"
@echo -n $(RENDERER) > "./bin/exe/default/renderer"
@ -398,8 +402,8 @@ $(EX_DLL): $(OBJS_DLL)
$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS
$(EXT_EX_DLL): $(OBJS_EXT_DLL)
$(CXX) $(FLAGS) -shared -o $(EXT_EX_DLL) -Wl,--out-implib=$(EXT_IM_DLL) $(OBJS_EXT_DLL) $(EXT_LIBS) $(EXT_INCS) $(EXT_LINKS)
cp $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL).$(LIB_EXTENSION).a $(ENGINE_LIB_DIR)/$(PREFIX_PATH)/$(BASE_EXT_DLL).a
$(CXX) $(FLAGS) -shared -o $(EXT_EX_DLL) -Wl,--out-implib=$(EXT_IM_DLL)$(SLIB_EXTENSION) $(OBJS_EXT_DLL) $(EXT_LIBS) $(EXT_INCS) $(EXT_LINKS)
endif
$(TARGET): $(OBJS)

View File

@ -328,6 +328,8 @@
},
"audio": {
"mute": false,
"async update": false,
"streams by default": true,
"buffers": {
"size": 32768,
"count": 4
@ -336,8 +338,7 @@
"sfx": 0.35,
"bgm": 0.15,
"voice": 1.0
},
"streams by default": true
}
},
"memory pool": {
"enabled": true, // needs to be kept on

View File

@ -187,6 +187,7 @@ ent:bind( "tick", function(self)
-- simulate click on input press
if (inputs.key("A") or inputs.key("START") or inputs.key("Enter")) and timer:elapsed() >= INPUT_DELAY then
timer:reset()
--playSound( "buttonclickrelease" )
v:callHook("gui:Clicked.%UID%", {})
end
else

View File

@ -136,7 +136,7 @@ ent:bind( "tick", function(self)
static.alpha = 0
end
if (window.keyPressed("Escape") or inputs.key("START")) and timer:elapsed() >= INPUT_DELAY then
if window.keyPressed("Escape") and timer:elapsed() >= INPUT_DELAY then
timer:reset()
self:callHook("menu:Close.%UID%", {})
end
@ -210,6 +210,7 @@ ent:bind( "tick", function(self)
-- simulate click on input press
if (inputs.key("A") or inputs.key("START") or inputs.key("Enter")) and timer:elapsed() >= INPUT_DELAY then
timer:reset()
--playSound( "buttonclickrelease" )
v:callHook("gui:Clicked.%UID%", {})
end
else

View File

@ -17,7 +17,7 @@
},
"bgm": {
"tracks": {
"/ui/tmrwah.wav": {}
"/ui/tmrwah.ogg": {}
// "/ui/main menu.ogg": {}
// "/ui/tainted.ogg": {
// "intro": "/ui/tainted_intro.ogg",

View File

@ -24,20 +24,33 @@
"opengl": {
"validation": { "enabled": true },
"framebuffer": { "size": 1, "msaa": 1 },
"experimental": {
"rebuild on tick begin": false
},
"pipelines": {
"culling": true
"culling": false
},
"experimental": {
"rebuild on tick begin": false,
"batch queue submissions": true,
"dedicated thread": false,
"memory budget": false,
"register render modes": false
},
"invariant": {
"default stage buffers": true,
"default defer buffer destroy": true,
"default command buffer immediate": true,
"multithreaded recording": false
},
"formats": {
"depth": "D32_SFLOAT",
"color": "R8G8B8A8_UNORM",
"color": "R8G8B8A8_UNORM", // "R32G32B32A32_SFLOAT",
"normal": "R16G16B16A16_SFLOAT",
"position": "R16G16B16A16_SFLOAT"
},
"features": [],
"extensions": {
"instance": [],
"device": []
}
"extensions": { "instance": [], "device": [] }
},
"lua": {
"enabled": true,
@ -54,8 +67,9 @@
"enabled": false
},
"reactphysics": {
"timescale": 0.03333333333,
"interpolate": false,
"global storage": false,
"timescale": 0.01666666666,
"interpolate": true,
"gravity": {
"mode": "default",
"constant": 6.67408e-11
@ -69,7 +83,9 @@
}
},
"audio": {
"mute": true,
"mute": false,
"async update": false,
"streams by default": true,
"buffers": {
"size": 24576,
"count": 6
@ -78,8 +94,7 @@
"sfx": 1.0,
"bgm": 1.0,
"voice": 1.0
},
"streams by default": true
}
},
"memory pool": {
"enabled": true, // probably should be enabled
@ -100,7 +115,7 @@
},
"threads": {
"workers" : 1,
"frame limiter": 15 // "auto"
"frame limiter": 15 // 60 // "auto"
},
"debug": {
"framerate": {
@ -115,14 +130,15 @@
},
"entity": {
"delete children on destroy": false,
"delete components on destroy": false
"delete components on destroy": true
},
"userdata": {
"auto destruct": true,
"auto validate": false
},
"loader": {
"assert": true
"assert": true,
"async": true
},
"hooks": {
"defer lazy calls": true
@ -143,8 +159,8 @@
"mouse" : {
"visible" : true,
"center" : false,
"sensitivity": [ 2, 2 ],
"smoothing": [ 4, 4 ]
"sensitivity": [ 50, 50 ],
"smoothing": [ 0.25, 0.25 ]
},
"mode" : "windowed", // fullscreen, borderless, windowed
"icon" : "./data/textures/icon.png",

View File

@ -1 +1 @@
vulkan
opengl

View File

@ -106,8 +106,8 @@
#if UF_ENV_DREAMCAST
#define DC_STATS() {\
UF_MSG_DEBUG(spec::dreamcast::malloc_stats());\
UF_MSG_DEBUG(spec::dreamcast::pvr_malloc_stats());\
UF_MSG_DEBUG("{}", spec::dreamcast::malloc_stats());\
UF_MSG_DEBUG("{}", spec::dreamcast::pvr_malloc_stats());\
}
#endif

View File

@ -26,9 +26,11 @@
namespace uf {
namespace audio {
extern UF_API bool muted;
extern UF_API bool asyncUpdate;
extern UF_API bool streamsByDefault;
extern UF_API uint8_t buffers;
extern UF_API size_t bufferSize;
#if UF_AUDIO_MAPPED_VOLUMES
extern UF_API uf::stl::unordered_map<uf::stl::string, float> volumes;
#else
@ -47,6 +49,7 @@ namespace uf {
public:
bool initialized() const;
bool playing() const;
bool played() const;
void open( const uf::stl::string& );
void open( const uf::stl::string&, bool );
@ -57,6 +60,7 @@ namespace uf {
void stream( const uf::stl::string& );
void stream( const pod::PCM& );
void update();
void update( const pod::Vector3f&, const pod::Quaternion<>& );
void destroy();
void play();
@ -67,6 +71,9 @@ namespace uf {
float getTime() const;
void setTime( float );
bool spatial() const;
void setSpatial( bool );
void setPosition( const pod::Vector3f& );
void setOrientation( const pod::Quaternion<>& );

View File

@ -1,6 +1,5 @@
#pragma once
namespace uf {
class UF_API AudioEmitter {
public:
@ -24,6 +23,7 @@ namespace uf {
const container_t& get() const;
void update();
void update( const pod::Vector3f&, const pod::Quaternion<>& );
void cleanup( bool = false );
};
class UF_API MappedAudioEmitter {
@ -47,6 +47,7 @@ namespace uf {
const container_t& get() const;
void update();
void update( const pod::Vector3f&, const pod::Quaternion<>& );
void cleanup( bool = false );
};

View File

@ -51,6 +51,7 @@ namespace uf {
struct {
bool streamed = true;
bool loop = false;
bool spatial = false;
uint8_t buffers = 4;
uint8_t loopMode = 0;
} settings;

View File

@ -94,6 +94,8 @@ namespace uf {
bool UF_API exists( const uf::stl::string& );
size_t UF_API mtime( const uf::stl::string& );
bool UF_API mkdir( const uf::stl::string& );
uf::stl::string UF_API assetType( const uf::stl::string _filename );
uf::stl::string UF_API resolveURI( const uf::stl::string&, const uf::stl::string& = "" );
uf::stl::string UF_API preferred( const uf::stl::string& filename );
}
}

Binary file not shown.

View File

@ -9,11 +9,12 @@
#include <mutex>
UF_BEHAVIOR_REGISTER_CPP(ext::SoundEmitterBehavior)
UF_BEHAVIOR_TRAITS_CPP(ext::SoundEmitterBehavior, ticks = true, renders = false, multithread = true)
UF_BEHAVIOR_TRAITS_CPP(ext::SoundEmitterBehavior, ticks = false, renders = false, multithread = true)
#define this ((uf::Object*) &self)
void ext::SoundEmitterBehavior::initialize( uf::Object& self ) {
auto& metadata = this->getComponent<uf::Serializer>();
auto& emitter = this->getComponent<uf::SoundEmitter>();
//auto& emitter = this->getComponent<uf::MappedSoundEmitter>();
auto& sounds = emitter.get();
auto& scene = uf::scene::getCurrentScene();
@ -24,11 +25,10 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) {
this->addHook( "sound:Stop.%UID%", [&](ext::json::Value& json){
uf::stl::string filename = json["filename"].as<uf::stl::string>();
for ( size_t i = 0; i < sounds.size(); ++i ) {
if ( sounds[i].getFilename() != filename ) continue;
sounds[i].destroy();
sounds.erase(sounds.begin() + i);
metadata["sounds"].erase(i);
for ( auto& audio : sounds ) {
if ( audio.getFilename() != filename ) continue;
audio.stop();
audio.destroy();
}
});
this->addHook( "sound:Emit.%UID%", [&]( pod::PCM& waveform ){
@ -46,7 +46,7 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) {
if ( ext::json::isNull(json["loop"]) ) json["loop"] = metadata["audio"]["loop"];
if ( ext::json::isNull(json["streamed"]) ) json["streamed"] = metadata["audio"]["streamed"];
if ( ext::json::isNull(json["unique"]) ) json["unique"] = metadata["audio"]["unique"];
metadata["sounds"].emplace_back(json);
if ( ext::json::isNull(json["spatial"]) ) json["spatial"] = metadata["audio"]["spatial"];
uf::stl::string filename = json["filename"].as<uf::stl::string>();
bool unique = json["unique"].as<bool>();
@ -62,6 +62,7 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) {
if ( json["rolloffFactor"].is<double>() ) audio.setRolloffFactor(json["rolloffFactor"].as<float>());
if ( json["maxDistance"].is<double>() ) audio.setMaxDistance(json["maxDistance"].as<float>());
if ( json["loop"].is<bool>() ) audio.loop(json["loop"].as<bool>());
if ( json["spatial"].is<bool>() ) audio.setSpatial(json["spatial"].as<bool>());
float volume = 1.0f;
if ( json["volume"].is<double>() ) volume = json["volume"].as<float>();
@ -90,6 +91,7 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) {
});
}
void ext::SoundEmitterBehavior::tick( uf::Object& self ) {
/*
auto& transform = this->getComponent<pod::Transform<>>();
auto flatten = uf::transform::flatten( transform );
@ -101,18 +103,24 @@ void ext::SoundEmitterBehavior::tick( uf::Object& self ) {
auto& audio = sounds[i];
auto& json = metadata["sounds"][i];
if ( audio.playing() ) audio.update();
// ObjectBehavior already handles it
// if ( audio.playing() ) audio.update();
// could probably have ObjectBehavior instead handle updating the spatial but there's no way to signal it at the moment
if ( json["spatial"].as<bool>() && audio.playing() ) {
audio.setPosition( flatten.position );
audio.setOrientation( flatten.orientation );
}
if ( audio.loops() && !audio.playing() ) {
if ( !audio.playing() ) {
audio.destroy();
sounds.erase(sounds.begin() + i);
metadata["sounds"].erase(i);
--i;
}
}
emitter.cleanup();
*/
}
void ext::SoundEmitterBehavior::render( uf::Object& self ){}

View File

@ -198,6 +198,7 @@ void UF_API uf::load( ext::json::Value& json ) {
auto& configEngineAudioJson = json["engine"]["audio"];
uf::audio::muted = configEngineAudioJson["mute"].as( uf::audio::muted );
uf::audio::asyncUpdate = configEngineAudioJson["async update"].as( uf::audio::asyncUpdate );
uf::audio::streamsByDefault = configEngineAudioJson["streams by default"].as( uf::audio::streamsByDefault );
uf::audio::bufferSize = configEngineAudioJson["buffers"]["size"].as( uf::audio::bufferSize );
uf::audio::buffers = configEngineAudioJson["buffers"]["count"].as( uf::audio::buffers );

View File

@ -234,18 +234,22 @@ void uf::ObjectBehavior::destroy( uf::Object& self ) {
#endif
}
void uf::ObjectBehavior::tick( uf::Object& self ) {
auto& transform = this->getComponent<pod::Transform<>>();
auto flattened = uf::transform::flatten( transform );
// update audios
if ( this->hasComponent<uf::Audio>() ) {
auto& audio = this->getComponent<uf::Audio>();
audio.update();
audio.update( flattened.position, flattened.orientation );
}
if ( this->hasComponent<uf::SoundEmitter>() ) {
auto& audio = this->getComponent<uf::SoundEmitter>();
audio.update();
audio.update( flattened.position, flattened.orientation );
audio.cleanup();
}
if ( this->hasComponent<uf::MappedSoundEmitter>() ) {
auto& audio = this->getComponent<uf::MappedSoundEmitter>();
audio.update();
audio.update( flattened.position, flattened.orientation );
audio.cleanup();
}
if ( this->hasComponent<pod::Graph>() ) {
auto& graph = this->getComponent<pod::Graph>();

View File

@ -4,7 +4,7 @@
namespace {
unsigned long first_codepoint(const std::u8string& str) {
if (str.empty()) throw std::runtime_error("Empty string");
if (str.empty()) UF_EXCEPTION("Empty string");
const unsigned char* bytes = reinterpret_cast<const unsigned char*>(str.data());
unsigned char b0 = bytes[0];

View File

@ -1,5 +1,6 @@
#include <uf/utils/audio/audio.h>
#include <uf/utils/string/ext.h>
#include <uf/utils/thread/thread.h>
#if UF_USE_OPENAL
#include <uf/ext/openal/openal.h>
@ -11,11 +12,19 @@
bool uf::audio::muted = true;
#endif
bool uf::audio::asyncUpdate = false;
bool uf::audio::streamsByDefault = true;
uint8_t uf::audio::buffers = 4;
size_t uf::audio::bufferSize = 1024 * 16;
uf::Audio uf::audio::null;
// to-do: make this a global setting
#if UF_ENV_DREAMCAST
#define UF_AUDIO_ASYNC 0
#else
#define UF_AUDIO_ASYNC 0
#endif
#if UF_AUDIO_MAPPED_VOLUMES
uf::stl::unordered_map<uf::stl::string, float> uf::audio::volumes;
#else
@ -38,6 +47,13 @@ bool uf::Audio::playing() const {
return false;
#endif
}
bool uf::Audio::played() const {
#if UF_USE_OPENAL
return this->getDuration() > 0 && this->getTime() >= this->getDuration();
#else
return false;
#endif
}
void uf::Audio::open( const uf::stl::string& filename ) {
this->open( filename, uf::audio::streamsByDefault );
@ -82,9 +98,20 @@ void uf::Audio::stream( const pod::PCM& buffer ) {
void uf::Audio::update() {
#if UF_USE_OPENAL
if ( !this->m_metadata ) return;
ext::al::update( *this->m_metadata );
if ( !this->m_metadata->settings.streamed ) return;
if ( uf::audio::asyncUpdate ) uf::thread::queue( uf::thread::fetchWorker(), [&]{
ext::al::update( *this->m_metadata );
}); else ext::al::update( *this->m_metadata );
#endif
}
void uf::Audio::update( const pod::Vector3f& position, const pod::Quaternion<>& orientation ) {
if ( this->spatial() ) {
this->setPosition( position );
this->setOrientation( orientation );
}
this->update();
}
void uf::Audio::destroy() {
#if UF_USE_OPENAL
if ( !this->m_metadata ) return;
@ -129,6 +156,19 @@ bool uf::Audio::loops() const {
#endif
}
bool uf::Audio::spatial() const {
#if UF_USE_OPENAL
if ( !this->m_metadata ) return false;
return this->m_metadata->settings.spatial;
#endif
}
void uf::Audio::setSpatial( bool state ) {
#if UF_USE_OPENAL
if ( !this->m_metadata ) return;
this->m_metadata->settings.spatial = state;
#endif
}
float uf::Audio::getTime() const {
#if UF_USE_OPENAL
if ( !this->m_metadata ) return 0;

View File

@ -48,11 +48,22 @@ const uf::AudioEmitter::container_t& uf::AudioEmitter::get() const {
void uf::AudioEmitter::update() {
for ( auto& audio : this->m_container ) if ( audio.playing() ) audio.update();
}
void uf::AudioEmitter::update( const pod::Vector3f& position, const pod::Quaternion<>& orientation ) {
for ( auto& audio : this->m_container ) {
if ( audio.playing() ) audio.update( position, orientation );
}
}
void uf::AudioEmitter::cleanup( bool purge ) {
for ( size_t i = 0; i < this->m_container.size(); ++i ) {
if ( !purge && this->m_container[i].playing() ) continue;
this->m_container[i].destroy();
this->m_container.erase(this->m_container.begin() + i);
for ( auto it = this->m_container.begin(); it != this->m_container.end(); ) {
auto& audio = *it;
if ( purge || audio.played() ) {
audio.stop();
audio.destroy();
// because cleanup might only happen on nonplaying audio (for some reason) we're erasing here instead of just clearing the container
it = this->m_container.erase(it);
} else {
++it;
}
}
}
@ -104,10 +115,15 @@ void uf::MappedAudioEmitter::update() {
pair.second.update();
}
}
void uf::MappedAudioEmitter::update( const pod::Vector3f& position, const pod::Quaternion<>& orientation ) {
for ( auto& pair : this->m_container ) {
if ( pair.second.playing() ) pair.second.update( position, orientation );
}
}
void uf::MappedAudioEmitter::cleanup( bool purge ) {
for ( auto it = this->m_container.begin(); it != this->m_container.end(); ) {
auto& pair = *it;
if (purge || !pair.second.playing()) {
if ( purge || pair.second.played() ) {
pair.second.stop();
pair.second.destroy();
// because cleanup might only happen on nonplaying audio (for some reason) we're erasing here instead of just clearing the container

View File

@ -79,18 +79,14 @@ void uf::Image::setFilename( const uf::stl::string& filename ) {
((((uint16_t)r & 0xf8) << 8) | (((uint16_t) g & 0xfc) << 3) | ((uint16_t) b >> 3))
// from file
bool uf::Image::open( const uf::stl::string& filename, bool flip ) {
#if UF_USE_OPENGL_GLDC
uf::stl::string extension = uf::io::extension(filename);
if ( extension != "dtex" ) {
uf::stl::string dtex = uf::string::replace( filename, ".png", ".dtex" );
if ( uf::io::exists(dtex) ) return this->open(dtex, flip);
UF_MSG_WARNING("non-dtex loading is highly discouraged on this platform: {}", filename);
// return false;
}
#endif
bool uf::Image::open( const uf::stl::string& _filename, bool flip ) {
// to-do: use preferred
uf::stl::string filename = uf::io::preferred( _filename );
if ( !uf::io::exists(filename) ) UF_EXCEPTION("IO error: file does not exist: {}", filename);
#if UF_USE_OPENGL_GLDC
auto extension = uf::io::extension( filename );
if ( extension != "dtex" ) UF_MSG_WARNING("non-dtex loading is highly discouraged on this platform: {}", filename);
#endif
this->m_filename = filename;
this->m_pixels.clear();

View File

@ -279,36 +279,83 @@ bool uf::io::mkdir( const uf::stl::string& _filename ) {
return status != -1;
#endif
}
uf::stl::string uf::io::assetType( const uf::stl::string _filename ) {
// remove .gz
uf::stl::string filename = uf::string::replace( _filename, ".gz", "" );
// grab filename and extension
uf::stl::string basename = uf::io::filename( filename );
uf::stl::string extension = uf::io::extension( filename );
// a map does allocations, an if ladder is easy
if ( basename == "graph.json" ) return "model";
if ( basename == "scene.json" ) return "scene";
if ( extension == "json" ) return "entity";
if ( extension == "png" ) return "texture";
if ( extension == "glb" ) return "model";
if ( extension == "gltf" ) return "model";
if ( extension == "graph" ) return "model";
if ( extension == "ogg" ) return "audio";
if ( extension == "wav" ) return "audio";
if ( extension == "spv" ) return "shader";
if ( extension == "lua" ) return "script";
return "";
}
uf::stl::string uf::io::resolveURI( const uf::stl::string& filename, const uf::stl::string& _root ) {
uf::stl::string root = _root;
if ( filename.substr(0,8) == "https://" ) return filename;
const uf::stl::string extension = uf::io::extension(filename);
// just sanitize
if ( filename.find(uf::io::root) == 0 ) {
return uf::io::sanitize( uf::io::filename( filename ), uf::io::directory( filename ) );
return uf::io::preferred( uf::io::sanitize( uf::io::filename( filename ), uf::io::directory( filename ) ) );
}
if ( filename.find("%root%") == 0 ) {
const uf::stl::string f = uf::string::replace( filename, "%root%", uf::io::root );
return uf::io::sanitize( uf::io::filename( f ), uf::io::directory( f ) );
return uf::io::preferred( uf::io::sanitize( uf::io::filename( f ), uf::io::directory( f ) ) );
}
// if the filename contains an absolute path or if no root is provided
if ( filename[0] == '/' || root == "" ) {
const uf::stl::string basename = uf::io::filename( filename );
const uf::stl::string extensions = uf::io::extension( filename, -1 );
const uf::stl::string assetType = uf::io::assetType( filename );
if ( filename[0] == '/' && filename[1] == '/' ) root = uf::io::root;
// else if ( uf::io::extension(filename, -1) == "graph.json" ) root = uf::io::root + "/models/";
// else if ( uf::io::extension(filename, -1) == "scene.json" ) root = uf::io::root + "/scenes/";
else if ( basename == "graph.json" || basename == "graph.json.gz" ) root = uf::io::root + "/models/";
else if ( basename == "scene.json" || basename == "scene.json.gz" ) root = uf::io::root + "/scenes/";
else if ( extension == "json" || extensions == "json.gz" ) root = uf::io::root + "/entities/";
else if ( extension == "png" || extensions == "png.gz" ) root = uf::io::root + "/textures/";
else if ( extension == "glb" || extensions == "glb.gz" ) root = uf::io::root + "/models/";
else if ( extension == "gltf" || extensions == "gltf.gz" ) root = uf::io::root + "/models/";
else if ( extension == "graph" || extensions == "graph.gz" ) root = uf::io::root + "/models/";
else if ( extension == "ogg" || extensions == "ogg.gz" ) root = uf::io::root + "/audio/";
else if ( extension == "wav" || extensions == "wav.gz" ) root = uf::io::root + "/audio/";
else if ( extension == "spv" || extensions == "spv.gz" ) root = uf::io::root + "/shaders/";
else if ( extension == "lua" || extensions == "lua.gz" ) root = uf::io::root + "/scripts/";
else if ( assetType != "" ) {
if ( assetType == "model" ) root = uf::io::root + "/models/";
else if ( assetType == "scene" ) root = uf::io::root + "/scenes/";
else if ( assetType == "entity" ) root = uf::io::root + "/entities/";
else if ( assetType == "texture" ) root = uf::io::root + "/textures/";
else if ( assetType == "audio" ) root = uf::io::root + "/audio/";
else if ( assetType == "shader" ) root = uf::io::root + "/shaders/";
else if ( assetType == "script" ) root = uf::io::root + "/scripts/";
else root = uf::io::root + "/" + assetType + "/";
}
}
return uf::io::sanitize(filename, root);
return uf::io::preferred( uf::io::sanitize( filename, root ) );
}
// attempts to coerce files into a preferred one if it exists
uf::stl::string uf::io::preferred( const uf::stl::string& filename ) {
// remove .gz
auto extension = "." + uf::io::extension( uf::string::replace( filename, ".gz", "" ) );
auto preferredExtension = extension;
// deduce asset type
auto assetType = uf::io::assetType( extension );
// to-do: make this config.json defineable
#if UF_ENV_DREAMCAST
if ( assetType == "texture" ) preferredExtension = ".dtex";
else if ( assetType == "audio" ) preferredExtension = ".ogg";
#else
if ( assetType == "texture" ) preferredExtension = ".png";
else if ( assetType == "audio" ) preferredExtension = ".ogg";
#endif
// no change
if ( extension == preferredExtension ) return filename;
// create preferred path
uf::stl::string preferredPath = uf::string::replace( filename, extension, preferredExtension );
// pick it if exists
return uf::io::exists( preferredPath ) ? preferredPath : filename;
}

View File

@ -3,9 +3,12 @@ CDIR =
CC = gcc
CXX = $(KOS_CCPLUS)
RENDERER = opengl
TARGET_EXTENSION = elf
OPTIMIZATIONS = -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -fstrict-aliasing -ffast-math -fno-unroll-all-loops -fno-optimize-sibling-calls -fschedule-insns2 -fomit-frame-pointer -DUF_NO_EXCEPTIONS -fno-exceptions -g # -flto
WARNINGS = -Wall -Wno-unknown-pragmas -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation -Wno-attributes -Wno-conversion-null
FLAGS += $(KOS_CPPFLAGS) -m4-single -std=c++17 $(OPTIMIZATIONS) $(WARNINGS) -fdiagnostics-color=always
FLAGS += $(KOS_CPPFLAGS) -m4-single -std=c++2b $(OPTIMIZATIONS) $(WARNINGS) -fdiagnostics-color=always
TARGET_EXTENSION = .elf
# KOS
INCS += $(KOS_INC_PATHS) -I/opt/dreamcast/sh-elf/sh-elf/include
LIBS += $(KOS_LIB_PATHS) -L/opt/dreamcast/sh-elf/sh-elf/lib

View File

@ -7,5 +7,6 @@ WARNINGS = -Wall -Wno-pointer-arith -Wno-unused-function -Wno-unused-variable
SANITIZE = -fsanitize=address # -fuse-ld=lld -fno-omit-frame-pointer
FLAGS += -std=c++2b $(OPTIMIZATIONS) $(WARNINGS) $(SANITIZE) -fcolor-diagnostics -fansi-escape-codes
LIB_EXTENSION = so
LIB_EXTENSION_A =
TARGET_EXTENSION =
DLIB_EXTENSION = .so
SLIB_EXTENSION =

View File

@ -6,5 +6,6 @@ OPTIMIZATIONS = -O3 -fstrict-aliasing -DUF_NO_EXCEPTIONS
WARNINGS = -Wall -Wno-attributes -Wno-dangling-reference -Wno-unknown-pragmas -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation
FLAGS += -std=c++2b $(OPTIMIZATIONS) $(WARNINGS) -fdiagnostics-color=always
LIB_EXTENSION = so
LIB_EXTENSION_A =
TARGET_EXTENSION =
DLIB_EXTENSION = .so
SLIB_EXTENSION =

View File

@ -5,4 +5,12 @@ CXX = clang++
OPTIMIZATIONS = -O3 -fstrict-aliasing -DUF_NO_EXCEPTIONS # -flto # -march=native
WARNINGS = -Wall -Wno-deprecated-literal-operator -Wno-pointer-arith -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder-ctor -Wno-ignored-attributes -Wno-c++11-narrowing -Wno-unknown-pragmas -Wno-nullability-completeness -Wno-defaulted-function-deleted -Wno-mismatched-tags
SANITIZE = -fsanitize=address # -fuse-ld=lld -fno-omit-frame-pointer
FLAGS += -std=c++2b $(OPTIMIZATIONS) $(WARNINGS) $(SANITIZE) -fcolor-diagnostics -fansi-escape-codes
FLAGS += -std=c++2b $(OPTIMIZATIONS) $(WARNINGS) $(SANITIZE) -fcolor-diagnostics -fansi-escape-codes
# MSYS2
INCS += -I/clang64/include/
LIBS += -L/clang64/lib/ -L/mingw64/lib/
TARGET_EXTENSION = .exe
DLIB_EXTENSION = .dll
SLIB_EXTENSION = .a

View File

@ -4,4 +4,13 @@ CC = gcc
CXX = g++
OPTIMIZATIONS = -O3 -fstrict-aliasing -DUF_NO_EXCEPTIONS
WARNINGS = -Wall -Wno-unknown-pragmas -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation
FLAGS += -std=c++2b $(OPTIMIZATIONS) $(WARNINGS) -fdiagnostics-color=always
FLAGS += -std=c++2b $(OPTIMIZATIONS) $(WARNINGS) -fdiagnostics-color=always
# MSYS2
INCS += -I/mingw64/include/
LIBS += -I/mingw64/lib/
TARGET_EXTENSION = .exe
DLIB_EXTENSION = .dll
SLIB_EXTENSION = .a

View File

@ -1,5 +0,0 @@
ARCH = win64
CDIR = /opt/mingw-w64/x86_64-7.2.0-posix-seh-rt_v5-rev1/mingw64/bin/
CC = gcc7
CXX = g++
FLAGS += -Wno-unknown-pragmas -std=c++17 -Og -g -fdiagnostics-color=always -Wall -Wno-conversion-null -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation

View File

@ -1,8 +0,0 @@
ARCH = win64
CDIR = /tdm-gcc/bin/
CC = gcc
CXX = g++
OPTIMIZATIONS = -O3 -fstrict-aliasing # -flto
WARNINGS = -Wall -Wno-pointer-arith -Wno-unknown-pragmas -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation
FLAGS = -std=c++17 $(OPTIMIZATIONS) $(WARNINGS) -fdiagnostics-color=always
PREFIX = $(ARCH).tdm-gcc