3#include <Tempest/MemReader>
4#include <Tempest/Pixmap>
5#include <Tempest/Device>
7#include <Tempest/Application>
8#include <Tempest/Sound>
9#include <Tempest/SoundEffect>
10#include <Tempest/TextCodec>
12#include <Tempest/Color>
14#include <zenkit/MultiResolutionMesh.hh>
15#include <zenkit/ModelHierarchy.hh>
16#include <zenkit/Model.hh>
17#include <zenkit/ModelScript.hh>
18#include <zenkit/Material.hh>
19#include <zenkit/Texture.hh>
20#include <zenkit/addon/texcvt.hh>
21#include <zenkit/Texture.hh>
39using namespace Tempest;
44 for(
size_t i=1;buf[i];++i){
45 if(buf[i]==tag && buf[i-1]==
'_' && buf[i+1]==
'0'){
58 static const uint16_t index[] = {
66 cube =
device.ibo(index,
sizeof(index)/
sizeof(index[0]));
70 dxMusic->addPath(
Gothic::nestedPath({u
"_work",u
"Data",u
"Music",u
"newworld"}, Dir::FT_Dir));
71 dxMusic->addPath(
Gothic::nestedPath({u
"_work",u
"Data",u
"Music",u
"AddonWorld"},Dir::FT_Dir));
73 dxMusic->addPath(
Gothic::nestedPath({u
"_work",u
"Data",u
"Music",u
"dungeon"}, Dir::FT_Dir));
74 dxMusic->addPath(
Gothic::nestedPath({u
"_work",u
"Data",u
"Music",u
"menu_men"}, Dir::FT_Dir));
75 dxMusic->addPath(
Gothic::nestedPath({u
"_work",u
"Data",u
"Music",u
"orchestra"},Dir::FT_Dir));
79 fBuff .reserve(8*1024*1024);
80 ddsBuf.reserve(8*1024*1024);
83 Pixmap pm(1,1,TextureFormat::RGBA8);
84 uint8_t* pix =
reinterpret_cast<uint8_t*
>(pm.data());
87 fallback =
device.texture(pm);
91 Pixmap pm(1,1,TextureFormat::RGBA8);
92 fbZero =
device.texture(pm);
95 fbImg =
device.image2d(TextureFormat::R32U,1,1);
98 DmResult rv = DmLoader_create(&dmLoader, DmLoader_DOWNLOAD);
99 if(rv != DmResult_SUCCESS) {
100 Log::e(
"Failed to created DmLoader object. Out of memory?");
103 DmLoader_addResolver(dmLoader, [](
void* ctx,
char const* name,
size_t* len) ->
void* {
104 auto* slf =
reinterpret_cast<Resources*
>(ctx);
105 auto* node = slf->gothicAssets.find(name);
107 if (node ==
nullptr) {
111 auto reader = node->open_read();
113 reader->seek(0, zenkit::Whence::END);
114 *len = reader->tell();
116 reader->seek(0, zenkit::Whence::BEG);
117 auto* bytes =
static_cast<uint8_t *
>(malloc(*len));
118 reader->read(bytes, *len);
125 inst->gothicAssets.mkdir(
"/_work");
126 inst->gothicAssets.mount_host(path,
"/_work", zenkit::VfsOverwriteBehavior::NONE);
130 std::vector<Archive> archives;
131 inst->detectVdf(archives,
Gothic::inst().nestedPath({u
"Data"},Dir::FT_Dir));
136 archives.erase(std::remove_if(archives.begin(), archives.end(),
137 [&modvdfs](
const Archive& a){
138 return a.isMod && modvdfs.end() == std::find_if(modvdfs.begin(), modvdfs.end(),
139 [&a](const std::u16string& modname) {
140 const std::u16string_view& full_path = a.name;
141 const std::u16string_view& file_name = modname;
142 return (0 == full_path.compare(full_path.length() - file_name.length(),
143 file_name.length(), file_name));
149 std::stable_sort(archives.begin(),archives.end(),[](
const Archive& a,
const Archive& b){
150 int aIsMod = a.isMod ? 1 : -1;
151 int bIsMod = b.isMod ? 1 : -1;
152 return std::make_tuple(aIsMod,a.time,int(a.ord)) >=
153 std::make_tuple(bIsMod,b.time,int(b.ord));
156 for(
auto& i:archives) {
158 auto in = zenkit::Read::from(i.name);
161 if(i.name.find(u
"Speech")!=std::string::npos)
164 inst->gothicAssets.mount_disk(i.name, zenkit::VfsOverwriteBehavior::OLDER);
166 catch(
const zenkit::VfsBrokenDiskError& err) {
167 Log::e(
"unable to load archive: \"", TextCodec::toUtf8(i.name),
"\", reason: ", err.what());
169 catch(
const std::exception& err) {
170 Log::e(
"unable to load archive: \"", TextCodec::toUtf8(i.name),
"\", reason: ", err.what());
183 DmLoader_release(dmLoader);
188 std::lock_guard<std::recursive_mutex> g(inst->sync);
189 return inst->gothicAssets.find(name) !=
nullptr;
200 auto reader = entry->open_read();
202 reader->seek(0, zenkit::Whence::END);
203 dat.resize(reader->tell());
204 reader->seek(0, zenkit::Whence::BEG);
205 reader->read(dat.data(), dat.size());
211 std::vector<uint8_t> data;
218 if (entry ==
nullptr)
219 throw std::runtime_error(
"failed to open resource: " + std::string{name});
220 return entry->open_read();
223std::unique_ptr<zenkit::ReadArchive>
Resources::openReader(std::string_view name, std::unique_ptr<zenkit::Read>& read) {
226 throw std::runtime_error(
"failed to open resource: " + std::string{name});
227 auto buf = entry->open_read();
229 throw std::runtime_error(
"failed to open resource: " + std::string{name});
230 auto zen = zenkit::ReadArchive::from(buf.get());
232 throw std::runtime_error(
"failed to open resource: " + std::string{name});
233 read = std::move(buf);
238 return inst->dev.properties().name;
242 Tempest::Sampler smp;
243 smp.setFiltration(Tempest::Filter::Nearest);
244 smp.setClamping(Tempest::ClampMode::ClampToEdge);
245 smp.anisotropic =
false;
254void Resources::detectVdf(std::vector<Archive>& ret,
const std::u16string &root) {
255 Dir::scan(root,[
this,&root,&ret](
const std::u16string& vdf, Dir::FileType t){
256 if(t==Dir::FT_File) {
257 auto file = root + vdf;
260 ar.time = vdfTimestamp(ar.name);
261 ar.ord = uint16_t(ret.size());
262 ar.isMod = vdf.rfind(u
".mod")==vdf.size()-4;
264 if(std::filesystem::file_size(ar.name)>0)
265 ret.emplace_back(std::move(ar));
270 if(vdf.find(u
".NX.")!=std::string::npos)
273 if(t==Dir::FT_Dir && vdf!=u
".." && vdf!=u
".") {
274 auto dir = root + vdf + u
"/";
289 return font(
"font_old_10_white.tga",type,scale);
295 return inst->implLoadFont(fname, type, scale);
299 return inst->fallback;
311 return inst->gothicAssets;
318int64_t Resources::vdfTimestamp(
const std::u16string& name) {
320 VDF_COMMENT_LENGTH = 256,
321 VDF_SIGNATURE_LENGTH = 16,
323 uint32_t count=0, timestamp=0;
324 char sign[VDF_SIGNATURE_LENGTH]={};
328 fin.seek(VDF_COMMENT_LENGTH);
329 fin.read(sign,VDF_SIGNATURE_LENGTH);
330 fin.read(&count,
sizeof(count));
332 fin.read(×tamp,
sizeof(timestamp));
334 return int64_t(timestamp);
341Tempest::Texture2d* Resources::implLoadTexture(std::string_view cname,
bool forceMips) {
346 std::string name = std::string(cname);
347 auto it=texCache.find(name);
348 if(it!=texCache.end())
349 return it->second.get();
351 auto tex = implLoadTextureUncached(cname, forceMips);
353 std::unique_ptr<Texture2d> t{
new Texture2d(std::move(tex))};
354 Texture2d* ret=t.get();
355 texCache[std::move(name)] = std::move(t);
358 texCache[std::move(name)] =
nullptr;
362Texture2d Resources::implLoadTextureUncached(std::string_view name,
bool forceMips) {
367 auto nameAlt = std::string(name);
368 nameAlt.resize(nameAlt.size() + 2);
369 std::memcpy(&nameAlt[0]+nameAlt.size()-6,
"-C.TEX", 6);
374 auto reader = entry->open_read();
375 tex.load(reader.get());
377 if(tex.format() == zenkit::TextureFormat::DXT1 ||
378 tex.format() == zenkit::TextureFormat::DXT2 ||
379 tex.format() == zenkit::TextureFormat::DXT3 ||
380 tex.format() == zenkit::TextureFormat::DXT4 ||
381 tex.format() == zenkit::TextureFormat::DXT5) {
382 auto dds = zenkit::to_dds(tex);
383 auto ddsRead = zenkit::Read::from(dds);
385 return implLoadTextureUncached(name, *ddsRead, forceMips);
387 auto rgba = tex.as_rgba8(0);
390 Tempest::Pixmap pm(tex.width(), tex.height(), TextureFormat::RGBA8);
391 std::memcpy(pm.data(), rgba.data(), rgba.size());
392 return dev.texture(pm);
401 auto reader = entry->open_read();
402 return implLoadTextureUncached(name, *reader, forceMips);
407Texture2d Resources::implLoadTextureUncached(std::string_view name, zenkit::Read& data,
bool forceMips) {
409 std::vector<uint8_t> raw;
410 data.seek(0, zenkit::Whence::END);
411 raw.resize(data.tell());
412 data.seek(0, zenkit::Whence::BEG);
413 data.read(raw.data(), raw.size());
415 Tempest::MemReader rd((uint8_t*)raw.data(), raw.size());
416 Tempest::Pixmap pm(rd);
418 const bool useMipmap = forceMips || (pm.mipCount()>1);
419 return dev.texture(pm, useMipmap);
426ProtoMesh* Resources::implLoadMesh(std::string_view name) {
430 auto cname = std::string(name);
431 auto it = aniMeshCache.find(cname);
432 if(it!=aniMeshCache.end())
433 return it->second.get();
435 auto t = implLoadMeshMain(cname);
437 aniMeshCache[cname] = std::move(t);
439 Log::e(
"unable to load mesh \"",cname,
"\"");
443std::unique_ptr<ProtoMesh> Resources::implLoadMeshMain(std::string name) {
451 zenkit::MultiResolutionMesh zmsh;
453 auto reader = entry->open_read();
454 zmsh.load(reader.get());
456 if(zmsh.sub_meshes.empty())
460 return std::unique_ptr<ProtoMesh>{
new ProtoMesh(std::move(packed),name)};
468 throw std::runtime_error(
"failed to open resource: " + name);
470 zenkit::MorphMesh zmm;
471 auto reader = entry->open_read();
472 zmm.load(reader.get());
474 if(zmm.mesh.sub_meshes.empty())
478 return std::unique_ptr<ProtoMesh>{
new ProtoMesh(std::move(packed),zmm.animations,name)};
486 auto mesh = std::string(anim->defaultMesh());
491 auto mdhName = std::string(anim->defaultMesh());
498 zenkit::ModelHierarchy mdh;
499 auto reader = entryMdh->open_read();
500 mdh.load(reader.get());
502 std::unique_ptr<Skeleton> sk{
new Skeleton(mdh,anim,name)};
503 std::unique_ptr<ProtoMesh> t;
506 auto reader = entry->open_read();
508 zenkit::ModelMesh mdm {};
509 mdm.load(reader.get());
510 t.reset(
new ProtoMesh(mdm,std::move(sk),name));
513 t.reset(
new ProtoMesh(mdh,std::move(sk),name));
521 if(entryMdl==
nullptr)
522 throw std::runtime_error(
"failed to open resource: " + mdhName);
525 auto reader = entryMdl->open_read();
526 mdm.load(reader.get());
528 std::unique_ptr<Skeleton> sk{
new Skeleton(mdm.hierarchy,anim,name)};
529 std::unique_ptr<ProtoMesh> t{
new ProtoMesh(mdm,std::move(sk),name)};
544 zenkit::ModelMesh mdm;
545 auto reader = entry->open_read();
546 mdm.load(reader.get());
548 std::unique_ptr<ProtoMesh> t{
new ProtoMesh(std::move(mdm),
nullptr,name)};
558 throw std::runtime_error(
"failed to open resource: " + name);
560 auto reader = entry->open_read();
561 mdm.load(reader.get());
563 std::unique_ptr<Skeleton> sk{
new Skeleton(mdm.hierarchy,
nullptr,name)};
564 std::unique_ptr<ProtoMesh> t{
new ProtoMesh(mdm,std::move(sk),name)};
569 Log::e(
"decals should be loaded by Resources::implDecalMesh instead");
575PfxEmitterMesh* Resources::implLoadEmiterMesh(std::string_view name) {
577 auto cname = std::string(name);
578 auto it = emiMeshCache.find(cname);
579 if(it!=emiMeshCache.end())
580 return it->second.get();
582 auto& ret = emiMeshCache[cname];
588 if (entry ==
nullptr)
return nullptr;
589 zenkit::MultiResolutionMesh zmsh;
590 auto reader = entry->open_read();
591 zmsh.load(reader.get());
593 if(zmsh.sub_meshes.empty())
597 ret = std::unique_ptr<PfxEmitterMesh>(
new PfxEmitterMesh(packed));
607 throw std::runtime_error(
"failed to open resource: " + cname);
608 zenkit::ModelMesh mdm;
609 auto reader = entry->open_read();
610 mdm.load(reader.get());
612 ret = std::unique_ptr<PfxEmitterMesh>(
new PfxEmitterMesh(std::move(mdm)));
619ProtoMesh* Resources::implDecalMesh(
const zenkit::VisualDecal& decal) {
622 key.sX = decal.dimension.x;
623 key.sY = decal.dimension.y;
624 key.decal2Sided = decal.two_sided;
626 if(key.mat.tex==
nullptr)
629 auto it = decalMeshCache.find(key);
630 if(it!=decalMeshCache.end())
631 return it->second.get();
634 {{-1.f, -1.f, 0.f},{0,0,-1},{0,1}, 0xFFFFFFFF},
635 {{ 1.f, -1.f, 0.f},{0,0,-1},{1,1}, 0xFFFFFFFF},
636 {{ 1.f, 1.f, 0.f},{0,0,-1},{1,0}, 0xFFFFFFFF},
637 {{-1.f, 1.f, 0.f},{0,0,-1},{0,0}, 0xFFFFFFFF},
639 {{-1.f, -1.f, 0.f},{0,0, 1},{0,1}, 0xFFFFFFFF},
640 {{ 1.f, -1.f, 0.f},{0,0, 1},{1,1}, 0xFFFFFFFF},
641 {{ 1.f, 1.f, 0.f},{0,0, 1},{1,0}, 0xFFFFFFFF},
642 {{-1.f, 1.f, 0.f},{0,0, 1},{0,0}, 0xFFFFFFFF},
649 std::vector<Resources::Vertex> cvbo(
vbo,
vbo+8);
650 std::vector<uint32_t> cibo;
652 cibo = { 0,1,2, 0,2,3, 4,6,5, 4,7,6 };
else
653 cibo = { 0,1,2, 0,2,3 };
655 std::unique_ptr<ProtoMesh> t{
new ProtoMesh(key.mat, std::move(cvbo), std::move(cibo))};
658 decalMeshCache[key] = std::move(t);
662std::unique_ptr<Animation> Resources::implLoadAnimation(std::string name) {
674 zenkit::ModelScript mds;
675 auto reader = entry->open_read();
676 mds.load(reader.get());
677 return std::unique_ptr<Animation>{
new Animation(mds,name.substr(0,name.size()-4),
false)};
684 auto u = Tempest::TextCodec::toUtf16(name);
685 return dxMusic->load(u.c_str());
688DmSegment* Resources::implLoadMusicSegment(
char const* name) {
689 DmSegment* sgt =
nullptr;
690 DmResult rv = DmLoader_getSegment(dmLoader, name, &sgt);
691 if(rv != DmResult_SUCCESS) {
692 Log::e(
"Music segment not found: ", name);
698Tempest::Sound Resources::implLoadSoundBuffer(std::string_view name) {
700 return Tempest::Sound();
703 return Tempest::Sound();
705 Tempest::MemReader rd(fBuff.data(),fBuff.size());
706 return Tempest::Sound(rd);
709 auto cname = std::string (name);
710 Log::e(
"unable to load sound \"",cname,
"\"");
711 return Tempest::Sound();
715GthFont &Resources::implLoadFont(std::string_view name, FontType type,
const float scale) {
716 std::lock_guard<std::recursive_mutex> g(inst->syncFont);
718 auto key = FontK(std::string(name), type, scale);
719 auto it = gothicFnt.find(key);
720 if(it!=gothicFnt.end())
721 return *(*it).second;
723 std::string_view file = name;
724 for(
size_t i=0; i<name.size();++i) {
726 file = name.substr(0, i);
746 auto color = Tempest::Color(1.f);
750 color = Tempest::Color(1.f);
753 color = Tempest::Color(1.f,1.f,1.f,0.6f);
756 color = Tempest::Color(1.f,1.f,0.1f,1.f);
760 color = Tempest::Color(1.f,0.f,0.f,1.f);
765 if(entry ==
nullptr) {
766 Log::e(
"failed to open resource: ", fnt);
768 auto ptr = std::make_unique<GthFont>();
770 gothicFnt[key] = std::move(ptr);
774 auto ptr = std::make_unique<GthFont>(*entry->open_read(),tex,color);
777 gothicFnt[key] = std::move(ptr);
782 return inst->implLoadTextureUncached(name, forceMips);
786 std::lock_guard<std::recursive_mutex> g(inst->sync);
787 return inst->implLoadTexture(name,forceMips);
793 std::lock_guard<std::recursive_mutex> g(inst->sync);
794 auto& cache = inst->pixCache;
795 auto it = cache.find(color);
797 return it->second.get();
799 uint8_t iv[4] = { uint8_t(255.f*color.r()), uint8_t(255.f*color.g()), uint8_t(255.f*color.b()), uint8_t(255.f*color.a()) };
800 Pixmap p2(1,1,TextureFormat::RGBA8);
801 std::memcpy(p2.data(),iv,4);
803 auto t = std::make_unique<Texture2d>(inst->dev.texture(p2));
805 cache[color] = std::move(t);
818 std::snprintf(v,
sizeof(v),
"V%d",iv);
819 std::snprintf(c,
sizeof(c),
"C%d",ic);
820 std::snprintf(buf1,
sizeof(buf1),
"%.*s",
int(name.size()),name.data());
823 std::snprintf(buf2,
sizeof(buf2),buf1,v);
826 std::snprintf(buf1,
sizeof(buf1),buf2,c);
832 std::vector<const Texture2d*> ret;
833 if(name.find(
"_A0")==std::string::npos &&
834 name.find(
"_a0")==std::string::npos)
837 for(
int id=0; ; ++id) {
840 for(
size_t i=0;i<name.size();++i) {
841 if(i+2<name.size() && name[i]==
'_' && (name[i+1]==
'A' || name[i+1]==
'a') && name[i+2]==
'0'){
842 at += size_t(std::snprintf(buf+at,
sizeof(buf)-at,
"_A%d",
id));
846 if(
'a'<=buf[at] && buf[at]<=
'z')
847 buf[at] = char(buf[at]+
'A'-
'a');
866 Pixmap p2(1,1,TextureFormat::R8);
867 std::memset(p2.data(),0,1);
868 return inst->dev.texture(p2);
870 return inst->dev.texture(pm);
874 return Material(src,enableAlphaTest);
880 std::lock_guard<std::recursive_mutex> g(inst->sync);
881 return inst->implLoadMesh(name);
887 std::lock_guard<std::recursive_mutex> g(inst->sync);
888 return inst->implLoadEmiterMesh(name);
895 return s->skeleton.get();
899 auto cname = std::string(name);
901 std::lock_guard<std::recursive_mutex> g(inst->sync);
902 auto& cache = inst->animCache;
903 auto it=cache.find(cname);
905 return it->second.get();
906 auto t = inst->implLoadAnimation(cname);
908 cache[cname] = std::move(t);
913 std::lock_guard<std::recursive_mutex> g(inst->sync);
914 return inst->implLoadSoundBuffer(name);
918 std::lock_guard<std::recursive_mutex> g(inst->sync);
919 return inst->implLoadDxMusic(name);
923 std::lock_guard<std::recursive_mutex> g(inst->sync);
924 return inst->implLoadMusicSegment(name);
928 std::lock_guard<std::recursive_mutex> g(inst->sync);
929 return inst->implDecalMesh(decal);
933 std::lock_guard<std::recursive_mutex> g(inst->sync);
934 return inst->implLoadVobBundle(name);
938 std::lock_guard<std::recursive_mutex> g(inst->sync);
939 inst->recycledId = fId;
940 inst->recycled[fId].ssbo.clear();
941 inst->recycled[fId].img.clear();
942 inst->recycled[fId].att.clear();
943 inst->recycled[fId].zb.clear();
944 inst->recycled[fId].arr.clear();
945 inst->recycled[fId].rtas.clear();
951 std::lock_guard<std::recursive_mutex> g(inst->sync);
952 inst->recycled[inst->recycledId].arr.emplace_back(std::move(arr));
958 std::lock_guard<std::recursive_mutex> g(inst->sync);
959 inst->recycled[inst->recycledId].ssbo.emplace_back(std::move(
ssbo));
965 std::lock_guard<std::recursive_mutex> g(inst->sync);
966 inst->recycled[inst->recycledId].img.emplace_back(std::move(img));
972 std::lock_guard<std::recursive_mutex> g(inst->sync);
973 inst->recycled[inst->recycledId].att.emplace_back(std::move(img));
979 std::lock_guard<std::recursive_mutex> g(inst->sync);
980 inst->recycled[inst->recycledId].zb.emplace_back(std::move(img));
986 std::lock_guard<std::recursive_mutex> g(inst->sync);
987 inst->recycled[inst->recycledId].rtas.emplace_back(std::move(rtas));
991 auto cname = std::string(filename);
992 auto i = zenCache.find(cname);
993 if(i!=zenCache.end())
994 return i->second.get();
996 std::vector<std::shared_ptr<zenkit::VirtualObject>> bundle;
1000 throw std::runtime_error(
"failed to open resource: " + cname);
1004 auto reader = entry->open_read();
1006 : zenkit::GameVersion::GOTHIC_2);
1008 bundle = std::move(wrld.world_vobs);
1011 Log::e(
"unable to load Zen-file: \"",cname,
"\"");
1014 auto ret = zenCache.insert(std::make_pair(filename,std::make_unique<VobTree>(std::move(bundle))));
1015 return ret.first->second.get();
1019 std::lock_guard<std::recursive_mutex> g(inst->sync);
1025 BindK k = BindK(&s,&anim);
1027 auto it = inst->bindCache.find(k);
1028 if(it!=inst->bindCache.end())
1029 return it->second.get();
1031 std::unique_ptr<AttachBinder> ret(
new AttachBinder(s,anim));
1033 inst->bindCache[k] = std::move(ret);
1037Tempest::VertexBuffer<Resources::Vertex> Resources::sphere(
int passCount,
float R){
1038 std::vector<Resources::Vertex> r;
1039 r.reserve(
size_t(4*pow(3, passCount+1)) );
1041 static const double pi = 3.141592654;
1048 {float(cos(2*pi/3)), float(sin(2*pi/3)), -0.5},
1052 {float(cos(2*pi/3)), -float(sin(2*pi/3)), -0.5},
1077 for(
size_t i=0; i<r.size(); ++i){
1086 for(
int c=0; c<passCount; ++c){
1087 size_t maxI = r.size();
1088 for(
size_t i=0; i<maxI; i+=3 ){
1091 0.5f*(r[i].pos[0]+r[i+1].pos[0]),
1092 0.5f*(r[i].pos[1]+r[i+1].pos[1]),
1093 0.5f*(r[i].pos[2]+r[i+1].pos[2])
1099 0.5f*(r[i+2].pos[0]+r[i+1].pos[0]),
1100 0.5f*(r[i+2].pos[1]+r[i+1].pos[1]),
1101 0.5f*(r[i+2].pos[2]+r[i+1].pos[2])
1107 0.5f*(r[i].pos[0]+r[i+2].pos[0]),
1108 0.5f*(r[i].pos[1]+r[i+2].pos[1]),
1109 0.5f*(r[i].pos[2]+r[i+2].pos[2])
1114 r.push_back( r[i] );
1119 r.push_back( r[i+1] );
1123 r.push_back( r[i+2] );
1131 for(
size_t i=0; i<r.size(); ++i){
1141 for(
size_t i=0; i<r.size(); ++i){
static std::u16string nestedPath(const std::initializer_list< const char16_t * > &name, Tempest::Dir::FileType type)
auto version() const -> const VersionInfo &
std::vector< SubMeshId > submeshId
static void loadVdfs(const std::vector< std::u16string > &modvdfs, bool modFilter)
static const PfxEmitterMesh * loadEmiterMesh(std::string_view name)
static Tempest::StorageBuffer ssbo(const void *data, size_t size)
std::vector< std::shared_ptr< zenkit::VirtualObject > > VobTree
static const Tempest::Texture2d & fallbackTexture()
static void resetRecycled(uint8_t fId)
static auto openReader(std::string_view name, std::unique_ptr< zenkit::Read > &read) -> std::unique_ptr< zenkit::ReadArchive >
static const Animation * loadAnimation(std::string_view name)
static const Skeleton * loadSkeleton(std::string_view name)
static const Tempest::IndexBuffer< uint16_t > & cubeIbo()
static const Tempest::Sampler & shadowSampler()
static Tempest::Texture2d loadTextureUncached(std::string_view name, bool forceMips=false)
static const GthFont & font(const float scale)
static const GthFont & dialogFont(const float scale)
static bool hasFile(std::string_view fname)
static const VobTree * loadVobBundle(std::string_view name)
static auto fallbackImage() -> const Tempest::StorageImage &
static Material loadMaterial(const zenkit::Material &src, bool enableAlphaTest)
static std::vector< uint8_t > getFileData(std::string_view name)
static const ProtoMesh * loadMesh(std::string_view name)
static Tempest::Device & device()
static Dx8::PatternList loadDxMusic(std::string_view name)
static const Tempest::Texture2d * loadTexture(std::string_view name, bool forceMips=false)
static std::unique_ptr< zenkit::Read > getFileBuffer(std::string_view name)
static const char * renderer()
Resources(Tempest::Device &device)
static Tempest::Sound loadSoundBuffer(std::string_view name)
static const Tempest::Texture2d & fallbackBlack()
static DmSegment * loadMusicSegment(char const *name)
static const zenkit::Vfs & vdfsIndex()
static const AttachBinder * bindMesh(const ProtoMesh &anim, const Skeleton &s)
static auto loadTextureAnim(std::string_view name) -> std::vector< const Tempest::Texture2d * >
static Tempest::Texture2d loadTexturePm(const Tempest::Pixmap &pm)
static void recycle(Tempest::DescriptorArray &&arr)
static void mountWork(const std::filesystem::path &path)
static Tempest::VertexBuffer< V > vbo(const V *data, size_t sz)
static const ProtoMesh * decalMesh(const zenkit::VisualDecal &decal)
bool exchangeExt(std::string &s, const char *extIn, const char *extOut)
bool hasExt(std::string_view s, const char *extIn)
void assignExt(std::string &s, const char *extOut)
static Sampler implShadowSampler()
static void emplaceTag(char *buf, char tag)