<commit_before>#include "generator.h"

#include <cassert>
#include <cstring>
#include <deque>
#include <iostream>
#include <map>

#include "dictionary.h"
#include "label.h"

static void compileCall(FILE* f, const char* wordName, bool tailCall, Dictionary* dictionary) {
    fprintf(f, tailCall ? "\tjmp %s\n" : "\tjsr %s\n", label(wordName).c_str());
    dictionary->markAsUsed(wordName);
}

void generateAsm(FILE* f, const Tokens& tokens, Dictionary* dictionary) {
    std::deque<int> stack;
    int localLabel = 0;
    bool state = false;
    std::set<int> undefinedVariables;
    int variableLabel = 0;
    std::map<std::string, int> variableLabels;

    for (auto it = tokens.begin(); it != tokens.end(); ++it) {
        switch (it->type) {
            case Cells:
                if (state) {
                    ++it;
                    bool tailCall = (it != tokens.end() && it->type == SemiColon);
                    --it;
                    compileCall(f, "2*", tailCall, dictionary);
                    if (tailCall) {
                        ++it;  // Skips ;
                        state = false;
                    }
                } else {
                    stack.back() *= 2;
                }
                break;
            case Allot:
                assert(!stack.empty());
                fprintf(f, "* = * + %i\n", stack.back());
                stack.pop_back();
                break;
            case Create:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "create must be followed by a word name!");
                    exit(1);
                }
                // printf("Create '%s'\n", it->stringData);
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                free(it->stringData);
                break;
            case String:
                fprintf(f, "\tjsr litstring\n!byte %i\n!text \"%s\"\n",
                        (int)strlen(it->stringData), it->stringData);
                dictionary->markAsUsed("litstring");
                free(it->stringData);
                break;
            case Variable:
                // puts("Variable");
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "variable must be followed by a word name!");
                    exit(1);
                }
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                fprintf(f, "\tlda #<+\n\tldy #>+\n\tjmp pushya\n+\n!word vl_%i\n", variableLabel);
                undefinedVariables.insert(variableLabel);
                variableLabels[it->stringData] = variableLabel;
                ++variableLabel;
                dictionary->markAsUsed("pushya");
                free(it->stringData);
                break;
            case Store:
                if (!state) {
                    int variableLabel = stack.back();
                    stack.pop_back();
                    int value = stack.back();
                    stack.pop_back();
                    fprintf(f, "vl_%i = %i\n", variableLabel, value);
                    undefinedVariables.erase(variableLabel);
                    break;
                } else {
                    ++it;
                    bool tailCall = (it != tokens.end() && it->type == SemiColon);
                    --it;
                    compileCall(f, "!", tailCall, dictionary);
                    if (tailCall) {
                        ++it;  // Skips ;
                        state = false;
                    }
                }
                break;
            case WordName:
                // printf("WordName %s\n", it->stringData);
                assert(it->stringData);
                if (state) {
                    ++it;
                    bool tailCall = (it != tokens.end() && it->type == SemiColon);
                    --it;
                    compileCall(f, it->stringData, tailCall, dictionary);
                    if (tailCall) {
                        ++it;  // Skips ;
                        state = false;
                    }
                    free(it->stringData);
                } else {
                    char* wordName = it->stringData;
                    if (variableLabels.find(wordName) != variableLabels.end()) {
                        stack.push_back(variableLabels[wordName]);
                        free(it->stringData);
                    } else {
                        fprintf(stderr, "Variable '%s' not defined\n", wordName);
                        exit(1);
                    }
                }
                break;
            case Number:
                // puts("Number");
                if (state) {
                    dictionary->markAsUsed("lit");
                    fprintf(f, "\tjsr lit\n\t!word %i\n", it->intData);
                } else {
                    stack.push_back(it->intData);
                }
                break;
            case Code:
                // puts("Code");
                {
                    char* p = it->stringData;
                    std::string wordName;
                    while (!isspace(*p)) {
                        wordName.push_back(*p);
                        ++p;
                    }
                    dictionary->addWord(wordName.c_str());
                    if (*p == '\n') {
                        ++p;
                    }
                    if (label(wordName.c_str()) != wordName) {
                        fprintf(f, "%s:\t; %s\n%s\n", label(wordName.c_str()).c_str(),
                                wordName.c_str(), p);
                    } else {
                        fprintf(f, "%s:\n%s\n", wordName.c_str(), p);
                    }
                }
                free(it->stringData);
                break;
            case Colon:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, ": must be followed by a word name! (is type %i)\n", it->type);
                    exit(1);
                }
                fprintf(f, "\n%s:", label(it->stringData).c_str());
                // printf("Colon %s\n", it->stringData);
                dictionary->addWord(it->stringData);
                if (it->stringData != label(it->stringData)) {
                    fprintf(f, "\t; %s", it->stringData);
                }
                fprintf(f, "\n");
                free(it->stringData);
                state = true;
                break;
            case Drop:
                fputs("\tinx\t; drop\n", f);
                break;
            case SemiColon:
                fputs("\trts\n", f);
                state = false;
                break;
            case If:
                fprintf(f, "\tjsr ifcmp\n\tbeq .l%i\n", localLabel);
                dictionary->markAsUsed("ifcmp");
                stack.push_back(localLabel++);
                break;
            case Else:
                fprintf(f, "\tjmp .l%i\n.l%i:\n", localLabel, stack.back());
                stack.pop_back();
                stack.push_back(localLabel++);
                break;
            case Then:
                fprintf(f, ".l%i:\n", stack.back());
                stack.pop_back();
                break;
            case Begin:
                stack.push_back(localLabel);
                fprintf(f, ".l%i:\n", localLabel++);
                break;
            case Again:
                fprintf(f, "\tjmp .l%i\n", stack.back());
                stack.pop_back();
                break;
            case Value:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "value must be followed by a word name!");
                    exit(1);
                }
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                fprintf(f, "\tlda #%i\n", stack.back() & 0xff);
                fprintf(f, "\tldy #%i\n", stack.back() >> 8);
                fprintf(f, "\tjmp pushya\n");
                stack.pop_back();
                dictionary->markAsUsed("pushya");
                free(it->stringData);
                break;
        }
    }
}
<commit_msg>refactoring<commit_after>#include "generator.h"

#include <cassert>
#include <cstring>
#include <deque>
#include <iostream>
#include <map>

#include "dictionary.h"
#include "label.h"

static void compileCall(FILE* f, const char* wordName, const Tokens& tokens,
        Tokens::const_iterator* it, bool* state, Dictionary* dictionary) {
    ++*it;
    bool tailCall = (*it != tokens.end() && (*it)->type == SemiColon);
    --*it;
    fprintf(f, tailCall ? "\tjmp %s\n" : "\tjsr %s\n", label(wordName).c_str());
    if (tailCall) {
        ++*it;  // Skips ;
        *state = false;
    }
    dictionary->markAsUsed(wordName);
}

void generateAsm(FILE* f, const Tokens& tokens, Dictionary* dictionary) {
    std::deque<int> stack;
    int localLabel = 0;
    bool state = false;
    std::set<int> undefinedVariables;
    int variableLabel = 0;
    std::map<std::string, int> variableLabels;

    for (auto it = tokens.begin(); it != tokens.end(); ++it) {
        switch (it->type) {
            case Cells:
                if (state) {
                    compileCall(f, "2*", tokens, &it, &state, dictionary);
                } else {
                    stack.back() *= 2;
                }
                break;
            case Allot:
                assert(!stack.empty());
                fprintf(f, "* = * + %i\n", stack.back());
                stack.pop_back();
                break;
            case Create:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "create must be followed by a word name!");
                    exit(1);
                }
                // printf("Create '%s'\n", it->stringData);
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                free(it->stringData);
                break;
            case String:
                fprintf(f, "\tjsr litstring\n!byte %i\n!text \"%s\"\n",
                        (int)strlen(it->stringData), it->stringData);
                dictionary->markAsUsed("litstring");
                free(it->stringData);
                break;
            case Variable:
                // puts("Variable");
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "variable must be followed by a word name!");
                    exit(1);
                }
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                fprintf(f, "\tlda #<+\n\tldy #>+\n\tjmp pushya\n+\n!word vl_%i\n", variableLabel);
                undefinedVariables.insert(variableLabel);
                variableLabels[it->stringData] = variableLabel;
                ++variableLabel;
                dictionary->markAsUsed("pushya");
                free(it->stringData);
                break;
            case Store:
                if (!state) {
                    int variableLabel = stack.back();
                    stack.pop_back();
                    int value = stack.back();
                    stack.pop_back();
                    fprintf(f, "vl_%i = %i\n", variableLabel, value);
                    undefinedVariables.erase(variableLabel);
                    break;
                } else {
                    compileCall(f, "!", tokens, &it, &state, dictionary);
                }
                break;
            case WordName:
                // printf("WordName %s\n", it->stringData);
                assert(it->stringData);
                if (state) {
                    compileCall(f, it->stringData, tokens, &it, &state, dictionary);
                    free(it->stringData);
                } else {
                    char* wordName = it->stringData;
                    if (variableLabels.find(wordName) != variableLabels.end()) {
                        stack.push_back(variableLabels[wordName]);
                        free(it->stringData);
                    } else {
                        fprintf(stderr, "Variable '%s' not defined\n", wordName);
                        exit(1);
                    }
                }
                break;
            case Number:
                // puts("Number");
                if (state) {
                    dictionary->markAsUsed("lit");
                    fprintf(f, "\tjsr lit\n\t!word %i\n", it->intData);
                } else {
                    stack.push_back(it->intData);
                }
                break;
            case Code:
                // puts("Code");
                {
                    char* p = it->stringData;
                    std::string wordName;
                    while (!isspace(*p)) {
                        wordName.push_back(*p);
                        ++p;
                    }
                    dictionary->addWord(wordName.c_str());
                    if (*p == '\n') {
                        ++p;
                    }
                    if (label(wordName.c_str()) != wordName) {
                        fprintf(f, "%s:\t; %s\n%s\n", label(wordName.c_str()).c_str(),
                                wordName.c_str(), p);
                    } else {
                        fprintf(f, "%s:\n%s\n", wordName.c_str(), p);
                    }
                }
                free(it->stringData);
                break;
            case Colon:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, ": must be followed by a word name! (is type %i)\n", it->type);
                    exit(1);
                }
                fprintf(f, "\n%s:", label(it->stringData).c_str());
                // printf("Colon %s\n", it->stringData);
                dictionary->addWord(it->stringData);
                if (it->stringData != label(it->stringData)) {
                    fprintf(f, "\t; %s", it->stringData);
                }
                fprintf(f, "\n");
                free(it->stringData);
                state = true;
                break;
            case Drop:
                fputs("\tinx\t; drop\n", f);
                break;
            case SemiColon:
                fputs("\trts\n", f);
                state = false;
                break;
            case If:
                fprintf(f, "\tjsr ifcmp\n\tbeq .l%i\n", localLabel);
                dictionary->markAsUsed("ifcmp");
                stack.push_back(localLabel++);
                break;
            case Else:
                fprintf(f, "\tjmp .l%i\n.l%i:\n", localLabel, stack.back());
                stack.pop_back();
                stack.push_back(localLabel++);
                break;
            case Then:
                fprintf(f, ".l%i:\n", stack.back());
                stack.pop_back();
                break;
            case Begin:
                stack.push_back(localLabel);
                fprintf(f, ".l%i:\n", localLabel++);
                break;
            case Again:
                fprintf(f, "\tjmp .l%i\n", stack.back());
                stack.pop_back();
                break;
            case Value:
                ++it;
                if (it == tokens.end() || it->type != WordName) {
                    fprintf(stderr, "value must be followed by a word name!");
                    exit(1);
                }
                fprintf(f, "\n%s:\n", label(it->stringData).c_str());
                dictionary->addWord(it->stringData);
                fprintf(f, "\tlda #%i\n", stack.back() & 0xff);
                fprintf(f, "\tldy #%i\n", stack.back() >> 8);
                fprintf(f, "\tjmp pushya\n");
                stack.pop_back();
                dictionary->markAsUsed("pushya");
                free(it->stringData);
                break;
        }
    }
}
<|endoftext|>


<commit_before>#pragma once

#include <functional>
#include <glm/glm.hpp>
#include <memory>
#include <Utility/LockBox.hpp>
#include <vector>
#include "../Entity/ComponentContainer.hpp"
#include "../linking.hpp"

namespace Component {
    class RigidBody;
    class Shape;
}

namespace Physics {
    class Shape;
    class Trigger;
}

namespace Json {
    class Value;
}

class btBroadphaseInterface;
class btDefaultCollisionConfiguration;
class btCollisionDispatcher;
class btSequentialImpulseConstraintSolver;
class btDiscreteDynamicsWorld;
class Entity;

/// Updates the physics of the world.
class PhysicsManager {
    friend class Hub;

    public:
        /// Moves entities and updates the physics component.
        /**
         * @param deltaTime Time since last frame (in seconds).
         */
        ENGINE_API void Update(float deltaTime);

        /// Update transforms of entities according to positions of physics
        /// components.
        ENGINE_API void UpdateEntityTransforms();

        /// Set up listener for when |object| has entered |trigger|.
        /**
         * @param trigger What trigger to check against.
         * @param object Body that is to enter the trigger volume.
         * @param callback Function to call when resolving event.
         */
        ENGINE_API void OnTriggerEnter(Utility::LockBox<Physics::Trigger> trigger, Component::RigidBody* object, std::function<void()> callback);

        /// Stop listening for when |object| has entered |trigger|.
        /**
         * @param trigger What trigger to stop listening on.
         * @param object Body that is to be forgotten.
         */
        ENGINE_API void ForgetTriggerEnter(Utility::LockBox<Physics::Trigger> trigger, Component::RigidBody* object);

        /// Set up listener for when |object| is intersecting |trigger|.
        /**
         * @param trigger What trigger to check against.
         * @param object Body that is to cause trigger to fire.
         * @param callback Function to call when resolving event.
         */
        ENGINE_API void OnTriggerRetain(Utility::LockBox<Physics::Trigger> trigger, Component::RigidBody* object, std::function<void()> callback);

        /// Stop listening for when |object| is intersecting |trigger|.
        /**
         * @param trigger What trigger to stop listening on.
         * @param object Body that is to be forgotten.
         */
        ENGINE_API void ForgetTriggerRetain(Utility::LockBox<Physics::Trigger> trigger, Component::RigidBody* object);

        /// Set up listener for when |object| has left |trigger|.
        /**
         * @param trigger What trigger to check against.
         * @param object Body that is to cause trigger to fire.
         * @param callback Function to call when resolving event.
         */
        ENGINE_API void OnTriggerLeave(Utility::LockBox<Physics::Trigger> trigger, Component::RigidBody* object, std::function<void()> callback);

        /// Stop listening for when |object| has left |trigger|.
        /**
         * @param trigger What trigger to stop listening on.
         * @param object Body that is to be forgotten.
         */
        ENGINE_API void ForgetTriggerLeave(Utility::LockBox<Physics::Trigger> trigger, Component::RigidBody* object);

        /// Create rigid body component.
        /**
         * @param owner The %Entity that will own the component.
         * @return The created component.
         */
        ENGINE_API Component::RigidBody* CreateRigidBody(Entity* owner);

        /// Create rigid body component.
        /**
         * @param owner The %Entity that will own the component.
         * @param node Json node from which to load component definition.
         * @return The created component.
         */
        ENGINE_API Component::RigidBody* CreateRigidBody(Entity* owner, const Json::Value& node);

        /// Create a component that represents a physical shape.
        /**
         * @param owner The %Entity that will own the component.
         * @return The created component.
         */
        ENGINE_API Component::Shape* CreateShape(Entity* owner);

        /// Create a component that represents a physical shape.
        /**
         * @param owner The %Entity that will own the component.
         * @param node Json node from which to load component definition.
         * @return The created component.
         */
        ENGINE_API Component::Shape* CreateShape(Entity* owner, const Json::Value& node);

        /// Create a trigger volume that can be used to check intersection
        /// events against physics bodies.
        /**
         * @param shape Shape of the trigger volume.
         * @return A reference to the internal trigger.
         */
        ENGINE_API Utility::LockBox<Physics::Trigger> CreateTrigger(std::shared_ptr<Physics::Shape> shape);

        /// Set the position of a trigger volume.
        /**
         * @param trigger Volume to reposition.
         * @param position New position in world space.
         */
        ENGINE_API void SetPosition(Utility::LockBox<Physics::Trigger> trigger, const glm::vec3& position);

        /// Set the shape of a given Component::Shape component.
        /**
         * @param comp The component on which to set the shape.
         * @param shape A Physics::Shape object that holds the shape definition.
         */
        ENGINE_API void SetShape(Component::Shape* comp, std::shared_ptr<::Physics::Shape> shape);

        /// Get the mass of a rigid body component.
        /**
         * @param comp Rigid body component to get mass of.
         * @return Mass in kilograms.
         */
        ENGINE_API float GetMass(Component::RigidBody* comp);

        /// Set the volume shape of a trigger.
        /**
         * @param trigger Trigger to alter shape of.
         * @param shape Shape definition.
         */
        ENGINE_API void SetShape(Utility::LockBox<Physics::Trigger> trigger, std::shared_ptr<Physics::Shape> shape);

        /// Set the mass of a Component::RigidBody component.
        /**
         * @param comp The component on which to set mass.
         * @param mass Mass in kilograms.
         */
        ENGINE_API void SetMass(Component::RigidBody* comp, float mass);

        /// Set the friction coefficient of a Component::RigidBody component.
        /**
         * @param comp Rigid body to alter.
         * @param friction Friction coefficient.
         */
        ENGINE_API void SetFriction(Component::RigidBody* comp, float friction);

        /// Set the rolling friction coefficient of a Component::RigidBody
        /// component.
        /**
         * @param comp Rigid body to alter.
         * @param friction Friction coefficient.
         */
        ENGINE_API void SetRollingFriction(Component::RigidBody* comp, float friction);

        /// Set the spinning friction coefficient of a Component::RigidBody
        /// component.
        /**
         * @param comp Rigid body to alter.
         * @param friction Friction coefficient.
         */
        ENGINE_API void SetSpinningFriction(Component::RigidBody* comp, float friction);

        /// Set the restitution (bounciness) of a Component::RigidBody component.
        /**
         * @param comp Rigid body to alter.
         * @param cor Coefficient of restitution.
         */
        ENGINE_API void SetRestitution(Component::RigidBody* comp, float cor);

        /// Set the linear damping factor of a Component::RigidBody component.
        /**
         * @param comp Rigid body to alter.
         * @param damping Linear damping.
         */
        ENGINE_API void SetLinearDamping(Component::RigidBody* comp, float damping);

        /// Set the angular damping factor of a Component::RigidBody component.
        /**
         * @param comp Rigid body to alter.
         * @param damping Angular damping.
         */
        ENGINE_API void SetAngularDamping(Component::RigidBody* comp, float damping);

        /// Turn a rigid body into a kinematic object, putting movement in the
        /// control of the programmer.
        /**
         * @param comp Rigid body to make kinematic.
         */
        ENGINE_API void MakeKinematic(Component::RigidBody* comp);

        /// Turn a rigid body into a dynamic object.
        /**
         * @param comp Rigid body to make dynamic.
         */
        ENGINE_API void MakeDynamic(Component::RigidBody* comp);

        /// Enables/disables ghost functionality on a rigid body.
        /**
         * @param comp Rigid body to alter state of.
         * @param ghost True: makes the rigid object a ghost, disregarding all
         collisions. False: disables ghost state, reverting to kinematic or
         dynamic as before.
         */
        ENGINE_API void SetGhost(Component::RigidBody* comp, bool ghost);

        /// Forces a dynamic rigid body to synchronize its transform with that
        /// of its owning entity during the next simulation iteration.
        /**
         * @param comp Rigid body to synchronize.
         */
        ENGINE_API void ForceTransformSync(Component::RigidBody* comp);

        /// Halts movement of a kinematic rigid body.
        /**
         * @param comp Rigid body to halt.
         */
        ENGINE_API void HaltMovement(Component::RigidBody* comp);

        /// Get all shape components.
        /**
         * @return All shape components.
         */
        ENGINE_API const std::vector<Component::Shape*>& GetShapeComponents() const;

        /// Remove all killed components.
        ENGINE_API void ClearKilledComponents();

    private:
        PhysicsManager();
        ~PhysicsManager();
        PhysicsManager(PhysicsManager const&) = delete;
        void operator=(PhysicsManager const&) = delete;

        glm::vec3 gravity = glm::vec3(0.f, -9.82f, 0.f);

        ComponentContainer<Component::RigidBody> rigidBodyComponents;
        ComponentContainer<Component::Shape> shapeComponents;

        btBroadphaseInterface* broadphase = nullptr;
        btDefaultCollisionConfiguration* collisionConfiguration = nullptr;
        btCollisionDispatcher* dispatcher = nullptr;
        btSequentialImpulseConstraintSolver* solver = nullptr;
        btDiscreteDynamicsWorld* dynamicsWorld = nullptr;

        std::shared_ptr<Utility::LockBox<Physics::Trigger>::Key> triggerLockBoxKey;
        std::vector<::Physics::Trigger*> triggers;
};
<commit_msg>Align asterisks in doxygen comment.<commit_after>#pragma once

#include <functional>
#include <glm/glm.hpp>
#include <memory>
#include <Utility/LockBox.hpp>
#include <vector>
#include "../Entity/ComponentContainer.hpp"
#include "../linking.hpp"

namespace Component {
    class RigidBody;
    class Shape;
}

namespace Physics {
    class Shape;
    class Trigger;
}

namespace Json {
    class Value;
}

class btBroadphaseInterface;
class btDefaultCollisionConfiguration;
class btCollisionDispatcher;
class btSequentialImpulseConstraintSolver;
class btDiscreteDynamicsWorld;
class Entity;

/// Updates the physics of the world.
class PhysicsManager {
    friend class Hub;

    public:
        /// Moves entities and updates the physics component.
        /**
         * @param deltaTime Time since last frame (in seconds).
         */
        ENGINE_API void Update(float deltaTime);

        /// Update transforms of entities according to positions of physics
        /// components.
        ENGINE_API void UpdateEntityTransforms();

        /// Set up listener for when |object| has entered |trigger|.
        /**
         * @param trigger What trigger to check against.
         * @param object Body that is to enter the trigger volume.
         * @param callback Function to call when resolving event.
         */
        ENGINE_API void OnTriggerEnter(Utility::LockBox<Physics::Trigger> trigger, Component::RigidBody* object, std::function<void()> callback);

        /// Stop listening for when |object| has entered |trigger|.
        /**
         * @param trigger What trigger to stop listening on.
         * @param object Body that is to be forgotten.
         */
        ENGINE_API void ForgetTriggerEnter(Utility::LockBox<Physics::Trigger> trigger, Component::RigidBody* object);

        /// Set up listener for when |object| is intersecting |trigger|.
        /**
         * @param trigger What trigger to check against.
         * @param object Body that is to cause trigger to fire.
         * @param callback Function to call when resolving event.
         */
        ENGINE_API void OnTriggerRetain(Utility::LockBox<Physics::Trigger> trigger, Component::RigidBody* object, std::function<void()> callback);

        /// Stop listening for when |object| is intersecting |trigger|.
        /**
         * @param trigger What trigger to stop listening on.
         * @param object Body that is to be forgotten.
         */
        ENGINE_API void ForgetTriggerRetain(Utility::LockBox<Physics::Trigger> trigger, Component::RigidBody* object);

        /// Set up listener for when |object| has left |trigger|.
        /**
         * @param trigger What trigger to check against.
         * @param object Body that is to cause trigger to fire.
         * @param callback Function to call when resolving event.
         */
        ENGINE_API void OnTriggerLeave(Utility::LockBox<Physics::Trigger> trigger, Component::RigidBody* object, std::function<void()> callback);

        /// Stop listening for when |object| has left |trigger|.
        /**
         * @param trigger What trigger to stop listening on.
         * @param object Body that is to be forgotten.
         */
        ENGINE_API void ForgetTriggerLeave(Utility::LockBox<Physics::Trigger> trigger, Component::RigidBody* object);

        /// Create rigid body component.
        /**
         * @param owner The %Entity that will own the component.
         * @return The created component.
         */
        ENGINE_API Component::RigidBody* CreateRigidBody(Entity* owner);

        /// Create rigid body component.
        /**
         * @param owner The %Entity that will own the component.
         * @param node Json node from which to load component definition.
         * @return The created component.
         */
        ENGINE_API Component::RigidBody* CreateRigidBody(Entity* owner, const Json::Value& node);

        /// Create a component that represents a physical shape.
        /**
         * @param owner The %Entity that will own the component.
         * @return The created component.
         */
        ENGINE_API Component::Shape* CreateShape(Entity* owner);

        /// Create a component that represents a physical shape.
        /**
         * @param owner The %Entity that will own the component.
         * @param node Json node from which to load component definition.
         * @return The created component.
         */
        ENGINE_API Component::Shape* CreateShape(Entity* owner, const Json::Value& node);

        /// Create a trigger volume that can be used to check intersection
        /// events against physics bodies.
        /**
         * @param shape Shape of the trigger volume.
         * @return A reference to the internal trigger.
         */
        ENGINE_API Utility::LockBox<Physics::Trigger> CreateTrigger(std::shared_ptr<Physics::Shape> shape);

        /// Set the position of a trigger volume.
        /**
         * @param trigger Volume to reposition.
         * @param position New position in world space.
         */
        ENGINE_API void SetPosition(Utility::LockBox<Physics::Trigger> trigger, const glm::vec3& position);

        /// Set the shape of a given Component::Shape component.
        /**
         * @param comp The component on which to set the shape.
         * @param shape A Physics::Shape object that holds the shape definition.
         */
        ENGINE_API void SetShape(Component::Shape* comp, std::shared_ptr<::Physics::Shape> shape);

        /// Get the mass of a rigid body component.
        /**
         * @param comp Rigid body component to get mass of.
         * @return Mass in kilograms.
         */
        ENGINE_API float GetMass(Component::RigidBody* comp);

        /// Set the volume shape of a trigger.
        /**
         * @param trigger Trigger to alter shape of.
         * @param shape Shape definition.
         */
        ENGINE_API void SetShape(Utility::LockBox<Physics::Trigger> trigger, std::shared_ptr<Physics::Shape> shape);

        /// Set the mass of a Component::RigidBody component.
        /**
         * @param comp The component on which to set mass.
         * @param mass Mass in kilograms.
         */
        ENGINE_API void SetMass(Component::RigidBody* comp, float mass);

        /// Set the friction coefficient of a Component::RigidBody component.
        /**
         * @param comp Rigid body to alter.
         * @param friction Friction coefficient.
         */
        ENGINE_API void SetFriction(Component::RigidBody* comp, float friction);

        /// Set the rolling friction coefficient of a Component::RigidBody
        /// component.
        /**
         * @param comp Rigid body to alter.
         * @param friction Friction coefficient.
         */
        ENGINE_API void SetRollingFriction(Component::RigidBody* comp, float friction);

        /// Set the spinning friction coefficient of a Component::RigidBody
        /// component.
        /**
         * @param comp Rigid body to alter.
         * @param friction Friction coefficient.
         */
        ENGINE_API void SetSpinningFriction(Component::RigidBody* comp, float friction);

        /// Set the restitution (bounciness) of a Component::RigidBody component.
        /**
         * @param comp Rigid body to alter.
         * @param cor Coefficient of restitution.
         */
        ENGINE_API void SetRestitution(Component::RigidBody* comp, float cor);

        /// Set the linear damping factor of a Component::RigidBody component.
        /**
         * @param comp Rigid body to alter.
         * @param damping Linear damping.
         */
        ENGINE_API void SetLinearDamping(Component::RigidBody* comp, float damping);

        /// Set the angular damping factor of a Component::RigidBody component.
        /**
         * @param comp Rigid body to alter.
         * @param damping Angular damping.
         */
        ENGINE_API void SetAngularDamping(Component::RigidBody* comp, float damping);

        /// Turn a rigid body into a kinematic object, putting movement in the
        /// control of the programmer.
        /**
         * @param comp Rigid body to make kinematic.
         */
        ENGINE_API void MakeKinematic(Component::RigidBody* comp);

        /// Turn a rigid body into a dynamic object.
        /**
         * @param comp Rigid body to make dynamic.
         */
        ENGINE_API void MakeDynamic(Component::RigidBody* comp);

        /// Enables/disables ghost functionality on a rigid body.
        /**
         * @param comp Rigid body to alter state of.
         * @param ghost True: makes the rigid object a ghost, disregarding all
         * collisions. False: disables ghost state, reverting to kinematic or
         * dynamic as before.
         */
        ENGINE_API void SetGhost(Component::RigidBody* comp, bool ghost);

        /// Forces a dynamic rigid body to synchronize its transform with that
        /// of its owning entity during the next simulation iteration.
        /**
         * @param comp Rigid body to synchronize.
         */
        ENGINE_API void ForceTransformSync(Component::RigidBody* comp);

        /// Halts movement of a kinematic rigid body.
        /**
         * @param comp Rigid body to halt.
         */
        ENGINE_API void HaltMovement(Component::RigidBody* comp);

        /// Get all shape components.
        /**
         * @return All shape components.
         */
        ENGINE_API const std::vector<Component::Shape*>& GetShapeComponents() const;

        /// Remove all killed components.
        ENGINE_API void ClearKilledComponents();

    private:
        PhysicsManager();
        ~PhysicsManager();
        PhysicsManager(PhysicsManager const&) = delete;
        void operator=(PhysicsManager const&) = delete;

        glm::vec3 gravity = glm::vec3(0.f, -9.82f, 0.f);

        ComponentContainer<Component::RigidBody> rigidBodyComponents;
        ComponentContainer<Component::Shape> shapeComponents;

        btBroadphaseInterface* broadphase = nullptr;
        btDefaultCollisionConfiguration* collisionConfiguration = nullptr;
        btCollisionDispatcher* dispatcher = nullptr;
        btSequentialImpulseConstraintSolver* solver = nullptr;
        btDiscreteDynamicsWorld* dynamicsWorld = nullptr;

        std::shared_ptr<Utility::LockBox<Physics::Trigger>::Key> triggerLockBoxKey;
        std::vector<::Physics::Trigger*> triggers;
};
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2011 Juergen Riegel <FreeCAD@juergen-riegel.net>        *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <Inventor/nodes/SoGroup.h>
#endif

#include "ViewProvider.h"
#include <ItemAssembly.h>
#include <Gui/Command.h>
//#include <Gui/Document.h>

using namespace AssemblyGui;

PROPERTY_SOURCE(AssemblyGui::ViewProviderItem,Gui::ViewProviderGeometryObject)

ViewProviderItem::ViewProviderItem()
{
    pcChildren = new SoGroup();
    pcChildren->ref();

}

ViewProviderItem::~ViewProviderItem()
{
    pcChildren->unref();
    pcChildren = 0;
}

bool ViewProviderItem::doubleClicked(void)
{
    return true;
}

<commit_msg>small fix<commit_after>/***************************************************************************
 *   Copyright (c) 2011 Juergen Riegel <FreeCAD@juergen-riegel.net>        *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <Inventor/nodes/SoGroup.h>
#endif

#include "ViewProvider.h"
#include <Item.h>
#include <Gui/Command.h>
//#include <Gui/Document.h>

using namespace AssemblyGui;

PROPERTY_SOURCE(AssemblyGui::ViewProviderItem,Gui::ViewProviderGeometryObject)

ViewProviderItem::ViewProviderItem()
{
    pcChildren = new SoGroup();
    pcChildren->ref();

}

ViewProviderItem::~ViewProviderItem()
{
    pcChildren->unref();
    pcChildren = 0;
}

bool ViewProviderItem::doubleClicked(void)
{
    return true;
}

<|endoftext|>


<commit_before>#include "DiceRoll/Operations/GetNumberOperation.hpp"

GetNumberOperation::GetNumberOperation(int number)
    : IOperation(nullptr), _number(number)
{
    _count = 0;
}

std::unique_ptr<RollResult> GetNumberOperation::evaluate()
{
    return execute();
}

std::unique_ptr<RollResult> GetNumberOperation::execute()
{
    _elements.push_back(_number);
    _count = 1;

    //For now, return dummy RollResult
    return std::make_unique<RollResult>();
}
<commit_msg>Replaced dummy RollResult in execute() with real one.<commit_after>#include "DiceRoll/Operations/GetNumberOperation.hpp"

GetNumberOperation::GetNumberOperation(int number)
    : IOperation(nullptr), _number(number)
{
    _count = 0;
}

std::unique_ptr<RollResult> GetNumberOperation::evaluate()
{
    return execute();
}

std::unique_ptr<RollResult> GetNumberOperation::execute()
{
    // DELETE THIS
    _elements.push_back(_number);
    _count = 1;
    // END OF DELETE

    //For now, return dummy RollResult
    auto result = std::make_unique<RollResult>();
    result->appendLastResult(_number);
    result->setOperationLog(std::to_string(_number));
    return result;
}
<|endoftext|>


<commit_before>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2014 Michael Fink
//
/// \file CameraInfoDlg.cpp Camera info dialog
//

// includes
#include "StdAfx.h"
#include "resource.h"
#include "CameraInfoDlg.hpp"
#include "Instance.hpp"
#include "CameraException.hpp"
#include "SourceDevice.hpp"
#include "RemoteReleaseControl.hpp"

LRESULT CameraInfoDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
   DoDataExchange(DDX_LOAD);

   CenterWindow(GetParent());

   DlgResize_Init(false, false);

   CString cszText;
   try
   {
      cszText = CollectCameraInfo();
   }
   catch(CameraException& ex)
   {
      cszText.AppendFormat(_T("\nError while collecting camera info: %s\n"), ex.Message().GetString());
   }

   cszText.Replace(_T("\n"), _T("\r\n"));
   m_ecCameraInfo.SetWindowText(cszText);

   return TRUE;
}

CString CameraInfoDlg::CollectCameraInfo()
{
   CString cszText;

   cszText = _T("Camera model: ") + m_sourceDevice.ModelName() + _T("\n");
   cszText += _T("Serial number: ") + m_sourceDevice.SerialNumber() + _T("\n\n");

   // get available device properties
   CollectDeviceProperties(cszText);

   // check if device supports remote release control
   if (!m_sourceDevice.GetDeviceCapability(SourceDevice::capRemoteReleaseControl))
   {
      cszText += _T("Camera doesn't support remote release control");
      return cszText;
   }

   std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl = m_sourceDevice.EnterReleaseControl();

   CollectCapabilities(spRemoteReleaseControl, cszText);
   CollectImageProperties(spRemoteReleaseControl, cszText);

   CollectShootingModeInfos(spRemoteReleaseControl, cszText);

   return cszText;
}

void CameraInfoDlg::CollectDeviceProperties(CString& cszText)
{
   cszText += _T("Supported device properties:\n");

   std::vector<unsigned int> vecProperties;
   try
   {
      vecProperties = m_sourceDevice.EnumDeviceProperties();
   }
   catch (CameraException& ex)
   {
      cszText.AppendFormat(_T("Error while enumerating device properties: %s\n"),
         ex.Message().GetString());
   }

   for (size_t i=0, iMax = vecProperties.size(); i<iMax; i++)
   {
      try
      {
         unsigned int uiPropertyId = vecProperties[i];
         DeviceProperty p = m_sourceDevice.GetDeviceProperty(uiPropertyId);

         cszText.AppendFormat(_T("Property %s (%08x): [%s]\n"),
            p.Name().GetString(), uiPropertyId, p.AsString().GetString());
      }
      catch(CameraException& ex)
      {
         cszText.AppendFormat(_T("Error while evaluating property %08x: %s\n"),
            vecProperties[i], ex.Message().GetString());
      }
   }

   cszText += _T("\n");
}

void CameraInfoDlg::CollectCapabilities(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, CString& cszText)
{
   cszText += _T("Remote release control capabilities:\n");

   cszText += _T("- can change shooting parameter: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capChangeShootingParameter) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("- can change shooting mode: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capChangeShootingMode) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("- can control zoom: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capZoomControl) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("- supports viewfinder: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capViewfinder) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("- can release while viewfinder is on: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capReleaseWhileViewfinder) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("- can lock/unlock AF: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capAFLock) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("\n");
}

void CameraInfoDlg::CollectImageProperties(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, CString& cszText)
{
   cszText += _T("Supported image properties:\n");

   std::vector<unsigned int> vecImageProperties = spRemoteReleaseControl->EnumImageProperties();

   if (vecImageProperties.empty())
   {
      cszText += _T("no image properties found.\n");
   }
   else
   for (size_t i=0,iMax=vecImageProperties.size(); i<iMax; i++)
   {
      unsigned int uiPropertyId = vecImageProperties[i];

      try
      {
         ImageProperty ip = spRemoteReleaseControl->GetImageProperty(uiPropertyId);

         cszText.AppendFormat(_T("Image property \"%s\" (%04x)%s: %s (%s)\n"),
            ip.Name().GetString(),
            uiPropertyId,
            ip.IsReadOnly() ? _T(" [read-only]") : _T(""),
            ip.Value().ToString().GetString(),
            ip.AsString().GetString());

         try
         {
            std::vector<ImageProperty> vecValues;
            spRemoteReleaseControl->EnumImagePropertyValues(vecImageProperties[i], vecValues);

            for (size_t j=0, jMax=vecValues.size(); j<jMax; j++)
            {
               const ImageProperty& ip2 = vecValues[j];
               cszText.AppendFormat(_T("   Valid value: %s (%s)\n"),
                  ip2.Value().ToString().GetString(),
                  ip.ValueAsString(ip2.Value()).GetString());
            }
         }
         catch (CameraException& ex)
         {
            cszText.AppendFormat(_T("Error while enumerating device property values for %08x: %s\n"),
               uiPropertyId, ex.Message().GetString());
         }
      }
      catch (CameraException& ex)
      {
         cszText.AppendFormat(_T("Error while getting device property %08x: %s\n"),
            uiPropertyId, ex.Message().GetString());
      }
   }

   cszText += _T("\n");
}

void CameraInfoDlg::CollectShootingModeInfos(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, CString& cszText)
{
   cszText += _T("Supported shooting modes:\n");

   try
   {
      if (!spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capChangeShootingMode))
      {
         cszText += _T("(Switching shooting modes not supported, can only dump current mode)\n");

         unsigned int uiShootingModePropertyId =
            spRemoteReleaseControl->MapImagePropertyTypeToId(T_enImagePropertyType::propShootingMode);

         // no, just dump current shooting mode
         ImageProperty currentShootingMode = spRemoteReleaseControl->GetImageProperty(uiShootingModePropertyId);

         CollectShootingModeDetails(spRemoteReleaseControl, currentShootingMode, cszText);
      }
      else
      {
      // switch through all shooting modes and dump
         std::vector<ImageProperty> vecShootingModes;
         unsigned int uiPropertyId = spRemoteReleaseControl->MapImagePropertyTypeToId(T_enImagePropertyType::propShootingMode);
         spRemoteReleaseControl->EnumImagePropertyValues(uiPropertyId, vecShootingModes);

         if (vecShootingModes.empty())
            cszText += _T("(No shooting modes found)\n");

         std::for_each(vecShootingModes.begin(), vecShootingModes.end(), [&](const ImageProperty& ip)
         {
            spRemoteReleaseControl->SetImageProperty(ip);

            CollectShootingModeDetails(spRemoteReleaseControl, ip, cszText);
         });
      }
   }
   catch (CameraException& ex)
   {
      cszText.AppendFormat(_T("Error while enumerating shooting modes: %s\n"),
         ex.Message().GetString());
   }
}

void CameraInfoDlg::CollectShootingModeDetails(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
   const ImageProperty& shootingMode, CString& cszText)
{
   cszText.AppendFormat(_T("Shooting mode: %s\n"), shootingMode.AsString().GetString());

   // get Av values
   {
      std::vector<ImageProperty> vecAvValues;
      unsigned int uiAvPropertyId = spRemoteReleaseControl->MapImagePropertyTypeToId(T_enImagePropertyType::propAv);

      try
      {
         spRemoteReleaseControl->EnumImagePropertyValues(uiAvPropertyId, vecAvValues);
      }
      catch(const CameraException& ex)
      {
         cszText.AppendFormat(_T("Error while enumerating Av values: %s\n"), ex.Message().GetString());
      }

      if (!vecAvValues.empty())
      {
         cszText += _T("  Available aperture values: ");
         for (size_t i=0, iMax=vecAvValues.size(); i<iMax; i++)
         {
            const ImageProperty& val = vecAvValues[i];

            cszText.AppendFormat(_T("%s%s"), i==0 ? _T("") : _T(", "), val.AsString().GetString());
         }
         cszText += _T("\n");
      }
   }

   // get Tv values
   {
      std::vector<ImageProperty> vecTvValues;
      unsigned int uiTvPropertyId = spRemoteReleaseControl->MapImagePropertyTypeToId(T_enImagePropertyType::propTv);

      try
      {
         spRemoteReleaseControl->EnumImagePropertyValues(uiTvPropertyId, vecTvValues);
      }
      catch(const CameraException& ex)
      {
         cszText.AppendFormat(_T("Exception while enumerating Tv values: %s\n"), ex.Message().GetString());
      }

      if (!vecTvValues.empty())
      {
         cszText += _T("  Available shutter speed values: ");
         for (size_t i=0, iMax=vecTvValues.size(); i<iMax; i++)
         {
            const ImageProperty& val = vecTvValues[i];

            cszText.AppendFormat(_T("%s%s"), i==0 ? _T("") : _T(", "), val.AsString().GetString());
         }
         cszText += _T("\n");
      }
   }

   // get exposure compensation values
   {
      std::vector<ImageProperty> vecEcValues;
      unsigned int uiEcPropertyId = spRemoteReleaseControl->MapImagePropertyTypeToId(T_enImagePropertyType::propExposureCompensation);

      try
      {
         spRemoteReleaseControl->EnumImagePropertyValues(uiEcPropertyId, vecEcValues);
      }
      catch(const CameraException& ex)
      {
         cszText.AppendFormat(_T("Error while enumerating exposure compensation values: %s\n"), ex.Message().GetString());
      }

      if (!vecEcValues.empty())
      {
         cszText += _T("  Available exposure compensation values: ");
         for (size_t i=0, iMax=vecEcValues.size(); i<iMax; i++)
         {
            const ImageProperty& val = vecEcValues[i];

            cszText.AppendFormat(_T("%s%s"), i==0 ? _T("") : _T(", "), val.AsString().GetString());
         }
         cszText += _T("\n");
      }
   }

   cszText += _T("\n");
}
<commit_msg>added missing remote capabilities in camera info dialog<commit_after>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2014 Michael Fink
//
/// \file CameraInfoDlg.cpp Camera info dialog
//

// includes
#include "StdAfx.h"
#include "resource.h"
#include "CameraInfoDlg.hpp"
#include "Instance.hpp"
#include "CameraException.hpp"
#include "SourceDevice.hpp"
#include "RemoteReleaseControl.hpp"

LRESULT CameraInfoDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
   DoDataExchange(DDX_LOAD);

   CenterWindow(GetParent());

   DlgResize_Init(false, false);

   CString cszText;
   try
   {
      cszText = CollectCameraInfo();
   }
   catch(CameraException& ex)
   {
      cszText.AppendFormat(_T("\nError while collecting camera info: %s\n"), ex.Message().GetString());
   }

   cszText.Replace(_T("\n"), _T("\r\n"));
   m_ecCameraInfo.SetWindowText(cszText);

   return TRUE;
}

CString CameraInfoDlg::CollectCameraInfo()
{
   CString cszText;

   cszText = _T("Camera model: ") + m_sourceDevice.ModelName() + _T("\n");
   cszText += _T("Serial number: ") + m_sourceDevice.SerialNumber() + _T("\n\n");

   // get available device properties
   CollectDeviceProperties(cszText);

   // check if device supports remote release control
   if (!m_sourceDevice.GetDeviceCapability(SourceDevice::capRemoteReleaseControl))
   {
      cszText += _T("Camera doesn't support remote release control");
      return cszText;
   }

   std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl = m_sourceDevice.EnterReleaseControl();

   CollectCapabilities(spRemoteReleaseControl, cszText);
   CollectImageProperties(spRemoteReleaseControl, cszText);

   CollectShootingModeInfos(spRemoteReleaseControl, cszText);

   return cszText;
}

void CameraInfoDlg::CollectDeviceProperties(CString& cszText)
{
   cszText += _T("Supported device properties:\n");

   std::vector<unsigned int> vecProperties;
   try
   {
      vecProperties = m_sourceDevice.EnumDeviceProperties();
   }
   catch (CameraException& ex)
   {
      cszText.AppendFormat(_T("Error while enumerating device properties: %s\n"),
         ex.Message().GetString());
   }

   for (size_t i=0, iMax = vecProperties.size(); i<iMax; i++)
   {
      try
      {
         unsigned int uiPropertyId = vecProperties[i];
         DeviceProperty p = m_sourceDevice.GetDeviceProperty(uiPropertyId);

         cszText.AppendFormat(_T("Property %s (%08x): [%s]\n"),
            p.Name().GetString(), uiPropertyId, p.AsString().GetString());
      }
      catch(CameraException& ex)
      {
         cszText.AppendFormat(_T("Error while evaluating property %08x: %s\n"),
            vecProperties[i], ex.Message().GetString());
      }
   }

   cszText += _T("\n");
}

void CameraInfoDlg::CollectCapabilities(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, CString& cszText)
{
   cszText += _T("Remote release control capabilities:\n");

   cszText += _T("- can change shooting parameter: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capChangeShootingParameter) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("- can change shooting mode: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capChangeShootingMode) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("- can control zoom: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capZoomControl) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("- supports viewfinder: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capViewfinder) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("- can release while viewfinder is on: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capReleaseWhileViewfinder) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("- can lock/unlock AF: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capAFLock) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("- can use Bulb mode: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capBulbMode) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("- can lock/unlock user interface: ");
   cszText += spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capUILock) ? _T("Yes") : _T("NO");
   cszText += _T("\n");

   cszText += _T("\n");
}

void CameraInfoDlg::CollectImageProperties(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, CString& cszText)
{
   cszText += _T("Supported image properties:\n");

   std::vector<unsigned int> vecImageProperties = spRemoteReleaseControl->EnumImageProperties();

   if (vecImageProperties.empty())
   {
      cszText += _T("no image properties found.\n");
   }
   else
   for (size_t i=0,iMax=vecImageProperties.size(); i<iMax; i++)
   {
      unsigned int uiPropertyId = vecImageProperties[i];

      try
      {
         ImageProperty ip = spRemoteReleaseControl->GetImageProperty(uiPropertyId);

         cszText.AppendFormat(_T("Image property \"%s\" (%04x)%s: %s (%s)\n"),
            ip.Name().GetString(),
            uiPropertyId,
            ip.IsReadOnly() ? _T(" [read-only]") : _T(""),
            ip.Value().ToString().GetString(),
            ip.AsString().GetString());

         try
         {
            std::vector<ImageProperty> vecValues;
            spRemoteReleaseControl->EnumImagePropertyValues(vecImageProperties[i], vecValues);

            for (size_t j=0, jMax=vecValues.size(); j<jMax; j++)
            {
               const ImageProperty& ip2 = vecValues[j];
               cszText.AppendFormat(_T("   Valid value: %s (%s)\n"),
                  ip2.Value().ToString().GetString(),
                  ip.ValueAsString(ip2.Value()).GetString());
            }
         }
         catch (CameraException& ex)
         {
            cszText.AppendFormat(_T("Error while enumerating device property values for %08x: %s\n"),
               uiPropertyId, ex.Message().GetString());
         }
      }
      catch (CameraException& ex)
      {
         cszText.AppendFormat(_T("Error while getting device property %08x: %s\n"),
            uiPropertyId, ex.Message().GetString());
      }
   }

   cszText += _T("\n");
}

void CameraInfoDlg::CollectShootingModeInfos(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl, CString& cszText)
{
   cszText += _T("Supported shooting modes:\n");

   try
   {
      if (!spRemoteReleaseControl->GetCapability(RemoteReleaseControl::capChangeShootingMode))
      {
         cszText += _T("(Switching shooting modes not supported, can only dump current mode)\n");

         unsigned int uiShootingModePropertyId =
            spRemoteReleaseControl->MapImagePropertyTypeToId(T_enImagePropertyType::propShootingMode);

         // no, just dump current shooting mode
         ImageProperty currentShootingMode = spRemoteReleaseControl->GetImageProperty(uiShootingModePropertyId);

         CollectShootingModeDetails(spRemoteReleaseControl, currentShootingMode, cszText);
      }
      else
      {
      // switch through all shooting modes and dump
         std::vector<ImageProperty> vecShootingModes;
         unsigned int uiPropertyId = spRemoteReleaseControl->MapImagePropertyTypeToId(T_enImagePropertyType::propShootingMode);
         spRemoteReleaseControl->EnumImagePropertyValues(uiPropertyId, vecShootingModes);

         if (vecShootingModes.empty())
            cszText += _T("(No shooting modes found)\n");

         std::for_each(vecShootingModes.begin(), vecShootingModes.end(), [&](const ImageProperty& ip)
         {
            spRemoteReleaseControl->SetImageProperty(ip);

            CollectShootingModeDetails(spRemoteReleaseControl, ip, cszText);
         });
      }
   }
   catch (CameraException& ex)
   {
      cszText.AppendFormat(_T("Error while enumerating shooting modes: %s\n"),
         ex.Message().GetString());
   }
}

void CameraInfoDlg::CollectShootingModeDetails(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl,
   const ImageProperty& shootingMode, CString& cszText)
{
   cszText.AppendFormat(_T("Shooting mode: %s\n"), shootingMode.AsString().GetString());

   // get Av values
   {
      std::vector<ImageProperty> vecAvValues;
      unsigned int uiAvPropertyId = spRemoteReleaseControl->MapImagePropertyTypeToId(T_enImagePropertyType::propAv);

      try
      {
         spRemoteReleaseControl->EnumImagePropertyValues(uiAvPropertyId, vecAvValues);
      }
      catch(const CameraException& ex)
      {
         cszText.AppendFormat(_T("Error while enumerating Av values: %s\n"), ex.Message().GetString());
      }

      if (!vecAvValues.empty())
      {
         cszText += _T("  Available aperture values: ");
         for (size_t i=0, iMax=vecAvValues.size(); i<iMax; i++)
         {
            const ImageProperty& val = vecAvValues[i];

            cszText.AppendFormat(_T("%s%s"), i==0 ? _T("") : _T(", "), val.AsString().GetString());
         }
         cszText += _T("\n");
      }
   }

   // get Tv values
   {
      std::vector<ImageProperty> vecTvValues;
      unsigned int uiTvPropertyId = spRemoteReleaseControl->MapImagePropertyTypeToId(T_enImagePropertyType::propTv);

      try
      {
         spRemoteReleaseControl->EnumImagePropertyValues(uiTvPropertyId, vecTvValues);
      }
      catch(const CameraException& ex)
      {
         cszText.AppendFormat(_T("Exception while enumerating Tv values: %s\n"), ex.Message().GetString());
      }

      if (!vecTvValues.empty())
      {
         cszText += _T("  Available shutter speed values: ");
         for (size_t i=0, iMax=vecTvValues.size(); i<iMax; i++)
         {
            const ImageProperty& val = vecTvValues[i];

            cszText.AppendFormat(_T("%s%s"), i==0 ? _T("") : _T(", "), val.AsString().GetString());
         }
         cszText += _T("\n");
      }
   }

   // get exposure compensation values
   {
      std::vector<ImageProperty> vecEcValues;
      unsigned int uiEcPropertyId = spRemoteReleaseControl->MapImagePropertyTypeToId(T_enImagePropertyType::propExposureCompensation);

      try
      {
         spRemoteReleaseControl->EnumImagePropertyValues(uiEcPropertyId, vecEcValues);
      }
      catch(const CameraException& ex)
      {
         cszText.AppendFormat(_T("Error while enumerating exposure compensation values: %s\n"), ex.Message().GetString());
      }

      if (!vecEcValues.empty())
      {
         cszText += _T("  Available exposure compensation values: ");
         for (size_t i=0, iMax=vecEcValues.size(); i<iMax; i++)
         {
            const ImageProperty& val = vecEcValues[i];

            cszText.AppendFormat(_T("%s%s"), i==0 ? _T("") : _T(", "), val.AsString().GetString());
         }
         cszText += _T("\n");
      }
   }

   cszText += _T("\n");
}
<|endoftext|>


<commit_before>//
//  main_menu_view.cc
//  AirHockey
//
//  Created by Jon Sharkey on 2010-04-30.
//  Copyright 2010 Sharkable. All rights reserved.
//

#include "airhockey/views/main_menu_view.h"

#include <map>
#include <sstream>
using std::map;
using std::string;

#include "gameengine/entities/simple_item.h"
#include "gameengine/modules/ad_engine.h"
#include "gameengine/modules/analytics_engine.h"
#include "gameengine/modules/local_store.h"
#include "gameengine/coordinate_types.h"
#include "gameengine/game_engine.h"
#include "gameengine/sprite.h"

#include "airhockey/entities/rink_overlay.h"
#include "airhockey/entities/sound_slider.h"
#include "airhockey/views/play_view.h"
#include "airhockey/views/settings_view.h"
#include "airhockey/views/story_view.h"

static const int kAnimateOutTicks = 15;

// Local Store keys
const string kLocalStoreMainMenuViewCount = "ls_main_menu_view_count";
const string kLocalStoreUpgraded = "ls_upgraded";

inline string to_string(int i) {
  std::stringstream ss;
  ss << i;
  return ss.str();
}

void fade_in(Animatable *entity) {
  entity->set_alpha(0);
  entity->AnimateToAlpha(1, kAnimationTypeLinear, 15);
}

void fade_out(Animatable *entity) {
  entity->AnimateToAlpha(0, kAnimationTypeLinear, 15);
}

MainMenuView::MainMenuView(GameEngine *game_engine) : EngineView(game_engine) {
  show_upgrade_button_ = game_engine->app_store_engine()->IsImplemented();
  supports_2_player_ = game_engine->platform_type() != kPlatformTypePC;

  InitializeSettings();
  state_ = kMainMenuStateRunning;

  rink_overlay_.reset(new RinkOverlay(game_engine));
  AddEntity(rink_overlay_);

  Sprite title_sprite(game_engine, "title");
  title_.reset(new SimpleItem(title_sprite, game_engine->position("title")));
  AddEntity(title_);
  title_->set_zoom(1.3);
  title_->AnimateToZoom(1, kAnimationTypeCubicEaseOut, 900);
  title_->set_alpha(0);
  title_->AnimateToAlpha(1, kAnimationTypeCubicEaseOut, 900);

  char const *start_button;
  char const *start_button_pressed;
  if (supports_2_player_) {
    start_button = "start_1_player_button";
    start_button_pressed = "start_1_player_button_pressed";
  } else {
    start_button = "start_button";
    start_button_pressed = "start_button_pressed";
  }
  Sprite start_1_player_button_image(game_engine, start_button);
  Sprite start_1_player_button_pressed_image(game_engine, start_button_pressed);
  start_1_player_button_.reset(new Button());
  start_1_player_button_->set_normal_sprite(start_1_player_button_image);
  start_1_player_button_->set_pressed_sprite(start_1_player_button_pressed_image);
  GamePoint player_1_position = game_engine->position("start_1_player_button");
  if (!show_upgrade_button_) {
    player_1_position.y += 90;
  }
  start_1_player_button_->set_position(player_1_position);
  start_1_player_button_->set_delegate(this);
  AddEntity(start_1_player_button_);
  fade_in(start_1_player_button_.get());

  if (supports_2_player_) {
    Sprite start_2_player_button_image(game_engine, "start_2_player_button");
    Sprite start_2_player_button_pressed_image(game_engine, "start_2_player_button_pressed");
    start_2_player_button_.reset(new Button());
    start_2_player_button_->set_normal_sprite(start_2_player_button_image);
    start_2_player_button_->set_pressed_sprite(start_2_player_button_pressed_image);
    GamePoint player_2_position = game_engine->position("start_2_player_button");
    if (!show_upgrade_button_) {
      player_2_position.y += 90;
    }
    start_2_player_button_->set_position(player_2_position);
    start_2_player_button_->set_delegate(this);
    AddEntity(start_2_player_button_);
    fade_in(start_2_player_button_.get());
  }

  Sprite settings_button_image(game_engine, "settings_button");
  Sprite settings_button_pressed_image(game_engine, "settings_button_pressed");
  settings_button_.reset(new Button());
  settings_button_->set_normal_sprite(settings_button_image);
  settings_button_->set_pressed_sprite(settings_button_pressed_image);
  settings_button_->set_position(game_engine->position("settings_button"));
  settings_button_->set_delegate(this);
  AddEntity(settings_button_);
  fade_in(settings_button_.get());

  Sprite story_button_image(game_engine, "story_button");
  Sprite story_button_pressed_image(game_engine, "story_button_pressed");
  story_button_.reset(new Button());
  story_button_->set_normal_sprite(story_button_image);
  story_button_->set_pressed_sprite(story_button_pressed_image);
  story_button_->set_position(game_engine->position("story_button"));
  story_button_->set_delegate(this);
  AddEntity(story_button_);
  fade_in(story_button_.get());

  if (show_upgrade_button_) {
    Sprite upgrade_button_image(game_engine, "upgrade_button");
    Sprite upgrade_button_pressed_image(game_engine, "upgrade_button_pressed");
    upgrade_button_.reset(new Button());
    upgrade_button_->set_normal_sprite(upgrade_button_image);
    upgrade_button_->set_pressed_sprite(upgrade_button_pressed_image);
    upgrade_button_->set_position(game_engine->position("upgrade_button"));
    upgrade_button_->set_delegate(this);
    if (!game_engine->local_store()->BoolForKey(kLocalStoreUpgraded)) {
      AddEntity(upgrade_button_);
    }
    fade_in(upgrade_button_.get());
  }

  sound_slider_.reset(new SoundSlider(game_engine,
                                      game_engine->position("sound_slider_main_menu")));
  AddEntity(sound_slider_);
}

// EngineView

void MainMenuView::ViewDidGainFocus() {
  if (show_upgrade_button_) {
    // Force the popup for rating and upgrading just once.
    int main_menu_view_count =
        game_engine()->local_store()->IntegerForKey(kLocalStoreMainMenuViewCount) + 1;
    game_engine()->local_store()->SetInteger(main_menu_view_count, kLocalStoreMainMenuViewCount);
    if (main_menu_view_count == 10) {
      PressedUpgrade();
    }
  }
}

void MainMenuView::Update() {
  EngineView::Update();
  if (state_ == kMainMenuStateAnimatingOut) {
    animating_out_ticks_left_--;
    // TODO This sometimes causes a brief overlap with the overlap in PlayView.
    if (animating_out_ticks_left_ == kAnimateOutTicks) {
      RemoveEntity(rink_overlay_);
    }
    if (animating_out_ticks_left_ <= 0) {
      game_engine()->RemoveView(this);
    }
  }
}

// AppStoreEngineDelegate

void MainMenuView::UpgradeSucceeded() {
  game_engine()->local_store()->SetBool(true, kLocalStoreUpgraded);
  RemoveEntity(upgrade_button_);
}

// ButtonDelegate

void MainMenuView::ButtonPressed(Button *button) {
  if (button == start_1_player_button_.get()) {
    PressedStart(1);
  } else if (button == start_2_player_button_.get()) {
    PressedStart(2);
  } else if (button == settings_button_.get()) {
    PressedSettings();
  } else if (button == story_button_.get()) {
    PressedStory();
  } else if (button == upgrade_button_.get()) {
    PressedUpgrade();
  }
}

// private

void MainMenuView::InitializeSettings() {
  if (!game_engine()->local_store()->HasEntryForKey(kLocalStoreDifficulty)) {
    game_engine()->local_store()->SetInteger(kComputerAIBad, kLocalStoreDifficulty);
    game_engine()->local_store()->SetInteger(kPaddleSizeLarge, kLocalStorePaddleSize);
  }
}

void MainMenuView::AnimateOut() {
  state_ = kMainMenuStateAnimatingOut;

  title_->AnimateToZoom(0, kAnimationTypeLinear, 15);
  fade_out(start_1_player_button_.get());
  if (supports_2_player_) {
    fade_out(start_2_player_button_.get());
  }
  fade_out(settings_button_.get());
  fade_out(story_button_.get());
  if (show_upgrade_button_) {
    fade_out(upgrade_button_.get());
  }
  RemoveEntity(sound_slider_);

  animating_out_ticks_left_ = kAnimateOutTicks;
}

void MainMenuView::PressedStart(int num_players) {
  if (game_engine()->platform_type() == kPlatformTypeTablet) {
    game_engine()->ad_engine()->RemoveAd();
  }

  // The stored number of pucks is one less than the desired value. Not ideal. This is for:
  // 1) Legacy.
  // 2) Defaults to 0, which means 1 puck.
  int num_pucks = game_engine()->local_store()->IntegerForKey(kLocalStoreNumPucks) + 1;
  ComputerAI difficulty =
      (ComputerAI)game_engine()->local_store()->IntegerForKey(kLocalStoreDifficulty);
  PaddleSize paddle_size =
      (PaddleSize)game_engine()->local_store()->IntegerForKey(kLocalStorePaddleSize);
  map<string, string> analytics_params;
  analytics_params["NumPlayers"] = to_string(num_players);
  analytics_params["NumPucks"] = to_string(num_pucks);
  analytics_params["Difficulty"] = to_string(difficulty);
  analytics_params["PaddleSize"] = to_string(paddle_size);
  game_engine()->analytics_engine()->LogEvent("START_GAME", analytics_params);

  PlayView *play_view = new PlayView(game_engine(),
                                     num_players,
                                     num_pucks,
                                     difficulty,
                                     paddle_size);
  AnimateOut();
  game_engine()->PushView(sp<EngineView>(play_view));
}

void MainMenuView::PressedSettings() {
  game_engine()->PushView(sp<SettingsView>(new SettingsView(game_engine())));
}

void MainMenuView::PressedStory() {
  game_engine()->analytics_engine()->LogEvent("STORY_PRESSED");
  if (game_engine()->platform_type() == kPlatformTypeTablet) {
    game_engine()->ad_engine()->RemoveAd();
  }
  game_engine()->PushView(sp<EngineView>(new StoryView(game_engine())));
}

void MainMenuView::PressedUpgrade() {
  if (!game_engine()->local_store()->BoolForKey(kLocalStoreUpgraded)) {
    game_engine()->app_store_engine()->AskForUpgrade("Glide Hockey HD", "GlideHockeyHDUpgrade",
                                                     this);
  }
}
<commit_msg>Default to medium paddle size on everything except a phone.<commit_after>//
//  main_menu_view.cc
//  AirHockey
//
//  Created by Jon Sharkey on 2010-04-30.
//  Copyright 2010 Sharkable. All rights reserved.
//

#include "airhockey/views/main_menu_view.h"

#include <map>
#include <sstream>
using std::map;
using std::string;

#include "gameengine/entities/simple_item.h"
#include "gameengine/modules/ad_engine.h"
#include "gameengine/modules/analytics_engine.h"
#include "gameengine/modules/local_store.h"
#include "gameengine/coordinate_types.h"
#include "gameengine/game_engine.h"
#include "gameengine/sprite.h"

#include "airhockey/entities/rink_overlay.h"
#include "airhockey/entities/sound_slider.h"
#include "airhockey/views/play_view.h"
#include "airhockey/views/settings_view.h"
#include "airhockey/views/story_view.h"

static const int kAnimateOutTicks = 15;

// Local Store keys
const string kLocalStoreMainMenuViewCount = "ls_main_menu_view_count";
const string kLocalStoreUpgraded = "ls_upgraded";

inline string to_string(int i) {
  std::stringstream ss;
  ss << i;
  return ss.str();
}

void fade_in(Animatable *entity) {
  entity->set_alpha(0);
  entity->AnimateToAlpha(1, kAnimationTypeLinear, 15);
}

void fade_out(Animatable *entity) {
  entity->AnimateToAlpha(0, kAnimationTypeLinear, 15);
}

MainMenuView::MainMenuView(GameEngine *game_engine) : EngineView(game_engine) {
  show_upgrade_button_ = game_engine->app_store_engine()->IsImplemented();
  supports_2_player_ = game_engine->platform_type() != kPlatformTypePC;

  InitializeSettings();
  state_ = kMainMenuStateRunning;

  rink_overlay_.reset(new RinkOverlay(game_engine));
  AddEntity(rink_overlay_);

  Sprite title_sprite(game_engine, "title");
  title_.reset(new SimpleItem(title_sprite, game_engine->position("title")));
  AddEntity(title_);
  title_->set_zoom(1.3);
  title_->AnimateToZoom(1, kAnimationTypeCubicEaseOut, 900);
  title_->set_alpha(0);
  title_->AnimateToAlpha(1, kAnimationTypeCubicEaseOut, 900);

  char const *start_button;
  char const *start_button_pressed;
  if (supports_2_player_) {
    start_button = "start_1_player_button";
    start_button_pressed = "start_1_player_button_pressed";
  } else {
    start_button = "start_button";
    start_button_pressed = "start_button_pressed";
  }
  Sprite start_1_player_button_image(game_engine, start_button);
  Sprite start_1_player_button_pressed_image(game_engine, start_button_pressed);
  start_1_player_button_.reset(new Button());
  start_1_player_button_->set_normal_sprite(start_1_player_button_image);
  start_1_player_button_->set_pressed_sprite(start_1_player_button_pressed_image);
  GamePoint player_1_position = game_engine->position("start_1_player_button");
  if (!show_upgrade_button_) {
    player_1_position.y += 90;
  }
  start_1_player_button_->set_position(player_1_position);
  start_1_player_button_->set_delegate(this);
  AddEntity(start_1_player_button_);
  fade_in(start_1_player_button_.get());

  if (supports_2_player_) {
    Sprite start_2_player_button_image(game_engine, "start_2_player_button");
    Sprite start_2_player_button_pressed_image(game_engine, "start_2_player_button_pressed");
    start_2_player_button_.reset(new Button());
    start_2_player_button_->set_normal_sprite(start_2_player_button_image);
    start_2_player_button_->set_pressed_sprite(start_2_player_button_pressed_image);
    GamePoint player_2_position = game_engine->position("start_2_player_button");
    if (!show_upgrade_button_) {
      player_2_position.y += 90;
    }
    start_2_player_button_->set_position(player_2_position);
    start_2_player_button_->set_delegate(this);
    AddEntity(start_2_player_button_);
    fade_in(start_2_player_button_.get());
  }

  Sprite settings_button_image(game_engine, "settings_button");
  Sprite settings_button_pressed_image(game_engine, "settings_button_pressed");
  settings_button_.reset(new Button());
  settings_button_->set_normal_sprite(settings_button_image);
  settings_button_->set_pressed_sprite(settings_button_pressed_image);
  settings_button_->set_position(game_engine->position("settings_button"));
  settings_button_->set_delegate(this);
  AddEntity(settings_button_);
  fade_in(settings_button_.get());

  Sprite story_button_image(game_engine, "story_button");
  Sprite story_button_pressed_image(game_engine, "story_button_pressed");
  story_button_.reset(new Button());
  story_button_->set_normal_sprite(story_button_image);
  story_button_->set_pressed_sprite(story_button_pressed_image);
  story_button_->set_position(game_engine->position("story_button"));
  story_button_->set_delegate(this);
  AddEntity(story_button_);
  fade_in(story_button_.get());

  if (show_upgrade_button_) {
    Sprite upgrade_button_image(game_engine, "upgrade_button");
    Sprite upgrade_button_pressed_image(game_engine, "upgrade_button_pressed");
    upgrade_button_.reset(new Button());
    upgrade_button_->set_normal_sprite(upgrade_button_image);
    upgrade_button_->set_pressed_sprite(upgrade_button_pressed_image);
    upgrade_button_->set_position(game_engine->position("upgrade_button"));
    upgrade_button_->set_delegate(this);
    if (!game_engine->local_store()->BoolForKey(kLocalStoreUpgraded)) {
      AddEntity(upgrade_button_);
    }
    fade_in(upgrade_button_.get());
  }

  sound_slider_.reset(new SoundSlider(game_engine,
                                      game_engine->position("sound_slider_main_menu")));
  AddEntity(sound_slider_);
}

// EngineView

void MainMenuView::ViewDidGainFocus() {
  if (show_upgrade_button_) {
    // Force the popup for rating and upgrading just once.
    int main_menu_view_count =
        game_engine()->local_store()->IntegerForKey(kLocalStoreMainMenuViewCount) + 1;
    game_engine()->local_store()->SetInteger(main_menu_view_count, kLocalStoreMainMenuViewCount);
    if (main_menu_view_count == 10) {
      PressedUpgrade();
    }
  }
}

void MainMenuView::Update() {
  EngineView::Update();
  if (state_ == kMainMenuStateAnimatingOut) {
    animating_out_ticks_left_--;
    // TODO This sometimes causes a brief overlap with the overlap in PlayView.
    if (animating_out_ticks_left_ == kAnimateOutTicks) {
      RemoveEntity(rink_overlay_);
    }
    if (animating_out_ticks_left_ <= 0) {
      game_engine()->RemoveView(this);
    }
  }
}

// AppStoreEngineDelegate

void MainMenuView::UpgradeSucceeded() {
  game_engine()->local_store()->SetBool(true, kLocalStoreUpgraded);
  RemoveEntity(upgrade_button_);
}

// ButtonDelegate

void MainMenuView::ButtonPressed(Button *button) {
  if (button == start_1_player_button_.get()) {
    PressedStart(1);
  } else if (button == start_2_player_button_.get()) {
    PressedStart(2);
  } else if (button == settings_button_.get()) {
    PressedSettings();
  } else if (button == story_button_.get()) {
    PressedStory();
  } else if (button == upgrade_button_.get()) {
    PressedUpgrade();
  }
}

// private

void MainMenuView::InitializeSettings() {
  if (!game_engine()->local_store()->HasEntryForKey(kLocalStoreDifficulty)) {
    game_engine()->local_store()->SetInteger(kComputerAIBad, kLocalStoreDifficulty);
    PaddleSize default_size = kPaddleSizeMedium;
    if (game_engine()->platform_type() == kPlatformTypePhone) {
      default_size = kPaddleSizeLarge;
    }
    game_engine()->local_store()->SetInteger(default_size, kLocalStorePaddleSize);
  }
}

void MainMenuView::AnimateOut() {
  state_ = kMainMenuStateAnimatingOut;

  title_->AnimateToZoom(0, kAnimationTypeLinear, 15);
  fade_out(start_1_player_button_.get());
  if (supports_2_player_) {
    fade_out(start_2_player_button_.get());
  }
  fade_out(settings_button_.get());
  fade_out(story_button_.get());
  if (show_upgrade_button_) {
    fade_out(upgrade_button_.get());
  }
  RemoveEntity(sound_slider_);

  animating_out_ticks_left_ = kAnimateOutTicks;
}

void MainMenuView::PressedStart(int num_players) {
  if (game_engine()->platform_type() == kPlatformTypeTablet) {
    game_engine()->ad_engine()->RemoveAd();
  }

  // The stored number of pucks is one less than the desired value. Not ideal. This is for:
  // 1) Legacy.
  // 2) Defaults to 0, which means 1 puck.
  int num_pucks = game_engine()->local_store()->IntegerForKey(kLocalStoreNumPucks) + 1;
  ComputerAI difficulty =
      (ComputerAI)game_engine()->local_store()->IntegerForKey(kLocalStoreDifficulty);
  PaddleSize paddle_size =
      (PaddleSize)game_engine()->local_store()->IntegerForKey(kLocalStorePaddleSize);
  map<string, string> analytics_params;
  analytics_params["NumPlayers"] = to_string(num_players);
  analytics_params["NumPucks"] = to_string(num_pucks);
  analytics_params["Difficulty"] = to_string(difficulty);
  analytics_params["PaddleSize"] = to_string(paddle_size);
  game_engine()->analytics_engine()->LogEvent("START_GAME", analytics_params);

  PlayView *play_view = new PlayView(game_engine(),
                                     num_players,
                                     num_pucks,
                                     difficulty,
                                     paddle_size);
  AnimateOut();
  game_engine()->PushView(sp<EngineView>(play_view));
}

void MainMenuView::PressedSettings() {
  game_engine()->PushView(sp<SettingsView>(new SettingsView(game_engine())));
}

void MainMenuView::PressedStory() {
  game_engine()->analytics_engine()->LogEvent("STORY_PRESSED");
  if (game_engine()->platform_type() == kPlatformTypeTablet) {
    game_engine()->ad_engine()->RemoveAd();
  }
  game_engine()->PushView(sp<EngineView>(new StoryView(game_engine())));
}

void MainMenuView::PressedUpgrade() {
  if (!game_engine()->local_store()->BoolForKey(kLocalStoreUpgraded)) {
    game_engine()->app_store_engine()->AskForUpgrade("Glide Hockey HD", "GlideHockeyHDUpgrade",
                                                     this);
  }
}
<|endoftext|>