<commit_before>// The "Square Detector" program.
// It loads several images sequentially and tries to find squares in
// each image

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <iostream>
#include <math.h>
#include <string.h>

using namespace cv;

int thresh = 50, N = 11;

// Find colors of any hue...
int wallHueLow  = 0;
int wallHueHigh = 179;

// ...of low saturation...
int wallSatLow  = 0;
int wallSatHigh = 40;

// ...ranging down to gray, but not completely dark. That is to say, white.
int wallValLow  = 50;
int wallValHigh = 255;

const char* wndname = "Square Detection Demo";

// helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
static double angle( Point pt1, Point pt2, Point pt0 )
{
    double dx1 = pt1.x - pt0.x;
    double dy1 = pt1.y - pt0.y;
    double dx2 = pt2.x - pt0.x;
    double dy2 = pt2.y - pt0.y;
    return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}

// returns sequence of squares detected on the image.
// the sequence is stored in the specified memory storage
static void findSquares( const Mat& image, vector<vector<Point> >& squares )
{
    squares.clear();

    Mat pyr, timg, gray0(image.size(), CV_8U), gray;

    // down-scale and upscale the image to filter out the noise
    pyrDown(image, pyr, Size(image.cols/2, image.rows/2));
    pyrUp(pyr, timg, image.size());
    vector<vector<Point> > contours;

    // find squares in every color plane of the image
    //for( int c = 0; c < 3; c++ )
    //{
        //int ch[] = {c, 0};
        //mixChannels(&timg, 1, &gray0, 1, ch, 1);

        // try several threshold levels
        for( int l = 0; l < N; l++ )
        {
            // hack: use Canny instead of zero threshold level.
            // Canny helps to catch squares with gradient shading
            if( l == 0 )
            {
                // apply Canny. Take the upper threshold from slider
                // and set the lower to 0 (which forces edges merging)
                Canny(gray0, gray, 0, thresh, 5);
                // dilate canny output to remove potential
                // holes between edge segments
                dilate(gray, gray, Mat(), Point(-1,-1));
            }
            else
            {
                // apply threshold if l!=0:
                //     tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
                gray = gray0 >= (l+1)*255/N;
            }

            // find contours and store them all as a list
            findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

            vector<Point> approx;

            // test each contour
            for( size_t i = 0; i < contours.size(); i++ )
            {
                // approximate contour with accuracy proportional
                // to the contour perimeter
                approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);

                // square contours should have 4 vertices after approximation
                // relatively large area (to filter out noisy contours)
                // and be convex.
                // Note: absolute value of an area is used because
                // area may be positive or negative - in accordance with the
                // contour orientation
                if( approx.size() == 4 &&
                    fabs(contourArea(Mat(approx))) > 1000 &&
                    isContourConvex(Mat(approx)) )
                {
                    double maxCosine = 0;

                    for( int j = 2; j < 5; j++ )
                    {
                        // find the maximum cosine of the angle between joint edges
                        double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
                        maxCosine = MAX(maxCosine, cosine);
                    }

                    // if cosines of all angles are small
                    // (all angles are ~90 degree) then write quandrange
                    // vertices to resultant sequence
                    if( maxCosine < 0.1 )
                        squares.push_back(approx);
                }
            }
        }
    //}
}

// the function draws all the squares in the image
static void drawSquares( Mat& image, const vector<vector<Point> >& squares )
{
    for( size_t i = 0; i < squares.size(); i++ )
    {
        const Point* p = &squares[i][0];
        int n = (int)squares[i].size();
        polylines(image, &p, &n, 1, true, Scalar(0,255,0), 3, CV_AA);
    }
}

int main(int /*argc*/, char** /*argv*/) {
    // Instantiate VideoCapture object. See here for details:
    // http://opencv.willowgarage.com/documentation/cpp/reading_and_writing_images_and_video.html
    VideoCapture cap(1);

    // Configure video. Our camera NEEDS the frame width to be set to 720
    // pixels.
    cap.set(CV_CAP_PROP_FRAME_WIDTH, 720);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    //cap.set(CV_CAP_PROP_FPS, 20);

    // Instantiate a Mat in which to store each video frame.
    Mat origFrame;
    Mat resizedFrame;   // Scaled-down from origFrame by factor of 2.
    Mat hsvFrame;   // Converted to HSV space from resizedFrame.
    Mat bwFrame;   // Black/white image after thresholding hsvFrame.

    namedWindow("origImage", 1);
    namedWindow("hsvImage", 1);
    namedWindow("bwImage", 1);
    cvNamedWindow("control panel");
    cvCreateTrackbar("threshold",   "control panel", &thresh,      300, NULL);
    cvCreateTrackbar("wallHueLow",  "control panel", &wallHueLow,  179, NULL);
    cvCreateTrackbar("wallHueHigh", "control panel", &wallHueHigh, 179, NULL);
    cvCreateTrackbar("wallSatLow",  "control panel", &wallSatLow,  255, NULL);
    cvCreateTrackbar("wallSatHigh", "control panel", &wallSatHigh, 255, NULL);
    cvCreateTrackbar("wallValLow",  "control panel", &wallValLow,  255, NULL);
    cvCreateTrackbar("wallValHigh", "control panel", &wallValHigh, 255, NULL);
    vector<vector<Point> > squares;

    while (true) {
        // Capture image.
        cap >> origFrame;

        // Resize the image to increase processing rate. See here for details:
        // http://opencv.willowgarage.com/documentation/cpp/image_filtering.html
        pyrDown(origFrame, resizedFrame, Size(origFrame.cols/2, origFrame.rows/2));

        // Convert the frame to HSV. TODO: combine this with more filtering and
        // turn into function.
        cvtColor(resizedFrame, hsvFrame, CV_BGR2HSV);

        // Threshold hsvFrame for color of maze walls.
        inRange(hsvFrame, Scalar(wallHueLow,  wallSatLow,  wallValLow),
                          Scalar(wallHueHigh, wallSatHigh, wallValHigh), bwFrame);

        // Find and draw squares.
        findSquares(bwFrame, squares);
        drawSquares(resizedFrame, squares);

        // Show the image, with the squares overlaid.
        imshow("origImage", resizedFrame);
        imshow("hsvImage", hsvFrame);
        imshow("bwImage", bwFrame);

        // Wait 5 milliseconds for a keypress.
        int c = waitKey(5);
        // Exit if the spacebar is pressed. NOTE: killing the program with
        // Ctrl+C sometimes stops OpenCV at a bad place and effects a kernel
        // panic! If you really like Ctrl+C, do so at your own risk!
        if ((char) c == 32) {
            return 0;
        }
    }

    return 0;
}
<commit_msg>Run square detection straight on the input image.<commit_after>// The "Square Detector" program.
// It loads several images sequentially and tries to find squares in
// each image

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <iostream>
#include <math.h>
#include <string.h>

using namespace cv;

int thresh = 50, N = 11;

// Find colors of any hue...
int wallHueLow  = 0;
int wallHueHigh = 179;

// ...of low saturation...
int wallSatLow  = 0;
int wallSatHigh = 40;

// ...ranging down to gray, but not completely dark. That is to say, white.
int wallValLow  = 50;
int wallValHigh = 255;

const char* wndname = "Square Detection Demo";

// helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
static double angle( Point pt1, Point pt2, Point pt0 )
{
    double dx1 = pt1.x - pt0.x;
    double dy1 = pt1.y - pt0.y;
    double dx2 = pt2.x - pt0.x;
    double dy2 = pt2.y - pt0.y;
    return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}

// returns sequence of squares detected on the image.
// the sequence is stored in the specified memory storage
static void findSquares( const Mat& image, vector<vector<Point> >& squares )
{
    squares.clear();

    Mat pyr, timg, gray0(image.size(), CV_8U), gray;

    // down-scale and upscale the image to filter out the noise
    pyrDown(image, pyr, Size(image.cols/2, image.rows/2));
    pyrUp(pyr, timg, image.size());
    vector<vector<Point> > contours;

    // find squares in every color plane of the image
    //for( int c = 0; c < 3; c++ )
    //{
        //int ch[] = {c, 0};
        //mixChannels(&timg, 1, &gray0, 1, ch, 1);

        // try several threshold levels
        for( int l = 0; l < N; l++ )
        {
            // hack: use Canny instead of zero threshold level.
            // Canny helps to catch squares with gradient shading
            if( l == 0 )
            {
                // apply Canny. Take the upper threshold from slider
                // and set the lower to 0 (which forces edges merging)
                Canny(image, gray, 0, thresh, 5);
                // dilate canny output to remove potential
                // holes between edge segments
                dilate(gray, gray, Mat(), Point(-1,-1));
            }
            else
            {
                // apply threshold if l!=0:
                //     tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
                gray = image >= (l+1)*255/N;
            }

            // find contours and store them all as a list
            findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

            vector<Point> approx;

            // test each contour
            for( size_t i = 0; i < contours.size(); i++ )
            {
                // approximate contour with accuracy proportional
                // to the contour perimeter
                approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);

                // square contours should have 4 vertices after approximation
                // relatively large area (to filter out noisy contours)
                // and be convex.
                // Note: absolute value of an area is used because
                // area may be positive or negative - in accordance with the
                // contour orientation
                if( approx.size() == 4 &&
                    fabs(contourArea(Mat(approx))) > 1000 &&
                    isContourConvex(Mat(approx)) )
                {
                    double maxCosine = 0;

                    for( int j = 2; j < 5; j++ )
                    {
                        // find the maximum cosine of the angle between joint edges
                        double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
                        maxCosine = MAX(maxCosine, cosine);
                    }

                    // if cosines of all angles are small
                    // (all angles are ~90 degree) then write quandrange
                    // vertices to resultant sequence
                    if( maxCosine < 0.3 )
                        squares.push_back(approx);
                }
            }
        }
    //}
}

// the function draws all the squares in the image
static void drawSquares( Mat& image, const vector<vector<Point> >& squares )
{
    for( size_t i = 0; i < squares.size(); i++ )
    {
        const Point* p = &squares[i][0];
        int n = (int)squares[i].size();
        polylines(image, &p, &n, 1, true, Scalar(0,255,0), 3, CV_AA);
    }
}

int main(int /*argc*/, char** /*argv*/) {
    // Instantiate VideoCapture object. See here for details:
    // http://opencv.willowgarage.com/documentation/cpp/reading_and_writing_images_and_video.html
    VideoCapture cap(1);

    // Configure video. Our camera NEEDS the frame width to be set to 720
    // pixels.
    cap.set(CV_CAP_PROP_FRAME_WIDTH, 720);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    //cap.set(CV_CAP_PROP_FPS, 20);

    // Instantiate a Mat in which to store each video frame.
    Mat origFrame;
    Mat resizedFrame;   // Scaled-down from origFrame by factor of 2.
    Mat hsvFrame;   // Converted to HSV space from resizedFrame.
    Mat bwFrame;   // Black/white image after thresholding hsvFrame.

    namedWindow("origImage", 1);
    namedWindow("hsvImage", 1);
    namedWindow("bwImage", 1);
    cvNamedWindow("control panel");
    cvCreateTrackbar("threshold",   "control panel", &thresh,      300, NULL);
    cvCreateTrackbar("wallHueLow",  "control panel", &wallHueLow,  179, NULL);
    cvCreateTrackbar("wallHueHigh", "control panel", &wallHueHigh, 179, NULL);
    cvCreateTrackbar("wallSatLow",  "control panel", &wallSatLow,  255, NULL);
    cvCreateTrackbar("wallSatHigh", "control panel", &wallSatHigh, 255, NULL);
    cvCreateTrackbar("wallValLow",  "control panel", &wallValLow,  255, NULL);
    cvCreateTrackbar("wallValHigh", "control panel", &wallValHigh, 255, NULL);
    vector<vector<Point> > squares;

    while (true) {
        // Capture image.
        cap >> origFrame;

        // Resize the image to increase processing rate. See here for details:
        // http://opencv.willowgarage.com/documentation/cpp/image_filtering.html
        pyrDown(origFrame, resizedFrame, Size(origFrame.cols/2, origFrame.rows/2));

        // Convert the frame to HSV. TODO: combine this with more filtering and
        // turn into function.
        cvtColor(resizedFrame, hsvFrame, CV_BGR2HSV);

        // Threshold hsvFrame for color of maze walls.
        inRange(hsvFrame, Scalar(wallHueLow,  wallSatLow,  wallValLow),
                          Scalar(wallHueHigh, wallSatHigh, wallValHigh), bwFrame);

        // Find and draw squares.
        findSquares(bwFrame, squares);
        drawSquares(resizedFrame, squares);

        // Show the image, with the squares overlaid.
        imshow("origImage", resizedFrame);
        imshow("hsvImage", hsvFrame);
        imshow("bwImage", bwFrame);

        // Wait 5 milliseconds for a keypress.
        int c = waitKey(5);
        // Exit if the spacebar is pressed. NOTE: killing the program with
        // Ctrl+C sometimes stops OpenCV at a bad place and effects a kernel
        // panic! If you really like Ctrl+C, do so at your own risk!
        if ((char) c == 32) {
            return 0;
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>#include <gst/gst.h>
#include "SdpEndpointImpl.hpp"
#include <jsonrpc/JsonSerializer.hpp>
#include <KurentoException.hpp>
#include <gst/gst.h>
#include <gst/sdp/gstsdpmessage.h>
#include <boost/filesystem.hpp>
#include <fstream>

#define GST_CAT_DEFAULT kurento_sdp_endpoint_impl
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define GST_DEFAULT_NAME "KurentoSdpEndpointImpl"

namespace kurento
{

static GstSDPMessage *
str_to_sdp (const std::string &sdpStr)
{
  GstSDPResult result;
  GstSDPMessage *sdp = NULL;

  result = gst_sdp_message_new (&sdp);

  if (result != GST_SDP_OK) {
    throw KurentoException (SDP_CREATE_ERROR, "Error creating SDP message");
  }

  result = gst_sdp_message_parse_buffer ( (const guint8 *) sdpStr.c_str (), -1,
                                          sdp);

  if (result != GST_SDP_OK) {

    gst_sdp_message_free (sdp);
    throw KurentoException (SDP_PARSE_ERROR, "Error parsing SDP");
  }

  return sdp;
}

static void
sdp_to_str (std::string &_return, const GstSDPMessage *sdp)
{
  std::string sdpStr;
  gchar *sdpGchar;

  sdpGchar = gst_sdp_message_as_text (sdp);
  _return.clear ();
  _return.append (sdpGchar);
  free (sdpGchar);
}

static std::string
readEntireFile (const std::string &file_name)
{
  std::ifstream t (file_name);
  std::string ret ( (std::istreambuf_iterator<char> (t) ),
                    std::istreambuf_iterator<char>() );

  if (ret.empty() ) {
    GST_ERROR ("Cannot read sdp pattern from: %s", file_name.c_str() );
    throw kurento::KurentoException (SDP_CONFIGURATION_ERROR, "Error reading SDP pattern from configuration, please contact the administrator");
  }

  return ret;
}

static std::shared_ptr <GstSDPMessage> pattern;
static std::mutex mutex;

static GstSDPMessage *
getSdpPattern (const boost::property_tree::ptree &config)
{
  GstSDPMessage *sdp;
  GstSDPResult result;
  boost::filesystem::path sdp_pattern_file;
  std::unique_lock<std::mutex> lock (mutex);

  if (pattern)
    return pattern.get();

  try {
    sdp_pattern_file = boost::filesystem::path (config.get<std::string> ("modules.kurento.SdpEndpoint.pattern") );
  } catch (boost::property_tree::ptree_error &e) {
    throw kurento::KurentoException (SDP_CONFIGURATION_ERROR, "Error reading SDP pattern from configuration, please contact the administrator: " + std::string (e.what() ) );
  }

  if (!sdp_pattern_file.is_absolute() ) {
    try {
      sdp_pattern_file = boost::filesystem::path (config.get<std::string> ("configPath") ) / sdp_pattern_file;
    } catch (boost::property_tree::ptree_error &e) {

    }
  }

  result = gst_sdp_message_new (&sdp);

  if (result != GST_SDP_OK) {
    GST_ERROR ("Error creating sdp message");
    throw kurento::KurentoException (SDP_CREATE_ERROR, "Error creating SDP pattern");
  }

  pattern = std::shared_ptr<GstSDPMessage> (sdp, gst_sdp_message_free);

  result = gst_sdp_message_parse_buffer ( (const guint8 *) readEntireFile (sdp_pattern_file.string() ).c_str(), -1, sdp);

  if (result != GST_SDP_OK) {
    GST_ERROR ("Error parsing SDP config pattern");
    pattern.reset();
    throw kurento::KurentoException (SDP_CONFIGURATION_ERROR, "Error reading SDP pattern from configuration, please contact the administrator");
  }

  return pattern.get();
}

SdpEndpointImpl::SdpEndpointImpl (const boost::property_tree::ptree &config,
                                  std::shared_ptr< MediaObjectImpl > parent,
                                  const std::string &factoryName) :
  SessionEndpointImpl (config, parent, factoryName)
{
  //   TODO: Add support for this events
  //   g_signal_connect (element, "media-start", G_CALLBACK (media_start_cb), this);
  //   g_signal_connect (element, "media-stop", G_CALLBACK (media_stop_cb), this);

  g_object_set (element, "pattern-sdp", getSdpPattern (config), NULL);
}

std::string SdpEndpointImpl::generateOffer ()
{
  GstSDPMessage *offer = NULL;
  std::string offerStr;

  if (element == NULL) {
  }

  g_signal_emit_by_name (element, "generate-offer", &offer);

  if (offer == NULL) {
    throw KurentoException (SDP_END_POINT_GENERATE_OFFER_ERROR,
                            "Error generating offer");
  }

  sdp_to_str (offerStr, offer);
  gst_sdp_message_free (offer);

  return offerStr;
}

std::string SdpEndpointImpl::processOffer (const std::string &offer)
{
  GstSDPMessage *offerSdp = NULL, *result = NULL;
  std::string offerSdpStr;

  offerSdp = str_to_sdp (offer);
  g_signal_emit_by_name (element, "process-offer", offerSdp, &result);
  gst_sdp_message_free (offerSdp);

  if (result == NULL) {
    throw KurentoException (SDP_END_POINT_PROCESS_OFFER_ERROR,
                            "Error processing offer");
  }

  sdp_to_str (offerSdpStr, result);
  gst_sdp_message_free (result);

  MediaSessionStarted event (shared_from_this(), MediaSessionStarted::getName() );
  signalMediaSessionStarted (event);

  return offerSdpStr;
}

std::string SdpEndpointImpl::processAnswer (const std::string &answer)
{
  GstSDPMessage *answerSdp;
  std::string resultStr;

  answerSdp = str_to_sdp (answer);
  g_signal_emit_by_name (element, "process-answer", answerSdp, NULL);
  gst_sdp_message_free (answerSdp);

  MediaSessionStarted event (shared_from_this(), MediaSessionStarted::getName() );
  signalMediaSessionStarted (event);

  return getLocalSessionDescriptor ();
}

std::string SdpEndpointImpl::getLocalSessionDescriptor ()
{
  GstSDPMessage *localSdp = NULL;
  std::string localSdpStr;

  g_object_get (element, "local-answer-sdp", &localSdp, NULL);

  if (localSdp == NULL) {
    g_object_get (element, "local-offer-sdp", &localSdp, NULL);
  }

  if (localSdp == NULL) {
    throw KurentoException (SDP_END_POINT_NO_LOCAL_SDP_ERROR, "No local SDP");
  }

  sdp_to_str (localSdpStr, localSdp);
  gst_sdp_message_free (localSdp);

  return localSdpStr;
}

std::string SdpEndpointImpl::getRemoteSessionDescriptor ()
{
  GstSDPMessage *remoteSdp = NULL;
  std::string remoteSdpStr;

  g_object_get (element, "remote-answer-sdp", &remoteSdp, NULL);

  if (remoteSdp == NULL) {
    g_object_get (element, "remote-offer-sdp", &remoteSdp, NULL);
  }

  if (remoteSdp == NULL) {
    throw KurentoException (SDP_END_POINT_NO_REMOTE_SDP_ERROR, "No remote SDP");
  }

  sdp_to_str (remoteSdpStr, remoteSdp);;
  gst_sdp_message_free (remoteSdp);

  return remoteSdpStr;
}

SdpEndpointImpl::StaticConstructor SdpEndpointImpl::staticConstructor;

SdpEndpointImpl::StaticConstructor::StaticConstructor()
{
  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0,
                           GST_DEFAULT_NAME);
}

} /* kurento */
<commit_msg>Fix SdpEndpoint configuration process<commit_after>#include <gst/gst.h>
#include "SdpEndpointImpl.hpp"
#include <jsonrpc/JsonSerializer.hpp>
#include <KurentoException.hpp>
#include <gst/gst.h>
#include <gst/sdp/gstsdpmessage.h>
#include <boost/filesystem.hpp>
#include <fstream>

#define GST_CAT_DEFAULT kurento_sdp_endpoint_impl
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define GST_DEFAULT_NAME "KurentoSdpEndpointImpl"

namespace kurento
{

static GstSDPMessage *
str_to_sdp (const std::string &sdpStr)
{
  GstSDPResult result;
  GstSDPMessage *sdp = NULL;

  result = gst_sdp_message_new (&sdp);

  if (result != GST_SDP_OK) {
    throw KurentoException (SDP_CREATE_ERROR, "Error creating SDP message");
  }

  result = gst_sdp_message_parse_buffer ( (const guint8 *) sdpStr.c_str (), -1,
                                          sdp);

  if (result != GST_SDP_OK) {

    gst_sdp_message_free (sdp);
    throw KurentoException (SDP_PARSE_ERROR, "Error parsing SDP");
  }

  return sdp;
}

static void
sdp_to_str (std::string &_return, const GstSDPMessage *sdp)
{
  std::string sdpStr;
  gchar *sdpGchar;

  sdpGchar = gst_sdp_message_as_text (sdp);
  _return.clear ();
  _return.append (sdpGchar);
  free (sdpGchar);
}

static std::string
readEntireFile (const std::string &file_name)
{
  std::ifstream t (file_name);
  std::string ret ( (std::istreambuf_iterator<char> (t) ),
                    std::istreambuf_iterator<char>() );

  if (ret.empty() ) {
    GST_ERROR ("Cannot read sdp pattern from: %s", file_name.c_str() );
    throw kurento::KurentoException (SDP_CONFIGURATION_ERROR, "Error reading SDP pattern from configuration, please contact the administrator");
  }

  return ret;
}

static std::shared_ptr <GstSDPMessage> pattern;
static std::mutex mutex;

static GstSDPMessage *
getSdpPattern (const boost::property_tree::ptree &config)
{
  GstSDPMessage *sdp;
  GstSDPResult result;
  boost::filesystem::path sdp_pattern_file;
  std::unique_lock<std::mutex> lock (mutex);

  if (pattern)
    return pattern.get();

  try {
    sdp_pattern_file = boost::filesystem::path (config.get<std::string> ("modules.kurento.SdpEndpoint.sdpPattern") );
  } catch (boost::property_tree::ptree_error &e) {
    throw kurento::KurentoException (SDP_CONFIGURATION_ERROR, "Error reading SDP pattern from configuration, please contact the administrator: " + std::string (e.what() ) );
  }

  if (!sdp_pattern_file.is_absolute() ) {
    try {
      sdp_pattern_file = boost::filesystem::path (config.get<std::string> ("configPath") ) / sdp_pattern_file;
    } catch (boost::property_tree::ptree_error &e) {

    }
  }

  result = gst_sdp_message_new (&sdp);

  if (result != GST_SDP_OK) {
    GST_ERROR ("Error creating sdp message");
    throw kurento::KurentoException (SDP_CREATE_ERROR, "Error creating SDP pattern");
  }

  pattern = std::shared_ptr<GstSDPMessage> (sdp, gst_sdp_message_free);

  result = gst_sdp_message_parse_buffer ( (const guint8 *) readEntireFile (sdp_pattern_file.string() ).c_str(), -1, sdp);

  if (result != GST_SDP_OK) {
    GST_ERROR ("Error parsing SDP config pattern");
    pattern.reset();
    throw kurento::KurentoException (SDP_CONFIGURATION_ERROR, "Error reading SDP pattern from configuration, please contact the administrator");
  }

  return pattern.get();
}

SdpEndpointImpl::SdpEndpointImpl (const boost::property_tree::ptree &config,
                                  std::shared_ptr< MediaObjectImpl > parent,
                                  const std::string &factoryName) :
  SessionEndpointImpl (config, parent, factoryName)
{
  //   TODO: Add support for this events
  //   g_signal_connect (element, "media-start", G_CALLBACK (media_start_cb), this);
  //   g_signal_connect (element, "media-stop", G_CALLBACK (media_stop_cb), this);

  g_object_set (element, "pattern-sdp", getSdpPattern (config), NULL);
}

std::string SdpEndpointImpl::generateOffer ()
{
  GstSDPMessage *offer = NULL;
  std::string offerStr;

  if (element == NULL) {
  }

  g_signal_emit_by_name (element, "generate-offer", &offer);

  if (offer == NULL) {
    throw KurentoException (SDP_END_POINT_GENERATE_OFFER_ERROR,
                            "Error generating offer");
  }

  sdp_to_str (offerStr, offer);
  gst_sdp_message_free (offer);

  return offerStr;
}

std::string SdpEndpointImpl::processOffer (const std::string &offer)
{
  GstSDPMessage *offerSdp = NULL, *result = NULL;
  std::string offerSdpStr;

  offerSdp = str_to_sdp (offer);
  g_signal_emit_by_name (element, "process-offer", offerSdp, &result);
  gst_sdp_message_free (offerSdp);

  if (result == NULL) {
    throw KurentoException (SDP_END_POINT_PROCESS_OFFER_ERROR,
                            "Error processing offer");
  }

  sdp_to_str (offerSdpStr, result);
  gst_sdp_message_free (result);

  MediaSessionStarted event (shared_from_this(), MediaSessionStarted::getName() );
  signalMediaSessionStarted (event);

  return offerSdpStr;
}

std::string SdpEndpointImpl::processAnswer (const std::string &answer)
{
  GstSDPMessage *answerSdp;
  std::string resultStr;

  answerSdp = str_to_sdp (answer);
  g_signal_emit_by_name (element, "process-answer", answerSdp, NULL);
  gst_sdp_message_free (answerSdp);

  MediaSessionStarted event (shared_from_this(), MediaSessionStarted::getName() );
  signalMediaSessionStarted (event);

  return getLocalSessionDescriptor ();
}

std::string SdpEndpointImpl::getLocalSessionDescriptor ()
{
  GstSDPMessage *localSdp = NULL;
  std::string localSdpStr;

  g_object_get (element, "local-answer-sdp", &localSdp, NULL);

  if (localSdp == NULL) {
    g_object_get (element, "local-offer-sdp", &localSdp, NULL);
  }

  if (localSdp == NULL) {
    throw KurentoException (SDP_END_POINT_NO_LOCAL_SDP_ERROR, "No local SDP");
  }

  sdp_to_str (localSdpStr, localSdp);
  gst_sdp_message_free (localSdp);

  return localSdpStr;
}

std::string SdpEndpointImpl::getRemoteSessionDescriptor ()
{
  GstSDPMessage *remoteSdp = NULL;
  std::string remoteSdpStr;

  g_object_get (element, "remote-answer-sdp", &remoteSdp, NULL);

  if (remoteSdp == NULL) {
    g_object_get (element, "remote-offer-sdp", &remoteSdp, NULL);
  }

  if (remoteSdp == NULL) {
    throw KurentoException (SDP_END_POINT_NO_REMOTE_SDP_ERROR, "No remote SDP");
  }

  sdp_to_str (remoteSdpStr, remoteSdp);;
  gst_sdp_message_free (remoteSdp);

  return remoteSdpStr;
}

SdpEndpointImpl::StaticConstructor SdpEndpointImpl::staticConstructor;

SdpEndpointImpl::StaticConstructor::StaticConstructor()
{
  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0,
                           GST_DEFAULT_NAME);
}

} /* kurento */
<|endoftext|>


<commit_before>//
// Created by andre on 13.05.16.
//

#include <utils/logger.h>
#include "DaedalusStdlib.h"
#include "DaedalusVM.h"

#define OFFSET(c, v) (int32_t)(((char*)v) - ((char*)c))
#define REGISTER(cname, obj, var) vm.getDATFile().getSymbolByName(cname "." #var).dataOffset = OFFSET(&obj, &obj.var);

void Daedalus::registerDaedalusStdLib(Daedalus::DaedalusVM& vm, bool enableVerboseLogging)
{
    bool l = enableVerboseLogging;

    vm.registerExternalFunction("inttostring", [l](Daedalus::DaedalusVM& vm){
        int32_t x = vm.popDataValue();

        vm.setReturn(std::to_string(x));
    });

    vm.registerExternalFunction("floattoint", [l](Daedalus::DaedalusVM& vm){
        float x = *reinterpret_cast<float*>(vm.popDataValue());
        vm.setReturn(static_cast<int32_t>(x));
    });

    vm.registerExternalFunction("inttofloat", [l](Daedalus::DaedalusVM& vm){
        int32_t x = vm.popDataValue();
        float y = static_cast<float>(x);

        vm.setReturn(*reinterpret_cast<int32_t*>(&y));
    });

    vm.registerExternalFunction("concatstrings", [l](Daedalus::DaedalusVM& vm){
        std::string s2 = vm.popString();
        std::string s1 = vm.popString();

        vm.setReturn(s1 + s2);
    });

    vm.registerExternalFunction("hlp_strcmp", [l](Daedalus::DaedalusVM& vm){
        std::string s1 = vm.popString();
        std::string s2 = vm.popString();

        vm.setReturn(s1 == s2 ? 1 : 0);
    });

    //
}

void Daedalus::registerGothicEngineClasses(DaedalusVM& vm)
{
    GEngineClasses::C_Npc npc;
    GEngineClasses::C_Focus focus;
    GEngineClasses::C_Info info;
    GEngineClasses::C_ItemReact itemreact;
    GEngineClasses::C_Item item;
    GEngineClasses::C_Mission mission;

    REGISTER("C_Npc", npc, id);
    REGISTER("C_Npc", npc, name);
    REGISTER("C_Npc", npc, slot);
    REGISTER("C_Npc", npc, npcType);
    REGISTER("C_Npc", npc, flags);
    REGISTER("C_Npc", npc, attribute);
    REGISTER("C_Npc", npc, protection);
    REGISTER("C_Npc", npc, damage);
    REGISTER("C_Npc", npc, damagetype);
    REGISTER("C_Npc", npc, guild);
    REGISTER("C_Npc", npc, level);
    REGISTER("C_Npc", npc, mission);
    REGISTER("C_Npc", npc, fight_tactic);
    REGISTER("C_Npc", npc, weapon);
    REGISTER("C_Npc", npc, voice);
    REGISTER("C_Npc", npc, voicePitch);
    REGISTER("C_Npc", npc, bodymass);
    REGISTER("C_Npc", npc, daily_routine);
    REGISTER("C_Npc", npc, start_aistate);
    REGISTER("C_Npc", npc, spawnPoint);
    REGISTER("C_Npc", npc, spawnDelay);
    REGISTER("C_Npc", npc, senses);
    REGISTER("C_Npc", npc, senses_range);
    REGISTER("C_Npc", npc, ai);
    REGISTER("C_Npc", npc, wp);
    REGISTER("C_Npc", npc, exp);
    REGISTER("C_Npc", npc, exp_next);
    REGISTER("C_Npc", npc, lp);

    REGISTER("C_Focus", focus, npc_longrange);
    REGISTER("C_Focus", focus, npc_range1);
    REGISTER("C_Focus", focus, npc_range2);
    REGISTER("C_Focus", focus, npc_azi);
    REGISTER("C_Focus", focus, npc_elevdo);
    REGISTER("C_Focus", focus, npc_elevup);
    REGISTER("C_Focus", focus, npc_prio);
    REGISTER("C_Focus", focus, item_range1);
    REGISTER("C_Focus", focus, item_range2);
    REGISTER("C_Focus", focus, item_azi);
    REGISTER("C_Focus", focus, item_elevdo);
    REGISTER("C_Focus", focus, item_elevup);
    REGISTER("C_Focus", focus, item_prio);
    REGISTER("C_Focus", focus, mob_range1);
    REGISTER("C_Focus", focus, mob_range2);
    REGISTER("C_Focus", focus, mob_azi);
    REGISTER("C_Focus", focus, mob_elevdo );
    REGISTER("C_Focus", focus, mob_elevup);
    REGISTER("C_Focus", focus, mob_prio);

    REGISTER("C_Info", info, npc);
    REGISTER("C_Info", info, nr);
    REGISTER("C_Info", info, important);
    REGISTER("C_Info", info, condition);
    REGISTER("C_Info", info, information);
    REGISTER("C_Info", info, description);
    REGISTER("C_Info", info, trade);
    REGISTER("C_Info", info, permanent);

    REGISTER("C_ItemReact", itemreact, npc);
    REGISTER("C_ItemReact", itemreact, trade_item);
    REGISTER("C_ItemReact", itemreact, trade_amount);
    REGISTER("C_ItemReact", itemreact, requested_cat);
    REGISTER("C_ItemReact", itemreact, requested_item);
    REGISTER("C_ItemReact", itemreact, requested_amount);
    REGISTER("C_ItemReact", itemreact, reaction);

    REGISTER("C_Item", item, id);
    REGISTER("C_Item", item, name );
    REGISTER("C_Item", item, nameID);
    REGISTER("C_Item", item, hp);
    REGISTER("C_Item", item, hp_max);
    REGISTER("C_Item", item, mainflag );
    REGISTER("C_Item", item, flags);
    REGISTER("C_Item", item, weight );
    REGISTER("C_Item", item, value);
    REGISTER("C_Item", item, damageType);
    REGISTER("C_Item", item, damageTotal);
    REGISTER("C_Item", item, damage);
    REGISTER("C_Item", item, wear);
    REGISTER("C_Item", item, protection);
    REGISTER("C_Item", item, nutrition);
    REGISTER("C_Item", item, cond_atr);
    REGISTER("C_Item", item, cond_value);
    REGISTER("C_Item", item, change_atr);
    REGISTER("C_Item", item, change_value);
    REGISTER("C_Item", item, magic   );
    REGISTER("C_Item", item, on_equip    );
    REGISTER("C_Item", item, on_unequip  );
    REGISTER("C_Item", item, on_state);
    REGISTER("C_Item", item, owner   );
    REGISTER("C_Item", item, ownerGuild    );
    REGISTER("C_Item", item, disguiseGuild);
    REGISTER("C_Item", item, visual);
    REGISTER("C_Item", item, visual_change );
    REGISTER("C_Item", item, visual_skin);
    REGISTER("C_Item", item, scemeName);
    REGISTER("C_Item", item, material);
    REGISTER("C_Item", item, munition);
    REGISTER("C_Item", item, spell);
    REGISTER("C_Item", item, range);
    REGISTER("C_Item", item, mag_circle);
    REGISTER("C_Item", item, description);
    REGISTER("C_Item", item, text);
    REGISTER("C_Item", item, count);

    REGISTER("C_Mission", mission, name);
    REGISTER("C_Mission", mission, description);
    REGISTER("C_Mission", mission, duration);
    REGISTER("C_Mission", mission, important);
    REGISTER("C_Mission", mission, offerConditions);
    REGISTER("C_Mission", mission, offer);
    REGISTER("C_Mission", mission, successConditions);
    REGISTER("C_Mission", mission, success);
    REGISTER("C_Mission", mission, failureConditions);
    REGISTER("C_Mission", mission, failure);
    REGISTER("C_Mission", mission, obsoleteConditions);
    REGISTER("C_Mission", mission, obsolete);
    REGISTER("C_Mission", mission, running);

}

<commit_msg>Added Hlp_Random<commit_after>//
// Created by andre on 13.05.16.
//

#include <utils/logger.h>
#include "DaedalusStdlib.h"
#include "DaedalusVM.h"

#define OFFSET(c, v) (int32_t)(((char*)v) - ((char*)c))
#define REGISTER(cname, obj, var) vm.getDATFile().getSymbolByName(cname "." #var).dataOffset = OFFSET(&obj, &obj.var);

void Daedalus::registerDaedalusStdLib(Daedalus::DaedalusVM& vm, bool enableVerboseLogging)
{
    bool l = enableVerboseLogging;

    vm.registerExternalFunction("inttostring", [l](Daedalus::DaedalusVM& vm){
        int32_t x = vm.popDataValue();

        vm.setReturn(std::to_string(x));
    });

    vm.registerExternalFunction("floattoint", [l](Daedalus::DaedalusVM& vm){
        float x = *reinterpret_cast<float*>(vm.popDataValue());
        vm.setReturn(static_cast<int32_t>(x));
    });

    vm.registerExternalFunction("inttofloat", [l](Daedalus::DaedalusVM& vm){
        int32_t x = vm.popDataValue();
        float y = static_cast<float>(x);

        vm.setReturn(*reinterpret_cast<int32_t*>(&y));
    });

    vm.registerExternalFunction("concatstrings", [l](Daedalus::DaedalusVM& vm){
        std::string s2 = vm.popString();
        std::string s1 = vm.popString();

        vm.setReturn(s1 + s2);
    });

    vm.registerExternalFunction("hlp_strcmp", [l](Daedalus::DaedalusVM& vm){
        std::string s1 = vm.popString();
        std::string s2 = vm.popString();

        vm.setReturn(s1 == s2 ? 1 : 0);
    });

    vm.registerExternalFunction("hlp_random", [=](Daedalus::DaedalusVM& vm){
        int32_t n0 = vm.popDataValue();

        vm.setReturn(rand() % n0);
    });

    //
}

void Daedalus::registerGothicEngineClasses(DaedalusVM& vm)
{
    GEngineClasses::C_Npc npc;
    GEngineClasses::C_Focus focus;
    GEngineClasses::C_Info info;
    GEngineClasses::C_ItemReact itemreact;
    GEngineClasses::C_Item item;
    GEngineClasses::C_Mission mission;

    REGISTER("C_Npc", npc, id);
    REGISTER("C_Npc", npc, name);
    REGISTER("C_Npc", npc, slot);
    REGISTER("C_Npc", npc, npcType);
    REGISTER("C_Npc", npc, flags);
    REGISTER("C_Npc", npc, attribute);
    REGISTER("C_Npc", npc, protection);
    REGISTER("C_Npc", npc, damage);
    REGISTER("C_Npc", npc, damagetype);
    REGISTER("C_Npc", npc, guild);
    REGISTER("C_Npc", npc, level);
    REGISTER("C_Npc", npc, mission);
    REGISTER("C_Npc", npc, fight_tactic);
    REGISTER("C_Npc", npc, weapon);
    REGISTER("C_Npc", npc, voice);
    REGISTER("C_Npc", npc, voicePitch);
    REGISTER("C_Npc", npc, bodymass);
    REGISTER("C_Npc", npc, daily_routine);
    REGISTER("C_Npc", npc, start_aistate);
    REGISTER("C_Npc", npc, spawnPoint);
    REGISTER("C_Npc", npc, spawnDelay);
    REGISTER("C_Npc", npc, senses);
    REGISTER("C_Npc", npc, senses_range);
    REGISTER("C_Npc", npc, ai);
    REGISTER("C_Npc", npc, wp);
    REGISTER("C_Npc", npc, exp);
    REGISTER("C_Npc", npc, exp_next);
    REGISTER("C_Npc", npc, lp);

    REGISTER("C_Focus", focus, npc_longrange);
    REGISTER("C_Focus", focus, npc_range1);
    REGISTER("C_Focus", focus, npc_range2);
    REGISTER("C_Focus", focus, npc_azi);
    REGISTER("C_Focus", focus, npc_elevdo);
    REGISTER("C_Focus", focus, npc_elevup);
    REGISTER("C_Focus", focus, npc_prio);
    REGISTER("C_Focus", focus, item_range1);
    REGISTER("C_Focus", focus, item_range2);
    REGISTER("C_Focus", focus, item_azi);
    REGISTER("C_Focus", focus, item_elevdo);
    REGISTER("C_Focus", focus, item_elevup);
    REGISTER("C_Focus", focus, item_prio);
    REGISTER("C_Focus", focus, mob_range1);
    REGISTER("C_Focus", focus, mob_range2);
    REGISTER("C_Focus", focus, mob_azi);
    REGISTER("C_Focus", focus, mob_elevdo );
    REGISTER("C_Focus", focus, mob_elevup);
    REGISTER("C_Focus", focus, mob_prio);

    REGISTER("C_Info", info, npc);
    REGISTER("C_Info", info, nr);
    REGISTER("C_Info", info, important);
    REGISTER("C_Info", info, condition);
    REGISTER("C_Info", info, information);
    REGISTER("C_Info", info, description);
    REGISTER("C_Info", info, trade);
    REGISTER("C_Info", info, permanent);

    REGISTER("C_ItemReact", itemreact, npc);
    REGISTER("C_ItemReact", itemreact, trade_item);
    REGISTER("C_ItemReact", itemreact, trade_amount);
    REGISTER("C_ItemReact", itemreact, requested_cat);
    REGISTER("C_ItemReact", itemreact, requested_item);
    REGISTER("C_ItemReact", itemreact, requested_amount);
    REGISTER("C_ItemReact", itemreact, reaction);

    REGISTER("C_Item", item, id);
    REGISTER("C_Item", item, name );
    REGISTER("C_Item", item, nameID);
    REGISTER("C_Item", item, hp);
    REGISTER("C_Item", item, hp_max);
    REGISTER("C_Item", item, mainflag );
    REGISTER("C_Item", item, flags);
    REGISTER("C_Item", item, weight );
    REGISTER("C_Item", item, value);
    REGISTER("C_Item", item, damageType);
    REGISTER("C_Item", item, damageTotal);
    REGISTER("C_Item", item, damage);
    REGISTER("C_Item", item, wear);
    REGISTER("C_Item", item, protection);
    REGISTER("C_Item", item, nutrition);
    REGISTER("C_Item", item, cond_atr);
    REGISTER("C_Item", item, cond_value);
    REGISTER("C_Item", item, change_atr);
    REGISTER("C_Item", item, change_value);
    REGISTER("C_Item", item, magic   );
    REGISTER("C_Item", item, on_equip    );
    REGISTER("C_Item", item, on_unequip  );
    REGISTER("C_Item", item, on_state);
    REGISTER("C_Item", item, owner   );
    REGISTER("C_Item", item, ownerGuild    );
    REGISTER("C_Item", item, disguiseGuild);
    REGISTER("C_Item", item, visual);
    REGISTER("C_Item", item, visual_change );
    REGISTER("C_Item", item, visual_skin);
    REGISTER("C_Item", item, scemeName);
    REGISTER("C_Item", item, material);
    REGISTER("C_Item", item, munition);
    REGISTER("C_Item", item, spell);
    REGISTER("C_Item", item, range);
    REGISTER("C_Item", item, mag_circle);
    REGISTER("C_Item", item, description);
    REGISTER("C_Item", item, text);
    REGISTER("C_Item", item, count);

    REGISTER("C_Mission", mission, name);
    REGISTER("C_Mission", mission, description);
    REGISTER("C_Mission", mission, duration);
    REGISTER("C_Mission", mission, important);
    REGISTER("C_Mission", mission, offerConditions);
    REGISTER("C_Mission", mission, offer);
    REGISTER("C_Mission", mission, successConditions);
    REGISTER("C_Mission", mission, success);
    REGISTER("C_Mission", mission, failureConditions);
    REGISTER("C_Mission", mission, failure);
    REGISTER("C_Mission", mission, obsoleteConditions);
    REGISTER("C_Mission", mission, obsolete);
    REGISTER("C_Mission", mission, running);

}

<|endoftext|>


<commit_before>#include "cluster.h"

template <>
void cluster<double>::init_suffstats() {
  score = 0;
  for(int col_idx=0; col_idx<num_cols; col_idx++) {
    suffstats_m[col_idx] = suffstats<double>();
    score += suffstats_m[col_idx].get_score();
  }
}

template <>
double cluster<double>::insert_row(std::vector<double> vd, int row_idx) {
  double sum_score_deltas = 0;
  std::pair<std::set<int>::iterator, bool> set_pair = \
    global_row_indices.insert(row_idx);
  assert(set_pair.second);
  for(int col_idx=0; col_idx<vd.size(); col_idx++) {
    assert(suffstats_m.count(col_idx)==1);
    sum_score_deltas += suffstats_m[col_idx].insert_el(vd[col_idx]);
  }
  score += sum_score_deltas;
  return sum_score_deltas;
}

template <>
double cluster<double>::remove_row(std::vector<double> vd, int row_idx) {
  double sum_score_deltas = 0;
  int num_removed = global_row_indices.erase(row_idx);
  assert(num_removed!=0);
  for(int col_idx=0; col_idx<vd.size(); col_idx++) {
    assert(suffstats_m.count(col_idx)==1);
    sum_score_deltas += suffstats_m[col_idx].remove_el(vd[col_idx]);
  }
  score += sum_score_deltas;
  return sum_score_deltas;
}

template <>
double cluster<double>::calc_data_logp(std::vector<double> vd) const {
  double sum_logps = 0;
  for(int col_idx=0; col_idx<vd.size(); col_idx++) {
    double el = vd[col_idx];
    const suffstats<double> sd = get_suffstats_i(col_idx);
    sum_logps += sd.calc_data_logp(el);
  }
  return sum_logps;
}

template <>
double cluster<double>::get_vector_logp(std::vector<double> vd) {
  // to be removed when test ensures calc_data_logps correctness
  double start_logp = calc_sum_logp();
  insert_row(vd, -1);
  double middle_logp = calc_sum_logp();
  remove_row(vd, -1);
  // double end_logp = calc_sum_logp();
  // assert(start_logp==end_logp);
  return middle_logp - start_logp;
}
<commit_msg>demarcate different sections of {insert,removw}_row<commit_after>#include "cluster.h"

template <>
void cluster<double>::init_suffstats() {
  score = 0;
  for(int col_idx=0; col_idx<num_cols; col_idx++) {
    suffstats_m[col_idx] = suffstats<double>();
    score += suffstats_m[col_idx].get_score();
  }
}

template <>
double cluster<double>::insert_row(std::vector<double> vd, int row_idx) {
  double sum_score_deltas = 0;
  // track row indices
  std::pair<std::set<int>::iterator, bool> set_pair = \
    global_row_indices.insert(row_idx);
  assert(set_pair.second);
  // track score
  for(int col_idx=0; col_idx<vd.size(); col_idx++) {
    assert(suffstats_m.count(col_idx)==1);
    sum_score_deltas += suffstats_m[col_idx].insert_el(vd[col_idx]);
  }
  score += sum_score_deltas;
  return sum_score_deltas;
}

template <>
double cluster<double>::remove_row(std::vector<double> vd, int row_idx) {
  double sum_score_deltas = 0;
  // track row indices
  int num_removed = global_row_indices.erase(row_idx);
  assert(num_removed!=0);
  // track score
  for(int col_idx=0; col_idx<vd.size(); col_idx++) {
    assert(suffstats_m.count(col_idx)==1);
    sum_score_deltas += suffstats_m[col_idx].remove_el(vd[col_idx]);
  }
  score += sum_score_deltas;
  return sum_score_deltas;
}

template <>
double cluster<double>::calc_data_logp(std::vector<double> vd) const {
  double sum_logps = 0;
  for(int col_idx=0; col_idx<vd.size(); col_idx++) {
    double el = vd[col_idx];
    const suffstats<double> sd = get_suffstats_i(col_idx);
    sum_logps += sd.calc_data_logp(el);
  }
  return sum_logps;
}

template <>
double cluster<double>::get_vector_logp(std::vector<double> vd) {
  // to be removed when test ensures calc_data_logps correctness
  double start_logp = calc_sum_logp();
  insert_row(vd, -1);
  double middle_logp = calc_sum_logp();
  remove_row(vd, -1);
  // double end_logp = calc_sum_logp();
  // assert(start_logp==end_logp);
  return middle_logp - start_logp;
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2014 Paul T. Bauman, Roy H. Stogner
// Copyright (C) 2010-2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

// This class
#include "grins/elastic_membrane.h"

// GRINS
#include "grins_config.h"
#include "grins/assembly_context.h"
#include "grins/solid_mechanics_bc_handling.h"

// libMesh
#include "libmesh/getpot.h"
#include "libmesh/quadrature.h"
#include "libmesh/boundary_info.h"
#include "libmesh/fem_system.h"

namespace GRINS
{
  template<typename StressStrainLaw>
  ElasticMembrane<StressStrainLaw>::ElasticMembrane( const GRINS::PhysicsName& physics_name, const GetPot& input )
    : Physics(physics_name,input),
      _disp_vars(input,physics_name),
      _stress_strain_law(input)
  {
    this->_bc_handler = new SolidMechanicsBCHandling( physics_name, input );

    return;
  }

  template<typename StressStrainLaw>
  ElasticMembrane<StressStrainLaw>::~ElasticMembrane()
  {
    return;
  }

  template<typename StressStrainLaw>
  void ElasticMembrane<StressStrainLaw>::init_variables( libMesh::FEMSystem* system )
  {
    // is_2D = false, is_3D = true
    _disp_vars.init(system,false,true);

    return;
  }

  template<typename StressStrainLaw>
  void ElasticMembrane<StressStrainLaw>::set_time_evolving_vars( libMesh::FEMSystem* system )
  {
    // Tell the system to march temperature forward in time
    system->time_evolving(_disp_vars.u_var());
    system->time_evolving(_disp_vars.v_var());
    system->time_evolving(_disp_vars.w_var());

    return;
  }

  template<typename StressStrainLaw>
  void ElasticMembrane<StressStrainLaw>::init_context( AssemblyContext& context )
  {
    context.get_element_fe(_disp_vars.u_var())->get_JxW();
    context.get_element_fe(_disp_vars.u_var())->get_dphi();

    // Need for constructing metric tensors
    context.get_element_fe(_disp_vars.u_var())->get_dxyzdxi();
    context.get_element_fe(_disp_vars.u_var())->get_dxyzdeta();
    context.get_element_fe(_disp_vars.u_var())->get_dxidx();
    context.get_element_fe(_disp_vars.u_var())->get_dxidy();
    context.get_element_fe(_disp_vars.u_var())->get_dxidz();
    context.get_element_fe(_disp_vars.u_var())->get_detadx();
    context.get_element_fe(_disp_vars.u_var())->get_detady();
    context.get_element_fe(_disp_vars.u_var())->get_detadz();

    return;
  }

  template<typename StressStrainLaw>
  void ElasticMembrane<StressStrainLaw>::element_time_derivative( bool compute_jacobian,
                                                                   AssemblyContext& context,
                                                                   CachedValues& /*cache*/ )
  {
    const unsigned int n_u_dofs = context.get_dof_indices(_disp_vars.u_var()).size();

    const std::vector<libMesh::Real> &JxW =
      context.get_element_fe(_disp_vars.u_var())->get_JxW();

    const std::vector<std::vector<libMesh::RealGradient> >& u_gradphi =
      context.get_element_fe(_disp_vars.u_var())->get_dphi();

    libMesh::DenseSubVector<libMesh::Number> &Fu = context.get_elem_residual(_disp_vars.u_var());
    libMesh::DenseSubVector<libMesh::Number> &Fv = context.get_elem_residual(_disp_vars.v_var());
    libMesh::DenseSubVector<libMesh::Number> &Fw = context.get_elem_residual(_disp_vars.w_var());

    unsigned int n_qpoints = context.get_element_qrule().n_points();

    const std::vector<libMesh::RealGradient>& dxdxi  = context.get_element_fe(_disp_vars.u_var())->get_dxyzdxi();
    const std::vector<libMesh::RealGradient>& dxdeta = context.get_element_fe(_disp_vars.u_var())->get_dxyzdeta();

    const std::vector<libMesh::Real>& dxidx  = context.get_element_fe(_disp_vars.u_var())->get_dxidx();
    const std::vector<libMesh::Real>& dxidy  = context.get_element_fe(_disp_vars.u_var())->get_dxidy();
    const std::vector<libMesh::Real>& dxidz  = context.get_element_fe(_disp_vars.u_var())->get_dxidz();

    const std::vector<libMesh::Real>& detadx  = context.get_element_fe(_disp_vars.u_var())->get_detadx();
    const std::vector<libMesh::Real>& detady  = context.get_element_fe(_disp_vars.u_var())->get_detady();
    const std::vector<libMesh::Real>& detadz  = context.get_element_fe(_disp_vars.u_var())->get_detadz();

    const unsigned int dim = 2; // The manifold dimension is always 2 for this physics

    for (unsigned int qp=0; qp != n_qpoints; qp++)
      {
        libMesh::Gradient grad_u = context.interior_gradient(_disp_vars.u_var(), qp);
        libMesh::Gradient grad_v = context.interior_gradient(_disp_vars.v_var(), qp);
        libMesh::Gradient grad_w = context.interior_gradient(_disp_vars.w_var(), qp);

        libMesh::RealGradient grad_x( dxdxi[qp](0), dxdeta[qp](0) );
        libMesh::RealGradient grad_y( dxdxi[qp](1), dxdeta[qp](1) );
        libMesh::RealGradient grad_z( dxdxi[qp](2), dxdeta[qp](2) );

        libMesh::RealGradient dudxi( grad_u(0), grad_v(0), grad_w(0) );
        libMesh::RealGradient dudeta( grad_u(1), grad_v(1), grad_w(1) );

        libMesh::RealGradient dxi( dxidx[qp], dxidy[qp], dxidz[qp] );
        libMesh::RealGradient deta( detadx[qp], detady[qp], detadz[qp] );

        // Covariant metric tensor of reference configuration
        libMesh::TensorValue<libMesh::Real> a_cov( dxdxi[qp]*dxdxi[qp], dxdxi[qp]*dxdeta[qp], 0.0,
                                                   dxdeta[qp]*dxdxi[qp], dxdeta[qp]*dxdeta[qp] );

        // Covariant metric tensor of current configuration
        libMesh::TensorValue<libMesh::Real> A_cov( (dxdxi[qp] + dudxi)*(dxdxi[qp] + dudxi),
                                                   (dxdxi[qp] + dudxi)*(dxdeta[qp] + dudeta), 0.0,
                                                   (dxdeta[qp] + dudeta)*(dxdxi[qp] + dudxi),
                                                   (dxdeta[qp] + dudeta)*(dxdeta[qp] + dudeta) );

        // Contravariant metric tensor of reference configuration
        libMesh::TensorValue<libMesh::Real> a_contra( dxi*dxi, dxi*deta, 0.0,
                                                      deta*dxi, deta*deta );

        // Contravariant metric tensor in current configuration is A_cov^{-1}
        libMesh::Real det = A_cov(0,0)*A_cov(1,1) - A_cov(0,1)*A_cov(1,0);
        libMesh::TensorValue<libMesh::Real> A_contra(  A_cov(1,1)/det, -A_cov(0,1)/det, 0.0,
                                                      -A_cov(1,0)/det,  A_cov(0,0)/det );

        // Strain tensor
        libMesh::TensorValue<libMesh::Real> strain = 0.5*(A_cov - a_cov);

        // Compute stress tensor
        libMesh::TensorValue<libMesh::Real> tau;
        _stress_strain_law.compute_stress(a_contra,A_contra,A_cov,strain,dim,tau);

        libMesh::Real jac = JxW[qp];

        for (unsigned int i=0; i != n_u_dofs; i++)
	  {
            for( unsigned int alpha = 0; alpha < dim; alpha++ )
              {
                for( unsigned int beta = 0; beta < dim; beta++ )
                  {
                    Fu(i) -= 0.5*tau(alpha,beta)*( (grad_x(beta) + grad_u(beta))*u_gradphi[i][qp](alpha) +
                                                   (grad_x(alpha) + grad_u(alpha))*u_gradphi[i][qp](beta) )*jac;

                    Fv(i) -= 0.5*tau(alpha,beta)*( (grad_y(beta) + grad_v(beta))*u_gradphi[i][qp](alpha) +
                                                   (grad_y(alpha) + grad_v(alpha))*u_gradphi[i][qp](beta) )*jac;

                    Fw(i) -= 0.5*tau(alpha,beta)*( (grad_z(beta) + grad_w(beta))*u_gradphi[i][qp](alpha) +
                                                   (grad_z(alpha) + grad_w(alpha))*u_gradphi[i][qp](beta) )*jac;
                  }
              }
            if( compute_jacobian )
              {
                libmesh_not_implemented();
              }
          }

      }

    return;
  }

  template<typename StressStrainLaw>
  void ElasticMembrane<StressStrainLaw>::side_time_derivative( bool compute_jacobian,
                                                                AssemblyContext& context,
                                                                CachedValues& cache )
  {
    /*
      std::vector<BoundaryID> ids = context.side_boundary_ids();

      for( std::vector<BoundaryID>::const_iterator it = ids.begin();
      it != ids.end(); it++ )
      {
      libmesh_assert (*it != libMesh::BoundaryInfo::invalid_id);

      _bc_handler->apply_neumann_bcs( context, cache, compute_jacobian, *it );
      }
    */

    return;
  }

  template<typename StressStrainLaw>
  void ElasticMembrane<StressStrainLaw>::mass_residual( bool compute_jacobian,
                                                         AssemblyContext& context,
                                                         CachedValues& cache )
  {
    libmesh_not_implemented();
    return;
  }

} // end namespace GRINS
<commit_msg>More readable variable name<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2014 Paul T. Bauman, Roy H. Stogner
// Copyright (C) 2010-2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

// This class
#include "grins/elastic_membrane.h"

// GRINS
#include "grins_config.h"
#include "grins/assembly_context.h"
#include "grins/solid_mechanics_bc_handling.h"

// libMesh
#include "libmesh/getpot.h"
#include "libmesh/quadrature.h"
#include "libmesh/boundary_info.h"
#include "libmesh/fem_system.h"

namespace GRINS
{
  template<typename StressStrainLaw>
  ElasticMembrane<StressStrainLaw>::ElasticMembrane( const GRINS::PhysicsName& physics_name, const GetPot& input )
    : Physics(physics_name,input),
      _disp_vars(input,physics_name),
      _stress_strain_law(input)
  {
    this->_bc_handler = new SolidMechanicsBCHandling( physics_name, input );

    return;
  }

  template<typename StressStrainLaw>
  ElasticMembrane<StressStrainLaw>::~ElasticMembrane()
  {
    return;
  }

  template<typename StressStrainLaw>
  void ElasticMembrane<StressStrainLaw>::init_variables( libMesh::FEMSystem* system )
  {
    // is_2D = false, is_3D = true
    _disp_vars.init(system,false,true);

    return;
  }

  template<typename StressStrainLaw>
  void ElasticMembrane<StressStrainLaw>::set_time_evolving_vars( libMesh::FEMSystem* system )
  {
    // Tell the system to march temperature forward in time
    system->time_evolving(_disp_vars.u_var());
    system->time_evolving(_disp_vars.v_var());
    system->time_evolving(_disp_vars.w_var());

    return;
  }

  template<typename StressStrainLaw>
  void ElasticMembrane<StressStrainLaw>::init_context( AssemblyContext& context )
  {
    context.get_element_fe(_disp_vars.u_var())->get_JxW();
    context.get_element_fe(_disp_vars.u_var())->get_dphi();

    // Need for constructing metric tensors
    context.get_element_fe(_disp_vars.u_var())->get_dxyzdxi();
    context.get_element_fe(_disp_vars.u_var())->get_dxyzdeta();
    context.get_element_fe(_disp_vars.u_var())->get_dxidx();
    context.get_element_fe(_disp_vars.u_var())->get_dxidy();
    context.get_element_fe(_disp_vars.u_var())->get_dxidz();
    context.get_element_fe(_disp_vars.u_var())->get_detadx();
    context.get_element_fe(_disp_vars.u_var())->get_detady();
    context.get_element_fe(_disp_vars.u_var())->get_detadz();

    return;
  }

  template<typename StressStrainLaw>
  void ElasticMembrane<StressStrainLaw>::element_time_derivative( bool compute_jacobian,
                                                                   AssemblyContext& context,
                                                                   CachedValues& /*cache*/ )
  {
    const unsigned int n_u_dofs = context.get_dof_indices(_disp_vars.u_var()).size();

    const std::vector<libMesh::Real> &JxW =
      context.get_element_fe(_disp_vars.u_var())->get_JxW();

    const std::vector<std::vector<libMesh::RealGradient> >& u_gradphi =
      context.get_element_fe(_disp_vars.u_var())->get_dphi();

    libMesh::DenseSubVector<libMesh::Number> &Fu = context.get_elem_residual(_disp_vars.u_var());
    libMesh::DenseSubVector<libMesh::Number> &Fv = context.get_elem_residual(_disp_vars.v_var());
    libMesh::DenseSubVector<libMesh::Number> &Fw = context.get_elem_residual(_disp_vars.w_var());

    unsigned int n_qpoints = context.get_element_qrule().n_points();

    const std::vector<libMesh::RealGradient>& dxdxi  = context.get_element_fe(_disp_vars.u_var())->get_dxyzdxi();
    const std::vector<libMesh::RealGradient>& dxdeta = context.get_element_fe(_disp_vars.u_var())->get_dxyzdeta();

    const std::vector<libMesh::Real>& dxidx  = context.get_element_fe(_disp_vars.u_var())->get_dxidx();
    const std::vector<libMesh::Real>& dxidy  = context.get_element_fe(_disp_vars.u_var())->get_dxidy();
    const std::vector<libMesh::Real>& dxidz  = context.get_element_fe(_disp_vars.u_var())->get_dxidz();

    const std::vector<libMesh::Real>& detadx  = context.get_element_fe(_disp_vars.u_var())->get_detadx();
    const std::vector<libMesh::Real>& detady  = context.get_element_fe(_disp_vars.u_var())->get_detady();
    const std::vector<libMesh::Real>& detadz  = context.get_element_fe(_disp_vars.u_var())->get_detadz();

    const unsigned int dim = 2; // The manifold dimension is always 2 for this physics

    for (unsigned int qp=0; qp != n_qpoints; qp++)
      {
        libMesh::Gradient grad_u = context.interior_gradient(_disp_vars.u_var(), qp);
        libMesh::Gradient grad_v = context.interior_gradient(_disp_vars.v_var(), qp);
        libMesh::Gradient grad_w = context.interior_gradient(_disp_vars.w_var(), qp);

        libMesh::RealGradient grad_x( dxdxi[qp](0), dxdeta[qp](0) );
        libMesh::RealGradient grad_y( dxdxi[qp](1), dxdeta[qp](1) );
        libMesh::RealGradient grad_z( dxdxi[qp](2), dxdeta[qp](2) );

        libMesh::RealGradient dudxi( grad_u(0), grad_v(0), grad_w(0) );
        libMesh::RealGradient dudeta( grad_u(1), grad_v(1), grad_w(1) );

        libMesh::RealGradient dxi( dxidx[qp], dxidy[qp], dxidz[qp] );
        libMesh::RealGradient deta( detadx[qp], detady[qp], detadz[qp] );

        // Covariant metric tensor of reference configuration
        libMesh::TensorValue<libMesh::Real> a_cov( dxdxi[qp]*dxdxi[qp], dxdxi[qp]*dxdeta[qp], 0.0,
                                                   dxdeta[qp]*dxdxi[qp], dxdeta[qp]*dxdeta[qp] );

        // Covariant metric tensor of current configuration
        libMesh::TensorValue<libMesh::Real> A_cov( (dxdxi[qp] + dudxi)*(dxdxi[qp] + dudxi),
                                                   (dxdxi[qp] + dudxi)*(dxdeta[qp] + dudeta), 0.0,
                                                   (dxdeta[qp] + dudeta)*(dxdxi[qp] + dudxi),
                                                   (dxdeta[qp] + dudeta)*(dxdeta[qp] + dudeta) );

        // Contravariant metric tensor of reference configuration
        libMesh::TensorValue<libMesh::Real> a_contra( dxi*dxi, dxi*deta, 0.0,
                                                      deta*dxi, deta*deta );

        // Contravariant metric tensor in current configuration is A_cov^{-1}
        libMesh::Real det_A = A_cov(0,0)*A_cov(1,1) - A_cov(0,1)*A_cov(1,0);
        libMesh::TensorValue<libMesh::Real> A_contra(  A_cov(1,1)/det_A, -A_cov(0,1)/det_A, 0.0,
                                                      -A_cov(1,0)/det_A,  A_cov(0,0)/det_A );

        // Strain tensor
        libMesh::TensorValue<libMesh::Real> strain = 0.5*(A_cov - a_cov);

        // Compute stress tensor
        libMesh::TensorValue<libMesh::Real> tau;
        _stress_strain_law.compute_stress(a_contra,A_contra,A_cov,strain,dim,tau);

        libMesh::Real jac = JxW[qp];

        for (unsigned int i=0; i != n_u_dofs; i++)
	  {
            for( unsigned int alpha = 0; alpha < dim; alpha++ )
              {
                for( unsigned int beta = 0; beta < dim; beta++ )
                  {
                    Fu(i) -= 0.5*tau(alpha,beta)*( (grad_x(beta) + grad_u(beta))*u_gradphi[i][qp](alpha) +
                                                   (grad_x(alpha) + grad_u(alpha))*u_gradphi[i][qp](beta) )*jac;

                    Fv(i) -= 0.5*tau(alpha,beta)*( (grad_y(beta) + grad_v(beta))*u_gradphi[i][qp](alpha) +
                                                   (grad_y(alpha) + grad_v(alpha))*u_gradphi[i][qp](beta) )*jac;

                    Fw(i) -= 0.5*tau(alpha,beta)*( (grad_z(beta) + grad_w(beta))*u_gradphi[i][qp](alpha) +
                                                   (grad_z(alpha) + grad_w(alpha))*u_gradphi[i][qp](beta) )*jac;
                  }
              }
            if( compute_jacobian )
              {
                libmesh_not_implemented();
              }
          }

      }

    return;
  }

  template<typename StressStrainLaw>
  void ElasticMembrane<StressStrainLaw>::side_time_derivative( bool compute_jacobian,
                                                                AssemblyContext& context,
                                                                CachedValues& cache )
  {
    /*
      std::vector<BoundaryID> ids = context.side_boundary_ids();

      for( std::vector<BoundaryID>::const_iterator it = ids.begin();
      it != ids.end(); it++ )
      {
      libmesh_assert (*it != libMesh::BoundaryInfo::invalid_id);

      _bc_handler->apply_neumann_bcs( context, cache, compute_jacobian, *it );
      }
    */

    return;
  }

  template<typename StressStrainLaw>
  void ElasticMembrane<StressStrainLaw>::mass_residual( bool compute_jacobian,
                                                         AssemblyContext& context,
                                                         CachedValues& cache )
  {
    libmesh_not_implemented();
    return;
  }

} // end namespace GRINS
<|endoftext|>


<commit_before>#include "GameController.h"

#include "AudioProcessor.h"

#include <QThread>

extern "C" {
#include "gba.h"
#include "gba-audio.h"
#include "gba-serialize.h"
#include "renderers/video-software.h"
#include "util/vfs.h"
}

using namespace QGBA;

GameController::GameController(QObject* parent)
	: QObject(parent)
	, m_drawContext(new uint32_t[256 * 256])
	, m_threadContext()
	, m_activeKeys(0)
	, m_rom(nullptr)
	, m_audioThread(new QThread(this))
	, m_audioProcessor(new AudioProcessor)
{
	m_renderer = new GBAVideoSoftwareRenderer;
	GBAVideoSoftwareRendererCreate(m_renderer);
	m_renderer->outputBuffer = (color_t*) m_drawContext;
	m_renderer->outputBufferStride = 256;
	m_threadContext.state = THREAD_INITIALIZED;
	m_threadContext.debugger = 0;
	m_threadContext.frameskip = 0;
	m_threadContext.bios = 0;
	m_threadContext.renderer = &m_renderer->d;
	m_threadContext.userData = this;
	m_threadContext.rewindBufferCapacity = 0;
	m_threadContext.logLevel = -1;

	GBAInputMapInit(&m_threadContext.inputMap);

#ifdef BUILD_SDL
	SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
	m_sdlEvents.bindings = &m_threadContext.inputMap;
	GBASDLInitEvents(&m_sdlEvents);
	SDL_JoystickEventState(SDL_QUERY);
#endif

	m_threadContext.startCallback = [] (GBAThread* context) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->m_audioProcessor->setInput(context);
		controller->gameStarted(context);
	};

	m_threadContext.cleanCallback = [] (GBAThread* context) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->gameStopped(context);
	};

	m_threadContext.frameCallback = [] (GBAThread* context) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->m_pauseMutex.lock();
		if (controller->m_pauseAfterFrame) {
			GBAThreadPauseFromThread(context);
			controller->m_pauseAfterFrame = false;
			controller->gamePaused(&controller->m_threadContext);
		}
		controller->m_pauseMutex.unlock();
		controller->frameAvailable(controller->m_drawContext);
	};

	m_threadContext.logHandler = [] (GBAThread* context, enum GBALogLevel level, const char* format, va_list args) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->postLog(level, QString().vsprintf(format, args));
	};

	m_audioThread->start(QThread::TimeCriticalPriority);
	m_audioProcessor->moveToThread(m_audioThread);
	connect(this, SIGNAL(gameStarted(GBAThread*)), m_audioProcessor, SLOT(start()));
	connect(this, SIGNAL(gameStopped(GBAThread*)), m_audioProcessor, SLOT(pause()));
	connect(this, SIGNAL(gamePaused(GBAThread*)), m_audioProcessor, SLOT(pause()));
	connect(this, SIGNAL(gameUnpaused(GBAThread*)), m_audioProcessor, SLOT(start()));

#ifdef BUILD_SDL
	connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(testSDLEvents()));
#endif
}

GameController::~GameController() {
	m_audioThread->quit();
	m_audioThread->wait();
	if (GBAThreadIsPaused(&m_threadContext)) {
		GBAThreadUnpause(&m_threadContext);
	}
	disconnect();
	closeGame();
	delete m_renderer;
}

ARMDebugger* GameController::debugger() {
	return m_threadContext.debugger;
}

void GameController::setDebugger(ARMDebugger* debugger) {
	bool wasPaused = isPaused();
	setPaused(true);
	if (m_threadContext.debugger && GBAThreadHasStarted(&m_threadContext)) {
		GBADetachDebugger(m_threadContext.gba);
	}
	m_threadContext.debugger = debugger;
	if (m_threadContext.debugger && GBAThreadHasStarted(&m_threadContext)) {
		GBAAttachDebugger(m_threadContext.gba, m_threadContext.debugger);
	}
	setPaused(wasPaused);
}

void GameController::loadGame(const QString& path) {
	closeGame();
	m_threadContext.sync.videoFrameWait = 0;
	m_threadContext.sync.audioWait = 1;
	m_rom = new QFile(path);
	if (!m_rom->open(QIODevice::ReadOnly)) {
		delete m_rom;
		m_rom = nullptr;
	}

	m_pauseAfterFrame = false;

	m_threadContext.rom = VFileFromFD(m_rom->handle());
	m_threadContext.fname = strdup(path.toLocal8Bit().constData());

	GBAThreadStart(&m_threadContext);
}

void GameController::closeGame() {
	if (!m_rom) {
		return;
	}
	GBAThreadEnd(&m_threadContext);
	GBAThreadJoin(&m_threadContext);
	if (m_threadContext.fname) {
		free(const_cast<char*>(m_threadContext.fname));
		m_threadContext.fname = nullptr;
	}
	if (m_rom) {
		m_rom->close();
		delete m_rom;
		m_rom = nullptr;
	}
	emit gameStopped(&m_threadContext);
}

bool GameController::isPaused() {
	return GBAThreadIsPaused(&m_threadContext);
}

void GameController::setPaused(bool paused) {
	if (paused == GBAThreadIsPaused(&m_threadContext)) {
		return;
	}
	if (paused) {
		GBAThreadPause(&m_threadContext);
		emit gamePaused(&m_threadContext);
	} else {
		GBAThreadUnpause(&m_threadContext);
		emit gameUnpaused(&m_threadContext);
	}
}

void GameController::reset() {
	GBAThreadReset(&m_threadContext);
}

void GameController::frameAdvance() {
	m_pauseMutex.lock();
	m_pauseAfterFrame = true;
	setPaused(false);
	m_pauseMutex.unlock();
}

void GameController::keyPressed(int key) {
	int mappedKey = 1 << key;
	m_activeKeys |= mappedKey;
	updateKeys();
}

void GameController::keyReleased(int key) {
	int mappedKey = 1 << key;
	m_activeKeys &= ~mappedKey;
	updateKeys();
}

void GameController::setAudioBufferSamples(int samples) {
	GBAThreadInterrupt(&m_threadContext);
	m_threadContext.audioBuffers = samples;
	GBAAudioResizeBuffer(&m_threadContext.gba->audio, samples);
	GBAThreadContinue(&m_threadContext);
	QMetaObject::invokeMethod(m_audioProcessor, "setBufferSamples", Q_ARG(int, samples));
}

void GameController::setFPSTarget(float fps) {
	GBAThreadInterrupt(&m_threadContext);
	m_threadContext.fpsTarget = fps;
	GBAThreadContinue(&m_threadContext);
	QMetaObject::invokeMethod(m_audioProcessor, "inputParametersChanged");
}

void GameController::loadState(int slot) {
	GBAThreadInterrupt(&m_threadContext);
	GBALoadState(m_threadContext.gba, m_threadContext.stateDir, slot);
	GBAThreadContinue(&m_threadContext);
	emit stateLoaded(&m_threadContext);
	emit frameAvailable(m_drawContext);
}

void GameController::saveState(int slot) {
	GBAThreadInterrupt(&m_threadContext);
	GBASaveState(m_threadContext.gba, m_threadContext.stateDir, slot, true);
	GBAThreadContinue(&m_threadContext);
}

void GameController::updateKeys() {
	int activeKeys = m_activeKeys;
#ifdef BUILD_SDL
	activeKeys |= m_activeButtons;
#endif
	m_threadContext.activeKeys = activeKeys;
}

#ifdef BUILD_SDL
void GameController::testSDLEvents() {
	SDL_Joystick* joystick = m_sdlEvents.joystick;
	SDL_JoystickUpdate();
	int numButtons = SDL_JoystickNumButtons(joystick);
	m_activeButtons = 0;
	int i;
	for (i = 0; i < numButtons; ++i) {
		GBAKey key = GBAInputMapKey(&m_threadContext.inputMap, SDL_BINDING_BUTTON, i);
		if (key == GBA_KEY_NONE) {
			continue;
		}
		if (SDL_JoystickGetButton(joystick, i)) {
			m_activeButtons |= 1 << key;
		}
	}
	int numHats = SDL_JoystickNumHats(joystick);
	for (i = 0; i < numHats; ++i) {
		int hat = SDL_JoystickGetHat(joystick, i);
		if (hat & SDL_HAT_UP) {
			m_activeButtons |= 1 << GBA_KEY_UP;
		}
		if (hat & SDL_HAT_LEFT) {
			m_activeButtons |= 1 << GBA_KEY_LEFT;
		}
		if (hat & SDL_HAT_DOWN) {
			m_activeButtons |= 1 << GBA_KEY_DOWN;
		}
		if (hat & SDL_HAT_RIGHT) {
			m_activeButtons |= 1 << GBA_KEY_RIGHT;
		}
	}
	updateKeys();
}
#endif
<commit_msg>Wake up the drawing thread after loading a state to make sure it draws the loaded state<commit_after>#include "GameController.h"

#include "AudioProcessor.h"

#include <QThread>

extern "C" {
#include "gba.h"
#include "gba-audio.h"
#include "gba-serialize.h"
#include "renderers/video-software.h"
#include "util/vfs.h"
}

using namespace QGBA;

GameController::GameController(QObject* parent)
	: QObject(parent)
	, m_drawContext(new uint32_t[256 * 256])
	, m_threadContext()
	, m_activeKeys(0)
	, m_rom(nullptr)
	, m_audioThread(new QThread(this))
	, m_audioProcessor(new AudioProcessor)
{
	m_renderer = new GBAVideoSoftwareRenderer;
	GBAVideoSoftwareRendererCreate(m_renderer);
	m_renderer->outputBuffer = (color_t*) m_drawContext;
	m_renderer->outputBufferStride = 256;
	m_threadContext.state = THREAD_INITIALIZED;
	m_threadContext.debugger = 0;
	m_threadContext.frameskip = 0;
	m_threadContext.bios = 0;
	m_threadContext.renderer = &m_renderer->d;
	m_threadContext.userData = this;
	m_threadContext.rewindBufferCapacity = 0;
	m_threadContext.logLevel = -1;

	GBAInputMapInit(&m_threadContext.inputMap);

#ifdef BUILD_SDL
	SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
	m_sdlEvents.bindings = &m_threadContext.inputMap;
	GBASDLInitEvents(&m_sdlEvents);
	SDL_JoystickEventState(SDL_QUERY);
#endif

	m_threadContext.startCallback = [] (GBAThread* context) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->m_audioProcessor->setInput(context);
		controller->gameStarted(context);
	};

	m_threadContext.cleanCallback = [] (GBAThread* context) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->gameStopped(context);
	};

	m_threadContext.frameCallback = [] (GBAThread* context) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->m_pauseMutex.lock();
		if (controller->m_pauseAfterFrame) {
			GBAThreadPauseFromThread(context);
			controller->m_pauseAfterFrame = false;
			controller->gamePaused(&controller->m_threadContext);
		}
		controller->m_pauseMutex.unlock();
		controller->frameAvailable(controller->m_drawContext);
	};

	m_threadContext.logHandler = [] (GBAThread* context, enum GBALogLevel level, const char* format, va_list args) {
		GameController* controller = static_cast<GameController*>(context->userData);
		controller->postLog(level, QString().vsprintf(format, args));
	};

	m_audioThread->start(QThread::TimeCriticalPriority);
	m_audioProcessor->moveToThread(m_audioThread);
	connect(this, SIGNAL(gameStarted(GBAThread*)), m_audioProcessor, SLOT(start()));
	connect(this, SIGNAL(gameStopped(GBAThread*)), m_audioProcessor, SLOT(pause()));
	connect(this, SIGNAL(gamePaused(GBAThread*)), m_audioProcessor, SLOT(pause()));
	connect(this, SIGNAL(gameUnpaused(GBAThread*)), m_audioProcessor, SLOT(start()));

#ifdef BUILD_SDL
	connect(this, SIGNAL(frameAvailable(const uint32_t*)), this, SLOT(testSDLEvents()));
#endif
}

GameController::~GameController() {
	m_audioThread->quit();
	m_audioThread->wait();
	if (GBAThreadIsPaused(&m_threadContext)) {
		GBAThreadUnpause(&m_threadContext);
	}
	disconnect();
	closeGame();
	delete m_renderer;
}

ARMDebugger* GameController::debugger() {
	return m_threadContext.debugger;
}

void GameController::setDebugger(ARMDebugger* debugger) {
	bool wasPaused = isPaused();
	setPaused(true);
	if (m_threadContext.debugger && GBAThreadHasStarted(&m_threadContext)) {
		GBADetachDebugger(m_threadContext.gba);
	}
	m_threadContext.debugger = debugger;
	if (m_threadContext.debugger && GBAThreadHasStarted(&m_threadContext)) {
		GBAAttachDebugger(m_threadContext.gba, m_threadContext.debugger);
	}
	setPaused(wasPaused);
}

void GameController::loadGame(const QString& path) {
	closeGame();
	m_threadContext.sync.videoFrameWait = 0;
	m_threadContext.sync.audioWait = 1;
	m_rom = new QFile(path);
	if (!m_rom->open(QIODevice::ReadOnly)) {
		delete m_rom;
		m_rom = nullptr;
	}

	m_pauseAfterFrame = false;

	m_threadContext.rom = VFileFromFD(m_rom->handle());
	m_threadContext.fname = strdup(path.toLocal8Bit().constData());

	GBAThreadStart(&m_threadContext);
}

void GameController::closeGame() {
	if (!m_rom) {
		return;
	}
	GBAThreadEnd(&m_threadContext);
	GBAThreadJoin(&m_threadContext);
	if (m_threadContext.fname) {
		free(const_cast<char*>(m_threadContext.fname));
		m_threadContext.fname = nullptr;
	}
	if (m_rom) {
		m_rom->close();
		delete m_rom;
		m_rom = nullptr;
	}
	emit gameStopped(&m_threadContext);
}

bool GameController::isPaused() {
	return GBAThreadIsPaused(&m_threadContext);
}

void GameController::setPaused(bool paused) {
	if (paused == GBAThreadIsPaused(&m_threadContext)) {
		return;
	}
	if (paused) {
		GBAThreadPause(&m_threadContext);
		emit gamePaused(&m_threadContext);
	} else {
		GBAThreadUnpause(&m_threadContext);
		emit gameUnpaused(&m_threadContext);
	}
}

void GameController::reset() {
	GBAThreadReset(&m_threadContext);
}

void GameController::frameAdvance() {
	m_pauseMutex.lock();
	m_pauseAfterFrame = true;
	setPaused(false);
	m_pauseMutex.unlock();
}

void GameController::keyPressed(int key) {
	int mappedKey = 1 << key;
	m_activeKeys |= mappedKey;
	updateKeys();
}

void GameController::keyReleased(int key) {
	int mappedKey = 1 << key;
	m_activeKeys &= ~mappedKey;
	updateKeys();
}

void GameController::setAudioBufferSamples(int samples) {
	GBAThreadInterrupt(&m_threadContext);
	m_threadContext.audioBuffers = samples;
	GBAAudioResizeBuffer(&m_threadContext.gba->audio, samples);
	GBAThreadContinue(&m_threadContext);
	QMetaObject::invokeMethod(m_audioProcessor, "setBufferSamples", Q_ARG(int, samples));
}

void GameController::setFPSTarget(float fps) {
	GBAThreadInterrupt(&m_threadContext);
	m_threadContext.fpsTarget = fps;
	GBAThreadContinue(&m_threadContext);
	QMetaObject::invokeMethod(m_audioProcessor, "inputParametersChanged");
}

void GameController::loadState(int slot) {
	GBAThreadInterrupt(&m_threadContext);
	GBALoadState(m_threadContext.gba, m_threadContext.stateDir, slot);
	ConditionWake(&m_threadContext.sync.videoFrameAvailableCond); // Hack: wake up the drawing thread
	GBAThreadContinue(&m_threadContext);
	emit stateLoaded(&m_threadContext);
	emit frameAvailable(m_drawContext);
}

void GameController::saveState(int slot) {
	GBAThreadInterrupt(&m_threadContext);
	GBASaveState(m_threadContext.gba, m_threadContext.stateDir, slot, true);
	GBAThreadContinue(&m_threadContext);
}

void GameController::updateKeys() {
	int activeKeys = m_activeKeys;
#ifdef BUILD_SDL
	activeKeys |= m_activeButtons;
#endif
	m_threadContext.activeKeys = activeKeys;
}

#ifdef BUILD_SDL
void GameController::testSDLEvents() {
	SDL_Joystick* joystick = m_sdlEvents.joystick;
	SDL_JoystickUpdate();
	int numButtons = SDL_JoystickNumButtons(joystick);
	m_activeButtons = 0;
	int i;
	for (i = 0; i < numButtons; ++i) {
		GBAKey key = GBAInputMapKey(&m_threadContext.inputMap, SDL_BINDING_BUTTON, i);
		if (key == GBA_KEY_NONE) {
			continue;
		}
		if (SDL_JoystickGetButton(joystick, i)) {
			m_activeButtons |= 1 << key;
		}
	}
	int numHats = SDL_JoystickNumHats(joystick);
	for (i = 0; i < numHats; ++i) {
		int hat = SDL_JoystickGetHat(joystick, i);
		if (hat & SDL_HAT_UP) {
			m_activeButtons |= 1 << GBA_KEY_UP;
		}
		if (hat & SDL_HAT_LEFT) {
			m_activeButtons |= 1 << GBA_KEY_LEFT;
		}
		if (hat & SDL_HAT_DOWN) {
			m_activeButtons |= 1 << GBA_KEY_DOWN;
		}
		if (hat & SDL_HAT_RIGHT) {
			m_activeButtons |= 1 << GBA_KEY_RIGHT;
		}
	}
	updateKeys();
}
#endif
<|endoftext|>


<commit_before>#include "system_sdl.h"
#include <SDL.h>
#include <fstream>
#include "halley/core/api/halley_api_internal.h"
#include <halley/support/console.h>
#include <halley/support/exception.h>
#include "sdl_rw_ops.h"
#include "halley/core/graphics/window.h"
#include "halley/os/os.h"
#include "sdl_window.h"
#include "sdl_gl_context.h"
#include "input_sdl.h"
#include "halley/support/logger.h"

using namespace Halley;

void SystemSDL::init()
{
	// SDL version
	SDL_version compiled;
	SDL_version linked;
	SDL_VERSION(&compiled);
	SDL_GetVersion(&linked);
	std::cout << ConsoleColour(Console::GREEN) << "\nInitializing SDL..." << ConsoleColour() << std::endl;
	std::cout << "\tVersion/Compiled: " << ConsoleColour(Console::DARK_GREY) << int(compiled.major) << "." << int(compiled.minor) << "." << int(compiled.patch) << ConsoleColour() << std::endl;
	std::cout << "\tVersion/Linked: " << ConsoleColour(Console::DARK_GREY) << int(linked.major) << "." << int(linked.minor) << "." << int(linked.patch) << ConsoleColour() << std::endl;

	// Initialize SDL
	if (!SDL_WasInit(0)) {
		if (SDL_Init(0) == -1) {
			throw Exception(String("Exception initializing SDL: ") + SDL_GetError(), HalleyExceptions::SystemPlugin);
		}
	}
	if (SDL_InitSubSystem(SDL_INIT_TIMER) == -1) {
		throw Exception(String("Exception initializing timer: ") + SDL_GetError(), HalleyExceptions::SystemPlugin);
	}
	if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) {
		throw Exception(String("Exception initializing joystick: ") + SDL_GetError(), HalleyExceptions::SystemPlugin);
	}

	SDL_ShowCursor(SDL_DISABLE);

	// Init clipboard
	clipboard = OS::get().getClipboard();
}

void SystemSDL::deInit()
{
	// Close SDL
	SDL_Quit();
}

Path SystemSDL::getAssetsPath(const Path& gamePath) const
{
	return gamePath / ".." / "assets";
}

Path SystemSDL::getUnpackedAssetsPath(const Path& gamePath) const
{
	return gamePath / ".." / "assets_unpacked";
}

bool SystemSDL::generateEvents(VideoAPI* video, InputAPI* input)
{
	SDL_Event event;
	SDL_PumpEvents();
	while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) > 0) {
		switch (event.type) {
			case SDL_KEYDOWN:
			case SDL_KEYUP:
			case SDL_TEXTINPUT:
			case SDL_TEXTEDITING:
			case SDL_JOYAXISMOTION:
			case SDL_JOYBUTTONDOWN:
			case SDL_JOYBUTTONUP:
			case SDL_JOYHATMOTION:
			case SDL_JOYBALLMOTION:
			case SDL_MOUSEMOTION:
			case SDL_MOUSEBUTTONUP:
			case SDL_MOUSEBUTTONDOWN:
			case SDL_MOUSEWHEEL:
			case SDL_FINGERUP:
			case SDL_FINGERDOWN:
			case SDL_FINGERMOTION:
			{
				auto sdlInput = dynamic_cast<InputSDL*>(input);
				if (sdlInput) {
					sdlInput->processEvent(event);
				}
				break;
			}
			case SDL_QUIT:
			{
				std::cout << "SDL_QUIT received." << std::endl;
				return false;
			}
			case SDL_WINDOWEVENT:
			{
				if (video) {
					processVideoEvent(video, event);
				}
				break;
			}
		}
	}
	return true;
}

void SystemSDL::processVideoEvent(VideoAPI* video, const SDL_Event& event)
{
	for (auto& w : windows) {
		if (w->getId() == int(event.window.windowID)) {
			if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
				int x, y;
				SDL_GetWindowPosition(SDL_GetWindowFromID(event.window.windowID), &x, &y);
				w->updateDefinition(w->getDefinition().withPosition(Vector2i(x, y)).withSize(Vector2i(event.window.data1, event.window.data2)));
			} else if (event.window.event == SDL_WINDOWEVENT_MAXIMIZED) {
				w->updateDefinition(w->getDefinition().withState(WindowState::Maximized));
			} else if (event.window.event == SDL_WINDOWEVENT_MINIMIZED) {
				w->updateDefinition(w->getDefinition().withState(WindowState::Minimized));
			} else if (event.window.event == SDL_WINDOWEVENT_RESTORED) {
				w->updateDefinition(w->getDefinition().withState(WindowState::Normal));
			}
		}
	}
}

std::unique_ptr<ResourceDataReader> SystemSDL::getDataReader(String path, int64_t start, int64_t end)
{
	return SDLRWOps::fromPath(path, start, end);
}

std::shared_ptr<Window> SystemSDL::createWindow(const WindowDefinition& windowDef)
{
	initVideo();
	bool openGL = true;

	// Set flags and GL attributes
	auto windowType = windowDef.getWindowType();
	int flags = SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_ALLOW_HIGHDPI;
	if (openGL) {
		flags |= SDL_WINDOW_OPENGL;
	}
	if (windowType == WindowType::BorderlessWindow) {
		flags |= SDL_WINDOW_BORDERLESS;
	}
	else if (windowType == WindowType::ResizableWindow) {
		flags |= SDL_WINDOW_RESIZABLE;
	}
	else if (windowType == WindowType::Fullscreen) {
		flags |= SDL_WINDOW_FULLSCREEN;
	}

	// Context options
	if (openGL) {
#if defined(WITH_OPENGL_ES2)
		SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
		SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
		SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
		SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
		SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 0);
#else
		SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
		SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
		SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
		SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
#ifdef _DEBUG
		//SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
#endif
		SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
#endif
	}

	// Window position
	Vector2i windowSize = windowDef.getSize();
	Vector2i winPos = windowDef.getPosition().get_value_or(getCenteredWindow(windowSize, 0));

	// Create window
	auto sdlWindow = SDL_CreateWindow(windowDef.getTitle().c_str(), winPos.x, winPos.y, windowSize.x, windowSize.y, flags);
	if (!sdlWindow) {
		throw Exception(String("Error creating SDL window: ") + SDL_GetError(), HalleyExceptions::SystemPlugin);
	}

	// Show window
	auto window = std::make_shared<SDLWindow>(sdlWindow);
	window->show();
	window->update(windowDef);
	windows.push_back(window);

	return window;
}

void SystemSDL::destroyWindow(std::shared_ptr<Window> window)
{
	for (size_t i = 0; i < windows.size(); ++i) {
		if (windows[i] == window) {
			windows[i]->destroy();
			windows.erase(windows.begin() + i);
			break;
		}
	}
	if (windows.empty()) {
		deInitVideo();
	}
}

Vector2i SystemSDL::getScreenSize(int n) const
{
	initVideo();
	SDL_DisplayMode info;
	if (SDL_GetDesktopDisplayMode(n, &info) == 0) {
		return Vector2i(info.w, info.h);
	} else {
		return Vector2i();
	}
}

Rect4i SystemSDL::getDisplayRect(int screen) const
{
	screen = std::max(0, std::min(screen, SDL_GetNumVideoDisplays() - 1));

	SDL_Rect rect;
	SDL_GetDisplayBounds(screen, &rect);
	return Rect4i(rect.x, rect.y, rect.w, rect.h);
}

Vector2i SystemSDL::getCenteredWindow(Vector2i size, int screen) const
{
	Rect4i rect = getDisplayRect(screen);
	return rect.getTopLeft() + (rect.getSize() - size) / 2;
}

std::unique_ptr<GLContext> SystemSDL::createGLContext()
{
	return std::make_unique<SDLGLContext>(windows[0]->getSDLWindow());
}

void SystemSDL::showCursor(bool show)
{
	SDL_ShowCursor(show ? 1 : 0);
}

std::shared_ptr<ISaveData> SystemSDL::getStorageContainer(SaveDataType type, const String& containerName)
{
	Path dir = saveDir[type];
	if (!containerName.isEmpty()) {
		dir = dir / containerName / ".";
	}

	OS::get().createDirectories(dir);
	return std::make_shared<SDLSaveData>(dir);
}

void SystemSDL::setEnvironment(Environment* env)
{
	for (int i = 0; i < int(SaveDataType::Cache); ++i) {
		SaveDataType type = SaveDataType(i);
		auto dir = env->getDataPath() / toString(type) / ".";
		saveDir[type] = dir;
	}
}

bool SystemSDL::canExit()
{
	return true;
}

std::shared_ptr<IClipboard> SystemSDL::getClipboard() const
{
	return clipboard;
}

void SystemSDL::printDebugInfo() const
{
	std::cout << std::endl << ConsoleColour(Console::GREEN) << "Initializing Video Display...\n" << ConsoleColour();
	std::cout << "Drivers available:\n";
	for (int i = 0; i < SDL_GetNumVideoDrivers(); i++) {
		std::cout << "\t" << i << ": " << SDL_GetVideoDriver(i) << "\n";
	}
	std::cout << "Video driver: " << ConsoleColour(Console::DARK_GREY) << SDL_GetCurrentVideoDriver() << ConsoleColour() << std::endl;
}

void SystemSDL::initVideo() const
{
	if (!videoInit) {
		if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) {
			throw Exception(String("Exception initializing video: ") + SDL_GetError(), HalleyExceptions::SystemPlugin);
		}
		SDL_VideoInit(nullptr);
		printDebugInfo();
		videoInit = true;
	}
}

void SystemSDL::deInitVideo()
{
	if (videoInit) {
		SDL_VideoQuit();
		SDL_QuitSubSystem(SDL_INIT_VIDEO);
		videoInit = false;
	}
}

SDLSaveData::SDLSaveData(Path dir)
	: dir(dir)
{
}

bool SDLSaveData::isReady() const
{
	return true;
}

Bytes SDLSaveData::getData(const String& path)
{
	Expects (!path.isEmpty());
	return Path::readFile(dir / path);
}

std::vector<String> SDLSaveData::enumerate(const String& root)
{
	auto paths = OS::get().enumerateDirectory(dir);
	std::vector<String> result;
	for (auto& p: paths) {
		auto path = p.toString();
		if (path.startsWith(root)) {
			result.push_back(path);
		}
	}
	return result;
}

void SDLSaveData::setData(const String& path, const Bytes& data, bool commit)
{
	Expects (!path.isEmpty());

	OS::get().createDirectories(dir);
	Path::writeFile(dir / path, data);

	Logger::logDev("Saving \"" + path + "\", " + String::prettySize(data.size()));
}

void SDLSaveData::commit()
{
}
<commit_msg>Fix SDL cache folder.<commit_after>#include "system_sdl.h"
#include <SDL.h>
#include <fstream>
#include "halley/core/api/halley_api_internal.h"
#include <halley/support/console.h>
#include <halley/support/exception.h>
#include "sdl_rw_ops.h"
#include "halley/core/graphics/window.h"
#include "halley/os/os.h"
#include "sdl_window.h"
#include "sdl_gl_context.h"
#include "input_sdl.h"
#include "halley/support/logger.h"

using namespace Halley;

void SystemSDL::init()
{
	// SDL version
	SDL_version compiled;
	SDL_version linked;
	SDL_VERSION(&compiled);
	SDL_GetVersion(&linked);
	std::cout << ConsoleColour(Console::GREEN) << "\nInitializing SDL..." << ConsoleColour() << std::endl;
	std::cout << "\tVersion/Compiled: " << ConsoleColour(Console::DARK_GREY) << int(compiled.major) << "." << int(compiled.minor) << "." << int(compiled.patch) << ConsoleColour() << std::endl;
	std::cout << "\tVersion/Linked: " << ConsoleColour(Console::DARK_GREY) << int(linked.major) << "." << int(linked.minor) << "." << int(linked.patch) << ConsoleColour() << std::endl;

	// Initialize SDL
	if (!SDL_WasInit(0)) {
		if (SDL_Init(0) == -1) {
			throw Exception(String("Exception initializing SDL: ") + SDL_GetError(), HalleyExceptions::SystemPlugin);
		}
	}
	if (SDL_InitSubSystem(SDL_INIT_TIMER) == -1) {
		throw Exception(String("Exception initializing timer: ") + SDL_GetError(), HalleyExceptions::SystemPlugin);
	}
	if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1) {
		throw Exception(String("Exception initializing joystick: ") + SDL_GetError(), HalleyExceptions::SystemPlugin);
	}

	SDL_ShowCursor(SDL_DISABLE);

	// Init clipboard
	clipboard = OS::get().getClipboard();
}

void SystemSDL::deInit()
{
	// Close SDL
	SDL_Quit();
}

Path SystemSDL::getAssetsPath(const Path& gamePath) const
{
	return gamePath / ".." / "assets";
}

Path SystemSDL::getUnpackedAssetsPath(const Path& gamePath) const
{
	return gamePath / ".." / "assets_unpacked";
}

bool SystemSDL::generateEvents(VideoAPI* video, InputAPI* input)
{
	SDL_Event event;
	SDL_PumpEvents();
	while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) > 0) {
		switch (event.type) {
			case SDL_KEYDOWN:
			case SDL_KEYUP:
			case SDL_TEXTINPUT:
			case SDL_TEXTEDITING:
			case SDL_JOYAXISMOTION:
			case SDL_JOYBUTTONDOWN:
			case SDL_JOYBUTTONUP:
			case SDL_JOYHATMOTION:
			case SDL_JOYBALLMOTION:
			case SDL_MOUSEMOTION:
			case SDL_MOUSEBUTTONUP:
			case SDL_MOUSEBUTTONDOWN:
			case SDL_MOUSEWHEEL:
			case SDL_FINGERUP:
			case SDL_FINGERDOWN:
			case SDL_FINGERMOTION:
			{
				auto sdlInput = dynamic_cast<InputSDL*>(input);
				if (sdlInput) {
					sdlInput->processEvent(event);
				}
				break;
			}
			case SDL_QUIT:
			{
				std::cout << "SDL_QUIT received." << std::endl;
				return false;
			}
			case SDL_WINDOWEVENT:
			{
				if (video) {
					processVideoEvent(video, event);
				}
				break;
			}
		}
	}
	return true;
}

void SystemSDL::processVideoEvent(VideoAPI* video, const SDL_Event& event)
{
	for (auto& w : windows) {
		if (w->getId() == int(event.window.windowID)) {
			if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
				int x, y;
				SDL_GetWindowPosition(SDL_GetWindowFromID(event.window.windowID), &x, &y);
				w->updateDefinition(w->getDefinition().withPosition(Vector2i(x, y)).withSize(Vector2i(event.window.data1, event.window.data2)));
			} else if (event.window.event == SDL_WINDOWEVENT_MAXIMIZED) {
				w->updateDefinition(w->getDefinition().withState(WindowState::Maximized));
			} else if (event.window.event == SDL_WINDOWEVENT_MINIMIZED) {
				w->updateDefinition(w->getDefinition().withState(WindowState::Minimized));
			} else if (event.window.event == SDL_WINDOWEVENT_RESTORED) {
				w->updateDefinition(w->getDefinition().withState(WindowState::Normal));
			}
		}
	}
}

std::unique_ptr<ResourceDataReader> SystemSDL::getDataReader(String path, int64_t start, int64_t end)
{
	return SDLRWOps::fromPath(path, start, end);
}

std::shared_ptr<Window> SystemSDL::createWindow(const WindowDefinition& windowDef)
{
	initVideo();
	bool openGL = true;

	// Set flags and GL attributes
	auto windowType = windowDef.getWindowType();
	int flags = SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_ALLOW_HIGHDPI;
	if (openGL) {
		flags |= SDL_WINDOW_OPENGL;
	}
	if (windowType == WindowType::BorderlessWindow) {
		flags |= SDL_WINDOW_BORDERLESS;
	}
	else if (windowType == WindowType::ResizableWindow) {
		flags |= SDL_WINDOW_RESIZABLE;
	}
	else if (windowType == WindowType::Fullscreen) {
		flags |= SDL_WINDOW_FULLSCREEN;
	}

	// Context options
	if (openGL) {
#if defined(WITH_OPENGL_ES2)
		SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
		SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
		SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
		SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
		SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 0);
#else
		SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
		SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
		SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
		SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
#ifdef _DEBUG
		//SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
#endif
		SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
#endif
	}

	// Window position
	Vector2i windowSize = windowDef.getSize();
	Vector2i winPos = windowDef.getPosition().get_value_or(getCenteredWindow(windowSize, 0));

	// Create window
	auto sdlWindow = SDL_CreateWindow(windowDef.getTitle().c_str(), winPos.x, winPos.y, windowSize.x, windowSize.y, flags);
	if (!sdlWindow) {
		throw Exception(String("Error creating SDL window: ") + SDL_GetError(), HalleyExceptions::SystemPlugin);
	}

	// Show window
	auto window = std::make_shared<SDLWindow>(sdlWindow);
	window->show();
	window->update(windowDef);
	windows.push_back(window);

	return window;
}

void SystemSDL::destroyWindow(std::shared_ptr<Window> window)
{
	for (size_t i = 0; i < windows.size(); ++i) {
		if (windows[i] == window) {
			windows[i]->destroy();
			windows.erase(windows.begin() + i);
			break;
		}
	}
	if (windows.empty()) {
		deInitVideo();
	}
}

Vector2i SystemSDL::getScreenSize(int n) const
{
	initVideo();
	SDL_DisplayMode info;
	if (SDL_GetDesktopDisplayMode(n, &info) == 0) {
		return Vector2i(info.w, info.h);
	} else {
		return Vector2i();
	}
}

Rect4i SystemSDL::getDisplayRect(int screen) const
{
	screen = std::max(0, std::min(screen, SDL_GetNumVideoDisplays() - 1));

	SDL_Rect rect;
	SDL_GetDisplayBounds(screen, &rect);
	return Rect4i(rect.x, rect.y, rect.w, rect.h);
}

Vector2i SystemSDL::getCenteredWindow(Vector2i size, int screen) const
{
	Rect4i rect = getDisplayRect(screen);
	return rect.getTopLeft() + (rect.getSize() - size) / 2;
}

std::unique_ptr<GLContext> SystemSDL::createGLContext()
{
	return std::make_unique<SDLGLContext>(windows[0]->getSDLWindow());
}

void SystemSDL::showCursor(bool show)
{
	SDL_ShowCursor(show ? 1 : 0);
}

std::shared_ptr<ISaveData> SystemSDL::getStorageContainer(SaveDataType type, const String& containerName)
{
	Path dir = saveDir[type];
	if (!containerName.isEmpty()) {
		dir = dir / containerName / ".";
	}

	OS::get().createDirectories(dir);
	return std::make_shared<SDLSaveData>(dir);
}

void SystemSDL::setEnvironment(Environment* env)
{
	for (int i = 0; i <= int(SaveDataType::Cache); ++i) {
		SaveDataType type = SaveDataType(i);
		auto dir = env->getDataPath() / toString(type) / ".";
		saveDir[type] = dir;
	}
}

bool SystemSDL::canExit()
{
	return true;
}

std::shared_ptr<IClipboard> SystemSDL::getClipboard() const
{
	return clipboard;
}

void SystemSDL::printDebugInfo() const
{
	std::cout << std::endl << ConsoleColour(Console::GREEN) << "Initializing Video Display...\n" << ConsoleColour();
	std::cout << "Drivers available:\n";
	for (int i = 0; i < SDL_GetNumVideoDrivers(); i++) {
		std::cout << "\t" << i << ": " << SDL_GetVideoDriver(i) << "\n";
	}
	std::cout << "Video driver: " << ConsoleColour(Console::DARK_GREY) << SDL_GetCurrentVideoDriver() << ConsoleColour() << std::endl;
}

void SystemSDL::initVideo() const
{
	if (!videoInit) {
		if (SDL_InitSubSystem(SDL_INIT_VIDEO) == -1) {
			throw Exception(String("Exception initializing video: ") + SDL_GetError(), HalleyExceptions::SystemPlugin);
		}
		SDL_VideoInit(nullptr);
		printDebugInfo();
		videoInit = true;
	}
}

void SystemSDL::deInitVideo()
{
	if (videoInit) {
		SDL_VideoQuit();
		SDL_QuitSubSystem(SDL_INIT_VIDEO);
		videoInit = false;
	}
}

SDLSaveData::SDLSaveData(Path dir)
	: dir(dir)
{
}

bool SDLSaveData::isReady() const
{
	return true;
}

Bytes SDLSaveData::getData(const String& path)
{
	Expects (!path.isEmpty());
	return Path::readFile(dir / path);
}

std::vector<String> SDLSaveData::enumerate(const String& root)
{
	auto paths = OS::get().enumerateDirectory(dir);
	std::vector<String> result;
	for (auto& p: paths) {
		auto path = p.toString();
		if (path.startsWith(root)) {
			result.push_back(path);
		}
	}
	return result;
}

void SDLSaveData::setData(const String& path, const Bytes& data, bool commit)
{
	Expects (!path.isEmpty());

	OS::get().createDirectories(dir);
	Path::writeFile(dir / path, data);

	Logger::logDev("Saving \"" + path + "\", " + String::prettySize(data.size()));
}

void SDLSaveData::commit()
{
}
<|endoftext|>