WIP adding directory structure
This commit is contained in:
@@ -32,7 +32,7 @@
|
||||
#include "KREngine-common.h"
|
||||
|
||||
#include "KRResource.h"
|
||||
#include "KRMesh.h"
|
||||
#include "mesh/KRMesh.h"
|
||||
|
||||
#include "mimir.h"
|
||||
|
||||
|
||||
1963
kraken/resources/audio/KRAudioManager.cpp
Executable file
1963
kraken/resources/audio/KRAudioManager.cpp
Executable file
File diff suppressed because it is too large
Load Diff
258
kraken/resources/audio/KRAudioManager.h
Executable file
258
kraken/resources/audio/KRAudioManager.h
Executable file
@@ -0,0 +1,258 @@
|
||||
//
|
||||
// FileManager.h
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "KREngine-common.h"
|
||||
|
||||
#include "resources/KRResourceManager.h"
|
||||
|
||||
#include "KRContextObject.h"
|
||||
#include "block.h"
|
||||
#include "KRAudioSource.h"
|
||||
#include "siren.h"
|
||||
|
||||
const int KRENGINE_AUDIO_MAX_POOL_SIZE = 60; //32;
|
||||
// for Circa we play a maximum of 11 mono audio streams at once + cross fading with ambient
|
||||
// so we could safely say a maximum of 12 or 13 streams, which would be 39 buffers
|
||||
// do the WAV files for the reverb use the same buffer pool ???
|
||||
|
||||
const int KRENGINE_AUDIO_MAX_BUFFER_SIZE = 5120; // in bytes
|
||||
// this is the buffer for our decoded audio (not the source file data)
|
||||
// it should be greater then 1152 samples (the size of an mp3 frame in samples)
|
||||
// so it should be greater then 2304 bytes and also a multiple of 128 samples (to make
|
||||
// the data flow efficient) but it shouldn't be too large or it will cause
|
||||
// the render loop to stall out decoding large chunks of mp3 data.
|
||||
// 2560 bytes would be the smallest size for mono sources, and 5120 would be smallest for stereo.
|
||||
|
||||
const int KRENGINE_AUDIO_BUFFERS_PER_SOURCE = 3;
|
||||
|
||||
const int KRENGINE_AUDIO_BLOCK_LOG2N = 7; // 2 ^ KRENGINE_AUDIO_BLOCK_LOG2N = KRENGINE_AUDIO_BLOCK_LENGTH
|
||||
// 7 is 128 .. NOTE: the hrtf code uses magic numbers everywhere and is hardcoded to 128 samples per frame
|
||||
|
||||
const int KRENGINE_AUDIO_BLOCK_LENGTH = 1 << KRENGINE_AUDIO_BLOCK_LOG2N;
|
||||
// Length of one block to process. Determines the latency of the audio system and sets size for FFT's used in HRTF convolution
|
||||
// the AUGraph works in 1024 sample chunks. At 128 we are making 8 consecutive calls to the renderBlock method for each
|
||||
// render initiated by the AUGraph.
|
||||
|
||||
const int KRENGINE_REVERB_MAX_FFT_LOG2 = 15;
|
||||
const int KRENGINE_REVERB_WORKSPACE_SIZE = 1 << KRENGINE_REVERB_MAX_FFT_LOG2;
|
||||
|
||||
const float KRENGINE_AUDIO_CUTOFF = 0.02f; // Cutoff gain level, to cull out processing of very quiet sounds
|
||||
|
||||
const int KRENGINE_REVERB_MAX_SAMPLES = 128000; // 2.9 seconds //435200; // At least 10s reverb impulse response length, divisible by KRENGINE_AUDIO_BLOCK_LENGTH
|
||||
const int KRENGINE_MAX_REVERB_IMPULSE_MIX = 8; // Maximum number of impulse response filters that can be mixed simultaneously
|
||||
const int KRENGINE_MAX_OUTPUT_CHANNELS = 2;
|
||||
|
||||
const int KRENGINE_MAX_ACTIVE_SOURCES = 16;
|
||||
const int KRENGINE_AUDIO_ANTICLICK_SAMPLES = 64;
|
||||
|
||||
|
||||
class KRAmbientZone;
|
||||
class KRReverbZone;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float weight;
|
||||
KRAmbientZone* ambient_zone;
|
||||
KRAudioSample* ambient_sample;
|
||||
} siren_ambient_zone_weight_info;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float weight;
|
||||
KRReverbZone* reverb_zone;
|
||||
KRAudioSample* reverb_sample;
|
||||
} siren_reverb_zone_weight_info;
|
||||
|
||||
class KRAudioManager : public KRResourceManager
|
||||
{
|
||||
public:
|
||||
KRAudioManager(KRContext& context);
|
||||
virtual ~KRAudioManager();
|
||||
void destroy();
|
||||
|
||||
virtual KRResource* loadResource(const std::string& name, const std::string& extension, mimir::Block* data) override;
|
||||
virtual KRResource* getResource(const std::string& name, const std::string& extension) override;
|
||||
|
||||
unordered_map<std::string, KRAudioSample*>& getSounds();
|
||||
|
||||
void add(KRAudioSample* Sound);
|
||||
|
||||
KRAudioSample* load(const std::string& name, const std::string& extension, mimir::Block* data);
|
||||
KRAudioSample* get(const std::string& name);
|
||||
|
||||
// Listener position and orientation
|
||||
KRScene* getListenerScene();
|
||||
void setListenerScene(KRScene* scene);
|
||||
void setListenerOrientation(const hydra::Vector3& position, const hydra::Vector3& forward, const hydra::Vector3& up);
|
||||
void setListenerOrientationFromModelMatrix(const hydra::Matrix4& modelMatrix);
|
||||
hydra::Vector3& getListenerForward();
|
||||
hydra::Vector3& getListenerPosition();
|
||||
hydra::Vector3& getListenerUp();
|
||||
|
||||
|
||||
// Global audio gain / attenuation
|
||||
float getGlobalGain();
|
||||
void setGlobalGain(float gain);
|
||||
float getGlobalReverbSendLevel();
|
||||
void setGlobalReverbSendLevel(float send_level);
|
||||
float getGlobalAmbientGain();
|
||||
void setGlobalAmbientGain(float gain);
|
||||
|
||||
|
||||
|
||||
void makeCurrentContext();
|
||||
|
||||
mimir::Block* getBufferData(int size);
|
||||
void recycleBufferData(mimir::Block* data);
|
||||
|
||||
void activateAudioSource(KRAudioSource* audioSource);
|
||||
void deactivateAudioSource(KRAudioSource* audioSource);
|
||||
|
||||
__int64_t getAudioFrame();
|
||||
|
||||
KRAudioBuffer* getBuffer(KRAudioSample& audio_sample, int buffer_index);
|
||||
|
||||
static void mute(bool onNotOff);
|
||||
void goToSleep();
|
||||
|
||||
void startFrame(float deltaTime);
|
||||
|
||||
bool getEnableAudio();
|
||||
void setEnableAudio(bool enable);
|
||||
|
||||
bool getEnableHRTF();
|
||||
void setEnableHRTF(bool enable);
|
||||
|
||||
bool getEnableReverb();
|
||||
void setEnableReverb(bool enable);
|
||||
|
||||
float getReverbMaxLength();
|
||||
void setReverbMaxLength(float max_length);
|
||||
|
||||
void _registerOpenAudioSample(KRAudioSample* audioSample);
|
||||
void _registerCloseAudioSample(KRAudioSample* audioSample);
|
||||
|
||||
private:
|
||||
bool m_enable_audio;
|
||||
bool m_enable_hrtf;
|
||||
bool m_enable_reverb;
|
||||
float m_reverb_max_length;
|
||||
|
||||
KRScene* m_listener_scene; // For now, only one scene is allowed to have active audio at once
|
||||
|
||||
float m_global_reverb_send_level;
|
||||
float m_global_ambient_gain;
|
||||
float m_global_gain;
|
||||
|
||||
hydra::Vector3 m_listener_position;
|
||||
hydra::Vector3 m_listener_forward;
|
||||
hydra::Vector3 m_listener_up;
|
||||
|
||||
unordered_map<std::string, KRAudioSample*> m_sounds;
|
||||
|
||||
std::vector<mimir::Block*> m_bufferPoolIdle;
|
||||
|
||||
std::vector<KRAudioBuffer*> m_bufferCache;
|
||||
|
||||
std::set<KRAudioSource*> m_activeAudioSources;
|
||||
|
||||
std::set<KRAudioSample*> m_openAudioSamples;
|
||||
|
||||
void initAudio();
|
||||
void initHRTF();
|
||||
|
||||
void cleanupAudio();
|
||||
|
||||
bool m_initialized;
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Apple Core Audio
|
||||
AUGraph m_auGraph;
|
||||
AudioUnit m_auMixer;
|
||||
|
||||
static OSStatus renderInput(void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData);
|
||||
void renderAudio(UInt32 inNumberFrames, AudioBufferList* ioData);
|
||||
#endif
|
||||
|
||||
siren::dsp::FFTWorkspace m_fft_setup[KRENGINE_REVERB_MAX_FFT_LOG2 - KRENGINE_AUDIO_BLOCK_LOG2N + 1];
|
||||
|
||||
__int64_t m_audio_frame; // Number of audio frames processed since the start of the application
|
||||
|
||||
float* m_reverb_input_samples; // Circular-buffered reverb input, single channel
|
||||
int m_reverb_input_next_sample; // Pointer to next sample in reverb buffer
|
||||
int m_reverb_sequence;
|
||||
|
||||
KRAudioSample* m_reverb_impulse_responses[KRENGINE_MAX_REVERB_IMPULSE_MIX];
|
||||
float m_reverb_impulse_responses_weight[KRENGINE_MAX_REVERB_IMPULSE_MIX];
|
||||
|
||||
float* m_output_accumulation; // Interleaved output accumulation buffer
|
||||
int m_output_accumulation_block_start;
|
||||
int m_output_sample;
|
||||
|
||||
float* m_workspace_data;
|
||||
siren::dsp::SplitComplex m_workspace[3];
|
||||
|
||||
float* getBlockAddress(int block_offset);
|
||||
void renderBlock();
|
||||
void renderReverb();
|
||||
void renderAmbient();
|
||||
void renderHRTF();
|
||||
void renderITD();
|
||||
void renderReverbImpulseResponse(int impulse_response_offset, int frame_count_log2);
|
||||
void renderLimiter();
|
||||
|
||||
std::vector<hydra::Vector2> m_hrtf_sample_locations;
|
||||
float* m_hrtf_data;
|
||||
unordered_map<hydra::Vector2, siren::dsp::SplitComplex> m_hrtf_spectral[2];
|
||||
|
||||
hydra::Vector2 getNearestHRTFSample(const hydra::Vector2& dir);
|
||||
void getHRTFMix(const hydra::Vector2& dir, hydra::Vector2& hrtf1, hydra::Vector2& hrtf2, hydra::Vector2& hrtf3, hydra::Vector2& hrtf4, float& mix1, float& mix2, float& mix3, float& mix4);
|
||||
KRAudioSample* getHRTFSample(const hydra::Vector2& hrtf_dir);
|
||||
siren::dsp::SplitComplex getHRTFSpectral(const hydra::Vector2& hrtf_dir, const int channel);
|
||||
|
||||
unordered_map<std::string, siren_ambient_zone_weight_info> m_ambient_zone_weights;
|
||||
float m_ambient_zone_total_weight = 0.0f; // For normalizing zone weights
|
||||
|
||||
unordered_map<std::string, siren_reverb_zone_weight_info> m_reverb_zone_weights;
|
||||
float m_reverb_zone_total_weight = 0.0f; // For normalizing zone weights
|
||||
|
||||
std::mutex m_mutex;
|
||||
#ifdef __APPLE__
|
||||
mach_timebase_info_data_t m_timebase_info;
|
||||
#endif
|
||||
|
||||
|
||||
unordered_multimap<hydra::Vector2, std::pair<KRAudioSource*, std::pair<float, float> > > m_mapped_sources, m_prev_mapped_sources;
|
||||
bool m_anticlick_block;
|
||||
bool m_high_quality_hrtf; // If true, 4 HRTF samples will be interpolated; if false, the nearest HRTF sample will be used without interpolation
|
||||
};
|
||||
396
kraken/resources/audio/KRAudioSample.cpp
Executable file
396
kraken/resources/audio/KRAudioSample.cpp
Executable file
@@ -0,0 +1,396 @@
|
||||
//
|
||||
// KRAudioSample.cpp
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#include "KRAudioSample.h"
|
||||
#include "KRAudioManager.h"
|
||||
#include "block.h"
|
||||
#include "KRAudioBuffer.h"
|
||||
#include "KRContext.h"
|
||||
#include "siren.h"
|
||||
|
||||
using namespace mimir;
|
||||
using namespace siren;
|
||||
|
||||
KRAudioSample::KRAudioSample(KRContext& context, std::string name, std::string extension) : KRResource(context, name)
|
||||
{
|
||||
m_pData = new Block();
|
||||
m_extension = extension;
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Apple Audio Toolbox
|
||||
m_audio_file_id = 0;
|
||||
m_fileRef = NULL;
|
||||
#endif
|
||||
m_totalFrames = 0;
|
||||
m_bytesPerFrame = 0;
|
||||
m_frameRate = 0;
|
||||
m_bufferCount = 0;
|
||||
|
||||
m_last_frame_used = 0;
|
||||
}
|
||||
|
||||
KRAudioSample::KRAudioSample(KRContext& context, std::string name, std::string extension, Block* data) : KRResource(context, name)
|
||||
{
|
||||
m_pData = data;
|
||||
m_extension = extension;
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Apple Audio Toolbox
|
||||
m_audio_file_id = 0;
|
||||
m_fileRef = NULL;
|
||||
#endif
|
||||
m_totalFrames = 0;
|
||||
m_bytesPerFrame = 0;
|
||||
m_frameRate = 0;
|
||||
m_bufferCount = 0;
|
||||
|
||||
m_last_frame_used = 0;
|
||||
}
|
||||
|
||||
KRAudioSample::~KRAudioSample()
|
||||
{
|
||||
closeFile();
|
||||
delete m_pData;
|
||||
}
|
||||
|
||||
int KRAudioSample::getChannelCount()
|
||||
{
|
||||
loadInfo();
|
||||
return m_channelsPerFrame;
|
||||
}
|
||||
|
||||
__int64_t KRAudioSample::getFrameCount()
|
||||
{
|
||||
loadInfo();
|
||||
//return (int)((__int64_t)m_totalFrames * (__int64_t)frame_rate / (__int64_t)m_frameRate);
|
||||
return m_totalFrames;
|
||||
}
|
||||
|
||||
float KRAudioSample::sample(int frame_offset, int frame_rate, int channel)
|
||||
{
|
||||
loadInfo();
|
||||
|
||||
int c = KRMIN(channel, m_channelsPerFrame - 1);
|
||||
|
||||
if (frame_offset < 0) {
|
||||
return 0.0f; // Past the beginning of the recording
|
||||
} else {
|
||||
int sample_frame;
|
||||
if (m_frameRate == frame_rate) {
|
||||
// No resampling required
|
||||
sample_frame = frame_offset;
|
||||
} else {
|
||||
// Need to resample from m_frameRate to frame_rate
|
||||
sample_frame = (int)((__int64_t)frame_offset * (__int64_t)m_frameRate / (__int64_t)frame_rate);
|
||||
}
|
||||
int maxFramesPerBuffer = KRENGINE_AUDIO_MAX_BUFFER_SIZE / m_bytesPerFrame;
|
||||
int buffer_index = sample_frame / maxFramesPerBuffer;
|
||||
if (buffer_index >= m_bufferCount) {
|
||||
return 0.0f; // Past the end of the recording
|
||||
} else {
|
||||
__int64_t buffer_offset = frame_offset - buffer_index * maxFramesPerBuffer;
|
||||
|
||||
KRAudioBuffer* buffer = getContext().getAudioManager()->getBuffer(*this, buffer_index);
|
||||
if (buffer == NULL) {
|
||||
return 0.0f;
|
||||
} else if (buffer_offset >= buffer->getFrameCount()) {
|
||||
return 0.0f; // past the end of the recording
|
||||
} else {
|
||||
short* frame = buffer->getFrameData() + (buffer_offset * m_channelsPerFrame);
|
||||
return frame[c] / 32767.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KRAudioSample::sample(__int64_t frame_offset, int frame_count, int channel, float* buffer, float amplitude, bool loop)
|
||||
{
|
||||
loadInfo();
|
||||
|
||||
m_last_frame_used = (int)getContext().getAudioManager()->getAudioFrame();
|
||||
|
||||
if (loop) {
|
||||
int buffer_offset = 0;
|
||||
int frames_left = frame_count;
|
||||
int sample_length = (int)getFrameCount();
|
||||
while (frames_left) {
|
||||
int next_frame = (int)(((__int64_t)frame_offset + (__int64_t)buffer_offset) % sample_length);
|
||||
if (next_frame + frames_left >= sample_length) {
|
||||
int frames_processed = sample_length - next_frame;
|
||||
sample(next_frame, frames_processed, channel, buffer + buffer_offset, amplitude, false);
|
||||
frames_left -= frames_processed;
|
||||
buffer_offset += frames_processed;
|
||||
} else {
|
||||
sample(next_frame, frames_left, channel, buffer + buffer_offset, amplitude, false);
|
||||
frames_left = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int c = KRMIN(channel, m_channelsPerFrame - 1);
|
||||
|
||||
if (frame_offset + frame_count <= 0) {
|
||||
// Range is entirely before the sample
|
||||
memset(buffer, 0, frame_count * sizeof(float));
|
||||
} else if (frame_offset >= m_totalFrames) {
|
||||
// Range is entirely after the sample
|
||||
memset(buffer, 0, frame_count * sizeof(float));
|
||||
} else {
|
||||
int start_frame = (int)(frame_offset < 0 ? 0 : frame_offset);
|
||||
int prefix_frames = (int)(frame_offset < 0 ? -frame_offset : 0);
|
||||
if (prefix_frames > 0) {
|
||||
// Prefix with padding of 0's
|
||||
memset(buffer, 0, prefix_frames * sizeof(float));
|
||||
}
|
||||
|
||||
int frames_per_buffer = KRENGINE_AUDIO_MAX_BUFFER_SIZE / m_bytesPerFrame;
|
||||
|
||||
int buffer_index = start_frame / frames_per_buffer;
|
||||
int buffer_offset = start_frame % frames_per_buffer;
|
||||
int processed_frames = prefix_frames;
|
||||
while (processed_frames < frame_count) {
|
||||
int frames_left = frame_count - processed_frames;
|
||||
if (buffer_index >= m_bufferCount) {
|
||||
// Suffix with padding of 0's
|
||||
memset(buffer + processed_frames, 0, frames_left * sizeof(float));
|
||||
processed_frames += frames_left;
|
||||
} else {
|
||||
KRAudioBuffer* source_buffer = getContext().getAudioManager()->getBuffer(*this, buffer_index);
|
||||
int frames_to_copy = source_buffer->getFrameCount() - buffer_offset;
|
||||
if (frames_to_copy > frames_left) frames_to_copy = frames_left;
|
||||
if (frames_to_copy > 0) {
|
||||
signed short* source_data = source_buffer->getFrameData() + buffer_offset * m_channelsPerFrame + c;
|
||||
siren::dsp::Int16ToFloat(source_data, m_channelsPerFrame, buffer + processed_frames, 1, frames_to_copy);
|
||||
//memcpy(buffer + processed_frames, source_buffer->getFrameData() + buffer_offset, frames_to_copy * m_channelsPerFrame * sizeof(float));
|
||||
processed_frames += frames_to_copy;
|
||||
}
|
||||
buffer_index++;
|
||||
buffer_offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float scale = amplitude / 32768.0f;
|
||||
siren::dsp::Scale(buffer, scale, frame_count);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Apple Audio Toolbox
|
||||
OSStatus KRAudioSample::ReadProc( // AudioFile_ReadProc
|
||||
void* inClientData,
|
||||
SInt64 inPosition,
|
||||
UInt32 requestCount,
|
||||
void* buffer,
|
||||
UInt32* actualCount)
|
||||
{
|
||||
KRAudioSample* sound = (KRAudioSample*)inClientData;
|
||||
UInt32 max_count = sound->m_pData->getSize() - inPosition;
|
||||
*actualCount = requestCount < max_count ? requestCount : max_count;
|
||||
sound->m_pData->copy(buffer, inPosition, *actualCount);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
SInt64 KRAudioSample::GetSizeProc( // AudioFile_GetSizeProc
|
||||
void* inClientData)
|
||||
{
|
||||
KRAudioSample* sound = (KRAudioSample*)inClientData;
|
||||
return sound->m_pData->getSize();
|
||||
}
|
||||
|
||||
OSStatus KRAudioSample::SetSizeProc( // AudioFile_SetSizeProc
|
||||
void* inClientData,
|
||||
SInt64 inSize)
|
||||
{
|
||||
return -1; // Writing not supported
|
||||
}
|
||||
|
||||
OSStatus KRAudioSample::WriteProc( // AudioFile_WriteProc
|
||||
void* inClientData,
|
||||
SInt64 inPosition,
|
||||
UInt32 requestCount,
|
||||
const void* buffer,
|
||||
UInt32* actualCount)
|
||||
{
|
||||
return -1; // Writing not supported
|
||||
}
|
||||
#endif // Apple Audio Toolbox
|
||||
|
||||
void KRAudioSample::openFile()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
// Apple Audio Toolbox
|
||||
|
||||
// AudioFileInitializeWithCallbacks
|
||||
if (m_fileRef == NULL) {
|
||||
|
||||
// printf("Call to KRAudioSample::openFile() with extension: %s\n", m_extension.c_str());
|
||||
// The m_extension is valid (it's either wav or mp3 for the files in Circa project)
|
||||
// so we can key off the extension and use a different data handler for mp3 files if we want to
|
||||
//
|
||||
|
||||
// Temp variables
|
||||
UInt32 propertySize;
|
||||
|
||||
// ---- Open audio file ----
|
||||
assert(AudioFileOpenWithCallbacks((void*)this, ReadProc, WriteProc, GetSizeProc, SetSizeProc, 0, &m_audio_file_id) == noErr);
|
||||
assert(ExtAudioFileWrapAudioFileID(m_audio_file_id, false, &m_fileRef) == noErr);
|
||||
|
||||
// ---- Get file format information ----
|
||||
AudioStreamBasicDescription inputFormat;
|
||||
propertySize = sizeof(inputFormat);
|
||||
ExtAudioFileGetProperty(m_fileRef, kExtAudioFileProperty_FileDataFormat, &propertySize, &inputFormat);
|
||||
|
||||
// ---- Set up output format ----
|
||||
AudioStreamBasicDescription outputFormat;
|
||||
// Set the client format to 16 bit signed integer (native-endian) data
|
||||
// Maintain the channel count and sample rate of the original source format
|
||||
outputFormat.mSampleRate = inputFormat.mSampleRate;
|
||||
outputFormat.mChannelsPerFrame = inputFormat.mChannelsPerFrame;
|
||||
outputFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
outputFormat.mBytesPerPacket = 2 * outputFormat.mChannelsPerFrame;
|
||||
outputFormat.mFramesPerPacket = 1;
|
||||
outputFormat.mBytesPerFrame = 2 * outputFormat.mChannelsPerFrame;
|
||||
outputFormat.mBitsPerChannel = 16;
|
||||
outputFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
|
||||
ExtAudioFileSetProperty(m_fileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(outputFormat), &outputFormat);
|
||||
|
||||
// ---- Get the buffer size and format parameters ----
|
||||
propertySize = sizeof(m_totalFrames);
|
||||
ExtAudioFileGetProperty(m_fileRef, kExtAudioFileProperty_FileLengthFrames, &propertySize, &m_totalFrames);
|
||||
|
||||
m_bytesPerFrame = outputFormat.mBytesPerFrame;
|
||||
m_frameRate = outputFormat.mSampleRate;
|
||||
|
||||
int maxFramesPerBuffer = KRENGINE_AUDIO_MAX_BUFFER_SIZE / m_bytesPerFrame;
|
||||
m_bufferCount = (m_totalFrames + maxFramesPerBuffer - 1) / maxFramesPerBuffer; // CEIL(_totalFrames / maxFramesPerBuffer)
|
||||
|
||||
m_channelsPerFrame = outputFormat.mChannelsPerFrame;
|
||||
|
||||
getContext().getAudioManager()->_registerOpenAudioSample(this);
|
||||
}
|
||||
#else
|
||||
#pragma message ( "TODO - implement for Windows" )
|
||||
#endif
|
||||
}
|
||||
|
||||
void KRAudioSample::closeFile()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
// Apple Audio Toolbox
|
||||
if (m_fileRef) {
|
||||
ExtAudioFileDispose(m_fileRef);
|
||||
m_fileRef = NULL;
|
||||
}
|
||||
|
||||
if (m_audio_file_id) {
|
||||
AudioFileClose(m_audio_file_id);
|
||||
m_audio_file_id = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
getContext().getAudioManager()->_registerCloseAudioSample(this);
|
||||
}
|
||||
|
||||
void KRAudioSample::loadInfo()
|
||||
{
|
||||
if (m_frameRate == 0) {
|
||||
openFile();
|
||||
closeFile();
|
||||
}
|
||||
}
|
||||
|
||||
std::string KRAudioSample::getExtension()
|
||||
{
|
||||
return m_extension;
|
||||
}
|
||||
|
||||
bool KRAudioSample::save(Block& data)
|
||||
{
|
||||
data.append(*m_pData);
|
||||
return true;
|
||||
}
|
||||
|
||||
float KRAudioSample::getDuration()
|
||||
{
|
||||
loadInfo();
|
||||
return (float)m_totalFrames / (float)m_frameRate;
|
||||
}
|
||||
|
||||
int KRAudioSample::getBufferCount()
|
||||
{
|
||||
loadInfo();
|
||||
return m_bufferCount;
|
||||
}
|
||||
|
||||
void KRAudioSample::PopulateBuffer(KRAudioSample* sound, int index, void* data)
|
||||
{
|
||||
int maxFramesPerBuffer = KRENGINE_AUDIO_MAX_BUFFER_SIZE / sound->m_bytesPerFrame;
|
||||
int startFrame = index * maxFramesPerBuffer;
|
||||
__uint32_t frameCount = (__uint32_t)KRMIN(sound->m_totalFrames - startFrame, maxFramesPerBuffer);
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Apple Audio Toolbox
|
||||
AudioBufferList outputBufferInfo;
|
||||
outputBufferInfo.mNumberBuffers = 1;
|
||||
outputBufferInfo.mBuffers[0].mDataByteSize = frameCount * sound->m_bytesPerFrame;
|
||||
outputBufferInfo.mBuffers[0].mNumberChannels = sound->m_channelsPerFrame;
|
||||
outputBufferInfo.mBuffers[0].mData = data;
|
||||
|
||||
// Read the data into an AudioBufferList
|
||||
ExtAudioFileSeek(sound->m_fileRef, startFrame);
|
||||
ExtAudioFileRead(sound->m_fileRef, (UInt32*)&frameCount, &outputBufferInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
KRAudioBuffer* KRAudioSample::getBuffer(int index)
|
||||
{
|
||||
openFile();
|
||||
|
||||
int maxFramesPerBuffer = KRENGINE_AUDIO_MAX_BUFFER_SIZE / m_bytesPerFrame;
|
||||
int startFrame = index * maxFramesPerBuffer;
|
||||
__uint32_t frameCount = (__uint32_t)KRMIN(m_totalFrames - startFrame, maxFramesPerBuffer);
|
||||
|
||||
KRAudioBuffer* buffer = new KRAudioBuffer(getContext().getAudioManager(), this, index, frameCount, m_frameRate, m_bytesPerFrame, PopulateBuffer);
|
||||
|
||||
if (m_bufferCount == 1) {
|
||||
// [self closeFile]; // We don't need to hold on to a file handle if not streaming
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void KRAudioSample::_endFrame()
|
||||
{
|
||||
const __int64_t AUDIO_SAMPLE_EXPIRY_FRAMES = 500;
|
||||
__int64_t current_frame = getContext().getAudioManager()->getAudioFrame();
|
||||
if (current_frame > m_last_frame_used + AUDIO_SAMPLE_EXPIRY_FRAMES) {
|
||||
closeFile();
|
||||
}
|
||||
}
|
||||
111
kraken/resources/audio/KRAudioSample.h
Executable file
111
kraken/resources/audio/KRAudioSample.h
Executable file
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// KRAudioSample.h
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "KREngine-common.h"
|
||||
#include "KRContextObject.h"
|
||||
#include "block.h"
|
||||
#include "resources/KRResource.h"
|
||||
|
||||
class KRAudioBuffer;
|
||||
|
||||
class KRAudioSample : public KRResource
|
||||
{
|
||||
|
||||
public:
|
||||
KRAudioSample(KRContext& context, std::string name, std::string extension);
|
||||
KRAudioSample(KRContext& context, std::string name, std::string extension, mimir::Block* data);
|
||||
virtual ~KRAudioSample();
|
||||
|
||||
virtual std::string getExtension();
|
||||
|
||||
virtual bool save(mimir::Block& data);
|
||||
|
||||
float getDuration();
|
||||
KRAudioBuffer* getBuffer(int index);
|
||||
int getBufferCount();
|
||||
|
||||
// Siren audio engine interface
|
||||
int getChannelCount();
|
||||
__int64_t getFrameCount();
|
||||
float sample(int frame_offset, int frame_rate, int channel);
|
||||
void sample(__int64_t frame_offset, int frame_count, int channel, float* buffer, float amplitude, bool loop);
|
||||
|
||||
void _endFrame();
|
||||
private:
|
||||
|
||||
__int64_t m_last_frame_used;
|
||||
|
||||
std::string m_extension;
|
||||
mimir::Block* m_pData;
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Apple Audio Toolbox
|
||||
AudioFileID m_audio_file_id;
|
||||
ExtAudioFileRef m_fileRef;
|
||||
|
||||
static OSStatus ReadProc( // AudioFile_ReadProc
|
||||
void* inClientData,
|
||||
SInt64 inPosition,
|
||||
UInt32 requestCount,
|
||||
void* buffer,
|
||||
UInt32* actualCount);
|
||||
|
||||
static OSStatus WriteProc( // AudioFile_WriteProc
|
||||
void* inClientData,
|
||||
SInt64 inPosition,
|
||||
UInt32 requestCount,
|
||||
const void* buffer,
|
||||
UInt32* actualCount);
|
||||
|
||||
static SInt64 GetSizeProc( // AudioFile_GetSizeProc
|
||||
void* inClientData);
|
||||
|
||||
|
||||
static OSStatus SetSizeProc( // AudioFile_SetSizeProc
|
||||
void* inClientData,
|
||||
SInt64 inSize);
|
||||
#endif
|
||||
|
||||
int m_bufferCount;
|
||||
|
||||
__int64_t m_totalFrames;
|
||||
int m_frameRate;
|
||||
int m_bytesPerFrame;
|
||||
int m_channelsPerFrame;
|
||||
|
||||
void openFile();
|
||||
void closeFile();
|
||||
void loadInfo();
|
||||
|
||||
static void PopulateBuffer(KRAudioSample* sound, int index, void* data);
|
||||
};
|
||||
1693
kraken/resources/mesh/KRMesh.cpp
Executable file
1693
kraken/resources/mesh/KRMesh.cpp
Executable file
File diff suppressed because it is too large
Load Diff
307
kraken/resources/mesh/KRMesh.h
Executable file
307
kraken/resources/mesh/KRMesh.h
Executable file
@@ -0,0 +1,307 @@
|
||||
//
|
||||
// KRMesh.h
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "KREngine-common.h"
|
||||
|
||||
#include "KRContext.h"
|
||||
#include "KRBone.h"
|
||||
#include "KRMeshManager.h"
|
||||
|
||||
#include "KREngine-common.h"
|
||||
|
||||
#include "hydra.h"
|
||||
|
||||
using namespace kraken;
|
||||
|
||||
#define MAX_VBO_SIZE 65535
|
||||
#define KRENGINE_MAX_BONE_WEIGHTS_PER_VERTEX 4
|
||||
#define KRENGINE_MAX_NAME_LENGTH 256
|
||||
// MAX_VBO_SIZE must be divisible by 3 so triangles aren't split across VBO objects...
|
||||
|
||||
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
|
||||
|
||||
#include "resources/material/KRMaterialManager.h"
|
||||
#include "KRCamera.h"
|
||||
#include "KRViewport.h"
|
||||
|
||||
class KRMaterial;
|
||||
class KRNode;
|
||||
class KRRenderPass;
|
||||
|
||||
enum class ModelFormat : __uint8_t
|
||||
{
|
||||
KRENGINE_MODEL_FORMAT_TRIANGLES = 0,
|
||||
KRENGINE_MODEL_FORMAT_STRIP,
|
||||
KRENGINE_MODEL_FORMAT_INDEXED_TRIANGLES,
|
||||
KRENGINE_MODEL_FORMAT_INDEXED_STRIP
|
||||
};
|
||||
|
||||
class KRMesh : public KRResource
|
||||
{
|
||||
|
||||
public:
|
||||
static void parseName(const std::string& name, std::string& lodBaseName, int& lodCoverage);
|
||||
|
||||
KRMesh(KRContext& context, std::string name, mimir::Block* data);
|
||||
KRMesh(KRContext& context, std::string name);
|
||||
virtual ~KRMesh();
|
||||
|
||||
kraken_stream_level getStreamLevel();
|
||||
void preStream(float lodCoverage);
|
||||
|
||||
bool hasTransparency();
|
||||
|
||||
typedef enum
|
||||
{
|
||||
KRENGINE_ATTRIB_VERTEX = 0,
|
||||
KRENGINE_ATTRIB_NORMAL,
|
||||
KRENGINE_ATTRIB_TANGENT,
|
||||
KRENGINE_ATTRIB_TEXUVA,
|
||||
KRENGINE_ATTRIB_TEXUVB,
|
||||
KRENGINE_ATTRIB_BONEINDEXES,
|
||||
KRENGINE_ATTRIB_BONEWEIGHTS,
|
||||
KRENGINE_ATTRIB_VERTEX_SHORT,
|
||||
KRENGINE_ATTRIB_NORMAL_SHORT,
|
||||
KRENGINE_ATTRIB_TANGENT_SHORT,
|
||||
KRENGINE_ATTRIB_TEXUVA_SHORT,
|
||||
KRENGINE_ATTRIB_TEXUVB_SHORT,
|
||||
KRENGINE_NUM_ATTRIBUTES
|
||||
} vertex_attrib_t;
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ModelFormat format;
|
||||
std::vector<hydra::Vector3> vertices;
|
||||
std::vector<__uint16_t> vertex_indexes;
|
||||
std::vector<std::pair<int, int> > vertex_index_bases;
|
||||
std::vector<hydra::Vector2> uva;
|
||||
std::vector<hydra::Vector2> uvb;
|
||||
std::vector<hydra::Vector3> normals;
|
||||
std::vector<hydra::Vector3> tangents;
|
||||
std::vector<int> submesh_starts;
|
||||
std::vector<int> submesh_lengths;
|
||||
std::vector<std::string> material_names;
|
||||
std::vector<std::string> bone_names;
|
||||
std::vector<std::vector<int> > bone_indexes;
|
||||
std::vector<hydra::Matrix4> bone_bind_poses;
|
||||
std::vector<std::vector<float> > bone_weights;
|
||||
} mesh_info;
|
||||
|
||||
void render(const KRNode::RenderInfo& ri, const std::string& object_name, const hydra::Matrix4& matModel, KRTexture* pLightMap, const std::vector<KRBone*>& bones, const hydra::Vector3& rim_color, float rim_power, float lod_coverage = 0.0f);
|
||||
|
||||
std::string m_lodBaseName;
|
||||
|
||||
virtual std::string getExtension();
|
||||
virtual bool save(const std::string& path);
|
||||
virtual bool save(mimir::Block& data);
|
||||
|
||||
void LoadData(const mesh_info& mi, bool calculate_normals, bool calculate_tangents);
|
||||
void loadPack(mimir::Block* data);
|
||||
|
||||
void convertToIndexed();
|
||||
void optimize();
|
||||
void optimizeIndexes();
|
||||
|
||||
void renderNoMaterials(VkCommandBuffer& commandBuffer, const KRRenderPass* renderPass, const std::string& object_name, const std::string& material_name, float lodCoverage);
|
||||
bool isReady() const;
|
||||
|
||||
float getMaxDimension();
|
||||
|
||||
hydra::Vector3 getMinPoint() const;
|
||||
hydra::Vector3 getMaxPoint() const;
|
||||
|
||||
class Submesh
|
||||
{
|
||||
public:
|
||||
Submesh()
|
||||
{};
|
||||
~Submesh()
|
||||
{
|
||||
vbo_data_blocks.clear();
|
||||
for (auto itr = vertex_data_blocks.begin(); itr != vertex_data_blocks.end(); itr++) {
|
||||
delete (*itr);
|
||||
}
|
||||
for (auto itr = index_data_blocks.begin(); itr != index_data_blocks.end(); itr++) {
|
||||
delete (*itr);
|
||||
}
|
||||
};
|
||||
|
||||
int start_vertex;
|
||||
int vertex_count;
|
||||
char szMaterialName[KRENGINE_MAX_NAME_LENGTH];
|
||||
vector<mimir::Block*> vertex_data_blocks;
|
||||
vector<mimir::Block*> index_data_blocks;
|
||||
// KRMeshManager depends on the address of KRVBOData's being constant
|
||||
// after allocation, enforced by deleted copy constructors.
|
||||
// As std::vector requires copy constuctors, we wrap these in shared_ptr.
|
||||
vector<shared_ptr<KRMeshManager::KRVBOData>> vbo_data_blocks;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{ // For Indexed triangles / strips
|
||||
uint16_t index_group;
|
||||
uint16_t index_group_offset;
|
||||
};
|
||||
int32_t start_vertex; // For non-indexed trigangles / strips
|
||||
};
|
||||
int32_t vertex_count;
|
||||
char szName[KRENGINE_MAX_NAME_LENGTH];
|
||||
} pack_material;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char szName[KRENGINE_MAX_NAME_LENGTH];
|
||||
float bind_pose[16];
|
||||
} pack_bone;
|
||||
|
||||
int getLODCoverage() const;
|
||||
std::string getLODBaseName() const;
|
||||
|
||||
|
||||
static bool lod_sort_predicate(const KRMesh* m1, const KRMesh* m2);
|
||||
bool has_vertex_attribute(vertex_attrib_t attribute_type) const;
|
||||
static bool has_vertex_attribute(int vertex_attrib_flags, vertex_attrib_t attribute_type);
|
||||
|
||||
int getSubmeshCount() const;
|
||||
int getVertexCount(int submesh) const;
|
||||
__uint32_t getVertexAttributes() const;
|
||||
|
||||
int getTriangleVertexIndex(int submesh, int index) const;
|
||||
hydra::Vector3 getVertexPosition(int index) const;
|
||||
hydra::Vector3 getVertexNormal(int index) const;
|
||||
hydra::Vector3 getVertexTangent(int index) const;
|
||||
hydra::Vector2 getVertexUVA(int index) const;
|
||||
hydra::Vector2 getVertexUVB(int index) const;
|
||||
int getBoneIndex(int index, int weight_index) const;
|
||||
float getBoneWeight(int index, int weight_index) const;
|
||||
|
||||
void setVertexPosition(int index, const hydra::Vector3& v);
|
||||
void setVertexNormal(int index, const hydra::Vector3& v);
|
||||
void setVertexTangent(int index, const hydra::Vector3& v);
|
||||
void setVertexUVA(int index, const hydra::Vector2& v);
|
||||
void setVertexUVB(int index, const hydra::Vector2& v);
|
||||
void setBoneIndex(int index, int weight_index, int bone_index);
|
||||
void setBoneWeight(int index, int weight_index, float bone_weight);
|
||||
|
||||
static size_t VertexSizeForAttributes(__int32_t vertex_attrib_flags);
|
||||
static size_t AttributeOffset(__int32_t vertex_attrib, __int32_t vertex_attrib_flags);
|
||||
static VkFormat AttributeVulkanFormat(__int32_t vertex_attrib);
|
||||
|
||||
int getBoneCount();
|
||||
char* getBoneName(int bone_index);
|
||||
hydra::Matrix4 getBoneBindPose(int bone_index);
|
||||
|
||||
|
||||
ModelFormat getModelFormat() const;
|
||||
|
||||
bool lineCast(const hydra::Vector3& v0, const hydra::Vector3& v1, hydra::HitInfo& hitinfo) const;
|
||||
bool rayCast(const hydra::Vector3& v0, const hydra::Vector3& dir, hydra::HitInfo& hitinfo) const;
|
||||
bool sphereCast(const hydra::Matrix4& model_to_world, const hydra::Vector3& v0, const hydra::Vector3& v1, float radius, hydra::HitInfo& hitinfo) const;
|
||||
|
||||
static int GetLODCoverage(const std::string& name);
|
||||
|
||||
protected:
|
||||
bool m_constant; // TRUE if this should be always loaded and should not be passed through the streamer
|
||||
|
||||
private:
|
||||
mimir::Block* m_pData;
|
||||
mimir::Block* m_pMetaData;
|
||||
mimir::Block* m_pIndexBaseData;
|
||||
|
||||
void getSubmeshes();
|
||||
void getMaterials();
|
||||
void renderSubmesh(VkCommandBuffer& commandBuffer, int iSubmesh, const KRRenderPass* renderPass, const std::string& object_name, const std::string& material_name, float lodCoverage);
|
||||
|
||||
static bool rayCast(const hydra::Vector3& start, const hydra::Vector3& dir, const hydra::Triangle3& tri, const hydra::Vector3& tri_n0, const hydra::Vector3& tri_n1, const hydra::Vector3& tri_n2, hydra::HitInfo& hitinfo);
|
||||
static bool sphereCast(const hydra::Matrix4& model_to_world, const hydra::Vector3& v0, const hydra::Vector3& v1, float radius, const hydra::Triangle3& tri, hydra::HitInfo& hitinfo);
|
||||
|
||||
int m_lodCoverage; // This LOD level is activated when the bounding box of the model will cover less than this percent of the screen (100 = highest detail model)
|
||||
vector<KRMaterial*> m_materials;
|
||||
set<KRMaterial*> m_uniqueMaterials;
|
||||
|
||||
bool m_hasTransparency;
|
||||
|
||||
|
||||
hydra::Vector3 m_minPoint, m_maxPoint;
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char szTag[16];
|
||||
int32_t model_format; // 0 == Triangle list, 1 == Triangle strips, 2 == Indexed triangle list, 3 == Indexed triangle strips, rest are reserved (model_format_t enum)
|
||||
int32_t vertex_attrib_flags;
|
||||
int32_t vertex_count;
|
||||
int32_t submesh_count;
|
||||
int32_t bone_count;
|
||||
float minx, miny, minz, maxx, maxy, maxz; // Axis aligned bounding box, in model's coordinate space
|
||||
int32_t index_count;
|
||||
int32_t index_base_count;
|
||||
unsigned char reserved[444]; // Pad out to 512 bytes
|
||||
} pack_header;
|
||||
|
||||
vector<Submesh> m_submeshes;
|
||||
int m_vertex_attribute_offset[KRENGINE_NUM_ATTRIBUTES];
|
||||
int m_vertex_size;
|
||||
void updateAttributeOffsets();
|
||||
|
||||
void setName(const std::string name);
|
||||
|
||||
|
||||
|
||||
pack_material* getSubmesh(int mesh_index) const;
|
||||
unsigned char* getVertexData() const;
|
||||
size_t getVertexDataOffset() const;
|
||||
unsigned char* getVertexData(int index) const;
|
||||
__uint16_t* getIndexData() const;
|
||||
size_t getIndexDataOffset() const;
|
||||
__uint32_t* getIndexBaseData() const;
|
||||
pack_header* getHeader() const;
|
||||
pack_bone* getBone(int index);
|
||||
|
||||
|
||||
void getIndexedRange(int index_group, int& start_index_offset, int& start_vertex_offset, int& index_count, int& vertex_count) const;
|
||||
|
||||
void releaseData();
|
||||
|
||||
void createDataBlocks(KRMeshManager::KRVBOData::vbo_type t);
|
||||
|
||||
|
||||
};
|
||||
70
kraken/resources/mesh/KRMeshCube.cpp
Executable file
70
kraken/resources/mesh/KRMeshCube.cpp
Executable file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// KRMeshCube.cpp
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#include "KRMeshCube.h"
|
||||
|
||||
using namespace hydra;
|
||||
|
||||
KRMeshCube::KRMeshCube(KRContext& context) : KRMesh(context, "__cube")
|
||||
{
|
||||
m_constant = true;
|
||||
|
||||
KRMesh::mesh_info mi;
|
||||
|
||||
mi.vertices.push_back(Vector3::Create(1.0, 1.0, 1.0));
|
||||
mi.vertices.push_back(Vector3::Create(-1.0, 1.0, 1.0));
|
||||
mi.vertices.push_back(Vector3::Create(1.0, -1.0, 1.0));
|
||||
mi.vertices.push_back(Vector3::Create(-1.0, -1.0, 1.0));
|
||||
mi.vertices.push_back(Vector3::Create(-1.0, -1.0, -1.0));
|
||||
mi.vertices.push_back(Vector3::Create(-1.0, 1.0, 1.0));
|
||||
mi.vertices.push_back(Vector3::Create(-1.0, 1.0, -1.0));
|
||||
mi.vertices.push_back(Vector3::Create(1.0, 1.0, 1.0));
|
||||
mi.vertices.push_back(Vector3::Create(1.0, 1.0, -1.0));
|
||||
mi.vertices.push_back(Vector3::Create(1.0, -1.0, 1.0));
|
||||
mi.vertices.push_back(Vector3::Create(1.0, -1.0, -1.0));
|
||||
mi.vertices.push_back(Vector3::Create(-1.0, -1.0, -1.0));
|
||||
mi.vertices.push_back(Vector3::Create(1.0, 1.0, -1.0));
|
||||
mi.vertices.push_back(Vector3::Create(-1.0, 1.0, -1.0));
|
||||
|
||||
|
||||
mi.submesh_starts.push_back(0);
|
||||
mi.submesh_lengths.push_back((int)mi.vertices.size());
|
||||
mi.material_names.push_back("");
|
||||
mi.format = ModelFormat::KRENGINE_MODEL_FORMAT_STRIP;
|
||||
|
||||
|
||||
LoadData(mi, true, true);
|
||||
}
|
||||
|
||||
KRMeshCube::~KRMeshCube()
|
||||
{
|
||||
|
||||
}
|
||||
43
kraken/resources/mesh/KRMeshCube.h
Executable file
43
kraken/resources/mesh/KRMeshCube.h
Executable file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// KRMeshCube.h
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "KRMesh.h"
|
||||
|
||||
class KRMeshCube : public KRMesh
|
||||
{
|
||||
public:
|
||||
KRMeshCube(KRContext& context);
|
||||
virtual ~KRMeshCube();
|
||||
private:
|
||||
};
|
||||
|
||||
715
kraken/resources/mesh/KRMeshManager.cpp
Executable file
715
kraken/resources/mesh/KRMeshManager.cpp
Executable file
@@ -0,0 +1,715 @@
|
||||
//
|
||||
// KRMeshManager.cpp
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#include "KREngine-common.h"
|
||||
|
||||
#include "KRMeshManager.h"
|
||||
|
||||
#include "KRMesh.h"
|
||||
#include "KRMeshCube.h"
|
||||
#include "KRMeshQuad.h"
|
||||
#include "KRMeshSphere.h"
|
||||
#include "KRRenderPass.h"
|
||||
|
||||
using namespace mimir;
|
||||
|
||||
KRMeshManager::KRMeshManager(KRContext& context)
|
||||
: KRResourceManager(context)
|
||||
, m_currentVBO(NULL)
|
||||
, m_vboMemUsed(0)
|
||||
, m_memoryTransferredThisFrame(0)
|
||||
, m_streamerComplete(true)
|
||||
, m_draw_call_logging_enabled(false)
|
||||
, m_draw_call_log_used(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void KRMeshManager::init()
|
||||
{
|
||||
addModel(new KRMeshCube(*m_pContext));
|
||||
addModel(new KRMeshQuad(*m_pContext));
|
||||
addModel(new KRMeshSphere(*m_pContext));
|
||||
|
||||
// ---- Initialize stock models ----
|
||||
static const float _KRENGINE_VBO_3D_CUBE_VERTEX_DATA[] = {
|
||||
1.0, 1.0, 1.0,
|
||||
-1.0, 1.0, 1.0,
|
||||
1.0,-1.0, 1.0,
|
||||
-1.0,-1.0, 1.0,
|
||||
-1.0,-1.0,-1.0,
|
||||
-1.0, 1.0, 1.0,
|
||||
-1.0, 1.0,-1.0,
|
||||
1.0, 1.0, 1.0,
|
||||
1.0, 1.0,-1.0,
|
||||
1.0,-1.0, 1.0,
|
||||
1.0,-1.0,-1.0,
|
||||
-1.0,-1.0,-1.0,
|
||||
1.0, 1.0,-1.0,
|
||||
-1.0, 1.0,-1.0
|
||||
};
|
||||
|
||||
KRENGINE_VBO_3D_CUBE_ATTRIBS = (1 << KRMesh::KRENGINE_ATTRIB_VERTEX);
|
||||
KRENGINE_VBO_3D_CUBE_VERTICES.expand(sizeof(float) * 3 * 14);
|
||||
KRENGINE_VBO_3D_CUBE_VERTICES.lock();
|
||||
memcpy(KRENGINE_VBO_3D_CUBE_VERTICES.getStart(), _KRENGINE_VBO_3D_CUBE_VERTEX_DATA, sizeof(float) * 3 * 14);
|
||||
KRENGINE_VBO_3D_CUBE_VERTICES.unlock();
|
||||
|
||||
KRENGINE_VBO_DATA_3D_CUBE_VERTICES.init(this, &KRENGINE_VBO_3D_CUBE_VERTICES, nullptr, KRENGINE_VBO_3D_CUBE_ATTRIBS, false, KRVBOData::CONSTANT
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
, "Cube Mesh [built-in]"
|
||||
#endif
|
||||
);
|
||||
|
||||
initRandomParticles();
|
||||
initVolumetricLightingVertexes();
|
||||
|
||||
static const float _KRENGINE_VBO_2D_SQUARE_VERTEX_DATA[] = {
|
||||
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
|
||||
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
|
||||
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
|
||||
1.0f, 1.0f, 0.0f, 1.0f, 1.0f
|
||||
};
|
||||
KRENGINE_VBO_2D_SQUARE_ATTRIBS = (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA);
|
||||
KRENGINE_VBO_2D_SQUARE_VERTICES.expand(sizeof(float) * 5 * 4);
|
||||
KRENGINE_VBO_2D_SQUARE_VERTICES.lock();
|
||||
memcpy(KRENGINE_VBO_2D_SQUARE_VERTICES.getStart(), _KRENGINE_VBO_2D_SQUARE_VERTEX_DATA, sizeof(float) * 5 * 4);
|
||||
KRENGINE_VBO_2D_SQUARE_VERTICES.unlock();
|
||||
|
||||
KRENGINE_VBO_DATA_2D_SQUARE_VERTICES.init(this, &KRENGINE_VBO_2D_SQUARE_VERTICES, nullptr, KRENGINE_VBO_2D_SQUARE_ATTRIBS, false, KRVBOData::CONSTANT
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
, "Square Mesh [built-in]"
|
||||
#endif
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
KRMeshManager::~KRMeshManager()
|
||||
{
|
||||
for (unordered_multimap<std::string, KRMesh*>::iterator itr = m_models.begin(); itr != m_models.end(); ++itr) {
|
||||
delete (*itr).second;
|
||||
}
|
||||
m_models.clear();
|
||||
}
|
||||
|
||||
KRResource* KRMeshManager::loadResource(const std::string& name, const std::string& extension, Block* data)
|
||||
{
|
||||
if (extension.compare("krmesh") == 0) {
|
||||
return loadModel(name.c_str(), data);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
KRResource* KRMeshManager::getResource(const std::string& name, const std::string& extension)
|
||||
{
|
||||
if (extension.compare("krmesh") == 0) {
|
||||
std::string lodBaseName;
|
||||
int lodCoverage;
|
||||
KRMesh::parseName(name, lodBaseName, lodCoverage);
|
||||
std::vector<KRMesh*> models = getModel(lodBaseName.c_str());
|
||||
for (KRMesh* mesh : models) {
|
||||
if (mesh->getLODCoverage() == lodCoverage) {
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
KRMesh* KRMeshManager::loadModel(const char* szName, Block* pData)
|
||||
{
|
||||
KRMesh* pModel = new KRMesh(*m_pContext, szName, pData);
|
||||
addModel(pModel);
|
||||
return pModel;
|
||||
}
|
||||
|
||||
void KRMeshManager::addModel(KRMesh* model)
|
||||
{
|
||||
std::string lowerName = model->getLODBaseName();
|
||||
std::transform(lowerName.begin(), lowerName.end(),
|
||||
lowerName.begin(), ::tolower);
|
||||
|
||||
m_models.insert(std::pair<std::string, KRMesh*>(lowerName, model));
|
||||
}
|
||||
|
||||
KRMesh* KRMeshManager::getMaxLODModel(const char* szName)
|
||||
{
|
||||
std::vector<KRMesh*> models = getModel(szName);
|
||||
// models are always in order of highest LOD first
|
||||
if (models.size()) {
|
||||
return models[0];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<KRMesh*> KRMeshManager::getModel(const char* szName)
|
||||
{
|
||||
std::string lowerName = szName;
|
||||
std::transform(lowerName.begin(), lowerName.end(),
|
||||
lowerName.begin(), ::tolower);
|
||||
|
||||
|
||||
std::vector<KRMesh*> matching_models;
|
||||
|
||||
std::pair<unordered_multimap<std::string, KRMesh*>::iterator, unordered_multimap<std::string, KRMesh*>::iterator> range = m_models.equal_range(lowerName);
|
||||
for (unordered_multimap<std::string, KRMesh*>::iterator itr_match = range.first; itr_match != range.second; itr_match++) {
|
||||
matching_models.push_back(itr_match->second);
|
||||
}
|
||||
|
||||
std::sort(matching_models.begin(), matching_models.end(), KRMesh::lod_sort_predicate);
|
||||
|
||||
if (matching_models.size() == 0) {
|
||||
KRContext::Log(KRContext::LOG_LEVEL_INFORMATION, "Model not found: %s", lowerName.c_str());
|
||||
}
|
||||
|
||||
return matching_models;
|
||||
}
|
||||
|
||||
unordered_multimap<std::string, KRMesh*>& KRMeshManager::getModels()
|
||||
{
|
||||
return m_models;
|
||||
}
|
||||
|
||||
void KRMeshManager::bindVBO(VkCommandBuffer& commandBuffer, KRVBOData* vbo_data, float lodCoverage)
|
||||
{
|
||||
vbo_data->resetPoolExpiry(lodCoverage);
|
||||
|
||||
bool vbo_changed = false;
|
||||
if (m_currentVBO == NULL) {
|
||||
vbo_changed = true;
|
||||
} else if (m_currentVBO->m_data != vbo_data->m_data) {
|
||||
vbo_changed = true;
|
||||
}
|
||||
|
||||
if (vbo_changed) {
|
||||
|
||||
if (m_vbosActive.find(vbo_data->m_data) != m_vbosActive.end()) {
|
||||
m_currentVBO = m_vbosActive[vbo_data->m_data];
|
||||
} else {
|
||||
m_currentVBO = vbo_data;
|
||||
|
||||
m_vbosActive[vbo_data->m_data] = m_currentVBO;
|
||||
}
|
||||
|
||||
m_currentVBO->bind(commandBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void KRMeshManager::startFrame(float deltaTime)
|
||||
{
|
||||
m_memoryTransferredThisFrame = 0;
|
||||
if (m_draw_call_log_used) {
|
||||
// Only log draw calls on the next frame if the draw call log was used on last frame
|
||||
m_draw_call_log_used = false;
|
||||
m_draw_call_logging_enabled = true;
|
||||
}
|
||||
m_draw_calls.clear();
|
||||
|
||||
// TODO - Implement proper double-buffering to reduce copy operations
|
||||
m_streamerFenceMutex.lock();
|
||||
|
||||
if (m_streamerComplete) {
|
||||
assert(m_activeVBOs_streamer_copy.size() == 0); // The streamer should have emptied this if it really did complete
|
||||
|
||||
const long KRENGINE_VBO_EXPIRY_FRAMES = 1;
|
||||
|
||||
std::set<KRVBOData*> expiredVBOs;
|
||||
for (auto itr = m_vbosActive.begin(); itr != m_vbosActive.end(); itr++) {
|
||||
KRVBOData* activeVBO = (*itr).second;
|
||||
activeVBO->_swapHandles();
|
||||
if (activeVBO->getType() == KRVBOData::CONSTANT) {
|
||||
// Ensure that CONSTANT data is always loaded
|
||||
float priority = std::numeric_limits<float>::max();
|
||||
m_activeVBOs_streamer_copy.push_back(std::pair<float, KRVBOData*>(priority, activeVBO));
|
||||
} else if (activeVBO->getLastFrameUsed() + KRENGINE_VBO_EXPIRY_FRAMES < getContext().getCurrentFrame()) {
|
||||
// Expire VBO's that haven't been used in a long time
|
||||
|
||||
switch (activeVBO->getType()) {
|
||||
case KRVBOData::STREAMING:
|
||||
case KRVBOData::IMMEDIATE:
|
||||
activeVBO->unload();
|
||||
break;
|
||||
case KRVBOData::CONSTANT:
|
||||
// CONSTANT VBO's are not unloaded
|
||||
break;
|
||||
}
|
||||
|
||||
expiredVBOs.insert(activeVBO);
|
||||
} else if (activeVBO->getType() == KRVBOData::STREAMING) {
|
||||
float priority = activeVBO->getStreamPriority();
|
||||
m_activeVBOs_streamer_copy.push_back(std::pair<float, KRVBOData*>(priority, activeVBO));
|
||||
}
|
||||
}
|
||||
for (std::set<KRVBOData*>::iterator itr = expiredVBOs.begin(); itr != expiredVBOs.end(); itr++) {
|
||||
m_vbosActive.erase((*itr)->m_data);
|
||||
}
|
||||
|
||||
if (m_activeVBOs_streamer_copy.size() > 0) {
|
||||
m_streamerComplete = false;
|
||||
}
|
||||
}
|
||||
m_streamerFenceMutex.unlock();
|
||||
|
||||
}
|
||||
|
||||
void KRMeshManager::endFrame(float deltaTime)
|
||||
{
|
||||
m_currentVBO = nullptr;
|
||||
}
|
||||
|
||||
void KRMeshManager::doStreaming(long& memoryRemaining, long& memoryRemainingThisFrame)
|
||||
{
|
||||
|
||||
// TODO - Implement proper double-buffering to reduce copy operations
|
||||
m_streamerFenceMutex.lock();
|
||||
m_activeVBOs_streamer = std::move(m_activeVBOs_streamer_copy);
|
||||
m_streamerFenceMutex.unlock();
|
||||
|
||||
if (m_activeVBOs_streamer.size() > 0) {
|
||||
balanceVBOMemory(memoryRemaining, memoryRemainingThisFrame);
|
||||
|
||||
m_streamerFenceMutex.lock();
|
||||
m_streamerComplete = true;
|
||||
m_streamerFenceMutex.unlock();
|
||||
} else {
|
||||
memoryRemaining -= getMemUsed();
|
||||
}
|
||||
}
|
||||
|
||||
void KRMeshManager::balanceVBOMemory(long& memoryRemaining, long& memoryRemainingThisFrame)
|
||||
{
|
||||
std::sort(m_activeVBOs_streamer.begin(), m_activeVBOs_streamer.end(), std::greater<std::pair<float, KRVBOData*>>());
|
||||
|
||||
|
||||
for (auto vbo_itr = m_activeVBOs_streamer.begin(); vbo_itr != m_activeVBOs_streamer.end(); vbo_itr++) {
|
||||
KRVBOData* vbo_data = (*vbo_itr).second;
|
||||
long vbo_size = vbo_data->getSize();
|
||||
if (!vbo_data->isVBOLoaded()) {
|
||||
if (memoryRemainingThisFrame > vbo_size) {
|
||||
vbo_data->load();
|
||||
memoryRemainingThisFrame -= vbo_size;
|
||||
}
|
||||
}
|
||||
memoryRemaining -= vbo_size;
|
||||
}
|
||||
}
|
||||
|
||||
long KRMeshManager::getMemUsed()
|
||||
{
|
||||
return m_vboMemUsed;
|
||||
}
|
||||
|
||||
long KRMeshManager::getMemActive()
|
||||
{
|
||||
long mem_active = 0;
|
||||
for (unordered_map<Block*, KRVBOData*>::iterator itr = m_vbosActive.begin(); itr != m_vbosActive.end(); itr++) {
|
||||
mem_active += (*itr).second->getSize();
|
||||
}
|
||||
return mem_active;
|
||||
}
|
||||
|
||||
void KRMeshManager::initVolumetricLightingVertexes()
|
||||
{
|
||||
if (m_volumetricLightingVertexData.getSize() == 0) {
|
||||
m_volumetricLightingVertexData.expand(sizeof(VolumetricLightingVertexData) * KRENGINE_MAX_VOLUMETRIC_PLANES * 6);
|
||||
m_volumetricLightingVertexData.lock();
|
||||
VolumetricLightingVertexData* vertex_data = (VolumetricLightingVertexData*)m_volumetricLightingVertexData.getStart();
|
||||
int iVertex = 0;
|
||||
for (int iPlane = 0; iPlane < KRENGINE_MAX_VOLUMETRIC_PLANES; iPlane++) {
|
||||
vertex_data[iVertex].vertex.x = -1.0f;
|
||||
vertex_data[iVertex].vertex.y = -1.0f;
|
||||
vertex_data[iVertex].vertex.z = (float)iPlane;
|
||||
iVertex++;
|
||||
|
||||
vertex_data[iVertex].vertex.x = 1.0f;
|
||||
vertex_data[iVertex].vertex.y = -1.0f;
|
||||
vertex_data[iVertex].vertex.z = (float)iPlane;
|
||||
iVertex++;
|
||||
|
||||
vertex_data[iVertex].vertex.x = -1.0f;
|
||||
vertex_data[iVertex].vertex.y = 1.0f;
|
||||
vertex_data[iVertex].vertex.z = (float)iPlane;
|
||||
iVertex++;
|
||||
|
||||
vertex_data[iVertex].vertex.x = -1.0f;
|
||||
vertex_data[iVertex].vertex.y = 1.0f;
|
||||
vertex_data[iVertex].vertex.z = (float)iPlane;
|
||||
iVertex++;
|
||||
|
||||
vertex_data[iVertex].vertex.x = 1.0f;
|
||||
vertex_data[iVertex].vertex.y = -1.0f;
|
||||
vertex_data[iVertex].vertex.z = (float)iPlane;
|
||||
iVertex++;
|
||||
|
||||
vertex_data[iVertex].vertex.x = 1.0f;
|
||||
vertex_data[iVertex].vertex.y = 1.0f;
|
||||
vertex_data[iVertex].vertex.z = (float)iPlane;
|
||||
iVertex++;
|
||||
|
||||
}
|
||||
|
||||
KRENGINE_VBO_DATA_VOLUMETRIC_LIGHTING.init(this, &m_volumetricLightingVertexData, nullptr, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX), false, KRVBOData::CONSTANT
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
, "Volumetric Lighting Planes [built-in]"
|
||||
#endif
|
||||
);
|
||||
|
||||
m_volumetricLightingVertexData.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void KRMeshManager::initRandomParticles()
|
||||
{
|
||||
if (m_randomParticleVertexData.getSize() == 0) {
|
||||
m_randomParticleVertexData.expand(sizeof(RandomParticleVertexData) * KRENGINE_MAX_RANDOM_PARTICLES * 3);
|
||||
m_randomParticleVertexData.lock();
|
||||
RandomParticleVertexData* vertex_data = (RandomParticleVertexData*)m_randomParticleVertexData.getStart();
|
||||
|
||||
// Generate vertices for randomly placed equilateral triangles with a side length of 1 and an origin point centered so that an inscribed circle can be efficiently rendered without wasting fill
|
||||
|
||||
float equilateral_triangle_height = sqrt(3.0f) * 0.5f;
|
||||
float inscribed_circle_radius = 1.0f / (2.0f * sqrt(3.0f));
|
||||
|
||||
int iVertex = 0;
|
||||
for (int iParticle = 0; iParticle < KRENGINE_MAX_RANDOM_PARTICLES; iParticle++) {
|
||||
vertex_data[iVertex].vertex.x = (float)(rand() % 2000) / 1000.0f - 1000.0f;
|
||||
vertex_data[iVertex].vertex.y = (float)(rand() % 2000) / 1000.0f - 1000.0f;
|
||||
vertex_data[iVertex].vertex.z = (float)(rand() % 2000) / 1000.0f - 1000.0f;
|
||||
vertex_data[iVertex].uva.x = -0.5f;
|
||||
vertex_data[iVertex].uva.y = -inscribed_circle_radius;
|
||||
iVertex++;
|
||||
|
||||
vertex_data[iVertex].vertex.x = vertex_data[iVertex - 1].vertex.x;
|
||||
vertex_data[iVertex].vertex.y = vertex_data[iVertex - 1].vertex.y;
|
||||
vertex_data[iVertex].vertex.z = vertex_data[iVertex - 1].vertex.z;
|
||||
vertex_data[iVertex].uva.x = 0.5f;
|
||||
vertex_data[iVertex].uva.y = -inscribed_circle_radius;
|
||||
iVertex++;
|
||||
|
||||
vertex_data[iVertex].vertex.x = vertex_data[iVertex - 1].vertex.x;
|
||||
vertex_data[iVertex].vertex.y = vertex_data[iVertex - 1].vertex.y;
|
||||
vertex_data[iVertex].vertex.z = vertex_data[iVertex - 1].vertex.z;
|
||||
vertex_data[iVertex].uva.x = 0.0f;
|
||||
vertex_data[iVertex].uva.y = -inscribed_circle_radius + equilateral_triangle_height;
|
||||
iVertex++;
|
||||
}
|
||||
|
||||
KRENGINE_VBO_DATA_RANDOM_PARTICLES.init(this, &m_randomParticleVertexData, nullptr, (1 << KRMesh::KRENGINE_ATTRIB_VERTEX) | (1 << KRMesh::KRENGINE_ATTRIB_TEXUVA), false, KRVBOData::CONSTANT
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
, "Random Particles [built-in]"
|
||||
#endif
|
||||
);
|
||||
|
||||
m_randomParticleVertexData.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
long KRMeshManager::getMemoryTransferedThisFrame()
|
||||
{
|
||||
return m_memoryTransferredThisFrame;
|
||||
}
|
||||
|
||||
|
||||
size_t KRMeshManager::getActiveVBOCount()
|
||||
{
|
||||
return m_vbosActive.size();
|
||||
}
|
||||
|
||||
void KRMeshManager::log_draw_call(RenderPassType pass, const std::string& object_name, const std::string& material_name, int vertex_count)
|
||||
{
|
||||
if (m_draw_call_logging_enabled) {
|
||||
draw_call_info info;
|
||||
info.pass = pass;
|
||||
strncpy(info.object_name, object_name.c_str(), 256);
|
||||
strncpy(info.material_name, material_name.c_str(), 256);
|
||||
info.vertex_count = vertex_count;
|
||||
m_draw_calls.push_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<KRMeshManager::draw_call_info> KRMeshManager::getDrawCalls()
|
||||
{
|
||||
m_draw_call_log_used = true;
|
||||
return m_draw_calls;
|
||||
}
|
||||
|
||||
KRMeshManager::KRVBOData::KRVBOData()
|
||||
{
|
||||
m_debugLabel[0] = '\0';
|
||||
m_is_vbo_loaded = false;
|
||||
m_is_vbo_ready = false;
|
||||
m_manager = NULL;
|
||||
m_type = STREAMING;
|
||||
m_data = NULL;
|
||||
m_index_data = NULL;
|
||||
m_vertex_attrib_flags = 0;
|
||||
m_size = 0;
|
||||
|
||||
m_last_frame_used = 0;
|
||||
m_last_frame_max_lod_coverage = 0.0f;
|
||||
|
||||
memset(m_allocations, 0, sizeof(AllocationInfo) * KRENGINE_MAX_GPU_COUNT);
|
||||
}
|
||||
|
||||
KRMeshManager::KRVBOData::KRVBOData(KRMeshManager* manager, Block* data, Block* index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
, const char* debug_label
|
||||
#endif
|
||||
)
|
||||
{
|
||||
m_debugLabel[0] = '\0';
|
||||
memset(m_allocations, 0, sizeof(AllocationInfo) * KRENGINE_MAX_GPU_COUNT);
|
||||
m_is_vbo_loaded = false;
|
||||
m_is_vbo_ready = false;
|
||||
init(manager, data, index_data, vertex_attrib_flags, static_vbo, t
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
, debug_label
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
void KRMeshManager::KRVBOData::init(KRMeshManager* manager, Block* data, Block* index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
, const char* debug_label
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
snprintf(m_debugLabel, KRENGINE_DEBUG_GPU_LABEL_MAX_LEN, debug_label);
|
||||
#endif //KRENGINE_DEBUG_GPU_LABELS
|
||||
m_manager = manager;
|
||||
m_type = t;
|
||||
m_static_vbo = static_vbo;
|
||||
m_data = data;
|
||||
m_index_data = index_data;
|
||||
m_vertex_attrib_flags = vertex_attrib_flags;
|
||||
|
||||
m_size = m_data->getSize();
|
||||
if (m_index_data != NULL) {
|
||||
m_size += m_index_data->getSize();
|
||||
}
|
||||
|
||||
if (t == KRVBOData::CONSTANT) {
|
||||
m_manager->primeVBO(this);
|
||||
}
|
||||
}
|
||||
|
||||
KRMeshManager::KRVBOData::~KRVBOData()
|
||||
{
|
||||
// TODO - This needs to be done by the streamer thread, and asserted here...
|
||||
unload();
|
||||
}
|
||||
|
||||
void KRMeshManager::KRVBOData::load()
|
||||
{
|
||||
// TODO - This is a bit messy. Clean up after Vulkan refactor.
|
||||
VkCommandBuffer noCommandBuffer = VK_NULL_HANDLE;
|
||||
load(noCommandBuffer);
|
||||
}
|
||||
|
||||
void KRMeshManager::KRVBOData::load(VkCommandBuffer& commandBuffer)
|
||||
{
|
||||
// TODO - We should load on each GPU only if there is a surface using the mesh
|
||||
if (isVBOLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
KRDeviceManager* deviceManager = m_manager->getContext().getDeviceManager();
|
||||
int iAllocation = 0;
|
||||
|
||||
for (auto deviceItr = deviceManager->getDevices().begin(); deviceItr != deviceManager->getDevices().end() && iAllocation < KRENGINE_MAX_GPU_COUNT; deviceItr++, iAllocation++) {
|
||||
KRDevice& device = *(*deviceItr).second;
|
||||
KrDeviceHandle deviceHandle = (*deviceItr).first;
|
||||
VmaAllocator allocator = device.getAllocator();
|
||||
AllocationInfo& allocation = m_allocations[iAllocation];
|
||||
allocation.device = deviceHandle;
|
||||
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
char debug_label[KRENGINE_DEBUG_GPU_LABEL_MAX_LEN];
|
||||
|
||||
const char* type_label = "";
|
||||
|
||||
switch (m_type) {
|
||||
case vbo_type::STREAMING:
|
||||
type_label = "Streaming";
|
||||
break;
|
||||
case vbo_type::CONSTANT:
|
||||
type_label = "Constant";
|
||||
break;
|
||||
case vbo_type::IMMEDIATE:
|
||||
type_label = "Immediate";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
snprintf(debug_label, KRENGINE_DEBUG_GPU_LABEL_MAX_LEN, "%s Vertices: %s", type_label, m_debugLabel);
|
||||
#endif // KRENGINE_DEBUG_GPU_LABELS
|
||||
|
||||
device.createBuffer(
|
||||
m_data->getSize(),
|
||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
&allocation.vertex_buffer,
|
||||
&allocation.vertex_allocation
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
, debug_label
|
||||
#endif // KRENGINE_DEBUG_GPU_LABELS
|
||||
);
|
||||
if (m_type == vbo_type::IMMEDIATE) {
|
||||
device.graphicsUpload(commandBuffer, *m_data, allocation.vertex_buffer);
|
||||
} else {
|
||||
device.streamUpload(*m_data, allocation.vertex_buffer);
|
||||
}
|
||||
|
||||
|
||||
if (m_index_data && m_index_data->getSize() > 0) {
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
snprintf(debug_label, KRENGINE_DEBUG_GPU_LABEL_MAX_LEN, "%s Indexes: %s", type_label, m_debugLabel);
|
||||
#endif // KRENGINE_DEBUG_GPU_LABELS
|
||||
device.createBuffer(
|
||||
m_index_data->getSize(),
|
||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
&allocation.index_buffer,
|
||||
&allocation.index_allocation
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
, debug_label
|
||||
#endif
|
||||
);
|
||||
if (m_type == vbo_type::IMMEDIATE) {
|
||||
device.graphicsUpload(commandBuffer, *m_index_data, allocation.index_buffer);
|
||||
} else {
|
||||
device.streamUpload(*m_index_data, allocation.index_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_is_vbo_loaded = true;
|
||||
|
||||
m_manager->m_vboMemUsed += getSize();
|
||||
m_manager->m_memoryTransferredThisFrame += getSize();
|
||||
|
||||
if (m_type != STREAMING) {
|
||||
_swapHandles();
|
||||
}
|
||||
}
|
||||
|
||||
void KRMeshManager::KRVBOData::unload()
|
||||
{
|
||||
KRDeviceManager* deviceManager = m_manager->getContext().getDeviceManager();
|
||||
for (int i = 0; i < KRENGINE_MAX_GPU_COUNT; i++) {
|
||||
AllocationInfo& allocation = m_allocations[i];
|
||||
if (allocation.device) {
|
||||
std::unique_ptr<KRDevice>& device = deviceManager->getDevice(allocation.device);
|
||||
if (device) {
|
||||
VmaAllocator allocator = device->getAllocator();
|
||||
vmaDestroyBuffer(allocator, allocation.vertex_buffer, allocation.vertex_allocation);
|
||||
if (allocation.index_buffer) {
|
||||
vmaDestroyBuffer(allocator, allocation.index_buffer, allocation.index_allocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
memset(&allocation, 0, sizeof(AllocationInfo));
|
||||
}
|
||||
|
||||
if (isVBOLoaded()) {
|
||||
m_manager->m_vboMemUsed -= getSize();
|
||||
}
|
||||
|
||||
m_is_vbo_loaded = false;
|
||||
m_is_vbo_ready = false;
|
||||
}
|
||||
|
||||
void KRMeshManager::KRVBOData::bind(VkCommandBuffer& commandBuffer)
|
||||
{
|
||||
VkBuffer vertexBuffers[] = { getVertexBuffer() };
|
||||
VkDeviceSize offsets[] = { 0 };
|
||||
vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
|
||||
|
||||
if (m_index_data && m_index_data->getSize() > 0) {
|
||||
// TODO - Support 32-bit index buffers
|
||||
vkCmdBindIndexBuffer(commandBuffer, getIndexBuffer(), 0, VK_INDEX_TYPE_UINT16);
|
||||
}
|
||||
}
|
||||
|
||||
void KRMeshManager::KRVBOData::resetPoolExpiry(float lodCoverage)
|
||||
{
|
||||
long current_frame = m_manager->getContext().getCurrentFrame();
|
||||
if (current_frame != m_last_frame_used) {
|
||||
m_last_frame_used = current_frame;
|
||||
m_last_frame_max_lod_coverage = 0.0f;
|
||||
|
||||
m_manager->primeVBO(this);
|
||||
}
|
||||
m_last_frame_max_lod_coverage = KRMAX(lodCoverage, m_last_frame_max_lod_coverage);
|
||||
}
|
||||
|
||||
|
||||
float KRMeshManager::KRVBOData::getStreamPriority()
|
||||
{
|
||||
long current_frame = m_manager->getContext().getCurrentFrame();
|
||||
if (current_frame > m_last_frame_used + 5) {
|
||||
return 1.0f - KRCLAMP((float)(current_frame - m_last_frame_used) / 60.0f, 0.0f, 1.0f);
|
||||
} else {
|
||||
return 10000.0f + m_last_frame_max_lod_coverage * 10.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void KRMeshManager::KRVBOData::_swapHandles()
|
||||
{
|
||||
m_is_vbo_ready = m_is_vbo_loaded;
|
||||
}
|
||||
|
||||
void KRMeshManager::primeVBO(KRVBOData* vbo_data)
|
||||
{
|
||||
if (m_vbosActive.find(vbo_data->m_data) == m_vbosActive.end()) {
|
||||
m_vbosActive[vbo_data->m_data] = vbo_data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VkBuffer& KRMeshManager::KRVBOData::getVertexBuffer()
|
||||
{
|
||||
assert(m_is_vbo_ready);
|
||||
return m_allocations->vertex_buffer;
|
||||
}
|
||||
|
||||
VkBuffer& KRMeshManager::KRVBOData::getIndexBuffer()
|
||||
{
|
||||
assert(m_is_vbo_ready);
|
||||
return m_allocations->index_buffer;
|
||||
}
|
||||
|
||||
|
||||
uint32_t KRMeshManager::KRVBOData::getVertexAttributes()
|
||||
{
|
||||
return m_vertex_attrib_flags;
|
||||
}
|
||||
248
kraken/resources/mesh/KRMeshManager.h
Executable file
248
kraken/resources/mesh/KRMeshManager.h
Executable file
@@ -0,0 +1,248 @@
|
||||
//
|
||||
// KRMeshManager.h
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "KREngine-common.h"
|
||||
|
||||
#include "resources/KRResourceManager.h"
|
||||
#include "KRContextObject.h"
|
||||
#include "block.h"
|
||||
#include "KRNode.h"
|
||||
|
||||
class KRContext;
|
||||
class KRMesh;
|
||||
enum RenderPassType : uint8_t;
|
||||
|
||||
class KRMeshManager : public KRResourceManager
|
||||
{
|
||||
public:
|
||||
static const int KRENGINE_MAX_VOLUMETRIC_PLANES = 500;
|
||||
static const int KRENGINE_MAX_RANDOM_PARTICLES = 150000;
|
||||
|
||||
KRMeshManager(KRContext& context);
|
||||
void init();
|
||||
virtual ~KRMeshManager();
|
||||
|
||||
virtual KRResource* loadResource(const std::string& name, const std::string& extension, mimir::Block* data) override;
|
||||
virtual KRResource* getResource(const std::string& name, const std::string& extension) override;
|
||||
|
||||
void startFrame(float deltaTime);
|
||||
void endFrame(float deltaTime);
|
||||
|
||||
KRMesh* loadModel(const char* szName, mimir::Block* pData);
|
||||
std::vector<KRMesh*> getModel(const char* szName);
|
||||
KRMesh* getMaxLODModel(const char* szName);
|
||||
void addModel(KRMesh* model);
|
||||
|
||||
std::vector<std::string> getModelNames();
|
||||
unordered_multimap<std::string, KRMesh*>& getModels();
|
||||
|
||||
class KRVBOData
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STREAMING,
|
||||
// STREAMING data is loaded asynchronously, with transfer queues in the streamer thread.
|
||||
|
||||
CONSTANT,
|
||||
// CONSTANT data is loaded asyncrhronously, with transfer queues in the streamer thread, but is not unloaded.
|
||||
|
||||
IMMEDIATE
|
||||
// IMMEDIATE data is loaded synchronously, with graphics queues in the presentation threads.
|
||||
// IMMEDIATE data is available for use immediately on the same frame it is generated.
|
||||
} vbo_type;
|
||||
|
||||
KRVBOData();
|
||||
KRVBOData(KRMeshManager* manager, mimir::Block* data, mimir::Block* index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
, const char* debug_label
|
||||
#endif
|
||||
);
|
||||
void init(KRMeshManager* manager, mimir::Block* data, mimir::Block* index_data, int vertex_attrib_flags, bool static_vbo, vbo_type t
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
, const char* debug_label
|
||||
#endif
|
||||
);
|
||||
~KRVBOData();
|
||||
|
||||
|
||||
mimir::Block* m_data;
|
||||
mimir::Block* m_index_data;
|
||||
|
||||
bool isVBOLoaded()
|
||||
{
|
||||
return m_is_vbo_loaded;
|
||||
}
|
||||
bool isVBOReady() const
|
||||
{
|
||||
return m_is_vbo_ready;
|
||||
}
|
||||
void load();
|
||||
void load(VkCommandBuffer& commandBuffer);
|
||||
void unload();
|
||||
void bind(VkCommandBuffer& commandBuffer);
|
||||
|
||||
// KRMeshManager depends on the address of KRVBOData's being constant
|
||||
// after allocation. This is enforced by deleted copy constructors.
|
||||
KRVBOData(const KRVBOData& o) = delete;
|
||||
KRVBOData& operator=(const KRVBOData& o) = delete;
|
||||
|
||||
long getSize()
|
||||
{
|
||||
return (long)m_size;
|
||||
}
|
||||
|
||||
void resetPoolExpiry(float lodCoverage);
|
||||
long getLastFrameUsed()
|
||||
{
|
||||
return m_last_frame_used;
|
||||
}
|
||||
|
||||
vbo_type getType()
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
float getStreamPriority();
|
||||
|
||||
void _swapHandles();
|
||||
|
||||
VkBuffer& getVertexBuffer();
|
||||
VkBuffer& getIndexBuffer();
|
||||
uint32_t getVertexAttributes();
|
||||
|
||||
private:
|
||||
KRMeshManager* m_manager;
|
||||
int m_vertex_attrib_flags;
|
||||
long m_size;
|
||||
|
||||
long m_last_frame_used;
|
||||
float m_last_frame_max_lod_coverage;
|
||||
vbo_type m_type;
|
||||
bool m_static_vbo;
|
||||
bool m_is_vbo_loaded;
|
||||
bool m_is_vbo_ready;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
KrDeviceHandle device;
|
||||
VkBuffer vertex_buffer;
|
||||
VmaAllocation vertex_allocation;
|
||||
VkBuffer index_buffer;
|
||||
VmaAllocation index_allocation;
|
||||
} AllocationInfo;
|
||||
|
||||
AllocationInfo m_allocations[KRENGINE_MAX_GPU_COUNT];
|
||||
|
||||
#if KRENGINE_DEBUG_GPU_LABELS
|
||||
char m_debugLabel[KRENGINE_DEBUG_GPU_LABEL_MAX_LEN];
|
||||
#endif
|
||||
};
|
||||
|
||||
void bindVBO(VkCommandBuffer& commandBuffer, KRVBOData* vbo_data, float lodCoverage);
|
||||
long getMemUsed();
|
||||
long getMemActive();
|
||||
|
||||
typedef struct
|
||||
{
|
||||
hydra::Vector3 vertex;
|
||||
hydra::Vector2 uva;
|
||||
} RandomParticleVertexData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
hydra::Vector3 vertex;
|
||||
} VolumetricLightingVertexData;
|
||||
|
||||
long getMemoryTransferedThisFrame();
|
||||
|
||||
size_t getActiveVBOCount();
|
||||
|
||||
struct draw_call_info
|
||||
{
|
||||
RenderPassType pass;
|
||||
char object_name[256];
|
||||
char material_name[256];
|
||||
int vertex_count;
|
||||
};
|
||||
|
||||
void log_draw_call(RenderPassType pass, const std::string& object_name, const std::string& material_name, int vertex_count);
|
||||
std::vector<draw_call_info> getDrawCalls();
|
||||
|
||||
|
||||
|
||||
KRVBOData KRENGINE_VBO_DATA_3D_CUBE_VERTICES;
|
||||
KRVBOData KRENGINE_VBO_DATA_2D_SQUARE_VERTICES;
|
||||
KRVBOData KRENGINE_VBO_DATA_RANDOM_PARTICLES;
|
||||
KRVBOData KRENGINE_VBO_DATA_VOLUMETRIC_LIGHTING;
|
||||
|
||||
|
||||
void doStreaming(long& memoryRemaining, long& memoryRemainingThisFrame);
|
||||
|
||||
private:
|
||||
mimir::Block KRENGINE_VBO_3D_CUBE_VERTICES;
|
||||
__int32_t KRENGINE_VBO_3D_CUBE_ATTRIBS;
|
||||
mimir::Block KRENGINE_VBO_2D_SQUARE_VERTICES;
|
||||
__int32_t KRENGINE_VBO_2D_SQUARE_ATTRIBS;
|
||||
|
||||
unordered_multimap<std::string, KRMesh*> m_models; // Multiple models with the same name/key may be inserted, representing multiple LOD levels of the model
|
||||
|
||||
long m_vboMemUsed;
|
||||
KRVBOData* m_currentVBO;
|
||||
|
||||
unordered_map<mimir::Block*, KRVBOData*> m_vbosActive;
|
||||
std::vector<std::pair<float, KRVBOData*> > m_activeVBOs_streamer;
|
||||
std::vector<std::pair<float, KRVBOData*> > m_activeVBOs_streamer_copy;
|
||||
|
||||
mimir::Block m_randomParticleVertexData;
|
||||
mimir::Block m_volumetricLightingVertexData;
|
||||
|
||||
long m_memoryTransferredThisFrame;
|
||||
|
||||
std::vector<draw_call_info> m_draw_calls;
|
||||
bool m_draw_call_logging_enabled;
|
||||
bool m_draw_call_log_used;
|
||||
|
||||
std::mutex m_streamerFenceMutex;
|
||||
bool m_streamerComplete;
|
||||
|
||||
void balanceVBOMemory(long& memoryRemaining, long& memoryRemainingThisFrame);
|
||||
|
||||
void primeVBO(KRVBOData* vbo_data);
|
||||
|
||||
void initRandomParticles();
|
||||
void initVolumetricLightingVertexes();
|
||||
|
||||
};
|
||||
64
kraken/resources/mesh/KRMeshQuad.cpp
Executable file
64
kraken/resources/mesh/KRMeshQuad.cpp
Executable file
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// KRMeshQuad.cpp
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#include "KRMeshQuad.h"
|
||||
|
||||
using namespace hydra;
|
||||
|
||||
KRMeshQuad::KRMeshQuad(KRContext& context) : KRMesh(context, "__quad")
|
||||
{
|
||||
m_constant = true;
|
||||
|
||||
KRMesh::mesh_info mi;
|
||||
|
||||
mi.vertices.push_back(Vector3::Create(-1.0f, -1.0f, 0.0f));
|
||||
mi.vertices.push_back(Vector3::Create(1.0f, -1.0f, 0.0f));
|
||||
mi.vertices.push_back(Vector3::Create(-1.0f, 1.0f, 0.0f));
|
||||
mi.vertices.push_back(Vector3::Create(1.0f, 1.0f, 0.0f));
|
||||
|
||||
mi.uva.push_back(Vector2::Create(0.0f, 0.0f));
|
||||
mi.uva.push_back(Vector2::Create(1.0f, 0.0f));
|
||||
mi.uva.push_back(Vector2::Create(0.0f, 1.0f));
|
||||
mi.uva.push_back(Vector2::Create(1.0f, 1.0f));
|
||||
|
||||
|
||||
mi.submesh_starts.push_back(0);
|
||||
mi.submesh_lengths.push_back((int)mi.vertices.size());
|
||||
mi.material_names.push_back("");
|
||||
mi.format = ModelFormat::KRENGINE_MODEL_FORMAT_STRIP;
|
||||
|
||||
LoadData(mi, true, true);
|
||||
}
|
||||
|
||||
KRMeshQuad::~KRMeshQuad()
|
||||
{
|
||||
|
||||
}
|
||||
42
kraken/resources/mesh/KRMeshQuad.h
Executable file
42
kraken/resources/mesh/KRMeshQuad.h
Executable file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// KRMeshQuad.h
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "KRMesh.h"
|
||||
|
||||
class KRMeshQuad : public KRMesh
|
||||
{
|
||||
public:
|
||||
KRMeshQuad(KRContext& context);
|
||||
virtual ~KRMeshQuad();
|
||||
private:
|
||||
};
|
||||
129
kraken/resources/mesh/KRMeshSphere.cpp
Executable file
129
kraken/resources/mesh/KRMeshSphere.cpp
Executable file
@@ -0,0 +1,129 @@
|
||||
//
|
||||
// KRMeshSphere.cpp
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#include "KRMeshSphere.h"
|
||||
|
||||
using namespace hydra;
|
||||
|
||||
KRMeshSphere::KRMeshSphere(KRContext& context) : KRMesh(context, "__sphere")
|
||||
{
|
||||
m_constant = true;
|
||||
|
||||
KRMesh::mesh_info mi;
|
||||
|
||||
// Create a triangular facet approximation to a sphere
|
||||
// Based on algorithm from Paul Bourke: http://paulbourke.net/miscellaneous/sphere_cylinder/
|
||||
|
||||
int iterations = 3;
|
||||
int facet_count = (int)(pow(4, iterations) * 8.0f);
|
||||
|
||||
std::vector<Triangle3> f = std::vector<Triangle3>(facet_count);
|
||||
|
||||
int i, it;
|
||||
float a;
|
||||
Vector3 p[6] = {
|
||||
Vector3::Create(0,0,1),
|
||||
Vector3::Create(0,0,-1),
|
||||
Vector3::Create(-1,-1,0),
|
||||
Vector3::Create(1,-1,0),
|
||||
Vector3::Create(1,1,0),
|
||||
Vector3::Create(-1,1,0)
|
||||
};
|
||||
|
||||
Vector3 pa, pb, pc;
|
||||
int nt = 0, ntold;
|
||||
|
||||
/* Create the level 0 object */
|
||||
a = 1.0f / sqrtf(2.0f);
|
||||
for (i = 0; i < 6; i++) {
|
||||
p[i].x *= a;
|
||||
p[i].y *= a;
|
||||
}
|
||||
f[0][0] = p[0]; f[0][1] = p[3]; f[0][2] = p[4];
|
||||
f[1][0] = p[0]; f[1][1] = p[4]; f[1][2] = p[5];
|
||||
f[2][0] = p[0]; f[2][1] = p[5]; f[2][2] = p[2];
|
||||
f[3][0] = p[0]; f[3][1] = p[2]; f[3][2] = p[3];
|
||||
f[4][0] = p[1]; f[4][1] = p[4]; f[4][2] = p[3];
|
||||
f[5][0] = p[1]; f[5][1] = p[5]; f[5][2] = p[4];
|
||||
f[6][0] = p[1]; f[6][1] = p[2]; f[6][2] = p[5];
|
||||
f[7][0] = p[1]; f[7][1] = p[3]; f[7][2] = p[2];
|
||||
nt = 8;
|
||||
|
||||
/* Bisect each edge and move to the surface of a unit sphere */
|
||||
for (it = 0; it < iterations; it++) {
|
||||
ntold = nt;
|
||||
for (i = 0; i < ntold; i++) {
|
||||
pa.x = (f[i][0].x + f[i][1].x) / 2;
|
||||
pa.y = (f[i][0].y + f[i][1].y) / 2;
|
||||
pa.z = (f[i][0].z + f[i][1].z) / 2;
|
||||
pb.x = (f[i][1].x + f[i][2].x) / 2;
|
||||
pb.y = (f[i][1].y + f[i][2].y) / 2;
|
||||
pb.z = (f[i][1].z + f[i][2].z) / 2;
|
||||
pc.x = (f[i][2].x + f[i][0].x) / 2;
|
||||
pc.y = (f[i][2].y + f[i][0].y) / 2;
|
||||
pc.z = (f[i][2].z + f[i][0].z) / 2;
|
||||
pa.normalize();
|
||||
pb.normalize();
|
||||
pc.normalize();
|
||||
f[nt][0] = f[i][0]; f[nt][1] = pa; f[nt][2] = pc; nt++;
|
||||
f[nt][0] = pa; f[nt][1] = f[i][1]; f[nt][2] = pb; nt++;
|
||||
f[nt][0] = pb; f[nt][1] = f[i][2]; f[nt][2] = pc; nt++;
|
||||
f[i][0] = pa;
|
||||
f[i][1] = pb;
|
||||
f[i][2] = pc;
|
||||
}
|
||||
}
|
||||
|
||||
for (int facet_index = 0; facet_index < facet_count; facet_index++) {
|
||||
mi.vertices.push_back(f[facet_index][0]);
|
||||
mi.vertices.push_back(f[facet_index][1]);
|
||||
mi.vertices.push_back(f[facet_index][2]);
|
||||
}
|
||||
|
||||
mi.submesh_starts.push_back(0);
|
||||
mi.submesh_lengths.push_back((int)mi.vertices.size());
|
||||
mi.material_names.push_back("");
|
||||
|
||||
|
||||
mi.format = ModelFormat::KRENGINE_MODEL_FORMAT_TRIANGLES;
|
||||
|
||||
// Generate normals pointing away from center of sphere.
|
||||
for (int vertex_index = 0; vertex_index < mi.vertices.size(); vertex_index++) {
|
||||
mi.normals.push_back(Vector3::Normalize(mi.vertices[vertex_index] - Vector3::Zero()));
|
||||
}
|
||||
|
||||
LoadData(mi, true, true);
|
||||
}
|
||||
|
||||
KRMeshSphere::~KRMeshSphere()
|
||||
{
|
||||
|
||||
}
|
||||
42
kraken/resources/mesh/KRMeshSphere.h
Executable file
42
kraken/resources/mesh/KRMeshSphere.h
Executable file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// KRMeshSphere.h
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "KRMesh.h"
|
||||
|
||||
class KRMeshSphere : public KRMesh
|
||||
{
|
||||
public:
|
||||
KRMeshSphere(KRContext& context);
|
||||
virtual ~KRMeshSphere();
|
||||
private:
|
||||
};
|
||||
67
kraken/resources/unknown/KRUnknown.cpp
Executable file
67
kraken/resources/unknown/KRUnknown.cpp
Executable file
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// KRUnknown.cpp
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#include "KRUnknown.h"
|
||||
|
||||
using namespace mimir;
|
||||
|
||||
KRUnknown::KRUnknown(KRContext& context, std::string name, std::string extension) : KRResource(context, name)
|
||||
{
|
||||
m_pData = new Block();
|
||||
m_extension = extension;
|
||||
}
|
||||
|
||||
KRUnknown::KRUnknown(KRContext& context, std::string name, std::string extension, Block* data) : KRResource(context, name)
|
||||
{
|
||||
m_pData = data;
|
||||
m_extension = extension;
|
||||
}
|
||||
|
||||
KRUnknown::~KRUnknown()
|
||||
{
|
||||
delete m_pData;
|
||||
}
|
||||
|
||||
std::string KRUnknown::getExtension()
|
||||
{
|
||||
return m_extension;
|
||||
}
|
||||
|
||||
bool KRUnknown::save(Block& data)
|
||||
{
|
||||
data.append(*m_pData);
|
||||
return true;
|
||||
}
|
||||
|
||||
Block* KRUnknown::getData()
|
||||
{
|
||||
return m_pData;
|
||||
}
|
||||
57
kraken/resources/unknown/KRUnknown.h
Executable file
57
kraken/resources/unknown/KRUnknown.h
Executable file
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// KRUnknown.h
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "KREngine-common.h"
|
||||
#include "KRContextObject.h"
|
||||
#include "block.h"
|
||||
#include "resources/KRResource.h"
|
||||
|
||||
class KRUnknown : public KRResource
|
||||
{
|
||||
|
||||
public:
|
||||
KRUnknown(KRContext& context, std::string name, std::string extension);
|
||||
KRUnknown(KRContext& context, std::string name, std::string extension, mimir::Block* data);
|
||||
virtual ~KRUnknown();
|
||||
|
||||
virtual std::string getExtension();
|
||||
|
||||
virtual bool save(mimir::Block& data);
|
||||
|
||||
mimir::Block* getData();
|
||||
|
||||
private:
|
||||
|
||||
std::string m_extension;
|
||||
mimir::Block* m_pData;
|
||||
};
|
||||
117
kraken/resources/unknown/KRUnknownManager.cpp
Executable file
117
kraken/resources/unknown/KRUnknownManager.cpp
Executable file
@@ -0,0 +1,117 @@
|
||||
//
|
||||
// KRUnknownManager.cpp
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#include "KRUnknownManager.h"
|
||||
#include "KREngine-common.h"
|
||||
|
||||
using namespace mimir;
|
||||
|
||||
KRUnknownManager::KRUnknownManager(KRContext& context) : KRResourceManager(context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
KRUnknownManager::~KRUnknownManager()
|
||||
{
|
||||
for (unordered_map<std::string, unordered_map<std::string, KRUnknown*> >::iterator extension_itr = m_unknowns.begin(); extension_itr != m_unknowns.end(); extension_itr++) {
|
||||
for (unordered_map<std::string, KRUnknown*>::iterator name_itr = (*extension_itr).second.begin(); name_itr != (*extension_itr).second.end(); name_itr++) {
|
||||
delete (*name_itr).second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unordered_map<std::string, unordered_map<std::string, KRUnknown*> >& KRUnknownManager::getUnknowns()
|
||||
{
|
||||
return m_unknowns;
|
||||
}
|
||||
|
||||
void KRUnknownManager::add(KRUnknown* unknown)
|
||||
{
|
||||
std::string lower_name = unknown->getName();
|
||||
std::string lower_extension = unknown->getExtension();
|
||||
|
||||
std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(), ::tolower);
|
||||
std::transform(lower_extension.begin(), lower_extension.end(), lower_extension.begin(), ::tolower);
|
||||
|
||||
unordered_map<std::string, unordered_map<std::string, KRUnknown*> >::iterator extension_itr = m_unknowns.find(lower_extension);
|
||||
if (extension_itr == m_unknowns.end()) {
|
||||
m_unknowns[lower_extension] = unordered_map<std::string, KRUnknown*>();
|
||||
extension_itr = m_unknowns.find(lower_extension);
|
||||
}
|
||||
|
||||
unordered_map<std::string, KRUnknown*>::iterator name_itr = (*extension_itr).second.find(lower_name);
|
||||
if (name_itr != (*extension_itr).second.end()) {
|
||||
delete (*name_itr).second;
|
||||
(*name_itr).second = unknown;
|
||||
} else {
|
||||
(*extension_itr).second[lower_name] = unknown;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
KRResource* KRUnknownManager::loadResource(const std::string& name, const std::string& extension, Block* data)
|
||||
{
|
||||
// KRUnknown's can have any extension
|
||||
return load(name, extension, data);
|
||||
}
|
||||
|
||||
KRResource* KRUnknownManager::getResource(const std::string& name, const std::string& extension)
|
||||
{
|
||||
// KRUnknown's can have any extension
|
||||
return get(name, extension);
|
||||
}
|
||||
|
||||
KRUnknown* KRUnknownManager::load(const std::string& name, const std::string& extension, Block* data)
|
||||
{
|
||||
KRUnknown* unknown = new KRUnknown(getContext(), name, extension, data);
|
||||
if (unknown) add(unknown);
|
||||
return unknown;
|
||||
}
|
||||
|
||||
KRUnknown* KRUnknownManager::get(const std::string& name, const std::string& extension)
|
||||
{
|
||||
std::string lower_name = name;
|
||||
std::string lower_extension = extension;
|
||||
|
||||
std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(), ::tolower);
|
||||
std::transform(lower_extension.begin(), lower_extension.end(), lower_extension.begin(), ::tolower);
|
||||
|
||||
return m_unknowns[lower_extension][lower_name];
|
||||
}
|
||||
|
||||
|
||||
const unordered_map<std::string, KRUnknown*>& KRUnknownManager::get(const std::string& extension)
|
||||
{
|
||||
std::string lower_extension = extension;
|
||||
std::transform(lower_extension.begin(), lower_extension.end(), lower_extension.begin(), ::tolower);
|
||||
return m_unknowns[lower_extension];
|
||||
}
|
||||
|
||||
63
kraken/resources/unknown/KRUnknownManager.h
Executable file
63
kraken/resources/unknown/KRUnknownManager.h
Executable file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// KRUnknownManager.h
|
||||
// Kraken Engine
|
||||
//
|
||||
// Copyright 2024 Kearwood Gilbert. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other materials
|
||||
// provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// The views and conclusions contained in the software and documentation are those of the
|
||||
// authors and should not be interpreted as representing official policies, either expressed
|
||||
// or implied, of Kearwood Gilbert.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "KREngine-common.h"
|
||||
|
||||
#include "resources/KRResourceManager.h"
|
||||
|
||||
#include "KRUnknown.h"
|
||||
#include "KRContextObject.h"
|
||||
#include "block.h"
|
||||
|
||||
class KRUnknownManager : public KRResourceManager
|
||||
{
|
||||
public:
|
||||
KRUnknownManager(KRContext& context);
|
||||
virtual ~KRUnknownManager();
|
||||
|
||||
virtual KRResource* loadResource(const std::string& name, const std::string& extension, mimir::Block* data) override;
|
||||
virtual KRResource* getResource(const std::string& name, const std::string& extension) override;
|
||||
|
||||
void add(KRUnknown* unknown);
|
||||
|
||||
KRUnknown* load(const std::string& name, const std::string& extension, mimir::Block* data);
|
||||
KRUnknown* get(const std::string& name, const std::string& extension);
|
||||
|
||||
|
||||
const unordered_map<std::string, KRUnknown*>& get(const std::string& extension);
|
||||
|
||||
unordered_map<std::string, unordered_map<std::string, KRUnknown*> >& getUnknowns();
|
||||
|
||||
private:
|
||||
unordered_map<std::string, unordered_map<std::string, KRUnknown*> > m_unknowns;
|
||||
};
|
||||
Reference in New Issue
Block a user