Offset needs to be multiplied by scale, otherwise the effect will be disproportionately pronounced when the face is scaled down.
110 lines
3.3 KiB
C++
110 lines
3.3 KiB
C++
#include <GL/glew.h>
|
|
#include <glm/mat4x4.hpp>
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
|
|
#include <graphics.hpp>
|
|
#include <modelpart.hpp>
|
|
|
|
#include <iostream>
|
|
|
|
std::map<std::string, int> bindStringToNum {
|
|
{"null", BIND_NULL},
|
|
{"head", BIND_HEAD},
|
|
{"face", BIND_FACE},
|
|
{"offset-eyes", OFFSET_EYES},
|
|
};
|
|
|
|
std::map<std::string, bool> triggerStringToNum {
|
|
{"null", TRIGGER_NULL},
|
|
{"mouth-open", TRIGGER_MOUTH_OPEN},
|
|
};
|
|
|
|
ModelPart::ModelPart() {
|
|
//create vbo, ebo, vao
|
|
initBuffers(&vao);
|
|
|
|
empty = false;
|
|
}
|
|
|
|
void ModelPart::bindAndDraw() {
|
|
glBindVertexArray(vao);
|
|
glBindTexture(GL_TEXTURE_2D, tex[texSelection]);
|
|
glUniformMatrix4fv(transUniform, 1, GL_FALSE, glm::value_ptr(transMatrix));
|
|
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
|
|
}
|
|
|
|
void ModelPart::setBind(std::string bindName) {
|
|
bind = bindStringToNum[bindName];
|
|
}
|
|
|
|
void ModelPart::setFollowTarget(std::string followTarget) {
|
|
follow = bindStringToNum[followTarget];
|
|
}
|
|
|
|
void ModelPart::setOffsetBind(std::string bindName) {
|
|
offsetBind = bindStringToNum[bindName];
|
|
}
|
|
|
|
void ModelPart::smoothTransform(glm::vec2 position, float rotation, float scale) {
|
|
histPositions[histI] = position;
|
|
histRotations[histI] = rotation;
|
|
histScales[histI] = scale;
|
|
|
|
histI++;
|
|
histI = histI % SMOOTHING_FRAMES;
|
|
|
|
glm::vec2 smoothedPosition(0,0);
|
|
float smoothedRotation = 0;
|
|
float smoothedScale = 0;
|
|
|
|
for(size_t i = 0; i < SMOOTHING_FRAMES; i++) {
|
|
smoothedPosition += histPositions[i];
|
|
smoothedRotation += histRotations[i];
|
|
smoothedScale += histScales[i];
|
|
}
|
|
|
|
smoothedPosition /= SMOOTHING_FRAMES;
|
|
smoothedRotation /= SMOOTHING_FRAMES;
|
|
smoothedScale /= SMOOTHING_FRAMES;
|
|
|
|
setTransform(smoothedPosition, smoothedRotation, smoothedScale);
|
|
}
|
|
|
|
void ModelPart::setTransform(glm::vec2 position, float rotation, float scale) {
|
|
transMatrix = glm::ortho(-windowAspectRatio, windowAspectRatio, -1.0f, 1.0f);
|
|
transMatrix = glm::translate(transMatrix, glm::vec3(position.x, -position.y, 0.0f) + glm::vec3(posOffset, 0.0f));
|
|
transMatrix = glm::rotate(transMatrix, rotation * rotFactor, glm::vec3(0.0f, 0.0f, 1.0f));
|
|
transMatrix = glm::scale(transMatrix, glm::vec3(1,1,1) + (scale - 1 + glm::vec3(scaleOffset, 0.0f)) * scaleFactor);
|
|
transMatrix = glm::translate(transMatrix, glm::vec3(-origin, 0.0f));
|
|
}
|
|
|
|
void ModelPart::processFaceData(struct FaceData faceData) {
|
|
// calculate position
|
|
glm::vec2 bindPosition = faceData.positions[bind];
|
|
glm::vec2 followPosition = faceData.positions[follow];
|
|
glm::vec2 followDirection = followPosition - bindPosition;
|
|
glm::vec2 offset = faceData.positions[offsetBind] * offsetFactor * faceData.scale;
|
|
glm::vec2 newPosition = bindPosition + offset + (followDirection * factor);
|
|
|
|
smoothTransform(newPosition, faceData.headRotation, faceData.scale);
|
|
|
|
// change textures
|
|
selectTexture(0); // if none are triggered, use the first one
|
|
for (size_t i = 0; i < texCount; i++) {
|
|
if (faceData.triggers[texTriggers[i]]) {
|
|
selectTexture(i);
|
|
break; // if several textures are triggered, the first one defined in model.toml will get priority
|
|
}
|
|
}
|
|
}
|
|
|
|
void ModelPart::addTexture(unsigned char* texBuffer, size_t texLength, size_t slot, std::string triggerName) {
|
|
initTexture(&tex[slot], texBuffer, texLength);
|
|
texTriggers[slot] = triggerStringToNum[triggerName];
|
|
texCount++;
|
|
}
|
|
|
|
void ModelPart::selectTexture(size_t slot) {
|
|
texSelection = slot;
|
|
}
|