<commit_before>#include "ContextCairo.h"

#include <cassert>
#include <cmath>

using namespace canvas;

#if 0
Mutex CairoMapCanvas::pango_mutex;
Mutex CairoMapCanvas::draw_mutex;
#endif

using namespace std;

CairoSurface::CairoSurface(unsigned int _width, unsigned int _height)
  : Surface(_width, _height) {
  cairo_format_t format = CAIRO_FORMAT_ARGB32;
  // format = CAIRO_FORMAT_RGB24;
  surface = cairo_image_surface_create(format, _width, _height);
  assert(surface);
  cr = cairo_create(surface);
  assert(cr);
}

CairoSurface::CairoSurface(unsigned int _width, unsigned int _height, const unsigned char * data)
  : Surface(_width, _height)
{
  cairo_format_t format = CAIRO_FORMAT_RGB24;
  unsigned int stride = cairo_format_stride_for_width(format, _width);
  assert(stride == 4 * _width);
  storage = new unsigned int[_width * _height];
  for (unsigned int i = 0; i < _width * _height; i++) {
    storage[i] = data[3 * i + 2] + (data[3 * i + 1] << 8) + (data[3 * i + 0] << 16);
  }
  surface = cairo_image_surface_create_for_data((unsigned char*)storage,
						format,
						_width,
						_height,
						stride);
  assert(surface);
  cr = cairo_create(surface);
  assert(cr);
}

CairoSurface::CairoSurface(const std::string & filename) : Surface(0, 0)
{
  surface = cairo_image_surface_create_from_png(filename.c_str());
  assert(surface);
  Surface::resize(cairo_image_surface_get_width(surface),
		  cairo_image_surface_get_height(surface));
  cr = cairo_create(surface);
  assert(cr);
}

CairoSurface::~CairoSurface() {
  if (cr) {
    cairo_destroy(cr);
  }
  if (surface) {
    cairo_surface_destroy(surface);
  }
  delete[] storage;
}

void
CairoSurface::flush() {
  cairo_surface_flush(surface);
}

void
CairoSurface::markDirty() {
  cairo_surface_mark_dirty(surface);
}

void
CairoSurface::resize(unsigned int _width, unsigned int _height) {
  Surface::resize(_width, _height);
  if (cr) cairo_destroy(cr);
  if (surface) cairo_surface_destroy(surface);
  cairo_format_t format = CAIRO_FORMAT_ARGB32;
  // format = CAIRO_FORMAT_RGB24;
  surface = cairo_image_surface_create(format, _width, _height);
  assert(surface);
  cr = cairo_create(surface);
  assert(cr);
}

#if 0
unsigned char *
CairoSurface::getBuffer() {
  assert(surface);
  return cairo_image_surface_get_data(surface);
}
#endif

void
CairoSurface::fillText(Context & context, const std::string & text, double x, double y) {
  const Font & font = context.font;
  cairo_set_source_rgba(cr, context.fillStyle.color.red / 255.0f, context.fillStyle.color.green / 255.0f, context.fillStyle.color.blue / 255.0f, 1.0f);
  cairo_select_font_face(cr, font.family.c_str(),
			 font.slant == Font::NORMAL_SLANT ? CAIRO_FONT_SLANT_NORMAL : (font.slant == Font::ITALIC ? CAIRO_FONT_SLANT_ITALIC : CAIRO_FONT_SLANT_OBLIQUE),
			 font.weight == Font::NORMAL || font.weight == Font::LIGHTER ? CAIRO_FONT_WEIGHT_NORMAL : CAIRO_FONT_WEIGHT_BOLD);
  cairo_set_font_size(cr, font.size);
  cairo_text_extents_t extents;
  cairo_text_extents(cr, text.c_str(), &extents);

  switch (context.textBaseline.getType()) {
  case TextBaseline::MIDDLE: y -= (extents.height/2 + extents.y_bearing); break;
  case TextBaseline::TOP: y += extents.height; break;
  default: break;
  }

  switch (context.textAlign) {
  case LEFT: break;
  case CENTER: x -= extents.width / 2; break;
  case RIGHT: x -= extents.width; break;
  default: break;
  }

  cairo_move_to(cr, x, y);
  cairo_show_text(cr, text.c_str());
}

void
CairoSurface::drawImage(Surface & _img, double x, double y, double w, double h) {
  CairoSurface & img = dynamic_cast<CairoSurface&>(_img);
  double sx = w / img.getWidth(), sy = h / img.getHeight();
  cairo_save(cr);
  cairo_scale(cr, sx, sy);
  cairo_set_source_surface(cr, img.surface, x / sx, y / sy);
  cairo_paint(cr);
  cairo_restore(cr);
}

ContextCairo::ContextCairo(unsigned int _width, unsigned int _height)
  : Context(_width, _height),
    default_surface(_width, _height)
{

  // double pxscale = preport->hPX>preport->vPX ? preport->hPX:preport->vPX;
  // cairo_text_extents_t te;

  // cairo_scale(*ppcr, pxscale, pxscale);

  // cairo_set_font_size(cr, FONTSIZENORMAL);              // font
  // cairo_select_font_face(cr, "Georgia", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);

  // cairo_text_extents(*ppcr, preport->ptitle, &te);       // center title
  // preport->titleH = 0.5 - te.x_bearing - te.width / 2;

  // cairo_set_line_width(*ppcr, 0.001*preport->linewidth);  // frame
  // preport->legendlinewidth = 0.003/powf((preport->hPX*preport->vPX)/1E4, 0.3)

#if 0
  // MutexLocker mh(pango_mutex);
  font_description = pango_font_description_new();
  pango_font_description_set_family(font_description, "sans-serif");
  // pango_font_description_set_weight(font_description, PANGO_WEIGHT_BOLD);
  pango_font_description_set_absolute_size(font_description, 11 * PANGO_SCALE);
  // mh.release();
#endif
}

ContextCairo::~ContextCairo() {
#if 0
  if (font_description) {
    // MutexLocker mh(pango_mutex);
    pango_font_description_free(font_description);
  }
#endif
}

void
ContextCairo::save() {
  cairo_save(default_surface.cr);
}

void
ContextCairo::restore() {
  cairo_restore(default_surface.cr);
}

void
ContextCairo::beginPath() {
  cairo_new_path(default_surface.cr);
}

void
ContextCairo::closePath() {
  cairo_close_path(default_surface.cr);
}

void
ContextCairo::clip() {
  cairo_clip(default_surface.cr);
}

void
ContextCairo::arc(double x, double y, double r, double sa, double ea, bool anticlockwise) {
  double span = 0;

  if ((!anticlockwise && (ea - sa >= 2 * M_PI)) || (anticlockwise && (sa - ea >= 2 * M_PI))) {
    // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
    // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
    // circumference of this circle.
    span = 2 * M_PI;
  } else {
    if (!anticlockwise && (ea < sa)) {
      span += 2 * M_PI;
    } else if (anticlockwise && (sa < ea)) {
      span -= 2 * M_PI;
    }

#if 0
    // this is also due to switched coordinate system
    // we would end up with a 0 span instead of 360
    if (!(qFuzzyCompare(span + (ea - sa) + 1, 1.0) && qFuzzyCompare(qAbs(span), 360.0))) {
      // mod 360
      span += (ea - sa) - (static_cast<int>((ea - sa) / 360)) * 360;
    }
#else
    span += ea - sa;
#endif
  }

#if 0
  // If the path is empty, move to where the arc will start to avoid painting a line from (0,0)
  // NOTE: QPainterPath::isEmpty() won't work here since it ignores a lone MoveToElement
  if (!m_path.elementCount())
    m_path.arcMoveTo(xs, ys, width, height, sa);
  else if (!radius) {
    m_path.lineTo(xc, yc);
    return;
  }
#endif

  if (!anticlockwise) {
    cairo_arc(default_surface.cr, x, y, r, sa, sa + span);
  } else {
    cairo_arc_negative(default_surface.cr, x, y, r, sa, sa + span);
  }
}

TextMetrics
ContextCairo::measureText(const std::string & text) {
  cairo_select_font_face(default_surface.cr, font.family.c_str(),
			 font.slant == Font::NORMAL_SLANT ? CAIRO_FONT_SLANT_NORMAL : (font.slant == Font::ITALIC ? CAIRO_FONT_SLANT_ITALIC : CAIRO_FONT_SLANT_OBLIQUE),
			 font.weight == Font::NORMAL || font.weight == Font::LIGHTER ? CAIRO_FONT_WEIGHT_NORMAL : CAIRO_FONT_WEIGHT_BOLD);
  cairo_set_font_size(default_surface.cr, font.size);
  cairo_text_extents_t te;
  cairo_text_extents(default_surface.cr, text.c_str(), &te);
  return { (float)te.width, (float)te.height };
}

void
ContextCairo::moveTo(double x, double y) {
  cairo_move_to(default_surface.cr, x, y);
}

void
ContextCairo::lineTo(double x, double y) {
  cairo_line_to(default_surface.cr, x, y);
}

void
ContextCairo::stroke() {
  cairo_set_line_width(default_surface.cr, lineWidth);
  // cairo_set_line_join(default_surface.cr, CAIRO_LINE_JOIN_ROUND);
  cairo_set_source_rgba(default_surface.cr, strokeStyle.color.red / 255.0f, strokeStyle.color.green / 255.0f, strokeStyle.color.blue / 255.0f, 1.0f);
  cairo_stroke_preserve(default_surface.cr);
}

void
ContextCairo::fill() {
  if (fillStyle.getType() == Style::LINEAR_GRADIENT) {
    cairo_pattern_t * pat = cairo_pattern_create_linear(fillStyle.x0, fillStyle.y0, fillStyle.x1, fillStyle.y1);
    for (map<float, Color>::const_iterator it = fillStyle.getColors().begin(); it != fillStyle.getColors().end(); it++) {
      cairo_pattern_add_color_stop_rgba(pat, it->first, it->second.red / 255.0f, it->second.green / 255.0f, it->second.blue / 255.0f, 1);
    }
    cairo_set_source (default_surface.cr, pat);
    cairo_pattern_destroy (pat);
  } else {
    cairo_set_source_rgba(default_surface.cr, fillStyle.color.red / 255.0f, fillStyle.color.green / 255.0f, fillStyle.color.blue / 255.0f, 1.0f);
  }
  cairo_fill_preserve(default_surface.cr);
}

Point
ContextCairo::getCurrentPoint() {
  double x0, y0;
  cairo_get_current_point(default_surface.cr, &x0, &y0);
  return Point(x0, y0);
}
<commit_msg>modify cairo pixel alignment<commit_after>#include "ContextCairo.h"

#include <cassert>
#include <cmath>

using namespace canvas;

#if 0
Mutex CairoMapCanvas::pango_mutex;
Mutex CairoMapCanvas::draw_mutex;
#endif

using namespace std;

CairoSurface::CairoSurface(unsigned int _width, unsigned int _height)
  : Surface(_width, _height) {
  cairo_format_t format = CAIRO_FORMAT_ARGB32;
  // format = CAIRO_FORMAT_RGB24;
  surface = cairo_image_surface_create(format, _width, _height);
  assert(surface);
  cr = cairo_create(surface);
  assert(cr);
}

CairoSurface::CairoSurface(unsigned int _width, unsigned int _height, const unsigned char * data)
  : Surface(_width, _height)
{
  cairo_format_t format = CAIRO_FORMAT_RGB24;
  unsigned int stride = cairo_format_stride_for_width(format, _width);
  assert(stride == 4 * _width);
  storage = new unsigned int[_width * _height];
  for (unsigned int i = 0; i < _width * _height; i++) {
    storage[i] = data[3 * i + 2] + (data[3 * i + 1] << 8) + (data[3 * i + 0] << 16);
  }
  surface = cairo_image_surface_create_for_data((unsigned char*)storage,
						format,
						_width,
						_height,
						stride);
  assert(surface);
  cr = cairo_create(surface);
  assert(cr);
}

CairoSurface::CairoSurface(const std::string & filename) : Surface(0, 0)
{
  surface = cairo_image_surface_create_from_png(filename.c_str());
  assert(surface);
  Surface::resize(cairo_image_surface_get_width(surface),
		  cairo_image_surface_get_height(surface));
  cr = cairo_create(surface);
  assert(cr);
}

CairoSurface::~CairoSurface() {
  if (cr) {
    cairo_destroy(cr);
  }
  if (surface) {
    cairo_surface_destroy(surface);
  }
  delete[] storage;
}

void
CairoSurface::flush() {
  cairo_surface_flush(surface);
}

void
CairoSurface::markDirty() {
  cairo_surface_mark_dirty(surface);
}

void
CairoSurface::resize(unsigned int _width, unsigned int _height) {
  Surface::resize(_width, _height);
  if (cr) cairo_destroy(cr);
  if (surface) cairo_surface_destroy(surface);
  cairo_format_t format = CAIRO_FORMAT_ARGB32;
  // format = CAIRO_FORMAT_RGB24;
  surface = cairo_image_surface_create(format, _width, _height);
  assert(surface);
  cr = cairo_create(surface);
  assert(cr);
}

#if 0
unsigned char *
CairoSurface::getBuffer() {
  assert(surface);
  return cairo_image_surface_get_data(surface);
}
#endif

void
CairoSurface::fillText(Context & context, const std::string & text, double x, double y) {
  const Font & font = context.font;
  cairo_set_source_rgba(cr, context.fillStyle.color.red / 255.0f, context.fillStyle.color.green / 255.0f, context.fillStyle.color.blue / 255.0f, 1.0f);
  cairo_select_font_face(cr, font.family.c_str(),
			 font.slant == Font::NORMAL_SLANT ? CAIRO_FONT_SLANT_NORMAL : (font.slant == Font::ITALIC ? CAIRO_FONT_SLANT_ITALIC : CAIRO_FONT_SLANT_OBLIQUE),
			 font.weight == Font::NORMAL || font.weight == Font::LIGHTER ? CAIRO_FONT_WEIGHT_NORMAL : CAIRO_FONT_WEIGHT_BOLD);
  cairo_set_font_size(cr, font.size);
  cairo_text_extents_t extents;
  cairo_text_extents(cr, text.c_str(), &extents);

  switch (context.textBaseline.getType()) {
  case TextBaseline::MIDDLE: y -= (extents.height/2 + extents.y_bearing); break;
  case TextBaseline::TOP: y += extents.height; break;
  default: break;
  }

  switch (context.textAlign) {
  case LEFT: break;
  case CENTER: x -= extents.width / 2; break;
  case RIGHT: x -= extents.width; break;
  default: break;
  }

  cairo_move_to(cr, x + 0.5, y + 0.5);
  cairo_show_text(cr, text.c_str());
}

void
CairoSurface::drawImage(Surface & _img, double x, double y, double w, double h) {
  cerr << "trying to draw image " << &_img << endl;
  CairoSurface & img = dynamic_cast<CairoSurface&>(_img);
  double sx = w / img.getWidth(), sy = h / img.getHeight();
  cairo_save(cr);
  cairo_scale(cr, sx, sy);
  cairo_set_source_surface(cr, img.surface, (x / sx) + 0.5, y / sy + 0.5);
  cairo_paint(cr);
  cairo_restore(cr);
}

ContextCairo::ContextCairo(unsigned int _width, unsigned int _height)
  : Context(_width, _height),
    default_surface(_width, _height)
{

  // double pxscale = preport->hPX>preport->vPX ? preport->hPX:preport->vPX;
  // cairo_text_extents_t te;

  // cairo_scale(*ppcr, pxscale, pxscale);

  // cairo_set_font_size(cr, FONTSIZENORMAL);              // font
  // cairo_select_font_face(cr, "Georgia", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);

  // cairo_text_extents(*ppcr, preport->ptitle, &te);       // center title
  // preport->titleH = 0.5 - te.x_bearing - te.width / 2;

  // cairo_set_line_width(*ppcr, 0.001*preport->linewidth);  // frame
  // preport->legendlinewidth = 0.003/powf((preport->hPX*preport->vPX)/1E4, 0.3)

#if 0
  // MutexLocker mh(pango_mutex);
  font_description = pango_font_description_new();
  pango_font_description_set_family(font_description, "sans-serif");
  // pango_font_description_set_weight(font_description, PANGO_WEIGHT_BOLD);
  pango_font_description_set_absolute_size(font_description, 11 * PANGO_SCALE);
  // mh.release();
#endif
}

ContextCairo::~ContextCairo() {
#if 0
  if (font_description) {
    // MutexLocker mh(pango_mutex);
    pango_font_description_free(font_description);
  }
#endif
}

void
ContextCairo::save() {
  cairo_save(default_surface.cr);
}

void
ContextCairo::restore() {
  cairo_restore(default_surface.cr);
}

void
ContextCairo::beginPath() {
  cairo_new_path(default_surface.cr);
}

void
ContextCairo::closePath() {
  cairo_close_path(default_surface.cr);
}

void
ContextCairo::clip() {
  cairo_clip(default_surface.cr);
}

void
ContextCairo::arc(double x, double y, double r, double sa, double ea, bool anticlockwise) {
  double span = 0;

  if ((!anticlockwise && (ea - sa >= 2 * M_PI)) || (anticlockwise && (sa - ea >= 2 * M_PI))) {
    // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
    // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
    // circumference of this circle.
    span = 2 * M_PI;
  } else {
    if (!anticlockwise && (ea < sa)) {
      span += 2 * M_PI;
    } else if (anticlockwise && (sa < ea)) {
      span -= 2 * M_PI;
    }

#if 0
    // this is also due to switched coordinate system
    // we would end up with a 0 span instead of 360
    if (!(qFuzzyCompare(span + (ea - sa) + 1, 1.0) && qFuzzyCompare(qAbs(span), 360.0))) {
      // mod 360
      span += (ea - sa) - (static_cast<int>((ea - sa) / 360)) * 360;
    }
#else
    span += ea - sa;
#endif
  }

#if 0
  // If the path is empty, move to where the arc will start to avoid painting a line from (0,0)
  // NOTE: QPainterPath::isEmpty() won't work here since it ignores a lone MoveToElement
  if (!m_path.elementCount())
    m_path.arcMoveTo(xs, ys, width, height, sa);
  else if (!radius) {
    m_path.lineTo(xc, yc);
    return;
  }
#endif

  if (!anticlockwise) {
    cairo_arc(default_surface.cr, x + 0.5, y + 0.5, r, sa, sa + span);
  } else {
    cairo_arc_negative(default_surface.cr, x + 0.5, y + 0.5, r, sa, sa + span);
  }
}

TextMetrics
ContextCairo::measureText(const std::string & text) {
  cairo_select_font_face(default_surface.cr, font.family.c_str(),
			 font.slant == Font::NORMAL_SLANT ? CAIRO_FONT_SLANT_NORMAL : (font.slant == Font::ITALIC ? CAIRO_FONT_SLANT_ITALIC : CAIRO_FONT_SLANT_OBLIQUE),
			 font.weight == Font::NORMAL || font.weight == Font::LIGHTER ? CAIRO_FONT_WEIGHT_NORMAL : CAIRO_FONT_WEIGHT_BOLD);
  cairo_set_font_size(default_surface.cr, font.size);
  cairo_text_extents_t te;
  cairo_text_extents(default_surface.cr, text.c_str(), &te);
  return { (float)te.width, (float)te.height };
}

void
ContextCairo::moveTo(double x, double y) {
  cairo_move_to(default_surface.cr, x + 0.5, y + 0.5);
}

void
ContextCairo::lineTo(double x, double y) {
  cairo_line_to(default_surface.cr, x + 0.5, y + 0.5);
}

void
ContextCairo::stroke() {
  cairo_set_line_width(default_surface.cr, lineWidth);
  // cairo_set_line_join(default_surface.cr, CAIRO_LINE_JOIN_ROUND);
  cairo_set_source_rgba(default_surface.cr, strokeStyle.color.red / 255.0f, strokeStyle.color.green / 255.0f, strokeStyle.color.blue / 255.0f, 1.0f);
  cairo_stroke_preserve(default_surface.cr);
}

void
ContextCairo::fill() {
  if (fillStyle.getType() == Style::LINEAR_GRADIENT) {
    cairo_pattern_t * pat = cairo_pattern_create_linear(fillStyle.x0, fillStyle.y0, fillStyle.x1, fillStyle.y1);
    for (map<float, Color>::const_iterator it = fillStyle.getColors().begin(); it != fillStyle.getColors().end(); it++) {
      cairo_pattern_add_color_stop_rgba(pat, it->first, it->second.red / 255.0f, it->second.green / 255.0f, it->second.blue / 255.0f, 1);
    }
    cairo_set_source (default_surface.cr, pat);
    cairo_pattern_destroy (pat);
  } else {
    cairo_set_source_rgba(default_surface.cr, fillStyle.color.red / 255.0f, fillStyle.color.green / 255.0f, fillStyle.color.blue / 255.0f, 1.0f);
  }
  cairo_fill_preserve(default_surface.cr);
}

Point
ContextCairo::getCurrentPoint() {
  double x0, y0;
  cairo_get_current_point(default_surface.cr, &x0, &y0);
  return Point(x0 - 0.5, y0 - 0.5);
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/thread.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/address.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/socket.hpp"
#include "peer_server.hpp"

#include <boost/detail/atomic_count.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>

using namespace libtorrent;

struct peer_server
{

	boost::asio::io_service m_ios;
	boost::detail::atomic_count m_peer_requests;
	tcp::acceptor m_acceptor;
	int m_port;

	boost::shared_ptr<libtorrent::thread> m_thread;

	peer_server()
		: m_peer_requests(0)
		, m_acceptor(m_ios)
	{
		error_code ec;
		m_acceptor.open(tcp::v4(), ec);
		if (ec)
		{
			fprintf(stderr, "Error opening peer listen socket: %s\n", ec.message().c_str());
			return;
		}

		m_acceptor.bind(tcp::endpoint(address_v4::any(), 0), ec);
		if (ec)
		{
			fprintf(stderr, "Error binding peer socket to port 0: %s\n", ec.message().c_str());
			return;
		}
		m_port = m_acceptor.local_endpoint(ec).port();
		if (ec)
		{
			fprintf(stderr, "Error getting local endpoint of peer socket: %s\n", ec.message().c_str());
			return;
		}
		m_acceptor.listen(10, ec);
		if (ec)
		{
			fprintf(stderr, "Error listening on peer socket: %s\n", ec.message().c_str());
			return;
		}

		fprintf(stderr, "%s: peer initialized on port %d\n", time_now_string(), m_port);

		m_thread.reset(new thread(boost::bind(&peer_server::thread_fun, this)));
	}

	~peer_server()
	{
		m_acceptor.cancel();
		m_acceptor.close();
		if (m_thread) m_thread->join();
	}

	int port() const { return m_port; }

	int num_hits() const { return m_peer_requests; }

	static void new_connection(error_code const& ec, error_code* ret, bool* done)
	{
		*ret = ec;
		*done = true;
	}

	void thread_fun()
	{
		for (;;)
		{
			error_code ec;
			tcp::endpoint from;
			tcp::socket socket(m_ios);
			condition_variable cond;
			bool done = false;
			m_acceptor.async_accept(socket, from, boost::bind(&new_connection, _1, &ec, &done));
			while (!done)
			{
				m_ios.run_one();
				m_ios.reset();
			}

			if (ec == boost::asio::error::operation_aborted
				|| ec == boost::asio::error::bad_descriptor) return;

			if (ec)
			{
				fprintf(stderr, "Error accepting connection on peer socket: %s\n", ec.message().c_str());
				return;
			}

			fprintf(stderr, "%s: incoming peer connection\n", time_now_string());
			++m_peer_requests;
			socket.close(ec);
		}
	}
};

boost::shared_ptr<peer_server> g_peer;

int start_peer()
{
	g_peer.reset(new peer_server);
	return g_peer->port();
}

// the number of DHT messages received
int num_peer_hits()
{
	if (g_peer) return g_peer->num_hits();
	return 0;
}

void stop_peer()
{
	fprintf(stderr, "%s: stop_peer()\n", time_now_string());
	g_peer.reset();
	fprintf(stderr, "%s: done\n", time_now_string());
}

<commit_msg>test logging<commit_after>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/thread.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/address.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/socket.hpp"
#include "peer_server.hpp"

#include <boost/detail/atomic_count.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>

using namespace libtorrent;

struct peer_server
{

	boost::asio::io_service m_ios;
	boost::detail::atomic_count m_peer_requests;
	tcp::acceptor m_acceptor;
	int m_port;

	boost::shared_ptr<libtorrent::thread> m_thread;

	peer_server()
		: m_peer_requests(0)
		, m_acceptor(m_ios)
	{
		error_code ec;
		m_acceptor.open(tcp::v4(), ec);
		if (ec)
		{
			fprintf(stderr, "Error opening peer listen socket: %s\n", ec.message().c_str());
			return;
		}

		m_acceptor.bind(tcp::endpoint(address_v4::any(), 0), ec);
		if (ec)
		{
			fprintf(stderr, "Error binding peer socket to port 0: %s\n", ec.message().c_str());
			return;
		}
		m_port = m_acceptor.local_endpoint(ec).port();
		if (ec)
		{
			fprintf(stderr, "Error getting local endpoint of peer socket: %s\n", ec.message().c_str());
			return;
		}
		m_acceptor.listen(10, ec);
		if (ec)
		{
			fprintf(stderr, "Error listening on peer socket: %s\n", ec.message().c_str());
			return;
		}

		fprintf(stderr, "%s: peer initialized on port %d\n", time_now_string(), m_port);

		m_thread.reset(new thread(boost::bind(&peer_server::thread_fun, this)));
	}

	~peer_server()
	{
		m_acceptor.cancel();
		m_acceptor.close();
		if (m_thread) m_thread->join();
	}

	int port() const { return m_port; }

	int num_hits() const { return m_peer_requests; }

	static void new_connection(error_code const& ec, error_code* ret, bool* done)
	{
		*ret = ec;
		*done = true;
	}

	void thread_fun()
	{
		for (;;)
		{
			error_code ec;
			tcp::endpoint from;
			tcp::socket socket(m_ios);
			condition_variable cond;
			bool done = false;
			m_acceptor.async_accept(socket, from, boost::bind(&new_connection, _1, &ec, &done));
			while (!done)
			{
				m_ios.run_one();
				m_ios.reset();
			}

			if (ec == boost::asio::error::operation_aborted
				|| ec == boost::asio::error::bad_descriptor) return;

			if (ec)
			{
				fprintf(stderr, "Error accepting connection on peer socket: %s\n", ec.message().c_str());
				return;
			}

			fprintf(stderr, "%s: incoming peer connection\n", time_now_string());
			++m_peer_requests;
			socket.close(ec);
		}
	}
};

boost::shared_ptr<peer_server> g_peer;

int start_peer()
{
	g_peer.reset(new peer_server);
	return g_peer->port();
}

// the number of DHT messages received
int num_peer_hits()
{
	if (g_peer) return g_peer->num_hits();
	return 0;
}

void stop_peer()
{
	fprintf(stderr, "%s: stop_peer()\n", time_now_string());
	g_peer.reset();
	fprintf(stderr, "%s: stop_peer() done\n", time_now_string());
}

<|endoftext|>


<commit_before>/*
 * (C) Copyright 2013 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * 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.
 *
 */

#include "server_test_base.hpp"
#include <boost/test/unit_test.hpp>

#include "KmsMediaServer_constants.h"
#include "KmsMediaDataType_constants.h"
#include "KmsMediaErrorCodes_constants.h"

#include "KmsMediaUriEndPointType_constants.h"
#include "KmsMediaPlayerEndPointType_constants.h"
#include "KmsMediaRecorderEndPointType_constants.h"
#include "KmsMediaZBarFilterType_constants.h"

#include "utils/marshalling.hpp"

#include <gst/gst.h>

#include "common/MediaSet.hpp"

#define GST_CAT_DEFAULT _server_test_
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define GST_DEFAULT_NAME "server_test"

using namespace kurento;

BOOST_FIXTURE_TEST_SUITE ( server_test_suite,  F)

static void
check_version (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  int32_t gotVersion;

  gotVersion = client->getVersion();
  BOOST_CHECK_EQUAL (gotVersion, g_KmsMediaServer_constants.VERSION);
}

#if 0 /* Temporally disabled */
static void
check_type (boost::shared_ptr<kurento::MediaServerServiceClient> client)
{
  MediaObjectId mediaPipeline = MediaObjectId();
  MediaObjectId mo = MediaObjectId();

  client->createMediaPipeline (mediaPipeline, 0);
  BOOST_CHECK (mediaPipeline.type.__isset.mediaObject);
  BOOST_CHECK_EQUAL (mediaPipeline.type.mediaObject, MediaObjectType::type::MEDIA_PIPELINE);

  client->createSdpEndPoint (mo, mediaPipeline, SdpEndPointType::type::RTP_END_POINT);
  BOOST_CHECK (mo.type.__isset.sdpEndPoint);
  BOOST_CHECK_EQUAL (mo.type.sdpEndPoint, SdpEndPointType::type::RTP_END_POINT);

  client->createSdpEndPoint (mo, mediaPipeline, SdpEndPointType::type::WEBRTC_END_POINT);
  BOOST_CHECK (mo.type.__isset.sdpEndPoint);
  BOOST_CHECK_EQUAL (mo.type.sdpEndPoint, SdpEndPointType::type::WEBRTC_END_POINT);

  client->createUriEndPoint (mo, mediaPipeline, UriEndPointType::type::PLAYER_END_POINT, "");
  BOOST_CHECK (mo.type.__isset.uriEndPoint);
  BOOST_CHECK_EQUAL (mo.type.uriEndPoint, UriEndPointType::type::PLAYER_END_POINT);

  client->createUriEndPoint (mo, mediaPipeline, UriEndPointType::type::RECORDER_END_POINT, "");
  BOOST_CHECK (mo.type.__isset.uriEndPoint);
  BOOST_CHECK_EQUAL (mo.type.uriEndPoint, UriEndPointType::type::RECORDER_END_POINT);

  client->createHttpEndPoint (mo, mediaPipeline);
  BOOST_CHECK (mo.type.__isset.endPoint);
  BOOST_CHECK_EQUAL (mo.type.endPoint, EndPointType::type::HTTP_END_POINT);

  client->createMixer (mo, mediaPipeline, MixerType::type::MAIN_MIXER);
  BOOST_CHECK (mo.type.__isset.mixerType);
  BOOST_CHECK_EQUAL (mo.type.mixerType, MixerType::type::MAIN_MIXER);

  client->release (mediaPipeline);
}
#endif

static void
check_use_released_media_pipeline (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef mo = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString ("file:///tmp/f.webm") );

  client->createMediaPipeline (mediaPipeline);
  client->release (mediaPipeline);

  try {
    client->createMediaElementWithParams (mo, mediaPipeline, g_KmsMediaPlayerEndPointType_constants.TYPE_NAME, params);
    BOOST_FAIL ("Use a released MediaPipeline must throw a KmsMediaServerException");
  } catch (const KmsMediaServerException &e) {
    BOOST_CHECK_EQUAL (g_KmsMediaErrorCodes_constants.MEDIA_OBJECT_NOT_FOUND, e.errorCode);
  }
}

static void
check_auto_released_media_pipeline (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();

  client->createMediaPipeline (mediaPipeline);
  g_usleep ( (2 * AUTO_RELEASE_INTERVAL + 1) * G_USEC_PER_SEC);

  try {
    client->keepAlive (mediaPipeline);
    BOOST_FAIL ("Use an auto released MediaPipeline must throw a KmsMediaServerException");
  } catch (const KmsMediaServerException &e) {
    BOOST_CHECK_EQUAL (g_KmsMediaErrorCodes_constants.MEDIA_OBJECT_NOT_FOUND, e.errorCode);
  }
}

static void
check_keep_alive_media_pipeline (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  int i;
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();

  client->createMediaPipeline (mediaPipeline);

  for (i = 0; i < 5; i++) {
    g_usleep (AUTO_RELEASE_INTERVAL * G_USEC_PER_SEC);
    client->keepAlive (mediaPipeline);
  }

  client->release (mediaPipeline);
}

static void
check_parent (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef mo = KmsMediaObjectRef();
  KmsMediaObjectRef parent = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString ("file:///tmp/f.webm") );

  client->createMediaPipeline (mediaPipeline);
  client->createMediaElementWithParams (mo, mediaPipeline, g_KmsMediaPlayerEndPointType_constants.TYPE_NAME, params);
  client->getParent (parent, mo);
  BOOST_CHECK_EQUAL (mediaPipeline.id, parent.id);

  client->release (mediaPipeline);
}

static void
check_get_parent_of_media_pipeline (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef parent = KmsMediaObjectRef();

  client->createMediaPipeline (mediaPipeline);

  try {
    client->getParent (parent, mediaPipeline);
    BOOST_FAIL ("Get parent of a MediaPipeline must throw a KmsMediaServerException");
  } catch (const KmsMediaServerException &e) {
    BOOST_CHECK_EQUAL (g_KmsMediaErrorCodes_constants.MEDIA_OBJECT_HAS_NOT_PARENT, e.errorCode);
  }

  client->release (mediaPipeline);
}

static void
check_getMediaPipeline (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef mo = KmsMediaObjectRef();
  KmsMediaObjectRef mediaPipelineGot = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString ("file:///tmp/f.webm") );

  client->createMediaPipeline (mediaPipeline);
  client->getMediaPipeline (mediaPipelineGot, mediaPipeline);
  BOOST_CHECK_EQUAL (mediaPipeline.id, mediaPipelineGot.id);

  client->createMediaElementWithParams (mo, mediaPipeline, g_KmsMediaPlayerEndPointType_constants.TYPE_NAME, params);
  client->getMediaPipeline (mediaPipelineGot, mo);
  BOOST_CHECK_EQUAL (mediaPipeline.id, mediaPipelineGot.id);

  client->release (mediaPipeline);
}

static void
check_same_token (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef mo = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString ("file:///tmp/f.webm") );

  client->createMediaPipeline (mediaPipeline);
  client->createMediaElementWithParams (mo, mediaPipeline, g_KmsMediaPlayerEndPointType_constants.TYPE_NAME, params);
  BOOST_CHECK_EQUAL (mediaPipeline.token, mo.token);

  client->release (mediaPipeline);
}

static void
check_get_media_element_from_pad (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef playerEndPoint = KmsMediaObjectRef();
  KmsMediaObjectRef me = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();
  std::vector<KmsMediaObjectRef> pads;
  std::vector<KmsMediaObjectRef>::iterator it;

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString ("file:///tmp/a.webm") );

  client->createMediaPipeline (mediaPipeline);
  client->createMediaElementWithParams (playerEndPoint, mediaPipeline, g_KmsMediaPlayerEndPointType_constants.TYPE_NAME, params);

  client->getMediaSrcs (pads, playerEndPoint);

  for (it = pads.begin(); it != pads.end(); ++it) {
    client->getMediaElement (me, *it);
    BOOST_CHECK_EQUAL (playerEndPoint.id, me.id);
  }

  client->getMediaSinks (pads, playerEndPoint);

  for (it = pads.begin(); it != pads.end(); ++it) {
    client->getMediaElement (me, *it);
    BOOST_CHECK_EQUAL (playerEndPoint.id, me.id);
  }

  client->release (mediaPipeline);
}

static void
check_player_end_point (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef playerEndPoint = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();
  KmsMediaCommand command;
  KmsMediaCommandResult result;
  std::string originalUri = "file:///tmp/player_end_point_test.webm";
  std::string resultUri;
  std::string callbackToken;

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString (originalUri) );

  client->createMediaPipeline (mediaPipeline);
  client->createMediaElementWithParams (playerEndPoint, mediaPipeline, g_KmsMediaPlayerEndPointType_constants.TYPE_NAME, params);

  command = * createVoidCommand (g_KmsMediaUriEndPointType_constants.GET_URI);
  client->sendCommand (result, playerEndPoint, command);

  BOOST_REQUIRE_NO_THROW (resultUri = unmarshalStringCommandResult (result) );
  BOOST_CHECK_EQUAL (0, originalUri.compare (resultUri) );

  client->subscribe (callbackToken, playerEndPoint, g_KmsMediaPlayerEndPointType_constants.EVENT_EOS, "", 0);
  GST_DEBUG ("callbackToken: %s", callbackToken.c_str () );
  client->unsubscribe (playerEndPoint, callbackToken);

  try {
    client->subscribe (callbackToken, playerEndPoint, "BAD_EVENT_TYPE", "", 0);
    BOOST_FAIL ("Subscribe for an event not supported by PlayerEndPoint must throw a KmsMediaServerException");
  } catch (const KmsMediaServerException &e) {
    BOOST_CHECK_EQUAL (g_KmsMediaErrorCodes_constants.MEDIA_OBJECT_EVENT_NOT_SUPPORTED, e.errorCode);
  }

  client->release (mediaPipeline);
}

static void
check_recorder_end_point (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef recorderEndPoint = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();
  KmsMediaCommand command;
  KmsMediaCommandResult result;
  std::string originalUri = "file:///tmp/player_end_point_test.webm";
  std::string resultUri;

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString (originalUri) );

  client->createMediaPipeline (mediaPipeline);
  client->createMediaElementWithParams (recorderEndPoint, mediaPipeline, g_KmsMediaRecorderEndPointType_constants.TYPE_NAME, params);

  command = * createVoidCommand (g_KmsMediaUriEndPointType_constants.GET_URI);
  client->sendCommand (result, recorderEndPoint, command);

  BOOST_REQUIRE_NO_THROW (resultUri = unmarshalStringCommandResult (result) );;
  BOOST_CHECK_EQUAL (0, originalUri.compare (resultUri) );

  client->release (mediaPipeline);
}

#if 0 /* Temporally disabled */
static void
check_http_end_point (boost::shared_ptr<kurento::MediaServerServiceClient> client)
{
  MediaObjectId mediaPipeline = MediaObjectId();
  MediaObjectId httpEp = MediaObjectId();
  std::string out;

  client->createMediaPipeline (mediaPipeline, 0);

  client->createHttpEndPoint (httpEp, mediaPipeline);
  client->getUrl (out, httpEp);

  client->release (mediaPipeline);
}
#endif

static void
check_zbar_filter (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef zbarFilter = KmsMediaObjectRef();

  client->createMediaPipeline (mediaPipeline);
  client->createMediaElement (zbarFilter, mediaPipeline, g_KmsMediaZBarFilterType_constants.TYPE_NAME);
  client->release (mediaPipeline);
}

static void
client_side (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  check_version (client);
  check_use_released_media_pipeline (client);
  check_auto_released_media_pipeline (client);
  check_keep_alive_media_pipeline (client);
  check_parent (client);
  check_get_parent_of_media_pipeline (client);
  check_getMediaPipeline (client);
  check_same_token (client);
  check_get_media_element_from_pad (client);

#if 0 /* Temporally disabled */
  check_type (client);
#endif

  check_player_end_point (client);
  check_recorder_end_point (client);

#if 0 /* Temporally disabled */
  check_http_end_point (client);
#endif

  check_zbar_filter (client);
}

BOOST_AUTO_TEST_CASE ( server_test )
{
  BOOST_REQUIRE_MESSAGE (initialized, "Cannot connect to the server");
  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0, GST_DEFAULT_NAME);
  client_side (client);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Enable test for HttpEndPoint<commit_after>/*
 * (C) Copyright 2013 Kurento (http://kurento.org/)
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 *
 * 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.
 *
 */

#include "server_test_base.hpp"
#include <boost/test/unit_test.hpp>

#include "KmsMediaServer_constants.h"
#include "KmsMediaDataType_constants.h"
#include "KmsMediaErrorCodes_constants.h"

#include "KmsMediaUriEndPointType_constants.h"
#include "KmsMediaPlayerEndPointType_constants.h"
#include "KmsMediaRecorderEndPointType_constants.h"
#include "KmsMediaZBarFilterType_constants.h"
#include "KmsMediaHttpEndPointType_constants.h"

#include "utils/marshalling.hpp"

#include <gst/gst.h>

#include "common/MediaSet.hpp"

#define GST_CAT_DEFAULT _server_test_
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define GST_DEFAULT_NAME "server_test"

using namespace kurento;

BOOST_FIXTURE_TEST_SUITE ( server_test_suite,  F)

static void
check_version (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  int32_t gotVersion;

  gotVersion = client->getVersion();
  BOOST_CHECK_EQUAL (gotVersion, g_KmsMediaServer_constants.VERSION);
}

#if 0 /* Temporally disabled */
static void
check_type (boost::shared_ptr<kurento::MediaServerServiceClient> client)
{
  MediaObjectId mediaPipeline = MediaObjectId();
  MediaObjectId mo = MediaObjectId();

  client->createMediaPipeline (mediaPipeline, 0);
  BOOST_CHECK (mediaPipeline.type.__isset.mediaObject);
  BOOST_CHECK_EQUAL (mediaPipeline.type.mediaObject, MediaObjectType::type::MEDIA_PIPELINE);

  client->createSdpEndPoint (mo, mediaPipeline, SdpEndPointType::type::RTP_END_POINT);
  BOOST_CHECK (mo.type.__isset.sdpEndPoint);
  BOOST_CHECK_EQUAL (mo.type.sdpEndPoint, SdpEndPointType::type::RTP_END_POINT);

  client->createSdpEndPoint (mo, mediaPipeline, SdpEndPointType::type::WEBRTC_END_POINT);
  BOOST_CHECK (mo.type.__isset.sdpEndPoint);
  BOOST_CHECK_EQUAL (mo.type.sdpEndPoint, SdpEndPointType::type::WEBRTC_END_POINT);

  client->createUriEndPoint (mo, mediaPipeline, UriEndPointType::type::PLAYER_END_POINT, "");
  BOOST_CHECK (mo.type.__isset.uriEndPoint);
  BOOST_CHECK_EQUAL (mo.type.uriEndPoint, UriEndPointType::type::PLAYER_END_POINT);

  client->createUriEndPoint (mo, mediaPipeline, UriEndPointType::type::RECORDER_END_POINT, "");
  BOOST_CHECK (mo.type.__isset.uriEndPoint);
  BOOST_CHECK_EQUAL (mo.type.uriEndPoint, UriEndPointType::type::RECORDER_END_POINT);

  client->createHttpEndPoint (mo, mediaPipeline);
  BOOST_CHECK (mo.type.__isset.endPoint);
  BOOST_CHECK_EQUAL (mo.type.endPoint, EndPointType::type::HTTP_END_POINT);

  client->createMixer (mo, mediaPipeline, MixerType::type::MAIN_MIXER);
  BOOST_CHECK (mo.type.__isset.mixerType);
  BOOST_CHECK_EQUAL (mo.type.mixerType, MixerType::type::MAIN_MIXER);

  client->release (mediaPipeline);
}
#endif

static void
check_use_released_media_pipeline (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef mo = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString ("file:///tmp/f.webm") );

  client->createMediaPipeline (mediaPipeline);
  client->release (mediaPipeline);

  try {
    client->createMediaElementWithParams (mo, mediaPipeline, g_KmsMediaPlayerEndPointType_constants.TYPE_NAME, params);
    BOOST_FAIL ("Use a released MediaPipeline must throw a KmsMediaServerException");
  } catch (const KmsMediaServerException &e) {
    BOOST_CHECK_EQUAL (g_KmsMediaErrorCodes_constants.MEDIA_OBJECT_NOT_FOUND, e.errorCode);
  }
}

static void
check_auto_released_media_pipeline (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();

  client->createMediaPipeline (mediaPipeline);
  g_usleep ( (2 * AUTO_RELEASE_INTERVAL + 1) * G_USEC_PER_SEC);

  try {
    client->keepAlive (mediaPipeline);
    BOOST_FAIL ("Use an auto released MediaPipeline must throw a KmsMediaServerException");
  } catch (const KmsMediaServerException &e) {
    BOOST_CHECK_EQUAL (g_KmsMediaErrorCodes_constants.MEDIA_OBJECT_NOT_FOUND, e.errorCode);
  }
}

static void
check_keep_alive_media_pipeline (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  int i;
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();

  client->createMediaPipeline (mediaPipeline);

  for (i = 0; i < 5; i++) {
    g_usleep (AUTO_RELEASE_INTERVAL * G_USEC_PER_SEC);
    client->keepAlive (mediaPipeline);
  }

  client->release (mediaPipeline);
}

static void
check_parent (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef mo = KmsMediaObjectRef();
  KmsMediaObjectRef parent = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString ("file:///tmp/f.webm") );

  client->createMediaPipeline (mediaPipeline);
  client->createMediaElementWithParams (mo, mediaPipeline, g_KmsMediaPlayerEndPointType_constants.TYPE_NAME, params);
  client->getParent (parent, mo);
  BOOST_CHECK_EQUAL (mediaPipeline.id, parent.id);

  client->release (mediaPipeline);
}

static void
check_get_parent_of_media_pipeline (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef parent = KmsMediaObjectRef();

  client->createMediaPipeline (mediaPipeline);

  try {
    client->getParent (parent, mediaPipeline);
    BOOST_FAIL ("Get parent of a MediaPipeline must throw a KmsMediaServerException");
  } catch (const KmsMediaServerException &e) {
    BOOST_CHECK_EQUAL (g_KmsMediaErrorCodes_constants.MEDIA_OBJECT_HAS_NOT_PARENT, e.errorCode);
  }

  client->release (mediaPipeline);
}

static void
check_getMediaPipeline (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef mo = KmsMediaObjectRef();
  KmsMediaObjectRef mediaPipelineGot = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString ("file:///tmp/f.webm") );

  client->createMediaPipeline (mediaPipeline);
  client->getMediaPipeline (mediaPipelineGot, mediaPipeline);
  BOOST_CHECK_EQUAL (mediaPipeline.id, mediaPipelineGot.id);

  client->createMediaElementWithParams (mo, mediaPipeline, g_KmsMediaPlayerEndPointType_constants.TYPE_NAME, params);
  client->getMediaPipeline (mediaPipelineGot, mo);
  BOOST_CHECK_EQUAL (mediaPipeline.id, mediaPipelineGot.id);

  client->release (mediaPipeline);
}

static void
check_same_token (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef mo = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString ("file:///tmp/f.webm") );

  client->createMediaPipeline (mediaPipeline);
  client->createMediaElementWithParams (mo, mediaPipeline, g_KmsMediaPlayerEndPointType_constants.TYPE_NAME, params);
  BOOST_CHECK_EQUAL (mediaPipeline.token, mo.token);

  client->release (mediaPipeline);
}

static void
check_get_media_element_from_pad (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef playerEndPoint = KmsMediaObjectRef();
  KmsMediaObjectRef me = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();
  std::vector<KmsMediaObjectRef> pads;
  std::vector<KmsMediaObjectRef>::iterator it;

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString ("file:///tmp/a.webm") );

  client->createMediaPipeline (mediaPipeline);
  client->createMediaElementWithParams (playerEndPoint, mediaPipeline, g_KmsMediaPlayerEndPointType_constants.TYPE_NAME, params);

  client->getMediaSrcs (pads, playerEndPoint);

  for (it = pads.begin(); it != pads.end(); ++it) {
    client->getMediaElement (me, *it);
    BOOST_CHECK_EQUAL (playerEndPoint.id, me.id);
  }

  client->getMediaSinks (pads, playerEndPoint);

  for (it = pads.begin(); it != pads.end(); ++it) {
    client->getMediaElement (me, *it);
    BOOST_CHECK_EQUAL (playerEndPoint.id, me.id);
  }

  client->release (mediaPipeline);
}

static void
check_player_end_point (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef playerEndPoint = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();
  KmsMediaCommand command;
  KmsMediaCommandResult result;
  std::string originalUri = "file:///tmp/player_end_point_test.webm";
  std::string resultUri;
  std::string callbackToken;

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString (originalUri) );

  client->createMediaPipeline (mediaPipeline);
  client->createMediaElementWithParams (playerEndPoint, mediaPipeline, g_KmsMediaPlayerEndPointType_constants.TYPE_NAME, params);

  command = * createVoidCommand (g_KmsMediaUriEndPointType_constants.GET_URI);
  client->sendCommand (result, playerEndPoint, command);

  BOOST_REQUIRE_NO_THROW (resultUri = unmarshalStringCommandResult (result) );
  BOOST_CHECK_EQUAL (0, originalUri.compare (resultUri) );

  client->subscribe (callbackToken, playerEndPoint, g_KmsMediaPlayerEndPointType_constants.EVENT_EOS, "", 0);
  GST_DEBUG ("callbackToken: %s", callbackToken.c_str () );
  client->unsubscribe (playerEndPoint, callbackToken);

  try {
    client->subscribe (callbackToken, playerEndPoint, "BAD_EVENT_TYPE", "", 0);
    BOOST_FAIL ("Subscribe for an event not supported by PlayerEndPoint must throw a KmsMediaServerException");
  } catch (const KmsMediaServerException &e) {
    BOOST_CHECK_EQUAL (g_KmsMediaErrorCodes_constants.MEDIA_OBJECT_EVENT_NOT_SUPPORTED, e.errorCode);
  }

  client->release (mediaPipeline);
}

static void
check_recorder_end_point (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef recorderEndPoint = KmsMediaObjectRef();
  KmsMediaParams params = KmsMediaParams ();
  KmsMediaCommand command;
  KmsMediaCommandResult result;
  std::string originalUri = "file:///tmp/player_end_point_test.webm";
  std::string resultUri;

  params.__set_dataType (g_KmsMediaDataType_constants.STRING_DATA_TYPE);
  params.__set_data (marshalString (originalUri) );

  client->createMediaPipeline (mediaPipeline);
  client->createMediaElementWithParams (recorderEndPoint, mediaPipeline, g_KmsMediaRecorderEndPointType_constants.TYPE_NAME, params);

  command = * createVoidCommand (g_KmsMediaUriEndPointType_constants.GET_URI);
  client->sendCommand (result, recorderEndPoint, command);

  BOOST_REQUIRE_NO_THROW (resultUri = unmarshalStringCommandResult (result) );;
  BOOST_CHECK_EQUAL (0, originalUri.compare (resultUri) );

  client->release (mediaPipeline);
}

static void
check_http_end_point (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef httpEp = KmsMediaObjectRef();
  KmsMediaCommand command;
  KmsMediaCommandResult result;
  std::string resultUrl;

  client->createMediaPipeline (mediaPipeline);
  client->createMediaElement (httpEp, mediaPipeline, g_KmsMediaHttpEndPointType_constants.TYPE_NAME);

  command = * createVoidCommand (g_KmsMediaHttpEndPointType_constants.GET_URL);
  client->sendCommand (result, httpEp, command);

  GST_INFO ("HttpEndPoint URL: %s", unmarshalString (result.data).c_str () );

  client->release (mediaPipeline);
}

static void
check_zbar_filter (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  KmsMediaObjectRef mediaPipeline = KmsMediaObjectRef();
  KmsMediaObjectRef zbarFilter = KmsMediaObjectRef();

  client->createMediaPipeline (mediaPipeline);
  client->createMediaElement (zbarFilter, mediaPipeline, g_KmsMediaZBarFilterType_constants.TYPE_NAME);
  client->release (mediaPipeline);
}

static void
client_side (boost::shared_ptr<kurento::KmsMediaServerServiceClient> client)
{
  check_version (client);
  check_use_released_media_pipeline (client);
  check_auto_released_media_pipeline (client);
  check_keep_alive_media_pipeline (client);
  check_parent (client);
  check_get_parent_of_media_pipeline (client);
  check_getMediaPipeline (client);
  check_same_token (client);
  check_get_media_element_from_pad (client);

#if 0 /* Temporally disabled */
  check_type (client);
#endif

  check_player_end_point (client);
  check_recorder_end_point (client);
  check_http_end_point (client);
  check_zbar_filter (client);
}

BOOST_AUTO_TEST_CASE ( server_test )
{
  BOOST_REQUIRE_MESSAGE (initialized, "Cannot connect to the server");
  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0, GST_DEFAULT_NAME);
  client_side (client);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include "photon_blocks.h"
#include "photon_level.h"
#include "photon_laser.h"
#include "photon_core.h"
#include <glm/gtx/norm.hpp>

namespace photon{

namespace blocks{

photon_lasersegment *OnLightInteract(photon_lasersegment *segment, glm::uvec2 location, photon_level &level, float time){
    photon_level_coord coord(location.x, location.y);
    if(level.grid.count(coord)){
        photon_block &block = level.grid[coord];
        block.activated = true;

        switch(block.type){
        case air:
        default:
            break;
        case reciever:
            block.power++;
            // stops tracing the laser.
            return nullptr;
            break;
        case reciever_red:
            if(segment->color.r > 0.8f){
                block.power++;
            }
            // stops tracing the laser.
            return nullptr;
            break;
        case reciever_green:
            if(segment->color.g > 0.8f){
                block.power++;
            }
            // stops tracing the laser.
            return nullptr;
            break;
        case reciever_blue:
            if(segment->color.b > 0.8f){
                block.power++;
            }
            // stops tracing the laser.
            return nullptr;
            break;
        case reciever_white:
            if(segment->color.r > 0.8f && segment->color.g > 0.8f && segment->color.b > 0.8f){
                block.power++;
            }
            // stops tracing the laser.
            return nullptr;
            break;
        case emitter_white:
        case emitter_red:
        case emitter_green:
        case emitter_blue:
        case plain:
        case indestructible:
            // stops tracing the laser.
            return nullptr;
            break;
        case mirror:
        case mirror_locked:{
            float angle = segment->angle - block.angle;
            if(fmod(angle, 180.0f) == 0.0f){
                return nullptr;
            }
            angle = fmod(angle + 180.0f, 360.0f) - 180.0f;
            segment = tracer::CreateChildBeam(segment);
            segment->angle = block.angle - angle;
            break;
        }
        case tnt:
            block.power += time;
            // stops tracing the laser.
            return nullptr;
            break;
        case filter_red:{
            glm::vec3 color = segment->color;
            color.g = glm::min(color.g, 0.2f);
            color.b = glm::min(color.b, 0.1f);
            if(glm::length2(color) > 0.2f){
                segment = tracer::CreateChildBeam(segment);
                segment->color = color;
            }else{
                // stops tracing the laser.
                return nullptr;
            }
            break;
        }
        case filter_green:{
            glm::vec3 color = segment->color;
            color.r = glm::min(color.r, 0.1f);
            color.b = glm::min(color.b, 0.1f);
            if(glm::length2(color) > 0.2f){
                segment = tracer::CreateChildBeam(segment);
                segment->color = color;
            }else{
                // stops tracing the laser.
                return nullptr;
            }
            break;
        }
        case filter_blue:{
            glm::vec3 color = segment->color;
            color.r = glm::min(color.r, 0.1f);
            color.g = glm::min(color.g, 0.2f);
            if(glm::length2(color) > 0.2f){
                segment = tracer::CreateChildBeam(segment);
                segment->color = color;
            }else{
                // stops tracing the laser.
                return nullptr;
            }
            break;
        }
        case filter_yellow:{
            glm::vec3 color = segment->color;
            color.b = glm::min(color.b, 0.1f);
            if(glm::length2(color) > 0.2f){
                segment = tracer::CreateChildBeam(segment);
                segment->color = color;
            }else{
                // stops tracing the laser.
                return nullptr;
            }
            break;
        }
        case filter_cyan:{
            glm::vec3 color = segment->color;
            color.r = glm::min(color.r, 0.1f);
            if(glm::length2(color) > 0.2f){
                segment = tracer::CreateChildBeam(segment);
                segment->color = color;
            }else{
                // stops tracing the laser.
                return nullptr;
            }
            break;
        }
        case filter_magenta:{
            glm::vec3 color = segment->color;
            color.g = glm::min(color.g, 0.2f);
            if(glm::length2(color) > 0.2f){
                segment = tracer::CreateChildBeam(segment);
                segment->color = color;
            }else{
                // stops tracing the laser.
                return nullptr;
            }
            break;
        }
        }
    }
    return segment;
}

void OnPhotonInteract(glm::uvec2 location, photon_level &level, photon_player &player){
    photon_level_coord coord(location.x, location.y);
    photon_block &block = level.grid[coord];
    switch(block.type){
    case air:
        if(player.current_item != invalid_block){
            block.type = player.current_item;
            player::AddItemCurrent(player, -1);
            level.moves++;
        }
        break;
    default:
        break;
    case tnt:
    case filter_red:
    case filter_green:
    case filter_blue:
    case filter_yellow:
    case filter_cyan:
    case filter_magenta:
    case mirror:
        if(!block.locked){
            player::AddItem(player, block.type);
            level.grid.erase(coord);
            level.moves++;
        }
        break;
    case reciever:
    case reciever_red:
    case reciever_green:
    case reciever_blue:
    case reciever_white:
        if(level::CheckVictory(level, player) > 0){
            // TODO - show victory screen.
            PrintToLog("INFO: VICTORY!");
            level = photon_level();
        }
        // TODO - show some indication of incompleteness.
        break;
    }
    // if for some reason nothing happened to this block after it was added...
    if(block.type == air){
        level.grid.erase(coord);
    }
}

void OnRotate(glm::uvec2 location, photon_level &level, bool counter_clockwise){
    photon_level_coord coord(location.x, location.y);
    if(level.grid.count(coord)){
        photon_block &block = level.grid[coord];
        switch(block.type){
        default:
            break;
        case mirror:
            if(counter_clockwise){
                block.angle += 22.5f;
            }else{
                block.angle -= 22.5f;
            }
            level.moves++;
            break;
        }
    }
}

void OnFrame(glm::uvec2 location, photon_level &level, float time){
    photon_level_coord coord(location.x, location.y);
    if(level.grid.count(coord)){
        photon_block &block = level.grid[coord];
        switch(block.type){
        default:
            break;
        case tnt:
            // if block is triggered, explode.
            if(block.power > 1.0f){
                DamageAroundPoint(location, level, 4.0f);
                // TODO - KABOOM goes here...
                PrintToLog("INFO: KABOOM!");
                block.type = tnt_fireball;
                // cooldown of fireball
                block.power = 1.0f;
                break;
            }
            // if block was not activated last frame cool down timer.
            if(!block.activated){
                block.power -= time;
                block.power = std::max(block.power, 0.0f);
            }
            break;
        case tnt_fireball:
            block.power -= time * 3.0f;
            if(block.power < 0.0f){
                level.grid.erase(coord);
            }
            break;
        case emitter_white:{
            level.beams.push_back(photon_laserbeam());
            photon_laserbeam &beam = level.beams.back();
            beam.color = glm::vec3(0.9f,0.9f,0.9f);
            beam.origin = location;
            beam.origin_angle = block.angle;
            break;
        }
        case emitter_red:{
            level.beams.push_back(photon_laserbeam());
            photon_laserbeam &beam = level.beams.back();
            beam.color = glm::vec3(0.9f,0.2f,0.1f);
            beam.origin = location;
            beam.origin_angle = block.angle;
            break;
        }
        case emitter_green:{
            level.beams.push_back(photon_laserbeam());
            photon_laserbeam &beam = level.beams.back();
            beam.color = glm::vec3(0.1f,0.9f,0.2f);
            beam.origin = location;
            beam.origin_angle = block.angle;
            break;
        }
        case emitter_blue:{
            level.beams.push_back(photon_laserbeam());
            photon_laserbeam &beam = level.beams.back();
            beam.color = glm::vec3(0.1f,0.2f,0.9f);
            beam.origin = location;
            beam.origin_angle = block.angle;
            break;
        }
        case reciever:
        case reciever_red:
        case reciever_green:
        case reciever_blue:
        case reciever_white:
            block.power = 0.0f;
            break;
        }
        block.activated = false;
    }
}

void OnDamage(glm::uvec2 location, photon_level &level, float damage){
    photon_level_coord coord(location.x, location.y);
    if(level.grid.count(coord)){
        photon_block &block = level.grid[coord];
        switch(block.type){
        default:
            break;
        case plain:
            if(damage > 0.5f){
                level.grid.erase(coord);
            }
            break;
        case tnt:
            // will make explosions trigger nearby TNT...
            block.power += damage * 2.0f;
            break;
        }
    }
}

void DamageAroundPoint(glm::uvec2 location, photon_level &level, float strength){
    glm::uvec2 dist(std::ceil(strength));
    glm::uvec2 current = glm::uvec2(glm::max(glm::ivec2(location) - glm::ivec2(dist), glm::ivec2(0)));
    glm::uvec2 end = location + dist;

    unsigned int y = current.y;
    for(;current.x <= end.x;current.x++){
        for(current.y = y;current.y <= end.y;current.y++){
            OnDamage(current, level, std::max(2.0f - (glm::distance2(glm::vec2(current), glm::vec2(location)) / strength), 0.0f));
        }
    }
}
#define CASESTR(X) case X: return #X; break;

const char* GetBlockName(block_type type){
    switch(type){
    default:
        CASESTR(invalid_block);
        CASESTR(air);
        CASESTR(mirror);
        CASESTR(mirror_locked);
        CASESTR(plain);
        CASESTR(indestructible);
        CASESTR(emitter_white);
        CASESTR(emitter_red);
        CASESTR(emitter_green);
        CASESTR(emitter_blue);
        CASESTR(reciever);
        CASESTR(reciever_white);
        CASESTR(reciever_red);
        CASESTR(reciever_green);
        CASESTR(reciever_blue);
        CASESTR(tnt);
        CASESTR(tnt_fireball);
        CASESTR(filter_red);
        CASESTR(filter_green);
        CASESTR(filter_blue);
        CASESTR(filter_yellow);
        CASESTR(filter_cyan);
        CASESTR(filter_magenta);
    }
}
#undef CASESTR
#define CASESTR(X) if(!strcmp(name, #X)){ return X; }

block_type GetBlockFromName(const char* name){
    CASESTR(invalid_block)
    else CASESTR(air)
    else CASESTR(mirror)
    else CASESTR(mirror_locked)
    else CASESTR(plain)
    else CASESTR(indestructible)
    else CASESTR(emitter_white)
    else CASESTR(emitter_red)
    else CASESTR(emitter_green)
    else CASESTR(emitter_blue)
    else CASESTR(reciever)
    else CASESTR(reciever_white)
    else CASESTR(reciever_red)
    else CASESTR(reciever_green)
    else CASESTR(reciever_blue)
    else CASESTR(tnt)
    else CASESTR(tnt_fireball)
    else CASESTR(filter_red)
    else CASESTR(filter_green)
    else CASESTR(filter_blue)
    else CASESTR(filter_yellow)
    else CASESTR(filter_cyan)
    else CASESTR(filter_magenta)
    else{
        return invalid_block;
    }
}

#undef CASESTR

}

}
<commit_msg>added delay in explosion triggering other tnt.<commit_after>#include "photon_blocks.h"
#include "photon_level.h"
#include "photon_laser.h"
#include "photon_core.h"
#include <glm/gtx/norm.hpp>

namespace photon{

namespace blocks{

photon_lasersegment *OnLightInteract(photon_lasersegment *segment, glm::uvec2 location, photon_level &level, float time){
    photon_level_coord coord(location.x, location.y);
    if(level.grid.count(coord)){
        photon_block &block = level.grid[coord];
        block.activated = true;

        switch(block.type){
        case air:
        default:
            break;
        case reciever:
            block.power++;
            // stops tracing the laser.
            return nullptr;
            break;
        case reciever_red:
            if(segment->color.r > 0.8f){
                block.power++;
            }
            // stops tracing the laser.
            return nullptr;
            break;
        case reciever_green:
            if(segment->color.g > 0.8f){
                block.power++;
            }
            // stops tracing the laser.
            return nullptr;
            break;
        case reciever_blue:
            if(segment->color.b > 0.8f){
                block.power++;
            }
            // stops tracing the laser.
            return nullptr;
            break;
        case reciever_white:
            if(segment->color.r > 0.8f && segment->color.g > 0.8f && segment->color.b > 0.8f){
                block.power++;
            }
            // stops tracing the laser.
            return nullptr;
            break;
        case emitter_white:
        case emitter_red:
        case emitter_green:
        case emitter_blue:
        case plain:
        case indestructible:
            // stops tracing the laser.
            return nullptr;
            break;
        case mirror:
        case mirror_locked:{
            float angle = segment->angle - block.angle;
            if(fmod(angle, 180.0f) == 0.0f){
                return nullptr;
            }
            angle = fmod(angle + 180.0f, 360.0f) - 180.0f;
            segment = tracer::CreateChildBeam(segment);
            segment->angle = block.angle - angle;
            break;
        }
        case tnt:
            block.power += time;
            // stops tracing the laser.
            return nullptr;
            break;
        case filter_red:{
            glm::vec3 color = segment->color;
            color.g = glm::min(color.g, 0.2f);
            color.b = glm::min(color.b, 0.1f);
            if(glm::length2(color) > 0.2f){
                segment = tracer::CreateChildBeam(segment);
                segment->color = color;
            }else{
                // stops tracing the laser.
                return nullptr;
            }
            break;
        }
        case filter_green:{
            glm::vec3 color = segment->color;
            color.r = glm::min(color.r, 0.1f);
            color.b = glm::min(color.b, 0.1f);
            if(glm::length2(color) > 0.2f){
                segment = tracer::CreateChildBeam(segment);
                segment->color = color;
            }else{
                // stops tracing the laser.
                return nullptr;
            }
            break;
        }
        case filter_blue:{
            glm::vec3 color = segment->color;
            color.r = glm::min(color.r, 0.1f);
            color.g = glm::min(color.g, 0.2f);
            if(glm::length2(color) > 0.2f){
                segment = tracer::CreateChildBeam(segment);
                segment->color = color;
            }else{
                // stops tracing the laser.
                return nullptr;
            }
            break;
        }
        case filter_yellow:{
            glm::vec3 color = segment->color;
            color.b = glm::min(color.b, 0.1f);
            if(glm::length2(color) > 0.2f){
                segment = tracer::CreateChildBeam(segment);
                segment->color = color;
            }else{
                // stops tracing the laser.
                return nullptr;
            }
            break;
        }
        case filter_cyan:{
            glm::vec3 color = segment->color;
            color.r = glm::min(color.r, 0.1f);
            if(glm::length2(color) > 0.2f){
                segment = tracer::CreateChildBeam(segment);
                segment->color = color;
            }else{
                // stops tracing the laser.
                return nullptr;
            }
            break;
        }
        case filter_magenta:{
            glm::vec3 color = segment->color;
            color.g = glm::min(color.g, 0.2f);
            if(glm::length2(color) > 0.2f){
                segment = tracer::CreateChildBeam(segment);
                segment->color = color;
            }else{
                // stops tracing the laser.
                return nullptr;
            }
            break;
        }
        }
    }
    return segment;
}

void OnPhotonInteract(glm::uvec2 location, photon_level &level, photon_player &player){
    photon_level_coord coord(location.x, location.y);
    photon_block &block = level.grid[coord];
    switch(block.type){
    case air:
        if(player.current_item != invalid_block){
            block.type = player.current_item;
            player::AddItemCurrent(player, -1);
            level.moves++;
        }
        break;
    default:
        break;
    case tnt:
    case filter_red:
    case filter_green:
    case filter_blue:
    case filter_yellow:
    case filter_cyan:
    case filter_magenta:
    case mirror:
        if(!block.locked){
            player::AddItem(player, block.type);
            level.grid.erase(coord);
            level.moves++;
        }
        break;
    case reciever:
    case reciever_red:
    case reciever_green:
    case reciever_blue:
    case reciever_white:
        if(level::CheckVictory(level, player) > 0){
            // TODO - show victory screen.
            PrintToLog("INFO: VICTORY!");
            level = photon_level();
        }
        // TODO - show some indication of incompleteness.
        break;
    }
    // if for some reason nothing happened to this block after it was added...
    if(block.type == air){
        level.grid.erase(coord);
    }
}

void OnRotate(glm::uvec2 location, photon_level &level, bool counter_clockwise){
    photon_level_coord coord(location.x, location.y);
    if(level.grid.count(coord)){
        photon_block &block = level.grid[coord];
        switch(block.type){
        default:
            break;
        case mirror:
            if(counter_clockwise){
                block.angle += 22.5f;
            }else{
                block.angle -= 22.5f;
            }
            level.moves++;
            break;
        }
    }
}

void OnFrame(glm::uvec2 location, photon_level &level, float time){
    photon_level_coord coord(location.x, location.y);
    if(level.grid.count(coord)){
        photon_block &block = level.grid[coord];
        switch(block.type){
        default:
            break;
        case tnt:
            // if block is triggered, explode.
            if(block.power > 1.0f){
                DamageAroundPoint(location, level, 4.0f);
                // TODO - KABOOM goes here...
                PrintToLog("INFO: KABOOM!");
                block.type = tnt_fireball;
                // cooldown of fireball
                block.power = 1.0f;
                break;
            }
            // if block was not activated last frame cool down timer.
            if(!block.activated){
                block.power -= time;
                block.power = std::max(block.power, 0.0f);
            }
            break;
        case tnt_fireball:
            block.power -= time * 3.0f;
            if(block.power > 0.4f){
                DamageAroundPoint(location, level, (1.4f - block.power) * time * 1.4e3f);
            }else if(block.power < 0.0f){
                level.grid.erase(coord);
            }
            break;
        case emitter_white:{
            level.beams.push_back(photon_laserbeam());
            photon_laserbeam &beam = level.beams.back();
            beam.color = glm::vec3(0.9f,0.9f,0.9f);
            beam.origin = location;
            beam.origin_angle = block.angle;
            break;
        }
        case emitter_red:{
            level.beams.push_back(photon_laserbeam());
            photon_laserbeam &beam = level.beams.back();
            beam.color = glm::vec3(0.9f,0.2f,0.1f);
            beam.origin = location;
            beam.origin_angle = block.angle;
            break;
        }
        case emitter_green:{
            level.beams.push_back(photon_laserbeam());
            photon_laserbeam &beam = level.beams.back();
            beam.color = glm::vec3(0.1f,0.9f,0.2f);
            beam.origin = location;
            beam.origin_angle = block.angle;
            break;
        }
        case emitter_blue:{
            level.beams.push_back(photon_laserbeam());
            photon_laserbeam &beam = level.beams.back();
            beam.color = glm::vec3(0.1f,0.2f,0.9f);
            beam.origin = location;
            beam.origin_angle = block.angle;
            break;
        }
        case reciever:
        case reciever_red:
        case reciever_green:
        case reciever_blue:
        case reciever_white:
            block.power = 0.0f;
            break;
        }
        block.activated = false;
    }
}

void OnDamage(glm::uvec2 location, photon_level &level, float damage){
    photon_level_coord coord(location.x, location.y);
    if(level.grid.count(coord)){
        photon_block &block = level.grid[coord];
        switch(block.type){
        default:
            break;
        case plain:
            if(damage > 0.5f){
                level.grid.erase(coord);
            }
            break;
        case tnt:
            // will make explosions trigger nearby TNT...
            block.power += damage;
            break;
        }
    }
}

void DamageAroundPoint(glm::uvec2 location, photon_level &level, float strength){
    glm::uvec2 dist(std::ceil(strength));
    glm::uvec2 current = glm::uvec2(glm::max(glm::ivec2(location) - glm::ivec2(dist), glm::ivec2(0)));
    glm::uvec2 end = location + dist;

    unsigned int y = current.y;
    for(;current.x <= end.x;current.x++){
        for(current.y = y;current.y <= end.y;current.y++){
            OnDamage(current, level, std::max(2.0f - (glm::distance2(glm::vec2(current), glm::vec2(location)) / strength), 0.0f));
        }
    }
}
#define CASESTR(X) case X: return #X; break;

const char* GetBlockName(block_type type){
    switch(type){
    default:
        CASESTR(invalid_block);
        CASESTR(air);
        CASESTR(mirror);
        CASESTR(mirror_locked);
        CASESTR(plain);
        CASESTR(indestructible);
        CASESTR(emitter_white);
        CASESTR(emitter_red);
        CASESTR(emitter_green);
        CASESTR(emitter_blue);
        CASESTR(reciever);
        CASESTR(reciever_white);
        CASESTR(reciever_red);
        CASESTR(reciever_green);
        CASESTR(reciever_blue);
        CASESTR(tnt);
        CASESTR(tnt_fireball);
        CASESTR(filter_red);
        CASESTR(filter_green);
        CASESTR(filter_blue);
        CASESTR(filter_yellow);
        CASESTR(filter_cyan);
        CASESTR(filter_magenta);
    }
}
#undef CASESTR
#define CASESTR(X) if(!strcmp(name, #X)){ return X; }

block_type GetBlockFromName(const char* name){
    CASESTR(invalid_block)
    else CASESTR(air)
    else CASESTR(mirror)
    else CASESTR(mirror_locked)
    else CASESTR(plain)
    else CASESTR(indestructible)
    else CASESTR(emitter_white)
    else CASESTR(emitter_red)
    else CASESTR(emitter_green)
    else CASESTR(emitter_blue)
    else CASESTR(reciever)
    else CASESTR(reciever_white)
    else CASESTR(reciever_red)
    else CASESTR(reciever_green)
    else CASESTR(reciever_blue)
    else CASESTR(tnt)
    else CASESTR(tnt_fireball)
    else CASESTR(filter_red)
    else CASESTR(filter_green)
    else CASESTR(filter_blue)
    else CASESTR(filter_yellow)
    else CASESTR(filter_cyan)
    else CASESTR(filter_magenta)
    else{
        return invalid_block;
    }
}

#undef CASESTR

}

}
<|endoftext|>


<commit_before>#include "./camera.h"
#include <Eigen/Geometry>
#include <math.h>

#include <iostream>

Camera::Camera()
  : origin(0.0f, 0.0f, 0.0f), position(0.0f, 0.0f, -1.0f),
    direction(0.0f, 0.0f, 1.0f), up(0.0f, 1.0f, 0.0f), radius(1.0f),
    azimuth(static_cast<float>(-M_PI / 2.0)), declination(0.0f)
{
  projection = createProjection(fieldOfView, aspectRatio, nearPlane, farPlane);
  // projection = createOrthographicProjection(aspectRatio, nearPlane,
  // farPlane);

  update();
}

Camera::Camera(Eigen::Matrix4f viewMatrix, Eigen::Matrix4f projectionMatrix,
               Eigen::Vector3f origin)
  : projection(projectionMatrix), view(viewMatrix), origin(origin)
{
  position = -viewMatrix.inverse().col(3).head<3>();
  direction = viewMatrix.col(2).head<3>();
  up = viewMatrix.col(1).head<3>();

  radius = (position - origin).norm();

  Eigen::Vector3f diff = (position - origin) / radius;
  declination = asin(diff.y());
  azimuth = -acos(diff.x() / cos(declination));
}

Camera::~Camera()
{
}

Eigen::Matrix4f Camera::createProjection(float fov, float aspectRatio,
                                         float nearPlane, float farPlane)
{
  float tanHalfFovy = tan(fov / 2.0f);
  Eigen::Matrix4f result = Eigen::Matrix4f::Zero();
  result(0, 0) = 1.0f / (aspectRatio * tanHalfFovy);
  result(1, 1) = 1.0f / (tanHalfFovy);
  result(2, 2) = -(farPlane + nearPlane) / (farPlane - nearPlane);
  result(3, 2) = -1.0f;
  result(2, 3) = -(2.0f * farPlane * nearPlane) / (farPlane - nearPlane);

  return result;
}

Eigen::Matrix4f Camera::createOrthographicProjection(float aspectRatio,
                                                     float nearPlane,
                                                     float farPlane)
{
  float diff = farPlane - nearPlane;
  Eigen::Matrix4f result = Eigen::Matrix4f::Zero();
  result(0, 0) = 2.0f;
  result(1, 1) = 2.0f * aspectRatio;
  result(2, 2) = 1.0f / diff;
  result(2, 3) = -nearPlane / diff;
  result(3, 3) = 1.0f;

  return result;
}

void Camera::moveForward(float distance)
{
  position += distance * direction;
  update();
}

void Camera::moveBackward(float distance)
{
  position -= distance * direction;
  update();
}

void Camera::strafe(float distance)
{
  auto right = direction.cross(up);
  position += distance * right;
  origin += distance * right;
  update();
}

void Camera::strafeLeft(float distance)
{
  strafe(-distance);
}

void Camera::strafeRight(float distance)
{
  strafe(distance);
}

void Camera::moveVertical(float distance)
{
  position += distance * up;
  origin += distance * up;
  update();
}

void Camera::changeAzimuth(float deltaAngle)
{
  azimuth += deltaAngle;
  update();
}

void Camera::changeDeclination(float deltaAngle)
{
  declination += deltaAngle;
  update();
}

void Camera::changeRadius(float deltaRadius)
{
  radius += deltaRadius;
  position = origin + (position - origin).normalized() * radius;
  update();
}

void Camera::update()
{
  radius = (origin - position).norm();
  position = origin +
             Eigen::Vector3f(cos(azimuth) * cos(declination), sin(declination),
                             sin(azimuth) * cos(declination)) *
                 radius;
  direction = (origin - position).normalized();
  float upDeclination = declination - static_cast<float>(M_PI / 2.0);
  up = -Eigen::Vector3f(cos(azimuth) * cos(upDeclination), sin(upDeclination),
                        sin(azimuth) * cos(upDeclination)).normalized();

  auto n = direction.normalized();
  auto u = up.cross(n).normalized();
  auto v = n.cross(u);
  auto e = position;

  view << u.x(), u.y(), u.z(), u.dot(e), v.x(), v.y(), v.z(), v.dot(e), n.x(),
      n.y(), n.z(), n.dot(e), 0, 0, 0, 1;
}

Eigen::Matrix4f Camera::getViewMatrix() const
{
  return view;
}

Eigen::Matrix4f Camera::getProjectionMatrix() const
{
  return projection;
}

Eigen::Vector3f Camera::getPosition() const
{
  return position;
}

Eigen::Vector3f Camera::getOrigin() const
{
  return -origin;
}

float Camera::getRadius() const
{
  return (position - origin).norm();
}

void Camera::resize(float width, float height)
{
  aspectRatio = width / height;
  projection = createProjection(fieldOfView, aspectRatio, 0.1f, 100.0f);
}

void Camera::updateNearAndFarPlanes(float nearPlane, float farPlane)
{
  this->nearPlane = nearPlane;
  this->farPlane = farPlane;

  projection = createProjection(fieldOfView, aspectRatio, nearPlane, farPlane);
}

float Camera::getNearPlane()
{
  return this->nearPlane;
}

float Camera::getFarPlane()
{
  return this->farPlane;
}

void Camera::setOrigin(Eigen::Vector3f origin)
{
  this->origin = -origin;
  Eigen::Vector3f diff = (position - this->origin).normalized();

  declination = asin(diff.y());
  azimuth = -acos(diff.x() / cos(declination));
  update();
}

bool Camera::needsResizing()
{
  return aspectRatio == 0.0f;
}

<commit_msg>Fix loading of camera origin by inverting it.<commit_after>#include "./camera.h"
#include <Eigen/Geometry>
#include <math.h>

#include <iostream>

Camera::Camera()
  : origin(0.0f, 0.0f, 0.0f), position(0.0f, 0.0f, -1.0f),
    direction(0.0f, 0.0f, 1.0f), up(0.0f, 1.0f, 0.0f), radius(1.0f),
    azimuth(static_cast<float>(-M_PI / 2.0)), declination(0.0f)
{
  projection = createProjection(fieldOfView, aspectRatio, nearPlane, farPlane);
  // projection = createOrthographicProjection(aspectRatio, nearPlane,
  // farPlane);

  update();
}

Camera::Camera(Eigen::Matrix4f viewMatrix, Eigen::Matrix4f projectionMatrix,
               Eigen::Vector3f origin)
  : projection(projectionMatrix), view(viewMatrix), origin(-origin)
{
  position = -viewMatrix.inverse().col(3).head<3>();
  direction = viewMatrix.col(2).head<3>();
  up = viewMatrix.col(1).head<3>();

  radius = (position - origin).norm();

  Eigen::Vector3f diff = (position - origin) / radius;
  declination = asin(diff.y());
  azimuth = -acos(diff.x() / cos(declination));
}

Camera::~Camera()
{
}

Eigen::Matrix4f Camera::createProjection(float fov, float aspectRatio,
                                         float nearPlane, float farPlane)
{
  float tanHalfFovy = tan(fov / 2.0f);
  Eigen::Matrix4f result = Eigen::Matrix4f::Zero();
  result(0, 0) = 1.0f / (aspectRatio * tanHalfFovy);
  result(1, 1) = 1.0f / (tanHalfFovy);
  result(2, 2) = -(farPlane + nearPlane) / (farPlane - nearPlane);
  result(3, 2) = -1.0f;
  result(2, 3) = -(2.0f * farPlane * nearPlane) / (farPlane - nearPlane);

  return result;
}

Eigen::Matrix4f Camera::createOrthographicProjection(float aspectRatio,
                                                     float nearPlane,
                                                     float farPlane)
{
  float diff = farPlane - nearPlane;
  Eigen::Matrix4f result = Eigen::Matrix4f::Zero();
  result(0, 0) = 2.0f;
  result(1, 1) = 2.0f * aspectRatio;
  result(2, 2) = 1.0f / diff;
  result(2, 3) = -nearPlane / diff;
  result(3, 3) = 1.0f;

  return result;
}

void Camera::moveForward(float distance)
{
  position += distance * direction;
  update();
}

void Camera::moveBackward(float distance)
{
  position -= distance * direction;
  update();
}

void Camera::strafe(float distance)
{
  auto right = direction.cross(up);
  position += distance * right;
  origin += distance * right;
  update();
}

void Camera::strafeLeft(float distance)
{
  strafe(-distance);
}

void Camera::strafeRight(float distance)
{
  strafe(distance);
}

void Camera::moveVertical(float distance)
{
  position += distance * up;
  origin += distance * up;
  update();
}

void Camera::changeAzimuth(float deltaAngle)
{
  azimuth += deltaAngle;
  update();
}

void Camera::changeDeclination(float deltaAngle)
{
  declination += deltaAngle;
  update();
}

void Camera::changeRadius(float deltaRadius)
{
  radius += deltaRadius;
  position = origin + (position - origin).normalized() * radius;
  update();
}

void Camera::update()
{
  radius = (origin - position).norm();
  position = origin +
             Eigen::Vector3f(cos(azimuth) * cos(declination), sin(declination),
                             sin(azimuth) * cos(declination)) *
                 radius;
  direction = (origin - position).normalized();
  float upDeclination = declination - static_cast<float>(M_PI / 2.0);
  up = -Eigen::Vector3f(cos(azimuth) * cos(upDeclination), sin(upDeclination),
                        sin(azimuth) * cos(upDeclination)).normalized();

  auto n = direction.normalized();
  auto u = up.cross(n).normalized();
  auto v = n.cross(u);
  auto e = position;

  view << u.x(), u.y(), u.z(), u.dot(e), v.x(), v.y(), v.z(), v.dot(e), n.x(),
      n.y(), n.z(), n.dot(e), 0, 0, 0, 1;
}

Eigen::Matrix4f Camera::getViewMatrix() const
{
  return view;
}

Eigen::Matrix4f Camera::getProjectionMatrix() const
{
  return projection;
}

Eigen::Vector3f Camera::getPosition() const
{
  return position;
}

Eigen::Vector3f Camera::getOrigin() const
{
  return -origin;
}

float Camera::getRadius() const
{
  return (position - origin).norm();
}

void Camera::resize(float width, float height)
{
  aspectRatio = width / height;
  projection = createProjection(fieldOfView, aspectRatio, 0.1f, 100.0f);
}

void Camera::updateNearAndFarPlanes(float nearPlane, float farPlane)
{
  this->nearPlane = nearPlane;
  this->farPlane = farPlane;

  projection = createProjection(fieldOfView, aspectRatio, nearPlane, farPlane);
}

float Camera::getNearPlane()
{
  return this->nearPlane;
}

float Camera::getFarPlane()
{
  return this->farPlane;
}

void Camera::setOrigin(Eigen::Vector3f origin)
{
  this->origin = -origin;
  Eigen::Vector3f diff = (position - this->origin).normalized();

  declination = asin(diff.y());
  azimuth = -acos(diff.x() / cos(declination));
  update();
}

bool Camera::needsResizing()
{
  return aspectRatio == 0.0f;
}

<|endoftext|>