New type of anim
This commit is contained in:
parent
c198f39515
commit
b3a5e36e1b
@ -30,6 +30,8 @@ add_executable(space-game001
|
|||||||
../src/AudioPlayerAsync.h
|
../src/AudioPlayerAsync.h
|
||||||
../src/BoneAnimatedModel.cpp
|
../src/BoneAnimatedModel.cpp
|
||||||
../src/BoneAnimatedModel.h
|
../src/BoneAnimatedModel.h
|
||||||
|
../src/BoneAnimatedModelNew.cpp
|
||||||
|
../src/BoneAnimatedModelNew.h
|
||||||
../src/render/OpenGlExtensions.cpp
|
../src/render/OpenGlExtensions.cpp
|
||||||
../src/render/OpenGlExtensions.h
|
../src/render/OpenGlExtensions.h
|
||||||
../src/utils/Utils.cpp
|
../src/utils/Utils.cpp
|
||||||
|
|||||||
BIN
resources/e/female_packed0_diffuse.png
(Stored with Git LFS)
Normal file
BIN
resources/e/female_packed0_diffuse.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/e/female_packed1_diffuse.png
(Stored with Git LFS)
Normal file
BIN
resources/e/female_packed1_diffuse.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/e/female_packed2_diffuse.png
(Stored with Git LFS)
Normal file
BIN
resources/e/female_packed2_diffuse.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/e/female_packed3_diffuse.png
(Stored with Git LFS)
Normal file
BIN
resources/e/female_packed3_diffuse.png
(Stored with Git LFS)
Normal file
Binary file not shown.
424511
resources/e/gg_stand_idle003.txt
Normal file
424511
resources/e/gg_stand_idle003.txt
Normal file
File diff suppressed because it is too large
Load Diff
BIN
resources/e/male_packed0_diffuse.png
(Stored with Git LFS)
Normal file
BIN
resources/e/male_packed0_diffuse.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/e/male_packed1_diffuse.png
(Stored with Git LFS)
Normal file
BIN
resources/e/male_packed1_diffuse.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/e/male_packed2_diffuse.png
(Stored with Git LFS)
Normal file
BIN
resources/e/male_packed2_diffuse.png
(Stored with Git LFS)
Normal file
Binary file not shown.
237188
resources/e/woman_run001.txt
Normal file
237188
resources/e/woman_run001.txt
Normal file
File diff suppressed because it is too large
Load Diff
334094
resources/e/woman_stand_idle001.txt
Normal file
334094
resources/e/woman_stand_idle001.txt
Normal file
File diff suppressed because it is too large
Load Diff
76146
resources/e/woman_stand_idle002.txt
Normal file
76146
resources/e/woman_stand_idle002.txt
Normal file
File diff suppressed because one or more lines are too long
334138
resources/e/woman_stand_idle003.txt
Normal file
334138
resources/e/woman_stand_idle003.txt
Normal file
File diff suppressed because it is too large
Load Diff
684
src/BoneAnimatedModelNew.cpp
Normal file
684
src/BoneAnimatedModelNew.cpp
Normal file
@ -0,0 +1,684 @@
|
|||||||
|
#include "BoneAnimatedModelNew.h"
|
||||||
|
#include <regex>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace ZL
|
||||||
|
{
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
using std::min;
|
||||||
|
using std::max;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int getIndexByValue(const std::string& name, const std::vector<std::string>& words);
|
||||||
|
|
||||||
|
static std::string trimRight(const std::string& s)
|
||||||
|
{
|
||||||
|
size_t end = s.size();
|
||||||
|
while (end > 0 && (s[end - 1] == '\r' || s[end - 1] == '\n' || s[end - 1] == ' ' || s[end - 1] == '\t'))
|
||||||
|
end--;
|
||||||
|
return s.substr(0, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoneSystemNew::LoadFromFile(const std::string& fileName, const std::string& ZIPFileName)
|
||||||
|
{
|
||||||
|
std::ifstream filestream;
|
||||||
|
std::istringstream zipStream;
|
||||||
|
|
||||||
|
if (!ZIPFileName.empty())
|
||||||
|
{
|
||||||
|
std::vector<char> fileData = readFileFromZIP(fileName, ZIPFileName);
|
||||||
|
std::string fileContents(fileData.begin(), fileData.end());
|
||||||
|
zipStream.str(fileContents);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filestream.open(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& f = (!ZIPFileName.empty()) ? static_cast<std::istream&>(zipStream) : static_cast<std::istream&>(filestream);
|
||||||
|
|
||||||
|
static const std::regex pattern_count(R"(\d+)");
|
||||||
|
static const std::regex pattern_float(R"([-]?\d+\.\d+)");
|
||||||
|
static const std::regex pattern_int(R"([-]?\d+)");
|
||||||
|
static const std::regex pattern_boneChildren(R"(\'([^\']+)\')");
|
||||||
|
static const std::regex pattern_bone_weight(R"(\'([^\']+)\'.*?([-]?\d+\.\d+))");
|
||||||
|
|
||||||
|
std::smatch match;
|
||||||
|
std::string tempLine;
|
||||||
|
|
||||||
|
// ---- Armature matrix (4 lines after the header) ----
|
||||||
|
std::getline(f, tempLine); // === Armature Matrix ===
|
||||||
|
armatureMatrix = Matrix4f::Identity();
|
||||||
|
for (int r = 0; r < 4; r++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
std::vector<float> floatValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
if (floatValues.size() >= 4)
|
||||||
|
{
|
||||||
|
for (int c = 0; c < 4; c++)
|
||||||
|
armatureMatrix.data()[r + c * 4] = floatValues[c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Bones ----
|
||||||
|
std::getline(f, tempLine); // === Armature Bones: N
|
||||||
|
int numberBones;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberBones = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Armature bones count not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Bone> bones;
|
||||||
|
std::vector<std::string> boneNames;
|
||||||
|
std::vector<std::string> boneParentNames;
|
||||||
|
std::unordered_map<std::string, std::vector<std::string>> boneChildren;
|
||||||
|
|
||||||
|
bones.resize(numberBones);
|
||||||
|
boneNames.resize(numberBones);
|
||||||
|
boneParentNames.resize(numberBones);
|
||||||
|
|
||||||
|
for (int i = 0; i < numberBones; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine); // Bone: name
|
||||||
|
std::string boneName = trimRight(tempLine.substr(6));
|
||||||
|
boneNames[i] = boneName;
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // HEAD_LOCAL
|
||||||
|
std::vector<float> floatValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
bones[i].boneStartWorld = Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // TAIL_LOCAL
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // Length
|
||||||
|
if (std::regex_search(tempLine, match, pattern_float)) {
|
||||||
|
bones[i].boneLength = std::stof(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Bone length not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3x3 matrix
|
||||||
|
for (int r = 0; r < 3; r++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
b = tempLine.cbegin();
|
||||||
|
e = tempLine.cend();
|
||||||
|
floatValues.clear();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
bones[i].boneMatrixWorld.data()[r] = floatValues[0];
|
||||||
|
bones[i].boneMatrixWorld.data()[r + 1 * 3] = floatValues[1];
|
||||||
|
bones[i].boneMatrixWorld.data()[r + 2 * 3] = floatValues[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // Parent
|
||||||
|
std::string parentLine = trimRight(tempLine);
|
||||||
|
if (parentLine == " Parent: None")
|
||||||
|
{
|
||||||
|
bones[i].parent = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
boneParentNames[i] = parentLine.substr(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // Children
|
||||||
|
auto bc = tempLine.cbegin();
|
||||||
|
auto ec = tempLine.cend();
|
||||||
|
while (std::regex_search(bc, ec, match, pattern_boneChildren)) {
|
||||||
|
boneChildren[boneName].push_back(match.str(1));
|
||||||
|
bc = match.suffix().first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve parent/child indices
|
||||||
|
for (int i = 0; i < numberBones; i++)
|
||||||
|
{
|
||||||
|
const std::string& boneName = boneNames[i];
|
||||||
|
const std::string& boneParent = boneParentNames[i];
|
||||||
|
if (boneParent == "" || boneParent == "None")
|
||||||
|
bones[i].parent = -1;
|
||||||
|
else
|
||||||
|
bones[i].parent = getIndexByValue(boneParent, boneNames);
|
||||||
|
|
||||||
|
for (size_t j = 0; j < boneChildren[boneName].size(); j++)
|
||||||
|
bones[i].children.push_back(getIndexByValue(boneChildren[boneName][j], boneNames));
|
||||||
|
}
|
||||||
|
|
||||||
|
startBones = bones;
|
||||||
|
currentBones = bones;
|
||||||
|
|
||||||
|
// ---- Multi-mesh header ----
|
||||||
|
std::getline(f, tempLine); // === TOTAL MESHES TO EXPORT: N ===
|
||||||
|
int numberMeshes;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberMeshes = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Total meshes count not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int meshIdx = 0; meshIdx < numberMeshes; meshIdx++)
|
||||||
|
{
|
||||||
|
// === Mesh Object: Name ===
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
std::string meshHeader = trimRight(tempLine);
|
||||||
|
// Extract mesh name: strip "=== Mesh Object: " prefix and " ===" suffix
|
||||||
|
const std::string prefix = "=== Mesh Object: ";
|
||||||
|
const std::string suffix = " ===";
|
||||||
|
std::string meshName;
|
||||||
|
if (meshHeader.size() >= prefix.size() + suffix.size() &&
|
||||||
|
meshHeader.compare(0, prefix.size(), prefix) == 0 &&
|
||||||
|
meshHeader.compare(meshHeader.size() - suffix.size(), suffix.size(), suffix) == 0)
|
||||||
|
{
|
||||||
|
meshName = meshHeader.substr(prefix.size(),
|
||||||
|
meshHeader.size() - prefix.size() - suffix.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid mesh header: " + meshHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshBoneData meshData;
|
||||||
|
|
||||||
|
// Vertices
|
||||||
|
std::getline(f, tempLine); // ===Vertices: N
|
||||||
|
int numberVertices;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberVertices = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Vertex count not found for mesh " + meshName);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Vector3f> vertices(numberVertices);
|
||||||
|
for (int i = 0; i < numberVertices; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
std::vector<float> floatValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
vertices[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// UV coordinates
|
||||||
|
std::getline(f, tempLine); // ===UV Coordinates:
|
||||||
|
std::getline(f, tempLine); // Face count: M
|
||||||
|
int numberFaces;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberFaces = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Face count not found for mesh " + meshName);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::array<Vector2f, 3>> uvCoords(numberFaces);
|
||||||
|
for (int i = 0; i < numberFaces; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine); // Face X
|
||||||
|
std::getline(f, tempLine); // UV Count: 3
|
||||||
|
int uvCount;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
uvCount = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("UV count not found");
|
||||||
|
}
|
||||||
|
if (uvCount != 3)
|
||||||
|
throw std::runtime_error("more than 3 uvs");
|
||||||
|
|
||||||
|
for (int j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine); // UV <Vector (u, v)>
|
||||||
|
std::vector<float> floatValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
if (floatValues.size() != 2)
|
||||||
|
throw std::runtime_error("more than 2 uvs---");
|
||||||
|
uvCoords[i][j] = Vector2f{ floatValues[0], floatValues[1] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normals
|
||||||
|
std::getline(f, tempLine); // ===Normals:
|
||||||
|
std::vector<Vector3f> normals(numberVertices);
|
||||||
|
for (int i = 0; i < numberVertices; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
std::vector<float> floatValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
normals[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triangles
|
||||||
|
std::getline(f, tempLine); // ===Triangles: M
|
||||||
|
int numberTriangles;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberTriangles = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Triangle count not found for mesh " + meshName);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::array<int, 3>> triangles(numberTriangles);
|
||||||
|
for (int i = 0; i < numberTriangles; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
std::vector<int> intValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_int)) {
|
||||||
|
intValues.push_back(std::stoi(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
triangles[i] = { intValues[0], intValues[1], intValues[2] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vertex weights
|
||||||
|
std::getline(f, tempLine); // === Vertex Weights (Max 5 bones per vertex) ===
|
||||||
|
std::vector<std::array<BoneWeight, MAX_BONE_COUNT>> localVerticesBoneWeight(numberVertices);
|
||||||
|
for (int i = 0; i < numberVertices; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine); // Vertex X:
|
||||||
|
std::getline(f, tempLine); // Vertex groups: K
|
||||||
|
int boneCount;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
boneCount = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Vertex group count not found");
|
||||||
|
}
|
||||||
|
if (boneCount > MAX_BONE_COUNT)
|
||||||
|
throw std::runtime_error("more than 5 bones");
|
||||||
|
|
||||||
|
float sumWeights = 0;
|
||||||
|
for (int j = 0; j < boneCount; j++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
if (std::regex_search(tempLine, match, pattern_bone_weight)) {
|
||||||
|
std::string word = match.str(1);
|
||||||
|
double weight = std::stod(match.str(2));
|
||||||
|
int boneNumber = getIndexByValue(word, boneNames);
|
||||||
|
localVerticesBoneWeight[i][j].boneIndex = boneNumber;
|
||||||
|
localVerticesBoneWeight[i][j].weight = static_cast<float>(weight);
|
||||||
|
sumWeights += static_cast<float>(weight);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("No match found in bone weight line");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int j = 0; j < boneCount; j++)
|
||||||
|
localVerticesBoneWeight[i][j].weight /= sumWeights;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build per-triangle expanded mesh
|
||||||
|
for (int i = 0; i < numberTriangles; i++)
|
||||||
|
{
|
||||||
|
meshData.mesh.PositionData.push_back(vertices[triangles[i][0]]);
|
||||||
|
meshData.mesh.PositionData.push_back(vertices[triangles[i][1]]);
|
||||||
|
meshData.mesh.PositionData.push_back(vertices[triangles[i][2]]);
|
||||||
|
|
||||||
|
meshData.verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][0]]);
|
||||||
|
meshData.verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][1]]);
|
||||||
|
meshData.verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][2]]);
|
||||||
|
|
||||||
|
meshData.mesh.TexCoordData.push_back(uvCoords[i][0]);
|
||||||
|
meshData.mesh.TexCoordData.push_back(uvCoords[i][1]);
|
||||||
|
meshData.mesh.TexCoordData.push_back(uvCoords[i][2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
meshData.startMesh = meshData.mesh;
|
||||||
|
|
||||||
|
meshes[meshName] = std::move(meshData);
|
||||||
|
meshNamesOrdered.push_back(meshName);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Loaded " << numberMeshes << " meshes from " << fileName << std::endl;
|
||||||
|
|
||||||
|
// ---- Animation Keyframes ----
|
||||||
|
std::getline(f, tempLine); // === Animation Keyframes ===
|
||||||
|
std::getline(f, tempLine); // === Bone Transforms per Keyframe ===
|
||||||
|
std::getline(f, tempLine); // Keyframes: N
|
||||||
|
int numberKeyFrames;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberKeyFrames = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Keyframe count not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
animations.resize(1);
|
||||||
|
animations[0].keyFrames.resize(numberKeyFrames);
|
||||||
|
|
||||||
|
for (int i = 0; i < numberKeyFrames; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine); // Frame: N
|
||||||
|
int numberFrame;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberFrame = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Frame number not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
animations[0].keyFrames[i].frame = numberFrame;
|
||||||
|
animations[0].keyFrames[i].bones.resize(numberBones);
|
||||||
|
|
||||||
|
for (int j = 0; j < numberBones; j++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine); // Bone: name
|
||||||
|
std::string boneName = trimRight(tempLine.substr(8));
|
||||||
|
int boneNumber = getIndexByValue(boneName, boneNames);
|
||||||
|
animations[0].keyFrames[i].bones[boneNumber] = startBones[boneNumber];
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // Location
|
||||||
|
std::vector<float> floatValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
animations[0].keyFrames[i].bones[boneNumber].boneStartWorld =
|
||||||
|
Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // Rotation
|
||||||
|
std::getline(f, tempLine); // Matrix:
|
||||||
|
|
||||||
|
for (int r = 0; r < 4; r++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
b = tempLine.cbegin();
|
||||||
|
e = tempLine.cend();
|
||||||
|
floatValues.clear();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[r] = floatValues[0];
|
||||||
|
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[r + 1 * 4] = floatValues[1];
|
||||||
|
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[r + 2 * 4] = floatValues[2];
|
||||||
|
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[r + 3 * 4] = floatValues[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startBones.size() > MAX_GPU_BONES)
|
||||||
|
{
|
||||||
|
std::cout << "Warning: model has " << startBones.size()
|
||||||
|
<< " bones, exceeding GPU skinning limit of " << MAX_GPU_BONES << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoneSystemNew::Interpolate(int frame)
|
||||||
|
{
|
||||||
|
int startingKeyFrame = -1;
|
||||||
|
for (int i = 0; i < static_cast<int>(animations[0].keyFrames.size()) - 1; i++)
|
||||||
|
{
|
||||||
|
int oldFrame = animations[0].keyFrames[i].frame;
|
||||||
|
int nextFrame = animations[0].keyFrames[i + 1].frame;
|
||||||
|
if (frame >= oldFrame && frame < nextFrame)
|
||||||
|
{
|
||||||
|
startingKeyFrame = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startingKeyFrame == -1)
|
||||||
|
{
|
||||||
|
std::cout << "Exception here: frame number is out of range of keyframes. Frame: " << frame << std::endl;
|
||||||
|
throw std::runtime_error("Exception here");
|
||||||
|
}
|
||||||
|
|
||||||
|
int modifiedFrameNumber = frame - animations[0].keyFrames[startingKeyFrame].frame;
|
||||||
|
int diffFrames = animations[0].keyFrames[startingKeyFrame + 1].frame - animations[0].keyFrames[startingKeyFrame].frame;
|
||||||
|
float t = (modifiedFrameNumber + 0.f) / diffFrames;
|
||||||
|
|
||||||
|
std::vector<Bone>& oneFrameBones = animations[0].keyFrames[startingKeyFrame].bones;
|
||||||
|
std::vector<Bone>& nextFrameBones = animations[0].keyFrames[startingKeyFrame + 1].bones;
|
||||||
|
|
||||||
|
std::vector<Matrix4f> skinningMatrixForEachBone(currentBones.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < currentBones.size(); i++)
|
||||||
|
{
|
||||||
|
currentBones[i].boneStartWorld(0) = oneFrameBones[i].boneStartWorld(0) + t * (nextFrameBones[i].boneStartWorld(0) - oneFrameBones[i].boneStartWorld(0));
|
||||||
|
currentBones[i].boneStartWorld(1) = oneFrameBones[i].boneStartWorld(1) + t * (nextFrameBones[i].boneStartWorld(1) - oneFrameBones[i].boneStartWorld(1));
|
||||||
|
currentBones[i].boneStartWorld(2) = oneFrameBones[i].boneStartWorld(2) + t * (nextFrameBones[i].boneStartWorld(2) - oneFrameBones[i].boneStartWorld(2));
|
||||||
|
|
||||||
|
Matrix3f oneFrameBonesMatrix = oneFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0);
|
||||||
|
Matrix3f nextFrameBonesMatrix = nextFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0);
|
||||||
|
|
||||||
|
Eigen::Quaternionf q1 = Eigen::Quaternionf(oneFrameBonesMatrix).normalized();
|
||||||
|
Eigen::Quaternionf q2 = Eigen::Quaternionf(nextFrameBonesMatrix).normalized();
|
||||||
|
Eigen::Quaternionf result = q1.slerp(t, q2);
|
||||||
|
|
||||||
|
Matrix3f boneMatrixWorld3 = result.toRotationMatrix();
|
||||||
|
|
||||||
|
currentBones[i].boneMatrixWorld = Eigen::Matrix4f::Identity();
|
||||||
|
currentBones[i].boneMatrixWorld.block<3, 3>(0, 0) = boneMatrixWorld3;
|
||||||
|
currentBones[i].boneMatrixWorld.block<3, 1>(0, 3) = currentBones[i].boneStartWorld;
|
||||||
|
|
||||||
|
Matrix4f startBoneMatrixWorld4 = animations[0].keyFrames[0].bones[i].boneMatrixWorld;
|
||||||
|
skinningMatrixForEachBone[i] = currentBones[i].boneMatrixWorld * startBoneMatrixWorld4.inverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& name : meshNamesOrdered)
|
||||||
|
{
|
||||||
|
auto it = meshes.find(name);
|
||||||
|
if (it == meshes.end()) continue;
|
||||||
|
MeshBoneData& md = it->second;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < md.mesh.PositionData.size(); i++)
|
||||||
|
{
|
||||||
|
Vector4f originalPos = {
|
||||||
|
md.startMesh.PositionData[i](0),
|
||||||
|
md.startMesh.PositionData[i](1),
|
||||||
|
md.startMesh.PositionData[i](2), 1.0f };
|
||||||
|
|
||||||
|
Vector4f finalPos = Vector4f{ 0.f, 0.f, 0.f, 0.f };
|
||||||
|
bool vMoved = false;
|
||||||
|
|
||||||
|
for (int j = 0; j < MAX_BONE_COUNT; j++)
|
||||||
|
{
|
||||||
|
if (md.verticesBoneWeight[i][j].weight != 0)
|
||||||
|
{
|
||||||
|
if (md.verticesBoneWeight[i][j].boneIndex == -1)
|
||||||
|
{
|
||||||
|
std::cout << "Exception here: bone index is -1 but weight is > 0" << std::endl;
|
||||||
|
throw std::runtime_error("Bones loaded incorrectly - bone index is -1 but weight is > 0");
|
||||||
|
}
|
||||||
|
vMoved = true;
|
||||||
|
finalPos = finalPos + (skinningMatrixForEachBone[md.verticesBoneWeight[i][j].boneIndex] * originalPos) * md.verticesBoneWeight[i][j].weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vMoved) finalPos = originalPos;
|
||||||
|
|
||||||
|
md.mesh.PositionData[i](0) = finalPos(0);
|
||||||
|
md.mesh.PositionData[i](1) = finalPos(1);
|
||||||
|
md.mesh.PositionData[i](2) = finalPos(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshGpuSkinningData::prepareGpuSkinningVBOs(MeshBoneData& meshData)
|
||||||
|
{
|
||||||
|
if (gpuSkinningPrepared) return;
|
||||||
|
|
||||||
|
gpuBoneData.PrepareGpuSkinningData(meshData.verticesBoneWeight);
|
||||||
|
bindPoseMutable.AssignFrom(meshData.startMesh);
|
||||||
|
|
||||||
|
auto& gpu = gpuBoneData;
|
||||||
|
|
||||||
|
boneIndices0VBO = std::make_shared<VBOHolder>();
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneIndices0VBO->getBuffer());
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, gpu.boneIndices0.size() * sizeof(Eigen::Vector4f),
|
||||||
|
gpu.boneIndices0.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
boneIndices1VBO = std::make_shared<VBOHolder>();
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneIndices1VBO->getBuffer());
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, gpu.boneIndices1.size() * sizeof(Eigen::Vector2f),
|
||||||
|
gpu.boneIndices1.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
boneWeights0VBO = std::make_shared<VBOHolder>();
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneWeights0VBO->getBuffer());
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, gpu.boneWeights0.size() * sizeof(Eigen::Vector4f),
|
||||||
|
gpu.boneWeights0.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
boneWeights1VBO = std::make_shared<VBOHolder>();
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneWeights1VBO->getBuffer());
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, gpu.boneWeights1.size() * sizeof(Eigen::Vector2f),
|
||||||
|
gpu.boneWeights1.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
gpuSkinningPrepared = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshGpuSkinningData::RenderVBO(Renderer& renderer)
|
||||||
|
{
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, bindPoseMutable.positionVBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer3fv("vPosition", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
|
||||||
|
if (bindPoseMutable.texCoordVBO) {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, bindPoseMutable.texCoordVBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer2fv("vTexCoord", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bindPoseMutable.normalVBO) {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, bindPoseMutable.normalVBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer3fv("vNormal", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
} else {
|
||||||
|
renderer.DisableVertexAttribArray("vNormal");
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneIndices0VBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer4fv("aBoneIndices0", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneIndices1VBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer2fv("aBoneIndices1", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneWeights0VBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer4fv("aBoneWeights0", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneWeights1VBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer2fv("aBoneWeights1", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(bindPoseMutable.data.PositionData.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpuSkinningShaderDataNew::prepareGpuSkinningVBOs(BoneSystemNew& model)
|
||||||
|
{
|
||||||
|
for (const auto& name : model.meshNamesOrdered)
|
||||||
|
{
|
||||||
|
auto it = model.meshes.find(name);
|
||||||
|
if (it == model.meshes.end()) continue;
|
||||||
|
perMesh[name].prepareGpuSkinningVBOs(it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpuSkinningShaderDataNew::RenderVBO(Renderer& renderer, const std::vector<std::string>& meshNamesOrdered)
|
||||||
|
{
|
||||||
|
for (const auto& name : meshNamesOrdered)
|
||||||
|
{
|
||||||
|
auto it = perMesh.find(name);
|
||||||
|
if (it == perMesh.end()) continue;
|
||||||
|
it->second.RenderVBO(renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpuSkinningShaderDataNew::ComputeSkinningMatrices(const std::vector<Bone>& startBones, const std::vector<AnimationKeyFrame>& keyFrames, int frame)
|
||||||
|
{
|
||||||
|
int startingKeyFrame = -1;
|
||||||
|
for (size_t i = 0; i < keyFrames.size() - 1; i++)
|
||||||
|
{
|
||||||
|
int oldFrame = keyFrames[i].frame;
|
||||||
|
int nextFrame = keyFrames[i + 1].frame;
|
||||||
|
if (frame >= oldFrame && frame < nextFrame)
|
||||||
|
{
|
||||||
|
startingKeyFrame = static_cast<int>(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
skinningMatrices.resize(startBones.size());
|
||||||
|
|
||||||
|
if (startingKeyFrame == -1)
|
||||||
|
{
|
||||||
|
for (auto& m : skinningMatrices) m = Matrix4f::Identity();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int modifiedFrameNumber = frame - keyFrames[startingKeyFrame].frame;
|
||||||
|
int diffFrames = keyFrames[startingKeyFrame + 1].frame - keyFrames[startingKeyFrame].frame;
|
||||||
|
float t = (modifiedFrameNumber + 0.f) / diffFrames;
|
||||||
|
|
||||||
|
const std::vector<Bone>& oneFrameBones = keyFrames[startingKeyFrame].bones;
|
||||||
|
const std::vector<Bone>& nextFrameBones = keyFrames[startingKeyFrame + 1].bones;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < startBones.size(); i++)
|
||||||
|
{
|
||||||
|
Vector3f interpPos;
|
||||||
|
interpPos(0) = oneFrameBones[i].boneStartWorld(0) + t * (nextFrameBones[i].boneStartWorld(0) - oneFrameBones[i].boneStartWorld(0));
|
||||||
|
interpPos(1) = oneFrameBones[i].boneStartWorld(1) + t * (nextFrameBones[i].boneStartWorld(1) - oneFrameBones[i].boneStartWorld(1));
|
||||||
|
interpPos(2) = oneFrameBones[i].boneStartWorld(2) + t * (nextFrameBones[i].boneStartWorld(2) - oneFrameBones[i].boneStartWorld(2));
|
||||||
|
|
||||||
|
Matrix3f oneFrameBonesMatrix = oneFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0);
|
||||||
|
Matrix3f nextFrameBonesMatrix = nextFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0);
|
||||||
|
|
||||||
|
Eigen::Quaternionf q1 = Eigen::Quaternionf(oneFrameBonesMatrix).normalized();
|
||||||
|
Eigen::Quaternionf q2 = Eigen::Quaternionf(nextFrameBonesMatrix).normalized();
|
||||||
|
Eigen::Quaternionf result = q1.slerp(t, q2);
|
||||||
|
|
||||||
|
Matrix3f boneMatrixWorld3 = result.toRotationMatrix();
|
||||||
|
|
||||||
|
Matrix4f currentBoneMatrixWorld4 = Eigen::Matrix4f::Identity();
|
||||||
|
currentBoneMatrixWorld4.block<3, 3>(0, 0) = boneMatrixWorld3;
|
||||||
|
currentBoneMatrixWorld4.block<3, 1>(0, 3) = interpPos;
|
||||||
|
|
||||||
|
Matrix4f startBoneMatrixWorld4 = keyFrames[0].bones[i].boneMatrixWorld;
|
||||||
|
skinningMatrices[i] = currentBoneMatrixWorld4 * startBoneMatrixWorld4.inverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
66
src/BoneAnimatedModelNew.h
Normal file
66
src/BoneAnimatedModelNew.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "BoneAnimatedModel.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace ZL
|
||||||
|
{
|
||||||
|
struct MeshBoneData
|
||||||
|
{
|
||||||
|
VertexDataStruct mesh;
|
||||||
|
VertexDataStruct startMesh;
|
||||||
|
std::vector<std::array<BoneWeight, MAX_BONE_COUNT>> verticesBoneWeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoneSystemNew
|
||||||
|
{
|
||||||
|
std::unordered_map<std::string, MeshBoneData> meshes;
|
||||||
|
std::vector<std::string> meshNamesOrdered;
|
||||||
|
|
||||||
|
Matrix4f armatureMatrix;
|
||||||
|
|
||||||
|
std::vector<Bone> startBones;
|
||||||
|
std::vector<Bone> currentBones;
|
||||||
|
|
||||||
|
std::vector<Animation> animations;
|
||||||
|
int startingFrame = 0;
|
||||||
|
|
||||||
|
void LoadFromFile(const std::string& fileName, const std::string& ZIPFileName = "");
|
||||||
|
|
||||||
|
void Interpolate(int frame);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MeshGpuSkinningData
|
||||||
|
{
|
||||||
|
GpuBoneData gpuBoneData;
|
||||||
|
|
||||||
|
VertexRenderStruct bindPoseMutable;
|
||||||
|
std::shared_ptr<VBOHolder> boneIndices0VBO;
|
||||||
|
std::shared_ptr<VBOHolder> boneIndices1VBO;
|
||||||
|
std::shared_ptr<VBOHolder> boneWeights0VBO;
|
||||||
|
std::shared_ptr<VBOHolder> boneWeights1VBO;
|
||||||
|
bool gpuSkinningPrepared = false;
|
||||||
|
|
||||||
|
void prepareGpuSkinningVBOs(MeshBoneData& meshData);
|
||||||
|
void RenderVBO(Renderer& renderer);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GpuSkinningShaderDataNew
|
||||||
|
{
|
||||||
|
std::unordered_map<std::string, MeshGpuSkinningData> perMesh;
|
||||||
|
std::vector<Eigen::Matrix4f> skinningMatrices;
|
||||||
|
|
||||||
|
void prepareGpuSkinningVBOs(BoneSystemNew& model);
|
||||||
|
void RenderVBO(Renderer& renderer, const std::vector<std::string>& meshNamesOrdered);
|
||||||
|
void ComputeSkinningMatrices(const std::vector<Bone>& startBones, const std::vector<AnimationKeyFrame>& keyFrames, int frame);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoneAnimationDataNew
|
||||||
|
{
|
||||||
|
BoneSystemNew model;
|
||||||
|
float currentFrame = 0.f;
|
||||||
|
int lastFrame = -1;
|
||||||
|
int totalFrames = 1;
|
||||||
|
|
||||||
|
GpuSkinningShaderDataNew gpuSkinningShaderData;
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -18,14 +18,17 @@ void Character::loadAnimation(AnimationState state, const std::string& filename,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Character::loadBinaryAnimation(AnimationState state, const std::string& filename, const std::string& zipFile) {
|
void Character::loadBinaryAnimation(AnimationState state, const std::string& filename, const std::string& zipFile) {
|
||||||
auto& data = animations[state];
|
|
||||||
|
throw std::runtime_error("Not supported");
|
||||||
|
|
||||||
|
/*auto& data = animations[state];
|
||||||
data.model.LoadFromBinaryFile(filename, zipFile);
|
data.model.LoadFromBinaryFile(filename, zipFile);
|
||||||
if (!data.model.animations.empty() && !data.model.animations[0].keyFrames.empty()) {
|
if (!data.model.animations.empty() && !data.model.animations[0].keyFrames.empty()) {
|
||||||
data.totalFrames = data.model.animations[0].keyFrames.back().frame + 1;
|
data.totalFrames = data.model.animations[0].keyFrames.back().frame + 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
data.totalFrames = 1;
|
data.totalFrames = 1;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void Character::setTarget(const Eigen::Vector3f& target,
|
void Character::setTarget(const Eigen::Vector3f& target,
|
||||||
@ -272,7 +275,7 @@ void Character::draw(Renderer& renderer) {
|
|||||||
|
|
||||||
AnimationState drawState = resolveActiveState();
|
AnimationState drawState = resolveActiveState();
|
||||||
auto it = animations.find(drawState);
|
auto it = animations.find(drawState);
|
||||||
if (it == animations.end() || !texture) return;
|
if (it == animations.end() || texturePerMesh.empty()) return;
|
||||||
|
|
||||||
renderer.shaderManager.PushShader(defaultShaderName);
|
renderer.shaderManager.PushShader(defaultShaderName);
|
||||||
renderer.RenderUniform1i(textureUniformName, 0);
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
@ -288,10 +291,13 @@ void Character::draw(Renderer& renderer) {
|
|||||||
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
||||||
|
|
||||||
auto& anim = it->second;
|
auto& anim = it->second;
|
||||||
modelMutable.AssignFrom(anim.model.mesh);
|
|
||||||
modelMutable.RefreshVBO();
|
for (const auto& [meshName, texture] : texturePerMesh) {
|
||||||
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
modelMutableMap[meshName].AssignFrom(anim.model.meshes[meshName].mesh);
|
||||||
renderer.DrawVertexRenderStruct(modelMutable);
|
modelMutableMap[meshName].RefreshVBO();
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
||||||
|
renderer.DrawVertexRenderStruct(modelMutableMap[meshName]);
|
||||||
|
}
|
||||||
|
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
renderer.PopProjectionMatrix();
|
renderer.PopProjectionMatrix();
|
||||||
@ -301,7 +307,7 @@ void Character::draw(Renderer& renderer) {
|
|||||||
void Character::drawGpuSkinning(Renderer& renderer) {
|
void Character::drawGpuSkinning(Renderer& renderer) {
|
||||||
AnimationState drawState = resolveActiveState();
|
AnimationState drawState = resolveActiveState();
|
||||||
auto it = animations.find(drawState);
|
auto it = animations.find(drawState);
|
||||||
if (it == animations.end() || !texture)
|
if (it == animations.end() || texturePerMesh.empty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -338,19 +344,26 @@ void Character::drawGpuSkinning(Renderer& renderer) {
|
|||||||
static_cast<int>(anim.gpuSkinningShaderData.skinningMatrices.size()), false,
|
static_cast<int>(anim.gpuSkinningShaderData.skinningMatrices.size()), false,
|
||||||
anim.gpuSkinningShaderData.skinningMatrices[0].data());
|
anim.gpuSkinningShaderData.skinningMatrices[0].data());
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
for (const auto& meshName : anim.model.meshNamesOrdered) {
|
||||||
|
auto texIt = texturePerMesh.find(meshName);
|
||||||
|
if (texIt == texturePerMesh.end()) continue;
|
||||||
|
|
||||||
|
auto meshIt = anim.gpuSkinningShaderData.perMesh.find(meshName);
|
||||||
|
if (meshIt == anim.gpuSkinningShaderData.perMesh.end()) continue;
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texIt->second->getTexID());
|
||||||
|
|
||||||
// Bind VAO (desktop only)
|
|
||||||
#ifndef EMSCRIPTEN
|
#ifndef EMSCRIPTEN
|
||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
if (anim.gpuSkinningShaderData.bindPoseMutable.vao) {
|
if (meshIt->second.bindPoseMutable.vao) {
|
||||||
glBindVertexArray(anim.gpuSkinningShaderData.bindPoseMutable.vao->getBuffer());
|
glBindVertexArray(meshIt->second.bindPoseMutable.vao->getBuffer());
|
||||||
renderer.shaderManager.EnableVertexAttribArrays();
|
renderer.shaderManager.EnableVertexAttribArrays();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
anim.gpuSkinningShaderData.RenderVBO(renderer);
|
meshIt->second.RenderVBO(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
renderer.PopProjectionMatrix();
|
renderer.PopProjectionMatrix();
|
||||||
@ -396,6 +409,7 @@ void Character::drawShadowDepth(Renderer& renderer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Character::drawShadowDepthCpu(Renderer& renderer) {
|
void Character::drawShadowDepthCpu(Renderer& renderer) {
|
||||||
|
/*
|
||||||
AnimationState drawState = resolveActiveState();
|
AnimationState drawState = resolveActiveState();
|
||||||
auto it = animations.find(drawState);
|
auto it = animations.find(drawState);
|
||||||
if (it == animations.end()) return;
|
if (it == animations.end()) return;
|
||||||
@ -413,11 +427,14 @@ void Character::drawShadowDepthCpu(Renderer& renderer) {
|
|||||||
modelMutable.RefreshVBO();
|
modelMutable.RefreshVBO();
|
||||||
renderer.DrawVertexRenderStruct(modelMutable);
|
renderer.DrawVertexRenderStruct(modelMutable);
|
||||||
|
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();*/
|
||||||
|
std::cout << "CPU skinning shadow depth rendering is not implemented." << std::endl;
|
||||||
|
throw std::runtime_error("Not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Character::drawShadowDepthGpuSkinning(Renderer& renderer) {
|
void Character::drawShadowDepthGpuSkinning(Renderer& renderer) {
|
||||||
|
|
||||||
|
/*
|
||||||
CheckGlError(__FILE__, __LINE__);
|
CheckGlError(__FILE__, __LINE__);
|
||||||
AnimationState drawState = resolveActiveState();
|
AnimationState drawState = resolveActiveState();
|
||||||
auto it = animations.find(drawState);
|
auto it = animations.find(drawState);
|
||||||
@ -453,7 +470,9 @@ void Character::drawShadowDepthGpuSkinning(Renderer& renderer) {
|
|||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
CheckGlError(__FILE__, __LINE__);
|
CheckGlError(__FILE__, __LINE__);*/
|
||||||
|
std::cout << "CPU skinning shadow depth rendering is not implemented." << std::endl;
|
||||||
|
throw std::runtime_error("Not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== Main pass with shadows ====================
|
// ==================== Main pass with shadows ====================
|
||||||
@ -467,7 +486,7 @@ void Character::drawWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightF
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Character::drawCpuWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera) {
|
void Character::drawCpuWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera) {
|
||||||
AnimationState drawState = resolveActiveState();
|
/*AnimationState drawState = resolveActiveState();
|
||||||
auto it = animations.find(drawState);
|
auto it = animations.find(drawState);
|
||||||
if (it == animations.end() || !texture) return;
|
if (it == animations.end() || !texture) return;
|
||||||
|
|
||||||
@ -501,11 +520,13 @@ void Character::drawCpuWithShadow(Renderer& renderer, const Eigen::Matrix4f& lig
|
|||||||
|
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
renderer.PopProjectionMatrix();
|
renderer.PopProjectionMatrix();
|
||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();*/
|
||||||
|
std::cout << "CPU skinning shadow depth rendering is not implemented." << std::endl;
|
||||||
|
throw std::runtime_error("Not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Character::drawGpuSkinningWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera) {
|
void Character::drawGpuSkinningWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera) {
|
||||||
AnimationState drawState = resolveActiveState();
|
/*AnimationState drawState = resolveActiveState();
|
||||||
auto it = animations.find(drawState);
|
auto it = animations.find(drawState);
|
||||||
if (it == animations.end() || !texture) return;
|
if (it == animations.end() || !texture) return;
|
||||||
|
|
||||||
@ -559,7 +580,9 @@ void Character::drawGpuSkinningWithShadow(Renderer& renderer, const Eigen::Matri
|
|||||||
renderer.PopProjectionMatrix();
|
renderer.PopProjectionMatrix();
|
||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
CheckGlError(__FILE__, __LINE__);
|
CheckGlError(__FILE__, __LINE__);*/
|
||||||
|
std::cout << "CPU skinning shadow depth rendering is not implemented." << std::endl;
|
||||||
|
throw std::runtime_error("Not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "BoneAnimatedModel.h"
|
#include "BoneAnimatedModel.h"
|
||||||
|
|
||||||
|
#include "BoneAnimatedModelNew.h"
|
||||||
#include "render/Renderer.h"
|
#include "render/Renderer.h"
|
||||||
#include "render/TextureManager.h"
|
#include "render/TextureManager.h"
|
||||||
#include "items/Item.h"
|
#include "items/Item.h"
|
||||||
@ -30,8 +32,8 @@ public:
|
|||||||
void loadAnimation(AnimationState state, const std::string& filename, const std::string& zipFile = "");
|
void loadAnimation(AnimationState state, const std::string& filename, const std::string& zipFile = "");
|
||||||
void loadBinaryAnimation(AnimationState state, const std::string& filename, const std::string& zipFile = "");
|
void loadBinaryAnimation(AnimationState state, const std::string& filename, const std::string& zipFile = "");
|
||||||
|
|
||||||
void setTexture(std::shared_ptr<Texture> texture) {
|
void setTexture(const std::string& meshName, std::shared_ptr<Texture> texture) {
|
||||||
this->texture = texture;
|
texturePerMesh[meshName] = texture;
|
||||||
}
|
}
|
||||||
void update(int64_t deltaMs);
|
void update(int64_t deltaMs);
|
||||||
// onArrived is called once when the character reaches this target.
|
// onArrived is called once when the character reaches this target.
|
||||||
@ -78,9 +80,9 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::map<AnimationState, BoneAnimationData> animations;
|
std::map<AnimationState, BoneAnimationDataNew> animations;
|
||||||
VertexRenderStruct modelMutable;
|
std::map<std::string, VertexRenderStruct> modelMutableMap;
|
||||||
std::shared_ptr<Texture> texture;
|
std::map<std::string, std::shared_ptr<Texture>> texturePerMesh;
|
||||||
|
|
||||||
Eigen::Vector3f walkTarget = Eigen::Vector3f(0.f, 0.f, 0.f);
|
Eigen::Vector3f walkTarget = Eigen::Vector3f(0.f, 0.f, 0.f);
|
||||||
Eigen::Vector3f requestedWalkTarget = Eigen::Vector3f(0.f, 0.f, 0.f);
|
Eigen::Vector3f requestedWalkTarget = Eigen::Vector3f(0.f, 0.f, 0.f);
|
||||||
|
|||||||
313
src/Location.cpp
313
src/Location.cpp
@ -29,199 +29,58 @@ namespace ZL
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*void Location::setup()
|
|
||||||
{
|
|
||||||
roomTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/w/room005.png", CONST_ZIP_FILE));
|
|
||||||
roomMesh.data = LoadFromTextFile02("resources/w/room001.txt", CONST_ZIP_FILE);
|
|
||||||
roomMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
|
||||||
roomMesh.RefreshVBO();
|
|
||||||
|
|
||||||
carTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/e/car002.png", CONST_ZIP_FILE));
|
|
||||||
carMesh.data = LoadFromTextFile02("resources/e/car001.txt", CONST_ZIP_FILE);
|
|
||||||
//carMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
|
||||||
carMesh.RefreshVBO();
|
|
||||||
|
|
||||||
|
|
||||||
// Load static game objects
|
|
||||||
gameObjects = GameObjectLoader::loadAndCreateGameObjects("resources/config2/gameobjects.json", renderer, CONST_ZIP_FILE);
|
|
||||||
|
|
||||||
// Load interactive objects
|
|
||||||
interactiveObjects = GameObjectLoader::loadAndCreateInteractiveObjects("resources/config2/gameobjects.json", renderer, CONST_ZIP_FILE);
|
|
||||||
|
|
||||||
|
|
||||||
auto playerTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/gg/IMG_20260413_182354_992.png", CONST_ZIP_FILE));
|
|
||||||
|
|
||||||
player = std::make_unique<Character>();
|
|
||||||
|
|
||||||
player->loadBinaryAnimation(AnimationState::STAND, "resources/w/gg/gg_stand_idle001.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::WALK, "resources/w/gg/gg_walking001.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::STAND_TO_ACTION, "resources/w/gg/gg_stand_to_action002.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_ATTACK, "resources/w/gg/gg_action_attack001.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_IDLE, "resources/w/gg/gg_action_idle001.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_TO_STAND, "resources/w/gg/gg_action_to_stand001.anim", CONST_ZIP_FILE);
|
|
||||||
|
|
||||||
player->setTexture(playerTexture);
|
|
||||||
player->walkSpeed = 3.0f;
|
|
||||||
player->rotationSpeed = 8.0f;
|
|
||||||
|
|
||||||
player->modelScale = 1.f;
|
|
||||||
player->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
|
||||||
|
|
||||||
player->canAttack = true;
|
|
||||||
player->isPlayer = true;
|
|
||||||
std::cout << "Load resurces step 9" << std::endl;
|
|
||||||
|
|
||||||
// Load NPCs from JSON
|
|
||||||
npcs = GameObjectLoader::loadAndCreateNpcs("resources/config2/npcs.json", CONST_ZIP_FILE);
|
|
||||||
|
|
||||||
auto ghostTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/ghost_skin001.png", CONST_ZIP_FILE));
|
|
||||||
|
|
||||||
std::cout << "Load resurces step 11" << std::endl;
|
|
||||||
auto npc02 = std::make_unique<Character>();
|
|
||||||
|
|
||||||
npc02->loadBinaryAnimation(AnimationState::STAND, "resources/w/default_float001.anim", CONST_ZIP_FILE);
|
|
||||||
npc02->loadBinaryAnimation(AnimationState::WALK, "resources/w/default_float001.anim", CONST_ZIP_FILE);
|
|
||||||
npc02->loadBinaryAnimation(AnimationState::ACTION_IDLE, "resources/w/float_attack003_cut.anim", CONST_ZIP_FILE);
|
|
||||||
npc02->loadBinaryAnimation(AnimationState::ACTION_ATTACK, "resources/w/float_attack003.anim", CONST_ZIP_FILE);
|
|
||||||
npc02->loadBinaryAnimation(AnimationState::STAND_TO_ACTION, "resources/w/default_float001_cut.anim", CONST_ZIP_FILE);
|
|
||||||
npc02->loadBinaryAnimation(AnimationState::ACTION_TO_STAND, "resources/w/default_float001_cut.anim", CONST_ZIP_FILE);
|
|
||||||
npc02->setTexture(ghostTexture);
|
|
||||||
npc02->walkSpeed = 1.5f;
|
|
||||||
npc02->rotationSpeed = 8.0f;
|
|
||||||
npc02->modelScale = 0.01f;
|
|
||||||
//npc02->modelScale = 0.1f;
|
|
||||||
npc02->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
|
||||||
|
|
||||||
npc02->position = Eigen::Vector3f(0.f, 0.f, -20.f);
|
|
||||||
npc02->setTarget(npc02->position);
|
|
||||||
npc02->canAttack = true;
|
|
||||||
npc02->attackTarget = player.get();
|
|
||||||
|
|
||||||
npcs.push_back(std::move(npc02));
|
|
||||||
|
|
||||||
// Create shadow map (2048x2048, ortho size 40, near 0.1, far 100)
|
|
||||||
shadowMap = std::make_unique<ShadowMap>(2048, 40.0f, 0.1f, 100.0f);
|
|
||||||
shadowMap->setLightDirection(Eigen::Vector3f(-0.5f, -1.0f, -0.3f));
|
|
||||||
std::cout << "Shadow map initialized" << std::endl;
|
|
||||||
|
|
||||||
setupNavigation();
|
|
||||||
|
|
||||||
scriptEngine.init(this, &inventory);
|
|
||||||
|
|
||||||
|
|
||||||
dialogueSystem.init(renderer, CONST_ZIP_FILE);
|
|
||||||
dialogueSystem.loadDatabase("resources/dialogue/sample_dialogues.json");
|
|
||||||
/*dialogueSystem.addTriggerZone({
|
|
||||||
"ghost_room_trigger",
|
|
||||||
"test_line_dialogue",
|
|
||||||
Eigen::Vector3f(0.0f, 0.0f, -8.5f),
|
|
||||||
2.0f,
|
|
||||||
true,
|
|
||||||
false
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/*void Location::setup()
|
|
||||||
{
|
|
||||||
std::string roomTexPath;
|
|
||||||
std::string roomMeshPath;
|
|
||||||
std::string gameObjectsPath;
|
|
||||||
std::string interactiveObjectsPath;
|
|
||||||
std::string npcsPath;
|
|
||||||
|
|
||||||
if (locationId == "forest")
|
|
||||||
{
|
|
||||||
std::cout << "[LOCATION] Setting up FOREST location (using placeholder resources)" << std::endl;
|
|
||||||
roomTexPath = "resources/w/room005.png";
|
|
||||||
roomMeshPath = "resources/w/room001.txt";
|
|
||||||
gameObjectsPath = "resources/config2/gameobjects2.json";
|
|
||||||
interactiveObjectsPath = "resources/config2/gameobjects2.json";
|
|
||||||
npcsPath = "resources/config2/npcs2.json";
|
|
||||||
}
|
|
||||||
else // default
|
|
||||||
{
|
|
||||||
std::cout << "[LOCATION] Setting up DEFAULT location" << std::endl;
|
|
||||||
roomTexPath = "resources/w/room005.png";
|
|
||||||
roomMeshPath = "resources/w/room001.txt";
|
|
||||||
gameObjectsPath = "resources/config2/gameobjects.json";
|
|
||||||
interactiveObjectsPath = "resources/config2/gameobjects.json";
|
|
||||||
npcsPath = "resources/config2/npcs.json";
|
|
||||||
}
|
|
||||||
|
|
||||||
roomTexture = std::make_unique<Texture>(CreateTextureDataFromPng(roomTexPath.c_str(), CONST_ZIP_FILE));
|
|
||||||
roomMesh.data = LoadFromTextFile02(roomMeshPath.c_str(), CONST_ZIP_FILE);
|
|
||||||
roomMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
|
||||||
roomMesh.RefreshVBO();
|
|
||||||
|
|
||||||
carTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/e/car002.png", CONST_ZIP_FILE));
|
|
||||||
carMesh.data = LoadFromTextFile02("resources/e/car001.txt", CONST_ZIP_FILE);
|
|
||||||
carMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
|
||||||
carMesh.RefreshVBO();
|
|
||||||
|
|
||||||
carWheelTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/e/Wheel_base002.png", CONST_ZIP_FILE));
|
|
||||||
carWheelMesh.data = LoadFromTextFile02("resources/e/car_wheel001.txt", CONST_ZIP_FILE);
|
|
||||||
carWheelMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
|
||||||
carWheelMesh.RefreshVBO();
|
|
||||||
|
|
||||||
gameObjects = GameObjectLoader::loadAndCreateGameObjects(gameObjectsPath, renderer, CONST_ZIP_FILE);
|
|
||||||
|
|
||||||
interactiveObjects = GameObjectLoader::loadAndCreateInteractiveObjects(interactiveObjectsPath, renderer, CONST_ZIP_FILE);
|
|
||||||
|
|
||||||
auto playerTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/gg/IMG_20260413_182354_992.png", CONST_ZIP_FILE));
|
|
||||||
player = std::make_unique<Character>();
|
|
||||||
player->loadBinaryAnimation(AnimationState::STAND, "resources/w/gg/gg_stand_idle001.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::WALK, "resources/w/gg/gg_walking001.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::STAND_TO_ACTION, "resources/w/gg/gg_stand_to_action002.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_ATTACK, "resources/w/gg/gg_action_attack001.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_IDLE, "resources/w/gg/gg_action_idle001.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_TO_STAND, "resources/w/gg/gg_action_to_stand001.anim", CONST_ZIP_FILE);
|
|
||||||
player->setTexture(playerTexture);
|
|
||||||
player->walkSpeed = 3.0f;
|
|
||||||
player->rotationSpeed = 8.0f;
|
|
||||||
player->modelScale = 1.f;
|
|
||||||
player->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
|
||||||
player->canAttack = true;
|
|
||||||
player->isPlayer = true;
|
|
||||||
std::cout << "Load resources step 9" << std::endl;
|
|
||||||
|
|
||||||
npcs = GameObjectLoader::loadAndCreateNpcs(npcsPath, CONST_ZIP_FILE);
|
|
||||||
|
|
||||||
auto ghostTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/ghost_skin001.png", CONST_ZIP_FILE));
|
|
||||||
std::cout << "Load resources step 11" << std::endl;
|
|
||||||
auto npc02 = std::make_unique<Character>();
|
|
||||||
npc02->loadBinaryAnimation(AnimationState::STAND, "resources/w/default_float001.anim", CONST_ZIP_FILE);
|
|
||||||
npc02->loadBinaryAnimation(AnimationState::WALK, "resources/w/default_float001.anim", CONST_ZIP_FILE);
|
|
||||||
npc02->loadBinaryAnimation(AnimationState::ACTION_IDLE, "resources/w/float_attack003_cut.anim", CONST_ZIP_FILE);
|
|
||||||
npc02->loadBinaryAnimation(AnimationState::ACTION_ATTACK, "resources/w/float_attack003.anim", CONST_ZIP_FILE);
|
|
||||||
npc02->loadBinaryAnimation(AnimationState::STAND_TO_ACTION, "resources/w/default_float001_cut.anim", CONST_ZIP_FILE);
|
|
||||||
npc02->loadBinaryAnimation(AnimationState::ACTION_TO_STAND, "resources/w/default_float001_cut.anim", CONST_ZIP_FILE);
|
|
||||||
npc02->setTexture(ghostTexture);
|
|
||||||
npc02->walkSpeed = 1.5f;
|
|
||||||
npc02->rotationSpeed = 8.0f;
|
|
||||||
npc02->modelScale = 0.01f;
|
|
||||||
npc02->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
|
||||||
npc02->position = Eigen::Vector3f(0.f, 0.f, -20.f);
|
|
||||||
npc02->setTarget(npc02->position);
|
|
||||||
npc02->canAttack = true;
|
|
||||||
npc02->attackTarget = player.get();
|
|
||||||
npcs.push_back(std::move(npc02));
|
|
||||||
|
|
||||||
shadowMap = std::make_unique<ShadowMap>(2048, 40.0f, 0.1f, 100.0f);
|
|
||||||
shadowMap->setLightDirection(Eigen::Vector3f(-0.5f, -1.0f, -0.3f));
|
|
||||||
std::cout << "Shadow map initialized" << std::endl;
|
|
||||||
|
|
||||||
setupNavigation();
|
|
||||||
|
|
||||||
scriptEngine.init(this, &inventory);
|
|
||||||
|
|
||||||
dialogueSystem.init(renderer, CONST_ZIP_FILE);
|
|
||||||
dialogueSystem.loadDatabase("resources/dialogue/sample_dialogues.json");
|
|
||||||
}*/
|
|
||||||
|
|
||||||
void Location::setup()
|
void Location::setup()
|
||||||
{
|
{
|
||||||
|
auto playerTexture0 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/male_packed0_diffuse.png", CONST_ZIP_FILE));
|
||||||
|
auto playerTexture1 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/male_packed1_diffuse.png", CONST_ZIP_FILE));
|
||||||
|
auto playerTexture2 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/male_packed2_diffuse.png", CONST_ZIP_FILE));
|
||||||
|
|
||||||
|
player = std::make_unique<Character>();
|
||||||
|
player->loadAnimation(AnimationState::STAND, "resources/e/gg_stand_idle003.txt", CONST_ZIP_FILE);
|
||||||
|
player->loadAnimation(AnimationState::WALK, "resources/e/gg_stand_idle003.txt", CONST_ZIP_FILE);
|
||||||
|
player->setTexture("Body", playerTexture0);
|
||||||
|
player->setTexture("Bottoms", playerTexture1);
|
||||||
|
player->setTexture("Eyelashes", playerTexture0);
|
||||||
|
player->setTexture("Eyes", playerTexture0);
|
||||||
|
player->setTexture("Eyewear", playerTexture0);
|
||||||
|
player->setTexture("Gloves", playerTexture1);
|
||||||
|
player->setTexture("Hair", playerTexture0);
|
||||||
|
player->setTexture("Shoes", playerTexture1);
|
||||||
|
player->setTexture("Tops", playerTexture1);
|
||||||
|
player->walkSpeed = 3.0f;
|
||||||
|
player->rotationSpeed = 8.0f;
|
||||||
|
player->modelScale = 0.01f;
|
||||||
|
player->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
||||||
|
player->canAttack = true;
|
||||||
|
player->isPlayer = true;
|
||||||
|
|
||||||
|
|
||||||
|
auto girlfriendTexture0 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/female_packed0_diffuse.png", CONST_ZIP_FILE));
|
||||||
|
auto girlfriendTexture1 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/female_packed1_diffuse.png", CONST_ZIP_FILE));
|
||||||
|
auto girlfriendTexture2 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/female_packed2_diffuse.png", CONST_ZIP_FILE));
|
||||||
|
auto girlfriendTexture3 = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/female_packed3_diffuse.png", CONST_ZIP_FILE));
|
||||||
|
|
||||||
|
girlfriend = std::make_unique<Character>();
|
||||||
|
girlfriend->loadAnimation(AnimationState::STAND, "resources/e/woman_stand_idle003.txt", CONST_ZIP_FILE);
|
||||||
|
girlfriend->loadAnimation(AnimationState::WALK, "resources/e/woman_stand_idle003.txt", CONST_ZIP_FILE);
|
||||||
|
girlfriend->setTexture("Body", girlfriendTexture0);
|
||||||
|
girlfriend->setTexture("Bottoms", girlfriendTexture3);
|
||||||
|
girlfriend->setTexture("Eyelashes", girlfriendTexture0);
|
||||||
|
girlfriend->setTexture("Eyes", girlfriendTexture0);
|
||||||
|
girlfriend->setTexture("Hair", girlfriendTexture2);
|
||||||
|
girlfriend->setTexture("Shoes", girlfriendTexture1);
|
||||||
|
girlfriend->setTexture("Tops", girlfriendTexture2);
|
||||||
|
girlfriend->walkSpeed = 3.0f;
|
||||||
|
girlfriend->rotationSpeed = 8.0f;
|
||||||
|
girlfriend->modelScale = 0.01f;
|
||||||
|
girlfriend->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
||||||
|
girlfriend->position = Vector3f{ -10, -0, -10 };
|
||||||
|
girlfriend->setTarget(girlfriend->position);
|
||||||
|
|
||||||
|
|
||||||
|
//girlfriend->canAttack = true;
|
||||||
|
//player->isPlayer = true;
|
||||||
|
|
||||||
if (locationId == "forest")
|
if (locationId == "forest")
|
||||||
{
|
{
|
||||||
std::cout << "[LOCATION] Setting up FOREST location (custom models only)" << std::endl;
|
std::cout << "[LOCATION] Setting up FOREST location (custom models only)" << std::endl;
|
||||||
@ -263,21 +122,6 @@ void Location::setup()
|
|||||||
gameObjects["forest_model_" + std::to_string(i)] = std::move(obj);
|
gameObjects["forest_model_" + std::to_string(i)] = std::move(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto playerTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/gg/IMG_20260413_182354_992.png", CONST_ZIP_FILE));
|
|
||||||
player = std::make_unique<Character>();
|
|
||||||
player->loadBinaryAnimation(AnimationState::STAND, "resources/w/gg/gg_stand_idle001.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::WALK, "resources/w/gg/gg_walking001.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::STAND_TO_ACTION, "resources/w/gg/gg_stand_to_action002.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_ATTACK, "resources/w/gg/gg_action_attack001.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_IDLE, "resources/w/gg/gg_action_idle001.anim", CONST_ZIP_FILE);
|
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_TO_STAND, "resources/w/gg/gg_action_to_stand001.anim", CONST_ZIP_FILE);
|
|
||||||
player->setTexture(playerTexture);
|
|
||||||
player->walkSpeed = 3.0f;
|
|
||||||
player->rotationSpeed = 8.0f;
|
|
||||||
player->modelScale = 1.f;
|
|
||||||
player->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
|
||||||
player->canAttack = true;
|
|
||||||
player->isPlayer = true;
|
|
||||||
|
|
||||||
shadowMap = std::make_unique<ShadowMap>(2048, 40.0f, 0.1f, 100.0f);
|
shadowMap = std::make_unique<ShadowMap>(2048, 40.0f, 0.1f, 100.0f);
|
||||||
shadowMap->setLightDirection(Eigen::Vector3f(-0.5f, -1.0f, -0.3f));
|
shadowMap->setLightDirection(Eigen::Vector3f(-0.5f, -1.0f, -0.3f));
|
||||||
@ -307,23 +151,26 @@ void Location::setup()
|
|||||||
gameObjects = GameObjectLoader::loadAndCreateGameObjects(gameObjectsPath, renderer, CONST_ZIP_FILE);
|
gameObjects = GameObjectLoader::loadAndCreateGameObjects(gameObjectsPath, renderer, CONST_ZIP_FILE);
|
||||||
interactiveObjects = GameObjectLoader::loadAndCreateInteractiveObjects(interactiveObjectsPath, renderer, CONST_ZIP_FILE);
|
interactiveObjects = GameObjectLoader::loadAndCreateInteractiveObjects(interactiveObjectsPath, renderer, CONST_ZIP_FILE);
|
||||||
npcs = GameObjectLoader::loadAndCreateNpcs(npcsPath, CONST_ZIP_FILE);
|
npcs = GameObjectLoader::loadAndCreateNpcs(npcsPath, CONST_ZIP_FILE);
|
||||||
|
/*
|
||||||
auto playerTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/gg/IMG_20260413_182354_992.png", CONST_ZIP_FILE));
|
auto playerTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/gg/IMG_20260413_182354_992.png", CONST_ZIP_FILE));
|
||||||
player = std::make_unique<Character>();
|
player = std::make_unique<Character>();
|
||||||
player->loadBinaryAnimation(AnimationState::STAND, "resources/w/gg/gg_stand_idle001.anim", CONST_ZIP_FILE);
|
player->loadAnimation(AnimationState::STAND, "resources/e/woman_stand_idle003.txt", CONST_ZIP_FILE);
|
||||||
player->loadBinaryAnimation(AnimationState::WALK, "resources/w/gg/gg_walking001.anim", CONST_ZIP_FILE);
|
player->loadAnimation(AnimationState::WALK, "resources/e/woman_stand_idle003.txt", CONST_ZIP_FILE);
|
||||||
player->loadBinaryAnimation(AnimationState::STAND_TO_ACTION, "resources/w/gg/gg_stand_to_action002.anim", CONST_ZIP_FILE);
|
player->setTexture("Body", playerTexture1);
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_ATTACK, "resources/w/gg/gg_action_attack001.anim", CONST_ZIP_FILE);
|
player->setTexture("Bottoms", playerTexture4);
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_IDLE, "resources/w/gg/gg_action_idle001.anim", CONST_ZIP_FILE);
|
player->setTexture("Eyelashes", playerTexture1);
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_TO_STAND, "resources/w/gg/gg_action_to_stand001.anim", CONST_ZIP_FILE);
|
player->setTexture("Eyes", playerTexture1);
|
||||||
player->setTexture(playerTexture);
|
player->setTexture("Hair", playerTexture3);
|
||||||
|
player->setTexture("Shoes", playerTexture1);
|
||||||
|
player->setTexture("Tops", playerTexture3);
|
||||||
player->walkSpeed = 3.0f;
|
player->walkSpeed = 3.0f;
|
||||||
player->rotationSpeed = 8.0f;
|
player->rotationSpeed = 8.0f;
|
||||||
player->modelScale = 1.f;
|
player->modelScale = 0.01f;
|
||||||
player->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
player->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
||||||
player->canAttack = true;
|
player->canAttack = true;
|
||||||
player->isPlayer = true;
|
player->isPlayer = true;
|
||||||
|
*/
|
||||||
|
/*
|
||||||
auto ghostTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/ghost_skin001.png", CONST_ZIP_FILE));
|
auto ghostTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/ghost_skin001.png", CONST_ZIP_FILE));
|
||||||
auto npc02 = std::make_unique<Character>();
|
auto npc02 = std::make_unique<Character>();
|
||||||
npc02->loadBinaryAnimation(AnimationState::STAND, "resources/w/default_float001.anim", CONST_ZIP_FILE);
|
npc02->loadBinaryAnimation(AnimationState::STAND, "resources/w/default_float001.anim", CONST_ZIP_FILE);
|
||||||
@ -342,7 +189,7 @@ void Location::setup()
|
|||||||
npc02->canAttack = true;
|
npc02->canAttack = true;
|
||||||
npc02->attackTarget = player.get();
|
npc02->attackTarget = player.get();
|
||||||
npcs.push_back(std::move(npc02));
|
npcs.push_back(std::move(npc02));
|
||||||
|
*/
|
||||||
shadowMap = std::make_unique<ShadowMap>(2048, 40.0f, 0.1f, 100.0f);
|
shadowMap = std::make_unique<ShadowMap>(2048, 40.0f, 0.1f, 100.0f);
|
||||||
shadowMap->setLightDirection(Eigen::Vector3f(-0.5f, -1.0f, -0.3f));
|
shadowMap->setLightDirection(Eigen::Vector3f(-0.5f, -1.0f, -0.3f));
|
||||||
|
|
||||||
@ -362,6 +209,20 @@ void Location::setup()
|
|||||||
carWheelMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
carWheelMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||||
carWheelMesh.RefreshVBO();
|
carWheelMesh.RefreshVBO();
|
||||||
|
|
||||||
|
/*
|
||||||
|
auto girlfriendTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/e/female_packed0_diffuse.png", CONST_ZIP_FILE));
|
||||||
|
girlfriend = std::make_unique<Character>();
|
||||||
|
girlfriend->loadAnimation(AnimationState::STAND, "resources/e/woman_stand_idle001.txt", CONST_ZIP_FILE);
|
||||||
|
girlfriend->loadAnimation(AnimationState::WALK, "resources/e/woman_run001.txt", CONST_ZIP_FILE);
|
||||||
|
girlfriend->setTexture(girlfriendTexture);
|
||||||
|
girlfriend->walkSpeed = 3.0f;
|
||||||
|
girlfriend->rotationSpeed = 8.0f;
|
||||||
|
girlfriend->modelScale = 0.01f;
|
||||||
|
girlfriend->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
||||||
|
girlfriend->position = Vector3f{ -10, -0, -10 };
|
||||||
|
girlfriend->setTarget(girlfriend->position);*/
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Location::setupNavigation()
|
void Location::setupNavigation()
|
||||||
@ -592,6 +453,12 @@ void Location::setup()
|
|||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
|
|
||||||
if (player && !inCar) player->draw(renderer);
|
if (player && !inCar) player->draw(renderer);
|
||||||
|
|
||||||
|
if (girlfriend)
|
||||||
|
{
|
||||||
|
girlfriend->draw(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& npc : npcs) npc->draw(renderer);
|
for (auto& npc : npcs) npc->draw(renderer);
|
||||||
|
|
||||||
//#ifdef SHOW_PATH
|
//#ifdef SHOW_PATH
|
||||||
@ -665,6 +532,12 @@ void Location::setup()
|
|||||||
|
|
||||||
// Draw characters (they handle their own skinning shader switch internally)
|
// Draw characters (they handle their own skinning shader switch internally)
|
||||||
if (player) player->drawShadowDepth(renderer);
|
if (player) player->drawShadowDepth(renderer);
|
||||||
|
|
||||||
|
if (girlfriend)
|
||||||
|
{
|
||||||
|
girlfriend->drawShadowDepth(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& npc : npcs) npc->drawShadowDepth(renderer);
|
for (auto& npc : npcs) npc->drawShadowDepth(renderer);
|
||||||
|
|
||||||
renderer.PopMatrix(); // light view
|
renderer.PopMatrix(); // light view
|
||||||
@ -783,6 +656,12 @@ void Location::setup()
|
|||||||
player->update(delta);
|
player->update(delta);
|
||||||
dialogueSystem.update(static_cast<int>(delta), player->position);
|
dialogueSystem.update(static_cast<int>(delta), player->position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (girlfriend)
|
||||||
|
{
|
||||||
|
girlfriend->update(delta);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& npc : npcs) npc->update(delta);
|
for (auto& npc : npcs) npc->update(delta);
|
||||||
|
|
||||||
if (inCar) {
|
if (inCar) {
|
||||||
|
|||||||
@ -28,6 +28,8 @@ namespace ZL
|
|||||||
|
|
||||||
|
|
||||||
std::unique_ptr<Character> player;
|
std::unique_ptr<Character> player;
|
||||||
|
std::unique_ptr<Character> girlfriend;
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Character>> npcs;
|
std::vector<std::unique_ptr<Character>> npcs;
|
||||||
|
|
||||||
float cameraAzimuth = 0.0f;
|
float cameraAzimuth = 0.0f;
|
||||||
|
|||||||
@ -382,6 +382,7 @@ namespace ZL {
|
|||||||
const std::string& jsonPath,
|
const std::string& jsonPath,
|
||||||
const std::string& zipPath)
|
const std::string& zipPath)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
std::vector<std::unique_ptr<Character>> npcs;
|
std::vector<std::unique_ptr<Character>> npcs;
|
||||||
std::vector<NpcData> npcsData = loadNpcsFromJson(jsonPath, zipPath);
|
std::vector<NpcData> npcsData = loadNpcsFromJson(jsonPath, zipPath);
|
||||||
|
|
||||||
@ -474,7 +475,8 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Total NPCs loaded: " << npcs.size() << std::endl;
|
std::cout << "Total NPCs loaded: " << npcs.size() << std::endl;
|
||||||
return npcs;
|
return npcs;*/
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
Loading…
Reference in New Issue
Block a user