<commit_before>#define BOOST_TEST_MODULE test engines
#define BOOST_TEST_DYN_LINK

#include <vector>
#include <sstream>
#include <boost/test/unit_test.hpp>
#include <boost/mpl/list.hpp>

#include <trng/lcg64.hpp>
#include <trng/lcg64_shift.hpp>
#include <trng/mrg2.hpp>
#include <trng/mrg3.hpp>
#include <trng/mrg3s.hpp>
#include <trng/mrg4.hpp>
#include <trng/mrg5.hpp>
#include <trng/mrg5s.hpp>
#include <trng/yarn2.hpp>
#include <trng/yarn3.hpp>
#include <trng/yarn3s.hpp>
#include <trng/yarn4.hpp>
#include <trng/yarn5.hpp>
#include <trng/yarn5s.hpp>
#include <trng/lagfib2xor.hpp>
#include <trng/lagfib4xor.hpp>
#include <trng/lagfib2plus.hpp>
#include <trng/lagfib4plus.hpp>
#include <trng/mt19937.hpp>
#include <trng/mt19937_64.hpp>

typedef boost::mpl::list<trng::lcg64, trng::lcg64_shift,  //
                         trng::mrg2, trng::mrg3, trng::mrg3s, trng::mrg4, trng::mrg5,
                         trng::mrg5s,  //
                         trng::yarn2, trng::yarn3, trng::yarn3s, trng::yarn4, trng::yarn5,
                         trng::yarn5s,                                        //
                         trng::lagfib2xor_521_64, trng::lagfib4xor_521_32,    //
                         trng::lagfib2plus_521_32, trng::lagfib4plus_521_64,  //
                         trng::mt19937, trng::mt19937_64>
    engines;

template<typename R>
void advance_engine(R &r1, const long N) {
  for (long i{0}; i < N; ++i)
    r1();
}

template<typename R>
void advance_engine(R &r1, R &r2, const long N) {
  for (long i{0}; i < N; ++i) {
    r1();
    r2();
  }
}

template<typename R>
std::tuple<std::vector<typename R::result_type>, std::vector<typename R::result_type>>
generate_list(R &r1, R &r2, const long N) {
  std::vector<typename R::result_type> v1, v2;
  if (N > 0) {
    v1.reserve(N);
    v2.reserve(N);
  }
  for (long i{0}; i < N; ++i) {
    v1.push_back(r1());
    v2.push_back(r2());
  }
  return {v1, v2};
}

BOOST_AUTO_TEST_SUITE(test_suite_engines)

BOOST_AUTO_TEST_SUITE(test_suite_advance)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_advance, R, engines) {
  // two engines with equal state
  R r1, r2;
  advance_engine(r1, 271828l);  // advance engine r1
  BOOST_TEST(r1 != r2, "engines have different state");
}
BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE(test_suite_restore)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_restore, R, engines) {
  // three engines with equal state
  R r1, r2, r3;
  advance_engine(r1, r2, 271828l);  // advance engines ra and rb
  r3 = r1;                          // backup r1 in r3
  // advance ra such that ra and rb have different states
  advance_engine(r1, 314159l);
  r1 = r3;  // restore ra
  BOOST_TEST(r1 == r2, "engine state restored successfully");
  // when state has been restored correctly, r1 and r2 must yield the same values
  auto v = generate_list(r1, r2, 32);
  BOOST_TEST(std::get<0>(v) == std::get<1>(v), "engines yield same values after restore");
}
BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE(test_suite_status_io)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_status_io, R, engines) {
  // two engines with equal state
  R r1, r2;
  advance_engine(r1, 271828l);  // advance engine r1
  std::stringstream str;
  str << r1 << '\n';
  str >> r2;
  BOOST_TEST(r1 == r2, "engine state restored from stream successfully");
  // when state has been restored correctly, r1 and r2 must yield the same values
  auto v = generate_list(r1, r2, 32);
  BOOST_TEST(std::get<0>(v) == std::get<1>(v),
             "engines yield same values after restore from stream");
}
BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>add unit tests<commit_after>#include <vector>
#include <string>
#include <sstream>
#include <tuple>

#define BOOST_TEST_MODULE test engines
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include <boost/mpl/list.hpp>

#include <trng/lcg64.hpp>
#include <trng/lcg64_shift.hpp>
#include <trng/mrg2.hpp>
#include <trng/mrg3.hpp>
#include <trng/mrg3s.hpp>
#include <trng/mrg4.hpp>
#include <trng/mrg5.hpp>
#include <trng/mrg5s.hpp>
#include <trng/yarn2.hpp>
#include <trng/yarn3.hpp>
#include <trng/yarn3s.hpp>
#include <trng/yarn4.hpp>
#include <trng/yarn5.hpp>
#include <trng/yarn5s.hpp>
#include <trng/lagfib2xor.hpp>
#include <trng/lagfib4xor.hpp>
#include <trng/lagfib2plus.hpp>
#include <trng/lagfib4plus.hpp>
#include <trng/mt19937.hpp>
#include <trng/mt19937_64.hpp>

using engines =
    boost::mpl::list<trng::lcg64, trng::lcg64_shift,  //
                     trng::mrg2, trng::mrg3, trng::mrg3s, trng::mrg4, trng::mrg5,
                     trng::mrg5s,  //
                     trng::yarn2, trng::yarn3, trng::yarn3s, trng::yarn4, trng::yarn5,
                     trng::yarn5s,                                        //
                     trng::lagfib2xor_521_64, trng::lagfib4xor_521_32,    //
                     trng::lagfib2plus_521_32, trng::lagfib4plus_521_64,  //
                     trng::mt19937, trng::mt19937_64>;

using parallel_engines =
    boost::mpl::list<trng::lcg64, trng::lcg64_shift,  //
                     trng::mrg2, trng::mrg3, trng::mrg3s, trng::mrg4, trng::mrg5,
                     trng::mrg5s,  //
                     trng::yarn2, trng::yarn3, trng::yarn3s, trng::yarn4, trng::yarn5,
                     trng::yarn5s>;

using floats = boost::mpl::list<float, double, long double>;

template<typename R>
void advance_engine(R &r1, const long N) {
  for (long i{0}; i < N; ++i)
    r1();
}

template<typename R>
void advance_engine(R &r1, R &r2, const long N) {
  for (long i{0}; i < N; ++i) {
    r1();
    r2();
  }
}

template<typename R>
std::tuple<std::vector<typename R::result_type>, std::vector<typename R::result_type>>
generate_list(R &r1, R &r2, const long N, const long skip1, const long skip2) {
  std::vector<typename R::result_type> v1, v2;
  if (N > 0) {
    v1.reserve(N);
    v2.reserve(N);
  }
  for (long i{0}; i < N; ++i) {
    v1.push_back(r1());
    v2.push_back(r2());
    for (long j{0}; j < skip1; ++j)
      r1();
    for (long j{0}; j < skip2; ++j)
      r2();
  }
  return {v1, v2};
}

template<typename R>
std::tuple<std::vector<typename R::result_type>, std::vector<typename R::result_type>>
generate_list(R &r1, R &r2, const long N) {
  return generate_list(r1, r2, N, 0, 0);
}

//-----------------------------------------------------------------------------------------

BOOST_AUTO_TEST_SUITE(test_suite_engines)

//-----------------------------------------------------------------------------------------

BOOST_AUTO_TEST_SUITE(test_suite_advance)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_advance, R, engines) {
  // two engines with equal state
  R r1, r2;
  advance_engine(r1, 271828l);  // advance engine r1
  BOOST_TEST(r1 != r2, "engines have different state");
}
BOOST_AUTO_TEST_SUITE_END()

//-----------------------------------------------------------------------------------------

BOOST_AUTO_TEST_SUITE(test_suite_restore)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_restore, R, engines) {
  // three engines with equal state
  R r1, r2, r3;
  advance_engine(r1, r2, 271828l);  // advance engines ra and rb
  r3 = r1;                          // backup r1 in r3
  // advance ra such that ra and rb have different states
  advance_engine(r1, 314159l);
  r1 = r3;  // restore ra
  BOOST_TEST(r1 == r2, "engine state restored successfully");
  // when state has been restored correctly, r1 and r2 must yield the same values
  auto v = generate_list(r1, r2, 32);
  BOOST_TEST(std::get<0>(v) == std::get<1>(v), "engines yield same values after restore");
}
BOOST_AUTO_TEST_SUITE_END()

//-----------------------------------------------------------------------------------------

BOOST_AUTO_TEST_SUITE(test_suite_status_io)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_status_io, R, engines) {
  // two engines with equal state
  R r1, r2;
  advance_engine(r1, 271828l);  // advance engine r1
  std::stringstream str;
  str << r1;
  str >> r2;
  BOOST_TEST(r1 == r2, "engine state restored from stream successfully");
  // when state has been restored correctly, r1 and r2 must yield the same values
  auto v = generate_list(r1, r2, 32);
  BOOST_TEST(std::get<0>(v) == std::get<1>(v),
             "engines yield same values after restore from stream");
}
BOOST_AUTO_TEST_SUITE_END()

//-----------------------------------------------------------------------------------------

template<typename R>
struct generator_min_max {
  typedef typename R::result_type result_type;
  static constexpr result_type min() { return R::min(); }
  static constexpr result_type max() { return R::max(); }
};

template<typename R>
struct generator_min : public generator_min_max<R> {
  using base = generator_min_max<R>;
  typename base::result_type operator()() const { return base::min(); }
};

template<typename R>
struct generator_max : public generator_min_max<R> {
  using base = generator_min_max<R>;
  typename base::result_type operator()() const { return base::max(); }
};

template<typename T>
struct type_name;

template<>
struct type_name<float> {
  static const std::string name;
};

const std::string type_name<float>::name = "float";

template<>
struct type_name<double> {
  static const std::string name;
};

const std::string type_name<double>::name = "double";

template<>
struct type_name<long double> {
  static const std::string name;
};

const std::string type_name<long double>::name = "long double";

template<typename R, typename T>
void test_ranges_impl() {
  const std::string &name{type_name<T>::name};
  generator_min<R> r_min;
  generator_max<R> r_max;
  using u01xx_min = trng::utility::u01xx_traits<T, 1, generator_min<R>>;
  using u01xx_max = trng::utility::u01xx_traits<T, 1, generator_max<R>>;
  T x_min{}, x_max{};
  x_min = u01xx_min::cc(r_min);
  x_max = u01xx_max::cc(r_max);
  BOOST_TEST((x_min >= 0 && x_max <= 1), "[0, 1] bounds ok for " + name);
  x_min = u01xx_min::co(r_min);
  x_max = u01xx_max::co(r_max);
  BOOST_TEST((x_min >= 0 and x_max < 1), "[0, 1) bounds ok for " + name);
  x_min = u01xx_min::oc(r_min);
  x_max = u01xx_max::oc(r_max);
  BOOST_TEST((x_min > 0 and x_max <= 1), "(0, 1] bounds ok for " + name);
  x_min = u01xx_min::oo(r_min);
  x_max = u01xx_max::oo(r_max);
  BOOST_TEST((x_min > 0 and x_max < 1), "(0, 1) bounds ok for " + name);
}

BOOST_AUTO_TEST_SUITE(test_suite_ranges)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_ranges, R, engines) {
  test_ranges_impl<R, float>();
  test_ranges_impl<R, double>();
  test_ranges_impl<R, long double>();
}
BOOST_AUTO_TEST_SUITE_END()

//-----------------------------------------------------------------------------------------

BOOST_AUTO_TEST_SUITE(test_suite_jump2)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_jump2, R, parallel_engines) {
  // two engines with equal state
  R r1, r2;
  long n{1l};
  // jump ahead in steps of 2^i or step forwards in unit steps
  for (long i{0l}; i < 20l; ++i) {
    r1.jump2(i);
    for (long j{0l}; j < n; ++j)
      r2();
    std::stringstream message;
    message << "engines have equal state after jump2(" << i << ")";
    BOOST_TEST(r1 == r2, message.str().c_str());
    n <<= 1;
  }
}
BOOST_AUTO_TEST_SUITE_END()

//-----------------------------------------------------------------------------------------

BOOST_AUTO_TEST_SUITE(test_suite_split)
BOOST_AUTO_TEST_CASE_TEMPLATE(test_split, R, parallel_engines) {
  for (long i{2l}; i <= 20l; ++i) {
    for (long j{0l}; j < i; ++j) {
      // two engines with equal state
      R r1, r2;
      // split or step forwards in j unit steps
      for (long k{0l}; k < j; ++k)
        r1();
      r2.split(i, j);  // split into i streams, pick stream j
      {
        auto v = generate_list(r1, r2, 32, i - 1, 0);
        std::stringstream message;
        message << "engines yield same values after split(" << i << ", " << j << ")";
        BOOST_TEST(std::get<0>(v) == std::get<1>(v), message.str().c_str());
      }
    }
  }
}
BOOST_AUTO_TEST_SUITE_END()

//-----------------------------------------------------------------------------------------

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include "catch.hpp"
#include "LuaBinding.h"

void run( lua_State* L, const char* code );

using namespace ManualBind;

class Extra
{
};

using ExtraPtr = std::shared_ptr<Extra>;

struct ExtraBinding : public Binding<ExtraBinding,Extra>
{
    static constexpr const char* class_name = "Extra";

    static void setExtraMeta( lua_State* L )
    {
        lua_pushliteral( L, "Alara" );
        lua_setfield( L, -2, "DEF_NAME" );
    }
};

TEST_CASE( "Can set extra elements in class meta table." ) {

    lua_State* L = luaL_newstate();
    luaL_openlibs( L );

    ExtraBinding::register_class( L );

    ExtraPtr pp = std::make_shared<Extra>();

    ExtraBinding::push( L, pp );
    lua_setglobal( L, "person" );

    run( L, "name = person.DEF_NAME" );

    lua_getglobal( L, "name" );
    std::string name( lua_tostring( L, -1 ) );

    REQUIRE( name == "Alara" );

    lua_close( L );
}
<commit_msg>Add per instance extra table item test.<commit_after>#include "catch.hpp"
#include "LuaBinding.h"

void run( lua_State* L, const char* code );

using namespace ManualBind;

class Extra
{
};

using ExtraPtr = std::shared_ptr<Extra>;

struct ExtraBinding : public Binding<ExtraBinding,Extra>
{
    static constexpr const char* class_name = "Extra";

    static void setExtraMeta( lua_State* L )
    {
        lua_pushliteral( L, "Alara" );
        lua_setfield( L, -2, "DEF_NAME" );
    }
};

TEST_CASE( "Can set extra elements in class meta table." ) {

    lua_State* L = luaL_newstate();

    ExtraBinding::register_class( L );

    ExtraPtr pp = std::make_shared<Extra>();

    ExtraBinding::push( L, pp );
    lua_setglobal( L, "person" );

    run( L, "name = person.DEF_NAME" );

    lua_getglobal( L, "name" );
    std::string name( lua_tostring( L, -1 ) );

    REQUIRE( name == "Alara" );

    lua_close( L );
}

TEST_CASE( "Lua can assign extra elements per instance." ) {

    lua_State* L = luaL_newstate();

    ExtraBinding::register_class( L );

    ExtraPtr p1 = std::make_shared<Extra>();
    ExtraBinding::push( L, p1 );
    lua_setglobal( L, "p1" );

    ExtraPtr p2 = std::make_shared<Extra>();
    ExtraBinding::push( L, p2 );
    lua_setglobal( L, "p2" );

    run( L, "p1.perinstance = 'Nigel'" );

    run( L, "name = p1.perinstance" );

    lua_getglobal( L, "name" );
    std::string name( lua_tostring( L, -1 ) );

    REQUIRE( name == "Nigel" );

    run( L, "name = p2.perinstance" );

    lua_getglobal( L, "name" );

    REQUIRE( lua_type( L, -1 ) == LUA_TNIL );

    lua_close( L );
};
<|endoftext|>


<commit_before>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2022                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/
#include <modules/skybrowser/include/utility.h>

#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/camera/camera.h>
#include <glm/gtx/vector_angle.hpp>
#include <cmath>

namespace openspace::skybrowser {

// Converts from spherical coordinates in the unit of degrees to cartesian coordianates
glm::dvec3 sphericalToCartesian(const glm::dvec2& coords) {
    glm::dvec2 coordsRadians = glm::radians(coords);

    glm::dvec3 cartesian = glm::dvec3(
        cos(coordsRadians.x) * cos(coordsRadians.y),
        sin(coordsRadians.x) * cos(coordsRadians.y),
        sin(coordsRadians.y)
    );

    return cartesian;
}

// Converts from cartesian coordianates to spherical in the unit of degrees
glm::dvec2 cartesianToSpherical(const glm::dvec3& coord) {
    // Equatorial coordinates RA = right ascension, Dec = declination
    double ra = atan2(coord.y, coord.x);
    double dec = atan2(coord.z, glm::sqrt((coord.x * coord.x) + (coord.y * coord.y)));

    ra = ra > 0 ? ra : ra + (2.0 * glm::pi<double>());

    glm::dvec2 celestialCoords{ ra, dec };

    return glm::degrees(celestialCoords);
}

glm::dvec3 galacticToEquatorial(const glm::dvec3& coords) {
    return glm::transpose(conversionMatrix) * glm::normalize(coords);
}

glm::dvec3 equatorialToGalactic(const glm::dvec3& coords) {
    // On the unit sphere
    glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords);
    return rGalactic;
}

glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords) {
    // Ensure that if the coord is behind the camera,
    // the converted coordinate will be there too
    double zCoord = coords.z > 0 ? -ScreenSpaceZ : ScreenSpaceZ;

    // Calculate screen space coords x and y
    double tanX = coords.x / coords.z;
    double tanY = coords.y / coords.z;

    glm::dvec3 screenSpace = glm::dvec3(zCoord * tanX, zCoord * tanY, zCoord);

    return screenSpace;
}

glm::dvec3 localCameraToGalactic(const glm::dvec3& coords) {
    glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
    glm::dvec4 coordsVec4 = glm::dvec4(coords, 1.0) ;
    glm::dmat4 camMat = glm::inverse(
        global::navigationHandler->camera()->combinedViewMatrix()
    );
    // Subtract gamera position to get the view direction
    glm::dvec3 galactic = glm::dvec3(camMat * coordsVec4) - camPos;

    return glm::normalize(galactic) * skybrowser::CelestialSphereRadius;
}

glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords) {
    // Calculate the galactic coordinate of the target direction
    // projected onto the celestial sphere
    glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
    glm::dvec3 galactic = camPos + skybrowser::localCameraToGalactic(coords);

    return skybrowser::galacticToEquatorial(galactic);
}

glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords) {
    // Transform equatorial J2000 to galactic coord with infinite radius
    glm::dvec3 galactic = equatorialToGalactic(coords) * CelestialSphereRadius;
    glm::dvec3 localCamera = galacticToLocalCamera(galactic);
    return localCamera;
}

glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords) {
    // Transform vector to camera's local coordinate system
    glm::dmat4 camMat = global::navigationHandler->camera()->combinedViewMatrix();
    glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(coords, 1.0);

    return glm::normalize(viewDirectionLocal);
}

double cameraRoll() {
    openspace::Camera* camera = global::navigationHandler->camera();
    glm::dvec3 upWorld = camera->lookUpVectorWorldSpace();
    glm::dvec3 forwardWorld = camera->viewDirectionWorldSpace();

    glm::dvec3 camUpJ2000 = skybrowser::galacticToEquatorial(upWorld);
    glm::dvec3 camForwardJ2000 = skybrowser::galacticToEquatorial(forwardWorld);

    glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NorthPole);
    double dotNorthUp = glm::dot(skybrowser::NorthPole, camUpJ2000);
    double dotCrossUpNorthForward = glm::dot(crossUpNorth, camForwardJ2000);

    return glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp));
}

glm::dvec3 cameraDirectionEquatorial() {
    // Get the view direction of the screen in cartesian J2000 coordinates
    return galacticToEquatorial(cameraDirectionGalactic());
}

glm::dvec3 cameraDirectionGalactic() {
    // Get the view direction of the screen in galactic coordinates
    glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
    glm::dvec3 view = global::navigationHandler->camera()->viewDirectionWorldSpace();
    glm::dvec3 galCoord = camPos + (skybrowser::CelestialSphereRadius * view);

    return galCoord;
}

float windowRatio() {
    glm::vec2 windowRatio = global::windowDelegate->currentWindowSize();
    return windowRatio.x / windowRatio.y;
}

bool isCoordinateInView(const glm::dvec3& equatorial) {
    // Check if image coordinate is within current FOV
    glm::dvec3 localCamera = equatorialToLocalCamera(equatorial);
    glm::dvec3 coordsScreen = localCameraToScreenSpace3d(localCamera);
    double r = static_cast<float>(windowRatio());

    bool isCoordInView = abs(coordsScreen.x) < r && abs(coordsScreen.y) < 1.f &&
                                coordsScreen.z < 0;

    return isCoordInView;
}

// Transforms a pixel coordinate to a screen space coordinate
glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate) {
    glm::vec2 size = glm::vec2(global::windowDelegate->currentWindowSize());
    // Change origin to middle of the window
    glm::vec2 screenSpacePos = mouseCoordinate - (size / 2.0f);
    // Ensure the upper right corner is positive on the y axis
    screenSpacePos *= glm::vec2(1.0f, -1.0f);
    // Transform pixel coordinates to screen space coordinates [-1,1][-ratio, ratio]
    screenSpacePos /= (0.5f * size.y);
    return screenSpacePos;
}

// The horizontal and vertical fov of the OpenSpace window
glm::dvec2 fovWindow() {
    // OpenSpace FOV
    glm::dvec2 windowDim = glm::dvec2(global::windowDelegate->currentWindowSize());
    double windowRatio = windowDim.y / windowDim.x;
    double hFov = global::windowDelegate->getHorizFieldOfView();
    glm::dvec2 OpenSpaceFOV = glm::dvec2(hFov, hFov * windowRatio);
    return OpenSpaceFOV;
}

double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end) {
    // Find smallest angle between the two vectors
    double cos = glm::dot(start, end) / (glm::length(start) * glm::length(end));
    return std::acos(cos);
}

glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& end,
                                      double deltaTime, double speedFactor)
{
    double smallestAngle = angleBetweenVectors(start, end);
    // Calculate rotation this frame
    double rotationAngle = smallestAngle * deltaTime * speedFactor;

    // Create the rotation matrix for local camera space
    glm::dvec3 rotationAxis = glm::normalize(glm::cross(start, end));
    return glm::rotate(rotationAngle, rotationAxis);
}
double sizeFromFov(double fov, glm::dvec3 worldPosition) {

    // Calculate the size with trigonometry
    //  /|
    // /_|    Adjacent is the horizontal line, opposite the vertical
    // \ |    Calculate for half the triangle first, then multiply with 2
    //  \|
    double adjacent = glm::length(worldPosition);
    double opposite = 2 * adjacent * glm::tan(glm::radians(fov * 0.5));
    return opposite;
}
} // namespace openspace

<commit_msg>Fix precision issue that led to nan values. This fixes #1934<commit_after>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2022                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/
#include <modules/skybrowser/include/utility.h>

#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/camera/camera.h>
#include <glm/gtx/vector_angle.hpp>
#include <cmath>

namespace openspace::skybrowser {

// Converts from spherical coordinates in the unit of degrees to cartesian coordianates
glm::dvec3 sphericalToCartesian(const glm::dvec2& coords) {
    glm::dvec2 coordsRadians = glm::radians(coords);

    glm::dvec3 cartesian = glm::dvec3(
        cos(coordsRadians.x) * cos(coordsRadians.y),
        sin(coordsRadians.x) * cos(coordsRadians.y),
        sin(coordsRadians.y)
    );

    return cartesian;
}

// Converts from cartesian coordianates to spherical in the unit of degrees
glm::dvec2 cartesianToSpherical(const glm::dvec3& coord) {
    // Equatorial coordinates RA = right ascension, Dec = declination
    double ra = atan2(coord.y, coord.x);
    double dec = atan2(coord.z, glm::sqrt((coord.x * coord.x) + (coord.y * coord.y)));

    ra = ra > 0 ? ra : ra + (2.0 * glm::pi<double>());

    glm::dvec2 celestialCoords{ ra, dec };

    return glm::degrees(celestialCoords);
}

glm::dvec3 galacticToEquatorial(const glm::dvec3& coords) {
    return glm::transpose(conversionMatrix) * glm::normalize(coords);
}

glm::dvec3 equatorialToGalactic(const glm::dvec3& coords) {
    // On the unit sphere
    glm::dvec3 rGalactic = conversionMatrix * glm::normalize(coords);
    return rGalactic;
}

glm::dvec3 localCameraToScreenSpace3d(const glm::dvec3& coords) {
    // Ensure that if the coord is behind the camera,
    // the converted coordinate will be there too
    double zCoord = coords.z > 0 ? -ScreenSpaceZ : ScreenSpaceZ;

    // Calculate screen space coords x and y
    double tanX = coords.x / coords.z;
    double tanY = coords.y / coords.z;

    glm::dvec3 screenSpace = glm::dvec3(zCoord * tanX, zCoord * tanY, zCoord);

    return screenSpace;
}

glm::dvec3 localCameraToGalactic(const glm::dvec3& coords) {
    glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
    glm::dvec4 coordsVec4 = glm::dvec4(coords, 1.0) ;
    glm::dmat4 camMat = glm::inverse(
        global::navigationHandler->camera()->combinedViewMatrix()
    );
    // Subtract gamera position to get the view direction
    glm::dvec3 galactic = glm::dvec3(camMat * coordsVec4) - camPos;

    return glm::normalize(galactic) * skybrowser::CelestialSphereRadius;
}

glm::dvec3 localCameraToEquatorial(const glm::dvec3& coords) {
    // Calculate the galactic coordinate of the target direction
    // projected onto the celestial sphere
    glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
    glm::dvec3 galactic = camPos + skybrowser::localCameraToGalactic(coords);

    return skybrowser::galacticToEquatorial(galactic);
}

glm::dvec3 equatorialToLocalCamera(const glm::dvec3& coords) {
    // Transform equatorial J2000 to galactic coord with infinite radius
    glm::dvec3 galactic = equatorialToGalactic(coords) * CelestialSphereRadius;
    glm::dvec3 localCamera = galacticToLocalCamera(galactic);
    return localCamera;
}

glm::dvec3 galacticToLocalCamera(const glm::dvec3& coords) {
    // Transform vector to camera's local coordinate system
    glm::dmat4 camMat = global::navigationHandler->camera()->combinedViewMatrix();
    glm::dvec3 viewDirectionLocal = camMat * glm::dvec4(coords, 1.0);

    return glm::normalize(viewDirectionLocal);
}

double cameraRoll() {
    openspace::Camera* camera = global::navigationHandler->camera();
    glm::dvec3 upWorld = camera->lookUpVectorWorldSpace();
    glm::dvec3 forwardWorld = camera->viewDirectionWorldSpace();

    glm::dvec3 camUpJ2000 = skybrowser::galacticToEquatorial(upWorld);
    glm::dvec3 camForwardJ2000 = skybrowser::galacticToEquatorial(forwardWorld);

    glm::dvec3 crossUpNorth = glm::cross(camUpJ2000, skybrowser::NorthPole);
    double dotNorthUp = glm::dot(skybrowser::NorthPole, camUpJ2000);
    double dotCrossUpNorthForward = glm::dot(crossUpNorth, camForwardJ2000);

    return glm::degrees(atan2(dotCrossUpNorthForward, dotNorthUp));
}

glm::dvec3 cameraDirectionEquatorial() {
    // Get the view direction of the screen in cartesian J2000 coordinates
    return galacticToEquatorial(cameraDirectionGalactic());
}

glm::dvec3 cameraDirectionGalactic() {
    // Get the view direction of the screen in galactic coordinates
    glm::dvec3 camPos = global::navigationHandler->camera()->positionVec3();
    glm::dvec3 view = global::navigationHandler->camera()->viewDirectionWorldSpace();
    glm::dvec3 galCoord = camPos + (skybrowser::CelestialSphereRadius * view);

    return galCoord;
}

float windowRatio() {
    glm::vec2 windowRatio = global::windowDelegate->currentWindowSize();
    return windowRatio.x / windowRatio.y;
}

bool isCoordinateInView(const glm::dvec3& equatorial) {
    // Check if image coordinate is within current FOV
    glm::dvec3 localCamera = equatorialToLocalCamera(equatorial);
    glm::dvec3 coordsScreen = localCameraToScreenSpace3d(localCamera);
    double r = static_cast<float>(windowRatio());

    bool isCoordInView = abs(coordsScreen.x) < r && abs(coordsScreen.y) < 1.f &&
                                coordsScreen.z < 0;

    return isCoordInView;
}

// Transforms a pixel coordinate to a screen space coordinate
glm::vec2 pixelToScreenSpace2d(const glm::vec2& mouseCoordinate) {
    glm::vec2 size = glm::vec2(global::windowDelegate->currentWindowSize());
    // Change origin to middle of the window
    glm::vec2 screenSpacePos = mouseCoordinate - (size / 2.0f);
    // Ensure the upper right corner is positive on the y axis
    screenSpacePos *= glm::vec2(1.0f, -1.0f);
    // Transform pixel coordinates to screen space coordinates [-1,1][-ratio, ratio]
    screenSpacePos /= (0.5f * size.y);
    return screenSpacePos;
}

// The horizontal and vertical fov of the OpenSpace window
glm::dvec2 fovWindow() {
    // OpenSpace FOV
    glm::dvec2 windowDim = glm::dvec2(global::windowDelegate->currentWindowSize());
    double windowRatio = windowDim.y / windowDim.x;
    double hFov = global::windowDelegate->getHorizFieldOfView();
    glm::dvec2 OpenSpaceFOV = glm::dvec2(hFov, hFov * windowRatio);
    return OpenSpaceFOV;
}

double angleBetweenVectors(const glm::dvec3& start, const glm::dvec3& end) {
    // Find smallest angle between the two vectors
    double cos = glm::dot(glm::normalize(start), glm::normalize(end));
    // Ensure cos is within defined interval [-1,1]
    return std::acos(std::clamp(cos, -1.0, 1.0));
}

glm::dmat4 incrementalAnimationMatrix(const glm::dvec3& start, const glm::dvec3& end,
                                      double deltaTime, double speedFactor)
{
    double smallestAngle = angleBetweenVectors(start, end);
    // Calculate rotation this frame
    double rotationAngle = smallestAngle * deltaTime * speedFactor;

    // Create the rotation matrix for local camera space
    glm::dvec3 rotationAxis = glm::normalize(glm::cross(start, end));
    return glm::rotate(rotationAngle, rotationAxis);
}
double sizeFromFov(double fov, glm::dvec3 worldPosition) {

    // Calculate the size with trigonometry
    //  /|
    // /_|    Adjacent is the horizontal line, opposite the vertical
    // \ |    Calculate for half the triangle first, then multiply with 2
    //  \|
    double adjacent = glm::length(worldPosition);
    double opposite = 2 * adjacent * glm::tan(glm::radians(fov * 0.5));
    return opposite;
}
} // namespace openspace

<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
// Licensed to Qualys, Inc. (QUALYS) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// QUALYS licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/// @file
/// @brief IronBee --- PCRE module tests
///
/// @author Brian Rectanus <brectanus@qualys.com>
//////////////////////////////////////////////////////////////////////////////

#include "gtest/gtest.h"

#include "base_fixture.h"
#include <ironbee/rule_engine.h>
#include <ironbee/operator.h>
#include <ironbee/hash.h>
#include <ironbee/mpool.h>
#include <ironbee/field.h>
#include <ironbee/capture.h>
#include <ironbee/bytestr.h>

// @todo Remove once ib_engine_operator_get() is available.
#include "engine_private.h"

#include <string>

class PcreModuleTest : public BaseTransactionFixture
{
public:

    ib_rule_exec_t rule_exec1;
    ib_rule_exec_t rule_exec2;
    ib_rule_t *rule1;
    ib_rule_t *rule2;
    ib_field_t* field1;
    ib_field_t* field2;

    virtual void SetUp()
    {
        ib_status_t rc;
        const char *s1 = "string 1";
        const char *s2 = "string 2";

        BaseTransactionFixture::SetUp();
        configureIronBee();
        performTx();

        ib_mpool_t *mp = ib_engine_pool_main_get(ib_engine);
        char* str1 = (char *)ib_mpool_alloc(mp, (strlen(s1)+1));
        if (str1 == NULL) {
            throw std::runtime_error("Could not allocate string 1.");
        }
        strcpy(str1, s1);
        char* str2 = (char *)ib_mpool_alloc(mp, (strlen(s2)+1));
        if (str1 == NULL) {
            throw std::runtime_error("Could not allocate string 2.");
        }
        strcpy(str2, s2);

        // Create field 1.
        rc = ib_field_create(&field1,
                             mp,
                             IB_FIELD_NAME("field1"),
                             IB_FTYPE_NULSTR,
                             ib_ftype_nulstr_in(str1));
        if (rc != IB_OK) {
            throw std::runtime_error("Could not initialize field1.");
        }

        // Create field 2.
        rc = ib_field_create(&field2,
                             mp,
                             IB_FIELD_NAME("field2"),
                             IB_FTYPE_NULSTR,
                             ib_ftype_nulstr_in(str2));
        if (rc != IB_OK) {
            throw std::runtime_error("Could not initialize field2.");
        }

        /* Create rule 1 */
        rc = ib_rule_create(ib_engine,
                            ib_context_engine(ib_engine),
                            __FILE__,
                            __LINE__,
                            true,
                            &rule1);
        if (rc != IB_OK) {
            throw std::runtime_error("Could not create rule1.");
        }
        rc = ib_rule_set_id(ib_engine, rule1, "rule1");
        if (rc != IB_OK) {
            throw std::runtime_error("Could not set ID for rule1.");
        }

        /* Create the rule execution object #1 */
        memset(&rule_exec1, 0, sizeof(rule_exec1));
        rule_exec1.ib = ib_engine;
        rule_exec1.tx = ib_tx;
        rule_exec1.rule = rule1;

        /* Create rule 2 */
        rc = (ib_rule_create(ib_engine,
                             ib_context_engine(ib_engine),
                             __FILE__,
                             __LINE__,
                             true,
                             &rule2));
        if (rc != IB_OK) {
            throw std::runtime_error("Could not create rule2.");
        }
        rc = ib_rule_set_id(ib_engine, rule2, "rule2");
        if (rc != IB_OK) {
            throw std::runtime_error("Could not set ID for rule2.");
        }
        rule2->flags |= IB_RULE_FLAG_CAPTURE;

        /* Create the rule execution object #1 */
        memset(&rule_exec2, 0, sizeof(rule_exec2));
        rule_exec2.ib = ib_engine;
        rule_exec2.tx = ib_tx;
        rule_exec2.rule = rule2;
    }

};

TEST_F(PcreModuleTest, test_load_module)
{
    const ib_operator_t *op;
    ASSERT_EQ(IB_OK, ib_operator_lookup(ib_engine, "pcre", &op));
}

TEST_F(PcreModuleTest, test_pcre_operator)
{
    ib_field_t *outfield;
    ib_num_t result;
    ib_field_t *capture;
    const ib_operator_t *op;
    void *instance_data = NULL;
    ASSERT_EQ(IB_OK, ib_operator_lookup(ib_engine, "pcre", &op));

    // Create the operator instance.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_create(
              op,
              ib_context_main(ib_engine),
              IB_OP_CAPABILITY_NONE
              "string\\s2",
              &instance_data
        )
    );

    // Attempt to match.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_execute(
            op, instance_data,
            rule_exec1.tx,
            field1,
            NULL,
            &result
        )
    );

    // We should fail.
    ASSERT_FALSE(result);

    // Attempt to match again.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_execute(
            op, instance_data,
            rule_exec1.tx,
            field2,
            NULL,
            &result
        )
    );

    // This time we should succeed.
    ASSERT_TRUE(result);

    // Should be no capture set */
    outfield = getTarget1(IB_TX_CAPTURE":0");
    ASSERT_FALSE(outfield);

    // Create the operator instance.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_create(
            op,
            ib_context_main(ib_engine),
            IB_OP_CAPABILITY_NONE
            "(string 2)",
            &instance_data
        )
    );

    // Attempt to match.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_execute(
            op, instance_data,
            rule_exec1.tx,
            field1,
            NULL,
            &result
        )
    );

    // We should fail.
    ASSERT_FALSE(result);

    // Attempt to match again.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_execute(
            op, instance_data,
            rule_exec1.tx,
            field2,
            NULL,
            &result
        )
    );

    // This time we should succeed.
    ASSERT_TRUE(result);

    // Should be no capture (CAPTURE flag not set for rule 1)
    outfield = getTarget1(IB_TX_CAPTURE":0");
    ASSERT_FALSE(outfield);

    // Create the operator instance.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_create(
            op,
            ib_context_main(ib_engine),
            IB_OP_CAPABILITY_NONE,
            "(string 2)",
            &instance_data
        )
    );

    ASSERT_EQ(IB_OK,
              ib_capture_acquire(
                  rule_exec2.tx,
                  NULL,
                  &capture));

    // Attempt to match again.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_execute(
            op, instance_data,
            rule_exec1.tx,
            field2,
            capture,
            &result
        )
    );

    // This time we should succeed.
    ASSERT_TRUE(result);

    // Should be a capture (CAPTURE flag is set for rule 2)
    outfield = getTarget1(IB_TX_CAPTURE":0");
    ASSERT_TRUE(outfield);
}

TEST_F(PcreModuleTest, test_match_basic)
{
    ib_field_t *outfield;

    // Should be no capture set */
    outfield = getTarget1(IB_TX_CAPTURE":0");
    ASSERT_FALSE(outfield);
}

TEST_F(PcreModuleTest, test_match_capture)
{
    ib_field_t *ib_field;

    const ib_bytestr_t *ib_bytestr;
    ib_status_t rc;

    /* Check :0 */
    ib_field = getTarget1(IB_TX_CAPTURE":0");
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    /* Check :1 */
    ib_field = getTarget1(IB_TX_CAPTURE":1");
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    /* Check :2 */
    ib_field = getTarget1(IB_TX_CAPTURE":2");
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    rc = ib_field_value(ib_field, ib_ftype_bytestr_out(&ib_bytestr));
    ASSERT_EQ(IB_OK, rc);

    /* Check that a value is over written correctly. */
    ASSERT_EQ("4", std::string(
        reinterpret_cast<const char*>(ib_bytestr_const_ptr(ib_bytestr)),
        ib_bytestr_length(ib_bytestr)
    ));

    ib_field = getTarget1(IB_TX_CAPTURE":3");
    ASSERT_FALSE(ib_field);
}

TEST_F(PcreModuleTest, test_match_capture_named)
{
    ib_field_t *ib_field;
    const char *capname;

    const ib_bytestr_t *ib_bytestr;
    ib_status_t rc;

    /* Check :0 */
    capname = ib_capture_fullname(ib_tx, "captest", 0);
    ASSERT_STREQ(capname, "captest:0");
    ib_field = getTarget1(capname);
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    /* Check :1 */
    capname = ib_capture_fullname(ib_tx, "captest", 1);
    ASSERT_STREQ(capname, "captest:1");
    ib_field = getTarget1(capname);
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    /* Check :2 */
    capname = ib_capture_fullname(ib_tx, "captest", 2);
    ASSERT_STREQ(capname, "captest:2");
    ib_field = getTarget1(capname);
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    rc = ib_field_value(ib_field, ib_ftype_bytestr_out(&ib_bytestr));
    ASSERT_EQ(IB_OK, rc);

    /* Check that a value is over written correctly. */
    ASSERT_EQ("4", std::string(
        reinterpret_cast<const char*>(ib_bytestr_const_ptr(ib_bytestr)),
        ib_bytestr_length(ib_bytestr)
    ));

    capname = ib_capture_fullname(ib_tx, "captest", 3);
    ASSERT_STREQ(capname, "captest:3");
    ib_field = getTarget1(capname);
    ASSERT_FALSE(ib_field);
}
<commit_msg>test_module_pcre.cpp: Adding some missing commas.<commit_after>//////////////////////////////////////////////////////////////////////////////
// Licensed to Qualys, Inc. (QUALYS) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// QUALYS licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/// @file
/// @brief IronBee --- PCRE module tests
///
/// @author Brian Rectanus <brectanus@qualys.com>
//////////////////////////////////////////////////////////////////////////////

#include "gtest/gtest.h"

#include "base_fixture.h"
#include <ironbee/rule_engine.h>
#include <ironbee/operator.h>
#include <ironbee/hash.h>
#include <ironbee/mpool.h>
#include <ironbee/field.h>
#include <ironbee/capture.h>
#include <ironbee/bytestr.h>

// @todo Remove once ib_engine_operator_get() is available.
#include "engine_private.h"

#include <string>

class PcreModuleTest : public BaseTransactionFixture
{
public:

    ib_rule_exec_t rule_exec1;
    ib_rule_exec_t rule_exec2;
    ib_rule_t *rule1;
    ib_rule_t *rule2;
    ib_field_t* field1;
    ib_field_t* field2;

    virtual void SetUp()
    {
        ib_status_t rc;
        const char *s1 = "string 1";
        const char *s2 = "string 2";

        BaseTransactionFixture::SetUp();
        configureIronBee();
        performTx();

        ib_mpool_t *mp = ib_engine_pool_main_get(ib_engine);
        char* str1 = (char *)ib_mpool_alloc(mp, (strlen(s1)+1));
        if (str1 == NULL) {
            throw std::runtime_error("Could not allocate string 1.");
        }
        strcpy(str1, s1);
        char* str2 = (char *)ib_mpool_alloc(mp, (strlen(s2)+1));
        if (str1 == NULL) {
            throw std::runtime_error("Could not allocate string 2.");
        }
        strcpy(str2, s2);

        // Create field 1.
        rc = ib_field_create(&field1,
                             mp,
                             IB_FIELD_NAME("field1"),
                             IB_FTYPE_NULSTR,
                             ib_ftype_nulstr_in(str1));
        if (rc != IB_OK) {
            throw std::runtime_error("Could not initialize field1.");
        }

        // Create field 2.
        rc = ib_field_create(&field2,
                             mp,
                             IB_FIELD_NAME("field2"),
                             IB_FTYPE_NULSTR,
                             ib_ftype_nulstr_in(str2));
        if (rc != IB_OK) {
            throw std::runtime_error("Could not initialize field2.");
        }

        /* Create rule 1 */
        rc = ib_rule_create(ib_engine,
                            ib_context_engine(ib_engine),
                            __FILE__,
                            __LINE__,
                            true,
                            &rule1);
        if (rc != IB_OK) {
            throw std::runtime_error("Could not create rule1.");
        }
        rc = ib_rule_set_id(ib_engine, rule1, "rule1");
        if (rc != IB_OK) {
            throw std::runtime_error("Could not set ID for rule1.");
        }

        /* Create the rule execution object #1 */
        memset(&rule_exec1, 0, sizeof(rule_exec1));
        rule_exec1.ib = ib_engine;
        rule_exec1.tx = ib_tx;
        rule_exec1.rule = rule1;

        /* Create rule 2 */
        rc = (ib_rule_create(ib_engine,
                             ib_context_engine(ib_engine),
                             __FILE__,
                             __LINE__,
                             true,
                             &rule2));
        if (rc != IB_OK) {
            throw std::runtime_error("Could not create rule2.");
        }
        rc = ib_rule_set_id(ib_engine, rule2, "rule2");
        if (rc != IB_OK) {
            throw std::runtime_error("Could not set ID for rule2.");
        }
        rule2->flags |= IB_RULE_FLAG_CAPTURE;

        /* Create the rule execution object #1 */
        memset(&rule_exec2, 0, sizeof(rule_exec2));
        rule_exec2.ib = ib_engine;
        rule_exec2.tx = ib_tx;
        rule_exec2.rule = rule2;
    }

};

TEST_F(PcreModuleTest, test_load_module)
{
    const ib_operator_t *op;
    ASSERT_EQ(IB_OK, ib_operator_lookup(ib_engine, "pcre", &op));
}

TEST_F(PcreModuleTest, test_pcre_operator)
{
    ib_field_t *outfield;
    ib_num_t result;
    ib_field_t *capture;
    const ib_operator_t *op;
    void *instance_data = NULL;
    ASSERT_EQ(IB_OK, ib_operator_lookup(ib_engine, "pcre", &op));

    // Create the operator instance.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_create(
              op,
              ib_context_main(ib_engine),
              IB_OP_CAPABILITY_NONE,
              "string\\s2",
              &instance_data
        )
    );

    // Attempt to match.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_execute(
            op, instance_data,
            rule_exec1.tx,
            field1,
            NULL,
            &result
        )
    );

    // We should fail.
    ASSERT_FALSE(result);

    // Attempt to match again.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_execute(
            op, instance_data,
            rule_exec1.tx,
            field2,
            NULL,
            &result
        )
    );

    // This time we should succeed.
    ASSERT_TRUE(result);

    // Should be no capture set */
    outfield = getTarget1(IB_TX_CAPTURE":0");
    ASSERT_FALSE(outfield);

    // Create the operator instance.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_create(
            op,
            ib_context_main(ib_engine),
            IB_OP_CAPABILITY_NONE,
            "(string 2)",
            &instance_data
        )
    );

    // Attempt to match.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_execute(
            op, instance_data,
            rule_exec1.tx,
            field1,
            NULL,
            &result
        )
    );

    // We should fail.
    ASSERT_FALSE(result);

    // Attempt to match again.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_execute(
            op, instance_data,
            rule_exec1.tx,
            field2,
            NULL,
            &result
        )
    );

    // This time we should succeed.
    ASSERT_TRUE(result);

    // Should be no capture (CAPTURE flag not set for rule 1)
    outfield = getTarget1(IB_TX_CAPTURE":0");
    ASSERT_FALSE(outfield);

    // Create the operator instance.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_create(
            op,
            ib_context_main(ib_engine),
            IB_OP_CAPABILITY_NONE,
            "(string 2)",
            &instance_data
        )
    );

    ASSERT_EQ(IB_OK,
              ib_capture_acquire(
                  rule_exec2.tx,
                  NULL,
                  &capture));

    // Attempt to match again.
    ASSERT_EQ(
        IB_OK,
        ib_operator_inst_execute(
            op, instance_data,
            rule_exec1.tx,
            field2,
            capture,
            &result
        )
    );

    // This time we should succeed.
    ASSERT_TRUE(result);

    // Should be a capture (CAPTURE flag is set for rule 2)
    outfield = getTarget1(IB_TX_CAPTURE":0");
    ASSERT_TRUE(outfield);
}

TEST_F(PcreModuleTest, test_match_basic)
{
    ib_field_t *outfield;

    // Should be no capture set */
    outfield = getTarget1(IB_TX_CAPTURE":0");
    ASSERT_FALSE(outfield);
}

TEST_F(PcreModuleTest, test_match_capture)
{
    ib_field_t *ib_field;

    const ib_bytestr_t *ib_bytestr;
    ib_status_t rc;

    /* Check :0 */
    ib_field = getTarget1(IB_TX_CAPTURE":0");
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    /* Check :1 */
    ib_field = getTarget1(IB_TX_CAPTURE":1");
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    /* Check :2 */
    ib_field = getTarget1(IB_TX_CAPTURE":2");
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    rc = ib_field_value(ib_field, ib_ftype_bytestr_out(&ib_bytestr));
    ASSERT_EQ(IB_OK, rc);

    /* Check that a value is over written correctly. */
    ASSERT_EQ("4", std::string(
        reinterpret_cast<const char*>(ib_bytestr_const_ptr(ib_bytestr)),
        ib_bytestr_length(ib_bytestr)
    ));

    ib_field = getTarget1(IB_TX_CAPTURE":3");
    ASSERT_FALSE(ib_field);
}

TEST_F(PcreModuleTest, test_match_capture_named)
{
    ib_field_t *ib_field;
    const char *capname;

    const ib_bytestr_t *ib_bytestr;
    ib_status_t rc;

    /* Check :0 */
    capname = ib_capture_fullname(ib_tx, "captest", 0);
    ASSERT_STREQ(capname, "captest:0");
    ib_field = getTarget1(capname);
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    /* Check :1 */
    capname = ib_capture_fullname(ib_tx, "captest", 1);
    ASSERT_STREQ(capname, "captest:1");
    ib_field = getTarget1(capname);
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    /* Check :2 */
    capname = ib_capture_fullname(ib_tx, "captest", 2);
    ASSERT_STREQ(capname, "captest:2");
    ib_field = getTarget1(capname);
    ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field);
    ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type);

    rc = ib_field_value(ib_field, ib_ftype_bytestr_out(&ib_bytestr));
    ASSERT_EQ(IB_OK, rc);

    /* Check that a value is over written correctly. */
    ASSERT_EQ("4", std::string(
        reinterpret_cast<const char*>(ib_bytestr_const_ptr(ib_bytestr)),
        ib_bytestr_length(ib_bytestr)
    ));

    capname = ib_capture_fullname(ib_tx, "captest", 3);
    ASSERT_STREQ(capname, "captest:3");
    ib_field = getTarget1(capname);
    ASSERT_FALSE(ib_field);
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * projectm: visualization module based on libprojectM
 *****************************************************************************
 * Copyright (C) 2009 the VideoLAN team
 * $Id$
 *
 * Authors: Rémi Duraffort <ivoire@videolan.org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program 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 General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_aout.h>
#include <vlc_vout.h>

#include <libprojectM/projectM.hpp>

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open         ( vlc_object_t * );
static void Close        ( vlc_object_t * );

#define CONFIG_TEXT N_("projectM configuration file")
#define CONFIG_LONGTEXT N_("File that will be used to configure the projectM " \
                           "module.")

#define WIDTH_TEXT N_("Video width")
#define WIDTH_LONGTEXT N_("The width of the video window, in pixels.")

#define HEIGHT_TEXT N_("Video height")
#define HEIGHT_LONGTEXT N_("The height of the video window, in pixels.")

vlc_module_begin ()
    set_shortname( N_("projectM"))
    set_description( N_("libprojectM effect") )
    set_capability( "visualization", 0 )
    set_category( CAT_AUDIO )
    set_subcategory( SUBCAT_AUDIO_VISUAL )
    add_file( "projectm-config", "/usr/share/projectM/config.inp", NULL,
                CONFIG_TEXT, CONFIG_LONGTEXT, true )
    add_integer( "projectm-width", 800, NULL, WIDTH_TEXT, WIDTH_LONGTEXT,
                 false )
    add_integer( "projectm-height", 640, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT,
                 false )
    add_shortcut( "projectm" )
    set_callbacks( Open, Close )
vlc_module_end ()

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
typedef struct
{
    VLC_COMMON_MEMBERS

    /* video output module and opengl provider */
    vout_thread_t *p_opengl;
    module_t      *p_module;

    /* libprojectM objects */
    projectM      *p_projectm;
    char          *psz_config;

    /* Window size */
    int i_width;
    int i_height;

    /* audio info */
    int i_channels;
    float *p_buffer;
    int   i_buffer_size;
    int   i_nb_samples;

    vlc_mutex_t lock;
} projectm_thread_t;

struct aout_filter_sys_t
{
    projectm_thread_t *p_thread;
};

static void DoWork( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
                    aout_buffer_t * );
static void* Thread( vlc_object_t * );

/**
 * Init the openGL context
 * p_thread: projectm thread object
 * @return VLC_SUCCESS or vlc error codes
 */
static int initOpenGL( projectm_thread_t *p_thread )
{
    p_thread->p_opengl = (vout_thread_t *)vlc_object_create( p_thread,
                                                    sizeof( vout_thread_t ) );
    if( !p_thread->p_opengl )
        return VLC_ENOMEM;

    vlc_object_attach( p_thread->p_opengl, p_thread );

    /* Initialize the opengl object */
    video_format_Setup( &p_thread->p_opengl->fmt_in, VLC_CODEC_RGB32,
                        p_thread->i_width, p_thread->i_height, 1 );
    p_thread->p_opengl->i_window_width = p_thread->i_width;
    p_thread->p_opengl->i_window_height = p_thread->i_height;
    p_thread->p_opengl->render.i_width = p_thread->i_width;
    p_thread->p_opengl->render.i_height = p_thread->i_height;
    p_thread->p_opengl->render.i_aspect = VOUT_ASPECT_FACTOR;
    p_thread->p_opengl->b_fullscreen = false;
    p_thread->p_opengl->i_alignment = 0;
    p_thread->p_opengl->fmt_in.i_sar_num = 1;
    p_thread->p_opengl->fmt_in.i_sar_den = 1;
    p_thread->p_opengl->fmt_render = p_thread->p_opengl->fmt_in;

    /* Ask for the opengl provider */
    p_thread->p_module = module_need( p_thread->p_opengl, "opengl provider",
                                      NULL, false );
    if( !p_thread->p_module )
    {
        msg_Err( p_thread, "unable to initialize OpenGL" );
        vlc_object_detach( p_thread->p_opengl );
        vlc_object_release( p_thread->p_opengl );
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}

/**
 * Open the module
 * @param p_this: the filter object
 * @return VLC_SUCCESS or vlc error codes
 */
static int Open( vlc_object_t * p_this )
{
    aout_filter_t       *p_filter = (aout_filter_t *)p_this;
    aout_filter_sys_t   *p_sys;
    projectm_thread_t   *p_thread;

    /* Test the audio format */
    if( p_filter->input.i_format != VLC_CODEC_FL32 ||
        p_filter->output.i_format != VLC_CODEC_FL32 )
    {
        msg_Warn( p_filter, "bad input or output format" );
        return VLC_EGENERIC;
    }
    if( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
    {
        msg_Warn( p_filter, "input and outut are not similar" );
        return VLC_EGENERIC;
    }

    p_filter->pf_do_work = DoWork;
    p_filter->b_in_place = true;

    p_sys = p_filter->p_sys = (aout_filter_sys_t*)malloc( sizeof( *p_sys ) );
    if( !p_sys )
        return VLC_ENOMEM;

    /* Create the object for the thread */
    p_sys->p_thread = p_thread = (projectm_thread_t *)
                    vlc_object_create( p_filter, sizeof( projectm_thread_t ) );
    vlc_object_attach( p_sys->p_thread, p_filter );
    p_thread->i_width  = var_CreateGetInteger( p_filter, "projectm-width" );
    p_thread->i_height = var_CreateGetInteger( p_filter, "projectm-height" );

    /* Create the openGL provider */
    int i_ret = initOpenGL( p_sys->p_thread );
    if( i_ret != VLC_SUCCESS )
    {
        vlc_object_detach( p_sys->p_thread );
        vlc_object_release( p_sys->p_thread );
        free( p_sys );
        return i_ret;
    }

    p_thread->i_channels = aout_FormatNbChannels( &p_filter->input );
    p_thread->psz_config = var_CreateGetString( p_filter, "projectm-config" );
    vlc_mutex_init( &p_thread->lock );
    p_thread->p_buffer = NULL;
    p_thread->i_buffer_size = 0;
    p_thread->i_nb_samples = 0;

    /* Create the thread */
    if( vlc_thread_create( p_thread, "projectm update thread", Thread,
                           VLC_THREAD_PRIORITY_LOW ) )
    {
        msg_Err( p_filter, "cannot launch the projectm thread" );
        vlc_object_detach( p_thread );
        vlc_object_release( p_thread );
        free (p_sys );
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}

/**
 * Close the module
 * @param p_this: the filter object
 */
static void Close( vlc_object_t *p_this )
{
    aout_filter_t     *p_filter = (aout_filter_t *)p_this;
    aout_filter_sys_t *p_sys = p_filter->p_sys;
    projectm_thread_t *p_thread = p_sys->p_thread;

    /* Stop the thread */
    vlc_object_kill( p_thread );
    vlc_thread_join( p_thread );

    /* Free the ressources */
    vlc_mutex_destroy( &p_thread->lock );
    free( p_thread->p_buffer );
    free( p_thread->psz_config );

    vlc_object_detach( p_thread );
    vlc_object_release( p_thread );

    free( p_sys );
}

/**
 * Do the actual work with the new sample
 * @param p_aout: audio output object
 * @param p_filter: filter object
 * @param p_in_buf: input buffer
 * @param p_out_buf: output buffer
 */
static void DoWork( aout_instance_t *p_aout, aout_filter_t *p_filter,
                    aout_buffer_t *p_in_buf, aout_buffer_t *p_out_buf )
{
    projectm_thread_t *p_thread = p_filter->p_sys->p_thread;

    p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
    p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;

    vlc_mutex_lock( &p_thread->lock );
    if( p_thread->i_buffer_size > 0 )
    {
        p_thread->p_buffer[0] = 0;
        p_thread->i_nb_samples = __MIN( p_thread->i_buffer_size,
                                        p_in_buf->i_nb_samples );
        for( int i = 0; i < p_thread->i_nb_samples; i++ )
            p_thread->p_buffer[i] = p_in_buf->p_buffer[i];
    }

    vlc_mutex_unlock( &p_thread->lock );

    return;
}

/**
 * ProjectM update thread which do the rendering
 * @param p_this: the p_thread object
 */
static void* Thread( vlc_object_t *p_this )
{
    /* we don't want to be interupted in this thread */
    int cancel = vlc_savecancel();
    projectm_thread_t *p_thread = (projectm_thread_t *)p_this;

    /* Initialize the opengl provider for this thread */
    p_thread->p_opengl->pf_init( p_thread->p_opengl );

    /* Create the projectM object */
    p_thread->p_projectm = new projectM( p_thread->psz_config );
    p_thread->i_buffer_size = p_thread->p_projectm->pcm()->maxsamples;
    p_thread->p_buffer = (float*)malloc( p_thread->i_buffer_size *
                                         sizeof( float ) );

    /* TODO: Give to projectm the name of the input
    p_thread->p_projectm->projectM_setTitle( "" ); */

    /* Reset the dislay to get the right size */
    p_thread->p_projectm->projectM_resetGL( p_thread->i_width,
                                            p_thread->i_height );

    while( vlc_object_alive( p_thread ) )
    {
        /* Render the image and swap the buffers */
        vlc_mutex_lock( &p_thread->lock );
        if( p_thread->i_nb_samples > 0 )
            p_thread->p_projectm->pcm()->addPCMfloat( p_thread->p_buffer,
                                                      p_thread->i_nb_samples );

        p_thread->p_projectm->renderFrame();
        p_thread->p_opengl->pf_swap( p_thread->p_opengl );
        vlc_mutex_unlock( &p_thread->lock );

        /* TODO: use a fps limiter */
        msleep( 1000 );
    }

    /* Cleanup */
    delete p_thread->p_projectm;

    /* Free the openGL provider */
    module_unneed( p_thread->p_opengl, p_thread->p_module );
    vlc_object_detach( p_thread->p_opengl );
    vlc_object_release( p_thread->p_opengl );

    vlc_restorecancel( cancel );
    return NULL;
}
<commit_msg>projectm: manage the events.<commit_after>/*****************************************************************************
 * projectm: visualization module based on libprojectM
 *****************************************************************************
 * Copyright (C) 2009 the VideoLAN team
 * $Id$
 *
 * Authors: Rémi Duraffort <ivoire@videolan.org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program 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 General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51
 * Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_aout.h>
#include <vlc_vout.h>

#include <libprojectM/projectM.hpp>

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open         ( vlc_object_t * );
static void Close        ( vlc_object_t * );

#define CONFIG_TEXT N_("projectM configuration file")
#define CONFIG_LONGTEXT N_("File that will be used to configure the projectM " \
                           "module.")

#define WIDTH_TEXT N_("Video width")
#define WIDTH_LONGTEXT N_("The width of the video window, in pixels.")

#define HEIGHT_TEXT N_("Video height")
#define HEIGHT_LONGTEXT N_("The height of the video window, in pixels.")

vlc_module_begin ()
    set_shortname( N_("projectM"))
    set_description( N_("libprojectM effect") )
    set_capability( "visualization", 0 )
    set_category( CAT_AUDIO )
    set_subcategory( SUBCAT_AUDIO_VISUAL )
    add_file( "projectm-config", "/usr/share/projectM/config.inp", NULL,
                CONFIG_TEXT, CONFIG_LONGTEXT, true )
    add_integer( "projectm-width", 800, NULL, WIDTH_TEXT, WIDTH_LONGTEXT,
                 false )
    add_integer( "projectm-height", 640, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT,
                 false )
    add_shortcut( "projectm" )
    set_callbacks( Open, Close )
vlc_module_end ()

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
typedef struct
{
    VLC_COMMON_MEMBERS

    /* video output module and opengl provider */
    vout_thread_t *p_opengl;
    module_t      *p_module;

    /* libprojectM objects */
    projectM      *p_projectm;
    char          *psz_config;

    /* Window size */
    int i_width;
    int i_height;

    /* audio info */
    int i_channels;
    float *p_buffer;
    int   i_buffer_size;
    int   i_nb_samples;

    vlc_mutex_t lock;
} projectm_thread_t;

struct aout_filter_sys_t
{
    projectm_thread_t *p_thread;
};

static void DoWork( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
                    aout_buffer_t * );
static void* Thread( vlc_object_t * );

/**
 * Init the openGL context
 * p_thread: projectm thread object
 * @return VLC_SUCCESS or vlc error codes
 */
static int initOpenGL( projectm_thread_t *p_thread )
{
    p_thread->p_opengl = (vout_thread_t *)vlc_object_create( p_thread,
                                                    sizeof( vout_thread_t ) );
    if( !p_thread->p_opengl )
        return VLC_ENOMEM;

    vlc_object_attach( p_thread->p_opengl, p_thread );

    /* Initialize the opengl object */
    video_format_Setup( &p_thread->p_opengl->fmt_in, VLC_CODEC_RGB32,
                        p_thread->i_width, p_thread->i_height, 1 );
    p_thread->p_opengl->i_window_width = p_thread->i_width;
    p_thread->p_opengl->i_window_height = p_thread->i_height;
    p_thread->p_opengl->render.i_width = p_thread->i_width;
    p_thread->p_opengl->render.i_height = p_thread->i_height;
    p_thread->p_opengl->render.i_aspect = VOUT_ASPECT_FACTOR;
    p_thread->p_opengl->b_fullscreen = false;
    p_thread->p_opengl->b_autoscale = true;
    p_thread->p_opengl->i_alignment = 0;
    p_thread->p_opengl->fmt_in.i_sar_num = 1;
    p_thread->p_opengl->fmt_in.i_sar_den = 1;
    p_thread->p_opengl->fmt_render = p_thread->p_opengl->fmt_in;

    /* Ask for the opengl provider */
    p_thread->p_module = module_need( p_thread->p_opengl, "opengl provider",
                                      NULL, false );
    if( !p_thread->p_module )
    {
        msg_Err( p_thread, "unable to initialize OpenGL" );
        vlc_object_detach( p_thread->p_opengl );
        vlc_object_release( p_thread->p_opengl );
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}

/**
 * Open the module
 * @param p_this: the filter object
 * @return VLC_SUCCESS or vlc error codes
 */
static int Open( vlc_object_t * p_this )
{
    aout_filter_t       *p_filter = (aout_filter_t *)p_this;
    aout_filter_sys_t   *p_sys;
    projectm_thread_t   *p_thread;

    /* Test the audio format */
    if( p_filter->input.i_format != VLC_CODEC_FL32 ||
        p_filter->output.i_format != VLC_CODEC_FL32 )
    {
        msg_Warn( p_filter, "bad input or output format" );
        return VLC_EGENERIC;
    }
    if( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
    {
        msg_Warn( p_filter, "input and outut are not similar" );
        return VLC_EGENERIC;
    }

    p_filter->pf_do_work = DoWork;
    p_filter->b_in_place = true;

    p_sys = p_filter->p_sys = (aout_filter_sys_t*)malloc( sizeof( *p_sys ) );
    if( !p_sys )
        return VLC_ENOMEM;

    /* Create the object for the thread */
    p_sys->p_thread = p_thread = (projectm_thread_t *)
                    vlc_object_create( p_filter, sizeof( projectm_thread_t ) );
    vlc_object_attach( p_sys->p_thread, p_filter );
    p_thread->i_width  = var_CreateGetInteger( p_filter, "projectm-width" );
    p_thread->i_height = var_CreateGetInteger( p_filter, "projectm-height" );

    /* Create the openGL provider */
    int i_ret = initOpenGL( p_sys->p_thread );
    if( i_ret != VLC_SUCCESS )
    {
        vlc_object_detach( p_sys->p_thread );
        vlc_object_release( p_sys->p_thread );
        free( p_sys );
        return i_ret;
    }

    p_thread->i_channels = aout_FormatNbChannels( &p_filter->input );
    p_thread->psz_config = var_CreateGetString( p_filter, "projectm-config" );
    vlc_mutex_init( &p_thread->lock );
    p_thread->p_buffer = NULL;
    p_thread->i_buffer_size = 0;
    p_thread->i_nb_samples = 0;

    /* Create the thread */
    if( vlc_thread_create( p_thread, "projectm update thread", Thread,
                           VLC_THREAD_PRIORITY_LOW ) )
    {
        msg_Err( p_filter, "cannot launch the projectm thread" );
        vlc_object_detach( p_thread );
        vlc_object_release( p_thread );
        free (p_sys );
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}

/**
 * Close the module
 * @param p_this: the filter object
 */
static void Close( vlc_object_t *p_this )
{
    aout_filter_t     *p_filter = (aout_filter_t *)p_this;
    aout_filter_sys_t *p_sys = p_filter->p_sys;
    projectm_thread_t *p_thread = p_sys->p_thread;

    /* Stop the thread */
    vlc_object_kill( p_thread );
    vlc_thread_join( p_thread );

    /* Free the ressources */
    vlc_mutex_destroy( &p_thread->lock );
    free( p_thread->p_buffer );
    free( p_thread->psz_config );

    vlc_object_detach( p_thread );
    vlc_object_release( p_thread );

    free( p_sys );
}

/**
 * Do the actual work with the new sample
 * @param p_aout: audio output object
 * @param p_filter: filter object
 * @param p_in_buf: input buffer
 * @param p_out_buf: output buffer
 */
static void DoWork( aout_instance_t *p_aout, aout_filter_t *p_filter,
                    aout_buffer_t *p_in_buf, aout_buffer_t *p_out_buf )
{
    projectm_thread_t *p_thread = p_filter->p_sys->p_thread;

    p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
    p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;

    vlc_mutex_lock( &p_thread->lock );
    if( p_thread->i_buffer_size > 0 )
    {
        p_thread->p_buffer[0] = 0;
        p_thread->i_nb_samples = __MIN( p_thread->i_buffer_size,
                                        p_in_buf->i_nb_samples );
        for( int i = 0; i < p_thread->i_nb_samples; i++ )
            p_thread->p_buffer[i] = p_in_buf->p_buffer[i];
    }

    vlc_mutex_unlock( &p_thread->lock );

    return;
}

/**
 * ProjectM update thread which do the rendering
 * @param p_this: the p_thread object
 */
static void* Thread( vlc_object_t *p_this )
{
    /* we don't want to be interupted in this thread */
    int cancel = vlc_savecancel();
    projectm_thread_t *p_thread = (projectm_thread_t *)p_this;

    /* Initialize the opengl provider for this thread */
    p_thread->p_opengl->pf_init( p_thread->p_opengl );

    /* Create the projectM object */
    p_thread->p_projectm = new projectM( p_thread->psz_config );
    p_thread->i_buffer_size = p_thread->p_projectm->pcm()->maxsamples;
    p_thread->p_buffer = (float*)malloc( p_thread->i_buffer_size *
                                         sizeof( float ) );

    /* TODO: Give to projectm the name of the input
    p_thread->p_projectm->projectM_setTitle( "" ); */

    /* Reset the dislay to get the right size */
    p_thread->p_projectm->projectM_resetGL( p_thread->i_width,
                                            p_thread->i_height );

    while( vlc_object_alive( p_thread ) )
    {
        /* Manage the events */
        p_thread->p_opengl->pf_manage( p_thread->p_opengl );
        /* Render the image and swap the buffers */
        vlc_mutex_lock( &p_thread->lock );
        if( p_thread->i_nb_samples > 0 )
            p_thread->p_projectm->pcm()->addPCMfloat( p_thread->p_buffer,
                                                      p_thread->i_nb_samples );

        p_thread->p_projectm->renderFrame();
        p_thread->p_opengl->pf_swap( p_thread->p_opengl );
        vlc_mutex_unlock( &p_thread->lock );

        /* TODO: use a fps limiter */
        msleep( 1000 );
    }

    /* Cleanup */
    delete p_thread->p_projectm;

    /* Free the openGL provider */
    module_unneed( p_thread->p_opengl, p_thread->p_module );
    vlc_object_detach( p_thread->p_opengl );
    vlc_object_release( p_thread->p_opengl );

    vlc_restorecancel( cancel );
    return NULL;
}
<|endoftext|>


<commit_before>// Hunt the Wumpus - originally written in BASIC by Gregory Yob in 1973
// File Name: huntTheWumpus
// Programmer: Josh Guerra
// Last Modified: Dec 2, 2015

#include "myHeader.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

void main() {
	bool
		mapLoaded = false,		// helps me avoid reading files
		instrLoaded = false,	// and loading arrays more than needed
		statsLoaded = false;

	int const
		SIZE_TITLE = 4,
		SIZE_MENU = 4,

		SIZE_STATS = 3,			// most stats are grouped into arr[3] with other similar stats
		SIZE_INSTR = 37,		// num of lines in instructions.txt

		SIZE_ROOMS = 21,		// size is 1 more than used for map, done for alignment
		SIZE_EXITS = 3;

	int
		map[SIZE_ROOMS][SIZE_EXITS],

		gamesPld,				// stats
		whoWon[SIZE_STATS],

		moveCounter,			// keeps track of
		winner,					// current game outcome

		// game entities
		posPlayer = 1,
		posWumpus = 6,
		posBat1 = 3,
		posBat2 = 10,
		posPit1 = 13,
		posPit2 = 16;

	double
		winPct[SIZE_STATS],
		numMvs[SIZE_STATS];

	string
		mapFilename = "map.txt",
		instrFilename = "instructions.txt",
		statsFilename = "stats.txt",

		// loaded by input file
		instrArray[SIZE_INSTR],

		titleArr[SIZE_TITLE] = {
			"\t\t    CIT-120 Capstone Project    ",
			"\t\t          by J. Guerra          ",
			"\t\t        Hunt the Wumpus!        ",
			"\t\tOriginally by Gregory Yob (1973)"
		},

		menuArr[SIZE_MENU] = {
			"\t1] View Instructions",
			"\t2] View Statistics",
			"\t3] Play Game",
			"\t4] Exit Program"
		};

	ifstream
		ifsInstr,
		ifsStats;

	ofstream
		ofsStats;

	system("color 2f");		// set console color: 2 (green background), f (white text)

	// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //

	while (true) {
		printStringArr(titleArr, SIZE_TITLE);

		cout << endl << endl;
		printStringArr(menuArr, SIZE_MENU);
		cout << "\n\nPlease make a selection: ";

		switch (getIntInRange(1, 5)) {
			case 1:			// instructions
				if (!instrLoaded) {
					cout << "\n Loading statistics...";

					ifsInstr.open(instrFilename);
					loadStringArrayFromFile(instrArray, SIZE_INSTR, ifsInstr, instrLoaded);
					ifsInstr.close();

					cout << "Done loading statistics";
				}

				system("cls");
				printStringArr(instrArray, SIZE_INSTR);
				break;
			case 2:			// Stats
				if (!statsLoaded) {
					ifsStats.open(statsFilename);
					loadStats(gamesPld, whoWon, winPct, numMvs, SIZE_STATS, ifsStats, statsLoaded);
					ifsStats.close();
				}

				printStats(gamesPld, whoWon, winPct, numMvs, SIZE_STATS);
				break;
			case 3:
				cout
					<< "\n\tPlease finish each game."
					<< "\n\tStatistics will be automatically updated after each game."
					<< "\n\tYou may view statistics in main menu or in \"stats.txt\"";

				// load stats if not done already
				if (!statsLoaded) {
					cout << "\n\n\tLoading statistics...";

					ifsStats.open(statsFilename);
					loadStats(gamesPld, whoWon, winPct, numMvs, SIZE_STATS, ifsStats, statsLoaded);
					ifsStats.close();

					cout << "\n\tDone loading statistics\n\n";
				}
				else
					cout << "\n\n";

				// load map if not done already
				if (!mapLoaded) {
					cout << "\tLoading map...";
					load2DArr(map, SIZE_ROOMS, SIZE_EXITS);
					cout << "\n\tDone loading map\n\n";
				}

				system("pause");
				system("cls");

				// play game
				winner = startHunt(map, posPlayer, posWumpus, posBat1, posBat2, posPit1, posPit2, moveCounter);

				// update stats
				cout << "\n\n\tUpdating Statistics...";
				updateStats(gamesPld, whoWon, winPct, numMvs, SIZE_STATS, winner, moveCounter);
				cout
					<< "\n\tDone Updating Statistics..."
					<< "\n\n\tSaving Statistics in \"stats.txt\"";
				ofsStats.open(statsFilename);
				printStats(gamesPld, whoWon, winPct, numMvs, SIZE_STATS, ofsStats);
				ofsStats.close();
				cout << "\n\tDone Saving Statistics...";

				break;
			case 4:			// EXIT
				cout << "\nThank you for using my program.\n\n";
				system("pause");
				exit(0);
		}

		cout << endl << endl;
		system("pause");
		system("cls");
	}
}<commit_msg>added checks for valid open filestreams<commit_after>// Hunt the Wumpus - originally written in BASIC by Gregory Yob in 1973
// File Name: huntTheWumpus
// Programmer: Josh Guerra
// Last Modified: Dec 2, 2015

#include "myHeader.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

void main() {
	bool
		mapLoaded = false,		// helps me avoid reading files
		instrLoaded = false,	// and loading arrays more than needed
		statsLoaded = false;

	int const
		SIZE_TITLE = 4,
		SIZE_MENU = 4,

		SIZE_STATS = 3,			// most stats are grouped into arr[3] with other similar stats
		SIZE_INSTR = 37,		// num of lines in instructions.txt

		SIZE_ROOMS = 21,		// size is 1 more than used for map, done for alignment
		SIZE_EXITS = 3;

	int
		map[SIZE_ROOMS][SIZE_EXITS],

		gamesPld,				// stats
		whoWon[SIZE_STATS],

		moveCounter,			// keeps track of
		winner,					// current game outcome

		// game entities
		posPlayer = 1,
		posWumpus = 6,
		posBat1 = 3,
		posBat2 = 10,
		posPit1 = 13,
		posPit2 = 16;

	double
		winPct[SIZE_STATS],
		numMvs[SIZE_STATS];

	string
		instrFilename = "instructions.txt",
		statsFilename = "stats.txt",

		// loaded by input file
		instrArray[SIZE_INSTR],

		titleArr[SIZE_TITLE] = {
		"\t\t    CIT-120 Capstone Project    ",
		"\t\t          by J. Guerra          ",
		"\t\t        Hunt the Wumpus!        ",
		"\t\tOriginally by Gregory Yob (1973)"
	},

	menuArr[SIZE_MENU] = {
			"\t1] View Instructions",
			"\t2] View Statistics",
			"\t3] Play Game",
			"\t4] Exit Program"
		};

		ifstream
			ifsInstr,
			ifsStats;

		ofstream
			ofsStats;

		system("color 2f");		// set console color: 2 (green background), f (white text)

		// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //

		while (true) {
			printStringArr(titleArr, SIZE_TITLE);

			cout << endl << endl;
			printStringArr(menuArr, SIZE_MENU);
			cout << "\n\nPlease make a selection: ";

			switch (getIntInRange(1, 5)) {
			case 1:			// instructions
				if (!instrLoaded) {
					ifsInstr.open(instrFilename);
					if (!ifsInstr.fail()) {
						loadStringArrayFromFile(instrArray, SIZE_INSTR, ifsInstr, instrLoaded);
						ifsInstr.close();

						system("cls");
						printStringArr(instrArray, SIZE_INSTR);
					}
					else
						cout << "\n\tUnable to load instructions...";
				}
				else
					printStringArr(instrArray, SIZE_INSTR);

				break;
			case 2:			// Stats
				if (!statsLoaded) {
					ifsStats.open(statsFilename);
					if (!ifsStats.fail()) {
						cout << "\n\tLoading statistics...";
						loadStats(gamesPld, whoWon, winPct, numMvs, SIZE_STATS, ifsStats, statsLoaded);
						cout << "\n\tDone loading statistics";
						ifsStats.close();

						printStats(gamesPld, whoWon, winPct, numMvs, SIZE_STATS);
					}
					else
						cout << "\n\tUnable to load stats...";
				}
				else
					printStats(gamesPld, whoWon, winPct, numMvs, SIZE_STATS);

				break;
			case 3:
				cout
					<< "\n\tPlease finish each game."
					<< "\n\tStatistics will be automatically updated after each game."
					<< "\n\tYou may view statistics in main menu or in \"stats.txt\"";

				// load stats if not done already
				if (!statsLoaded) {
					ifsStats.open(statsFilename);
					if (!ifsStats.fail()) {
						cout << "\n\tLoading statistics...";
						loadStats(gamesPld, whoWon, winPct, numMvs, SIZE_STATS, ifsStats, statsLoaded);
						cout << "\n\tDone loading statistics";
						ifsStats.close();
					}
					else
						cout << "\n\tUnable to load stats...";
				}

				cout << "\n\n";

				// load map if not done already
				if (!mapLoaded) {
					cout << "\tLoading map...";
					load2DArr(map, SIZE_ROOMS, SIZE_EXITS);
					cout << "\n\tDone loading map\n\n";
				}

				system("pause");
				system("cls");

				// play game
				winner = startHunt(map, posPlayer, posWumpus, posBat1, posBat2, posPit1, posPit2, moveCounter);

				// update stats
				cout << "\n\n\tUpdating Statistics...";
				updateStats(gamesPld, whoWon, winPct, numMvs, SIZE_STATS, winner, moveCounter);
				cout
					<< "\n\tDone Updating Statistics..."
					<< "\n\n\tSaving Statistics in \"stats.txt\"";
				ofsStats.open(statsFilename);
				printStats(gamesPld, whoWon, winPct, numMvs, SIZE_STATS, ofsStats);
				ofsStats.close();
				cout << "\n\tDone Saving Statistics...";

				break;
			case 4:			// EXIT
				cout << "\nThank you for using my program.\n\n";
				system("pause");
				exit(0);
			}

			cout << endl << endl;
			system("pause");
			system("cls");
		}
}<|endoftext|>