Working on optimization: GPU skinning and binary animations

This commit is contained in:
Vladislav Khorev committed 2026-04-15 16:39:33 +03:00
1 parent a589765b7e
commit f708843747
24 files changed
+890 -489525

No files matched your search

+259
View File
@@ -4,6 +4,7 @@
#include <fstream>
#include <iostream>
#include <sstream>
#include <cstring>
namespace ZL
{
@@ -588,6 +589,264 @@ namespace ZL
startMesh = mesh;
}
void BoneSystem::LoadFromBinaryFile(const std::string& fileName, const std::string& ZIPFileName)
{
std::vector<char> fileData;
if (!ZIPFileName.empty())
{
fileData = readFileFromZIP(fileName, ZIPFileName);
}
else
{
std::ifstream f(fileName, std::ios::binary | std::ios::ate);
if (!f.is_open()) throw std::runtime_error("Failed to open binary file: " + fileName);
std::streamsize fileSize = f.tellg();
f.seekg(0);
fileData.resize(static_cast<size_t>(fileSize));
f.read(fileData.data(), fileSize);
}
const char* ptr = fileData.data();
auto readRaw = [&](void* dst, size_t n) {
std::memcpy(dst, ptr, n);
ptr += n;
};
auto readUint32 = [&]() -> uint32_t { uint32_t v; readRaw(&v, 4); return v; };
auto readInt32 = [&]() -> int32_t { int32_t v; readRaw(&v, 4); return v; };
auto readFloat = [&]() -> float { float v; readRaw(&v, 4); return v; };
auto readVec3 = [&]() -> Vector3f { return Vector3f{readFloat(), readFloat(), readFloat()}; };
auto readVec2 = [&]() -> Vector2f { return Vector2f{readFloat(), readFloat()}; };
// Header
char magic[4];
readRaw(magic, 4);
if (std::memcmp(magic, "BSAF", 4) != 0)
throw std::runtime_error("Invalid binary animation file (bad magic)");
uint32_t version = readUint32();
if (version != 1)
throw std::runtime_error("Unsupported binary animation file version");
// ---- Bones ----
uint32_t numBones = readUint32();
std::vector<Bone> bones(numBones);
for (uint32_t i = 0; i < numBones; i++)
{
bones[i].boneStartWorld = readVec3();
bones[i].boneLength = readFloat();
// 3x3 matrix (row-major in file).
// Stored with stride-3 into Matrix4f to match the text loader.
float m[9];
for (int j = 0; j < 9; j++) m[j] = readFloat();
bones[i].boneMatrixWorld = Matrix4f::Zero();
for (int r = 0; r < 3; r++)
for (int c = 0; c < 3; c++)
bones[i].boneMatrixWorld.data()[r + c * 3] = m[r * 3 + c];
bones[i].parent = readInt32();
uint32_t numChildren = readUint32();
bones[i].children.resize(numChildren);
for (uint32_t j = 0; j < numChildren; j++)
bones[i].children[j] = readInt32();
}
startBones = bones;
currentBones = bones;
// ---- Vertices ----
uint32_t numVertices = readUint32();
std::vector<Vector3f> vertices(numVertices);
for (uint32_t i = 0; i < numVertices; i++)
vertices[i] = readVec3();
// ---- UV Coordinates ----
uint32_t numFaces = readUint32();
std::vector<std::array<Vector2f, 3>> uvCoords(numFaces);
for (uint32_t i = 0; i < numFaces; i++)
for (int j = 0; j < 3; j++)
uvCoords[i][j] = readVec2();
// ---- Normals (read but not currently used by mesh) ----
std::vector<Vector3f> normals(numVertices);
for (uint32_t i = 0; i < numVertices; i++)
normals[i] = readVec3();
// ---- Triangles ----
uint32_t numTriangles = readUint32();
std::vector<std::array<int, 3>> triangles(numTriangles);
for (uint32_t i = 0; i < numTriangles; i++)
triangles[i] = { readInt32(), readInt32(), readInt32() };
// ---- Vertex Weights ----
std::vector<std::array<BoneWeight, MAX_BONE_COUNT>> localVerticesBoneWeight(numVertices);
for (uint32_t i = 0; i < numVertices; i++)
{
uint32_t numGroups = readUint32();
float sumWeights = 0;
for (uint32_t j = 0; j < numGroups; j++)
{
int boneIdx = readInt32();
float weight = readFloat();
if (j < MAX_BONE_COUNT)
{
localVerticesBoneWeight[i][j].boneIndex = boneIdx;
localVerticesBoneWeight[i][j].weight = weight;
sumWeights += weight;
}
}
// Normalize weights
uint32_t cap = (numGroups < MAX_BONE_COUNT) ? numGroups : MAX_BONE_COUNT;
for (uint32_t j = 0; j < cap; j++)
localVerticesBoneWeight[i][j].weight /= sumWeights;
}
// ---- Animation Keyframes ----
uint32_t numKeyframes = readUint32();
animations.resize(1);
animations[0].keyFrames.resize(numKeyframes);
for (uint32_t i = 0; i < numKeyframes; i++)
{
animations[0].keyFrames[i].frame = readInt32();
animations[0].keyFrames[i].bones.resize(numBones);
for (uint32_t j = 0; j < numBones; j++)
{
animations[0].keyFrames[i].bones[j] = startBones[j];
animations[0].keyFrames[i].bones[j].boneStartWorld = readVec3();
// 4x4 matrix (row-major in file, stored with stride-4 into Matrix4f)
float m[16];
for (int k = 0; k < 16; k++) m[k] = readFloat();
for (int r = 0; r < 4; r++)
for (int c = 0; c < 4; c++)
animations[0].keyFrames[i].bones[j].boneMatrixWorld.data()[r + c * 4] = m[r * 4 + c];
}
}
// ---- Build per-triangle mesh (same expansion as text loader) ----
for (uint32_t i = 0; i < numTriangles; i++)
{
mesh.PositionData.push_back(vertices[triangles[i][0]]);
mesh.PositionData.push_back(vertices[triangles[i][1]]);
mesh.PositionData.push_back(vertices[triangles[i][2]]);
verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][0]]);
verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][1]]);
verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][2]]);
mesh.TexCoordData.push_back(uvCoords[i][0]);
mesh.TexCoordData.push_back(uvCoords[i][1]);
mesh.TexCoordData.push_back(uvCoords[i][2]);
}
startMesh = mesh;
}
void BoneSystem::PrepareGpuSkinningData()
{
size_t vertexCount = verticesBoneWeight.size();
gpuBoneData.boneIndices0.resize(vertexCount);
gpuBoneData.boneIndices1.resize(vertexCount);
gpuBoneData.boneWeights0.resize(vertexCount);
gpuBoneData.boneWeights1.resize(vertexCount);
for (size_t i = 0; i < vertexCount; i++)
{
gpuBoneData.boneIndices0[i] = Vector4f(
static_cast<float>(max(0, verticesBoneWeight[i][0].boneIndex)),
static_cast<float>(max(0, verticesBoneWeight[i][1].boneIndex)),
static_cast<float>(max(0, verticesBoneWeight[i][2].boneIndex)),
static_cast<float>(max(0, verticesBoneWeight[i][3].boneIndex))
);
gpuBoneData.boneIndices1[i] = Vector2f(
static_cast<float>(max(0, verticesBoneWeight[i][4].boneIndex)),
static_cast<float>(max(0, verticesBoneWeight[i][5].boneIndex))
);
gpuBoneData.boneWeights0[i] = Vector4f(
verticesBoneWeight[i][0].weight,
verticesBoneWeight[i][1].weight,
verticesBoneWeight[i][2].weight,
verticesBoneWeight[i][3].weight
);
gpuBoneData.boneWeights1[i] = Vector2f(
verticesBoneWeight[i][4].weight,
verticesBoneWeight[i][5].weight
);
}
gpuBoneData.prepared = true;
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 BoneSystem::ComputeSkinningMatrices(int frame, std::vector<Matrix4f>& outMatrices) const
{
int startingKeyFrame = -1;
for (size_t i = 0; i < 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 = static_cast<int>(i);
break;
}
}
if (startingKeyFrame == -1)
{
outMatrices.resize(startBones.size());
for (auto& m : outMatrices) m = Matrix4f::Identity();
return;
}
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;
const std::vector<Bone>& oneFrameBones = animations[0].keyFrames[startingKeyFrame].bones;
const std::vector<Bone>& nextFrameBones = animations[0].keyFrames[startingKeyFrame + 1].bones;
outMatrices.resize(startBones.size());
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 = animations[0].keyFrames[0].bones[i].boneMatrixWorld;
Matrix4f invertedStartBoneMatrixWorld4 = startBoneMatrixWorld4.inverse();
outMatrices[i] = currentBoneMatrixWorld4 * invertedStartBoneMatrixWorld4;
}
}
void BoneSystem::Interpolate(int frame)
{
int startingFrame = -1;
+18 -1
View File
@@ -6,6 +6,7 @@
namespace ZL
{
constexpr int MAX_BONE_COUNT = 6;
constexpr int MAX_GPU_BONES = 64;
struct Bone
{
Vector3f boneStartWorld;
@@ -35,12 +36,20 @@ namespace ZL
std::vector<AnimationKeyFrame> keyFrames;
};
struct GpuBoneData {
std::vector<Vector4f> boneIndices0; // bone indices 0-3 per vertex (as float)
std::vector<Vector2f> boneIndices1; // bone indices 4-5 per vertex
std::vector<Vector4f> boneWeights0; // bone weights 0-3 per vertex
std::vector<Vector2f> boneWeights1; // bone weights 4-5 per vertex
bool prepared = false;
};
struct BoneSystem
{
VertexDataStruct mesh;
VertexDataStruct startMesh;
std::vector<std::array<BoneWeight, MAX_BONE_COUNT>> verticesBoneWeight;
Matrix4f armatureMatrix;
std::vector<Bone> startBones;
@@ -49,9 +58,17 @@ namespace ZL
std::vector<Animation> animations;
int startingFrame = 0;
GpuBoneData gpuBoneData;
void LoadFromFile(const std::string& fileName, const std::string& ZIPFileName = "");
void LoadFromBinaryFile(const std::string& fileName, const std::string& ZIPFileName = "");
void Interpolate(int frame);
// GPU skinning: prepare per-vertex bone data for VBO upload
void PrepareGpuSkinningData();
// GPU skinning: compute skinning matrices without modifying the mesh
void ComputeSkinningMatrices(int frame, std::vector<Matrix4f>& outMatrices) const;
};
+137 -35
View File
@@ -1,6 +1,8 @@
#include "Character.h"
#include <cmath>
#include <iostream>
#include "GameConstants.h"
#include "Environment.h"
namespace ZL {
@@ -15,7 +17,16 @@ void Character::loadAnimation(AnimationState state, const std::string& filename,
data.totalFrames = 1;
}
}
void Character::loadBinaryAnimation(AnimationState state, const std::string& filename, const std::string& zipFile) {
auto& data = animations[state];
data.model.LoadFromBinaryFile(filename, zipFile);
if (!data.model.animations.empty() && !data.model.animations[0].keyFrames.empty()) {
data.totalFrames = data.model.animations[0].keyFrames.back().frame + 1;
}
else {
data.totalFrames = 1;
}
}
/*void Character::setTexture(std::shared_ptr<Texture> tex) {
texture = tex;
}*/
@@ -123,38 +134,6 @@ void Character::update(int64_t deltaMs) {
}
}
/*
if (isPlayer) //Player should decide only by himself
{
if (attackTarget != nullptr)
{
auto pos = attackTarget->position;
float distToTarget = (position - pos).norm();
if (distToTarget > 1.0)
{
setTarget(Eigen::Vector3f(pos.x(), 0.f, pos.z()));
}
else
{
if (battle_state != 1)
{
setTarget(position);
battle_state = 1;
//player->attack = 1;
}
}
}
else
{
if (battle_state != 0)
{
battle_state = 0;
attack = 0;
}
}
}*/
if (battle_state == 1)
{
if (currentState == AnimationState::STAND || currentState == AnimationState::WALK) {
@@ -226,17 +205,32 @@ void Character::update(int64_t deltaMs) {
if (static_cast<int>(anim.currentFrame) != anim.lastFrame) {
anim.model.Interpolate(static_cast<int>(anim.currentFrame));
if (useGpuSkinning) {
anim.model.ComputeSkinningMatrices(static_cast<int>(anim.currentFrame), anim.skinningMatrices);
} else {
anim.model.Interpolate(static_cast<int>(anim.currentFrame));
}
anim.lastFrame = static_cast<int>(anim.currentFrame);
}
}
void Character::draw(Renderer& renderer) {
//std::cout << "draw called for Character at position: " << position.transpose() << std::endl;
if (useGpuSkinning) {
drawGpuSkinning(renderer);
return;
}
AnimationState drawState = resolveActiveState();
auto it = animations.find(drawState);
if (it == animations.end() || !texture) return;
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
renderer.PushMatrix();
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
@@ -250,6 +244,114 @@ void Character::draw(Renderer& renderer) {
renderer.DrawVertexRenderStruct(anim.modelMutable);
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader();
}
void Character::prepareGpuSkinningVBOs(AnimationData& anim) {
if (anim.gpuSkinningPrepared) return;
anim.model.PrepareGpuSkinningData();
// Upload bind-pose mesh (static, done once)
anim.bindPoseMutable.AssignFrom(anim.model.startMesh);
auto& gpu = anim.model.gpuBoneData;
anim.boneIndices0VBO = std::make_shared<VBOHolder>();
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices0VBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, gpu.boneIndices0.size() * sizeof(Eigen::Vector4f),
gpu.boneIndices0.data(), GL_STATIC_DRAW);
anim.boneIndices1VBO = std::make_shared<VBOHolder>();
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices1VBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, gpu.boneIndices1.size() * sizeof(Eigen::Vector2f),
gpu.boneIndices1.data(), GL_STATIC_DRAW);
anim.boneWeights0VBO = std::make_shared<VBOHolder>();
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights0VBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, gpu.boneWeights0.size() * sizeof(Eigen::Vector4f),
gpu.boneWeights0.data(), GL_STATIC_DRAW);
anim.boneWeights1VBO = std::make_shared<VBOHolder>();
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights1VBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, gpu.boneWeights1.size() * sizeof(Eigen::Vector2f),
gpu.boneWeights1.data(), GL_STATIC_DRAW);
anim.gpuSkinningPrepared = true;
}
void Character::drawGpuSkinning(Renderer& renderer) {
AnimationState drawState = resolveActiveState();
auto it = animations.find(drawState);
if (it == animations.end() || !texture) return;
auto& anim = it->second;
prepareGpuSkinningVBOs(anim);
if (anim.skinningMatrices.empty()) return;
static const std::string skinningShaderName = "skinning";
static const std::string boneMatricesUniform = "uBoneMatrices[0]";
renderer.shaderManager.PushShader(skinningShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
renderer.PushMatrix();
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
renderer.ScaleMatrix(modelScale);
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
// Upload bone skinning matrices
renderer.RenderUniformMatrix4fvArray(boneMatricesUniform,
static_cast<int>(anim.skinningMatrices.size()), false,
anim.skinningMatrices[0].data());
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
// Bind VAO (desktop only)
#ifndef EMSCRIPTEN
#ifndef __ANDROID__
if (anim.bindPoseMutable.vao) {
glBindVertexArray(anim.bindPoseMutable.vao->getBuffer());
renderer.shaderManager.EnableVertexAttribArrays();
}
#endif
#endif
// Bind position and texcoord VBOs
glBindBuffer(GL_ARRAY_BUFFER, anim.bindPoseMutable.positionVBO->getBuffer());
renderer.VertexAttribPointer3fv("vPosition", 0, NULL);
if (anim.bindPoseMutable.texCoordVBO) {
glBindBuffer(GL_ARRAY_BUFFER, anim.bindPoseMutable.texCoordVBO->getBuffer());
renderer.VertexAttribPointer2fv("vTexCoord", 0, NULL);
}
// Bind bone index VBOs
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices0VBO->getBuffer());
renderer.VertexAttribPointer4fv("aBoneIndices0", 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices1VBO->getBuffer());
renderer.VertexAttribPointer2fv("aBoneIndices1", 0, NULL);
// Bind bone weight VBOs
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights0VBO->getBuffer());
renderer.VertexAttribPointer4fv("aBoneWeights0", 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights1VBO->getBuffer());
renderer.VertexAttribPointer2fv("aBoneWeights1", 0, NULL);
glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(anim.bindPoseMutable.data.PositionData.size()));
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader();
}
} // namespace ZL
+16
View File
@@ -23,6 +23,7 @@ enum class AnimationState {
class Character {
public:
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 setTexture(std::shared_ptr<Texture> texture);
void setTexture(std::shared_ptr<Texture> texture) {
this->texture = texture;
@@ -59,6 +60,7 @@ public:
bool canAttack = false;
Character* attackTarget = nullptr;
bool isPlayer = false;
bool useGpuSkinning = true;
private:
struct AnimationData {
@@ -67,6 +69,15 @@ private:
float currentFrame = 0.f;
int lastFrame = -1;
int totalFrames = 1;
// GPU skinning data (lazily initialized)
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;
std::vector<Eigen::Matrix4f> skinningMatrices;
};
std::map<AnimationState, AnimationData> animations;
@@ -81,6 +92,11 @@ private:
// Returns the animation state to actually play/draw, falling back to IDLE
// if the requested state has no loaded animation.
AnimationState resolveActiveState() const;
// GPU skinning: prepare per-animation VBOs (called lazily on first draw)
void prepareGpuSkinningVBOs(AnimationData& anim);
// GPU skinning: draw using shader-based skinning
void drawGpuSkinning(Renderer& renderer);
};
} // namespace ZL
+18 -1
View File
@@ -130,6 +130,7 @@ namespace ZL
renderer.shaderManager.AddShaderFromFiles("planetStone", "resources/shaders/planet_stone.vertex", "resources/shaders/planet_stone_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetLand", "resources/shaders/planet_land.vertex", "resources/shaders/planet_land_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("spark", "resources/shaders/spark.vertex", "resources/shaders/spark_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("skinning", "resources/shaders/skinning.vertex", "resources/shaders/default_web.fragment", CONST_ZIP_FILE);
#else
renderer.shaderManager.AddShaderFromFiles("env_sky", "resources/shaders/env_sky.vertex", "resources/shaders/env_sky_desktop.fragment", CONST_ZIP_FILE);
@@ -138,6 +139,7 @@ namespace ZL
renderer.shaderManager.AddShaderFromFiles("planetStone", "resources/shaders/planet_stone.vertex", "resources/shaders/planet_stone_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("planetLand", "resources/shaders/planet_land.vertex", "resources/shaders/planet_land_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("spark", "resources/shaders/spark.vertex", "resources/shaders/spark_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("skinning", "resources/shaders/skinning.vertex", "resources/shaders/default_desktop.fragment", CONST_ZIP_FILE);
#endif
std::cout << "Load resurces step 4" << std::endl;
@@ -158,12 +160,20 @@ namespace ZL
// Player (Viola)
player = std::make_unique<Character>();
/*
player->loadAnimation(AnimationState::STAND, "resources/w/gg/gg_stand_idle001.txt", CONST_ZIP_FILE);
player->loadAnimation(AnimationState::WALK, "resources/w/gg/gg_walking001.txt", CONST_ZIP_FILE);
player->loadAnimation(AnimationState::STAND_TO_ACTION, "resources/w/gg/gg_stand_to_action002.txt", CONST_ZIP_FILE);
player->loadAnimation(AnimationState::ACTION_ATTACK, "resources/w/gg/gg_action_attack001.txt", CONST_ZIP_FILE);
player->loadAnimation(AnimationState::ACTION_IDLE, "resources/w/gg/gg_action_idle001.txt", CONST_ZIP_FILE);
player->loadAnimation(AnimationState::ACTION_TO_STAND, "resources/w/gg/gg_action_to_stand001.txt", CONST_ZIP_FILE);
*/
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(violaTexture);
player->walkSpeed = 3.0f;
@@ -209,13 +219,20 @@ namespace ZL
std::cout << "Load resurces step 11" << std::endl;
auto npc02 = std::make_unique<Character>();
/*
npc02->loadAnimation(AnimationState::STAND, "resources/w/default_float001.txt", CONST_ZIP_FILE);
npc02->loadAnimation(AnimationState::WALK, "resources/w/default_float001.txt", CONST_ZIP_FILE);
npc02->loadAnimation(AnimationState::ACTION_IDLE, "resources/w/float_attack003_cut.txt", CONST_ZIP_FILE);
npc02->loadAnimation(AnimationState::ACTION_ATTACK, "resources/w/float_attack003.txt", CONST_ZIP_FILE);
npc02->loadAnimation(AnimationState::STAND_TO_ACTION, "resources/w/default_float001_cut.txt", CONST_ZIP_FILE);
npc02->loadAnimation(AnimationState::ACTION_TO_STAND, "resources/w/default_float001_cut.txt", CONST_ZIP_FILE);
*/
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->loadAnimation(AnimationState::STAND, "resources/w/float_attack003.txt", CONST_ZIP_FILE);
//npc02->loadAnimation(AnimationState::STAND, "resources/idleviola_uv010.txt", CONST_ZIP_FILE);
npc02->setTexture(ghostTexture);
+17 -2
View File
@@ -331,7 +331,14 @@ namespace ZL {
// Load animations
try {
npc->loadAnimation(AnimationState::STAND, npcData.animationIdlePath, zipPath);
if (npcData.animationIdlePath.substr(npcData.animationIdlePath.size() - 5) == ".anim")
{
npc->loadBinaryAnimation(AnimationState::STAND, npcData.animationIdlePath, zipPath);
}
else
{
npc->loadAnimation(AnimationState::STAND, npcData.animationIdlePath, zipPath);
}
std::cout << " Loaded IDLE animation: " << npcData.animationIdlePath << std::endl;
}
catch (const std::exception& e) {
@@ -340,7 +347,15 @@ namespace ZL {
}
try {
npc->loadAnimation(AnimationState::WALK, npcData.animationWalkPath, zipPath);
if (npcData.animationIdlePath.substr(npcData.animationIdlePath.size() - 5) == ".anim")
{
npc->loadBinaryAnimation(AnimationState::WALK, npcData.animationIdlePath, zipPath);
}
else
{
npc->loadAnimation(AnimationState::WALK, npcData.animationWalkPath, zipPath);
}
std::cout << " Loaded WALK animation: " << npcData.animationWalkPath << std::endl;
}
catch (const std::exception& e) {
+20 -1
View File
@@ -774,7 +774,7 @@ namespace ZL {
void Renderer::RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value)
{
auto shader = shaderManager.GetCurrentShader();
auto uniform = shader->uniformList.find(uniformName);
if (uniform != shader->uniformList.end())
@@ -783,6 +783,18 @@ namespace ZL {
}
}
void Renderer::RenderUniformMatrix4fvArray(const std::string& uniformName, int count, bool transpose, const float* value)
{
auto shader = shaderManager.GetCurrentShader();
auto uniform = shader->uniformList.find(uniformName);
if (uniform != shader->uniformList.end())
{
glUniformMatrix4fv(uniform->second, count, transpose, value);
}
}
void Renderer::RenderUniform3fv(const std::string& uniformName, const float* value)
{
auto shader = shaderManager.GetCurrentShader();
@@ -847,6 +859,13 @@ namespace ZL {
glVertexAttribPointer(shader->attribList[attribName], 3, GL_FLOAT, GL_FALSE, stride, pointer);
}
void Renderer::VertexAttribPointer4fv(const std::string& attribName, int stride, const char* pointer)
{
auto shader = shaderManager.GetCurrentShader();
if (shader->attribList.find(attribName) != shader->attribList.end())
glVertexAttribPointer(shader->attribList[attribName], 4, GL_FLOAT, GL_FALSE, stride, pointer);
}
void Renderer::DisableVertexAttribArray(const std::string& attribName)
{
auto shader = shaderManager.GetCurrentShader();
+3
View File
@@ -129,6 +129,7 @@ namespace ZL {
void RenderUniformMatrix3fv(const std::string& uniformName, bool transpose, const float* value);
void RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value);
void RenderUniformMatrix4fvArray(const std::string& uniformName, int count, bool transpose, const float* value);
void RenderUniform1i(const std::string& uniformName, const int value);
void RenderUniform3fv(const std::string& uniformName, const float* value);
void RenderUniform4fv(const std::string& uniformName, const float* value);
@@ -138,6 +139,8 @@ namespace ZL {
void VertexAttribPointer3fv(const std::string& attribName, int stride, const char* pointer);
void VertexAttribPointer4fv(const std::string& attribName, int stride, const char* pointer);
void DisableVertexAttribArray(const std::string& attribName);
void DrawVertexRenderStruct(const VertexRenderStruct& VertexRenderStruct);