+bool keyStates[256] = {false};
+
+void keyboard(unsigned char key, int x, int y) {
+ keyStates[key] = true;
+ if (key == 'z')
+ activeSkybox = (activeSkybox + 1) % skyboxes.size();
+ if (key == 'c')
+ discoLights = !discoLights;
+}
+
+void keyboardUp(unsigned char key, int x, int y) {
+ keyStates[key] = false;
+}
+
+int mouseX, mouseY;
+
+struct Mode {
+ virtual void display(float d) = 0;
+ virtual void timer() = 0;
+ virtual void motion(int x, int y, int dx, int dy) = 0;
+ virtual void passiveMotion(int x, int y, int dx, int dy) = 0;
+ virtual void mouse(int button, int state, int x, int y) = 0;
+};
+
+struct AnimationMode : public Mode {
+ Model *sceneModel;
+
+ AnimationMode(std::string modelPath) {
+ const aiScene *scene = importer.ReadFile(
+ modelPath, aiProcess_Triangulate | aiProcess_CalcTangentSpace |
+ aiProcess_GenNormals | aiProcess_FlipUVs);
+ if (!scene) {
+ std::cerr << importer.GetErrorString() << std::endl;
+ exit(1);
+ }
+
+ if (scene->mNumCameras > 0) {
+ aiCamera *cam = scene->mCameras[0];
+ glm::mat4 camTrans;
+ if (findNodeTrans(scene->mRootNode, cam->mName, &camTrans) != 0)
+ abort(); // there must be a node with the same name as camera
+
+ camPos = {camTrans[3][0], camTrans[3][1], camTrans[3][2]};
+
+ glm::vec3 camLookAt =
+ glm::vec3(cam->mLookAt.x, cam->mLookAt.y, cam->mLookAt.z);
+ camFront = camLookAt - camPos;
+
+ camUp = glm::vec3(cam->mUp.x, cam->mUp.y, cam->mUp.z);
+
+ fov = cam->mHorizontalFOV;
+ // TODO: aspectRatio = cam->mAspect;
+ znear = cam->mClipPlaneNear;
+ zfar = cam->mClipPlaneFar;
+ }
+
+ for (int i = 0; i < scene->mNumLights; i++) {
+ aiLight *light = scene->mLights[i];
+ glm::mat4 trans;
+ findNodeTrans(scene->mRootNode, light->mName, &trans);
+ glm::vec3 col = {light->mColorAmbient.r, light->mColorAmbient.g,
+ light->mColorAmbient.b};
+ Light l = {trans, col};
+ lights.push_back(l);
+ }
+
+ sceneModel = new Model(scene, *pbrProg);
+ }
+
+ void display(float d) override {
+ sceneModel->draw(skyboxes[activeSkybox], d * 1000);
+ }
+
+ void timer() override {};
+ void motion(int x, int y, int dx, int dy) override {}
+ void passiveMotion(int x, int y, int dx, int dy) override {}
+ void mouse(int button, int state, int x, int y) override {}
+};
+
+
+// TODO: move these inside
+bool needToCalculateClosestVertex = false;
+bool needToInterpolateBlendshapes = false;
+struct BlendshapeMode : public Mode {
+
+ class Delegate : public ControlWindowDelegate {
+ public:
+
+ virtual void weightChanged(int blendshape, float weight) override {
+ bsModel.blendshapes[blendshape].weight = weight;
+ needToInterpolateBlendshapes = true;
+ }
+
+ virtual void solveWeights(std::vector<float> &newWeights) override {
+ ::solveWeights(&bsModel, manipulators);
+ for (int i = 0; i < newWeights.size(); i++)
+ newWeights[i] = bsModel.blendshapes[i].weight;
+ needToInterpolateBlendshapes = true;
+ }
+
+ virtual void resetManipulators() override {
+ manipulators.clear();
+ curManipulator = { -1, -1 };
+ }
+
+ virtual void playbackChanged(bool playing) override {
+ playBlendshapeAnim = playing;
+ }
+ };
+
+ Delegate cwDelegate;
+ ControlWindow controlWindow;
+
+ BlendshapeMode(std::string directory) {
+ loadBlendshapes(directory, *pbrProg, &bsModel);
+ targetModel = bsModel.model;
+
+ size_t numBlends = bsModel.blendshapes.size();
+ std::vector<std::string> names(numBlends);
+ for (int i = 0; i < numBlends; i++) names[i] = bsModel.blendshapes[i].name;
+
+ controlWindow = createControlWindow(names, &cwDelegate);
+
+ camPos = { 0, 18, 81 };
+ camFront = { 0, 0, -1 };
+ camUp = { 0, 1, 0 };
+ zfar = 10000;
+ znear = 0.1f;
+ }
+