pandemonium_engine/modules/creaturegodot/CreatureModule.cpp
2024-09-29 18:28:44 +02:00

1934 lines
58 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
* Creature Runtimes License
*
* Copyright (c) 2015, Kestrel Moon Studios
* All rights reserved.
*
* Preamble: This Agreement governs the relationship between Licensee and Kestrel Moon Studios(Hereinafter: Licensor).
* This Agreement sets the terms, rights, restrictions and obligations on using [Creature Runtimes] (hereinafter: The Software) created and owned by Licensor,
* as detailed herein:
* License Grant: Licensor hereby grants Licensee a Sublicensable, Non-assignable & non-transferable, Commercial, Royalty free,
* Including the rights to create but not distribute derivative works, Non-exclusive license, all with accordance with the terms set forth and
* other legal restrictions set forth in 3rd party software used while running Software.
* Limited: Licensee may use Software for the purpose of:
* Running Software on Licensees Website[s] and Server[s];
* Allowing 3rd Parties to run Software on Licensees Website[s] and Server[s];
* Publishing Softwares output to Licensee and 3rd Parties;
* Distribute verbatim copies of Softwares output (including compiled binaries);
* Modify Software to suit Licensees needs and specifications.
* Binary Restricted: Licensee may sublicense Software as a part of a larger work containing more than Software,
* distributed solely in Object or Binary form under a personal, non-sublicensable, limited license. Such redistribution shall be limited to unlimited codebases.
* Non Assignable & Non-Transferable: Licensee may not assign or transfer his rights and duties under this license.
* Commercial, Royalty Free: Licensee may use Software for any purpose, including paid-services, without any royalties
* Including the Right to Create Derivative Works: Licensee may create derivative works based on Software,
* including amending Softwares source code, modifying it, integrating it into a larger work or removing portions of Software,
* as long as no distribution of the derivative works is made
*
* THE RUNTIMES IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE RUNTIMES OR THE USE OR OTHER DEALINGS IN THE
* RUNTIMES.
*****************************************************************************/
#include "CreatureModule.h"
#include <algorithm>
template <typename T>
static T clipNum(const T& n, const T& lower, const T& upper) {
return std::max(lower, std::min(n, upper));
}
static JsonNode * GetJSONLevelNodeFromKey(JsonNode& json_obj,
const std::string& key)
{
JsonNode * ret_node = NULL;
if(std::string(json_obj.key) == key) {
ret_node = &json_obj;
}
else {
JsonNode * cur_node = &json_obj;
while(true) {
if(std::string(cur_node->key) == key) {
ret_node = cur_node;
break;
}
JsonNode * next_node = cur_node->next;
if(next_node == NULL) {
break;
}
cur_node = next_node;
}
}
return ret_node;
}
static JsonNode * GetJSONNodeFromKey(JsonNode& json_obj,
const std::string& key)
{
JsonNode * ret_node = NULL;
for(JsonIterator it = JsonBegin(json_obj.value);
it != JsonEnd(json_obj.value); ++it)
{
if( std::string((*it)->key) == key) {
ret_node = *it;
break;
}
}
return ret_node;
}
static std::vector<std::string> GetJSONKeysFromNode(JsonNode& json_obj)
{
std::vector<std::string> ret_keys;
for(JsonIterator it = JsonBegin(json_obj.value);
it != JsonEnd(json_obj.value); ++it)
{
ret_keys.push_back(std::string((*it)->key));
}
return ret_keys;
}
static std::vector<float> GetJSONNodeFloatArray(JsonNode& json_obj)
{
std::vector<float> ret_vals;
for(JsonIterator it = JsonBegin(json_obj.value);
it != JsonEnd(json_obj.value); ++it)
{
JsonNode * cur_node = *it;
ret_vals.push_back((float)cur_node->value.toNumber());
}
return ret_vals;
}
static std::vector<int> GetJSONNodeIntArray(JsonNode& json_obj)
{
std::vector<int> ret_vals;
for(JsonIterator it = JsonBegin(json_obj.value);
it != JsonEnd(json_obj.value); ++it)
{
JsonNode * cur_node = *it;
ret_vals.push_back((int)cur_node->value.toNumber());
}
return ret_vals;
}
static glm::float32 * ReadJSONPoints3D(JsonNode& json_obj,
const std::string& key,
int& num_pts)
{
std::vector<float> pts_array = GetJSONNodeFloatArray(*GetJSONNodeFromKey(json_obj, key));
num_pts = (int)pts_array.size() / 2; // Since we are storing them as x,y pairs
glm::float32 * ret_pts = new glm::float32[num_pts * 3];
int cur_index = 0;
for(size_t i = 0; i < pts_array.size(); i+=2)
{
ret_pts[cur_index] = pts_array[i];
ret_pts[cur_index + 1] = pts_array[i + 1];
ret_pts[cur_index + 2] = 0;
cur_index += 3;
}
return ret_pts;
}
static glm::float32 * ReadJSONPoints2D(JsonNode& json_obj,
const std::string& key,
int& num_pts)
{
std::vector<float> pts_array = GetJSONNodeFloatArray(*GetJSONNodeFromKey(json_obj, key));
glm::float32 * ret_pts = new glm::float32[pts_array.size()];
for(size_t i = 0; i < pts_array.size(); i++)
{
ret_pts[i] = pts_array[i];
}
num_pts = (int)pts_array.size() / 2; // Since we are storing them as x,y pairs
return ret_pts;
}
static std::vector<glm::vec2> ReadJSONPoints2DVector(JsonNode& json_obj,
const std::string& key)
{
std::vector<float> pts_array = GetJSONNodeFloatArray(*GetJSONNodeFromKey(json_obj, key));
std::vector<glm::vec2> ret_pts(pts_array.size() / 2);
int pt_index = 0;
for(size_t i = 0; i < pts_array.size(); i+=2)
{
ret_pts[pt_index].x = pts_array[i];
ret_pts[pt_index].y = pts_array[i + 1];
pt_index++;
}
return ret_pts;
}
static glm::uint32 * ReadJSONUints(JsonNode& json_obj,
const std::string& key,
int& num_ints)
{
std::vector<int> ints_array = GetJSONNodeIntArray(*GetJSONNodeFromKey(json_obj, key));
glm::uint32 * ret_pts = new glm::uint32[ints_array.size()];
for(size_t i = 0; i < ints_array.size(); i++)
{
ret_pts[i] = (glm::uint32)ints_array[i];
}
num_ints = (int)ints_array.size();
return ret_pts;
}
static glm::vec2 ReadJSONVec2(JsonNode& json_obj,
const std::string& key)
{
std::vector<float> read_array = GetJSONNodeFloatArray(*GetJSONNodeFromKey(json_obj, key));
return glm::vec2(read_array[0], read_array[1]);
}
static glm::vec4 ReadJSONVec4_2(JsonNode& json_obj,
const std::string& key)
{
std::vector<float> read_array = GetJSONNodeFloatArray(*GetJSONNodeFromKey(json_obj, key));
return glm::vec4(read_array[0], read_array[1], 0, 1.0f);
}
static glm::mat4 ReadJSONMat4(JsonNode& json_obj,
const std::string& key)
{
std::vector<float> read_array = GetJSONNodeFloatArray(*GetJSONNodeFromKey(json_obj, key));
float mat_vals[16];
for(int i = 0; i < 16; i++) {
mat_vals[i] = read_array[i];
}
return glm::make_mat4(mat_vals);
}
static std::vector<int> ReadIntArray(JsonNode& json_obj,
const std::string& key)
{
std::vector<int> read_array = GetJSONNodeIntArray(*GetJSONNodeFromKey(json_obj, key));;
std::vector<int> ret_array(read_array.size());
for(int i = 0; i < read_array.size(); i++)
{
ret_array[i] = read_array[i];
}
return ret_array;
}
static std::vector<float> ReadFloatArray(JsonNode& json_obj,
const std::string& key)
{
std::vector<float> read_array = GetJSONNodeFloatArray(*GetJSONNodeFromKey(json_obj, key));
std::vector<float> ret_array(read_array.size());
for(int i = 0; i < read_array.size(); i++)
{
ret_array[i] = read_array[i];
}
return ret_array;
}
static meshBone * CreateBones(JsonNode& json_obj,
const std::string& key)
{
meshBone * root_bone = NULL;
JsonNode * base_obj = GetJSONLevelNodeFromKey(json_obj, key);
std::map<int, std::pair<meshBone *, std::vector<int> > > bone_data;
std::set<int> child_set;
// layout bones
for (JsonIterator it = JsonBegin(base_obj->value);
it != JsonEnd(base_obj->value);
++it)
{
JsonNode * cur_node = *it;
std::string cur_name(cur_node->key);
int cur_id = (int)GetJSONNodeFromKey(*cur_node, "id")->value.toNumber();
glm::mat4 cur_parent_mat = ReadJSONMat4(*cur_node, "restParentMat");
glm::vec4 cur_local_rest_start_pt = ReadJSONVec4_2(*cur_node, "localRestStartPt");
glm::vec4 cur_local_rest_end_pt = ReadJSONVec4_2(*cur_node, "localRestEndPt");
std::vector<int> cur_children_ids = ReadIntArray(*cur_node, "children");
meshBone * new_bone = new meshBone(cur_name,
glm::vec4(0),
glm::vec4(0),
cur_parent_mat);
new_bone->getLocalRestStartPt() = cur_local_rest_start_pt;
new_bone->getLocalRestEndPt() = cur_local_rest_end_pt;
new_bone->calcRestData();
new_bone->setTagId(cur_id);
bone_data[cur_id] = std::make_pair(new_bone, cur_children_ids);
for(auto& cur_child_id : cur_children_ids) {
child_set.insert(cur_child_id);
}
}
// Find root
for(auto& cur_data : bone_data)
{
int cur_id = cur_data.first;
if(child_set.count(cur_id) <= 0) {
// not a child, so is root
root_bone = cur_data.second.first;
break;
}
}
// construct hierarchy
for(auto& cur_data : bone_data)
{
meshBone * cur_bone = cur_data.second.first;
const std::vector<int>& children_ids = cur_data.second.second;
for(auto& cur_child_id : children_ids)
{
meshBone * child_bone = bone_data[cur_child_id].first;
cur_bone->addChild(child_bone);
}
}
return root_bone;
}
static std::vector<meshRenderRegion *> CreateRegions(JsonNode& json_obj,
const std::string& key,
glm::uint32 * indices_in,
glm::float32 * rest_pts_in,
glm::float32 * uvs_in)
{
std::vector<meshRenderRegion *> ret_regions;
JsonNode * base_obj = GetJSONNodeFromKey(json_obj, key);
for (JsonIterator it = JsonBegin(base_obj->value);
it != JsonEnd(base_obj->value);
++it)
{
JsonNode * cur_node = *it;
std::string cur_name(cur_node->key);
int cur_id = (int)GetJSONNodeFromKey(*cur_node, "id")->value.toNumber();
int cur_start_pt_index = (int)GetJSONNodeFromKey(*cur_node, "start_pt_index")->value.toNumber();
int cur_end_pt_index = (int)GetJSONNodeFromKey(*cur_node, "end_pt_index")->value.toNumber();
int cur_start_index = (int)GetJSONNodeFromKey(*cur_node, "start_index")->value.toNumber();
int cur_end_index = (int)GetJSONNodeFromKey(*cur_node, "end_index")->value.toNumber();
meshRenderRegion * new_region = new meshRenderRegion(indices_in,
rest_pts_in,
uvs_in,
cur_start_pt_index,
cur_end_pt_index,
cur_start_index,
cur_end_index);
new_region->setName(cur_name);
new_region->setTagId(cur_id);
// Read in weights
std::unordered_map<std::string, std::vector<float> >& weight_map =
new_region->getWeights();
JsonNode * weight_obj = GetJSONNodeFromKey(*cur_node, "weights");
for (JsonIterator w_it = JsonBegin(weight_obj->value);
w_it != JsonEnd(weight_obj->value);
++w_it)
{
JsonNode * w_node = *w_it;
const std::string& key(w_node->key);
std::vector<float> values = ReadFloatArray(*weight_obj, key);
weight_map[key] = values;
}
ret_regions.push_back(new_region);
}
return ret_regions;
}
static std::pair<int, int> GetStartEndTimes(JsonNode& json_obj,
const std::string& key)
{
std::pair<int, int> ret_times(0,0);
bool first = true;
JsonNode * base_obj = GetJSONNodeFromKey(json_obj, key);
for (JsonIterator it = JsonBegin(base_obj->value);
it != JsonEnd(base_obj->value);
++it)
{
JsonNode * cur_node = *it;
int cur_val = atoi(cur_node->key);
if(first) {
ret_times.first = cur_val;
ret_times.second = cur_val;
first = false;
}
else {
if(cur_val > ret_times.second) {
ret_times.second = cur_val;
}
if(cur_val < ret_times.first) {
ret_times.first = cur_val;
}
}
}
return ret_times;
}
static void FillBoneCache(JsonNode& json_obj,
const std::string& key,
int start_time,
int end_time,
meshBoneCacheManager& cache_manager)
{
JsonNode * base_obj = GetJSONNodeFromKey(json_obj, key);
cache_manager.init(start_time, end_time);
int prev_time = start_time;
for (JsonIterator it = JsonBegin(base_obj->value);
it != JsonEnd(base_obj->value);
++it)
{
JsonNode * cur_node = *it;
int cur_time = atoi(cur_node->key);
std::vector<meshBoneCache> cache_list;
for (JsonIterator bone_it = JsonBegin(cur_node->value);
bone_it != JsonEnd(cur_node->value);
++bone_it)
{
JsonNode * bone_node = *bone_it;
std::string cur_name(bone_node->key);
glm::vec4 cur_start_pt = ReadJSONVec4_2(*bone_node, "start_pt");
glm::vec4 cur_end_pt = ReadJSONVec4_2(*bone_node, "end_pt");
meshBoneCache cache_data(cur_name);
cache_data.setWorldStartPt(cur_start_pt);
cache_data.setWorldEndPt(cur_end_pt);
cache_list.push_back(cache_data);
}
int set_index = cache_manager.getIndexByTime(cur_time);
cache_manager.getCacheTable()[set_index] = cache_list;
auto gap_diff = cur_time - prev_time;
if (gap_diff > 1)
{
auto ptInterp = [&](const glm::vec4& src_pt, const glm::vec4& target_pt, float fraction)
{
return ((1.0f - fraction ) * src_pt) + (fraction * target_pt);
};
// Gap Step
auto prev_index = cache_manager.getIndexByTime(prev_time);
for (int j = 1; j < gap_diff; j++)
{
auto gap_fraction = (float)j / (float)gap_diff;
std::vector<meshBoneCache> gap_cache_list;
gap_cache_list.reserve(cache_list.size());
for (size_t k = 0; k < cache_list.size(); k++)
{
auto& cur_data = cache_manager.getCacheTable()[set_index][k];
auto& prev_data = cache_manager.getCacheTable()[prev_index][k];
meshBoneCache gap_cache_data(cur_data.getKey());
gap_cache_data.setWorldStartPt(
ptInterp(prev_data.getWorldStartPt(), cur_data.getWorldStartPt(), gap_fraction));
gap_cache_data.setWorldEndPt(
ptInterp(prev_data.getWorldEndPt(), cur_data.getWorldEndPt(), gap_fraction));
gap_cache_list.push_back(gap_cache_data);
}
cache_manager.getCacheTable()[prev_index + j] = gap_cache_list;
}
}
prev_time = cur_time;
}
cache_manager.makeAllReady();
}
static void FillDeformationCache(JsonNode& json_obj,
const std::string& key,
int start_time,
int end_time,
meshDisplacementCacheManager& cache_manager)
{
JsonNode * base_obj = GetJSONNodeFromKey(json_obj, key);
cache_manager.init(start_time, end_time);
int prev_time = start_time;
for (JsonIterator it = JsonBegin(base_obj->value);
it != JsonEnd(base_obj->value);
++it)
{
JsonNode * cur_node = *it;
int cur_time = atoi(cur_node->key);
std::vector<meshDisplacementCache> cache_list;
for (JsonIterator mesh_it = JsonBegin(cur_node->value);
mesh_it != JsonEnd(cur_node->value);
++mesh_it)
{
JsonNode * mesh_node = *mesh_it;
std::string cur_name(mesh_node->key);
meshDisplacementCache cache_data(cur_name);
bool use_local_displacement = GetJSONNodeFromKey(*mesh_node, "use_local_displacements")->value.toBool();
bool use_post_displacement = GetJSONNodeFromKey(*mesh_node, "use_post_displacements")->value.toBool();
if(use_local_displacement) {
std::vector<glm::vec2> read_pts = ReadJSONPoints2DVector(*mesh_node, "local_displacements");
cache_data.setLocalDisplacements(read_pts);
}
if(use_post_displacement) {
std::vector<glm::vec2> read_pts = ReadJSONPoints2DVector(*mesh_node, "post_displacements");
cache_data.setPostDisplacements(read_pts);
}
cache_list.push_back(cache_data);
}
int set_index = cache_manager.getIndexByTime(cur_time);
cache_manager.getCacheTable()[set_index] = cache_list;
auto gap_diff = cur_time - prev_time;
if (gap_diff > 1)
{
auto ptsInterp = [&](const std::vector<glm::vec2> src_pts, const std::vector<glm::vec2> target_pts, float fraction)
{
std::vector<glm::vec2> ret_pts(src_pts.size());
for (size_t i = 0; i < src_pts.size(); i++)
{
ret_pts[i] = ((1.0f - fraction) * src_pts[i]) + (fraction * target_pts[i]);
}
return ret_pts;
};
// Gap Step
auto prev_index = cache_manager.getIndexByTime(prev_time);
for (int j = 1; j < gap_diff; j++)
{
auto gap_fraction = (float)j / (float)gap_diff;
std::vector<meshDisplacementCache> gap_cache_list;
gap_cache_list.reserve(cache_list.size());
for (size_t k = 0; k < cache_list.size(); k++)
{
auto& cur_data = cache_manager.getCacheTable()[set_index][k];
auto& prev_data = cache_manager.getCacheTable()[prev_index][k];
meshDisplacementCache gap_cache_data(cur_data.getKey());
if (!cur_data.getLocalDisplacements().empty())
{
gap_cache_data.setLocalDisplacements(
ptsInterp(prev_data.getLocalDisplacements(), cur_data.getLocalDisplacements(), gap_fraction));
}
else {
gap_cache_data.setPostDisplacements(
ptsInterp(prev_data.getPostDisplacements(), cur_data.getPostDisplacements(), gap_fraction));
}
gap_cache_list.push_back(gap_cache_data);
}
cache_manager.getCacheTable()[prev_index + j] = gap_cache_list;
}
}
prev_time = cur_time;
}
cache_manager.makeAllReady();
}
static void FillUVSwapCache(JsonNode& json_obj,
const std::string& key,
int start_time,
int end_time,
meshUVWarpCacheManager& cache_manager)
{
JsonNode * base_obj = GetJSONNodeFromKey(json_obj, key);
cache_manager.init(start_time, end_time);
for (JsonIterator it = JsonBegin(base_obj->value);
it != JsonEnd(base_obj->value);
++it)
{
JsonNode * cur_node = *it;
int cur_time = atoi(cur_node->key);
std::vector<meshUVWarpCache> cache_list;
for (JsonIterator uv_it = JsonBegin(cur_node->value);
uv_it != JsonEnd(cur_node->value);
++uv_it)
{
JsonNode * uv_node = *uv_it;
std::string cur_name(uv_node->key);
meshUVWarpCache cache_data(cur_name);
bool use_uv = GetJSONNodeFromKey(*uv_node, "enabled")->value.toBool();
cache_data.setEnabled(use_uv);
if(use_uv) {
glm::vec2 local_offset = ReadJSONVec2(*uv_node, "local_offset");
glm::vec2 global_offset = ReadJSONVec2(*uv_node, "global_offset");
glm::vec2 scale = ReadJSONVec2(*uv_node, "scale");
cache_data.setUvWarpLocalOffset(local_offset);
cache_data.setUvWarpGlobalOffset(global_offset);
cache_data.setUvWarpScale(scale);
}
cache_list.push_back(cache_data);
}
int set_index = cache_manager.getIndexByTime(cur_time);
cache_manager.getCacheTable()[set_index] = cache_list;
}
cache_manager.makeAllReady();
}
static void FillOpacityCache(JsonNode& json_obj,
const std::string& key,
int start_time,
int end_time,
meshOpacityCacheManager& cache_manager)
{
JsonNode * base_obj = GetJSONNodeFromKey(json_obj, key);
cache_manager.init(start_time, end_time);
if (base_obj == NULL)
{
return;
}
int prev_time = start_time;
for (JsonIterator it = JsonBegin(base_obj->value);
it != JsonEnd(base_obj->value);
++it)
{
JsonNode * cur_node = *it;
int cur_time = atoi(cur_node->key);
std::vector<meshOpacityCache> cache_list;
for (JsonIterator uv_it = JsonBegin(cur_node->value);
uv_it != JsonEnd(cur_node->value);
++uv_it)
{
JsonNode * opacity_node = *uv_it;
std::string cur_name(opacity_node->key);
meshOpacityCache cache_data(cur_name);
float cur_opacity = (float)GetJSONNodeFromKey(*opacity_node, "opacity")->value.toNumber();
cache_data.setOpacity(cur_opacity);
cache_list.push_back(cache_data);
}
int set_index = cache_manager.getIndexByTime(cur_time);
cache_manager.getCacheTable()[set_index] = cache_list;
auto gap_diff = cur_time - prev_time;
if (gap_diff > 1)
{
auto scalarInterp = [&](const float& src_val, const float& target_val, float fraction)
{
return ((1.0f - fraction) * src_val) + (fraction * target_val);
};
// Gap Step
auto prev_index = cache_manager.getIndexByTime(prev_time);
for (int j = 1; j < gap_diff; j++)
{
auto gap_fraction = (float)j / (float)gap_diff;
std::vector<meshOpacityCache> gap_cache_list;
gap_cache_list.reserve(cache_list.size());
for (size_t k = 0; k < cache_list.size(); k++)
{
auto& cur_data = cache_manager.getCacheTable()[set_index][k];
auto& prev_data = cache_manager.getCacheTable()[prev_index][k];
meshOpacityCache gap_cache_data(cur_data.getKey());
gap_cache_data.setOpacity(scalarInterp(prev_data.getOpacity(), cur_data.getOpacity(), gap_fraction));
gap_cache_list.push_back(gap_cache_data);
}
cache_manager.getCacheTable()[prev_index + j] = gap_cache_list;
}
}
prev_time = cur_time;
}
cache_manager.makeAllReady();
}
static std::map<std::string, std::vector<CreatureModule::CreatureUVSwapPacket> >
FillSwapUVPacketMap(JsonNode& json_obj)
{
std::map<std::string, std::vector<CreatureModule::CreatureUVSwapPacket> > ret_map;
for (JsonIterator it = JsonBegin(json_obj.value);
it != JsonEnd(json_obj.value);
++it)
{
JsonNode * cur_node = *it;
std::string cur_name(cur_node->key);
std::vector<CreatureModule::CreatureUVSwapPacket> cur_packets;
for (JsonIterator node_it = JsonBegin(cur_node->value);
node_it != JsonEnd(cur_node->value);
++node_it)
{
JsonNode * packet_node = *node_it;
CreatureModule::CreatureUVSwapPacket new_packet(ReadJSONVec2(*packet_node, "local_offset"),
ReadJSONVec2(*packet_node, "global_offset"),
ReadJSONVec2(*packet_node, "scale"),
(int)GetJSONNodeFromKey(*packet_node, "tag")->value.toNumber());
cur_packets.push_back(new_packet);
}
ret_map[cur_name] = cur_packets;
}
return ret_map;
}
static std::map<std::string, glm::vec2>
FillAnchorPointMap(JsonNode& json_obj)
{
auto anchor_data_node = GetJSONNodeFromKey(json_obj, "AnchorPoints");
std::map<std::string, glm::vec2> ret_map;
for (JsonIterator it = JsonBegin(anchor_data_node->value);
it != JsonEnd(anchor_data_node->value);
++it)
{
JsonNode * cur_node = *it;
glm::vec2 cur_pt = ReadJSONVec2(*cur_node, "point");
std::string cur_name(GetJSONNodeFromKey(*cur_node, "anim_clip_name")->value.toString());
ret_map[cur_name] = cur_pt;
}
return ret_map;
}
namespace CreatureModule {
// Load the json structure
void LoadCreatureJSONData(const std::string& filename_in,
CreatureLoadDataPacket& load_data)
{
std::ifstream read_file;
read_file.open(filename_in.c_str());
std::stringstream str_stream;
str_stream << read_file.rdbuf();
read_file.close();
LoadCreatureJSONDataFromString(str_stream.str(), load_data);
}
void LoadCreatureJSONDataFromString(const std::string& string_in,
CreatureLoadDataPacket& load_data)
{
char *endptr;
size_t source_size = string_in.size();
char *source_chars = new char[source_size+1];
source_chars[source_size]=0;
memcpy(source_chars,string_in.c_str(),source_size);
JsonParseStatus status = jsonParse(source_chars, &endptr, &load_data.base_node, load_data.allocator);
load_data.src_chars = source_chars;
if(status != JSON_PARSE_OK) {
std::cerr<<"LoadCreatureJSONData() - Error parsing JSON!"<<std::endl;
}
}
// Creature class
Creature::Creature(CreatureLoadDataPacket& load_data)
{
anchor_points_active = false;
LoadFromData(load_data);
}
Creature::~Creature()
{
delete global_pts;
delete global_indices;
delete global_uvs;
delete render_colours;
delete render_composition;
delete render_pts;
}
glm::uint32 *
Creature::GetGlobalIndices()
{
return global_indices;
}
glm::float32 *
Creature::GetGlobalPts()
{
return global_pts;
}
glm::float32 *
Creature::GetGlobalUvs()
{
return global_uvs;
}
glm::float32 *
Creature::GetRenderPts()
{
return render_pts;
}
glm::uint8 *
Creature::GetRenderColours()
{
return render_colours;
}
int
Creature::GetTotalNumPoints() const
{
return total_num_pts;
}
int
Creature::GetTotalNumIndices() const
{
return total_num_indices;
}
meshRenderBoneComposition *
Creature::GetRenderComposition()
{
return render_composition;
}
void
Creature::FillRenderColours(glm::uint8 r, glm::uint8 g, glm::uint8 b, glm::uint8 a)
{
for(int i = 0; i < total_num_pts; i++)
{
glm::uint8 * cur_colour = render_colours + (i * 4);
cur_colour[0] = r;
cur_colour[1] = g;
cur_colour[2] = b;
cur_colour[3] = a;
}
}
const std::vector<std::string>&
Creature::GetAnimationNames() const
{
return animation_names;
}
const std::map<std::string, std::vector<CreatureUVSwapPacket> >&
Creature::GetUvSwapPackets() const
{
return uv_swap_packets;
}
void
Creature::SetActiveItemSwap(const std::string& region_name, int swap_idx)
{
active_uv_swap_actions[region_name] = swap_idx;
}
void
Creature::RemoveActiveItemSwap(const std::string& region_name)
{
active_uv_swap_actions.erase(region_name);
}
std::map<std::string, int>&
Creature::GetActiveItemSwaps()
{
return active_uv_swap_actions;
}
void Creature::SetAnchorPointsActive(bool flag_in)
{
anchor_points_active = flag_in;
}
bool Creature::GetAnchorPointsActive() const
{
return anchor_points_active;
}
glm::vec2 Creature::GetAnchorPoint(const std::string & anim_clip_name_in) const
{
if (anchor_point_map.count(anim_clip_name_in) > 0)
{
return anchor_point_map.at(anim_clip_name_in);
}
return glm::vec2(0, 0);
}
void
Creature::LoadFromData(CreatureLoadDataPacket& load_data)
{
JsonNode * json_root = load_data.base_node.toNode();
// Load points and topology
JsonNode * json_mesh = GetJSONLevelNodeFromKey(*json_root, "mesh");
global_pts = ReadJSONPoints3D(*json_mesh, "points", total_num_pts);
global_indices = ReadJSONUints(*json_mesh,"indices", total_num_indices);
global_uvs = ReadJSONPoints2D(*json_mesh, "uvs", total_num_pts);
render_colours = new glm::uint8[total_num_pts * 4];
render_pts = new glm::float32[total_num_pts * 3];
FillRenderColours(255, 255, 255, 255);
// Load bones
meshBone * root_bone = CreateBones(*json_root, "skeleton");
// Load regions
std::vector<meshRenderRegion *> regions = CreateRegions(*json_mesh,
"regions",
global_indices,
global_pts,
global_uvs);
// Add into composition
render_composition = new meshRenderBoneComposition();
render_composition->setRootBone(root_bone);
render_composition->getRootBone()->computeRestParentTransforms();
for(auto& cur_region : regions) {
cur_region->setMainBoneKey(root_bone->getKey());
cur_region->determineMainBone(root_bone);
render_composition->addRegion(cur_region);
}
render_composition->initBoneMap();
render_composition->initRegionsMap();
for(auto& cur_region : regions) {
cur_region->initFastNormalWeightMap(render_composition->getBonesMap());
}
render_composition->resetToWorldRestPts();
// Fill up available animation names
JsonNode * json_anim_base = GetJSONLevelNodeFromKey(*json_root, "animation");
animation_names = GetJSONKeysFromNode(*json_anim_base);
// Fill up uv swap packets
JsonNode * json_uv_swap_base = GetJSONLevelNodeFromKey(*json_root, "uv_swap_items");
if (json_uv_swap_base)
{
uv_swap_packets = FillSwapUVPacketMap(*json_uv_swap_base);
}
// Load Anchor Points
JsonNode * anchor_point_base = GetJSONLevelNodeFromKey(*json_root, "anchor_points_items");
if (anchor_point_base)
{
anchor_point_map = FillAnchorPointMap(*anchor_point_base);
}
}
// CreatureAnimation class
CreatureAnimation::CreatureAnimation(CreatureLoadDataPacket& load_data,
const std::string& name_in)
: name(name_in)
{
LoadFromData(name_in, load_data);
}
CreatureAnimation::~CreatureAnimation()
{
if(!cache_pts.empty())
{
for(auto pt_pool : cache_pts)
{
delete [] pt_pool;
}
}
}
float CreatureAnimation::getStartTime() const
{
return start_time;
}
float CreatureAnimation::getEndTime() const
{
return end_time;
}
void CreatureAnimation::setStartTime(int value_in)
{
start_time = (float)value_in;
}
void CreatureAnimation::setEndTime(int value_in)
{
end_time = (float)value_in;
}
meshBoneCacheManager&
CreatureAnimation::getBonesCache()
{
return bones_cache;
}
meshDisplacementCacheManager&
CreatureAnimation::getDisplacementCache()
{
return displacement_cache;
}
meshUVWarpCacheManager&
CreatureAnimation::getUVWarpCache()
{
return uv_warp_cache;
}
meshOpacityCacheManager&
CreatureAnimation::getOpacityCache()
{
return opacity_cache;
}
const std::string&
CreatureAnimation::getName() const
{
return name;
}
void
CreatureAnimation::LoadFromData(const std::string& name_in,
CreatureLoadDataPacket& load_data)
{
JsonNode * json_root = load_data.base_node.toNode();
JsonNode * json_anim_base = GetJSONLevelNodeFromKey(*json_root, "animation");
JsonNode * json_clip = GetJSONNodeFromKey(*json_anim_base, name_in);
std::pair<int, int> start_end_times = GetStartEndTimes(*json_clip, "bones");
start_time = (float)start_end_times.first;
end_time = (float)start_end_times.second;
// bone animation
FillBoneCache(*json_clip,
"bones",
(int)start_time,
(int)end_time,
bones_cache);
// mesh deformation animation
FillDeformationCache(*json_clip,
"meshes",
(int)start_time,
(int)end_time,
displacement_cache);
// uv swapping animation
FillUVSwapCache(*json_clip,
"uv_swaps",
(int)start_time,
(int)end_time,
uv_warp_cache);
// opacity animation
FillOpacityCache(*json_clip,
"mesh_opacities",
(int)start_time,
(int)end_time,
opacity_cache);
}
bool
CreatureAnimation::hasCachePts() const
{
return !cache_pts.empty();
}
std::vector<glm::float32 *>&
CreatureAnimation::getCachePts()
{
return cache_pts;
}
void
CreatureAnimation::clearCachePts()
{
for (size_t i = 0; i < cache_pts.size(); i++)
{
delete[] cache_pts[i];
}
cache_pts.clear();
}
int
CreatureAnimation::getIndexByTime(int time_in) const
{
int retval = time_in - (int)start_time;
retval = clipNum(retval, 0, (int)cache_pts.size() - 1);
return retval;
}
void
CreatureAnimation::poseFromCachePts(float time_in, glm::float32 * target_pts, int num_pts)
{
int cur_floor_time = getIndexByTime((int)floorf(time_in));
int cur_ceil_time = getIndexByTime((int)ceilf(time_in));
float cur_ratio = (time_in - (float)floorf(time_in));
glm::float32 * set_pt = target_pts;
glm::float32 * floor_pts = cache_pts[cur_floor_time];
glm::float32 * ceil_pts = cache_pts[cur_ceil_time];
for(int i = 0; i < num_pts; i++)
{
set_pt[0] = ((1.0f - cur_ratio) * floor_pts[0]) + (cur_ratio * ceil_pts[0]);
set_pt[1] = ((1.0f - cur_ratio) * floor_pts[1]) + (cur_ratio * ceil_pts[1]);
set_pt[2] = ((1.0f - cur_ratio) * floor_pts[2]) + (cur_ratio * ceil_pts[2]);
set_pt += 3;
floor_pts += 3;
ceil_pts += 3;
}
}
// CreatureManager class
CreatureManager::CreatureManager(std::shared_ptr<CreatureModule::Creature> target_creature_in)
: target_creature(target_creature_in), is_playing(false), run_time(0), time_scale(30.0),
do_blending(false),
blending_factor(0), mirror_y(false), use_custom_time_range(false),
custom_start_time(0), custom_end_time(0), should_loop(true),
do_auto_blending(false), auto_blend_delta(0.1f), do_point_caching(false)
{
for(int i = 0; i < 2; i++) {
blend_render_pts[i] = NULL;
}
}
CreatureManager::~CreatureManager()
{
for(int i = 0; i < 2; i++) {
if(blend_render_pts[i] != NULL) {
delete blend_render_pts[i];
}
}
}
void
CreatureManager::AddAnimation(std::shared_ptr<CreatureModule::CreatureAnimation> animation_in)
{
animations[animation_in->getName()] = animation_in;
active_blend_run_times[animation_in->getName()] = animation_in->getStartTime();
}
void
CreatureManager::CreateAnimation(CreatureLoadDataPacket& load_data,
const std::string& name_in)
{
auto new_animation = std::shared_ptr<CreatureModule::CreatureAnimation>(new CreatureAnimation(load_data,
name_in));
AddAnimation(new_animation);
}
CreatureModule::CreatureAnimation *
CreatureManager::GetAnimation(const std::string name_in)
{
if(animations.count(name_in) > 0) {
return animations[name_in].get();
}
return NULL;
}
CreatureModule::Creature *
CreatureManager::GetCreature()
{
return target_creature.get();
}
void
CreatureManager::SetActiveAnimationName(const std::string& name_in, bool check_already_active)
{
if(check_already_active)
{
if(active_animation_name == name_in)
{
// animation clip already set to this name, so just return
return;
}
}
if(animations.count(name_in) > 0) {
active_animation_name = name_in;
auto& cur_animation = animations[active_animation_name];
run_time = cur_animation->getStartTime();
UpdateRegionSwitches(name_in);
}
}
void
CreatureManager::UpdateRegionSwitches(const std::string& animation_name_in)
{
if (animations.count(animation_name_in) > 0) {
auto& cur_animation = animations[animation_name_in];
auto& displacement_cache_manager = cur_animation->getDisplacementCache();
std::vector<meshDisplacementCache>& displacement_table =
displacement_cache_manager.getCacheTable()[0];
auto& uv_warp_cache_manager = cur_animation->getUVWarpCache();
std::vector<meshUVWarpCache>& uv_swap_table =
uv_warp_cache_manager.getCacheTable()[0];
meshRenderBoneComposition * render_composition =
target_creature->GetRenderComposition();
std::vector<meshRenderRegion *>& all_regions = render_composition->getRegions();
int index = 0;
for (auto& cur_region : all_regions) {
// Setup active or inactive displacements
bool use_local_displacements = !displacement_table[index].getLocalDisplacements().empty();
bool use_post_displacements = !displacement_table[index].getPostDisplacements().empty();
cur_region->setUseLocalDisplacements(use_local_displacements);
cur_region->setUsePostDisplacements(use_post_displacements);
// Setup active or inactive uv swaps
cur_region->setUseUvWarp(uv_swap_table[index].getEnabled());
index++;
}
}
}
const std::string&
CreatureManager::GetActiveAnimationName() const
{
return active_animation_name;
}
std::unordered_map<std::string, std::shared_ptr<CreatureModule::CreatureAnimation> >&
CreatureManager::GetAllAnimations()
{
return animations;
}
bool
CreatureManager::GetIsPlaying() const
{
return is_playing;
}
void
CreatureManager::SetIsPlaying(bool flag_in)
{
is_playing = flag_in;
}
void
CreatureManager::SetTimeScale(float scale_in)
{
time_scale = scale_in;
}
void
CreatureManager::SetBlending(bool flag_in)
{
do_blending = flag_in;
if(do_blending) {
if(blend_render_pts[0] == NULL) {
blend_render_pts[0] = new glm::float32[target_creature->GetTotalNumPoints() * 3];
}
if(blend_render_pts[1] == NULL) {
blend_render_pts[1] = new glm::float32[target_creature->GetTotalNumPoints() * 3];
}
}
}
void
CreatureManager::SetBlendingAnimations(const std::string& name_1, const std::string& name_2)
{
active_blend_animation_names[0] = name_1;
active_blend_animation_names[1] = name_2;
}
void
CreatureManager::SetAutoBlending(bool flag_in)
{
do_auto_blending = flag_in;
SetBlending(flag_in);
if(do_auto_blending)
{
AutoBlendTo(active_animation_name, 0.1f);
}
}
void
CreatureManager::AutoBlendTo(const std::string& animation_name_in, float blend_delta)
{
if(animation_name_in == auto_blend_names[1])
{
// already blending to that so just return
return;
}
ResetBlendTime(animation_name_in);
auto_blend_delta = blend_delta;
auto_blend_names[0] = active_animation_name;
auto_blend_names[1] = animation_name_in;
blending_factor = 0;
active_animation_name = animation_name_in;
SetBlendingAnimations(auto_blend_names[0], auto_blend_names[1]);
}
void CreatureManager::SetDoPointCache(bool flag_in)
{
do_point_caching = flag_in;
}
bool CreatureManager::GetDoPointCache() const
{
return do_point_caching;
}
void
CreatureManager::ResetBlendTime(const std::string& name_in)
{
auto& cur_animation = animations[name_in];
active_blend_run_times[name_in] = cur_animation->getStartTime();
}
void
CreatureManager::ResetToStartTimes()
{
if(animations.count(active_animation_name) <= 0)
{
return;
}
// reset non blend time
auto& cur_animation = animations[active_animation_name];
run_time = cur_animation->getStartTime();
// reset blend times too
for (auto& blend_time_data : active_blend_run_times)
{
ResetBlendTime(blend_time_data.first);
}
}
void
CreatureManager::SetBlendingFactor(float value_in)
{
blending_factor = value_in;
}
void
CreatureManager::ClearPointCache(const std::string& animation_name_in)
{
if (animations.count(animation_name_in) == 0)
{
return;
}
auto cur_animation = animations[animation_name_in];
if (cur_animation->hasCachePts())
{
cur_animation->clearCachePts();
}
}
void
CreatureManager::MakePointCache(const std::string& animation_name_in, int gap_step)
{
if (animations.count(animation_name_in) == 0)
{
return;
}
if (gap_step < 1) {
gap_step = 1;
}
float store_run_time = getRunTime();
auto cur_animation = animations[animation_name_in];
if(cur_animation->hasCachePts())
{
// cache already generated, just exit
return;
}
std::vector<glm::float32 *>& cache_pts_list = cur_animation->getCachePts();
int array_size = target_creature->GetTotalNumPoints() * 3;
UpdateRegionSwitches(animation_name_in);
//for(int i = (int)cur_animation->getStartTime(); i <= (int)cur_animation->getEndTime(); i++)
int i = (int)cur_animation->getStartTime();
while (true)
{
run_time = (float)i;
auto new_pts = new glm::float32[array_size];
PoseCreature(animation_name_in, new_pts, getRunTime());
int real_step = gap_step;
if (i + real_step > cur_animation->getEndTime())
{
real_step = (int)cur_animation->getEndTime() - i;
}
bool firstCase = real_step > 1;
bool secondCase = cache_pts_list.size() >= 1;
if (firstCase && secondCase)
{
// fill in the gaps
glm::float32 * prev_pts = cache_pts_list[cache_pts_list.size() - 1];
for (int j = 0; j < real_step; j++)
{
float factor = (float)j / (float)real_step;
glm::float32 * gap_pts = interpFloatArray(prev_pts, new_pts, factor, array_size);
cache_pts_list.push_back(gap_pts);
}
}
cache_pts_list.push_back(new_pts);
i += real_step;
if (i > cur_animation->getEndTime() || real_step == 0)
{
break;
}
}
setRunTime(store_run_time);
}
glm::float32 *
CreatureManager::interpFloatArray(glm::float32 * first_list, glm::float32 * second_list, float factor, int array_size)
{
glm::float32 * ret_array = new glm::float32[array_size];
for (int i = 0; i < array_size; i++)
{
float new_val = ((1.0f - factor) * first_list[i]) + (factor * second_list[i]);
ret_array[i] = new_val;
}
return ret_array;
}
void
CreatureManager::PoseCreature(const std::string& animation_name_in,
glm::float32 * target_pts,
float input_run_time)
{
if(animations.count(animation_name_in) <= 0)
{
std::cerr<<"CreatureManager::PoseCreature() - Animation not found: "<<animation_name_in<<std::endl;
return;
}
auto& cur_animation = animations[animation_name_in];
auto& bone_cache_manager = cur_animation->getBonesCache();
auto& displacement_cache_manager = cur_animation->getDisplacementCache();
auto& uv_warp_cache_manager = cur_animation->getUVWarpCache();
auto& opacity_cache_manager = cur_animation->getOpacityCache();
meshRenderBoneComposition * render_composition =
target_creature->GetRenderComposition();
// Extract values from caches
std::unordered_map<std::string, meshBone *>& bones_map =
render_composition->getBonesMap();
std::unordered_map<std::string, meshRenderRegion *>& regions_map =
render_composition->getRegionsMap();
bone_cache_manager.retrieveValuesAtTime(input_run_time,
bones_map);
AlterBonesByAnchor(bones_map, animation_name_in);
if(bones_override_callback)
{
bones_override_callback(bones_map);
}
displacement_cache_manager.retrieveValuesAtTime(input_run_time,
regions_map);
uv_warp_cache_manager.retrieveValuesAtTime(input_run_time,
regions_map);
opacity_cache_manager.retrieveValuesAtTime(input_run_time,
regions_map);
// Do posing, decide if we are blending or not
std::vector<meshRenderRegion *>& cur_regions =
render_composition->getRegions();
render_composition->updateAllTransforms(false);
for(size_t j = 0; j < cur_regions.size(); j++) {
meshRenderRegion * cur_region = cur_regions[j];
int cur_pt_index = cur_region->getStartPtIndex();
cur_region->poseFastFinalPts(target_pts + (cur_pt_index * 3));
}
}
void
CreatureManager::ProcessAutoBlending()
{
// process blending factor
blending_factor += auto_blend_delta;
if(blending_factor > 1)
{
blending_factor = 1;
}
}
void
CreatureManager::PoseJustBones(const std::string& animation_name_in,
glm::float32 * target_pts,
float input_run_time)
{
if (animations.count(animation_name_in) <= 0)
{
std::cerr << "CreatureManager::PoseCreature() - Animation not found: " << animation_name_in << std::endl;
return;
}
auto& cur_animation = animations[animation_name_in];
auto& bone_cache_manager = cur_animation->getBonesCache();
auto& opacity_cache_manager = cur_animation->getOpacityCache();
meshRenderBoneComposition * render_composition =
target_creature->GetRenderComposition();
// Extract values from caches
std::unordered_map<std::string, meshBone *>& bones_map =
render_composition->getBonesMap();
std::unordered_map<std::string, meshRenderRegion *>& regions_map =
render_composition->getRegionsMap();
bone_cache_manager.retrieveValuesAtTime(input_run_time,
bones_map);
AlterBonesByAnchor(bones_map, animation_name_in);
if (bones_override_callback)
{
bones_override_callback(bones_map);
}
opacity_cache_manager.retrieveValuesAtTime(input_run_time,
regions_map);
JustRunUVWarps(animation_name_in, input_run_time);
}
void CreatureManager::JustRunUVWarps(const std::string& animation_name_in, float input_run_time)
{
auto& cur_animation = animations[animation_name_in];
meshRenderBoneComposition * render_composition =
target_creature->GetRenderComposition();
std::unordered_map<std::string, meshRenderRegion *>& regions_map =
render_composition->getRegionsMap();
auto& uv_warp_cache_manager = cur_animation->getUVWarpCache();
uv_warp_cache_manager.retrieveValuesAtTime(input_run_time,
regions_map);
std::vector<meshRenderRegion *>& all_regions = render_composition->getRegions();
int index = 0;
for (auto& cur_region : all_regions) {
if (cur_region->getUseUvWarp())
{
cur_region->runUvWarp();
}
}
}
void
CreatureManager::RunUVItemSwap()
{
meshRenderBoneComposition * render_composition =
target_creature->GetRenderComposition();
std::unordered_map<std::string, meshRenderRegion *>& regions_map =
render_composition->getRegionsMap();
auto& swap_packets = target_creature->GetUvSwapPackets();
auto& active_swap_actions = target_creature->GetActiveItemSwaps();
if (swap_packets.empty() || active_swap_actions.empty())
{
return;
}
for(auto& cur_action : active_swap_actions)
{
if (regions_map.count(cur_action.first) > 0)
{
auto swap_tag = cur_action.second;
auto& swap_list = swap_packets.at(cur_action.first);
for (auto& cur_item : swap_list)
{
if (cur_item.tag == swap_tag)
{
// Perfrom UV Item Swap
auto cur_region = regions_map[cur_action.first];
cur_region->setUvWarpLocalOffset(cur_item.local_offset);
cur_region->setUvWarpGlobalOffset(cur_item.global_offset);
cur_region->setUvWarpScale(cur_item.scale);
cur_region->runUvWarp();
break;
}
}
}
}
}
void CreatureManager::AlterBonesByAnchor(std::unordered_map<std::string, meshBone*>& bones_map, const std::string & animation_name_in)
{
if (target_creature->GetAnchorPointsActive() == false)
{
return;
}
auto anchor_point = target_creature->GetAnchorPoint(animation_name_in);
for (auto& cur_data : bones_map)
{
auto cur_bone = cur_data.second;
auto start_pt = cur_bone->getWorldStartPt();
auto end_pt = cur_bone->getWorldEndPt();
start_pt -= glm::vec4(anchor_point.x, anchor_point.y, 0, 0);
end_pt -= glm::vec4(anchor_point.x, anchor_point.y, 0, 0);
cur_bone->setWorldStartPt(start_pt);
cur_bone->setWorldEndPt(end_pt);
}
}
void
CreatureManager::Update(float delta)
{
if(!is_playing)
{
return;
}
increRunTime(delta * time_scale);
if(do_auto_blending)
{
ProcessAutoBlending();
// process run times for blends
increAutoBlendRuntimes(delta * time_scale);
}
if(do_blending)
{
for(int i = 0; i < 2; i++) {
auto& cur_animation_name = active_blend_animation_names[i];
auto& cur_animation = animations[cur_animation_name];
auto& cur_animation_run_time = active_blend_run_times[cur_animation_name];
if(cur_animation->hasCachePts() && do_point_caching)
{
UpdateRegionSwitches(cur_animation_name);
cur_animation->poseFromCachePts(cur_animation_run_time, blend_render_pts[i], target_creature->GetTotalNumPoints());
PoseJustBones(cur_animation_name, blend_render_pts[i], cur_animation_run_time);
}
else {
UpdateRegionSwitches(active_blend_animation_names[i]);
PoseCreature(active_blend_animation_names[i], blend_render_pts[i], cur_animation_run_time);
}
}
for(int j = 0; j < target_creature->GetTotalNumPoints() * 3; j++)
{
glm::float32 * set_data = target_creature->GetRenderPts() + j;
glm::float32 * read_data_1 = blend_render_pts[0] + j;
glm::float32 * read_data_2 = blend_render_pts[1] + j;
*set_data = ((1.0f - blending_factor) * (*read_data_1)) +
(blending_factor * (*read_data_2));
}
}
else {
auto& cur_animation = animations[active_animation_name];
if(cur_animation->hasCachePts() && do_point_caching)
{
cur_animation->poseFromCachePts(getRunTime(), target_creature->GetRenderPts(), target_creature->GetTotalNumPoints());
PoseJustBones(active_animation_name, target_creature->GetRenderPts(), getRunTime());
}
else {
PoseCreature(active_animation_name, target_creature->GetRenderPts(), getRunTime());
}
}
RunUVItemSwap();
if(mirror_y)
{
glm::float32 * set_data = target_creature->GetRenderPts();
for(int j = 0; j < target_creature->GetTotalNumPoints(); j++)
{
set_data[0] = -set_data[0];
set_data += 3;
}
}
}
void
CreatureManager::SetMirrorY(bool flag_in)
{
mirror_y = flag_in;
}
std::string
CreatureManager::IsContactBone(const glm::vec2& pt_in,
const glm::mat4& creature_xform,
float radius) const
{
std::string ret_name;
meshBone * cur_bone = target_creature->GetRenderComposition()->getRootBone();
glm::vec4 local_pt = glm::inverse(creature_xform) * glm::vec4(pt_in, 0, 1);
glm::vec2 real_pt(local_pt.x, local_pt.y);
if(mirror_y)
{
real_pt.x = -real_pt.x;
}
return ProcessContactBone(real_pt, radius, cur_bone);
}
std::string
CreatureManager::ProcessContactBone(const glm::vec2& pt_in,
float radius,
meshBone * bone_in) const
{
std::string ret_name;
glm::vec2 cur_vec = glm::vec2(bone_in->getWorldEndPt() - bone_in->getWorldStartPt());
float cur_length = glm::length(cur_vec);
glm::vec2 unit_vec = glm::normalize(cur_vec);
glm::vec2 norm_vec(unit_vec.y, unit_vec.x);
glm::vec2 rel_vec = pt_in - glm::vec2(bone_in->getWorldStartPt());
float proj = glm::dot(rel_vec, unit_vec);
if( (proj >= 0) && (proj <= cur_length))
{
float norm_proj = glm::dot(rel_vec, norm_vec);
if(norm_proj <= radius)
{
return bone_in->getKey();
}
}
auto& cur_children = bone_in->getChildren();
for(auto& cur_child : cur_children)
{
ret_name = ProcessContactBone(pt_in, radius, cur_child);
if(!ret_name.empty()) {
break;
}
}
return ret_name;
}
float CreatureManager::getRunTime() const
{
return run_time;
}
void
CreatureManager::setRunTime(float time_in)
{
run_time = time_in;
}
float
CreatureManager::getActualRunTime() const
{
if (do_auto_blending)
{
if (active_blend_run_times.count(active_animation_name)) {
return active_blend_run_times.at(active_animation_name);
}
}
return run_time;
}
float
CreatureManager::correctRunTime(float time_in, const std::string& animation_name)
{
float ret_time = time_in;
auto& cur_animation = animations[animation_name];
float anim_start_time = cur_animation->getStartTime();
float anim_end_time = cur_animation->getEndTime();
if (use_custom_time_range)
{
anim_start_time = (float)custom_start_time;
anim_end_time = (float)custom_end_time;
}
if (ret_time > anim_end_time)
{
if (should_loop)
{
ret_time = anim_start_time;
}
else {
ret_time = anim_end_time;
}
}
else if (ret_time < anim_start_time)
{
if (should_loop)
{
ret_time = anim_end_time;
}
else {
ret_time = anim_start_time;
}
}
return ret_time;
}
void
CreatureManager::increRunTime(float delta_in)
{
if(animations.count(active_animation_name) <= 0)
{
return;
}
run_time += delta_in;
run_time = correctRunTime(run_time, active_animation_name);
}
void
CreatureManager::increAutoBlendRuntimes(float delta_in)
{
std::string set_animation_name;
for (auto& cur_animation_name : auto_blend_names)
{
if ((animations.count(cur_animation_name) > 0)
&& (set_animation_name != cur_animation_name))
{
float& cur_run_time = active_blend_run_times[cur_animation_name];
cur_run_time += delta_in;
cur_run_time = correctRunTime(cur_run_time, cur_animation_name);
set_animation_name = cur_animation_name;
}
}
}
void
CreatureManager::SetShouldLoop(bool flag_in)
{
should_loop = flag_in;
}
void
CreatureManager::SetUseCustomTimeRange(bool flag_in)
{
use_custom_time_range = flag_in;
}
void
CreatureManager::SetCustomTimeRange(int start_time_in, int end_time_in)
{
custom_start_time = start_time_in;
custom_end_time = end_time_in;
}
void
CreatureManager::SetBonesOverrideCallback(std::function<void (std::unordered_map<std::string, meshBone *>&) >& callback_in)
{
bones_override_callback = callback_in;
}
}