<commit_before>// For conditions of distribution and use, see copyright notice in license.txt
// Based on Mesmerizer.cs in libopenmetaverse

/*
 * Copyright (c) 2008, openmetaverse.org
 * All rights reserved.
 *
 * - Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * - Neither the name of the openmetaverse.org nor the names
 *   of its contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * This code comes from the OpenSim project. Meshmerizer is written by dahlia
 * <dahliatrimble@gmail.com>
 */

#include "StableHeaders.h"
#include "PrimMesher.h"
#include "RexTypes.h"
#include "RexLogicModule.h"
#include "EC_OpenSimPrim.h"
#include "../OgreRenderingModule/OgreMaterialUtils.h"

#include <Ogre.h>

namespace RexLogic
{
    void CreatePrimGeometry(Ogre::ManualObject* object, EC_OpenSimPrim& primitive)
    {
        try
        {
            float profileBegin = primitive.ProfileBegin;
            float profileEnd = 1.0f - primitive.ProfileEnd;
            float profileHollow = primitive.ProfileHollow;

            int sides = 4;
            if ((primitive.ProfileCurve & 0x07) == RexTypes::SHAPE_EQUILATERAL_TRIANGLE)
                sides = 3;
            else if ((primitive.ProfileCurve & 0x07) == RexTypes::SHAPE_CIRCLE)
                sides = 24;
            else if ((primitive.ProfileCurve & 0x07) == RexTypes::SHAPE_HALF_CIRCLE)
            {
                // half circle, prim is a sphere
                sides = 24;

                profileBegin = 0.5f * profileBegin + 0.5f;
                profileEnd = 0.5f * profileEnd + 0.5f;
            }

            int hollowSides = sides;
            if ((primitive.ProfileCurve & 0xf0) == RexTypes::HOLLOW_CIRCLE)
                hollowSides = 24;
            else if ((primitive.ProfileCurve & 0xf0) == RexTypes::HOLLOW_SQUARE)
                hollowSides = 4;
            else if ((primitive.ProfileCurve & 0xf0) == RexTypes::HOLLOW_TRIANGLE)
                hollowSides = 3;

            PrimMesher::PrimMesh primMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);
            primMesh.topShearX = primitive.PathShearX;
            primMesh.topShearY = primitive.PathShearY;
            primMesh.pathCutBegin = primitive.PathBegin;
            primMesh.pathCutEnd = 1.0f - primitive.PathEnd;

            if (primitive.PathCurve == RexTypes::EXTRUSION_STRAIGHT)
            {
                primMesh.twistBegin = primitive.PathTwistBegin * 180;
                primMesh.twistEnd = primitive.PathTwist * 180;
                primMesh.taperX = primitive.PathScaleX - 1.0f;
                primMesh.taperY = primitive.PathScaleY - 1.0f;
                primMesh.ExtrudeLinear();
            }
            else
            {
                primMesh.holeSizeX = (2.0f - primitive.PathScaleX);
                primMesh.holeSizeY = (2.0f - primitive.PathScaleY);
                primMesh.radius = primitive.PathRadiusOffset;
                primMesh.revolutions = primitive.PathRevolutions;
                primMesh.skew = primitive.PathSkew;
                primMesh.twistBegin = primitive.PathTwistBegin * 360;
                primMesh.twistEnd = primitive.PathTwist * 360;
                primMesh.taperX = primitive.PathTaperX;
                primMesh.taperY = primitive.PathTaperY;
                primMesh.ExtrudeCircular();
            }

            if (object)
            {
                object->clear();

                RexTypes::RexUUID tex_id;
                RexTypes::RexUUID prev_tex_id;

                Core::uint indices = 0;

                for (Core::uint i = 0; i < primMesh.viewerFaces.size(); ++i)
                {
                    // Here we assume (again) that material name = texture UUID in text form
                    //! \todo handle material override if prim is using material script

                    // Try to find face's texture in texturemap, use default if not found
                    tex_id = primitive.PrimDefaultTexture;
                    TextureMap::const_iterator t = primitive.PrimTextures.find(primMesh.viewerFaces[i].primFaceNumber);
                    if (t != primitive.PrimTextures.end())
                        tex_id = t->second;

                    if ((i == 0) || (tex_id != prev_tex_id))
                    {
                        // Fill the indices of previous subsection before beginning new
                        if (indices)
                        {
                            for (Core::uint j = 0; j < indices; j += 3)
                            {
                                object->index(j);
                                object->index(j+1);
                                object->index(j+2);
                            }
                            indices = 0;
                            object->end();
                        }

                        std::string mat_name = tex_id.ToString();
                        // Actually create the material here if texture yet missing, we'll fill later
                        OgreRenderer::GetOrCreateUnlitTexturedMaterial(mat_name.c_str());

                        object->begin(mat_name);
                    }
                    prev_tex_id = tex_id;

                    Ogre::Vector3 pos1(primMesh.viewerFaces[i].v1.X, primMesh.viewerFaces[i].v1.Y, primMesh.viewerFaces[i].v1.Z);
                    Ogre::Vector3 pos2(primMesh.viewerFaces[i].v2.X, primMesh.viewerFaces[i].v2.Y, primMesh.viewerFaces[i].v2.Z);
                    Ogre::Vector3 pos3(primMesh.viewerFaces[i].v3.X, primMesh.viewerFaces[i].v3.Y, primMesh.viewerFaces[i].v3.Z);

                    Ogre::Vector3 n1(primMesh.viewerFaces[i].n1.X, primMesh.viewerFaces[i].n1.Y, primMesh.viewerFaces[i].n1.Z);
                    Ogre::Vector3 n2(primMesh.viewerFaces[i].n2.X, primMesh.viewerFaces[i].n2.Y, primMesh.viewerFaces[i].n2.Z);
                    Ogre::Vector3 n3(primMesh.viewerFaces[i].n3.X, primMesh.viewerFaces[i].n3.Y, primMesh.viewerFaces[i].n3.Z);

                    Ogre::Vector2 uv1(primMesh.viewerFaces[i].uv1.U, primMesh.viewerFaces[i].uv1.V);
                    Ogre::Vector2 uv2(primMesh.viewerFaces[i].uv2.U, primMesh.viewerFaces[i].uv2.V);
                    Ogre::Vector2 uv3(primMesh.viewerFaces[i].uv3.U, primMesh.viewerFaces[i].uv3.V);

                    object->position(pos1);
                    object->normal(n1);
                    object->textureCoord(uv1);

                    object->position(pos2);
                    object->normal(n2);
                    object->textureCoord(uv2);

                    object->position(pos3);
                    object->normal(n3);
                    object->textureCoord(uv3);
                    indices += 3;
                }

                // Fill the indices of last subsection
                if (indices)
                {
                    for (Core::uint j = 0; j < indices; j += 3)
                    {
                        object->index(j);
                        object->index(j+1);
                        object->index(j+2);
                    }
                    indices = 0;
                    object->end();
                }
            }
            else
            {
                RexLogicModule::LogError(std::string("Null manualobject passed to CreatePrimGeometry"));
            }
        }
        catch (Core::Exception& e)
        {
            RexLogicModule::LogError(std::string("Exception while creating primitive geometry: ") + e.what());
        }
    }
}<commit_msg>Added todo item about probable cause of random crashes.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt
// Based on Mesmerizer.cs in libopenmetaverse

/*
 * Copyright (c) 2008, openmetaverse.org
 * All rights reserved.
 *
 * - Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * - Neither the name of the openmetaverse.org nor the names
 *   of its contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * This code comes from the OpenSim project. Meshmerizer is written by dahlia
 * <dahliatrimble@gmail.com>
 */

#include "StableHeaders.h"
#include "PrimMesher.h"
#include "RexTypes.h"
#include "RexLogicModule.h"
#include "EC_OpenSimPrim.h"
#include "../OgreRenderingModule/OgreMaterialUtils.h"

#include <Ogre.h>

namespace RexLogic
{
    void CreatePrimGeometry(Ogre::ManualObject* object, EC_OpenSimPrim& primitive)
    {
        try
        {
            float profileBegin = primitive.ProfileBegin;
            float profileEnd = 1.0f - primitive.ProfileEnd;
            float profileHollow = primitive.ProfileHollow;

            int sides = 4;
            if ((primitive.ProfileCurve & 0x07) == RexTypes::SHAPE_EQUILATERAL_TRIANGLE)
                sides = 3;
            else if ((primitive.ProfileCurve & 0x07) == RexTypes::SHAPE_CIRCLE)
                sides = 24;
            else if ((primitive.ProfileCurve & 0x07) == RexTypes::SHAPE_HALF_CIRCLE)
            {
                // half circle, prim is a sphere
                sides = 24;

                profileBegin = 0.5f * profileBegin + 0.5f;
                profileEnd = 0.5f * profileEnd + 0.5f;
            }

            int hollowSides = sides;
            if ((primitive.ProfileCurve & 0xf0) == RexTypes::HOLLOW_CIRCLE)
                hollowSides = 24;
            else if ((primitive.ProfileCurve & 0xf0) == RexTypes::HOLLOW_SQUARE)
                hollowSides = 4;
            else if ((primitive.ProfileCurve & 0xf0) == RexTypes::HOLLOW_TRIANGLE)
                hollowSides = 3;

            RexLogicModule::LogInfo("PrimMesher::PrimMesh");
            //! \todo probably cause of random crash -cm
            PrimMesher::PrimMesh primMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);
            primMesh.topShearX = primitive.PathShearX;
            primMesh.topShearY = primitive.PathShearY;
            primMesh.pathCutBegin = primitive.PathBegin;
            primMesh.pathCutEnd = 1.0f - primitive.PathEnd;

            if (primitive.PathCurve == RexTypes::EXTRUSION_STRAIGHT)
            {
                primMesh.twistBegin = primitive.PathTwistBegin * 180;
                primMesh.twistEnd = primitive.PathTwist * 180;
                primMesh.taperX = primitive.PathScaleX - 1.0f;
                primMesh.taperY = primitive.PathScaleY - 1.0f;
                primMesh.ExtrudeLinear();
            }
            else
            {
                primMesh.holeSizeX = (2.0f - primitive.PathScaleX);
                primMesh.holeSizeY = (2.0f - primitive.PathScaleY);
                primMesh.radius = primitive.PathRadiusOffset;
                primMesh.revolutions = primitive.PathRevolutions;
                primMesh.skew = primitive.PathSkew;
                primMesh.twistBegin = primitive.PathTwistBegin * 360;
                primMesh.twistEnd = primitive.PathTwist * 360;
                primMesh.taperX = primitive.PathTaperX;
                primMesh.taperY = primitive.PathTaperY;
                primMesh.ExtrudeCircular();
            }
            // Doesn't get here in case of crash, see above todo

            RexLogicModule::LogInfo("Object begin.");

            if (object)
            {
                object->clear();

                RexTypes::RexUUID tex_id;
                RexTypes::RexUUID prev_tex_id;

                Core::uint indices = 0;

                for (Core::uint i = 0; i < primMesh.viewerFaces.size(); ++i)
                {
                    // Here we assume (again) that material name = texture UUID in text form
                    //! \todo handle material override if prim is using material script

                    // Try to find face's texture in texturemap, use default if not found
                    tex_id = primitive.PrimDefaultTexture;
                    TextureMap::const_iterator t = primitive.PrimTextures.find(primMesh.viewerFaces[i].primFaceNumber);
                    if (t != primitive.PrimTextures.end())
                        tex_id = t->second;

                    if ((i == 0) || (tex_id != prev_tex_id))
                    {
                        // Fill the indices of previous subsection before beginning new
                        if (indices)
                        {
                            for (Core::uint j = 0; j < indices; j += 3)
                            {
                                object->index(j);
                                object->index(j+1);
                                object->index(j+2);
                            }
                            indices = 0;
                            object->end();
                        }

                        std::string mat_name = tex_id.ToString();
                        // Actually create the material here if texture yet missing, we'll fill later
                        OgreRenderer::GetOrCreateUnlitTexturedMaterial(mat_name.c_str());

                        object->begin(mat_name);
                    }
                    prev_tex_id = tex_id;

                    Ogre::Vector3 pos1(primMesh.viewerFaces[i].v1.X, primMesh.viewerFaces[i].v1.Y, primMesh.viewerFaces[i].v1.Z);
                    Ogre::Vector3 pos2(primMesh.viewerFaces[i].v2.X, primMesh.viewerFaces[i].v2.Y, primMesh.viewerFaces[i].v2.Z);
                    Ogre::Vector3 pos3(primMesh.viewerFaces[i].v3.X, primMesh.viewerFaces[i].v3.Y, primMesh.viewerFaces[i].v3.Z);

                    Ogre::Vector3 n1(primMesh.viewerFaces[i].n1.X, primMesh.viewerFaces[i].n1.Y, primMesh.viewerFaces[i].n1.Z);
                    Ogre::Vector3 n2(primMesh.viewerFaces[i].n2.X, primMesh.viewerFaces[i].n2.Y, primMesh.viewerFaces[i].n2.Z);
                    Ogre::Vector3 n3(primMesh.viewerFaces[i].n3.X, primMesh.viewerFaces[i].n3.Y, primMesh.viewerFaces[i].n3.Z);

                    Ogre::Vector2 uv1(primMesh.viewerFaces[i].uv1.U, primMesh.viewerFaces[i].uv1.V);
                    Ogre::Vector2 uv2(primMesh.viewerFaces[i].uv2.U, primMesh.viewerFaces[i].uv2.V);
                    Ogre::Vector2 uv3(primMesh.viewerFaces[i].uv3.U, primMesh.viewerFaces[i].uv3.V);

                    object->position(pos1);
                    object->normal(n1);
                    object->textureCoord(uv1);

                    object->position(pos2);
                    object->normal(n2);
                    object->textureCoord(uv2);

                    object->position(pos3);
                    object->normal(n3);
                    object->textureCoord(uv3);
                    indices += 3;
                }

                // Fill the indices of last subsection
                if (indices)
                {
                    for (Core::uint j = 0; j < indices; j += 3)
                    {
                        object->index(j);
                        object->index(j+1);
                        object->index(j+2);
                    }
                    indices = 0;
                    object->end();
                }
            }
            else
            {
                RexLogicModule::LogError(std::string("Null manualobject passed to CreatePrimGeometry"));
            }
        }
        catch (Core::Exception& e)
        {
            RexLogicModule::LogError(std::string("Exception while creating primitive geometry: ") + e.what());
        }
    }
}<|endoftext|>


<commit_before>#include "ros/ros.h"
#include <math.h>
#include "geometry_msgs/Twist.h"
#include "std_msgs/String.h"
#include "nav_msgs/Odometry.h"
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

//Parameters
float v_max = 0.6;
float a_max = 0.8;
float a_max_p = 0.06;
double wait_period = 20;

//Common
bool bool_turn = false;
double angle_diff = 45;
bool calculate_turn = false;
bool first_run = true;
float vx_4 = v_max;
float az_4 = 0.0;
double time_begin_4 = 0;
double z_target_4 = 0;
char prev_4 = '0';
bool start_turn_4 = false;
bool quad_top_turn_4 = false;
bool is_turning_4 = false;

double time_begin_5 = 0;
double time_begin_6 = 0;
double time_begin_7 = 0;
double time_begin_8 = 0;
double time_begin_9 = 0;
double time_begin_10 = 0;
double time_begin_11= 0;
double time_begin_12 = 0;
double time_begin_13 = 0;

class Controller
{
  ros::NodeHandle n;
  ros::Publisher vel_pub_4;
  ros::Subscriber odom_sub_4;

  ros::Subscriber contact_sub;

public:
  Controller()
  {
    vel_pub_4 = n.advertise<geometry_msgs::Twist>("/robot4/cmd_vel", 1);
    odom_sub_4 = n.subscribe("/robot4/odom", 10, &Controller::odomCb,this);
  }
  ~Controller()
  {

  }

  struct Quaternionm
  {
      double w, x, y, z;
  };

    void GetEulerAngles(Quaternionm q, double& yaw, double& pitch, double& roll)
  {
      const double w2 = q.w*q.w;
      const double x2 = q.x*q.x;
      const double y2 = q.y*q.y;
      const double z2 = q.z*q.z;
      const double unitLength = w2 + x2 + y2 + z2;    // Normalised == 1, otherwise correction divisor.
      const double abcd = q.w*q.x + q.y*q.z;
      const double eps = 1e-7;    // TODO: pick from your math lib instead of hardcoding.
      const double pi = 3.14159265358979323846;   // TODO: pick from your math lib instead of hardcoding.
      if (abcd > (0.5-eps)*unitLength)
      {
          yaw = 2 * atan2(q.y, q.w);
          pitch = pi;
          roll = 0;
      }
      else if (abcd < (-0.5+eps)*unitLength)
      {
          yaw = -2 * ::atan2(q.y, q.w);
          pitch = -pi;
          roll = 0;
      }
      else
      {
          const double adbc = q.w*q.z - q.x*q.y;
          const double acbd = q.w*q.y - q.x*q.z;
          yaw = ::atan2(2*adbc, 1 - 2*(z2+x2));
          pitch = ::asin(2*abcd/unitLength);
          roll = ::atan2(2*acbd, 1 - 2*(y2+x2));
      }
  }

int add_multiple_error(int times)
  {
    int error = 0;
    for (int i = 0; i<times; i++)
    {
      error += rand() % 20 - 9;
    }
    return error;
  }

   void publish_velocity(std::string identification)
  {
    if(identification == "robot4/odom")
    {
      geometry_msgs::Twist command;
      command.linear.x = vx_4;
      command.angular.z = az_4;
      command.linear.y = command.linear.z = command.angular.x = command.angular.y = 0;
      vel_pub_4.publish(command);
    }

  }

  void odomCb(const nav_msgs::Odometry::ConstPtr& msg)
  {
    float *vx;
    double *z_target;
    float *az;
    double *time_begin;
    bool *start_turn;
    bool *quad_top_turn;
    bool *is_turning;

    Quaternionm myq;
    double yaw = 0;
    double pitch = 0;
    double roll = 0;
    myq.x = msg->pose.pose.orientation.x;
    myq.y = msg->pose.pose.orientation.y;
    myq.z = msg->pose.pose.orientation.z;
    myq.w = msg->pose.pose.orientation.w;
    GetEulerAngles(myq, yaw, pitch, roll);

    if(msg->header.frame_id == "robot4/odom")
    {
      vx = &vx_4;
      z_target = &z_target_4;
      az = &az_4;
      time_begin = &time_begin_4;
      start_turn = &start_turn_4;
      quad_top_turn = &quad_top_turn_4;
      is_turning = &is_turning_4;
    }

    std::string Caller = "";

    double diff = *z_target - yaw;
    diff = fabs(diff);
    double time_present = ros::Time::now().toSec();
    //ROS_INFO("time_present: %lf, time_begin: %lf, roll: %lf",time_present,time_begin,diff);
    if(diff > 0.13490 && *is_turning == true)
    {
      *time_begin = time_present;
      *vx = 0;
      *az = a_max;
    }
    else if(diff < 0.13490 && *is_turning == true)
    {
      *is_turning = false;
      *vx = v_max;
      *az = 0;
    }

    if(!*is_turning)
    {
      *vx = v_max;
      *az = 0;
    }

    if((time_present - *time_begin) > wait_period)
    {
      angle_diff = 45 + add_multiple_error(4);
      calculate_turn = true;
      Caller = "time";
    }

    if(*start_turn == true)
    {
      angle_diff = 180 + add_multiple_error(4);
      calculate_turn = true;
      *start_turn = false;
      Caller = "base";
    }

    if(*quad_top_turn == true)
    {
      angle_diff = 45 + add_multiple_error(4);
      calculate_turn = true;
      *quad_top_turn = false;
      Caller = "top";
    }

    if(calculate_turn)
    {
      *is_turning = true;

      double turn_angle = (angle_diff*3.141592)/180;
      *z_target = yaw - turn_angle;
      if(*z_target > 3.14)
      {
        *z_target = 2*3.14 - *z_target;
      }
      else if(*z_target < -3.14)
      {
        *z_target = 2*3.14 + *z_target;
      }
      //ROS_INFO("target: %lf",z_target);
      *time_begin = time_present;
      calculate_turn = false;
      *vx = -v_max*5;
    }
    publish_velocity(msg->header.frame_id);
  }

};

int main(int argc, char** argv)
{
  ros::init(argc, argv, "CreateController");
  Controller ic;
  time_begin_4 = time_begin_5 = time_begin_6 = time_begin_7 = time_begin_8 = time_begin_9 = time_begin_10 = time_begin_11 = time_begin_12 = time_begin_13 = ros::Time::now().toSec();
  srand (time(NULL));
  ros::spin();
return 0;
}

<commit_msg>Delete groundbot.cpp<commit_after><|endoftext|>


<commit_before>#include <cmath>
#include <algorithm>

#include "systems/movementsystem.h"
#include "cli_mousecmd.h"
#include "cli_stopmoving.h"
#include "cmapserver.h"
#include "packetfactory.h"
#include "srv_mousecmd.h"
#include "srv_stopmoving.h"
#include "srv_adjustposition.h"
#include "srv_switchserver.h"
#include "config.h"
#include "cmapclient.h"

using namespace Systems;
using namespace RoseCommon;

MovementSystem::MovementSystem(SystemManager &manager) : System(manager) {
  manager.registerDispatcher(ePacketType::PAKCS_MOUSE_CMD, &MovementSystem::processMove);
  manager.registerDispatcher(ePacketType::PAKCS_STOP_MOVING, &MovementSystem::stopMoving);
  manager.getEntityManager().on_component_removed<Destination>([this](Entity entity, Destination *dest) {
    if (!entity) return;
    if (auto client = getClient(entity))
      manager_.SendPacket(client, CMapServer::eSendType::NEARBY,
                                             *makePacket<ePacketType::PAKWC_STOP_MOVING>(entity));
    // TODO: check what type entity.component<BasicInfo>()->targetId_ is and execute corresponding action (npc talk, attack, item pickup...)
  });
  manager.getEntityManager().on_component_added<Position>([this](Entity entity, Position*) {
      updatePosition(entity);
  });
}

void MovementSystem::update(EntityManager &es, double dt) {
  for (Entity entity : es.entities_with_components<Position, Destination, AdvancedInfo>()) {
    Position *position = entity.component<Position>();
    Destination *destination = entity.component<Destination>();
    AdvancedInfo *advanced = entity.component<AdvancedInfo>();
    float dx = destination->x_ - position->x_;
    float dy = destination->y_ - position->y_;
    float distance = std::sqrt(dx * dx + dy * dy);
    destination->dist_ = distance;
    float speed = advanced->runSpeed_;
    float ntime = distance / speed;
    float old_x = position->x_;
    float old_y = position->y_;
    if (ntime <= dt || distance == 0) {
      position->x_ = destination->x_;
      position->y_ = destination->y_;
      entity.remove<Destination>();
    } else {
      position->x_ += dx * dt / ntime;
      position->y_ += dy * dt / ntime;
    }
    updatePosition(entity, old_x, old_y);
    if (Entity e = is_on_warpgate(entity); e) {
        auto dest = e.component<Destination>();
        teleport(entity, dest->dist_, dest->x_, dest->y_);
    }
  }
}

void MovementSystem::move(Entity entity, float x, float y, uint16_t target) {
  if (!entity) return;
  auto dest = entity.component<Destination>();
  auto pos = entity.component<Position>();
  float dx = pos->x_ - x;
  float dy = pos->y_ - y;
  float dist = std::sqrt(dx * dx + dy * dy);
  if (dest) {
    dest->x_ = x;
    dest->y_ = y;
    dest->dist_ = dist;
  } else {
    entity.assign<Destination>(x, y, dist);
  }
  entity.component<BasicInfo>()->targetId_ = target;
  // FIXME: what happens if the entity is an NPC or a monster?
  if (auto client = getClient(entity))
    manager_.SendPacket(client, CMapServer::eSendType::EVERYONE, *makePacket<ePacketType::PAKWC_MOUSE_CMD>(entity));
}

void MovementSystem::stop(Entity entity, float x, float y) {
  if (!entity || !entity.component<BasicInfo>()) return;
  entity.remove<Destination>();
  auto position = entity.component<Position>();
  if (position) {
    float dx = position->x_ - x;
    float dy = position->y_ - y;
    if (dx * dx + dy * dy < POSITION_CHEATING) {
      position->x_ = x;
      position->y_ = y;
    } else
      logger_->warn("Player {} attempted to cheat his position : calculated position : ({}, {}), got ({}, {})",
                    getId(entity), position->x_, position->y_, x, y);
  }
}

void MovementSystem::processMove(CMapClient &, Entity entity, const CliMouseCmd &packet) {
  logger_->trace("MovementSystem::processMove");
  if (!entity.component<Position>() || !entity.component<BasicInfo>()) return;
  move(entity, packet.x(), packet.y(), packet.targetId());
}

void MovementSystem::stopMoving(CMapClient &, Entity entity, const CliStopMoving &packet) {
  logger_->trace("MovementSystem::stopMoving");
  stop(entity, packet.x(), packet.y());
}

void MovementSystem::teleport(Entity entity, uint16_t map_id, float x, float y) {
    logger_->trace("MovementSystem::teleport");
    logger_->debug("Teleporting {} to {} {} {}", getId(entity), map_id, x, y);
    entity.component<BasicInfo>()->targetId_ = 0; // to avoid doing anything in the destination callback
    entity.remove<Destination>();
    auto pos = entity.component<Position>();
    pos->x_ = x;
    pos->y_ = y;
    if (pos->map_ == map_id) {
        manager_.SendPacket(getClient(entity), CMapServer::eSendType::EVERYONE,
                            *makePacket<ePacketType::PAKWC_ADJUST_POSITION>(entity));
    } else {
        if (auto client = getClient(entity)) {
            auto &config = Core::Config::getInstance();
            client->switch_server();
            client->send(*makePacket<ePacketType::PAKCC_SWITCH_SERVER>(
                config.mapServer().clientPort + map_id,
                client->get_session_id(),
                0,
                config.serverData().ip));
        }
    }
}

namespace {
constexpr std::tuple<uint16_t, uint16_t> get_grid_position(float x, float y) {
    uint16_t gx = x / 1000.f;
    uint16_t gy = y / 1000.f;
    return {gx, gy};
}

std::tuple<uint16_t, uint16_t> get_grid_position(Entity e) {
    auto pos = e.component<Position>();
    return get_grid_position(pos->x_, pos->y_);
}
}

bool MovementSystem::is_nearby(Entity a, Entity b) const {
    auto pos_a = get_grid_position(a);
    auto pos_b = get_grid_position(b);
    if (std::abs(std::get<0>(pos_a) - std::get<0>(pos_b)) <= 1
        && std::abs(std::get<1>(pos_a) - std::get<1>(pos_b)) <= 1)
        return true;
    return false;
}

void MovementSystem::updatePosition(Entity e, float old_x, float old_y) {
    if (old_x && old_y) {
        auto &list = grid[get_grid_position(old_x, old_y)];
        std::remove(list.begin(), list.end(), e);
    }
    grid[get_grid_position(e)].push_back(e);
}

Entity MovementSystem::is_on_warpgate(Entity e) {
    auto pos = e.component<Position>();
    for (auto &it : grid[get_grid_position(e)]) {
        if (it.component<Warpgate>()) continue; // skip non warpgates
        auto warp_pos = it.component<Position>();
        float dx = pos->x_ - warp_pos->x_;
        float dy = pos->x_ - warp_pos->y_;
        // FIXME: this should actually be a matrix multiplication to compute the warpgate final position
        // rot * scale * pos
        if (dx * dx + dy * dy < WARPGATE_DISTANCE) return it;
    }
    return {};
}
<commit_msg>Update movementsystem.cpp<commit_after>#include <cmath>
#include <algorithm>

#include "systems/movementsystem.h"
#include "cli_mousecmd.h"
#include "cli_stopmoving.h"
#include "cmapserver.h"
#include "packetfactory.h"
#include "srv_mousecmd.h"
#include "srv_stopmoving.h"
#include "srv_adjustposition.h"
#include "srv_switchserver.h"
#include "config.h"
#include "cmapclient.h"

using namespace Systems;
using namespace RoseCommon;

MovementSystem::MovementSystem(SystemManager &manager) : System(manager) {
  manager.registerDispatcher(ePacketType::PAKCS_MOUSE_CMD, &MovementSystem::processMove);
  manager.registerDispatcher(ePacketType::PAKCS_STOP_MOVING, &MovementSystem::stopMoving);
  manager.getEntityManager().on_component_removed<Destination>([this](Entity entity, Destination *dest) {
    if (!entity) return;
    if (auto client = getClient(entity))
      manager_.SendPacket(client, CMapServer::eSendType::NEARBY,
                                             *makePacket<ePacketType::PAKWC_STOP_MOVING>(entity));
    // TODO: check what type entity.component<BasicInfo>()->targetId_ is and execute corresponding action (npc talk, attack, item pickup...)
  });
  manager.getEntityManager().on_component_added<Position>([this](Entity entity, Position*) {
      updatePosition(entity);
  });
}

void MovementSystem::update(EntityManager &es, double dt) {
  for (Entity entity : es.entities_with_components<Position, Destination, AdvancedInfo>()) {
    Position *position = entity.component<Position>();
    Destination *destination = entity.component<Destination>();
    AdvancedInfo *advanced = entity.component<AdvancedInfo>();
    float dx = destination->x_ - position->x_;
    float dy = destination->y_ - position->y_;
    float distance = std::sqrt(dx * dx + dy * dy);
    destination->dist_ = distance;
    float speed = advanced->runSpeed_;
    float ntime = distance / speed;
    float old_x = position->x_;
    float old_y = position->y_;
    if (ntime <= dt || distance == 0) {
      position->x_ = destination->x_;
      position->y_ = destination->y_;
      entity.remove<Destination>();
    } else {
      position->x_ += dx * dt / ntime;
      position->y_ += dy * dt / ntime;
    }
    updatePosition(entity, old_x, old_y);
    if (Entity e = is_on_warpgate(entity); e) {
        auto dest = e.component<Destination>();
        teleport(entity, dest->dist_, dest->x_, dest->y_);
    }
  }
}

void MovementSystem::move(Entity entity, float x, float y, uint16_t target) {
  if (!entity) return;
  auto dest = entity.component<Destination>();
  auto pos = entity.component<Position>();
  float dx = pos->x_ - x;
  float dy = pos->y_ - y;
  float dist = std::sqrt(dx * dx + dy * dy);
  if (dest) {
    dest->x_ = x;
    dest->y_ = y;
    dest->dist_ = dist;
  } else {
    entity.assign<Destination>(x, y, dist);
  }
  entity.component<BasicInfo>()->targetId_ = target;
  // FIXME: what happens if the entity is an NPC or a monster?
  if (auto client = getClient(entity))
    manager_.SendPacket(client, CMapServer::eSendType::EVERYONE, *makePacket<ePacketType::PAKWC_MOUSE_CMD>(entity));
}

void MovementSystem::stop(Entity entity, float x, float y) {
  if (!entity || !entity.component<BasicInfo>()) return;
  entity.remove<Destination>();
  auto position = entity.component<Position>();
  if (position) {
    float dx = position->x_ - x;
    float dy = position->y_ - y;
    if (dx * dx + dy * dy < POSITION_CHEATING) {
      position->x_ = x;
      position->y_ = y;
    } else
      logger_->warn("Player {} attempted to cheat his position : calculated position : ({}, {}), got ({}, {})",
                    getId(entity), position->x_, position->y_, x, y);
  }
}

void MovementSystem::processMove(CMapClient &, Entity entity, const CliMouseCmd &packet) {
  logger_->trace("MovementSystem::processMove");
  if (!entity.component<Position>() || !entity.component<BasicInfo>()) return;
  move(entity, packet.x(), packet.y(), packet.targetId());
}

void MovementSystem::stopMoving(CMapClient &, Entity entity, const CliStopMoving &packet) {
  logger_->trace("MovementSystem::stopMoving");
  stop(entity, packet.x(), packet.y());
}

void MovementSystem::teleport(Entity entity, uint16_t map_id, float x, float y) {
    logger_->trace("MovementSystem::teleport");
    logger_->debug("Teleporting {} to {} {} {}", getId(entity), map_id, x, y);
    entity.component<BasicInfo>()->targetId_ = 0; // to avoid doing anything in the destination callback
    entity.remove<Destination>();
    auto pos = entity.component<Position>();
    pos->x_ = x;
    pos->y_ = y;
    if (pos->map_ == map_id) {
        manager_.SendPacket(getClient(entity), CMapServer::eSendType::EVERYONE,
                            *makePacket<ePacketType::PAKWC_ADJUST_POSITION>(entity));
    } else {
        if (auto client = getClient(entity)) {
            auto &config = Core::Config::getInstance();
            client->switch_server();
            client->send(*makePacket<ePacketType::PAKCC_SWITCH_SERVER>(
                config.mapServer().clientPort + map_id,
                client->get_session_id(),
                0,
                config.serverData().ip));
        }
    }
}

namespace {
constexpr std::tuple<uint16_t, uint16_t> get_grid_position(float x, float y) {
    uint16_t gx = x / 1000.f;
    uint16_t gy = y / 1000.f;
    return {gx, gy};
}

std::tuple<uint16_t, uint16_t> get_grid_position(Entity e) {
    auto pos = e.component<Position>();
    if (!pos) return {0, 0};
    return get_grid_position(pos->x_, pos->y_);
}
}

bool MovementSystem::is_nearby(Entity a, Entity b) const {
    if (!a || !b) return false;
    auto pos_a = get_grid_position(a);
    auto pos_b = get_grid_position(b);
    if (std::abs(std::get<0>(pos_a) - std::get<0>(pos_b)) <= 1
        && std::abs(std::get<1>(pos_a) - std::get<1>(pos_b)) <= 1)
        return true;
    return false;
}

void MovementSystem::updatePosition(Entity e, float old_x, float old_y) {
    if (old_x && old_y) {
        auto &list = grid[get_grid_position(old_x, old_y)];
        std::remove(list.begin(), list.end(), e);
    }
    grid[get_grid_position(e)].push_back(e);
}

Entity MovementSystem::is_on_warpgate(Entity e) {
    auto pos = e.component<Position>();
    for (auto &it : grid[get_grid_position(e)]) {
        if (it.component<Warpgate>()) continue; // skip non warpgates
        auto warp_pos = it.component<Position>();
        float dx = pos->x_ - warp_pos->x_;
        float dy = pos->x_ - warp_pos->y_;
        // FIXME: this should actually be a matrix multiplication to compute the warpgate final position
        // rot * scale * pos
        if (dx * dx + dy * dy < WARPGATE_DISTANCE) return it;
    }
    return {};
}
<|endoftext|>


<commit_before>/*!
* \brief
*
* \author ddubois
* \date 27-Sep-16.
*/

#include <algorithm>
#include <easylogging++.h>
#include <regex>
#include "mesh_store.h"
#include "../../../render/nova_renderer.h"
#include "builders/chunk_builder.h"
#include "../utils/io.h"

namespace nova {
    std::vector<render_object>& mesh_store::get_meshes_for_shader(std::string shader_name) {
        return renderables_grouped_by_shader[shader_name];
    }

    void print_buffers(std::string texture_name, std::vector<float>& vertex_buffer, std::vector<unsigned int>& index_buffer) {
        // debug
        LOG(DEBUG) << "texture name: " << texture_name << std::endl;
        LOG(DEBUG) << "new buffers:" << std::endl;
        for(int i = 0; i + 7 < vertex_buffer.size(); i += 8) {
            std::ostringstream ss;
            ss << "  vertex ";
            for(int k = 0; k < 8; k++) {
                ss << std::setfill(' ') << std::setw(4) << i + k << " = " << std::setfill(' ') << std::setw(12) << std::fixed << std::setprecision(5) << vertex_buffer[i + k] << "  ";
            }
            LOG(DEBUG) << ss.str();
        }
        for(int i = 0; i + 2 < index_buffer.size(); i += 3) {
            std::ostringstream ss;
            ss << "  index ";
            for(int k = 0; k < 3; k++) {
                ss << std::setfill(' ') << std::setw(4) << i + k << " = " << std::setfill(' ') << std::setw(8) << index_buffer[i + k] << "  ";
            }
            LOG(DEBUG) << ss.str();
        }
    }

    void mesh_store::add_gui_buffers(mc_gui_send_buffer_command* command) {
        std::string texture_name(command->texture_name);
        texture_name = std::regex_replace(texture_name, std::regex("^textures/"), "");
        texture_name = std::regex_replace(texture_name, std::regex(".png$"), "");
        texture_name = "minecraft:" + texture_name;
        const texture_manager::texture_location tex_location = nova_renderer::instance->get_texture_manager().get_texture_location(texture_name);
        glm::vec2 tex_size = tex_location.max - tex_location.min;

        std::vector<float> vertex_buffer(command->vertex_buffer_size);
        for (int i = 0; i + 8 < command->vertex_buffer_size; i += 9) {
            vertex_buffer[i]   = command->vertex_buffer[i];
            vertex_buffer[i+1] = command->vertex_buffer[i+1];
            vertex_buffer[i+2] = command->vertex_buffer[i+2];
            vertex_buffer[i+3] = command->vertex_buffer[i+3] * tex_size.x + tex_location.min.x;
            vertex_buffer[i+4] = command->vertex_buffer[i+4] * tex_size.y + tex_location.min.y;
            vertex_buffer[i+5] = command->vertex_buffer[i+5];
            vertex_buffer[i+6] = command->vertex_buffer[i+6];
            vertex_buffer[i+7] = command->vertex_buffer[i+7];
            vertex_buffer[i+8] = command->vertex_buffer[i+8];
        }
        std::vector<unsigned int> index_buffer(command->index_buffer_size);
        for(int i = 0; i < command->index_buffer_size; i++) {
            index_buffer[i] = (unsigned int)command->index_buffer[i];
        }

        // debug
        //print_buffers(texture_name, vertex_buffer, index_buffer);

        mesh_definition cur_screen_buffer;
        cur_screen_buffer.vertex_data = vertex_buffer;
        cur_screen_buffer.indices = index_buffer;
        cur_screen_buffer.vertex_format = format::POS_UV_COLOR;

        render_object gui = {};
        gui.geometry.reset(new gl_mesh(cur_screen_buffer));
        gui.type = geometry_type::gui;
        gui.name = "gui";
        gui.is_solid = true;
        gui.color_texture = command->atlas_name;

        sort_render_object(gui);
    }

    void mesh_store::remove_gui_render_objects() {
        for(auto& group : renderables_grouped_by_shader) {
            auto removed_elements = std::remove_if(group.second.begin(), group.second.end(),
                                                   [](auto& render_obj) {return render_obj.type == geometry_type::gui;});
            group.second.erase(removed_elements, group.second.end());
        }
    }

    void mesh_store::sort_render_object(render_object& object) {
        auto& all_shaders = shaders->get_loaded_shaders();
        for(auto& entry : all_shaders) {
            auto filter = entry.second.get_filter();
            if(filter->matches(object)) {
                renderables_grouped_by_shader[entry.first].push_back(std::move(object));
            }
        }
    }

    void mesh_store::remove_render_objects(std::function<bool(render_object&)> filter) {
        for(auto& group : renderables_grouped_by_shader) {
            std::remove_if(group.second.begin(), group.second.end(), filter);
        }
    }

    void mesh_store::set_shaderpack(std::shared_ptr<shaderpack> new_shaderpack) {
        shaders = new_shaderpack;

        renderables_grouped_by_shader.clear();
        for(auto& chunk : all_chunks) {
            generate_chunk_geometry(chunk);
        }
    }

    void mesh_store::add_or_update_chunk(mc_chunk &chunk) {
        chunk_adding_lock.lock();
        chunk.needs_update = true;
        LOG(INFO) << "Received a chunk with id " << chunk.chunk_id;
        all_chunks.push_back(chunk);
        chunk_adding_lock.unlock();
    }

    void mesh_store::generate_chunk_geometry(const mc_chunk &chunk) {
        auto render_objects_from_chunk = get_renderables_from_chunk(chunk, *shaders);
        for(auto& item : render_objects_from_chunk) {
            if(item.second) {
                renderables_grouped_by_shader[item.first].push_back(std::move(*item.second));
            }
        }
    }

    void mesh_store::register_model(std::string model_name, mc_simple_model &mc_model) {
        mesh_definition model = make_mesh_from_mc_model(mc_model);

		simple_models[model_name] = model;
    }

    mesh_definition mesh_store::make_mesh_from_mc_model(mc_simple_model &model) {
        mesh_definition mesh;
        // TODO: This method needs to happen
        return mesh;
    }

    void mesh_store::deregister_model(std::string model_name) {
        simple_models.erase(model_name);
    }

    void mesh_store::generate_needed_chunk_geometry() {
        for(auto& chunk : all_chunks) {
            if(chunk.needs_update) {
                LOG(INFO) << "Generating a geometry for chunk id " << chunk.chunk_id;
                make_geometry_for_chunk(chunk);
                chunk.needs_update = false;
            }
        }
    }

    void mesh_store::make_geometry_for_chunk(const mc_chunk &chunk) {
        LOG(INFO) << "Generating geometry for a chunk";
        auto start_time = std::clock();

        remove_render_objects([&](render_object& obj) {return obj.parent_id == chunk.chunk_id;});
        LOG(INFO) << "Removed render objects from our chunk";

        auto time_after_removing_objects = std::clock();

        generate_chunk_geometry(chunk);
        LOG(INFO) << "Generated chunk geometry";

        auto time_after_generating_chunk_geometry = std::clock();

        auto total_time = float(std::clock() - start_time) * 1000 / CLOCKS_PER_SEC;
        total_chunks_updated += 1;

        if(total_chunks_updated % 10 == 0) {
            LOG(INFO) << "We have spent:\n\t"
                      << float(time_after_removing_objects - start_time) * 1000 / CLOCKS_PER_SEC << "ms removing old render objects\n\t"
                      << float(time_after_generating_chunk_geometry - time_after_removing_objects) * 1000 / CLOCKS_PER_SEC << "ms generating chunk geometry\n\t"
                      << total_time << "ms in total";
        }
    }
}
<commit_msg>Many chunks<commit_after>/*!
* \brief
*
* \author ddubois
* \date 27-Sep-16.
*/

#include <algorithm>
#include <easylogging++.h>
#include <regex>
#include "mesh_store.h"
#include "../../../render/nova_renderer.h"
#include "builders/chunk_builder.h"
#include "../utils/io.h"

namespace nova {
    std::vector<render_object>& mesh_store::get_meshes_for_shader(std::string shader_name) {
        return renderables_grouped_by_shader[shader_name];
    }

    void print_buffers(std::string texture_name, std::vector<float>& vertex_buffer, std::vector<unsigned int>& index_buffer) {
        // debug
        LOG(DEBUG) << "texture name: " << texture_name << std::endl;
        LOG(DEBUG) << "new buffers:" << std::endl;
        for(int i = 0; i + 7 < vertex_buffer.size(); i += 8) {
            std::ostringstream ss;
            ss << "  vertex ";
            for(int k = 0; k < 8; k++) {
                ss << std::setfill(' ') << std::setw(4) << i + k << " = " << std::setfill(' ') << std::setw(12) << std::fixed << std::setprecision(5) << vertex_buffer[i + k] << "  ";
            }
            LOG(DEBUG) << ss.str();
        }
        for(int i = 0; i + 2 < index_buffer.size(); i += 3) {
            std::ostringstream ss;
            ss << "  index ";
            for(int k = 0; k < 3; k++) {
                ss << std::setfill(' ') << std::setw(4) << i + k << " = " << std::setfill(' ') << std::setw(8) << index_buffer[i + k] << "  ";
            }
            LOG(DEBUG) << ss.str();
        }
    }

    void mesh_store::add_gui_buffers(mc_gui_send_buffer_command* command) {
        std::string texture_name(command->texture_name);
        texture_name = std::regex_replace(texture_name, std::regex("^textures/"), "");
        texture_name = std::regex_replace(texture_name, std::regex(".png$"), "");
        texture_name = "minecraft:" + texture_name;
        const texture_manager::texture_location tex_location = nova_renderer::instance->get_texture_manager().get_texture_location(texture_name);
        glm::vec2 tex_size = tex_location.max - tex_location.min;

        std::vector<float> vertex_buffer(command->vertex_buffer_size);
        for (int i = 0; i + 8 < command->vertex_buffer_size; i += 9) {
            vertex_buffer[i]   = command->vertex_buffer[i];
            vertex_buffer[i+1] = command->vertex_buffer[i+1];
            vertex_buffer[i+2] = command->vertex_buffer[i+2];
            vertex_buffer[i+3] = command->vertex_buffer[i+3] * tex_size.x + tex_location.min.x;
            vertex_buffer[i+4] = command->vertex_buffer[i+4] * tex_size.y + tex_location.min.y;
            vertex_buffer[i+5] = command->vertex_buffer[i+5];
            vertex_buffer[i+6] = command->vertex_buffer[i+6];
            vertex_buffer[i+7] = command->vertex_buffer[i+7];
            vertex_buffer[i+8] = command->vertex_buffer[i+8];
        }
        std::vector<unsigned int> index_buffer(command->index_buffer_size);
        for(int i = 0; i < command->index_buffer_size; i++) {
            index_buffer[i] = (unsigned int)command->index_buffer[i];
        }

        // debug
        //print_buffers(texture_name, vertex_buffer, index_buffer);

        mesh_definition cur_screen_buffer;
        cur_screen_buffer.vertex_data = vertex_buffer;
        cur_screen_buffer.indices = index_buffer;
        cur_screen_buffer.vertex_format = format::POS_UV_COLOR;

        render_object gui = {};
        gui.geometry.reset(new gl_mesh(cur_screen_buffer));
        gui.type = geometry_type::gui;
        gui.name = "gui";
        gui.is_solid = true;
        gui.color_texture = command->atlas_name;

        sort_render_object(gui);
    }

    void mesh_store::remove_gui_render_objects() {
        for(auto& group : renderables_grouped_by_shader) {
            auto removed_elements = std::remove_if(group.second.begin(), group.second.end(),
                                                   [](auto& render_obj) {return render_obj.type == geometry_type::gui;});
            group.second.erase(removed_elements, group.second.end());
        }
    }

    void mesh_store::sort_render_object(render_object& object) {
        auto& all_shaders = shaders->get_loaded_shaders();
        for(auto& entry : all_shaders) {
            auto filter = entry.second.get_filter();
            if(filter->matches(object)) {
                renderables_grouped_by_shader[entry.first].push_back(std::move(object));
            }
        }
    }

    void mesh_store::remove_render_objects(std::function<bool(render_object&)> filter) {
        for(auto& group : renderables_grouped_by_shader) {
            std::remove_if(group.second.begin(), group.second.end(), filter);
        }
    }

    void mesh_store::set_shaderpack(std::shared_ptr<shaderpack> new_shaderpack) {
        shaders = new_shaderpack;

        renderables_grouped_by_shader.clear();
        for(auto& chunk : all_chunks) {
            generate_chunk_geometry(chunk);
        }
    }

    void mesh_store::add_or_update_chunk(mc_chunk &chunk) {
        chunk_adding_lock.lock();
        chunk.needs_update = true;
        LOG(INFO) << "Received a chunk with id " << chunk.chunk_id;
        all_chunks.push_back(chunk);
        chunk_adding_lock.unlock();
    }

    void mesh_store::generate_chunk_geometry(const mc_chunk &chunk) {
        auto render_objects_from_chunk = get_renderables_from_chunk(chunk, *shaders);
        for(auto& item : render_objects_from_chunk) {
            if(item.second) {
                renderables_grouped_by_shader[item.first].push_back(std::move(*item.second));
            }
        }
    }

    void mesh_store::register_model(std::string model_name, mc_simple_model &mc_model) {
        mesh_definition model = make_mesh_from_mc_model(mc_model);

		simple_models[model_name] = model;
    }

    mesh_definition mesh_store::make_mesh_from_mc_model(mc_simple_model &model) {
        mesh_definition mesh;
        // TODO: This method needs to happen
        return mesh;
    }

    void mesh_store::deregister_model(std::string model_name) {
        simple_models.erase(model_name);
    }

    void mesh_store::generate_needed_chunk_geometry() {
        chunk_adding_lock.lock();
        for(auto& chunk : all_chunks) {
            if(chunk.needs_update) {
                LOG(INFO) << "Generating a geometry for chunk id " << chunk.chunk_id;
                make_geometry_for_chunk(chunk);
                chunk.needs_update = false;
            }
        }
        chunk_adding_lock.unlock();
    }

    void mesh_store::make_geometry_for_chunk(const mc_chunk &chunk) {
        LOG(INFO) << "Generating geometry for a chunk";
        auto start_time = std::clock();

        remove_render_objects([&](render_object& obj) {return obj.parent_id == chunk.chunk_id;});
        LOG(INFO) << "Removed render objects from our chunk";

        auto time_after_removing_objects = std::clock();

        generate_chunk_geometry(chunk);
        LOG(INFO) << "Generated chunk geometry";

        auto time_after_generating_chunk_geometry = std::clock();

        auto total_time = float(std::clock() - start_time) * 1000 / CLOCKS_PER_SEC;
        total_chunks_updated += 1;

        if(total_chunks_updated % 10 == 0) {
            LOG(INFO) << "We have spent:\n\t"
                      << float(time_after_removing_objects - start_time) * 1000 / CLOCKS_PER_SEC << "ms removing old render objects\n\t"
                      << float(time_after_generating_chunk_geometry - time_after_removing_objects) * 1000 / CLOCKS_PER_SEC << "ms generating chunk geometry\n\t"
                      << total_time << "ms in total";
        }
    }
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2014-2017 Ian Godin and Kimball Thurston
// All rights reserved.
// Copyrights licensed under the MIT License.
// See the accompanying LICENSE.txt file for terms
//

#include <platform/platform.h>
#include <platform/system.h>
#include <platform/dispatcher.h>
#include <gl/opengl.h>
#include <gl/api.h>
#include <gl/mesh.h>
#include <gl/png_image.h>
#include <base/contract.h>
#include <base/timer.h>
#include <base/math_functions.h>
#include <draw/path.h>
#include <draw/polylines.h>
#include <draw/text.h>
#include <script/font_manager.h>

namespace
{

int safemain( int /*argc*/, char * /*argv*/ [] )
{
	auto sys = platform::platform::find_running();

	auto win = sys->new_window();
	win->resize( 400, 400 );
	win->set_title( "Draw Test" );
	win->acquire();

	gl::api ogl;
	ogl.setup_debugging();

	auto fm = script::font_manager::common();
	if ( ! fm )
		throw std::runtime_error( "no font manager enrolled" );

	draw::text samptext( fm->get_font( "Lucida Grande", "Regular", 28.0 ) );
	samptext.set_text( "Hello, world!" );
	samptext.set_position( gl::vec2( 100.F, 200.F ) );
	samptext.set_color( gl::color( 1.0, 1.0, 1.0, 1.0 ) );

	gl::mesh star;
	{
		// Draw a star shape (with 17 points).
		draw::path path;
		size_t p = 17;
		size_t q = 5;
		path.move_to( gl::vec2::polar( 200.F, 0.F ) );
		for ( size_t i = q % p; i != 0; i = ( i + q ) % p )
			path.line_to( gl::vec2::polar( 200.F, 360.0_deg * i / p ) );
		path.close();

		// Setup GL vertex/element buffers.
		gl::color color;
		size_t offset = 0;
		gl::vertex_buffer_data<gl::vec2,gl::color> pos;
		auto add_point = [&]( float x, float y )
		{
			pos.push_back( { x, y }, color );
		};

		gl::element_buffer_data tris;
		auto add_tri = [&]( size_t a, size_t b, size_t c )
		{
			tris.push_back( static_cast<uint32_t>( offset + a ), static_cast<uint32_t>( offset + b ), static_cast<uint32_t>( offset + c ) );
		};

		// Fill in the buffers
		draw::polylines lines;
		path.replay( lines );

	   	color = gl::blue;
		lines.filled( add_point, add_tri );
		offset = pos.size();

		color = gl::red;
		auto outline = lines.stroked( 2 );
		outline.filled( add_point, add_tri );

		// Finally setup the star mesh
		star.get_program().set(
			ogl.new_vertex_shader( R"SHADER(
				#version 330

				layout(location = 0) in vec2 vertex_position;
				layout(location = 1) in vec3 vertex_color;

				uniform mat4 matrix;

				out vec3 color;

				void main()
				{
					color = vertex_color;
					gl_Position = matrix * vec4( vertex_position, 0.0, 1.0 );
				}
			)SHADER" ),
			ogl.new_fragment_shader( R"SHADER(
				#version 330

				in vec3 color;
				out vec4 frag_color;

				void main()
				{
					frag_color = vec4( color, 1.0 );
				}
			)SHADER" )
		);

		auto bind = star.bind();
		bind.vertex_attribute( "vertex_position", pos, 0 );
		bind.vertex_attribute( "vertex_color", pos, 1 );
		bind.set_elements( tris );

		star.add_triangles( tris.size() );
	}

	// View/projection Matrix
	gl::matrix4 matrix;
	float angle = 0.F;
	gl::program::uniform matrix_loc = star.get_uniform_location( "matrix" );
	gl::matrix4 local = gl::matrix4::translation( 200, 200 );

	// Render function
	win->exposed = [&]( void )
	{
		gl::versor rotate( angle, 0.F, 0.F, 1.F );
		matrix = gl::matrix4::ortho( 0, static_cast<float>( win->width() ), 0, static_cast<float>( win->height() ) );

		ogl.clear();
		ogl.viewport( 0, 0, win->width(), win->height() );

		{
			auto bound = star.bind();
			bound.set_uniform( matrix_loc, rotate * local * matrix );
			bound.draw();
		}

		angle += 1.0_deg;
		while ( angle > 360.0_deg )
			angle -= 360.0_deg;

		// draw the text
		ogl.save_matrix();
		ogl.multiply( matrix );
		samptext.draw( ogl );
		ogl.restore_matrix();

		// Cause a redraw to continue the animation
		win->invalidate( base::rect() );
	};

	// Key to take a screenshot.
	win->key_pressed = [&]( const std::shared_ptr<platform::keyboard> &, platform::scancode c )
	{
		if ( c == platform::scancode::KEY_S )
		{
			win->acquire();
			gl::png_write( "/tmp/test.png", static_cast<size_t>( win->width() ), static_cast<size_t>( win->height() ), 3 );
			win->release();
		}
		else if ( c == platform::scancode::KEY_Q )
		{
			sys->get_dispatcher()->exit( 0 );
		}
	};

	win->show();

	auto dispatch = sys->get_dispatcher();
	return dispatch->execute();
}

}

////////////////////////////////////////

int main( int argc, char *argv[] )
{
	int ret = -1;
	try
	{
		ret = safemain( argc, argv );
	}
	catch ( std::exception &e )
	{
		base::print_exception( std::cerr, e );
	}
	return ret;
}

////////////////////////////////////////

<commit_msg>Fixed missing blend in test.<commit_after>//
// Copyright (c) 2014-2017 Ian Godin and Kimball Thurston
// All rights reserved.
// Copyrights licensed under the MIT License.
// See the accompanying LICENSE.txt file for terms
//

#include <platform/platform.h>
#include <platform/system.h>
#include <platform/dispatcher.h>
#include <gl/opengl.h>
#include <gl/api.h>
#include <gl/mesh.h>
#include <gl/png_image.h>
#include <base/contract.h>
#include <base/timer.h>
#include <base/math_functions.h>
#include <draw/path.h>
#include <draw/polylines.h>
#include <draw/text.h>
#include <script/font_manager.h>

namespace
{

int safemain( int /*argc*/, char * /*argv*/ [] )
{
	auto sys = platform::platform::find_running();

	auto win = sys->new_window();
	win->resize( 400, 400 );
	win->set_title( "Draw Test" );
	win->acquire();

	gl::api ogl;
	ogl.setup_debugging();

	auto fm = script::font_manager::common();
	if ( ! fm )
		throw std::runtime_error( "no font manager enrolled" );

	draw::text samptext( fm->get_font( "Lucida Grande", "Regular", 28.0 ) );
	samptext.set_text( "Hello, world!" );
	samptext.set_position( gl::vec2( 100.F, 200.F ) );
	samptext.set_color( gl::color( 1.0, 1.0, 1.0, 1.0 ) );

	gl::mesh star;
	{
		// Draw a star shape (with 17 points).
		draw::path path;
		size_t p = 17;
		size_t q = 5;
		path.move_to( gl::vec2::polar( 200.F, 0.F ) );
		for ( size_t i = q % p; i != 0; i = ( i + q ) % p )
			path.line_to( gl::vec2::polar( 200.F, 360.0_deg * i / p ) );
		path.close();

		// Setup GL vertex/element buffers.
		gl::color color;
		size_t offset = 0;
		gl::vertex_buffer_data<gl::vec2,gl::color> pos;
		auto add_point = [&]( float x, float y )
		{
			pos.push_back( { x, y }, color );
		};

		gl::element_buffer_data tris;
		auto add_tri = [&]( size_t a, size_t b, size_t c )
		{
			tris.push_back( static_cast<uint32_t>( offset + a ), static_cast<uint32_t>( offset + b ), static_cast<uint32_t>( offset + c ) );
		};

		// Fill in the buffers
		draw::polylines lines;
		path.replay( lines );

	   	color = gl::blue;
		lines.filled( add_point, add_tri );
		offset = pos.size();

		color = gl::red;
		auto outline = lines.stroked( 2 );
		outline.filled( add_point, add_tri );

		// Finally setup the star mesh
		star.get_program().set(
			ogl.new_vertex_shader( R"SHADER(
				#version 330

				layout(location = 0) in vec2 vertex_position;
				layout(location = 1) in vec3 vertex_color;

				uniform mat4 matrix;

				out vec3 color;

				void main()
				{
					color = vertex_color;
					gl_Position = matrix * vec4( vertex_position, 0.0, 1.0 );
				}
			)SHADER" ),
			ogl.new_fragment_shader( R"SHADER(
				#version 330

				in vec3 color;
				out vec4 frag_color;

				void main()
				{
					frag_color = vec4( color, 1.0 );
				}
			)SHADER" )
		);

		auto bind = star.bind();
		bind.vertex_attribute( "vertex_position", pos, 0 );
		bind.vertex_attribute( "vertex_color", pos, 1 );
		bind.set_elements( tris );

		star.add_triangles( tris.size() );
	}

	// View/projection Matrix
	gl::matrix4 matrix;
	float angle = 0.F;
	gl::program::uniform matrix_loc = star.get_uniform_location( "matrix" );
	gl::matrix4 local = gl::matrix4::translation( 200, 200 );

	// Render function
	win->exposed = [&]( void )
	{
		gl::versor rotate( angle, 0.F, 0.F, 1.F );
		matrix = gl::matrix4::ortho( 0, static_cast<float>( win->width() ), 0, static_cast<float>( win->height() ) );

		ogl.clear();
		ogl.viewport( 0, 0, win->width(), win->height() );
		ogl.enable( gl::capability::BLEND );
		ogl.blend_func( gl::blend_style::SRC_ALPHA, gl::blend_style::ONE_MINUS_SRC_ALPHA );

		{
			auto bound = star.bind();
			bound.set_uniform( matrix_loc, rotate * local * matrix );
			bound.draw();
		}

		angle += 1.0_deg;
		while ( angle > 360.0_deg )
			angle -= 360.0_deg;

		// draw the text
		ogl.save_matrix();
		ogl.multiply( matrix );
		samptext.draw( ogl );
		ogl.restore_matrix();

		// Cause a redraw to continue the animation
		win->invalidate( base::rect() );
	};

	// Key to take a screenshot.
	win->key_pressed = [&]( const std::shared_ptr<platform::keyboard> &, platform::scancode c )
	{
		if ( c == platform::scancode::KEY_S )
		{
			win->acquire();
			gl::png_write( "/tmp/test.png", static_cast<size_t>( win->width() ), static_cast<size_t>( win->height() ), 3 );
			win->release();
		}
		else if ( c == platform::scancode::KEY_Q )
		{
			sys->get_dispatcher()->exit( 0 );
		}
	};

	win->show();

	auto dispatch = sys->get_dispatcher();
	return dispatch->execute();
}

}

////////////////////////////////////////

int main( int argc, char *argv[] )
{
	int ret = -1;
	try
	{
		ret = safemain( argc, argv );
	}
	catch ( std::exception &e )
	{
		base::print_exception( std::cerr, e );
	}
	return ret;
}

////////////////////////////////////////

<|endoftext|>


<commit_before>// Copyright (c) 2019 Franka Emika GmbH
// Use of this source code is governed by the Apache-2.0 license, see LICENSE

#include <controller_manager/controller_manager.h>
#include <franka_hw/franka_combined_hw.h>
#include <ros/ros.h>

#include <franka/control_tools.h>
#include <sched.h>
#include <string>

int main(int argc, char** argv) {
  ros::init(argc, argv, "franka_combined_control_node");

  ros::AsyncSpinner spinner(4);
  spinner.start();

  ros::NodeHandle private_node_handle("~");
  franka_hw::FrankaCombinedHW franka_control;
  if (!franka_control.init(private_node_handle, private_node_handle)) {
    ROS_ERROR("franka_combined_control_node:: Initialization of FrankaCombinedHW failed!");
    return 1;
  }

  // set current thread to real-time priority
  std::string error_message;
  if (!franka::setCurrentThreadToHighestSchedulerPriority(&error_message)) {
    ROS_ERROR("franka_combined_control_node: Failed to set thread priority to real-time. Error: %s",
              error_message.c_str());
    return 1;
  }

  controller_manager::ControllerManager cm(&franka_control, private_node_handle);
  ros::Duration period(0.001);
  ros::Rate rate(period);

  while (ros::ok()) {
    rate.sleep();
    ros::Time now = ros::Time::now();
    franka_control.read(now, period);
    cm.update(now, period, franka_control.controllerNeedsReset());
    if (!franka_control.hasError()) {
      franka_control.write(now, period);
    } else {
      ROS_INFO_THROTTLE(2,
                        "franka_combined_control_node: The HW is in error state."
                        "To recover, call the recovery action.");
    }
  }

  return 0;
}
<commit_msg>make recovery print debug<commit_after>// Copyright (c) 2019 Franka Emika GmbH
// Use of this source code is governed by the Apache-2.0 license, see LICENSE

#include <controller_manager/controller_manager.h>
#include <franka_hw/franka_combined_hw.h>
#include <ros/ros.h>

#include <franka/control_tools.h>
#include <sched.h>
#include <string>

int main(int argc, char** argv) {
  ros::init(argc, argv, "franka_combined_control_node");

  ros::AsyncSpinner spinner(4);
  spinner.start();

  ros::NodeHandle private_node_handle("~");
  franka_hw::FrankaCombinedHW franka_control;
  if (!franka_control.init(private_node_handle, private_node_handle)) {
    ROS_ERROR("franka_combined_control_node:: Initialization of FrankaCombinedHW failed!");
    return 1;
  }

  // set current thread to real-time priority
  std::string error_message;
  if (!franka::setCurrentThreadToHighestSchedulerPriority(&error_message)) {
    ROS_ERROR("franka_combined_control_node: Failed to set thread priority to real-time. Error: %s",
              error_message.c_str());
    return 1;
  }

  controller_manager::ControllerManager cm(&franka_control, private_node_handle);
  ros::Duration period(0.001);
  ros::Rate rate(period);

  while (ros::ok()) {
    rate.sleep();
    ros::Time now = ros::Time::now();
    franka_control.read(now, period);
    cm.update(now, period, franka_control.controllerNeedsReset());
    if (!franka_control.hasError()) {
      franka_control.write(now, period);
    } else {
      ROS_DEBUG_THROTTLE(5,
                         "franka_combined_control_node: The HW is in error state."
                         "To recover, call the recovery action.");
    }
  }

  return 0;
}
<|endoftext|>


<commit_before>/*
 * This file is part of the UnTech Editor Suite.
 * Copyright (c) 2016 - 2021, Marcus Rowe <undisbeliever@gmail.com>.
 * Distributed under The MIT License: https://opensource.org/licenses/MIT
 */

#include "style.h"
#include "imgui-drawing.h"
#include "models/common/clamp.h"
#include "models/common/iterators.h"
#include "models/common/stringbuilder.h"
#include "vendor/imgui/imgui_internal.h"

namespace UnTech::Gui {

const ImVec4 Style::tileCollisionTint(0.75f, 0, 0.75f, 0.5);
const ImVec4 Style::tilePropertiesButtonTint(0.5f, 0.5f, 0.5f, 1.0f);
const ImVec4 Style::tilePropertiesButtonSelectedTint(1.0f, 1.0f, 1.0f, 1.0f);

const ImVec4 Style::commentColorDark = { 0.25f, 1.0f, 0.25f, 1.0f };
const ImVec4 Style::commentColorLight = { 0.0f, 0.45f, 0.0f, 1.0f };

Zoom Style::metaSpriteAnimationZoom(600);
Zoom Style::metaSpriteZoom(600);
Zoom Style::spriteImporterZoom(600);
Zoom Style::backgroundImageZoom(200);
Zoom Style::metaTileTilesetZoom(300);
Zoom Style::metaTileScratchpadZoom(300);
Zoom Style::roomEditorZoom(300);

ZoomAspectRatio Style::aspectRatio = ZoomAspectRatio::Ntsc;

const std::array<std::pair<unsigned, const char*>, 19> zoomComboItems{ {
    { 25, "25%" },
    { 50, "50%" },
    { 75, "75%" },
    { 100, "100%" },
    { 150, "150%" },
    { 200, "200%" },
    { 300, "300%" },
    { 400, "400%" },
    { 500, "500%" },
    { 600, "600%" },
    { 700, "700%" },
    { 800, "800%" },
    { 900, "900%" },
    { 1000, "1000%" },
    { 1200, "1200%" },
    { 1400, "1500%" },
    { 1600, "1600%" },
    { 1800, "1800%" },
    { 2000, "2000%" },
} };

Zoom::Zoom(unsigned z)
{
    setZoom(z);
}

void Zoom::setZoom(unsigned z)
{
    z = clamp<unsigned>(z, 5, 1800);

    _zoomInt = z;

    update();
}

static float aspectRatioScale(const ZoomAspectRatio ar)
{
    // Values taken from bsnes-plus
    switch (ar) {
    case ZoomAspectRatio::Ntsc:
        return 54.0f / 47.0f;

    case ZoomAspectRatio::Pal:
        return 32.0f / 23.0f;

    case ZoomAspectRatio::Square:
        return 1.0f;
    }

    return 1.0f;
}

void Zoom::update()
{
    const float scale = aspectRatioScale(Style::aspectRatio);

    _zoom.x = _zoomInt / 100.0f * scale;
    _zoom.y = _zoomInt / 100.0f;

    _zoomString = stringBuilder(_zoomInt, "%");
}

void Zoom::zoomCombo(const char* label)
{
    ImGui::SetNextItemWidth(100);
    if (ImGui::BeginCombo(label, _zoomString.c_str())) {
        for (auto& [z, str] : zoomComboItems) {
            if (ImGui::Selectable(str, _zoomInt == z)) {
                setZoom(z);
            }
        }
        ImGui::EndCombo();
    }
    if (ImGui::IsItemHovered()) {
        ImGui::BeginTooltip();
        ImGui::TextUnformatted("Zoom");
        ImGui::EndTooltip();
    }
}

void Zoom::processMouseWheel()
{
    const auto& io = ImGui::GetIO();

    auto updateZoom = [&](unsigned z) {
        if (_zoomInt == z) {
            return;
        }

        const ImVec2 oldZoom = _zoom;
        setZoom(z);

        const ImVec2 windowSize = ImGui::GetWindowSize();
        const ImVec2 halfWindowSize(windowSize.x / 2, windowSize.y / 2);

        ImGui::SetScrollX((ImGui::GetScrollX() + halfWindowSize.x) * _zoom.x / oldZoom.x - halfWindowSize.x);
        ImGui::SetScrollY((ImGui::GetScrollY() + halfWindowSize.y) * _zoom.y / oldZoom.y - halfWindowSize.y);
    };

    if (ImGui::IsWindowHovered()) {
        if (io.KeyCtrl) {
            if (io.MouseWheel < 0.0f) {
                unsigned z = zoomComboItems.front().first;
                auto it = std::find_if(zoomComboItems.begin(), zoomComboItems.end(),
                                       [&](auto& z) { return z.first >= _zoomInt; });
                if (it != zoomComboItems.begin()) {
                    it--;
                    z = it->first;
                }
                updateZoom(z);
            }
            else if (io.MouseWheel > 0.0f) {
                unsigned z = zoomComboItems.back().first;
                for (const auto i : range(zoomComboItems.size() - 1)) {
                    if (zoomComboItems.at(i).first >= zoomInt()) {
                        z = zoomComboItems.at(i + 1).first;
                        break;
                    }
                }
                updateZoom(z);
            }
        }
    }
}

const ImVec4& Style::commentColor()
{
    const bool isDark = ImGui::GetStyleColorVec4(ImGuiCol_Text).x > 0.5f;
    return isDark ? commentColorDark : commentColorLight;
}

void Style::setAspectRatio(ZoomAspectRatio ar)
{
    aspectRatio = ar;

    metaSpriteAnimationZoom.update();
    metaSpriteZoom.update();
    spriteImporterZoom.update();
    backgroundImageZoom.update();
    metaTileTilesetZoom.update();
    metaTileScratchpadZoom.update();
    roomEditorZoom.update();
}

}
<commit_msg>Fix unable to zoom to the maximum zoom level<commit_after>/*
 * This file is part of the UnTech Editor Suite.
 * Copyright (c) 2016 - 2021, Marcus Rowe <undisbeliever@gmail.com>.
 * Distributed under The MIT License: https://opensource.org/licenses/MIT
 */

#include "style.h"
#include "models/common/clamp.h"
#include "models/common/stringbuilder.h"

namespace UnTech::Gui {

const ImVec4 Style::tileCollisionTint(0.75f, 0, 0.75f, 0.5);
const ImVec4 Style::tilePropertiesButtonTint(0.5f, 0.5f, 0.5f, 1.0f);
const ImVec4 Style::tilePropertiesButtonSelectedTint(1.0f, 1.0f, 1.0f, 1.0f);

const ImVec4 Style::commentColorDark = { 0.25f, 1.0f, 0.25f, 1.0f };
const ImVec4 Style::commentColorLight = { 0.0f, 0.45f, 0.0f, 1.0f };

Zoom Style::metaSpriteAnimationZoom(600);
Zoom Style::metaSpriteZoom(600);
Zoom Style::spriteImporterZoom(600);
Zoom Style::backgroundImageZoom(200);
Zoom Style::metaTileTilesetZoom(300);
Zoom Style::metaTileScratchpadZoom(300);
Zoom Style::roomEditorZoom(300);

ZoomAspectRatio Style::aspectRatio = ZoomAspectRatio::Ntsc;

static constexpr std::array<std::pair<unsigned, const char*>, 19> zoomComboItems{ {
    { 25, "25%" },
    { 50, "50%" },
    { 75, "75%" },
    { 100, "100%" },
    { 150, "150%" },
    { 200, "200%" },
    { 300, "300%" },
    { 400, "400%" },
    { 500, "500%" },
    { 600, "600%" },
    { 700, "700%" },
    { 800, "800%" },
    { 900, "900%" },
    { 1000, "1000%" },
    { 1200, "1200%" },
    { 1400, "1500%" },
    { 1600, "1600%" },
    { 1800, "1800%" },
    { 2000, "2000%" },
} };

Zoom::Zoom(unsigned z)
{
    setZoom(z);
}

void Zoom::setZoom(unsigned z)
{
    constexpr unsigned MIN_ZOOM = 5;
    constexpr unsigned MAX_ZOOM = 2500;

    static_assert(MIN_ZOOM <= zoomComboItems.front().first);
    static_assert(MAX_ZOOM >= zoomComboItems.back().first);

    z = clamp<unsigned>(z, MIN_ZOOM, MAX_ZOOM);

    _zoomInt = z;

    update();
}

static float aspectRatioScale(const ZoomAspectRatio ar)
{
    // Values taken from bsnes-plus
    switch (ar) {
    case ZoomAspectRatio::Ntsc:
        return 54.0f / 47.0f;

    case ZoomAspectRatio::Pal:
        return 32.0f / 23.0f;

    case ZoomAspectRatio::Square:
        return 1.0f;
    }

    return 1.0f;
}

void Zoom::update()
{
    const float scale = aspectRatioScale(Style::aspectRatio);

    _zoom.x = _zoomInt / 100.0f * scale;
    _zoom.y = _zoomInt / 100.0f;

    _zoomString = stringBuilder(_zoomInt, "%");
}

void Zoom::zoomCombo(const char* label)
{
    ImGui::SetNextItemWidth(100);
    if (ImGui::BeginCombo(label, _zoomString.c_str())) {
        for (auto& [z, str] : zoomComboItems) {
            if (ImGui::Selectable(str, _zoomInt == z)) {
                setZoom(z);
            }
        }
        ImGui::EndCombo();
    }
    if (ImGui::IsItemHovered()) {
        ImGui::BeginTooltip();
        ImGui::TextUnformatted("Zoom");
        ImGui::EndTooltip();
    }
}

void Zoom::processMouseWheel()
{
    const auto& io = ImGui::GetIO();

    auto updateZoom = [&](unsigned z) {
        if (_zoomInt == z) {
            return;
        }

        const ImVec2 oldZoom = _zoom;
        setZoom(z);

        const ImVec2 windowSize = ImGui::GetWindowSize();
        const ImVec2 halfWindowSize(windowSize.x / 2, windowSize.y / 2);

        ImGui::SetScrollX((ImGui::GetScrollX() + halfWindowSize.x) * _zoom.x / oldZoom.x - halfWindowSize.x);
        ImGui::SetScrollY((ImGui::GetScrollY() + halfWindowSize.y) * _zoom.y / oldZoom.y - halfWindowSize.y);
    };

    if (ImGui::IsWindowHovered()) {
        if (io.KeyCtrl) {
            if (io.MouseWheel < 0.0f) {
                unsigned z = zoomComboItems.front().first;
                auto it = std::find_if(zoomComboItems.begin(), zoomComboItems.end(),
                                       [&](auto& z) { return z.first >= _zoomInt; });
                if (it != zoomComboItems.begin()) {
                    it--;
                    z = it->first;
                }
                updateZoom(z);
            }
            else if (io.MouseWheel > 0.0f) {
                unsigned z = zoomComboItems.back().first;
                auto it = std::find_if(zoomComboItems.begin(), zoomComboItems.end(),
                                       [&](auto& z) { return z.first > _zoomInt; });
                if (it != zoomComboItems.end()) {
                    z = it->first;
                }
                updateZoom(z);
            }
        }
    }
}

const ImVec4& Style::commentColor()
{
    const bool isDark = ImGui::GetStyleColorVec4(ImGuiCol_Text).x > 0.5f;
    return isDark ? commentColorDark : commentColorLight;
}

void Style::setAspectRatio(ZoomAspectRatio ar)
{
    aspectRatio = ar;

    metaSpriteAnimationZoom.update();
    metaSpriteZoom.update();
    spriteImporterZoom.update();
    backgroundImageZoom.update();
    metaTileTilesetZoom.update();
    metaTileScratchpadZoom.update();
    roomEditorZoom.update();
}

}
<|endoftext|>


<commit_before>#ifndef _PNMC_MC_STATISTICS_SERIALIZE_HH_
#define _PNMC_MC_STATISTICS_SERIALIZE_HH_

#include <cereal/archives/json.hpp>
#include <cereal/types/deque.hpp>

#include "conf/configuration.hh"
#include "mc/classic/statistics.hh"

namespace pnmc { namespace mc { namespace classic {

/*------------------------------------------------------------------------------------------------*/

template<class Archive>
void
save(Archive& archive, const statistics& s)
{
  if (s.conf.order_only)
  {
    archive(cereal::make_nvp("order only", true));
    if (s.conf.order_ordering_force)
    {
      archive( cereal::make_nvp("FORCE time", s.force_duration.count())
             , cereal::make_nvp("FORCE spans", s.force_spans));
    }
    return;
  }
  archive( cereal::make_nvp("order only", false)
         , cereal::make_nvp("interrupted", s.interrupted)
         , cereal::make_nvp("time limit", s.conf.max_time.count())
         , cereal::make_nvp("states", s.nb_states)
         , cereal::make_nvp("states as string", std::to_string(s.nb_states))
         , cereal::make_nvp("relation time", s.relation_duration.count())
         , cereal::make_nvp("rewrite time", s.rewrite_duration.count())
         , cereal::make_nvp("state space time", s.state_space_duration.count())
         , cereal::make_nvp("sdd samples", s.sdd_ut_size));
  if (s.conf.order_ordering_force)
  {
    archive( cereal::make_nvp("FORCE time", s.force_duration.count())
           , cereal::make_nvp("FORCE spans", s.force_spans));
  }
  if (s.conf.compute_dead_states)
  {
    archive( cereal::make_nvp("dead states relation time", s.dead_states_relation_duration.count())
           , cereal::make_nvp("dead states rewrite time", s.dead_states_rewrite_duration.count())
           , cereal::make_nvp("dead states time", s.dead_states_duration.count()));
  }
}

/*------------------------------------------------------------------------------------------------*/

}}} // namespace pnmc::mc::classic

#endif // _PNMC_MC_STATISTICS_SERIALIZE_HH_
<commit_msg>Fix JSPN output now that cereal behaves correctly for 64 bits types.<commit_after>#ifndef _PNMC_MC_STATISTICS_SERIALIZE_HH_
#define _PNMC_MC_STATISTICS_SERIALIZE_HH_

#include <cereal/archives/json.hpp>
#include <cereal/types/deque.hpp>

#include "conf/configuration.hh"
#include "mc/classic/statistics.hh"

namespace pnmc { namespace mc { namespace classic {

/*------------------------------------------------------------------------------------------------*/

template<class Archive>
void
save(Archive& archive, const statistics& s)
{
  if (s.conf.order_only)
  {
    archive(cereal::make_nvp("order only", true));
    if (s.conf.order_ordering_force)
    {
      archive( cereal::make_nvp("FORCE time", s.force_duration.count())
             , cereal::make_nvp("FORCE spans", s.force_spans));
    }
    return;
  }
  archive( cereal::make_nvp("order only", false)
         , cereal::make_nvp("interrupted", s.interrupted)
         , cereal::make_nvp("time limit", s.conf.max_time.count())
         , cereal::make_nvp("states", s.nb_states)
         , cereal::make_nvp("relation time", s.relation_duration.count())
         , cereal::make_nvp("rewrite time", s.rewrite_duration.count())
         , cereal::make_nvp("state space time", s.state_space_duration.count())
         , cereal::make_nvp("sdd samples", s.sdd_ut_size));
  if (s.conf.order_ordering_force)
  {
    archive( cereal::make_nvp("FORCE time", s.force_duration.count())
           , cereal::make_nvp("FORCE spans", s.force_spans));
  }
  if (s.conf.compute_dead_states)
  {
    archive( cereal::make_nvp("dead states relation time", s.dead_states_relation_duration.count())
           , cereal::make_nvp("dead states rewrite time", s.dead_states_rewrite_duration.count())
           , cereal::make_nvp("dead states time", s.dead_states_duration.count()));
  }
}

/*------------------------------------------------------------------------------------------------*/

}}} // namespace pnmc::mc::classic

#endif // _PNMC_MC_STATISTICS_SERIALIZE_HH_
<|endoftext|>


<commit_before>// Preprocessor directive for allowing us to do a post-initialization update.

#if (BL_SPACEDIM==3)
#ifndef do_problem_post_init
#define do_problem_post_init
#endif
#endif

// Preprocessor directive for allowing us to do a post-timestep update.

#ifndef do_problem_post_timestep
#define do_problem_post_timestep
#endif

// Routine for determining white dwarf masses, centers of mass and velocities.

void wdCOM (Real time, Real& mass_p, Real& mass_s, Real* com_p, Real* com_s, Real* vel_p, Real* vel_s);

// Volume within white dwarfs at a given density cutoff.

void volInBoundary (Real               time,
		    Real&              vol_p,
		    Real&              vol_s,
                    Real               rho_cutoff);

// Calculate gravitational wave signal.

void gwstrain (Real time,
	       Real& h_plus_1, Real& h_cross_1,
	       Real& h_plus_2, Real& h_cross_2,
	       Real& h_plus_3, Real& h_cross_3);

// Computes standard dot product of two three-vectors.

Real dot_product(const Real a[], const Real b[]);

// Computes standard cross-product of two three-vectors.

void cross_product(const Real a[], const Real b[], Real c[]);

// Computes norm of a three vector.

Real norm(const Real a[]);

// Problem post-initialization routine.

void problem_post_init();

// End of timestep analytics on the white dwarf properties.

void problem_post_timestep();

// Data we want to store, for interfacing with the Fortran

static int problem;
<commit_msg>Revert "Remove unused C++ variable"<commit_after>// Preprocessor directive for allowing us to do a post-initialization update.

#if (BL_SPACEDIM==3)
#ifndef do_problem_post_init
#define do_problem_post_init
#endif
#endif

// Preprocessor directive for allowing us to do a post-timestep update.

#ifndef do_problem_post_timestep
#define do_problem_post_timestep
#endif

// Routine for determining white dwarf masses, centers of mass and velocities.

void wdCOM (Real time, Real& mass_p, Real& mass_s, Real* com_p, Real* com_s, Real* vel_p, Real* vel_s);

// Volume within white dwarfs at a given density cutoff.

void volInBoundary (Real               time,
		    Real&              vol_p,
		    Real&              vol_s,
                    Real               rho_cutoff);

// Calculate gravitational wave signal.

void gwstrain (Real time,
	       Real& h_plus_1, Real& h_cross_1,
	       Real& h_plus_2, Real& h_cross_2,
	       Real& h_plus_3, Real& h_cross_3);

// Computes standard dot product of two three-vectors.

Real dot_product(const Real a[], const Real b[]);

// Computes standard cross-product of two three-vectors.

void cross_product(const Real a[], const Real b[], Real c[]);

// Computes norm of a three vector.

Real norm(const Real a[]);

// Problem post-initialization routine.

void problem_post_init();

// End of timestep analytics on the white dwarf properties.

void problem_post_timestep();

// Data we want to store, for interfacing with the Fortran

static bool relaxation_is_done;
static int problem;
<|endoftext|>