mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-12-08 12:24:56 +00:00
Start wiring up wgpu+winit
This commit is contained in:
@@ -20,7 +20,7 @@ endif()
|
||||
set(HECL_HEADERS
|
||||
../include/hecl/CVar.hpp
|
||||
../include/hecl/CVarManager.hpp
|
||||
../include/hecl/Console.hpp
|
||||
# ../include/hecl/Console.hpp
|
||||
../include/hecl/CVarCommons.hpp
|
||||
../include/hecl/hecl.hpp
|
||||
../include/hecl/MultiProgressPrinter.hpp
|
||||
@@ -37,11 +37,9 @@ set(HECL_HEADERS
|
||||
../include/hecl/ClientProcess.hpp
|
||||
../include/hecl/BitVector.hpp
|
||||
../include/hecl/MathExtras.hpp
|
||||
../include/hecl/UniformBufferPool.hpp
|
||||
../include/hecl/VertexBufferPool.hpp
|
||||
../include/hecl/PipelineBase.hpp
|
||||
../include/hecl/Pipeline.hpp
|
||||
../include/hecl/Compilers.hpp)
|
||||
# ../include/hecl/UniformBufferPool.hpp
|
||||
# ../include/hecl/VertexBufferPool.hpp
|
||||
)
|
||||
set(COMMON_SOURCES
|
||||
hecl.cpp
|
||||
MultiProgressPrinter.cpp
|
||||
@@ -51,11 +49,10 @@ set(COMMON_SOURCES
|
||||
CVar.cpp
|
||||
CVarCommons.cpp
|
||||
CVarManager.cpp
|
||||
Console.cpp
|
||||
# Console.cpp
|
||||
ClientProcess.cpp
|
||||
SteamFinder.cpp
|
||||
WideStringConvert.cpp
|
||||
Compilers.cpp)
|
||||
WideStringConvert.cpp)
|
||||
|
||||
if(UNIX)
|
||||
list(APPEND PLAT_SRCS closefrom.c)
|
||||
@@ -68,7 +65,7 @@ add_library(hecl-full
|
||||
${COMMON_SOURCES}
|
||||
${HECL_HEADERS}
|
||||
${PLAT_SRCS}
|
||||
Pipeline.cpp)
|
||||
${FIND_BLENDER_SOURCES})
|
||||
target_include_directories(hecl-full PUBLIC ../include)
|
||||
target_link_libraries(hecl-full PUBLIC ${HECL_APPLICATION_REPS_TARGETS_LIST}
|
||||
hecl-blender-addon boo athena-core logvisor)
|
||||
@@ -83,7 +80,7 @@ add_library(hecl-light
|
||||
${PLAT_SRCS}
|
||||
${FIND_BLENDER_SOURCES})
|
||||
target_include_directories(hecl-light PUBLIC ../include)
|
||||
target_link_libraries(hecl-light PUBLIC ${HECL_APPLICATION_REPS_TARGETS_LIST} boo athena-core logvisor)
|
||||
target_link_libraries(hecl-light PUBLIC ${HECL_APPLICATION_REPS_TARGETS_LIST} boo athena-core logvisor aurora)
|
||||
if (WIN32)
|
||||
# For FindBlender
|
||||
target_link_libraries(hecl-light PUBLIC Version)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
|
||||
#include "hecl/Console.hpp"
|
||||
#include "hecl/hecl.hpp"
|
||||
#include "hecl/Runtime.hpp"
|
||||
|
||||
@@ -207,62 +206,6 @@ void CVarManager::serialize() {
|
||||
|
||||
CVarManager* CVarManager::instance() { return m_instance; }
|
||||
|
||||
void CVarManager::list(Console* con, const std::vector<std::string>& /*args*/) {
|
||||
for (const auto& cvar : m_cvars) {
|
||||
if (!cvar.second->isHidden())
|
||||
con->report(Console::Level::Info, FMT_STRING("{}: {}"), cvar.second->name(), cvar.second->help());
|
||||
}
|
||||
}
|
||||
|
||||
void CVarManager::setCVar(Console* con, const std::vector<std::string>& args) {
|
||||
if (args.size() < 2) {
|
||||
con->report(Console::Level::Info, FMT_STRING("Usage setCvar <cvar> <value>"));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string cvName = args[0];
|
||||
athena::utility::tolower(cvName);
|
||||
const auto iter = m_cvars.find(cvName);
|
||||
if (iter == m_cvars.end()) {
|
||||
con->report(Console::Level::Error, FMT_STRING("CVar '{}' does not exist"), args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& cv = iter->second;
|
||||
std::string oldVal = cv->value();
|
||||
std::string value = args[1];
|
||||
auto it = args.begin() + 2;
|
||||
for (; it != args.end(); ++it)
|
||||
value += " " + *it;
|
||||
|
||||
/* Check to make sure we're not redundantly assigning the value */
|
||||
if (cv->value() == value)
|
||||
return;
|
||||
|
||||
if (!cv->fromLiteralToType(value))
|
||||
con->report(Console::Level::Warning, FMT_STRING("Unable to set cvar '{}' to value '{}'"), cv->name(), value);
|
||||
else
|
||||
con->report(Console::Level::Info, FMT_STRING("Set '{}' from '{}' to '{}'"), cv->name(), oldVal, value);
|
||||
}
|
||||
|
||||
void CVarManager::getCVar(Console* con, const std::vector<std::string>& args) {
|
||||
if (args.empty()) {
|
||||
con->report(Console::Level::Info, FMT_STRING("Usage getCVar <cvar>"));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string cvName = args[0];
|
||||
athena::utility::tolower(cvName);
|
||||
const auto iter = m_cvars.find(cvName);
|
||||
if (iter == m_cvars.end()) {
|
||||
con->report(Console::Level::Error, FMT_STRING("CVar '{}' does not exist"), args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& cv = iter->second;
|
||||
con->report(Console::Level::Info, FMT_STRING("'{}' = '{}'"), cv->name(), cv->value());
|
||||
}
|
||||
|
||||
void CVarManager::setDeveloperMode(bool v, bool setDeserialized) {
|
||||
com_developer->unlock();
|
||||
com_developer->fromBoolean(v);
|
||||
|
||||
@@ -1,292 +0,0 @@
|
||||
#include "hecl/Compilers.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#include <boo/graphicsdev/GLSLMacros.hpp>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
#include <glslang/Public/ShaderLang.h>
|
||||
#include <StandAlone/ResourceLimits.h>
|
||||
#include <SPIRV/GlslangToSpv.h>
|
||||
#include <SPIRV/disassemble.h>
|
||||
|
||||
#if _WIN32
|
||||
#include <d3dcompiler.h>
|
||||
extern pD3DCompile D3DCompilePROC;
|
||||
#endif
|
||||
|
||||
#if __APPLE__
|
||||
#include <unistd.h>
|
||||
#include <memory>
|
||||
#endif
|
||||
|
||||
namespace hecl {
|
||||
logvisor::Module Log("hecl::Compilers");
|
||||
|
||||
template <typename P>
|
||||
struct ShaderCompiler {};
|
||||
|
||||
template <>
|
||||
struct ShaderCompiler<PlatformType::OpenGL> {
|
||||
template <typename S>
|
||||
static std::pair<StageBinaryData, size_t> Compile(std::string_view text) {
|
||||
std::string str = "#version 330\n";
|
||||
str += BOO_GLSL_BINDING_HEAD;
|
||||
str += text;
|
||||
std::pair<StageBinaryData, size_t> ret(MakeStageBinaryData(str.size() + 1), str.size() + 1);
|
||||
memcpy(ret.first.get(), str.data(), ret.second);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ShaderCompiler<PlatformType::Vulkan> {
|
||||
static constexpr EShLanguage ShaderTypes[] = {EShLangVertex, /* Invalid */
|
||||
EShLangVertex, EShLangFragment, EShLangGeometry,
|
||||
EShLangTessControl, EShLangTessEvaluation};
|
||||
|
||||
template <typename S>
|
||||
static std::pair<StageBinaryData, size_t> Compile(std::string_view text) {
|
||||
EShLanguage lang = ShaderTypes[int(S::Enum)];
|
||||
const EShMessages messages = EShMessages(EShMsgSpvRules | EShMsgVulkanRules);
|
||||
glslang::TShader shader(lang);
|
||||
const char* strings[] = {"#version 330\n", BOO_GLSL_BINDING_HEAD, text.data()};
|
||||
shader.setStrings(strings, 3);
|
||||
if (!shader.parse(&glslang::DefaultTBuiltInResource, 110, false, messages)) {
|
||||
fmt::print(FMT_STRING("{}\n"), text);
|
||||
Log.report(logvisor::Fatal, FMT_STRING("unable to compile shader\n{}"), shader.getInfoLog());
|
||||
return {};
|
||||
}
|
||||
|
||||
glslang::TProgram prog;
|
||||
prog.addShader(&shader);
|
||||
if (!prog.link(messages)) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("unable to link shader program\n{}"), prog.getInfoLog());
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<unsigned int> out;
|
||||
glslang::GlslangToSpv(*prog.getIntermediate(lang), out);
|
||||
std::pair<StageBinaryData, size_t> ret(MakeStageBinaryData(out.size() * 4), out.size() * 4);
|
||||
memcpy(ret.first.get(), out.data(), ret.second);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
#if _WIN32
|
||||
static const char* D3DShaderTypes[] = {nullptr, "vs_5_0", "ps_5_0", "gs_5_0", "hs_5_0", "ds_5_0"};
|
||||
template <>
|
||||
struct ShaderCompiler<PlatformType::D3D11> {
|
||||
#if _DEBUG && 0
|
||||
#define BOO_D3DCOMPILE_FLAG D3DCOMPILE_DEBUG | D3DCOMPILE_OPTIMIZATION_LEVEL0
|
||||
#else
|
||||
#define BOO_D3DCOMPILE_FLAG D3DCOMPILE_OPTIMIZATION_LEVEL3
|
||||
#endif
|
||||
template <typename S>
|
||||
static std::pair<StageBinaryData, size_t> Compile(std::string_view text) {
|
||||
ComPtr<ID3DBlob> errBlob;
|
||||
ComPtr<ID3DBlob> blobOut;
|
||||
if (FAILED(D3DCompilePROC(text.data(), text.size(), "Boo HLSL Source", nullptr, nullptr, "main",
|
||||
D3DShaderTypes[int(S::Enum)], BOO_D3DCOMPILE_FLAG, 0, &blobOut, &errBlob))) {
|
||||
fmt::print(FMT_STRING("{}\n"), text);
|
||||
Log.report(logvisor::Fatal, FMT_STRING("error compiling shader: {}"), (char*)errBlob->GetBufferPointer());
|
||||
return {};
|
||||
}
|
||||
std::pair<StageBinaryData, size_t> ret(MakeStageBinaryData(blobOut->GetBufferSize()), blobOut->GetBufferSize());
|
||||
memcpy(ret.first.get(), blobOut->GetBufferPointer(), blobOut->GetBufferSize());
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if __APPLE__
|
||||
template <>
|
||||
struct ShaderCompiler<PlatformType::Metal> {
|
||||
static bool m_didCompilerSearch;
|
||||
static bool m_hasCompiler;
|
||||
|
||||
static bool SearchForCompiler() {
|
||||
m_didCompilerSearch = true;
|
||||
const char* no_metal_compiler = getenv("HECL_NO_METAL_COMPILER");
|
||||
if (no_metal_compiler && atoi(no_metal_compiler))
|
||||
return false;
|
||||
|
||||
pid_t pid = fork();
|
||||
if (!pid) {
|
||||
execlp("xcrun", "xcrun", "-sdk", "macosx", "metal", "--version", nullptr);
|
||||
/* xcrun returns 72 if metal command not found;
|
||||
* emulate that if xcrun not found */
|
||||
exit(72);
|
||||
}
|
||||
|
||||
int status, ret;
|
||||
while ((ret = waitpid(pid, &status, 0)) < 0 && errno == EINTR) {}
|
||||
if (ret < 0)
|
||||
return false;
|
||||
return WEXITSTATUS(status) == 0;
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
static std::pair<StageBinaryData, size_t> Compile(std::string_view text) {
|
||||
if (!m_didCompilerSearch)
|
||||
m_hasCompiler = SearchForCompiler();
|
||||
|
||||
std::string str =
|
||||
"#include <metal_stdlib>\n"
|
||||
"using namespace metal;\n";
|
||||
str += text;
|
||||
std::pair<StageBinaryData, size_t> ret;
|
||||
|
||||
if (!m_hasCompiler) {
|
||||
/* First byte unset to indicate source data */
|
||||
ret.first = MakeStageBinaryData(str.size() + 2);
|
||||
ret.first.get()[0] = 0;
|
||||
ret.second = str.size() + 2;
|
||||
memcpy(&ret.first.get()[1], str.data(), str.size() + 1);
|
||||
} else {
|
||||
int compilerOut[2];
|
||||
int compilerIn[2];
|
||||
pipe(compilerOut);
|
||||
pipe(compilerIn);
|
||||
|
||||
pid_t pid = getpid();
|
||||
const char* tmpdir = getenv("TMPDIR");
|
||||
std::string libFile = fmt::format(FMT_STRING("{}boo_metal_shader{}.metallib"), tmpdir, pid);
|
||||
|
||||
/* Pipe source write to compiler */
|
||||
pid_t compilerPid = fork();
|
||||
if (!compilerPid) {
|
||||
dup2(compilerIn[0], STDIN_FILENO);
|
||||
dup2(compilerOut[1], STDOUT_FILENO);
|
||||
|
||||
close(compilerOut[0]);
|
||||
close(compilerOut[1]);
|
||||
close(compilerIn[0]);
|
||||
close(compilerIn[1]);
|
||||
|
||||
execlp("xcrun", "xcrun", "-sdk", "macosx", "metal", "-o", "/dev/stdout", "-Wno-unused-variable",
|
||||
"-Wno-unused-const-variable", "-Wno-unused-function", "-c", "-x", "metal",
|
||||
#ifndef NDEBUG
|
||||
"-gline-tables-only", "-MO",
|
||||
#endif
|
||||
"-", nullptr);
|
||||
fmt::print(stderr, FMT_STRING("execlp fail {}\n"), strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
close(compilerIn[0]);
|
||||
close(compilerOut[1]);
|
||||
|
||||
/* Pipe compiler to linker */
|
||||
pid_t linkerPid = fork();
|
||||
if (!linkerPid) {
|
||||
dup2(compilerOut[0], STDIN_FILENO);
|
||||
|
||||
close(compilerOut[0]);
|
||||
close(compilerIn[1]);
|
||||
|
||||
/* metallib doesn't like outputting to a pipe, so temp file will have to do */
|
||||
execlp("xcrun", "xcrun", "-sdk", "macosx", "metallib", "-", "-o", libFile.c_str(), nullptr);
|
||||
fmt::print(stderr, FMT_STRING("execlp fail {}\n"), strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
close(compilerOut[0]);
|
||||
|
||||
/* Stream in source */
|
||||
const char* inPtr = str.data();
|
||||
size_t inRem = str.size();
|
||||
while (inRem) {
|
||||
ssize_t writeRes = write(compilerIn[1], inPtr, inRem);
|
||||
if (writeRes < 0) {
|
||||
fmt::print(stderr, FMT_STRING("write fail {}\n"), strerror(errno));
|
||||
break;
|
||||
}
|
||||
inPtr += writeRes;
|
||||
inRem -= writeRes;
|
||||
}
|
||||
close(compilerIn[1]);
|
||||
|
||||
/* Wait for completion */
|
||||
int compilerStat, linkerStat;
|
||||
while (waitpid(compilerPid, &compilerStat, 0) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
Log.report(logvisor::Fatal, FMT_STRING("waitpid fail {}"), strerror(errno));
|
||||
return {};
|
||||
}
|
||||
|
||||
if (WEXITSTATUS(compilerStat)) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("compile fail"));
|
||||
return {};
|
||||
}
|
||||
|
||||
while (waitpid(linkerPid, &linkerStat, 0) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
Log.report(logvisor::Fatal, FMT_STRING("waitpid fail {}"), strerror(errno));
|
||||
return {};
|
||||
}
|
||||
|
||||
if (WEXITSTATUS(linkerStat)) {
|
||||
Log.report(logvisor::Fatal, FMT_STRING("link fail"));
|
||||
return {};
|
||||
}
|
||||
|
||||
/* Copy temp file into buffer with first byte set to indicate binary data */
|
||||
FILE* fin = fopen(libFile.c_str(), "rb");
|
||||
fseek(fin, 0, SEEK_END);
|
||||
long libLen = ftell(fin);
|
||||
fseek(fin, 0, SEEK_SET);
|
||||
ret.first = MakeStageBinaryData(libLen + 1);
|
||||
ret.first.get()[0] = 1;
|
||||
ret.second = libLen + 1;
|
||||
fread(&ret.first.get()[1], 1, libLen, fin);
|
||||
fclose(fin);
|
||||
unlink(libFile.c_str());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
bool ShaderCompiler<PlatformType::Metal>::m_didCompilerSearch = false;
|
||||
bool ShaderCompiler<PlatformType::Metal>::m_hasCompiler = false;
|
||||
#endif
|
||||
|
||||
#if HECL_NOUVEAU_NX
|
||||
template <>
|
||||
struct ShaderCompiler<PlatformType::NX> {
|
||||
template <typename S>
|
||||
static std::pair<std::shared_ptr<uint8_t[]>, size_t> Compile(std::string_view text) {
|
||||
std::string str = "#version 330\n";
|
||||
str += BOO_GLSL_BINDING_HEAD;
|
||||
str += text;
|
||||
std::pair<std::shared_ptr<uint8_t[]>, size_t> ret(new uint8_t[str.size() + 1], str.size() + 1);
|
||||
memcpy(ret.first.get(), str.data(), str.size() + 1);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename P, typename S>
|
||||
std::pair<StageBinaryData, size_t> CompileShader(std::string_view text) {
|
||||
return ShaderCompiler<P>::template Compile<S>(text);
|
||||
}
|
||||
#define SPECIALIZE_COMPILE_SHADER(P) \
|
||||
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Vertex>(std::string_view text); \
|
||||
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Fragment>(std::string_view text); \
|
||||
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Geometry>(std::string_view text); \
|
||||
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Control>(std::string_view text); \
|
||||
template std::pair<StageBinaryData, size_t> CompileShader<P, PipelineStage::Evaluation>(std::string_view text);
|
||||
SPECIALIZE_COMPILE_SHADER(PlatformType::OpenGL)
|
||||
SPECIALIZE_COMPILE_SHADER(PlatformType::Vulkan)
|
||||
#if _WIN32
|
||||
SPECIALIZE_COMPILE_SHADER(PlatformType::D3D11)
|
||||
#endif
|
||||
#if __APPLE__
|
||||
SPECIALIZE_COMPILE_SHADER(PlatformType::Metal)
|
||||
#endif
|
||||
#if HECL_NOUVEAU_NX
|
||||
SPECIALIZE_COMPILE_SHADER(PlatformType::NX)
|
||||
#endif
|
||||
|
||||
} // namespace hecl
|
||||
@@ -1,410 +0,0 @@
|
||||
#include <hecl/Console.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "hecl/CVar.hpp"
|
||||
#include "hecl/CVarManager.hpp"
|
||||
#include "hecl/hecl.hpp"
|
||||
|
||||
#include <athena/Utility.hpp>
|
||||
#include <boo/IWindow.hpp>
|
||||
#include <boo/graphicsdev/IGraphicsCommandQueue.hpp>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
namespace hecl {
|
||||
Console* Console::m_instance = nullptr;
|
||||
Console::Console(CVarManager* cvarMgr) : m_cvarMgr(cvarMgr), m_overwrite(false), m_cursorAtEnd(false) {
|
||||
m_instance = this;
|
||||
registerCommand("help", "Prints information about a given function", "<command>",
|
||||
[this](Console* console, const std::vector<std::string>& args) { help(console, args); });
|
||||
registerCommand("listCommands", "Prints a list of all available Commands", "",
|
||||
[this](Console* console, const std::vector<std::string>& args) { listCommands(console, args); });
|
||||
registerCommand("listCVars", "Lists all available CVars", "",
|
||||
[this](Console* console, const std::vector<std::string>& args) { m_cvarMgr->list(console, args); });
|
||||
registerCommand(
|
||||
"setCVar", "Sets a given Console Variable to the specified value", "<cvar> <value>",
|
||||
[this](Console* console, const std::vector<std::string>& args) { m_cvarMgr->setCVar(console, args); });
|
||||
registerCommand(
|
||||
"getCVar", "Prints the value stored in the specified Console Variable", "<cvar>",
|
||||
[this](Console* console, const std::vector<std::string>& args) { m_cvarMgr->getCVar(console, args); });
|
||||
}
|
||||
|
||||
void Console::registerCommand(std::string_view name, std::string_view helpText, std::string_view usage,
|
||||
std::function<void(Console*, const std::vector<std::string>&)>&& func,
|
||||
SConsoleCommand::ECommandFlags cmdFlags) {
|
||||
std::string lowName{name};
|
||||
athena::utility::tolower(lowName);
|
||||
|
||||
if (m_commands.find(lowName) != m_commands.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_commands.emplace(std::move(lowName), SConsoleCommand{std::string{name}, std::string{helpText}, std::string{usage},
|
||||
std::move(func), cmdFlags});
|
||||
}
|
||||
|
||||
void Console::unregisterCommand(std::string_view name) {
|
||||
std::string lowName{name};
|
||||
athena::utility::tolower(lowName);
|
||||
|
||||
const auto iter = m_commands.find(lowName);
|
||||
if (iter == m_commands.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_commands.erase(iter);
|
||||
}
|
||||
|
||||
void Console::executeString(const std::string& str) {
|
||||
if (str.empty())
|
||||
return;
|
||||
|
||||
/* First let's split semi-colon delimited commands */
|
||||
std::vector<std::string> commands = athena::utility::split(str, ';');
|
||||
|
||||
if (commands.empty())
|
||||
return;
|
||||
|
||||
for (std::string command : commands) {
|
||||
command = athena::utility::trim(command);
|
||||
std::vector<std::string> tmpArgs = athena::utility::split(command, ' ');
|
||||
if (tmpArgs.empty())
|
||||
continue;
|
||||
std::vector<std::string> args;
|
||||
args.reserve(tmpArgs.size());
|
||||
/* detect string literals */
|
||||
bool isInLiteral = false;
|
||||
std::string curLiteral;
|
||||
int depth = 0;
|
||||
for (std::string arg : tmpArgs) {
|
||||
if ((arg.front() == '\'' || arg.front() == '"')) {
|
||||
++depth;
|
||||
isInLiteral = true;
|
||||
curLiteral += arg;
|
||||
} else if ((arg.back() == '\'' || arg.back() == '"') && isInLiteral) {
|
||||
--depth;
|
||||
curLiteral += arg;
|
||||
args.push_back(curLiteral);
|
||||
if (depth <= 0) {
|
||||
depth = 0;
|
||||
isInLiteral = false;
|
||||
curLiteral.clear();
|
||||
}
|
||||
} else if (isInLiteral) {
|
||||
curLiteral += arg;
|
||||
} else {
|
||||
args.push_back(std::move(arg));
|
||||
}
|
||||
}
|
||||
|
||||
if (isInLiteral) {
|
||||
if ((curLiteral.back() != '\'' && curLiteral.back() != '"') || depth > 1) {
|
||||
report(Level::Warning, FMT_STRING("Unterminated string literal"));
|
||||
return;
|
||||
}
|
||||
args.push_back(std::move(curLiteral));
|
||||
}
|
||||
|
||||
std::string commandName = args[0];
|
||||
args.erase(args.begin());
|
||||
|
||||
std::string lowComName = commandName;
|
||||
athena::utility::tolower(lowComName);
|
||||
if (const auto iter = m_commands.find(lowComName); iter != m_commands.end()) {
|
||||
const SConsoleCommand& cmd = iter->second;
|
||||
if (bool(cmd.m_flags & SConsoleCommand::ECommandFlags::Developer) && !com_developer->toBoolean()) {
|
||||
report(Level::Error, FMT_STRING("This command can only be executed in developer mode"), commandName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bool(cmd.m_flags & SConsoleCommand::ECommandFlags::Cheat) && !com_enableCheats->toBoolean()) {
|
||||
report(Level::Error, FMT_STRING("This command can only be executed with cheats enabled"), commandName);
|
||||
return;
|
||||
}
|
||||
cmd.m_func(this, args);
|
||||
} else if (const CVar* cv = m_cvarMgr->findCVar(commandName)) {
|
||||
args.insert(args.begin(), std::move(commandName));
|
||||
if (args.size() > 1)
|
||||
m_cvarMgr->setCVar(this, args);
|
||||
else
|
||||
m_cvarMgr->getCVar(this, args);
|
||||
} else {
|
||||
report(Level::Error, FMT_STRING("'{}' is not a valid command or variable!"), commandName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Console::help(Console* /*con*/, const std::vector<std::string>& args) {
|
||||
if (args.empty()) {
|
||||
report(Level::Info, FMT_STRING("Expected usage: help <command>"));
|
||||
return;
|
||||
}
|
||||
std::string cmd = args.front();
|
||||
athena::utility::tolower(cmd);
|
||||
auto it = m_commands.find(cmd);
|
||||
if (it == m_commands.end()) {
|
||||
report(Level::Error, FMT_STRING("No such command '{}'"), args.front());
|
||||
return;
|
||||
}
|
||||
|
||||
report(Level::Info, FMT_STRING("{}: {}"), it->second.m_displayName, it->second.m_helpString);
|
||||
if (!it->second.m_usage.empty())
|
||||
report(Level::Info, FMT_STRING("Usage: {} {}"), it->second.m_displayName, it->second.m_usage);
|
||||
}
|
||||
|
||||
void Console::listCommands(Console* /*con*/, const std::vector<std::string>& /*args*/) {
|
||||
for (const auto& comPair : m_commands)
|
||||
report(Level::Info, FMT_STRING("'{}': {}"), comPair.second.m_displayName, comPair.second.m_helpString);
|
||||
}
|
||||
|
||||
bool Console::commandExists(std::string_view cmd) const {
|
||||
std::string cmdName{cmd};
|
||||
athena::utility::tolower(cmdName);
|
||||
|
||||
return m_commands.find(cmdName) != m_commands.end();
|
||||
}
|
||||
|
||||
void Console::vreport(Level level, fmt::string_view fmt, fmt::format_args args) {
|
||||
std::string tmp = fmt::vformat(fmt, args);
|
||||
std::vector<std::string> lines = athena::utility::split(tmp, '\n');
|
||||
for (std::string& line : lines) {
|
||||
m_log.emplace_back(std::move(line), level);
|
||||
}
|
||||
fmt::print(FMT_STRING("{}\n"), tmp);
|
||||
}
|
||||
|
||||
void Console::init(boo::IWindow* window) {
|
||||
m_window = window;
|
||||
}
|
||||
|
||||
void Console::proc() {
|
||||
if (m_state == State::Opened) {
|
||||
fmt::print(FMT_STRING("\r{} "), m_commandString);
|
||||
fflush(stdout);
|
||||
} else if (m_state == State::Opening)
|
||||
m_state = State::Opened;
|
||||
else if (m_state == State::Closing) {
|
||||
m_state = State::Closed;
|
||||
m_commandString.clear();
|
||||
}
|
||||
|
||||
if (m_cursorPosition > int(m_commandString.size() - 1))
|
||||
m_cursorPosition = int(m_commandString.size() - 1);
|
||||
if (m_cursorPosition < -1)
|
||||
m_cursorPosition = -1;
|
||||
|
||||
if (m_logOffset > int(m_log.size() - 1))
|
||||
m_logOffset = int(m_log.size() - 1);
|
||||
if (m_logOffset < 0)
|
||||
m_logOffset = 0;
|
||||
}
|
||||
|
||||
void Console::draw(boo::IGraphicsCommandQueue* /* gfxQ */) {
|
||||
}
|
||||
|
||||
void Console::handleCharCode(unsigned long chr, boo::EModifierKey /*mod*/, bool /*repeat*/) {
|
||||
if (chr == U'`' || chr == U'~') {
|
||||
if (m_state == State::Closed || m_state == State::Closing)
|
||||
m_state = State::Opening;
|
||||
else
|
||||
m_state = State::Closing;
|
||||
}
|
||||
|
||||
if (m_state == State::Opened) {
|
||||
if (!m_commandString.empty() && m_cursorPosition + 1 < int(m_commandString.size())) {
|
||||
if (m_overwrite)
|
||||
m_commandString[unsigned(m_cursorPosition + 1)] = char(chr);
|
||||
else
|
||||
m_commandString.insert(m_commandString.begin() + m_cursorPosition + 1, char(chr));
|
||||
} else
|
||||
m_commandString += char(chr);
|
||||
|
||||
++m_cursorPosition;
|
||||
}
|
||||
}
|
||||
|
||||
void Console::handleSpecialKeyDown(boo::ESpecialKey sp, boo::EModifierKey mod, bool /*repeat*/) {
|
||||
if (m_state != State::Opened) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (sp) {
|
||||
case boo::ESpecialKey::Insert:
|
||||
m_overwrite ^= 1;
|
||||
break;
|
||||
case boo::ESpecialKey::Backspace: {
|
||||
if (!m_commandString.empty()) {
|
||||
if (True(mod & boo::EModifierKey::Ctrl)) {
|
||||
size_t index = m_commandString.rfind(' ', size_t(m_cursorPosition - 1));
|
||||
|
||||
if (index == std::string::npos) {
|
||||
m_commandString.clear();
|
||||
m_cursorPosition = -1;
|
||||
} else {
|
||||
m_commandString.erase(index, (index - m_commandString.size()));
|
||||
m_cursorPosition = int(index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (m_cursorPosition < 0)
|
||||
break;
|
||||
|
||||
m_commandString.erase(size_t(m_cursorPosition), 1);
|
||||
--m_cursorPosition;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::Delete: {
|
||||
if (!m_commandString.empty()) {
|
||||
// Don't try to delete if the cursor is at the end of the line
|
||||
if ((m_cursorPosition + 1) >= int(m_commandString.size()))
|
||||
break;
|
||||
|
||||
if (True(mod & boo::EModifierKey::Ctrl)) {
|
||||
size_t index = m_commandString.find_first_of(' ', size_t(m_cursorPosition + 1));
|
||||
if (index != std::string::npos)
|
||||
m_commandString.erase(size_t(m_cursorPosition + 1), index + 1);
|
||||
else
|
||||
m_commandString.erase(size_t(m_cursorPosition + 1), size_t(m_cursorPosition + 1) - m_commandString.size());
|
||||
break;
|
||||
}
|
||||
m_commandString.erase(size_t(m_cursorPosition + 1), 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::PgUp: {
|
||||
if (m_logOffset < int(m_log.size() - m_maxLines) - 1)
|
||||
m_logOffset++;
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::PgDown: {
|
||||
if (m_logOffset > 0)
|
||||
m_logOffset--;
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::Enter: {
|
||||
fmt::print(FMT_STRING("\n"));
|
||||
executeString(m_commandString);
|
||||
m_cursorPosition = -1;
|
||||
m_commandHistory.insert(m_commandHistory.begin(), m_commandString);
|
||||
m_commandString.clear();
|
||||
m_showCursor = true;
|
||||
m_cursorTime = 0.f;
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::Left: {
|
||||
if (m_cursorPosition < 0)
|
||||
break;
|
||||
|
||||
if (True(mod & boo::EModifierKey::Ctrl))
|
||||
m_cursorPosition = int(m_commandString.rfind(' ', size_t(m_cursorPosition) - 1));
|
||||
else
|
||||
m_cursorPosition--;
|
||||
|
||||
m_showCursor = true;
|
||||
m_cursorTime = 0.f;
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::Right: {
|
||||
if (m_cursorPosition >= int(m_commandString.size() - 1))
|
||||
break;
|
||||
|
||||
if (True(mod & boo::EModifierKey::Ctrl)) {
|
||||
if (m_commandString[size_t(m_cursorPosition)] == ' ')
|
||||
m_cursorPosition++;
|
||||
|
||||
size_t tmpPos = m_commandString.find(' ', size_t(m_cursorPosition));
|
||||
if (tmpPos == std::string::npos)
|
||||
m_cursorPosition = int(m_commandString.size() - 1);
|
||||
else
|
||||
m_cursorPosition = int(tmpPos);
|
||||
} else
|
||||
m_cursorPosition++;
|
||||
|
||||
m_showCursor = true;
|
||||
m_cursorTime = 0.f;
|
||||
break;
|
||||
}
|
||||
|
||||
case boo::ESpecialKey::Up: {
|
||||
if (m_commandHistory.size() == 0)
|
||||
break;
|
||||
|
||||
m_currentCommand++;
|
||||
|
||||
if (m_currentCommand > int(m_commandHistory.size() - 1))
|
||||
m_currentCommand = int(m_commandHistory.size() - 1);
|
||||
|
||||
m_commandString = m_commandHistory[size_t(m_currentCommand)];
|
||||
m_cursorPosition = int(m_commandString.size() - 1);
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::Down: {
|
||||
if (m_commandHistory.empty())
|
||||
break;
|
||||
m_currentCommand--;
|
||||
if (m_currentCommand >= 0) {
|
||||
m_commandString = m_commandHistory[size_t(m_currentCommand)];
|
||||
} else if (m_currentCommand <= -1) {
|
||||
m_currentCommand = -1;
|
||||
m_commandString.clear();
|
||||
}
|
||||
m_cursorPosition = int(m_commandString.size());
|
||||
break;
|
||||
}
|
||||
case boo::ESpecialKey::Home:
|
||||
m_cursorPosition = -1;
|
||||
break;
|
||||
case boo::ESpecialKey::End:
|
||||
m_cursorPosition = int(m_commandString.size() - 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Console::handleSpecialKeyUp(boo::ESpecialKey /*sp*/, boo::EModifierKey /*mod*/) {}
|
||||
|
||||
void Console::LogVisorAdapter::report(const char* modName, logvisor::Level severity,
|
||||
fmt::string_view format, fmt::format_args args) {
|
||||
auto tmp = fmt::vformat(format, args);
|
||||
std::vector<std::string> lines = athena::utility::split(tmp, '\n');
|
||||
for (const std::string& line : lines) {
|
||||
auto v = fmt::format(FMT_STRING("[{}] {}"), modName, line);
|
||||
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
|
||||
}
|
||||
}
|
||||
|
||||
void Console::LogVisorAdapter::reportSource(const char* modName, logvisor::Level severity, const char* file,
|
||||
unsigned linenum, fmt::string_view format, fmt::format_args args) {
|
||||
auto tmp = fmt::vformat(format, args);
|
||||
auto v = fmt::format(FMT_STRING("[{}] {} {}:{}"), modName, tmp, file, linenum);
|
||||
m_con->m_log.emplace_back(std::move(v), Console::Level(severity));
|
||||
}
|
||||
|
||||
void Console::dumpLog() {
|
||||
for (const auto& l : m_log) {
|
||||
switch (l.second) {
|
||||
case Level::Info:
|
||||
fmt::print(FMT_STRING("{}\n"), l.first);
|
||||
break;
|
||||
case Level::Warning:
|
||||
fmt::print(FMT_STRING("[Warning] {}\n"), l.first);
|
||||
break;
|
||||
case Level::Error:
|
||||
fmt::print(FMT_STRING("[ Error ] {}\n"), l.first);
|
||||
break;
|
||||
case Level::Fatal:
|
||||
fmt::print(FMT_STRING("[ Fatal ] {}\n"), l.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Console::RegisterLogger(Console* con) { logvisor::MainLoggers.emplace_back(new LogVisorAdapter(con)); }
|
||||
|
||||
Console* Console::instance() { return m_instance; }
|
||||
} // namespace hecl
|
||||
@@ -1,167 +0,0 @@
|
||||
#include "hecl/Pipeline.hpp"
|
||||
|
||||
#include <athena/FileReader.hpp>
|
||||
#include <zlib.h>
|
||||
|
||||
namespace hecl {
|
||||
|
||||
#if HECL_RUNTIME
|
||||
|
||||
PipelineConverterBase* conv = nullptr;
|
||||
|
||||
class ShaderCacheZipStream : public athena::io::IStreamReader {
|
||||
std::unique_ptr<uint8_t[]> m_compBuf;
|
||||
athena::io::FileReader m_reader;
|
||||
z_stream m_zstrm = {};
|
||||
|
||||
public:
|
||||
explicit ShaderCacheZipStream(const char* path) : m_reader(path) {
|
||||
if (m_reader.hasError())
|
||||
return;
|
||||
if (m_reader.readUint32Big() != SBIG('SHAD'))
|
||||
return;
|
||||
m_compBuf.reset(new uint8_t[4096]);
|
||||
m_zstrm.next_in = m_compBuf.get();
|
||||
m_zstrm.avail_in = 0;
|
||||
inflateInit(&m_zstrm);
|
||||
}
|
||||
~ShaderCacheZipStream() override { inflateEnd(&m_zstrm); }
|
||||
explicit operator bool() const { return m_compBuf.operator bool(); }
|
||||
atUint64 readUBytesToBuf(void* buf, atUint64 len) override {
|
||||
m_zstrm.next_out = (Bytef*)buf;
|
||||
m_zstrm.avail_out = len;
|
||||
m_zstrm.total_out = 0;
|
||||
while (m_zstrm.avail_out != 0) {
|
||||
if (m_zstrm.avail_in == 0) {
|
||||
atUint64 readSz = m_reader.readUBytesToBuf(m_compBuf.get(), 4096);
|
||||
m_zstrm.avail_in = readSz;
|
||||
m_zstrm.next_in = m_compBuf.get();
|
||||
}
|
||||
int inflateRet = inflate(&m_zstrm, Z_NO_FLUSH);
|
||||
if (inflateRet != Z_OK)
|
||||
break;
|
||||
}
|
||||
return m_zstrm.total_out;
|
||||
}
|
||||
void seek(atInt64, athena::SeekOrigin) override {}
|
||||
atUint64 position() const override { return 0; }
|
||||
atUint64 length() const override { return 0; }
|
||||
};
|
||||
|
||||
template <typename P, typename S>
|
||||
void StageConverter<P, S>::loadFromStream(FactoryCtx& ctx, ShaderCacheZipStream& r) {
|
||||
uint32_t count = r.readUint32Big();
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
uint64_t hash = r.readUint64Big();
|
||||
uint32_t size = r.readUint32Big();
|
||||
StageBinaryData data = MakeStageBinaryData(size);
|
||||
r.readUBytesToBuf(data.get(), size);
|
||||
m_stageCache.insert(std::make_pair(hash, Do<StageTargetTp>(ctx, StageBinary<P, S>(data, size))));
|
||||
}
|
||||
}
|
||||
|
||||
static boo::AdditionalPipelineInfo ReadAdditionalInfo(ShaderCacheZipStream& r) {
|
||||
boo::AdditionalPipelineInfo additionalInfo;
|
||||
additionalInfo.srcFac = boo::BlendFactor(r.readUint32Big());
|
||||
additionalInfo.dstFac = boo::BlendFactor(r.readUint32Big());
|
||||
additionalInfo.prim = boo::Primitive(r.readUint32Big());
|
||||
additionalInfo.depthTest = boo::ZTest(r.readUint32Big());
|
||||
additionalInfo.depthWrite = r.readBool();
|
||||
additionalInfo.colorWrite = r.readBool();
|
||||
additionalInfo.alphaWrite = r.readBool();
|
||||
additionalInfo.culling = boo::CullMode(r.readUint32Big());
|
||||
additionalInfo.patchSize = r.readUint32Big();
|
||||
additionalInfo.overwriteAlpha = r.readBool();
|
||||
additionalInfo.depthAttachment = r.readBool();
|
||||
return additionalInfo;
|
||||
}
|
||||
|
||||
static std::vector<boo::VertexElementDescriptor> ReadVertexFormat(ShaderCacheZipStream& r) {
|
||||
std::vector<boo::VertexElementDescriptor> ret;
|
||||
uint32_t count = r.readUint32Big();
|
||||
ret.reserve(count);
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
ret.emplace_back();
|
||||
ret.back().semantic = boo::VertexSemantic(r.readUint32Big());
|
||||
ret.back().semanticIdx = int(r.readUint32Big());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
bool PipelineConverter<P>::loadFromFile(FactoryCtx& ctx, const char* path) {
|
||||
ShaderCacheZipStream r(path);
|
||||
if (!r)
|
||||
return false;
|
||||
|
||||
m_vertexConverter.loadFromStream(ctx, r);
|
||||
m_fragmentConverter.loadFromStream(ctx, r);
|
||||
m_geometryConverter.loadFromStream(ctx, r);
|
||||
m_controlConverter.loadFromStream(ctx, r);
|
||||
m_evaluationConverter.loadFromStream(ctx, r);
|
||||
|
||||
uint32_t count = r.readUint32Big();
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
uint64_t hash = r.readUint64Big();
|
||||
StageRuntimeObject<P, PipelineStage::Vertex> vertex;
|
||||
StageRuntimeObject<P, PipelineStage::Fragment> fragment;
|
||||
StageRuntimeObject<P, PipelineStage::Geometry> geometry;
|
||||
StageRuntimeObject<P, PipelineStage::Control> control;
|
||||
StageRuntimeObject<P, PipelineStage::Evaluation> evaluation;
|
||||
if (uint64_t vhash = r.readUint64Big())
|
||||
vertex = m_vertexConverter.m_stageCache.find(vhash)->second;
|
||||
if (uint64_t fhash = r.readUint64Big())
|
||||
fragment = m_fragmentConverter.m_stageCache.find(fhash)->second;
|
||||
if (uint64_t ghash = r.readUint64Big())
|
||||
geometry = m_geometryConverter.m_stageCache.find(ghash)->second;
|
||||
if (uint64_t chash = r.readUint64Big())
|
||||
control = m_controlConverter.m_stageCache.find(chash)->second;
|
||||
if (uint64_t ehash = r.readUint64Big())
|
||||
evaluation = m_evaluationConverter.m_stageCache.find(ehash)->second;
|
||||
|
||||
boo::AdditionalPipelineInfo additionalInfo = ReadAdditionalInfo(r);
|
||||
std::vector<boo::VertexElementDescriptor> vtxFmt = ReadVertexFormat(r);
|
||||
|
||||
m_pipelineCache.insert(
|
||||
std::make_pair(hash, FinalPipeline<P>(*this, ctx,
|
||||
StageCollection<StageRuntimeObject<P, PipelineStage::Null>>(
|
||||
vertex, fragment, geometry, control, evaluation, additionalInfo,
|
||||
boo::VertexFormatInfo(vtxFmt.size(), vtxFmt.data())))));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define SPECIALIZE_STAGE_CONVERTER(P) \
|
||||
template class StageConverter<P, PipelineStage::Vertex>; \
|
||||
template class StageConverter<P, PipelineStage::Fragment>; \
|
||||
template class StageConverter<P, PipelineStage::Geometry>; \
|
||||
template class StageConverter<P, PipelineStage::Control>; \
|
||||
template class StageConverter<P, PipelineStage::Evaluation>;
|
||||
|
||||
#if BOO_HAS_GL
|
||||
template class PipelineConverter<PlatformType::OpenGL>;
|
||||
SPECIALIZE_STAGE_CONVERTER(PlatformType::OpenGL)
|
||||
#endif
|
||||
#if BOO_HAS_VULKAN
|
||||
template class PipelineConverter<PlatformType::Vulkan>;
|
||||
SPECIALIZE_STAGE_CONVERTER(PlatformType::Vulkan)
|
||||
#endif
|
||||
#if _WIN32
|
||||
template class PipelineConverter<PlatformType::D3D11>;
|
||||
SPECIALIZE_STAGE_CONVERTER(PlatformType::D3D11)
|
||||
#endif
|
||||
#if BOO_HAS_METAL
|
||||
template class PipelineConverter<PlatformType::Metal>;
|
||||
SPECIALIZE_STAGE_CONVERTER(PlatformType::Metal)
|
||||
#endif
|
||||
#if BOO_HAS_NX
|
||||
template class PipelineConverter<PlatformType::NX>;
|
||||
SPECIALIZE_STAGE_CONVERTER(PlatformType::NX)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace hecl
|
||||
@@ -1,5 +1,4 @@
|
||||
set(RUNTIME_SOURCES
|
||||
FileStoreManager.cpp
|
||||
HMDL_RT.cpp)
|
||||
FileStoreManager.cpp)
|
||||
|
||||
hecl_add_list(Runtime RUNTIME_SOURCES)
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
#include "hecl/HMDLMeta.hpp"
|
||||
|
||||
#include "hecl/Runtime.hpp"
|
||||
|
||||
#include <athena/MemoryReader.hpp>
|
||||
#include <logvisor/logvisor.hpp>
|
||||
|
||||
namespace hecl::Runtime {
|
||||
static logvisor::Module HMDL_Log("HMDL");
|
||||
|
||||
HMDLData::HMDLData(boo::IGraphicsDataFactory::Context& ctx, const void* metaData, const void* vbo, const void* ibo) {
|
||||
HMDLMeta meta;
|
||||
{
|
||||
athena::io::MemoryReader r(metaData, HECL_HMDL_META_SZ);
|
||||
meta.read(r);
|
||||
}
|
||||
if (meta.magic != 'TACO')
|
||||
HMDL_Log.report(logvisor::Fatal, FMT_STRING("invalid HMDL magic"));
|
||||
|
||||
m_vbo = ctx.newStaticBuffer(boo::BufferUse::Vertex, vbo, meta.vertStride, meta.vertCount);
|
||||
m_ibo = ctx.newStaticBuffer(boo::BufferUse::Index, ibo, 4, meta.indexCount);
|
||||
|
||||
const size_t elemCount = 2 + meta.colorCount + meta.uvCount + meta.weightCount;
|
||||
m_vtxFmtData = std::make_unique<boo::VertexElementDescriptor[]>(elemCount);
|
||||
|
||||
m_vtxFmtData[0].semantic = boo::VertexSemantic::Position3;
|
||||
m_vtxFmtData[1].semantic = boo::VertexSemantic::Normal3;
|
||||
size_t e = 2;
|
||||
|
||||
for (size_t i = 0; i < meta.colorCount; ++i, ++e) {
|
||||
m_vtxFmtData[e].semantic = boo::VertexSemantic::ColorUNorm;
|
||||
m_vtxFmtData[e].semanticIdx = i;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < meta.uvCount; ++i, ++e) {
|
||||
m_vtxFmtData[e].semantic = boo::VertexSemantic::UV2;
|
||||
m_vtxFmtData[e].semanticIdx = i;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < meta.weightCount; ++i, ++e) {
|
||||
m_vtxFmtData[e].semantic = boo::VertexSemantic::Weight;
|
||||
m_vtxFmtData[e].semanticIdx = i;
|
||||
}
|
||||
|
||||
m_vtxFmt = boo::VertexFormatInfo(elemCount, m_vtxFmtData.get());
|
||||
}
|
||||
|
||||
} // namespace hecl::Runtime
|
||||
Reference in New Issue
Block a user