Added korean location
This commit is contained in:
1 parent
d5ef126264
commit
96e748715b
80 files changed
+18949
-80
No files matched your search
+102
-31
@@ -55,6 +55,7 @@ namespace FRG {
|
||||
data.positionY = item.value("positionY", 0.0f);
|
||||
data.positionZ = item.value("positionZ", 0.0f);
|
||||
data.scale = item.value("scale", 1.0f);
|
||||
data.instanced = item.value("instanced", true);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -154,6 +155,36 @@ namespace FRG {
|
||||
return st;
|
||||
}
|
||||
|
||||
static VertexDataStruct loadMeshData(const std::string& meshPath, const std::string& zipPath)
|
||||
{
|
||||
if (meshPath.size() > 4 && meshPath.compare(meshPath.size() - 4, 4, ".bin") == 0)
|
||||
return LoadModelFromBinFile(meshPath, zipPath);
|
||||
return LoadFromTextFile02(meshPath, zipPath);
|
||||
}
|
||||
|
||||
static Eigen::Matrix3f makeRotationMatrix(const GameObjectData& data)
|
||||
{
|
||||
constexpr float kDeg2Rad = static_cast<float>(M_PI) / 180.0f;
|
||||
Eigen::Quaternionf rot = Eigen::Quaternionf::Identity();
|
||||
if (data.rotationX != 0.0f)
|
||||
rot = Eigen::Quaternionf(Eigen::AngleAxisf(data.rotationX * kDeg2Rad, Eigen::Vector3f::UnitX())) * rot;
|
||||
if (data.rotationY != 0.0f)
|
||||
rot = Eigen::Quaternionf(Eigen::AngleAxisf(data.rotationY * kDeg2Rad, Eigen::Vector3f::UnitY())) * rot;
|
||||
if (data.rotationZ != 0.0f)
|
||||
rot = Eigen::Quaternionf(Eigen::AngleAxisf(data.rotationZ * kDeg2Rad, Eigen::Vector3f::UnitZ())) * rot;
|
||||
return rot.toRotationMatrix();
|
||||
}
|
||||
|
||||
// Equivalent of what buildLoadedObject + Move() bake into the vertices:
|
||||
// RotateByMatrix computes v^T * R (= R^T * v), then Scale, then Move.
|
||||
static Eigen::Matrix4f makeInstanceMatrix(const GameObjectData& data)
|
||||
{
|
||||
Eigen::Matrix4f m = Eigen::Matrix4f::Identity();
|
||||
m.block<3, 3>(0, 0) = data.scale * makeRotationMatrix(data).transpose();
|
||||
m.block<3, 1>(0, 3) = Eigen::Vector3f(data.positionX, data.positionY, data.positionZ);
|
||||
return m;
|
||||
}
|
||||
|
||||
LoadedGameObject GameObjectLoader::buildLoadedObject(const GameObjectData& data, Renderer& renderer, const std::string& zipPath)
|
||||
{
|
||||
LoadedGameObject obj;
|
||||
@@ -164,20 +195,9 @@ namespace FRG {
|
||||
if (!data.textureDarkandsPath.empty())
|
||||
obj.textureDarklands = renderer.textureManager.LoadFromPng(data.textureDarkandsPath, zipPath);
|
||||
|
||||
if (data.meshPath.size() > 4 && data.meshPath.compare(data.meshPath.size() - 4, 4, ".bin") == 0)
|
||||
obj.mesh.data = LoadModelFromBinFile(data.meshPath, zipPath);
|
||||
else
|
||||
obj.mesh.data = LoadFromTextFile02(data.meshPath, zipPath);
|
||||
obj.mesh.data = loadMeshData(data.meshPath, zipPath);
|
||||
|
||||
constexpr float kDeg2Rad = static_cast<float>(M_PI) / 180.0f;
|
||||
Eigen::Quaternionf rot = Eigen::Quaternionf::Identity();
|
||||
if (data.rotationX != 0.0f)
|
||||
rot = Eigen::Quaternionf(Eigen::AngleAxisf(data.rotationX * kDeg2Rad, Eigen::Vector3f::UnitX())) * rot;
|
||||
if (data.rotationY != 0.0f)
|
||||
rot = Eigen::Quaternionf(Eigen::AngleAxisf(data.rotationY * kDeg2Rad, Eigen::Vector3f::UnitY())) * rot;
|
||||
if (data.rotationZ != 0.0f)
|
||||
rot = Eigen::Quaternionf(Eigen::AngleAxisf(data.rotationZ * kDeg2Rad, Eigen::Vector3f::UnitZ())) * rot;
|
||||
obj.mesh.data.RotateByMatrix(rot.toRotationMatrix());
|
||||
obj.mesh.data.RotateByMatrix(makeRotationMatrix(data));
|
||||
|
||||
if (data.scale != 1.0f)
|
||||
obj.mesh.data.Scale(data.scale);
|
||||
@@ -189,34 +209,85 @@ namespace FRG {
|
||||
// Public API
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
std::unordered_map<std::string, LoadedGameObject> GameObjectLoader::loadAndCreateGameObjects(
|
||||
StaticObjectSet GameObjectLoader::loadAndCreateGameObjects(
|
||||
const std::string& jsonPath,
|
||||
Renderer& renderer,
|
||||
const std::string& zipPath)
|
||||
{
|
||||
std::unordered_map<std::string, LoadedGameObject> gameObjects;
|
||||
StaticObjectSet result;
|
||||
|
||||
for (const auto& data : loadFromJson(jsonPath, zipPath)) {
|
||||
// Service the OS message queue between loads so the window doesn't
|
||||
// get flagged as "not responding" during long location loads.
|
||||
SDL_PumpEvents();
|
||||
logger() << "Loading game object: " << data.name << std::endl;
|
||||
try {
|
||||
LoadedGameObject obj = buildLoadedObject(data, renderer, zipPath);
|
||||
std::vector<GameObjectData> allData = loadFromJson(jsonPath, zipPath);
|
||||
|
||||
if (data.positionX != 0.0f || data.positionY != 0.0f || data.positionZ != 0.0f)
|
||||
obj.mesh.data.Move({ data.positionX, data.positionY, data.positionZ });
|
||||
// Group objects sharing mesh + textures (in file order) so they can be drawn instanced.
|
||||
std::vector<std::vector<const GameObjectData*>> groups;
|
||||
std::unordered_map<std::string, size_t> groupIndexByKey;
|
||||
|
||||
obj.mesh.RefreshVBO();
|
||||
gameObjects[data.name] = std::move(obj);
|
||||
logger() << "Successfully loaded: " << data.name << std::endl;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "GameObjectLoader: Failed to load '" << data.name << "': " << e.what() << std::endl;
|
||||
for (const auto& data : allData) {
|
||||
if (!data.instanced) {
|
||||
groups.push_back({ &data });
|
||||
continue;
|
||||
}
|
||||
std::string key = data.meshPath + '\n' + data.texturePath + '\n' + data.textureDarkandsPath;
|
||||
auto it = groupIndexByKey.find(key);
|
||||
if (it == groupIndexByKey.end()) {
|
||||
groupIndexByKey[key] = groups.size();
|
||||
groups.push_back({ &data });
|
||||
} else {
|
||||
groups[it->second].push_back(&data);
|
||||
}
|
||||
}
|
||||
|
||||
logger() << "Total game objects loaded: " << gameObjects.size() << std::endl;
|
||||
return gameObjects;
|
||||
for (const auto& group : groups) {
|
||||
// Service the OS message queue between loads so the window doesn't
|
||||
// get flagged as "not responding" during long location loads.
|
||||
SDL_PumpEvents();
|
||||
|
||||
const GameObjectData& first = *group.front();
|
||||
|
||||
if (group.size() == 1) {
|
||||
logger() << "Loading game object: " << first.name << std::endl;
|
||||
try {
|
||||
LoadedGameObject obj = buildLoadedObject(first, renderer, zipPath);
|
||||
|
||||
if (first.positionX != 0.0f || first.positionY != 0.0f || first.positionZ != 0.0f)
|
||||
obj.mesh.data.Move({ first.positionX, first.positionY, first.positionZ });
|
||||
|
||||
obj.mesh.RefreshVBO();
|
||||
result.single[first.name] = std::move(obj);
|
||||
logger() << "Successfully loaded: " << first.name << std::endl;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "GameObjectLoader: Failed to load '" << first.name << "': " << e.what() << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
logger() << "Loading instanced batch: " << first.meshPath << " x" << group.size() << std::endl;
|
||||
try {
|
||||
InstancedBatch batch;
|
||||
batch.name = first.name;
|
||||
batch.texture = renderer.textureManager.LoadFromPng(first.texturePath, zipPath);
|
||||
if (!first.textureDarkandsPath.empty())
|
||||
batch.textureDarklands = renderer.textureManager.LoadFromPng(first.textureDarkandsPath, zipPath);
|
||||
|
||||
// Mesh stays in local space; rotation, scale and position live in the instance matrices.
|
||||
batch.mesh.data = loadMeshData(first.meshPath, zipPath);
|
||||
batch.mesh.RefreshVBO();
|
||||
|
||||
batch.instances.reserve(group.size());
|
||||
for (const GameObjectData* d : group)
|
||||
batch.instances.push_back(makeInstanceMatrix(*d));
|
||||
batch.RefreshInstanceVBO();
|
||||
|
||||
result.batches.push_back(std::move(batch));
|
||||
logger() << "Successfully loaded instanced batch: " << first.meshPath << std::endl;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "GameObjectLoader: Failed to load instanced batch '" << first.meshPath << "': " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
logger() << "Total game objects loaded: " << result.single.size() << " single, "
|
||||
<< result.batches.size() << " instanced batches" << std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<InteractiveObject> GameObjectLoader::loadAndCreateInteractiveObjects(
|
||||
|
||||
@@ -26,10 +26,20 @@ namespace FRG {
|
||||
float positionY = 0.0f;
|
||||
float positionZ = 0.0f;
|
||||
float scale = 1.0f;
|
||||
// Objects sharing mesh and textures are drawn with one instanced call.
|
||||
// Set "instanced": false in the JSON to keep an object as a standalone mesh.
|
||||
bool instanced = true;
|
||||
|
||||
LoadedGameObjectState toLoadedGameObjectState() const;
|
||||
};
|
||||
|
||||
// Result of loading a static object list: unique objects keep their own mesh,
|
||||
// repeated ones are merged into instanced batches.
|
||||
struct StaticObjectSet {
|
||||
std::unordered_map<std::string, LoadedGameObject> single;
|
||||
std::vector<InstancedBatch> batches;
|
||||
};
|
||||
|
||||
struct InteractiveObjectData {
|
||||
GameObjectData base;
|
||||
float interactionRadius = 2.0f;
|
||||
@@ -86,7 +96,7 @@ namespace FRG {
|
||||
|
||||
class GameObjectLoader {
|
||||
public:
|
||||
static std::unordered_map<std::string, LoadedGameObject> loadAndCreateGameObjects(
|
||||
static StaticObjectSet loadAndCreateGameObjects(
|
||||
const std::string& jsonPath,
|
||||
Renderer& renderer,
|
||||
const std::string& zipPath = ""
|
||||
|
||||
Reference in new issue
Block a user