audio WIP
This commit is contained in:
parent
629c4da6bb
commit
71ac25755c
17 changed files with 482 additions and 165 deletions
|
@ -5,6 +5,7 @@ namespace Lumix
|
|||
{
|
||||
|
||||
|
||||
class Clip;
|
||||
class Engine;
|
||||
class IAllocator;
|
||||
class Path;
|
||||
|
@ -13,28 +14,28 @@ class Path;
|
|||
namespace Audio
|
||||
{
|
||||
|
||||
enum class ClipFlags
|
||||
{
|
||||
IS3D,
|
||||
enum class BufferFlags
|
||||
{
|
||||
IS3D = 1
|
||||
};
|
||||
|
||||
COUNT
|
||||
};
|
||||
typedef void* BufferHandle;
|
||||
static const BufferHandle INVALID_BUFFER_HANDLE = nullptr;
|
||||
|
||||
bool init(Engine& engine, IAllocator& allocator);
|
||||
void shutdown();
|
||||
|
||||
bool init(Engine& engine, IAllocator& allocator);
|
||||
void shutdown();
|
||||
|
||||
typedef void* ClipHandle;
|
||||
ClipHandle load(const Path& path, const void* data, int size, int channels, int sample_rate, int flags);
|
||||
void unload(ClipHandle clip);
|
||||
void play(ClipHandle clip);
|
||||
void stop(ClipHandle clip);
|
||||
void pause(ClipHandle clip);
|
||||
void setVolume(ClipHandle clip, float volume);
|
||||
void setFrequency(ClipHandle clip, float frequency);
|
||||
void setCurrentPosition(ClipHandle clip, float time_seconds);
|
||||
void setListenerPosition(int index, float x, float y, float z);
|
||||
void setSourcePosition(ClipHandle clip, float x, float y, float z);
|
||||
BufferHandle createBuffer(const void* data, int size_bytes, int channels, int sample_rate, int flags);
|
||||
void destroyBuffer(BufferHandle buffer);
|
||||
void play(BufferHandle buffer);
|
||||
void stop(BufferHandle buffer);
|
||||
void pause(BufferHandle buffer);
|
||||
void setVolume(BufferHandle buffer, float volume);
|
||||
void setFrequency(BufferHandle buffer, float frequency);
|
||||
void setCurrentTime(BufferHandle buffer, float time_seconds);
|
||||
void setListenerPosition(int index, float x, float y, float z);
|
||||
void setSourcePosition(BufferHandle buffer, float x, float y, float z);
|
||||
void update(float time_delta);
|
||||
|
||||
} // namespace Audio
|
||||
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
#include "audio_scene.h"
|
||||
#include "audio_device.h"
|
||||
#include "audio_system.h"
|
||||
#include "clip_manager.h"
|
||||
#include "core/blob.h"
|
||||
#include "core/crc32.h"
|
||||
#include "core/iallocator.h"
|
||||
#include "core/resource_manager.h"
|
||||
#include "core/resource_manager_base.h"
|
||||
#include "universe/universe.h"
|
||||
|
||||
|
||||
|
@ -10,13 +14,9 @@ namespace Lumix
|
|||
{
|
||||
|
||||
|
||||
namespace Audio
|
||||
{
|
||||
|
||||
|
||||
static const uint32 SOURCE_HASH = crc32("source");
|
||||
static const uint32 LISTENER_HASH = crc32("listener");
|
||||
static const int MAX_LISTENERS_COUNT = 1;
|
||||
static const uint32 LISTENER_HASH = crc32("audio_listener");
|
||||
static const uint32 CLIP_RESOURCE_HASH = crc32("CLIP");
|
||||
static const int MAX_PLAYING_SOUNDS = 256;
|
||||
|
||||
|
||||
struct Listener
|
||||
|
@ -32,66 +32,86 @@ struct Source
|
|||
};
|
||||
|
||||
|
||||
struct PlayingSound
|
||||
{
|
||||
Lumix::Audio::BufferHandle buffer_id;
|
||||
Entity entity;
|
||||
};
|
||||
|
||||
|
||||
struct ClipInfo
|
||||
{
|
||||
Clip* clip;
|
||||
char name[30];
|
||||
uint32 name_hash;
|
||||
int index;
|
||||
};
|
||||
|
||||
|
||||
struct AudioSceneImpl : public AudioScene
|
||||
{
|
||||
AudioSceneImpl(IPlugin& system, Universe& universe, IAllocator& allocator)
|
||||
AudioSceneImpl(AudioSystem& system, Universe& universe, IAllocator& allocator)
|
||||
: m_allocator(allocator)
|
||||
, m_universe(universe)
|
||||
, m_system(system)
|
||||
, m_sources(allocator)
|
||||
, m_clips(allocator)
|
||||
, m_system(system)
|
||||
{
|
||||
m_last_source_id = 0;
|
||||
for(auto& l : m_listeners)
|
||||
m_listener.entity = INVALID_ENTITY;
|
||||
for (auto& i : m_playing_sounds)
|
||||
{
|
||||
l.entity = INVALID_ENTITY;
|
||||
i.entity = INVALID_ENTITY;
|
||||
i.buffer_id = Audio::INVALID_BUFFER_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
~AudioSceneImpl()
|
||||
{
|
||||
clearClips();
|
||||
}
|
||||
|
||||
|
||||
void update(float time_delta) override
|
||||
{
|
||||
if(m_listeners[0].entity != INVALID_ENTITY)
|
||||
if (m_listener.entity != INVALID_ENTITY)
|
||||
{
|
||||
auto pos = m_universe.getPosition(m_listeners[0].entity);
|
||||
setListenerPosition(0, pos.x, pos.y, pos.z);
|
||||
auto pos = m_universe.getPosition(m_listener.entity);
|
||||
Audio::setListenerPosition(0, pos.x, pos.y, pos.z);
|
||||
}
|
||||
for (auto& i : m_playing_sounds)
|
||||
{
|
||||
if (i.buffer_id == Audio::INVALID_BUFFER_HANDLE) continue;
|
||||
auto pos = m_universe.getPosition(i.entity);
|
||||
Audio::setSourcePosition(i.buffer_id, pos.x, pos.y, pos.z);
|
||||
}
|
||||
Audio::update(time_delta);
|
||||
}
|
||||
|
||||
|
||||
void createListener(Entity entity)
|
||||
ComponentIndex createListener(Entity entity)
|
||||
{
|
||||
m_listeners[0].entity = entity;
|
||||
m_listener.entity = entity;
|
||||
m_universe.addComponent(entity, LISTENER_HASH, this, 0);
|
||||
}
|
||||
|
||||
|
||||
void createSource(Entity entity)
|
||||
{
|
||||
auto& source = m_sources.pushEmpty();
|
||||
source.entity = entity;
|
||||
source.component = m_last_source_id;
|
||||
++m_last_source_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ComponentIndex createComponent(uint32 type, Entity entity) override
|
||||
{
|
||||
if(type == LISTENER_HASH && m_listeners[0].entity == INVALID_ENTITY)
|
||||
if (type == LISTENER_HASH && m_listener.entity == INVALID_ENTITY)
|
||||
{
|
||||
createListener(entity);
|
||||
}
|
||||
else if(type == SOURCE_HASH)
|
||||
{
|
||||
createSource(entity);
|
||||
return createListener(entity);
|
||||
}
|
||||
return INVALID_COMPONENT;
|
||||
}
|
||||
|
||||
|
||||
int getSourceIndex(ComponentIndex component)
|
||||
{
|
||||
for(int i = 0, c = m_sources.size(); i < c; ++i)
|
||||
for (int i = 0, c = m_sources.size(); i < c; ++i)
|
||||
{
|
||||
if(m_sources[i].component == component) return i;
|
||||
if (m_sources[i].component == component) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -99,17 +119,11 @@ struct AudioSceneImpl : public AudioScene
|
|||
|
||||
void destroyComponent(ComponentIndex component, uint32 type) override
|
||||
{
|
||||
if(type == LISTENER_HASH)
|
||||
if (type == LISTENER_HASH)
|
||||
{
|
||||
auto entity = m_listeners[component].entity;
|
||||
m_listeners[component].entity = INVALID_ENTITY;
|
||||
m_universe.destroyComponent(entity, type, this, component);
|
||||
}
|
||||
else if (type == SOURCE_HASH)
|
||||
{
|
||||
int index = getSourceIndex(component);
|
||||
auto entity = m_sources[index].entity;
|
||||
m_sources.eraseFast(index);
|
||||
ASSERT(component == 0);
|
||||
auto entity = m_listener.entity;
|
||||
m_listener.entity = INVALID_ENTITY;
|
||||
m_universe.destroyComponent(entity, type, this, component);
|
||||
}
|
||||
}
|
||||
|
@ -117,72 +131,181 @@ struct AudioSceneImpl : public AudioScene
|
|||
|
||||
void serialize(OutputBlob& serializer) override
|
||||
{
|
||||
ASSERT(false);
|
||||
TODO("todo");
|
||||
serializer.write(m_listener.entity);
|
||||
serializer.write(m_clips.size());
|
||||
for (auto* clip : m_clips)
|
||||
{
|
||||
serializer.write(clip != nullptr);
|
||||
if (!clip) continue;
|
||||
|
||||
serializer.write(clip->index);
|
||||
serializer.writeString(clip->name);
|
||||
serializer.writeString(clip->clip->getPath().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void clearClips()
|
||||
{
|
||||
for (auto* clip : m_clips)
|
||||
{
|
||||
clip->clip->getResourceManager().get(CLIP_RESOURCE_HASH)->unload(*clip->clip);
|
||||
LUMIX_DELETE(m_allocator, clip);
|
||||
}
|
||||
m_clips.clear();
|
||||
}
|
||||
|
||||
|
||||
void deserialize(InputBlob& serializer, int version) override
|
||||
{
|
||||
ASSERT(false);
|
||||
TODO("todo");
|
||||
clearClips();
|
||||
|
||||
serializer.read(m_listener.entity);
|
||||
if (m_listener.entity != INVALID_ENTITY)
|
||||
{
|
||||
m_universe.addComponent(m_listener.entity, LISTENER_HASH, this, 0);
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
serializer.read(count);
|
||||
m_clips.resize(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
bool is_valid;
|
||||
serializer.read(is_valid);
|
||||
if (!is_valid)
|
||||
{
|
||||
m_clips[i] = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* clip = LUMIX_NEW(m_allocator, ClipInfo);
|
||||
m_clips[i] = clip;
|
||||
|
||||
serializer.read(clip->index);
|
||||
serializer.readString(clip->name, Lumix::lengthOf(clip->name));
|
||||
char path[MAX_PATH_LENGTH];
|
||||
serializer.readString(path, Lumix::lengthOf(path));
|
||||
|
||||
clip->clip = static_cast<Clip*>(m_system.getClipManager().load(Lumix::Path(path)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ownComponentType(uint32 type) const override
|
||||
{
|
||||
return type == SOURCE_HASH || type == LISTENER_HASH;
|
||||
}
|
||||
bool ownComponentType(uint32 type) const override { return type == LISTENER_HASH; }
|
||||
|
||||
|
||||
int getClipCount() const override
|
||||
{
|
||||
ASSERT(false);
|
||||
TODO("todo");
|
||||
}
|
||||
int getClipCount() const override { return m_clips.size(); }
|
||||
|
||||
|
||||
int addClip(const char* name, const Lumix::Path& path) override
|
||||
{
|
||||
ASSERT(false);
|
||||
TODO("todo");
|
||||
return -1;
|
||||
auto* clip = LUMIX_NEW(m_allocator, ClipInfo);
|
||||
copyString(clip->name, name);
|
||||
clip->name_hash = crc32(name);
|
||||
clip->clip = static_cast<Clip*>(m_system.getClipManager().load(path));
|
||||
m_clips.push(clip);
|
||||
return m_clips.size() - 1;
|
||||
}
|
||||
|
||||
|
||||
void setClipName(int clip_id, const char* clip_name) override
|
||||
{
|
||||
Lumix::copyString(m_clips[clip_id]->name, clip_name);
|
||||
}
|
||||
|
||||
|
||||
const char* getClipName(int clip_id) override { return m_clips[clip_id]->name; }
|
||||
|
||||
|
||||
void removeClip(int clip_id) override
|
||||
{
|
||||
ASSERT(false);
|
||||
TODO("todo");
|
||||
auto* clip = m_clips[clip_id]->clip;
|
||||
if (clip)
|
||||
{
|
||||
clip->getResourceManager().get(CLIP_RESOURCE_HASH)->unload(*clip);
|
||||
}
|
||||
LUMIX_DELETE(m_allocator, clip);
|
||||
m_clips[clip_id] = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void setClip(int clip_id, const Lumix::Path& path) override
|
||||
{
|
||||
auto* clip = m_clips[clip_id]->clip;
|
||||
if (clip)
|
||||
{
|
||||
clip->getResourceManager().get(CLIP_RESOURCE_HASH)->unload(*clip);
|
||||
}
|
||||
auto* new_res = m_system.getClipManager().load(path);
|
||||
m_clips[clip_id]->clip = static_cast<Clip*>(new_res);
|
||||
}
|
||||
|
||||
|
||||
bool isClipIDValid(int clip_id) override
|
||||
{
|
||||
return m_clips[clip_id] != nullptr;
|
||||
}
|
||||
|
||||
|
||||
Clip* getClip(int clip_id) override { return m_clips[clip_id]->clip; }
|
||||
|
||||
|
||||
int getClipID(const char* name) override
|
||||
{
|
||||
ASSERT(false);
|
||||
TODO("todo");
|
||||
uint32 hash = crc32(name);
|
||||
for (int i = 0; i < m_clips.size(); ++i)
|
||||
{
|
||||
if (m_clips[i] && m_clips[i]->name_hash == hash) return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int play(Entity entity, int clip_id) override
|
||||
SoundHandle play(Entity entity, int clip_id) override
|
||||
{
|
||||
ASSERT(false);
|
||||
TODO("todo");
|
||||
}
|
||||
auto* clip = m_clips[clip_id]->clip;
|
||||
if (!clip) return -1;
|
||||
|
||||
auto buffer = Audio::createBuffer(clip->getData(),
|
||||
clip->getSize(),
|
||||
clip->getChannels(),
|
||||
clip->getSampleRate(),
|
||||
(int)Audio::BufferFlags::IS3D);
|
||||
if (!buffer) return -1;
|
||||
Audio::play(buffer);
|
||||
|
||||
void stop(int sound_id) override
|
||||
auto pos = m_universe.getPosition(entity);
|
||||
Audio::setSourcePosition(buffer, pos.x, pos.y, pos.z);
|
||||
|
||||
for (int i = 0; i < Lumix::lengthOf(m_playing_sounds); ++i)
|
||||
{
|
||||
if (m_playing_sounds[i].buffer_id == Audio::INVALID_BUFFER_HANDLE)
|
||||
{
|
||||
ASSERT(false);
|
||||
TODO("todo");
|
||||
auto& sound = m_playing_sounds[i];
|
||||
sound.buffer_id = buffer;
|
||||
sound.entity = entity;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return INVALID_SOUND_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
void setVolume(int sound_id, float volume) override
|
||||
void stop(SoundHandle sound_id) override
|
||||
{
|
||||
ASSERT(false);
|
||||
TODO("todo");
|
||||
ASSERT(sound_id >= 0 && sound_id < Lumix::lengthOf(m_playing_sounds));
|
||||
Audio::stop(m_playing_sounds[sound_id].buffer_id);
|
||||
m_playing_sounds[sound_id].buffer_id = Audio::INVALID_BUFFER_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
void setVolume(SoundHandle sound_id, float volume) override
|
||||
{
|
||||
ASSERT(sound_id >= 0 && sound_id < Lumix::lengthOf(m_playing_sounds));
|
||||
Audio::setVolume(m_playing_sounds[sound_id].buffer_id, volume);
|
||||
}
|
||||
|
||||
|
||||
|
@ -190,27 +313,28 @@ struct AudioSceneImpl : public AudioScene
|
|||
IPlugin& getPlugin() const override { return m_system; }
|
||||
|
||||
Lumix::Array<Source> m_sources;
|
||||
int m_last_source_id;
|
||||
Listener m_listeners[MAX_LISTENERS_COUNT];
|
||||
Listener m_listener;
|
||||
IAllocator& m_allocator;
|
||||
Universe& m_universe;
|
||||
IPlugin& m_system;
|
||||
Array<ClipInfo*> m_clips;
|
||||
AudioSystem& m_system;
|
||||
PlayingSound m_playing_sounds[MAX_PLAYING_SOUNDS];
|
||||
};
|
||||
|
||||
|
||||
static AudioScene* createInstance(IPlugin& system, Engine& engine, Universe& universe, IAllocator& allocator)
|
||||
AudioScene* AudioScene::createInstance(AudioSystem& system,
|
||||
Engine& engine,
|
||||
Universe& universe,
|
||||
IAllocator& allocator)
|
||||
{
|
||||
return LUMIX_NEW(allocator, AudioSceneImpl)(system, universe, allocator);
|
||||
}
|
||||
|
||||
|
||||
static void destroyInstance(AudioScene* scene)
|
||||
void AudioScene::destroyInstance(AudioScene* scene)
|
||||
{
|
||||
LUMIX_DELETE(static_cast<AudioSceneImpl*>(scene)->m_allocator, scene);
|
||||
}
|
||||
|
||||
|
||||
} //namespace Audio
|
||||
|
||||
|
||||
} // namespace Lumix
|
|
@ -8,6 +8,8 @@ namespace Lumix
|
|||
{
|
||||
|
||||
|
||||
class AudioSystem;
|
||||
class Clip;
|
||||
class Path;
|
||||
|
||||
|
||||
|
@ -15,9 +17,10 @@ class AudioScene : public IScene
|
|||
{
|
||||
public:
|
||||
typedef int SoundHandle;
|
||||
static const SoundHandle INVALID_SOUND_HANDLE = -1;
|
||||
|
||||
public:
|
||||
static AudioScene* createInstance(IPlugin& system,
|
||||
static AudioScene* createInstance(AudioSystem& system,
|
||||
Engine& engine,
|
||||
Universe& universe,
|
||||
class IAllocator& allocator);
|
||||
|
@ -27,10 +30,15 @@ public:
|
|||
virtual int addClip(const char* name, const Lumix::Path& path) = 0;
|
||||
virtual void removeClip(int clip_id) = 0;
|
||||
virtual int getClipID(const char* name) = 0;
|
||||
virtual bool isClipIDValid(int clip_id) = 0;
|
||||
virtual Clip* getClip(int clid_id) = 0;
|
||||
virtual void setClip(int clip_id, const Lumix::Path& path) = 0;
|
||||
virtual const char* getClipName(int clip_id) = 0;
|
||||
virtual void setClipName(int clip_id, const char* clip_name) = 0;
|
||||
|
||||
virtual int play(Entity entity, int clip_id) = 0;
|
||||
virtual void stop(int sound_id) = 0;
|
||||
virtual void setVolume(int sound_id, float volume) = 0;
|
||||
virtual SoundHandle play(Entity entity, int clip_id) = 0;
|
||||
virtual void stop(SoundHandle sound_id) = 0;
|
||||
virtual void setVolume(SoundHandle sound_id, float volume) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
#include "audio_system.h"
|
||||
#include "audio_device.h"
|
||||
#include "audio_scene.h"
|
||||
#include "clip_manager.h"
|
||||
#include "core/crc32.h"
|
||||
#include "core/path.h"
|
||||
#include "core/resource_manager.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/iplugin.h"
|
||||
|
||||
|
@ -8,31 +13,46 @@ namespace Lumix
|
|||
{
|
||||
|
||||
|
||||
struct AudioSystemImpl : public IPlugin
|
||||
struct AudioSystemImpl : public AudioSystem
|
||||
{
|
||||
AudioSystemImpl(Engine& engine)
|
||||
: m_engine(engine)
|
||||
, m_manager(engine.getAllocator())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ClipManager& getClipManager() override { return m_manager; }
|
||||
|
||||
|
||||
bool create() override
|
||||
{
|
||||
return Audio::init(m_engine, m_engine.getAllocator());
|
||||
bool result = Audio::init(m_engine, m_engine.getAllocator());
|
||||
m_manager.create(crc32("CLIP"), m_engine.getResourceManager());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void destroy() override
|
||||
{
|
||||
Audio::shutdown();
|
||||
m_manager.destroy();
|
||||
}
|
||||
|
||||
|
||||
const char* getName() const override { return "audio"; }
|
||||
|
||||
IScene* createScene(UniverseContext&) { return nullptr; }
|
||||
void destroyScene(IScene* scene) { ASSERT(false); }
|
||||
|
||||
IScene* createScene(UniverseContext& ctx)
|
||||
{
|
||||
return AudioScene::createInstance(*this, m_engine, *ctx.m_universe, m_engine.getAllocator());
|
||||
}
|
||||
|
||||
|
||||
void destroyScene(IScene* scene) { AudioScene::destroyInstance(static_cast<AudioScene*>(scene)); }
|
||||
|
||||
|
||||
ClipManager m_manager;
|
||||
Engine& m_engine;
|
||||
};
|
||||
|
||||
|
|
18
src/audio/audio_system.h
Normal file
18
src/audio/audio_system.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include "engine/iplugin.h"
|
||||
|
||||
|
||||
namespace Lumix
|
||||
{
|
||||
|
||||
|
||||
class AudioSystem : public IPlugin
|
||||
{
|
||||
public:
|
||||
virtual class ClipManager& getClipManager() = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Lumix
|
|
@ -12,10 +12,6 @@ namespace Lumix
|
|||
{
|
||||
|
||||
|
||||
namespace Audio
|
||||
{
|
||||
|
||||
|
||||
void Clip::unload()
|
||||
{
|
||||
m_data.clear();
|
||||
|
@ -25,7 +21,8 @@ void Clip::unload()
|
|||
bool Clip::load(FS::IFile& file)
|
||||
{
|
||||
short* output = nullptr;
|
||||
auto res = stb_vorbis_decode_memory((unsigned char*)file.getBuffer(), file.size(), &m_channels, &m_sample_rate, &output);
|
||||
auto res = stb_vorbis_decode_memory(
|
||||
(unsigned char*)file.getBuffer(), (int)file.size(), &m_channels, &m_sample_rate, &output);
|
||||
if (res <= 0) return false;
|
||||
|
||||
m_data.resize(res);
|
||||
|
@ -48,7 +45,4 @@ void ClipManager::destroyResource(Resource& resource)
|
|||
}
|
||||
|
||||
|
||||
} // namespace Audio
|
||||
|
||||
|
||||
} // namespace Lumix
|
|
@ -10,11 +10,7 @@ namespace Lumix
|
|||
{
|
||||
|
||||
|
||||
namespace Audio
|
||||
{
|
||||
|
||||
|
||||
class LUMIX_LIBRARY_EXPORT Clip : public Resource
|
||||
class LUMIX_AUDIO_API Clip : public Resource
|
||||
{
|
||||
public:
|
||||
Clip(const Path& path, ResourceManager& manager, IAllocator& allocator)
|
||||
|
@ -26,7 +22,8 @@ public:
|
|||
void unload(void) override;
|
||||
bool load(FS::IFile& file) override;
|
||||
int getChannels() const { return m_channels; }
|
||||
int getSamplerate() const { return m_sample_rate; }
|
||||
int getSampleRate() const { return m_sample_rate; }
|
||||
int getSize() const { return m_data.size() * sizeof(m_data[0]); }
|
||||
uint16* getData() { return &m_data[0]; }
|
||||
|
||||
private:
|
||||
|
@ -36,7 +33,7 @@ private:
|
|||
};
|
||||
|
||||
|
||||
class LUMIX_LIBRARY_EXPORT ClipManager : public ResourceManagerBase
|
||||
class LUMIX_AUDIO_API ClipManager : public ResourceManagerBase
|
||||
{
|
||||
public:
|
||||
ClipManager(IAllocator& allocator)
|
||||
|
@ -56,7 +53,4 @@ private:
|
|||
};
|
||||
|
||||
|
||||
} // namespace Audio
|
||||
|
||||
|
||||
} // namespace Lumix
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "audio_device.h"
|
||||
#include "core/path.h"
|
||||
#include "clip_manager.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/iplugin.h"
|
||||
#include <dsound.h>
|
||||
|
@ -16,9 +16,10 @@ namespace Audio
|
|||
struct
|
||||
{
|
||||
HMODULE library;
|
||||
LPDIRECTSOUND direct_sound;
|
||||
LPDIRECTSOUND8 direct_sound;
|
||||
bool initialized;
|
||||
LPDIRECTSOUNDBUFFER primary_buffer;
|
||||
LPDIRECTSOUND3DLISTENER8 listener;
|
||||
} g_audio_device;
|
||||
|
||||
|
||||
|
@ -26,7 +27,8 @@ static bool initPrimaryBuffer()
|
|||
{
|
||||
DSBUFFERDESC primary_buffer_desc = {};
|
||||
primary_buffer_desc.dwSize = sizeof(primary_buffer_desc);
|
||||
primary_buffer_desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D;
|
||||
primary_buffer_desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRL3D;
|
||||
primary_buffer_desc.guid3DAlgorithm = DS3DALG_DEFAULT;
|
||||
auto result = SUCCEEDED(g_audio_device.direct_sound->CreateSoundBuffer(
|
||||
&primary_buffer_desc, &g_audio_device.primary_buffer, nullptr));
|
||||
if (!result) return false;
|
||||
|
@ -34,7 +36,7 @@ static bool initPrimaryBuffer()
|
|||
WAVEFORMATEX wave_format = {};
|
||||
wave_format.cbSize = 0;
|
||||
wave_format.nChannels = 2;
|
||||
wave_format.nSamplesPerSec = 24 * 1024;
|
||||
wave_format.nSamplesPerSec = 44100;
|
||||
wave_format.wBitsPerSample = 16;
|
||||
wave_format.nBlockAlign = wave_format.nChannels * wave_format.wBitsPerSample / 8;
|
||||
wave_format.nAvgBytesPerSec = wave_format.nSamplesPerSec * wave_format.nBlockAlign;
|
||||
|
@ -43,6 +45,15 @@ static bool initPrimaryBuffer()
|
|||
result = SUCCEEDED(g_audio_device.primary_buffer->SetFormat(&wave_format));
|
||||
if (!result) return false;
|
||||
|
||||
result = SUCCEEDED(g_audio_device.primary_buffer->QueryInterface(
|
||||
IID_IDirectSound3DListener8, (void**)&g_audio_device.listener));
|
||||
if (!result) return false;
|
||||
|
||||
g_audio_device.listener->SetDopplerFactor(1.0, DS3D_DEFERRED);
|
||||
g_audio_device.listener->SetDistanceFactor(1.0f, DS3D_DEFERRED);
|
||||
g_audio_device.listener->SetRolloffFactor(1.0f, DS3D_DEFERRED);
|
||||
g_audio_device.primary_buffer->Play(0, 0, DSBPLAY_LOOPING);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -51,10 +62,13 @@ bool init(Engine& engine, IAllocator& allocator)
|
|||
{
|
||||
ASSERT(!g_audio_device.initialized);
|
||||
|
||||
auto result = SUCCEEDED(CoInitialize(nullptr));
|
||||
ASSERT(result);
|
||||
|
||||
g_audio_device.library = LoadLibrary("dsound.dll");
|
||||
if (!g_audio_device.library) return false;
|
||||
decltype(DirectSoundCreate)* dsoundCreate =
|
||||
(decltype(DirectSoundCreate)*)GetProcAddress(g_audio_device.library, "DirectSoundCreate");
|
||||
auto* dsoundCreate =
|
||||
(decltype(DirectSoundCreate8)*)GetProcAddress(g_audio_device.library, "DirectSoundCreate8");
|
||||
if (!dsoundCreate)
|
||||
{
|
||||
ASSERT(false);
|
||||
|
@ -62,7 +76,7 @@ bool init(Engine& engine, IAllocator& allocator)
|
|||
return false;
|
||||
}
|
||||
|
||||
auto result = SUCCEEDED(dsoundCreate(0, &g_audio_device.direct_sound, nullptr));
|
||||
result = SUCCEEDED(dsoundCreate(0, &g_audio_device.direct_sound, nullptr));
|
||||
if (!result)
|
||||
{
|
||||
ASSERT(false);
|
||||
|
@ -94,14 +108,20 @@ void shutdown()
|
|||
}
|
||||
|
||||
|
||||
ClipHandle load(const Path& path, const void* data, int size, int channels, int sample_rate, int flags)
|
||||
BufferHandle createBuffer(const void* data,
|
||||
int size_bytes,
|
||||
int channels,
|
||||
int sample_rate,
|
||||
int flags)
|
||||
{
|
||||
DSBUFFERDESC desc = {};
|
||||
LPDIRECTSOUNDBUFFER buffer;
|
||||
desc.dwSize = sizeof(desc);
|
||||
desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLFX | DSBCAPS_LOCSOFTWARE;
|
||||
if ((flags & (int)ClipFlags::IS3D) != 0) desc.dwFlags = DSBCAPS_CTRL3D;
|
||||
desc.dwBufferBytes = size;
|
||||
desc.dwFlags =
|
||||
DSBCAPS_CTRLVOLUME | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLFX;
|
||||
bool is_3d = (flags & (int)BufferFlags::IS3D) != 0;
|
||||
if (is_3d) desc.dwFlags |= DSBCAPS_CTRL3D;
|
||||
desc.dwBufferBytes = size_bytes;
|
||||
|
||||
WAVEFORMATEX wave_format = {};
|
||||
wave_format.cbSize = 0;
|
||||
|
@ -120,7 +140,7 @@ ClipHandle load(const Path& path, const void* data, int size, int channels, int
|
|||
void* p1;
|
||||
void* p2;
|
||||
DWORD s1, s2;
|
||||
result = SUCCEEDED(buffer->Lock(0, size, &p1, &s1, &p2, &s2, 0));
|
||||
result = SUCCEEDED(buffer->Lock(0, size_bytes, &p1, &s1, &p2, &s2, 0));
|
||||
if (!result)
|
||||
{
|
||||
buffer->Release();
|
||||
|
@ -140,46 +160,57 @@ ClipHandle load(const Path& path, const void* data, int size, int channels, int
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (is_3d)
|
||||
{
|
||||
LPDIRECTSOUND3DBUFFER8 source;
|
||||
if (SUCCEEDED(buffer->QueryInterface(IID_IDirectSound3DBuffer8, (void**)&source)))
|
||||
{
|
||||
source->SetMaxDistance(10000, DS3D_DEFERRED);
|
||||
source->SetMinDistance(2, DS3D_DEFERRED);
|
||||
source->SetMode(DS3DMODE_NORMAL, DS3D_DEFERRED);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
void unload(ClipHandle clip)
|
||||
void destroyBuffer(BufferHandle clip)
|
||||
{
|
||||
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
|
||||
buffer->Release();
|
||||
}
|
||||
|
||||
|
||||
void play(ClipHandle clip)
|
||||
void play(BufferHandle clip)
|
||||
{
|
||||
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
|
||||
buffer->Play(0, 0, DSBPLAY_LOOPING);
|
||||
}
|
||||
|
||||
|
||||
void stop(ClipHandle clip)
|
||||
void stop(BufferHandle clip)
|
||||
{
|
||||
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
|
||||
buffer->Stop();
|
||||
}
|
||||
|
||||
|
||||
void pause(ClipHandle clip)
|
||||
void pause(BufferHandle clip)
|
||||
{
|
||||
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
|
||||
buffer->Stop();
|
||||
}
|
||||
|
||||
|
||||
void setVolume(ClipHandle clip, float volume)
|
||||
void setVolume(BufferHandle clip, float volume)
|
||||
{
|
||||
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
|
||||
buffer->SetVolume(DSBVOLUME_MIN + LONG(volume * (DSBVOLUME_MAX - DSBVOLUME_MIN)));
|
||||
}
|
||||
|
||||
|
||||
void setFrequency(ClipHandle clip, float frequency)
|
||||
void setFrequency(BufferHandle clip, float frequency)
|
||||
{
|
||||
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
|
||||
buffer->SetFrequency(
|
||||
|
@ -187,7 +218,7 @@ void setFrequency(ClipHandle clip, float frequency)
|
|||
}
|
||||
|
||||
|
||||
void setCurrentPosition(ClipHandle clip, float time_seconds)
|
||||
void setCurrentTime(BufferHandle clip, float time_seconds)
|
||||
{
|
||||
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
|
||||
WAVEFORMATEX format;
|
||||
|
@ -199,11 +230,17 @@ void setCurrentPosition(ClipHandle clip, float time_seconds)
|
|||
}
|
||||
|
||||
|
||||
void setSourcePosition(ClipHandle clip, float x, float y, float z)
|
||||
void update(float)
|
||||
{
|
||||
LPDIRECTSOUND3DBUFFER source;
|
||||
g_audio_device.listener->CommitDeferredSettings();
|
||||
}
|
||||
|
||||
|
||||
void setSourcePosition(BufferHandle clip, float x, float y, float z)
|
||||
{
|
||||
LPDIRECTSOUND3DBUFFER8 source;
|
||||
auto buffer = (LPDIRECTSOUNDBUFFER)clip;
|
||||
if(SUCCEEDED(buffer->QueryInterface(IID_IDirectSound3DBuffer8, (void**)&source)))
|
||||
if (SUCCEEDED(buffer->QueryInterface(IID_IDirectSound3DBuffer8, (void**)&source)))
|
||||
{
|
||||
source->SetPosition(x, y, z, DS3D_DEFERRED);
|
||||
}
|
||||
|
@ -212,11 +249,7 @@ void setSourcePosition(ClipHandle clip, float x, float y, float z)
|
|||
|
||||
void setListenerPosition(int index, float x, float y, float z)
|
||||
{
|
||||
LPDIRECTSOUND3DBUFFER listener;
|
||||
if(SUCCEEDED(g_audio_device.primary_buffer->QueryInterface(IID_IDirectSound3DBuffer8, (void**)&listener)))
|
||||
{
|
||||
listener->SetPosition(x, y, z, DS3D_DEFERRED);
|
||||
}
|
||||
g_audio_device.listener->SetPosition(x, y, z, DS3D_DEFERRED);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -59,6 +59,8 @@
|
|||
#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||
#define STB_VORBIS_INCLUDE_STB_VORBIS_H
|
||||
|
||||
#define STB_VORBIS_NO_STDIO 1
|
||||
|
||||
#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
|
||||
#define STB_VORBIS_NO_STDIO 1
|
||||
#endif
|
||||
|
@ -4458,7 +4460,7 @@ int stb_vorbis_decode_frame_pushdata(
|
|||
while (get8_packet(f) != EOP)
|
||||
if (f->eof) break;
|
||||
*samples = 0;
|
||||
return f->stream - data;
|
||||
return (int)(f->stream - data);
|
||||
}
|
||||
if (error == VORBIS_continued_packet_flag_invalid) {
|
||||
if (f->previous_length == 0) {
|
||||
|
@ -4468,7 +4470,7 @@ int stb_vorbis_decode_frame_pushdata(
|
|||
while (get8_packet(f) != EOP)
|
||||
if (f->eof) break;
|
||||
*samples = 0;
|
||||
return f->stream - data;
|
||||
return (int)(f->stream - data);
|
||||
}
|
||||
}
|
||||
// if we get an error while parsing, what to do?
|
||||
|
@ -4488,7 +4490,7 @@ int stb_vorbis_decode_frame_pushdata(
|
|||
if (channels) *channels = f->channels;
|
||||
*samples = len;
|
||||
*output = f->outputs;
|
||||
return f->stream - data;
|
||||
return (int)(f->stream - data);
|
||||
}
|
||||
|
||||
stb_vorbis *stb_vorbis_open_pushdata(
|
||||
|
@ -4511,7 +4513,7 @@ stb_vorbis *stb_vorbis_open_pushdata(
|
|||
f = vorbis_alloc(&p);
|
||||
if (f) {
|
||||
*f = p;
|
||||
*data_used = f->stream - data;
|
||||
*data_used = (int)(f->stream - data);
|
||||
*error = 0;
|
||||
return f;
|
||||
}
|
||||
|
@ -4527,7 +4529,7 @@ unsigned int stb_vorbis_get_file_offset(stb_vorbis *f)
|
|||
#ifndef STB_VORBIS_NO_PUSHDATA_API
|
||||
if (f->push_mode) return 0;
|
||||
#endif
|
||||
if (USE_MEMORY(f)) return f->stream - f->stream_start;
|
||||
if (USE_MEMORY(f)) return (unsigned int)(f->stream - f->stream_start);
|
||||
#ifndef STB_VORBIS_NO_STDIO
|
||||
return ftell(f->f) - f->f_start;
|
||||
#endif
|
||||
|
|
|
@ -69,6 +69,12 @@ namespace Lumix
|
|||
#define LUMIX_RESTRICT __restrict
|
||||
|
||||
|
||||
#ifdef BUILDING_AUDIO
|
||||
#define LUMIX_AUDIO_API LUMIX_LIBRARY_EXPORT
|
||||
#else
|
||||
#define LUMIX_AUDIO_API LUMIX_LIBRARY_IMPORT
|
||||
#endif
|
||||
|
||||
#ifdef BUILDING_PHYSICS
|
||||
#define LUMIX_PHYSICS_API LUMIX_LIBRARY_EXPORT
|
||||
#else
|
||||
|
|
52
src/lua_script/lua_audio_api.cpp
Normal file
52
src/lua_script/lua_audio_api.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
#include "audio/audio_scene.h"
|
||||
#include "core/crc32.h"
|
||||
#include "core/lua_wrapper.h"
|
||||
#include "engine.h"
|
||||
#include "iplugin.h"
|
||||
#include "universe/universe.h"
|
||||
|
||||
|
||||
namespace Lumix
|
||||
{
|
||||
|
||||
|
||||
namespace LuaAPI
|
||||
{
|
||||
|
||||
|
||||
static int playSound(IScene* scene,
|
||||
int entity,
|
||||
int clip_id)
|
||||
{
|
||||
return static_cast<AudioScene*>(scene)->play(entity, clip_id);
|
||||
}
|
||||
|
||||
|
||||
static void setSoundVolume(IScene* scene, int sound_id, float volume)
|
||||
{
|
||||
static_cast<AudioScene*>(scene)->setVolume(sound_id, volume);
|
||||
}
|
||||
|
||||
|
||||
} // namespace LuaAPI
|
||||
|
||||
|
||||
static void registerCFunction(lua_State* L, const char* name, lua_CFunction func)
|
||||
{
|
||||
lua_pushcfunction(L, func);
|
||||
lua_setglobal(L, name);
|
||||
}
|
||||
|
||||
|
||||
void registerAudioLuaAPI(Engine&, Universe&, lua_State* L)
|
||||
{
|
||||
registerCFunction(L,
|
||||
"API_playSound",
|
||||
LuaWrapper::wrap<decltype(&LuaAPI::playSound), LuaAPI::playSound>);
|
||||
registerCFunction(L,
|
||||
"API_setSoundVolume",
|
||||
LuaWrapper::wrap<decltype(&LuaAPI::setSoundVolume), LuaAPI::setSoundVolume>);
|
||||
}
|
||||
|
||||
|
||||
} // namespace Lumix
|
|
@ -14,19 +14,21 @@ namespace LuaAPI
|
|||
{
|
||||
|
||||
|
||||
static void moveController(
|
||||
IScene* scene, int component, float x, float y, float z, float time_delta)
|
||||
static void moveController(IScene* scene,
|
||||
int component,
|
||||
float x,
|
||||
float y,
|
||||
float z,
|
||||
float time_delta)
|
||||
{
|
||||
static_cast<PhysicsScene*>(scene)
|
||||
->moveController(component, Vec3(x, y, z), time_delta);
|
||||
static_cast<PhysicsScene*>(scene)->moveController(component, Vec3(x, y, z), time_delta);
|
||||
}
|
||||
|
||||
|
||||
} // namespace LuaAPI
|
||||
|
||||
|
||||
static void
|
||||
registerCFunction(lua_State* L, const char* name, lua_CFunction func)
|
||||
static void registerCFunction(lua_State* L, const char* name, lua_CFunction func)
|
||||
{
|
||||
lua_pushcfunction(L, func);
|
||||
lua_setglobal(L, name);
|
||||
|
|
|
@ -32,6 +32,8 @@ class LuaScriptSystemImpl;
|
|||
void registerEngineLuaAPI(Engine&, lua_State* L);
|
||||
void registerUniverse(UniverseContext*, lua_State* L);
|
||||
void registerPhysicsLuaAPI(Engine&, Universe&, lua_State* L);
|
||||
void registerAudioLuaAPI(Engine&, Universe&, lua_State* L);
|
||||
|
||||
|
||||
|
||||
static const uint32 LUA_SCRIPT_HASH = crc32("lua_script");
|
||||
|
@ -117,6 +119,10 @@ public:
|
|||
{
|
||||
registerPhysicsLuaAPI(m_system.m_engine, *m_universe_context.m_universe, L);
|
||||
}
|
||||
if (m_system.m_engine.getPluginManager().getPlugin("audio"))
|
||||
{
|
||||
registerAudioLuaAPI(m_system.m_engine, *m_universe_context.m_universe, L);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
static const Lumix::uint32 UNIVERSE_HASH = Lumix::crc32("universe");
|
||||
static const Lumix::uint32 SOURCE_HASH = Lumix::crc32("source");
|
||||
static const Lumix::uint32 CLIP_HASH = Lumix::crc32("CLIP");
|
||||
static const Lumix::uint32 LUA_SCRIPT_HASH = Lumix::crc32("lua_script");
|
||||
|
||||
|
||||
|
@ -38,6 +39,7 @@ static Lumix::uint32 getResourceType(const char* path)
|
|||
char ext[10];
|
||||
Lumix::PathUtils::getExtension(ext, sizeof(ext), path);
|
||||
|
||||
if (Lumix::compareString(ext, "ogg") == 0) return CLIP_HASH;
|
||||
if (Lumix::compareString(ext, "mat") == 0) return Lumix::ResourceManager::MATERIAL;
|
||||
if (Lumix::compareString(ext, "msh") == 0) return Lumix::ResourceManager::MODEL;
|
||||
if (Lumix::compareString(ext, "dds") == 0) return Lumix::ResourceManager::TEXTURE;
|
||||
|
@ -803,6 +805,7 @@ void AssetBrowser::addResource(const char* path, const char* filename)
|
|||
|
||||
int index = -1;
|
||||
if (Lumix::compareString(ext, "dds") == 0 || Lumix::compareString(ext, "tga") == 0 || Lumix::compareString(ext, "raw") == 0) index = TEXTURE;
|
||||
if (Lumix::compareString(ext, "ogg") == 0) index = AUDIO;
|
||||
if (Lumix::compareString(ext, "msh") == 0) index = MODEL;
|
||||
if (Lumix::compareString(ext, "mat") == 0) index = MATERIAL;
|
||||
if (Lumix::compareString(ext, "unv") == 0) index = UNIVERSE;
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
TEXTURE,
|
||||
UNIVERSE,
|
||||
LUA_SCRIPT,
|
||||
AUDIO,
|
||||
|
||||
Count
|
||||
};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include "audio/audio_scene.h"
|
||||
#include "audio/clip_manager.h"
|
||||
#include "asset_browser.h"
|
||||
#include "core/blob.h"
|
||||
#include "core/command_line_parser.h"
|
||||
|
@ -239,6 +241,7 @@ public:
|
|||
m_log_ui->onGUI();
|
||||
m_import_asset_dialog->onGUI();
|
||||
m_property_grid->onGUI();
|
||||
showClipManager();
|
||||
showEntityList();
|
||||
showEntityTemplateList();
|
||||
m_sceneview.onGUI();
|
||||
|
@ -597,6 +600,49 @@ public:
|
|||
}
|
||||
|
||||
|
||||
void showClipManager()
|
||||
{
|
||||
if (ImGui::Begin("Clip manager"))
|
||||
{
|
||||
auto* audio_scene = static_cast<Lumix::AudioScene*>(m_editor->getScene(Lumix::crc32("audio")));
|
||||
int clip_count = audio_scene->getClipCount();
|
||||
for (int clip_id = 0; clip_id < clip_count; ++clip_id)
|
||||
{
|
||||
if (!audio_scene->isClipIDValid(clip_id)) continue;
|
||||
if (ImGui::TreeNode((const void*)clip_id, audio_scene->getClipName(clip_id)))
|
||||
{
|
||||
char buf[30];
|
||||
Lumix::copyString(buf, Lumix::lengthOf(buf), audio_scene->getClipName(clip_id));
|
||||
if (ImGui::InputText("Name", buf, sizeof(buf)))
|
||||
{
|
||||
audio_scene->setClipName(clip_id, buf);
|
||||
}
|
||||
auto* clip = audio_scene->getClip(clip_id);
|
||||
char path[Lumix::MAX_PATH_LENGTH];
|
||||
Lumix::copyString(path, clip ? clip->getPath().c_str() : "");
|
||||
if (m_asset_browser->resourceInput(
|
||||
"Clip", "", path, Lumix::lengthOf(path), AssetBrowser::Type::AUDIO))
|
||||
{
|
||||
audio_scene->setClip(clip_id, Lumix::Path(path));
|
||||
}
|
||||
if (ImGui::Button("Remove"))
|
||||
{
|
||||
audio_scene->removeClip(clip_id);
|
||||
--clip_count;
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Button("Add"))
|
||||
{
|
||||
audio_scene->addClip("test", Lumix::Path("test.ogg"));
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
||||
void showEntityList()
|
||||
{
|
||||
if (!m_is_entity_list_opened) return;
|
||||
|
|
|
@ -26,6 +26,12 @@ void registerLuaScriptProperties(Lumix::IAllocator& allocator)
|
|||
}
|
||||
|
||||
|
||||
void registerAudioProperties(Lumix::IAllocator& allocator)
|
||||
{
|
||||
PropertyRegister::registerComponentType("audio_listener", "Audio - listener");
|
||||
}
|
||||
|
||||
|
||||
void registerPhysicsProperties(Lumix::IAllocator& allocator)
|
||||
{
|
||||
PropertyRegister::registerComponentType("box_rigid_actor", "Physics Box");
|
||||
|
@ -361,4 +367,5 @@ void registerProperties(Lumix::WorldEditor& editor)
|
|||
registerRendererProperties(editor.getAllocator());
|
||||
registerLuaScriptProperties(editor.getAllocator());
|
||||
registerPhysicsProperties(editor.getAllocator());
|
||||
registerAudioProperties(editor.getAllocator());
|
||||
}
|
Loading…
Reference in a new issue