<commit_before>/* This file is part of Ingen.
 * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
 *
 * Ingen is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <cassert>
#include <raul/Atom.hpp>
#include "interface/EngineInterface.hpp"
#include "client/PatchModel.hpp"
#include "client/NodeModel.hpp"
#include "App.hpp"
#include "NodeModule.hpp"
#include "PatchCanvas.hpp"
#include "Port.hpp"
#include "GladeFactory.hpp"
#include "RenameWindow.hpp"
#include "PatchWindow.hpp"
#include "WindowFactory.hpp"
#include "SubpatchModule.hpp"
#include "NodeControlWindow.hpp"

namespace Ingen {
namespace GUI {

NodeModule::NodeModule(boost::shared_ptr<PatchCanvas> canvas, SharedPtr<NodeModel> node)
	: FlowCanvas::Module(canvas, node->path().name())
	, _node(node)
	, _slv2_ui(NULL)
	, _gui(NULL)
	, _gui_item(NULL)
{
	assert(_node);

	node->signal_new_port.connect(sigc::bind(sigc::mem_fun(this, &NodeModule::add_port), true));
	node->signal_removed_port.connect(sigc::mem_fun(this, &NodeModule::remove_port));
	node->signal_metadata.connect(sigc::mem_fun(this, &NodeModule::set_metadata));
	node->signal_polyphonic.connect(sigc::mem_fun(this, &NodeModule::set_stacked_border));
	node->signal_renamed.connect(sigc::mem_fun(this, &NodeModule::rename));

	set_stacked_border(node->polyphonic());
}

NodeModule::~NodeModule()
{
	NodeControlWindow* win = App::instance().window_factory()->control_window(_node);

	if (win) {
		// Should remove from window factory via signal
		delete win;
	}
}

void
NodeModule::create_menu()
{
	Glib::RefPtr<Gnome::Glade::Xml> xml = GladeFactory::new_glade_reference();
	xml->get_widget_derived("object_menu", _menu);
	_menu->init(_node);
	_menu->signal_embed_gui.connect(sigc::mem_fun(this, &NodeModule::embed_gui));

	set_menu(_menu);
}

boost::shared_ptr<NodeModule>
NodeModule::create(boost::shared_ptr<PatchCanvas> canvas, SharedPtr<NodeModel> node)
{
	boost::shared_ptr<NodeModule> ret;

	SharedPtr<PatchModel> patch = PtrCast<PatchModel>(node);
	if (patch)
		ret = boost::shared_ptr<NodeModule>(new SubpatchModule(canvas, patch));
	else
		ret = boost::shared_ptr<NodeModule>(new NodeModule(canvas, node));

	for (MetadataMap::const_iterator m = node->metadata().begin(); m != node->metadata().end(); ++m)
		ret->set_metadata(m->first, m->second);

	uint32_t index = 0;
	for (PortModelList::const_iterator p = node->ports().begin(); p != node->ports().end(); ++p) {
		ret->add_port(*p, false);
		(*p)->signal_control.connect(sigc::bind<0>(
					sigc::mem_fun(ret.get(), &NodeModule::control_change), index));
		++index;
	}

	ret->resize();

	return ret;
}

void
NodeModule::control_change(uint32_t index, float control)
{
	if (_slv2_ui) {
		const LV2UI_Descriptor* ui_descriptor = slv2_ui_instance_get_descriptor(_slv2_ui);
		LV2UI_Handle ui_handle = slv2_ui_instance_get_handle(_slv2_ui);
		ui_descriptor->port_event(ui_handle, index, 4, &control);
	}
}

void
NodeModule::embed_gui(bool embed)
{
	if (embed) {

		// FIXME: leaks?

		GtkWidget* c_widget = NULL;
		Gtk::Bin* container = NULL;

		if (!_gui_item) {
			cerr << "Embedding LV2 GUI" << endl;

			_slv2_ui = _node->plugin()->ui(App::instance().engine().get(), _node.get());
			if (_slv2_ui) {
				cerr << "Found UI" << endl;
				c_widget = (GtkWidget*)slv2_ui_instance_get_widget(_slv2_ui);
				_gui = Glib::wrap(c_widget);
				assert(_gui);

				//container = new Gtk::Alignment();  // transparent bg but uber slow
				container = new Gtk::EventBox();
				container->add(*_gui);
				container->show_all();
				/*Gdk::Color color;
				color.set_red((_color & 0xFF000000) >> 24);
				color.set_green((_color & 0x00FF0000) >> 16);
				color.set_blue((_color & 0xFF000000) >> 8);
				container->modify_bg(Gtk::STATE_NORMAL,   color);
				container->modify_bg(Gtk::STATE_ACTIVE,   color);
				container->modify_bg(Gtk::STATE_PRELIGHT, color);
				container->modify_bg(Gtk::STATE_SELECTED, color);*/

				const double y = 4 + _canvas_title.property_text_height();
				_gui_item = new Gnome::Canvas::Widget(*this, 2.0, y, *container);
			}
		}

		if (_gui_item) {
			assert(_gui);
			cerr << "Created canvas item" << endl;
			_gui->show_all();
			_gui_item->show();

			GtkRequisition r;
			gtk_widget_size_request(c_widget, &r);
			gui_size_request(&r);

			_gui_item->raise_to_top();

			_gui->signal_size_request().connect(sigc::mem_fun(this, &NodeModule::gui_size_request));

			for (PortModelList::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p)
				if ((*p)->is_control() && (*p)->is_output())
					App::instance().engine()->enable_port_broadcasting((*p)->path());

		} else {
			cerr << "*** Failed to create canvas item" << endl;
		}

	} else {
		if (_gui_item) {
			delete _gui_item;
			_gui_item = NULL;
		}

		if (_gui) {
			delete _gui;
			_gui = NULL;
		}

		//slv2_ui_instance_free(_slv2_ui); // FIXME: leak
		_slv2_ui = NULL;

		_ports_y_offset = 0;
		_width = 0; // resize() takes care of it..

		for (PortModelList::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p)
			if ((*p)->is_control() && (*p)->is_output())
				App::instance().engine()->disable_port_broadcasting((*p)->path());
	}

	resize();
}

void
NodeModule::gui_size_request(Gtk::Requisition* r)
{
	if (r->width + 4 > _width)
		set_width(r->width + 4);

	_gui_item->property_width() = _width - 4;
	_gui_item->property_height() = r->height;
	_ports_y_offset = r->height + 2;

	resize();
}

void
NodeModule::rename()
{
	set_name(_node->path().name());
}

void
NodeModule::add_port(SharedPtr<PortModel> port, bool resize_to_fit)
{
	Module::add_port(boost::shared_ptr<Port>(new Port(
			PtrCast<NodeModule>(shared_from_this()), port)));

	if (resize_to_fit)
		resize();
}

void
NodeModule::remove_port(SharedPtr<PortModel> port)
{
	SharedPtr<FlowCanvas::Port> p = Module::remove_port(port->path().name());
	p.reset();
}

void
NodeModule::show_control_window()
{
#ifdef HAVE_SLV2
	if (_node->plugin()->type() == PluginModel::LV2) {
		// FIXME: check type

		SLV2UIInstance ui = _node->plugin()->ui(App::instance().engine().get(), _node.get());
		if (ui) {
			cerr << "Showing LV2 GUI" << endl;
			// FIXME: leak
			GtkWidget* c_widget = (GtkWidget*)slv2_ui_instance_get_widget(ui);
			Gtk::Widget* widget = Glib::wrap(c_widget);

			Gtk::Window* win = new Gtk::Window();
			win->add(*widget);
			widget->show_all();
			win->present();
		} else {
			cerr << "No LV2 GUI, showing builtin controls" << endl;
			App::instance().window_factory()->present_controls(_node);
		}
	} else {
		App::instance().window_factory()->present_controls(_node);
	}
#else
	App::instance().window_factory()->present_controls(_node);
#endif
}

void
NodeModule::store_location()
{
	const float x = static_cast<float>(property_x());
	const float y = static_cast<float>(property_y());

	const Atom& existing_x = _node->get_metadata("ingenuity:canvas-x");
	const Atom& existing_y = _node->get_metadata("ingenuity:canvas-y");

	if (existing_x.type() != Atom::FLOAT || existing_y.type() != Atom::FLOAT
			|| existing_x.get_float() != x || existing_y.get_float() != y) {
		App::instance().engine()->set_metadata(_node->path(), "ingenuity:canvas-x", Atom(x));
		App::instance().engine()->set_metadata(_node->path(), "ingenuity:canvas-y", Atom(y));
	}
}

void
NodeModule::set_metadata(const string& key, const Atom& value)
{
	if (key == "ingenuity:canvas-x" && value.type() == Atom::FLOAT)
		move_to(value.get_float(), property_y());
	else if (key == "ingenuity:canvas-y" && value.type() == Atom::FLOAT)
		move_to(property_x(), value.get_float());
}

} // namespace GUI
} // namespace Ingen
<commit_msg>Fix unembedding/reembedding of LV2 GUIs.<commit_after>/* This file is part of Ingen.
 * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
 *
 * Ingen is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <cassert>
#include <raul/Atom.hpp>
#include "interface/EngineInterface.hpp"
#include "client/PatchModel.hpp"
#include "client/NodeModel.hpp"
#include "App.hpp"
#include "NodeModule.hpp"
#include "PatchCanvas.hpp"
#include "Port.hpp"
#include "GladeFactory.hpp"
#include "RenameWindow.hpp"
#include "PatchWindow.hpp"
#include "WindowFactory.hpp"
#include "SubpatchModule.hpp"
#include "NodeControlWindow.hpp"

namespace Ingen {
namespace GUI {

NodeModule::NodeModule(boost::shared_ptr<PatchCanvas> canvas, SharedPtr<NodeModel> node)
	: FlowCanvas::Module(canvas, node->path().name())
	, _node(node)
	, _slv2_ui(NULL)
	, _gui(NULL)
	, _gui_item(NULL)
{
	assert(_node);

	node->signal_new_port.connect(sigc::bind(sigc::mem_fun(this, &NodeModule::add_port), true));
	node->signal_removed_port.connect(sigc::mem_fun(this, &NodeModule::remove_port));
	node->signal_metadata.connect(sigc::mem_fun(this, &NodeModule::set_metadata));
	node->signal_polyphonic.connect(sigc::mem_fun(this, &NodeModule::set_stacked_border));
	node->signal_renamed.connect(sigc::mem_fun(this, &NodeModule::rename));

	set_stacked_border(node->polyphonic());
}

NodeModule::~NodeModule()
{
	NodeControlWindow* win = App::instance().window_factory()->control_window(_node);

	if (win) {
		// Should remove from window factory via signal
		delete win;
	}
}

void
NodeModule::create_menu()
{
	Glib::RefPtr<Gnome::Glade::Xml> xml = GladeFactory::new_glade_reference();
	xml->get_widget_derived("object_menu", _menu);
	_menu->init(_node);
	_menu->signal_embed_gui.connect(sigc::mem_fun(this, &NodeModule::embed_gui));

	set_menu(_menu);
}

boost::shared_ptr<NodeModule>
NodeModule::create(boost::shared_ptr<PatchCanvas> canvas, SharedPtr<NodeModel> node)
{
	boost::shared_ptr<NodeModule> ret;

	SharedPtr<PatchModel> patch = PtrCast<PatchModel>(node);
	if (patch)
		ret = boost::shared_ptr<NodeModule>(new SubpatchModule(canvas, patch));
	else
		ret = boost::shared_ptr<NodeModule>(new NodeModule(canvas, node));

	for (MetadataMap::const_iterator m = node->metadata().begin(); m != node->metadata().end(); ++m)
		ret->set_metadata(m->first, m->second);

	uint32_t index = 0;
	for (PortModelList::const_iterator p = node->ports().begin(); p != node->ports().end(); ++p) {
		ret->add_port(*p, false);
		(*p)->signal_control.connect(sigc::bind<0>(
					sigc::mem_fun(ret.get(), &NodeModule::control_change), index));
		++index;
	}

	ret->resize();

	return ret;
}

void
NodeModule::control_change(uint32_t index, float control)
{
	if (_slv2_ui) {
		const LV2UI_Descriptor* ui_descriptor = slv2_ui_instance_get_descriptor(_slv2_ui);
		LV2UI_Handle ui_handle = slv2_ui_instance_get_handle(_slv2_ui);
		ui_descriptor->port_event(ui_handle, index, 4, &control);
	}
}

void
NodeModule::embed_gui(bool embed)
{
	if (embed) {

		// FIXME: leaks?

		GtkWidget* c_widget = NULL;
		Gtk::Bin* container = NULL;

		if (!_gui_item) {
			cerr << "Embedding LV2 GUI" << endl;

			_slv2_ui = _node->plugin()->ui(App::instance().engine().get(), _node.get());
			if (_slv2_ui) {
				cerr << "Found UI" << endl;
				c_widget = (GtkWidget*)slv2_ui_instance_get_widget(_slv2_ui);
				_gui = Glib::wrap(c_widget);
				assert(_gui);

				//container = new Gtk::Alignment();  // transparent bg but uber slow
				container = new Gtk::EventBox();
				container->add(*_gui);
				container->show_all();
				/*Gdk::Color color;
				color.set_red((_color & 0xFF000000) >> 24);
				color.set_green((_color & 0x00FF0000) >> 16);
				color.set_blue((_color & 0xFF000000) >> 8);
				container->modify_bg(Gtk::STATE_NORMAL,   color);
				container->modify_bg(Gtk::STATE_ACTIVE,   color);
				container->modify_bg(Gtk::STATE_PRELIGHT, color);
				container->modify_bg(Gtk::STATE_SELECTED, color);*/

				const double y = 4 + _canvas_title.property_text_height();
				_gui_item = new Gnome::Canvas::Widget(*this, 2.0, y, *container);
			}
		}

		if (_gui_item) {
			assert(_gui);
			cerr << "Created canvas item" << endl;
			_gui->show_all();
			_gui_item->show();

			GtkRequisition r;
			gtk_widget_size_request(c_widget, &r);
			gui_size_request(&r);

			_gui_item->raise_to_top();

			_gui->signal_size_request().connect(sigc::mem_fun(this, &NodeModule::gui_size_request));

			for (PortModelList::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p)
				if ((*p)->is_control() && (*p)->is_output())
					App::instance().engine()->enable_port_broadcasting((*p)->path());

		} else {
			cerr << "*** Failed to create canvas item" << endl;
		}

	} else {
		if (_gui_item) {
			delete _gui_item;
			_gui_item = NULL;
		}

		slv2_ui_instance_free(_slv2_ui);
		_slv2_ui = NULL;
		_gui = NULL;

		_ports_y_offset = 0;
		_width = 0; // resize() takes care of it..

		for (PortModelList::const_iterator p = _node->ports().begin(); p != _node->ports().end(); ++p)
			if ((*p)->is_control() && (*p)->is_output())
				App::instance().engine()->disable_port_broadcasting((*p)->path());
	}

	resize();
}

void
NodeModule::gui_size_request(Gtk::Requisition* r)
{
	if (r->width + 4 > _width)
		set_width(r->width + 4);

	_gui_item->property_width() = _width - 4;
	_gui_item->property_height() = r->height;
	_ports_y_offset = r->height + 2;

	resize();
}

void
NodeModule::rename()
{
	set_name(_node->path().name());
}

void
NodeModule::add_port(SharedPtr<PortModel> port, bool resize_to_fit)
{
	Module::add_port(boost::shared_ptr<Port>(new Port(
			PtrCast<NodeModule>(shared_from_this()), port)));

	if (resize_to_fit)
		resize();
}

void
NodeModule::remove_port(SharedPtr<PortModel> port)
{
	SharedPtr<FlowCanvas::Port> p = Module::remove_port(port->path().name());
	p.reset();
}

void
NodeModule::show_control_window()
{
#ifdef HAVE_SLV2
	if (_node->plugin()->type() == PluginModel::LV2) {
		// FIXME: check type

		SLV2UIInstance ui = _node->plugin()->ui(App::instance().engine().get(), _node.get());
		if (ui) {
			cerr << "Showing LV2 GUI" << endl;
			// FIXME: leak
			GtkWidget* c_widget = (GtkWidget*)slv2_ui_instance_get_widget(ui);
			Gtk::Widget* widget = Glib::wrap(c_widget);

			Gtk::Window* win = new Gtk::Window();
			win->add(*widget);
			widget->show_all();
			win->present();
		} else {
			cerr << "No LV2 GUI, showing builtin controls" << endl;
			App::instance().window_factory()->present_controls(_node);
		}
	} else {
		App::instance().window_factory()->present_controls(_node);
	}
#else
	App::instance().window_factory()->present_controls(_node);
#endif
}

void
NodeModule::store_location()
{
	const float x = static_cast<float>(property_x());
	const float y = static_cast<float>(property_y());

	const Atom& existing_x = _node->get_metadata("ingenuity:canvas-x");
	const Atom& existing_y = _node->get_metadata("ingenuity:canvas-y");

	if (existing_x.type() != Atom::FLOAT || existing_y.type() != Atom::FLOAT
			|| existing_x.get_float() != x || existing_y.get_float() != y) {
		App::instance().engine()->set_metadata(_node->path(), "ingenuity:canvas-x", Atom(x));
		App::instance().engine()->set_metadata(_node->path(), "ingenuity:canvas-y", Atom(y));
	}
}

void
NodeModule::set_metadata(const string& key, const Atom& value)
{
	if (key == "ingenuity:canvas-x" && value.type() == Atom::FLOAT)
		move_to(value.get_float(), property_y());
	else if (key == "ingenuity:canvas-y" && value.type() == Atom::FLOAT)
		move_to(property_x(), value.get_float());
}

} // namespace GUI
} // namespace Ingen
<|endoftext|>


<commit_before>#include "libircppclient.hpp"
#include "util.hpp"
#include <string>
#include <iostream>
#include <thread>
#include <stdexcept>

namespace irc {

client::client(const config &conf)
	: conf_(conf), con_(conf_.ssl)
{
	std::string ret = validate_conf(conf);

	if (!ret.empty())
		throw std::invalid_argument("Configuration error: " + ret);

	con_.set_addr(conf.address);
	con_.set_port(conf.port);

	/*
	 * "Bind" the external read handlers from connection to
	 * read_handler() here. Otherwise, you'd need to fiddle
	 * with connection.hpp inclusion.
	 */
	con_.set_ext_read_handler([this](const std::experimental::string_view &content) {
		this->read_handler(content);
	});
}

std::string client::validate_conf(const config &c)
{

	/* Address checking. */
	if (c.address.empty()) {
		return "the address is empty.";
	} else {
		std::string ret = util::valid_addr(c.address);

		if (!ret.empty())
			return "invalid address, reason: " + ret;
	}

	/* Port checking. */
	if (c.port.empty())
		return "port is empty.";

	else if (!util::is_integer(c.port))
		return "port contains one of more non-integers.";

	return "";
}

void client::initialize()
{
	con_.write("NICK " + conf_.nick);
	con_.write("USER " + conf_.user + " 0 * :" + conf_.user);
}

void client::start()
{
	con_.connect();

	/*
	 * These writes will be put in the io_service's
	 * queue until a complete connection has been made.
	 */
	initialize();
	con_.run();
}

void client::stop()
{
	/*
	 * Haven't I forgotten something?
	 * Some async function that needs terminating, maybe?
	 */
	con_.stop_ping();
	con_.stop();
}

void client::read_handler(const std::experimental::string_view &content)
{
	for (read_handler_t &func: read_handlers_) {
		func(content);
	}
}

void client::add_read_handler(std::function<void(const std::experimental::string_view &)> func)
{
	read_handlers_.emplace_back(func);
}

void client::raw_cmd(const std::experimental::string_view &content)
{
	if (content.empty())
		throw std::invalid_argument("content is empty.");

	con_.write(content.data());
}

/* ns irc */
}

<commit_msg>remove unecessary whitespace<commit_after>#include "libircppclient.hpp"
#include "util.hpp"
#include <string>
#include <iostream>
#include <thread>
#include <stdexcept>
#include <cassert>

namespace irc {

client::client(const config &conf)
	: conf_(conf), con_(conf_.ssl)
{
	std::string ret = validate_conf(conf);

	if (!ret.empty())
		throw std::invalid_argument("Configuration error: " + ret);

	con_.set_addr(conf.address);
	con_.set_port(conf.port);

	/*
	 * "Bind" the external read handlers from connection to
	 * read_handler() here. Otherwise, you'd need to fiddle
	 * with connection.hpp inclusion.
	 */
	con_.set_ext_read_handler([this](const std::experimental::string_view &content) {
		this->read_handler(content);
	});
}

std::string client::validate_conf(const config &c)
{
	/* Address checking. */
	if (c.address.empty()) {
		return "the address is empty.";
	} else {
		std::string ret = util::valid_addr(c.address);

		if (!ret.empty())
			return "invalid address, reason: " + ret;
	}

	/* Port checking. */
	if (c.port.empty())
		return "port is empty.";

	else if (!util::is_integer(c.port))
		return "port contains one of more non-integers.";

	return "";
}

void client::initialize()
{
	con_.write("NICK " + conf_.nick);
	con_.write("USER " + conf_.user + " 0 * :" + conf_.user);
}

void client::start()
{
	con_.connect();

	/*
	 * These writes will be put in the io_service's
	 * queue until a complete connection has been made.
	 */
	initialize();
	con_.run();
}

void client::stop()
{
	/*
	 * Haven't I forgotten something?
	 * Some async function that needs terminating, maybe?
	 */
	con_.stop_ping();
	con_.stop();
}

void client::read_handler(const std::experimental::string_view &content)
{
	for (read_handler_t &func: read_handlers_) {
		func(content);
	}
}

void client::add_read_handler(std::function<void(const std::experimental::string_view &)> func)
{
	read_handlers_.emplace_back(func);
}

void client::raw_cmd(const std::experimental::string_view &content)
{
	if (content.empty())
		throw std::invalid_argument("content is empty.");

	con_.write(content.data());
}

/* ns irc */
}

<|endoftext|>


<commit_before>/*

  SjASMPlus Z80 Cross Compiler

  This is modified sources of SjASM by Aprisobal - aprisobal@tut.by

  Copyright (c) 2005 Sjoerd Mastijn

  This software is provided 'as-is', without any express or implied warranty.
  In no event will the authors be held liable for any damages arising from the
  use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it freely,
  subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not claim
	 that you wrote the original software. If you use this software in a product,
	 an acknowledgment in the product documentation would be appreciated but is
	 not required.

  2. Altered source versions must be plainly marked as such, and must not be
	 misrepresented as being the original software.

  3. This notice may not be removed or altered from any source distribution.

*/

// support.cpp

#include "sjdefs.h"

#ifdef UNDER_CE

#endif

// http://legacy.imatix.com/html/sfl/sfl282.htm
char* strpad(char* string, char ch, aint length) {
	aint cursize;
	cursize = strlen (string);          /*  Get current length of string     */
	while (cursize < length)            /*  Pad until at desired length      */
		string [cursize++] = ch;

	string [cursize++] = '\0';          /*  Add terminating null             */
	return (string);                    /*    and return to caller           */
}

#if !defined (_MSC_VER) || defined (UNDER_CE)

void GetCurrentDirectory(int whatever, char* pad) {
	pad[0] = 0;
}

int SearchPath(char* oudzp, char* filename, char* whatever, int maxlen, char* nieuwzp, char** ach) {
	FILE* fp;
	char* p, * f;
	if (filename[0] == '/') {
		STRCPY(nieuwzp, maxlen, filename);
	} else {
		STRCPY(nieuwzp, maxlen, oudzp);
		if (*nieuwzp && nieuwzp[strlen(nieuwzp)] != '/') {
			STRCAT(nieuwzp, maxlen, "/");
		}
		STRCAT(nieuwzp, maxlen, filename);
	}
	if (ach) {
		p = f = nieuwzp;
		while (*p) {
			if (*p == '/') {
				f = p + 1;
			} ++p;
		}
		*ach = f;
	}
	if (FOPEN_ISOK(fp, nieuwzp, "r")) {
		fclose(fp);
		return 1;
	}
	return 0;
}

char* strset(char* str, char val) {
	//non-aligned
	char* pByte = str;
	while (((uintptr_t) pByte) & 3) {
		if (*pByte) {
			*pByte++ = val;
		} else {
			return str;
		}
	}

	//4-byte aligned
	unsigned long* pBlock = (unsigned long*) pByte;
	unsigned long a;
	unsigned long dwVal = val | val << 8 | val << 16 | val << 24;
	for (; ;) {
		a = *pBlock;
		a &= 0x7f7f7f7f;
		a -= 0x01010101;
		if (a & 0x80808080) {
			break;
		} else {
			*pBlock++ = dwVal;
		}
	}

	//non-aligned
	pByte = (char*) pBlock;
	while (*pByte) {
		*pByte++ = val;
	}
	return str;
}

#ifndef WIN32
long GetTickCount() {
	struct timeval tv1[1];
	gettimeofday(tv1, 0);
	return tv1->tv_usec / 1000;
}
#endif

#endif

#ifdef USE_LUA

void LuaShellExec(char *command) {
#ifdef UNDER_CE
	//_wsystem(_towchar(command));
	SHELLEXECUTEINFO info;
	info.cbSize = sizeof(SHELLEXECUTEINFO);
	info.fMask = NULL;
    info.hwnd = NULL;
    info.lpVerb = NULL;
    info.lpFile = _totchar(command);
    info.lpParameters = NULL;
    info.lpDirectory = NULL;
    info.nShow = SW_MAXIMIZE;
    info.hInstApp = NULL;
	ShellExecuteEx(&info);
#else
#ifdef WIN32

	WinExec(command, SW_SHOWNORMAL);
#else
	int ret = system(command);
	if ( ret == -1 ) {
		Error("[LUASHELEXEC] Unable to start child process for command", command, CATCHALL);
	}
#endif
#endif
}
#endif //USE_LUA

//eof support.cpp
<commit_msg>uintptr_t definition fixed for older compilers.<commit_after>/*

  SjASMPlus Z80 Cross Compiler

  This is modified sources of SjASM by Aprisobal - aprisobal@tut.by

  Copyright (c) 2005 Sjoerd Mastijn

  This software is provided 'as-is', without any express or implied warranty.
  In no event will the authors be held liable for any damages arising from the
  use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it freely,
  subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not claim
	 that you wrote the original software. If you use this software in a product,
	 an acknowledgment in the product documentation would be appreciated but is
	 not required.

  2. Altered source versions must be plainly marked as such, and must not be
	 misrepresented as being the original software.

  3. This notice may not be removed or altered from any source distribution.

*/

// support.cpp

#include "sjdefs.h"

#ifdef UNDER_CE

#endif

// http://legacy.imatix.com/html/sfl/sfl282.htm
char* strpad(char* string, char ch, aint length) {
	aint cursize;
	cursize = strlen (string);          /*  Get current length of string     */
	while (cursize < length)            /*  Pad until at desired length      */
		string [cursize++] = ch;

	string [cursize++] = '\0';          /*  Add terminating null             */
	return (string);                    /*    and return to caller           */
}

#if !defined (_MSC_VER) || defined (UNDER_CE)

void GetCurrentDirectory(int whatever, char* pad) {
	pad[0] = 0;
}

int SearchPath(char* oudzp, char* filename, char* whatever, int maxlen, char* nieuwzp, char** ach) {
	FILE* fp;
	char* p, * f;
	if (filename[0] == '/') {
		STRCPY(nieuwzp, maxlen, filename);
	} else {
		STRCPY(nieuwzp, maxlen, oudzp);
		if (*nieuwzp && nieuwzp[strlen(nieuwzp)] != '/') {
			STRCAT(nieuwzp, maxlen, "/");
		}
		STRCAT(nieuwzp, maxlen, filename);
	}
	if (ach) {
		p = f = nieuwzp;
		while (*p) {
			if (*p == '/') {
				f = p + 1;
			} ++p;
		}
		*ach = f;
	}
	if (FOPEN_ISOK(fp, nieuwzp, "r")) {
		fclose(fp);
		return 1;
	}
	return 0;
}

char* strset(char* str, char val) {
	//non-aligned
	char* pByte = str;
// mborik: fix for older compilers
#ifdef _UINTPTR_T_DEFINED
    	while (((uintptr_t) pByte) & 3) {
#else
	while (((unsigned long) pByte) & 3) {
#endif
		if (*pByte) {
			*pByte++ = val;
		} else {
			return str;
		}
	}

	//4-byte aligned
	unsigned long* pBlock = (unsigned long*) pByte;
	unsigned long a;
	unsigned long dwVal = val | val << 8 | val << 16 | val << 24;
	for (; ;) {
		a = *pBlock;
		a &= 0x7f7f7f7f;
		a -= 0x01010101;
		if (a & 0x80808080) {
			break;
		} else {
			*pBlock++ = dwVal;
		}
	}

	//non-aligned
	pByte = (char*) pBlock;
	while (*pByte) {
		*pByte++ = val;
	}
	return str;
}

#ifndef WIN32
long GetTickCount() {
	struct timeval tv1[1];
	gettimeofday(tv1, 0);
	return tv1->tv_usec / 1000;
}
#endif

#endif

#ifdef USE_LUA

void LuaShellExec(char *command) {
#ifdef UNDER_CE
	//_wsystem(_towchar(command));
	SHELLEXECUTEINFO info;
	info.cbSize = sizeof(SHELLEXECUTEINFO);
	info.fMask = NULL;
    info.hwnd = NULL;
    info.lpVerb = NULL;
    info.lpFile = _totchar(command);
    info.lpParameters = NULL;
    info.lpDirectory = NULL;
    info.nShow = SW_MAXIMIZE;
    info.hInstApp = NULL;
	ShellExecuteEx(&info);
#else
#ifdef WIN32

	WinExec(command, SW_SHOWNORMAL);
#else
	int ret = system(command);
	if ( ret == -1 ) {
		Error("[LUASHELEXEC] Unable to start child process for command", command, CATCHALL);
	}
#endif
#endif
}
#endif //USE_LUA

//eof support.cpp
<|endoftext|>


<commit_before>#include "susi/DuktapeEngine.h"

std::string Susi::Duktape::susiJS = R"SUSIJS(

var susi = {
    _consumerCallbacks: [],
    _processorCallbacks: [],

    _processorTopicCounter: {},
    _consumerTopicCounter: {},

    _publishCallbacks: {},
    _processorProcesses: {},

    _processed: [],

    registerConsumer: function(topic,callback) {
        var id = this._genID();
        this._consumerCallbacks.push({topic: topic, callback: callback, id: id});
        var count = this._consumerTopicCounter[topic] || 0;
        count++;
        this._consumerTopicCounter[topic] = count;
        if(count === 1){
            _registerConsumer(topic);
        }
        return id;
    },

    registerProcessor: function(topic,callback) {
        var id = this._genID();
        this._processorCallbacks.push({topic: topic, callback: callback, id: id});
        var count = this._processorTopicCounter[topic] || 0;
        count++;
        this._processorTopicCounter[topic] = count;
        if(count == 1){
            _registerProcessor(topic);
        }
        return id;
    },

    unregisterConsumer: function(id){
        for(var i=0;i<this._consumerCallbacks;i++){
            if(this._consumerCallbacks[i].id === id){
                var topic = this._consumerCallbacks[i].topic;
                this._consumerCallbacks.splice(i,1);
                var count = this._consumerTopicCounter[topic];
                count--;
                if(count === 0){
                    delete(this._consumerTopicCounter[topic]);
                    _unregisterConsumer(topic);
                }else{
                    this._consumerTopicCounter[topic] = count;
                }
                return true;
            }
        }
        return false;
    },

    unregisterProcessor: function(id){
        for(var i=0;i<this._processorCallbacks;i++){
            if(this._processorCallbacks[i].id === id){
                var topic = this._processorCallbacks[i].topic;
                this._processorCallbacks.splice(i,1);
                var count = this._processorTopicCounter[topic];
                count--;
                if(count === 0){
                    delete(this._processorTopicCounter[topic]);
                    _unregisterProcessor(topic);
                }else{
                    this._processorTopicCounter[topic] = count;
                }
                return true;
            }
        }
        return false;
    },

    publish: function(event,callback) {
        if(event.id === undefined){
            event.id = ''+this._genID();
        }
        if(callback !== undefined) {
            this._publishCallbacks[event.id] = callback;
        }
        _publish(JSON.stringify(event));
    },

    ack: function(event){
        var process = this._processorProcesses[event.id];
        if(process.next >= process.processors.length){
            delete this._processorProcesses[event.id];
            _ack(JSON.stringify(event));
        }else{
            process.next++;
            process.processors[process.next-1](event);
        }
    },

    dismiss: function(event){
        delete(this._processorProcesses[event.id]);
        _dismiss(JSON.stringify(event));
    },

    //used by js to interact with c++ part
    _processConsumerEvent: function(event){
        event = JSON.parse(event);
        for(var i=0;i<this._consumerCallbacks.length;i++){
            if(event.topic.match(this._consumerCallbacks[i].topic)){
                this._consumerCallbacks[i].callback(event);
            }
        }
    },

    _processProcessorEvent: function(event){
        event = JSON.parse(event);
        if(this._processed.indexOf(event.id) !== -1){
            _ack(JSON.stringify(event));
            return;
        }
        this._processed.push(event.id);
        if(this._processed.length > 64){
            this._processed.splice(0,1);
        }
        Duktape.fin(event,function(event){
            susi.ack(event);
        });
        var process = {
            processors: [],
            next: 0
        };

        for (var i = 0; i<this._processorCallbacks.length; i++) {
            if(event.topic.match(this._processorCallbacks[i].topic)){
                process.processors.push(this._processorCallbacks[i].callback);
            }
        }

        this._processorProcesses[event.id] = process;
        this.ack(event);
        Duktape.gc();
    },

    _processAck: function(event){
        event = JSON.parse(event);
        var cb = this._publishCallbacks[event.id];
        if(cb !== undefined) {
            cb(event);
            delete this._publishCallbacks[event.id];
        }
    },

    _genID: function(){
        return Math.floor(Math.random()*1000000000000);
    }
};

//called by c++ part
function _processConsumerEvent(event,topic){
    susi._processConsumerEvent(event,topic);
}

function _processProcessorEvent(event,topic){
    susi._processProcessorEvent(event,topic)
}

function _processAck(event){
    susi._processAck(event);
}

var duktapeLogger = new Duktape.Logger('susi-js');
duktapeLogger.l = 0;

var console = {
    _prepareArguments: function(args){
        var newArgs = [];
        for(var i=0;i<args.length;i++){
            if(typeof args[i] === 'object'){
                newArgs.push(Duktape.enc('jx',args[i]));
            }else{
                newArgs.push(args[i]);
            }
        }
        return newArgs;
    },
    _getLine: function(){
        var e = new Error(arguments);
        return e.stack.split('\n')[3].trim().split(' ')[1];
    },
    log: function(){
        duktapeLogger.info.apply(duktapeLogger,this._prepareArguments(arguments));
    },
    debug: function(){
        duktapeLogger.n = 'susi-js: '+this._getLine();
        duktapeLogger.debug.apply(duktapeLogger,this._prepareArguments(arguments));
        duktapeLogger.n = 'susi-js';
    },
    error: function(){
        duktapeLogger.n = 'susi-js: '+this._getLine();
        duktapeLogger.error.apply(duktapeLogger,this._prepareArguments(arguments));
        duktapeLogger.n = 'susi-js';
    }
};

var TimeoutManager = {
    timeoutFunctions: [],
    add: function(cb, millis){
        this.timeoutFunctions.push({
            deadline: Date.now()+millis,
            cb: cb
        });
    },
    check: function(){
        var now = Date.now();
        for(var i=this.timeoutFunctions.length-1;i>=0;i--){
            if(this.timeoutFunctions[i].deadline <= now){
                this.timeoutFunctions[i].cb();
                this.timeoutFunctions.splice(i,1);
            }
        }
    }
};

function setTimeout(cb,millis){
    TimeoutManager.add(cb,millis);
    _setTimeout(millis);
}

function _checkTimeouts(){
    TimeoutManager.check();
}

)SUSIJS";
<commit_msg>fixed double consumers in complex setups, needs further investigation;<commit_after>#include "susi/DuktapeEngine.h"

std::string Susi::Duktape::susiJS = R"SUSIJS(

var susi = {
    _consumerCallbacks: [],
    _processorCallbacks: [],

    _processorTopicCounter: {},
    _consumerTopicCounter: {},

    _publishCallbacks: {},
    _processorProcesses: {},

    _processed: [],
    _processedConsumer: [],

    registerConsumer: function(topic,callback) {
        var id = this._genID();
        this._consumerCallbacks.push({topic: topic, callback: callback, id: id});
        var count = this._consumerTopicCounter[topic] || 0;
        count++;
        this._consumerTopicCounter[topic] = count;
        if(count === 1){
            _registerConsumer(topic);
        }
        return id;
    },

    registerProcessor: function(topic,callback) {
        var id = this._genID();
        this._processorCallbacks.push({topic: topic, callback: callback, id: id});
        var count = this._processorTopicCounter[topic] || 0;
        count++;
        this._processorTopicCounter[topic] = count;
        if(count == 1){
            _registerProcessor(topic);
        }
        return id;
    },

    unregisterConsumer: function(id){
        for(var i=0;i<this._consumerCallbacks;i++){
            if(this._consumerCallbacks[i].id === id){
                var topic = this._consumerCallbacks[i].topic;
                this._consumerCallbacks.splice(i,1);
                var count = this._consumerTopicCounter[topic];
                count--;
                if(count === 0){
                    delete(this._consumerTopicCounter[topic]);
                    _unregisterConsumer(topic);
                }else{
                    this._consumerTopicCounter[topic] = count;
                }
                return true;
            }
        }
        return false;
    },

    unregisterProcessor: function(id){
        for(var i=0;i<this._processorCallbacks;i++){
            if(this._processorCallbacks[i].id === id){
                var topic = this._processorCallbacks[i].topic;
                this._processorCallbacks.splice(i,1);
                var count = this._processorTopicCounter[topic];
                count--;
                if(count === 0){
                    delete(this._processorTopicCounter[topic]);
                    _unregisterProcessor(topic);
                }else{
                    this._processorTopicCounter[topic] = count;
                }
                return true;
            }
        }
        return false;
    },

    publish: function(event,callback) {
        if(event.id === undefined){
            event.id = ''+this._genID();
        }
        if(callback !== undefined) {
            this._publishCallbacks[event.id] = callback;
        }
        _publish(JSON.stringify(event));
    },

    ack: function(event){
        var process = this._processorProcesses[event.id];
        if(process.next >= process.processors.length){
            delete this._processorProcesses[event.id];
            _ack(JSON.stringify(event));
        }else{
            process.next++;
            process.processors[process.next-1](event);
        }
    },

    dismiss: function(event){
        delete(this._processorProcesses[event.id]);
        _dismiss(JSON.stringify(event));
    },

    //used by js to interact with c++ part
    _processConsumerEvent: function(event){
        event = JSON.parse(event);
        if(this._processedConsumer.indexOf(event.id) !== -1){
            _ack(JSON.stringify(event));
            return;
        }
        this._processedConsumer.push(event.id);
        if(this._processedConsumer.length > 64){
            this._processedConsumer.splice(0,1);
        }
        for(var i=0;i<this._consumerCallbacks.length;i++){
            if(event.topic.match(this._consumerCallbacks[i].topic)){
                this._consumerCallbacks[i].callback(event);
            }
        }
    },

    _processProcessorEvent: function(event){
        event = JSON.parse(event);
        if(this._processed.indexOf(event.id) !== -1){
            _ack(JSON.stringify(event));
            return;
        }
        this._processed.push(event.id);
        if(this._processed.length > 64){
            this._processed.splice(0,1);
        }
        Duktape.fin(event,function(event){
            susi.ack(event);
        });
        var process = {
            processors: [],
            next: 0
        };

        for (var i = 0; i<this._processorCallbacks.length; i++) {
            if(event.topic.match(this._processorCallbacks[i].topic)){
                process.processors.push(this._processorCallbacks[i].callback);
            }
        }

        this._processorProcesses[event.id] = process;
        this.ack(event);
        Duktape.gc();
    },

    _processAck: function(event){
        event = JSON.parse(event);
        var cb = this._publishCallbacks[event.id];
        if(cb !== undefined) {
            cb(event);
            delete this._publishCallbacks[event.id];
        }
    },

    _genID: function(){
        return Math.floor(Math.random()*1000000000000);
    }
};

//called by c++ part
function _processConsumerEvent(event,topic){
    susi._processConsumerEvent(event,topic);
}

function _processProcessorEvent(event,topic){
    susi._processProcessorEvent(event,topic)
}

function _processAck(event){
    susi._processAck(event);
}

var duktapeLogger = new Duktape.Logger('susi-js');
duktapeLogger.l = 0;

var console = {
    _prepareArguments: function(args){
        var newArgs = [];
        for(var i=0;i<args.length;i++){
            if(typeof args[i] === 'object'){
                newArgs.push(Duktape.enc('jx',args[i]));
            }else{
                newArgs.push(args[i]);
            }
        }
        return newArgs;
    },
    _getLine: function(){
        var e = new Error(arguments);
        return e.stack.split('\n')[3].trim().split(' ')[1];
    },
    log: function(){
        duktapeLogger.info.apply(duktapeLogger,this._prepareArguments(arguments));
    },
    debug: function(){
        duktapeLogger.n = 'susi-js: '+this._getLine();
        duktapeLogger.debug.apply(duktapeLogger,this._prepareArguments(arguments));
        duktapeLogger.n = 'susi-js';
    },
    error: function(){
        duktapeLogger.n = 'susi-js: '+this._getLine();
        duktapeLogger.error.apply(duktapeLogger,this._prepareArguments(arguments));
        duktapeLogger.n = 'susi-js';
    }
};

var TimeoutManager = {
    timeoutFunctions: [],
    add: function(cb, millis){
        this.timeoutFunctions.push({
            deadline: Date.now()+millis,
            cb: cb
        });
    },
    check: function(){
        var now = Date.now();
        for(var i=this.timeoutFunctions.length-1;i>=0;i--){
            if(this.timeoutFunctions[i].deadline <= now){
                this.timeoutFunctions[i].cb();
                this.timeoutFunctions.splice(i,1);
            }
        }
    }
};

function setTimeout(cb,millis){
    TimeoutManager.add(cb,millis);
    _setTimeout(millis);
}

function _checkTimeouts(){
    TimeoutManager.check();
}

)SUSIJS";
<|endoftext|>


<commit_before>#include <Windows.h>
#include <stdint.h> // Types indpendents de la plateforme
#include <Xinput.h> // Pour la gestion des entres (manette...)

// Pour bien comprendre la diffrence de fonctionnement des variables statiques en C en fonction du scope
#define internal static // fonctions non visible depuis l'extrieur de ce fichier
#define local_persist static     // variable visibles juste dans le scope o elle dfinie
#define global_variable static   // variable visible dans tous le fichiers (globale)

// Quelques dfinitions de types d'entiers pour ne pas tre dpendant de la plateforme
typedef unsigned char uint8;
typedef uint8_t uint8; // comme un unsigned char, un 8 bits
typedef int16_t uint16;
typedef int32_t uint32;
typedef int64_t uint64;

// Struct qui reprsente un backbuffer qui nous permet de dessiner
struct win32_offscreen_buffer {
  BITMAPINFO Info;
  void *Memory;
  int Width;
  int Height;
  int BytesPerPixel;
  int Pitch; // Pitch reprsente la taille d'une ligne en octets
};

// variables globales pour le moment, on grera autrement plus tard
global_variable bool GlobalRunning;
global_variable win32_offscreen_buffer GlobalBackBuffer;

// Struct qui reprsente des dimensions
struct win32_window_dimension
{
  int Width;
  int Height;
};

// Permet de renvoyer les dimensions actuelles de la fentre
internal win32_window_dimension
Win32GetWindowDimension(HWND Window) {
  win32_window_dimension Result;
  RECT ClientRect;
  GetClientRect(Window, &ClientRect);
  Result.Width = ClientRect.right - ClientRect.left;
  Result.Height = ClientRect.bottom - ClientRect.top;
  return(Result);
}

// Ici on dfinit des pointeurs vers les fonctions de Xinput
// Cette technique traditionnelle permet d'utiliser des fonctions
// Sans linker directement la lib, et permet aussi de tester si la lib est prsente
// On utilise alors des macros pour dfinir la signature des fonctions
// Ici on dfinit deux fonctions qui vont se subsituer aux vraies si la lib n'est pas trouve
// D'abord pour XInputGetState
#define X_INPUT_GET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_STATE *pState)
typedef X_INPUT_GET_STATE(x_input_get_state);
X_INPUT_GET_STATE(XInputGetStateStub) {
  return(0);
}
global_variable x_input_get_state *XInputGetState_ = XInputGetStateStub;
#define XInputGetState XInputGetState_

// De mme pour XInputSetState
#define X_INPUT_SET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration)
typedef X_INPUT_SET_STATE(x_input_set_state);
X_INPUT_SET_STATE(XInputSetStateStub) {
  return(0);
}
global_variable x_input_set_state *XInputSetState_ = XInputSetStateStub;
#define XInputSetState XInputSetState_

// On va alors
internal void
Win32LoadXInput(void) {
  HMODULE XInputLibrary = LoadLibrary("xinput1_3.dll"); // on essaye une version un peu plus ancienne qui sera prsente sur plus de machines
  if (XInputLibrary)
  {
    XInputGetState_ = (x_input_get_state*)GetProcAddress(XInputLibrary, "XInputGetState");
    XInputSetState_ = (x_input_set_state*)GetProcAddress(XInputLibrary, "XInputSetState");
  }
}

/* Fonction qui va dessiner dans le backbuffer un gradient de couleur trange */
internal void
RenderWeirdGradient(win32_offscreen_buffer *Buffer, int XOffset, int YOffset)
{
  uint8 *Row = (uint8 *)Buffer->Memory; // on va se dplacer dans la mmoire par pas de 8 bits
  for (int Y = 0; Y < Buffer->Height; ++Y)
  {
    uint32 *Pixel = (uint32 *)Row; // Pixel par pixel, on commence par le premier de la ligne
    for (int X = 0; X < Buffer->Width; ++X)
    {
      /*
        Pixels en little endian architecture
                             0  1  2  3 ...
        Pixels en mmoire : 00 00 00 00 ...
        Couleur             BB GG RR XX
        en hexa: 0xXXRRGGBB
      */
      uint8 Blue = (X + XOffset);
      uint8 Green = (Y + YOffset);
      uint8 Red = (X + Y);
      // *Pixel = 0xFF00FF00;
      *Pixel++ = ((Red << 16) | (Green << 8) | Blue); // ce qui quivaut en hexa  0x00BBGG00
    }
    Row += Buffer->Pitch; // Ligne suivante
  }
}

/**
 * Fonction qui permet de dfinir et de rinitialiser un backbuffer en fonction de ses dimensions
 * DIB: Device Independent Bitmap
 **/
internal void
Win32ResizeDIBSection(win32_offscreen_buffer *Buffer, int Width, int Height)
{
  if (Buffer->Memory)
  {
    VirtualFree(Buffer->Memory, 0, MEM_RELEASE); // cf. VirtualProtect, utile pour debug
  }

  Buffer->Width = Width;
  Buffer->Height = Height;
  Buffer->BytesPerPixel = 4;

  Buffer->Info.bmiHeader.biSize = sizeof(Buffer->Info.bmiHeader);
  Buffer->Info.bmiHeader.biWidth = Buffer->Width;
  Buffer->Info.bmiHeader.biHeight = -Buffer->Height; // Attention au sens des coordonnes, du bas vers le haut (d'o le moins)
  Buffer->Info.bmiHeader.biPlanes = 1;
  Buffer->Info.bmiHeader.biBitCount = 32;
  Buffer->Info.bmiHeader.biCompression = BI_RGB;

  int BitmapMemorySize = (Buffer->Width * Buffer->Height) * Buffer->BytesPerPixel;
  Buffer->Memory = VirtualAlloc(0, BitmapMemorySize, MEM_COMMIT, PAGE_READWRITE); // cf. aussi HeapAlloc

  Buffer->Pitch = Width * Buffer->BytesPerPixel;
}

/**
 * Ici au dbut on passait ClientRect par rfrence avec un pointeur (*ClientRect)
 * cependant comme la structure est petite le passer par valeur est suffisant
 **/
internal void
Win32DisplayBufferInWindow(
  HDC DeviceContext,
  int WindowWidth,
  int WindowHeight,
  win32_offscreen_buffer *Buffer)
{
  StretchDIBits( // copie d'un rectangle vers un autre (scaling si ncessaire, bit oprations...)
    DeviceContext,
    0, 0, WindowWidth, WindowHeight,
    0, 0, Buffer->Width, Buffer->Height,
    Buffer->Memory,
    &Buffer->Info,
    DIB_RGB_COLORS,
    SRCCOPY // BitBlt: bit-block transfer of the color data => voir les autres modes dans la MSDN
  );
}

/**
 * Callback de la fentre principale qui va traiter les messages renvoys par Windows
 **/
internal LRESULT CALLBACK
Win32MainWindowCallback(
  HWND Window,
  UINT Message,
  WPARAM WParam,
  LPARAM LParam)
{
  LRESULT Result = 0;
  switch(Message)
  {
    case WM_SIZE:
      {
        OutputDebugStringA("WM_SIZE\n");
      }
      break;
    case WM_DESTROY:
      {
        // PostQuitMessage(0); // Va permettre de sortir de la boucle infinie en dessous
        GlobalRunning = false;
        OutputDebugStringA("WM_DESTROY\n");
      }
      break;
    case WM_CLOSE:
      {
        // DestroyWindow(Window);
        GlobalRunning = false;
        OutputDebugStringA("WM_CLOSE\n");
      }
      break;
    case WM_ACTIVATEAPP:
      {
        OutputDebugStringA("WM_ACTIVATEAPP\n");
      }
      break;
    case WM_PAINT:
      {
        PAINTSTRUCT Paint;
        HDC DeviceContext = BeginPaint(Window, &Paint);
        win32_window_dimension Dimension = Win32GetWindowDimension(Window);
        Win32DisplayBufferInWindow(DeviceContext, Dimension.Width, Dimension.Height, &GlobalBackBuffer);
        EndPaint(Window, &Paint);
      }
      break;
    default:
      {
        // OutputDebugStringA("default\n");
        Result = DefWindowProc(Window, Message, WParam, LParam);
      }
      break;
  }
  return(Result);
}

/**
 * Main du programme qui va initialiser la fentre et grer la boucle principale : attente des messages,
 * gestion de la manette et du clavier, dessin...
 **/
int CALLBACK
WinMain(
  HINSTANCE Instance,
  HINSTANCE PrevInstance,
  LPSTR CommandLine,
  int ShowCode)
{
  // On essaye de charger les fonctions de la dll qui gre les manettes
  Win32LoadXInput();

  // Cration de la fentre principale
  WNDCLASSA WindowClass = {}; // initialisation par dfaut, ANSI version de WNDCLASSA

  Win32ResizeDIBSection(&GlobalBackBuffer, 800, 600);

  // On ne configure que les membres que l'on veut
  WindowClass.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC; // indique que l'on veut rafraichir la fentre entire lors d'un resize (horizontal et vertical)
  WindowClass.lpfnWndProc = Win32MainWindowCallback;
  WindowClass.hInstance = Instance;
  // WindowClass.hIcon;
  WindowClass.lpszClassName = "FaitmainHerosWindowClass"; // nom pour retrouver la fentre

  // Ouverture de la fentre
  if (RegisterClassA(&WindowClass))
  {
    HWND Window = CreateWindowExA( // ANSI version de CreateWindowEx
      0, // dwExStyle : options de la fentre
      WindowClass.lpszClassName,
      "FaitmainHeros",
      WS_OVERLAPPEDWINDOW|WS_VISIBLE, //dwStyle : overlapped window, visible par dfaut
      CW_USEDEFAULT, // X
      CW_USEDEFAULT, // Y
      CW_USEDEFAULT, // nWidth
      CW_USEDEFAULT, // nHeight
      0, // hWndParent : 0 pour dire que c'est une fentre top
      0, // hMenu : 0 pour dire pas de menu
      Instance,
      0 // Pas de passage de paramtres  la fentre
    );
    if (Window)
    {
      // Comme on a spcifi CS_OWNDC on peut initialiser un seul HDC
      // et s'en servir indfiniment car on ne le partage pas
      HDC DeviceContext = GetDC(Window);

      int XOffset = 0;
      int YOffset = 0;
      GlobalRunning = true;

      while (GlobalRunning) // boucle infinie pour traiter tous les messages
      {
        MSG Message;
        while(PeekMessageA(&Message, 0, 0, 0, PM_REMOVE)) // On utilise PeekMessage au lieu de GetMessage qui est bloquant
        {
          if (Message.message == WM_QUIT) GlobalRunning = false;
          TranslateMessage(&Message); // On demande  Windows de traiter le message
          DispatchMessage(&Message); // Envoie le message au main WindowCallback, que l'on a dfini et dclar au dessus
        }

        // Gestion des entres, pour le moment on gre a  chaque image, il faudra peut-tre le faire plus frquemment
        // surtout si le nombre d'images par seconde chute
        for (DWORD ControllerIndex = 0; ControllerIndex < XUSER_MAX_COUNT; ++ControllerIndex)
        {
          XINPUT_STATE ControllerState;
          if (XInputGetState(ControllerIndex, &ControllerState) == ERROR_SUCCESS)
          {
            // Le controller est branch
            XINPUT_GAMEPAD *Pad = &ControllerState.Gamepad;

            bool Up = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_UP);
            bool Down = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN);
            bool Left = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT);
            bool Right = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT);
            bool Start = (Pad->wButtons & XINPUT_GAMEPAD_START);
            bool Back = (Pad->wButtons & XINPUT_GAMEPAD_BACK);
            bool LeftShoulder = (Pad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER);
            bool RightShoulder = (Pad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER);
            bool AButton = (Pad->wButtons & XINPUT_GAMEPAD_A);
            bool BButton = (Pad->wButtons & XINPUT_GAMEPAD_B);
            bool XButton = (Pad->wButtons & XINPUT_GAMEPAD_X);
            bool YButton = (Pad->wButtons & XINPUT_GAMEPAD_Y);

            uint16 StickX = Pad->sThumbLX;
            uint16 StickY = Pad->sThumbLY;

            // Test d'utilisation de la manette
            if (Up) YOffset += 2;
            if (Down) YOffset -= 2;
            if (Right) XOffset -= 4;

            // Vibration de la manette
            XINPUT_VIBRATION Vibration;
            if (Left)
            {
              Vibration.wLeftMotorSpeed = 60000;
              Vibration.wRightMotorSpeed = 60000;
            }
            else
            {
              Vibration.wLeftMotorSpeed = 0;
              Vibration.wRightMotorSpeed = 0;
            }
            XInputSetState(0, &Vibration);
          }
          else
          {
            // Le controlleur n'est pas branch
          }
        }

        // Grce  PeekMessage on a tout le temps CPU que l'on veut et on peut dessiner ici
        RenderWeirdGradient(&GlobalBackBuffer, XOffset, YOffset);
        ++XOffset;

        // On doit alors crire dans la fentre  chaque fois que l'on veut rendre
        // On en fera une fonction propre
        win32_window_dimension Dimension = Win32GetWindowDimension(Window);
        Win32DisplayBufferInWindow(
          DeviceContext,
          Dimension.Width, Dimension.Height,
          &GlobalBackBuffer);
        ReleaseDC(Window, DeviceContext);

        // Pour animer diffremment le gradient
        ++XOffset;
      }
    }
    else
    {
      OutputDebugStringA("Error: CreateWindowEx\n");
    }
  }
  else
  {
    OutputDebugStringA("Error: RegisterClass\n");
  }

  return(0);
};<commit_msg>Début de gestion du clavier<commit_after>#include <Windows.h>
#include <stdint.h> // Types indpendents de la plateforme
#include <Xinput.h> // Pour la gestion des entres (manette...)

// Pour bien comprendre la diffrence de fonctionnement des variables statiques en C en fonction du scope
#define internal static // fonctions non visible depuis l'extrieur de ce fichier
#define local_persist static     // variable visibles juste dans le scope o elle dfinie
#define global_variable static   // variable visible dans tous le fichiers (globale)

// Quelques dfinitions de types d'entiers pour ne pas tre dpendant de la plateforme
typedef unsigned char uint8;
typedef uint8_t uint8; // comme un unsigned char, un 8 bits
typedef int16_t uint16;
typedef int32_t uint32;
typedef int64_t uint64;

// Struct qui reprsente un backbuffer qui nous permet de dessiner
struct win32_offscreen_buffer {
  BITMAPINFO Info;
  void *Memory;
  int Width;
  int Height;
  int BytesPerPixel;
  int Pitch; // Pitch reprsente la taille d'une ligne en octets
};

// variables globales pour le moment, on grera autrement plus tard
global_variable bool GlobalRunning;
global_variable win32_offscreen_buffer GlobalBackBuffer;

// Struct qui reprsente des dimensions
struct win32_window_dimension
{
  int Width;
  int Height;
};

// Permet de renvoyer les dimensions actuelles de la fentre
internal win32_window_dimension
Win32GetWindowDimension(HWND Window) {
  win32_window_dimension Result;
  RECT ClientRect;
  GetClientRect(Window, &ClientRect);
  Result.Width = ClientRect.right - ClientRect.left;
  Result.Height = ClientRect.bottom - ClientRect.top;
  return(Result);
}

// Ici on dfinit des pointeurs vers les fonctions de Xinput
// Cette technique traditionnelle permet d'utiliser des fonctions
// Sans linker directement la lib, et permet aussi de tester si la lib est prsente
// On utilise alors des macros pour dfinir la signature des fonctions
// Ici on dfinit deux fonctions qui vont se subsituer aux vraies si la lib n'est pas trouve
// D'abord pour XInputGetState
#define X_INPUT_GET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_STATE *pState)
typedef X_INPUT_GET_STATE(x_input_get_state);
X_INPUT_GET_STATE(XInputGetStateStub) {
  return(0);
}
global_variable x_input_get_state *XInputGetState_ = XInputGetStateStub;
#define XInputGetState XInputGetState_

// De mme pour XInputSetState
#define X_INPUT_SET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration)
typedef X_INPUT_SET_STATE(x_input_set_state);
X_INPUT_SET_STATE(XInputSetStateStub) {
  return(0);
}
global_variable x_input_set_state *XInputSetState_ = XInputSetStateStub;
#define XInputSetState XInputSetState_

// On va alors
internal void
Win32LoadXInput(void) {
  HMODULE XInputLibrary = LoadLibrary("xinput1_3.dll"); // on essaye une version un peu plus ancienne qui sera prsente sur plus de machines
  if (XInputLibrary)
  {
    XInputGetState_ = (x_input_get_state*)GetProcAddress(XInputLibrary, "XInputGetState");
    XInputSetState_ = (x_input_set_state*)GetProcAddress(XInputLibrary, "XInputSetState");
  }
}

/* Fonction qui va dessiner dans le backbuffer un gradient de couleur trange */
internal void
RenderWeirdGradient(win32_offscreen_buffer *Buffer, int XOffset, int YOffset)
{
  uint8 *Row = (uint8 *)Buffer->Memory; // on va se dplacer dans la mmoire par pas de 8 bits
  for (int Y = 0; Y < Buffer->Height; ++Y)
  {
    uint32 *Pixel = (uint32 *)Row; // Pixel par pixel, on commence par le premier de la ligne
    for (int X = 0; X < Buffer->Width; ++X)
    {
      /*
        Pixels en little endian architecture
                             0  1  2  3 ...
        Pixels en mmoire : 00 00 00 00 ...
        Couleur             BB GG RR XX
        en hexa: 0xXXRRGGBB
      */
      uint8 Blue = (X + XOffset);
      uint8 Green = (Y + YOffset);
      uint8 Red = (X + Y);
      // *Pixel = 0xFF00FF00;
      *Pixel++ = ((Red << 16) | (Green << 8) | Blue); // ce qui quivaut en hexa  0x00BBGG00
    }
    Row += Buffer->Pitch; // Ligne suivante
  }
}

/**
 * Fonction qui permet de dfinir et de rinitialiser un backbuffer en fonction de ses dimensions
 * DIB: Device Independent Bitmap
 **/
internal void
Win32ResizeDIBSection(win32_offscreen_buffer *Buffer, int Width, int Height)
{
  if (Buffer->Memory)
  {
    VirtualFree(Buffer->Memory, 0, MEM_RELEASE); // cf. VirtualProtect, utile pour debug
  }

  Buffer->Width = Width;
  Buffer->Height = Height;
  Buffer->BytesPerPixel = 4;

  Buffer->Info.bmiHeader.biSize = sizeof(Buffer->Info.bmiHeader);
  Buffer->Info.bmiHeader.biWidth = Buffer->Width;
  Buffer->Info.bmiHeader.biHeight = -Buffer->Height; // Attention au sens des coordonnes, du bas vers le haut (d'o le moins)
  Buffer->Info.bmiHeader.biPlanes = 1;
  Buffer->Info.bmiHeader.biBitCount = 32;
  Buffer->Info.bmiHeader.biCompression = BI_RGB;

  int BitmapMemorySize = (Buffer->Width * Buffer->Height) * Buffer->BytesPerPixel;
  Buffer->Memory = VirtualAlloc(0, BitmapMemorySize, MEM_COMMIT, PAGE_READWRITE); // cf. aussi HeapAlloc

  Buffer->Pitch = Width * Buffer->BytesPerPixel;
}

/**
 * Ici au dbut on passait ClientRect par rfrence avec un pointeur (*ClientRect)
 * cependant comme la structure est petite le passer par valeur est suffisant
 **/
internal void
Win32DisplayBufferInWindow(
  HDC DeviceContext,
  int WindowWidth,
  int WindowHeight,
  win32_offscreen_buffer *Buffer)
{
  StretchDIBits( // copie d'un rectangle vers un autre (scaling si ncessaire, bit oprations...)
    DeviceContext,
    0, 0, WindowWidth, WindowHeight,
    0, 0, Buffer->Width, Buffer->Height,
    Buffer->Memory,
    &Buffer->Info,
    DIB_RGB_COLORS,
    SRCCOPY // BitBlt: bit-block transfer of the color data => voir les autres modes dans la MSDN
  );
}

/**
 * Callback de la fentre principale qui va traiter les messages renvoys par Windows
 **/
internal LRESULT CALLBACK
Win32MainWindowCallback(
  HWND Window,
  UINT Message,
  WPARAM WParam,
  LPARAM LParam)
{
  LRESULT Result = 0;
  switch(Message)
  {
    case WM_SIZE:
      {
        OutputDebugStringA("WM_SIZE\n");
      }
      break;
    case WM_DESTROY:
      {
        // PostQuitMessage(0); // Va permettre de sortir de la boucle infinie en dessous
        GlobalRunning = false;
        OutputDebugStringA("WM_DESTROY\n");
      }
      break;
    case WM_CLOSE:
      {
        // DestroyWindow(Window);
        GlobalRunning = false;
        OutputDebugStringA("WM_CLOSE\n");
      }
      break;
    case WM_ACTIVATEAPP:
      {
        OutputDebugStringA("WM_ACTIVATEAPP\n");
      }
      break;
    case WM_SYSKEYDOWN:
    case WM_SYSKEYUP:
    case WM_KEYDOWN:
    case WM_KEYUP:
      {
        uint32 VKCode = WParam;
        if (VKCode == 'Z')
        {
          OutputDebugStringA("Z\n");
        }
        else if (VKCode == 'S')
        {
          OutputDebugStringA("S\n");
        }
        else if (VKCode == 'Q')
        {
          OutputDebugStringA("Q\n");
        }
        else if (VKCode == 'D')
        {
          OutputDebugStringA("D\n");
        }
        else if (VKCode == VK_UP)
        {
          OutputDebugStringA("UP\n");
        }
        else if (VKCode == VK_DOWN)
        {
          OutputDebugStringA("DOWN\n");
        }
        else if (VKCode == VK_LEFT)
        {
          OutputDebugStringA("LEFT\n");
        }
        else if (VKCode == VK_RIGHT)
        {
          OutputDebugStringA("RIGHT\n");
        }
        else if (VKCode == VK_ESCAPE)
        {
          OutputDebugStringA("ESCAPE\n");
        }
        else if (VKCode == VK_SPACE)
        {
          OutputDebugStringA("SPACE\n");
        }
      }
      break;
    case WM_PAINT:
      {
        PAINTSTRUCT Paint;
        HDC DeviceContext = BeginPaint(Window, &Paint);
        win32_window_dimension Dimension = Win32GetWindowDimension(Window);
        Win32DisplayBufferInWindow(DeviceContext, Dimension.Width, Dimension.Height, &GlobalBackBuffer);
        EndPaint(Window, &Paint);
      }
      break;
    default:
      {
        // OutputDebugStringA("default\n");
        Result = DefWindowProc(Window, Message, WParam, LParam);
      }
      break;
  }
  return(Result);
}

/**
 * Main du programme qui va initialiser la fentre et grer la boucle principale : attente des messages,
 * gestion de la manette et du clavier, dessin...
 **/
int CALLBACK
WinMain(
  HINSTANCE Instance,
  HINSTANCE PrevInstance,
  LPSTR CommandLine,
  int ShowCode)
{
  // On essaye de charger les fonctions de la dll qui gre les manettes
  Win32LoadXInput();

  // Cration de la fentre principale
  WNDCLASSA WindowClass = {}; // initialisation par dfaut, ANSI version de WNDCLASSA

  Win32ResizeDIBSection(&GlobalBackBuffer, 800, 600);

  // On ne configure que les membres que l'on veut
  WindowClass.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC; // indique que l'on veut rafraichir la fentre entire lors d'un resize (horizontal et vertical)
  WindowClass.lpfnWndProc = Win32MainWindowCallback;
  WindowClass.hInstance = Instance;
  // WindowClass.hIcon;
  WindowClass.lpszClassName = "FaitmainHerosWindowClass"; // nom pour retrouver la fentre

  // Ouverture de la fentre
  if (RegisterClassA(&WindowClass))
  {
    HWND Window = CreateWindowExA( // ANSI version de CreateWindowEx
      0, // dwExStyle : options de la fentre
      WindowClass.lpszClassName,
      "FaitmainHeros",
      WS_OVERLAPPEDWINDOW|WS_VISIBLE, //dwStyle : overlapped window, visible par dfaut
      CW_USEDEFAULT, // X
      CW_USEDEFAULT, // Y
      CW_USEDEFAULT, // nWidth
      CW_USEDEFAULT, // nHeight
      0, // hWndParent : 0 pour dire que c'est une fentre top
      0, // hMenu : 0 pour dire pas de menu
      Instance,
      0 // Pas de passage de paramtres  la fentre
    );
    if (Window)
    {
      // Comme on a spcifi CS_OWNDC on peut initialiser un seul HDC
      // et s'en servir indfiniment car on ne le partage pas
      HDC DeviceContext = GetDC(Window);

      int XOffset = 0;
      int YOffset = 0;
      GlobalRunning = true;

      while (GlobalRunning) // boucle infinie pour traiter tous les messages
      {
        MSG Message;
        while(PeekMessageA(&Message, 0, 0, 0, PM_REMOVE)) // On utilise PeekMessage au lieu de GetMessage qui est bloquant
        {
          if (Message.message == WM_QUIT) GlobalRunning = false;
          TranslateMessage(&Message); // On demande  Windows de traiter le message
          DispatchMessage(&Message); // Envoie le message au main WindowCallback, que l'on a dfini et dclar au dessus
        }

        // Gestion des entres, pour le moment on gre a  chaque image, il faudra peut-tre le faire plus frquemment
        // surtout si le nombre d'images par seconde chute
        for (DWORD ControllerIndex = 0; ControllerIndex < XUSER_MAX_COUNT; ++ControllerIndex)
        {
          XINPUT_STATE ControllerState;
          if (XInputGetState(ControllerIndex, &ControllerState) == ERROR_SUCCESS)
          {
            // Le controller est branch
            XINPUT_GAMEPAD *Pad = &ControllerState.Gamepad;

            bool Up = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_UP);
            bool Down = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN);
            bool Left = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT);
            bool Right = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT);
            bool Start = (Pad->wButtons & XINPUT_GAMEPAD_START);
            bool Back = (Pad->wButtons & XINPUT_GAMEPAD_BACK);
            bool LeftShoulder = (Pad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER);
            bool RightShoulder = (Pad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER);
            bool AButton = (Pad->wButtons & XINPUT_GAMEPAD_A);
            bool BButton = (Pad->wButtons & XINPUT_GAMEPAD_B);
            bool XButton = (Pad->wButtons & XINPUT_GAMEPAD_X);
            bool YButton = (Pad->wButtons & XINPUT_GAMEPAD_Y);

            uint16 StickX = Pad->sThumbLX;
            uint16 StickY = Pad->sThumbLY;

            // Test d'utilisation de la manette
            if (Up) YOffset += 2;
            if (Down) YOffset -= 2;
            if (Right) XOffset -= 4;

            // Vibration de la manette
            XINPUT_VIBRATION Vibration;
            if (Left)
            {
              Vibration.wLeftMotorSpeed = 60000;
              Vibration.wRightMotorSpeed = 60000;
            }
            else
            {
              Vibration.wLeftMotorSpeed = 0;
              Vibration.wRightMotorSpeed = 0;
            }
            XInputSetState(0, &Vibration);
          }
          else
          {
            // Le controlleur n'est pas branch
          }
        }

        // Grce  PeekMessage on a tout le temps CPU que l'on veut et on peut dessiner ici
        RenderWeirdGradient(&GlobalBackBuffer, XOffset, YOffset);
        ++XOffset;

        // On doit alors crire dans la fentre  chaque fois que l'on veut rendre
        // On en fera une fonction propre
        win32_window_dimension Dimension = Win32GetWindowDimension(Window);
        Win32DisplayBufferInWindow(
          DeviceContext,
          Dimension.Width, Dimension.Height,
          &GlobalBackBuffer);
        ReleaseDC(Window, DeviceContext);

        // Pour animer diffremment le gradient
        ++XOffset;
      }
    }
    else
    {
      OutputDebugStringA("Error: CreateWindowEx\n");
    }
  }
  else
  {
    OutputDebugStringA("Error: RegisterClass\n");
  }

  return(0);
};<|endoftext|>


<commit_before>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
  *
  * Condor Software Copyright Notice
  * Copyright (C) 1990-2006, Condor Team, Computer Sciences Department,
  * University of Wisconsin-Madison, WI.
  *
  * This source code is covered by the Condor Public License, which can
  * be found in the accompanying LICENSE.TXT file, or online at
  * www.condorproject.org.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * AND THE UNIVERSITY OF WISCONSIN-MADISON "AS IS" AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY, OF SATISFACTORY QUALITY, AND FITNESS
  * FOR A PARTICULAR PURPOSE OR USE ARE DISCLAIMED. THE COPYRIGHT
  * HOLDERS AND CONTRIBUTORS AND THE UNIVERSITY OF WISCONSIN-MADISON
  * MAKE NO MAKE NO REPRESENTATION THAT THE SOFTWARE, MODIFICATIONS,
  * ENHANCEMENTS OR DERIVATIVE WORKS THEREOF, WILL NOT INFRINGE ANY
  * PATENT, COPYRIGHT, TRADEMARK, TRADE SECRET OR OTHER PROPRIETARY
  * RIGHT.
  *
  ****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/

#define _CONDOR_ALLOW_OPEN 1   // because this is used in the test suite

/* the below is defined in test suite programs that use these files. */
#ifndef NO_CONDOR_COMMON
#include "condor_common.h"
#endif

#include "memory_file.h"
#include "condor_fix_iostream.h"

static const int DEFAULT_BUFFER_SIZE=1024;
static const int COMPARE_BUFFER_SIZE=10000;

memory_file::memory_file()
{
	buffer = new char[DEFAULT_BUFFER_SIZE];
	bufsize = DEFAULT_BUFFER_SIZE;
	memset(buffer, 0, bufsize);
	pointer = filesize = 0;
}

memory_file::~memory_file()
{
	if( buffer ) delete [] buffer;
}

/*
Compare this memory_file against a real file.
Return the number of errors found.
*/

int memory_file::compare( char *filename )
{
	int errors=0;
	off_t position=0, chunksize=0;
	char cbuffer[COMPARE_BUFFER_SIZE];

	int fd = open(filename,O_RDONLY);
	if( fd==-1 ) {
		cerr << "Couldn't open " << filename << endl;
		return 100;
	}

	while(1) {
		chunksize = ::read(fd,cbuffer,COMPARE_BUFFER_SIZE);
		if(chunksize<=0) break;

		errors += count_errors( cbuffer, &buffer[position], chunksize, position );
		position += chunksize;

		if( errors>10 ) {
			cout << "Too many errors, stopping.\n";
			break;
		}

	}

	if(position!=filesize) {
		cout << "SIZE ERROR:\nFile was " << position
		     << " bytes, but mem was " << filesize
		     << " bytes.\n";
		errors++;
	}

	::close(fd);

	return errors;
}

/*
Move the current seek pointer to a new position, as lseek(2).
Return the new pointer, or -1 in case of an error.
*/

off_t memory_file::seek( off_t offset, int whence )
{
	off_t newpointer;

	switch(whence) {
		case SEEK_SET:
		newpointer = offset;
		break;
		case SEEK_CUR:
		newpointer = pointer+offset;
		break;
		case SEEK_END:
		newpointer = filesize+offset;
		break;
	}

	if( newpointer<0 ) {
		return -1;
	} else {
		pointer = newpointer;
	}

	return pointer;
}

/*
Read from the simulated file, as read(2).
Returns the number of bytes read, or an error.
*/

ssize_t memory_file::read( char *data, size_t length )
{

	if( (data==0) || (length<0) || (pointer<0) ) return -1;
	if( pointer>=filesize ) return 0;

	if(length==0) return 0;

	if((pointer+(off_t)length)>filesize) length = filesize-pointer;
	memcpy(data,&buffer[pointer],length);

	pointer += length;
	return length;
}

/*
Write to the simulated file, as write(2).
Returns the number of bytes written, or an error.
*/

ssize_t memory_file::write( char *data, size_t length )
{
	if( (data==0) || (length<0) || (pointer<0) ) return -1;

	if(length==0) return 0;

	ensure(pointer+length);

	memcpy(&buffer[pointer],data,length);
	pointer+=length;
	if( pointer>filesize ) filesize=pointer;

	return length;
}

/*
Expand the buffer so that it can hold up to needed.
To minimize memory allocations, the buffer size is
increased by powers of two.
*/

void memory_file::ensure( int needed )
{
	if( needed>bufsize ) {
		int newsize = bufsize;
		while(newsize<needed) newsize*=2;

		char *newbuffer = new char[newsize];
		memcpy(newbuffer,buffer,bufsize);
		memset(&newbuffer[bufsize], 0, newsize-bufsize);
		delete [] buffer;
		buffer = newbuffer;
		bufsize = newsize;
	}
}

/*
Count the number of discrepancies between two buffers and
return that number.  Display any errors along the way.
*/

int count_errors( char *b1, char *b2, int length, int offset )
{
	int errors=0;

	for( int i=0; i<length; i++ ) {
		if( b1[i]!=b2[i] ) {
			if(!errors) cout << "FOUND ERROR:\npos\ta\tb\n";
			errors++;
			cout << (i+offset) << '\t' << (int)b1[i] << '\t' << (int)b2[i] << endl;
			if( errors>50 ) {
				cout << "Too many errors, stopping." << endl;
				return 50;
			}
		}
	}

	return errors;
}

<commit_msg>remove warning<commit_after>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
  *
  * Condor Software Copyright Notice
  * Copyright (C) 1990-2006, Condor Team, Computer Sciences Department,
  * University of Wisconsin-Madison, WI.
  *
  * This source code is covered by the Condor Public License, which can
  * be found in the accompanying LICENSE.TXT file, or online at
  * www.condorproject.org.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * AND THE UNIVERSITY OF WISCONSIN-MADISON "AS IS" AND ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY, OF SATISFACTORY QUALITY, AND FITNESS
  * FOR A PARTICULAR PURPOSE OR USE ARE DISCLAIMED. THE COPYRIGHT
  * HOLDERS AND CONTRIBUTORS AND THE UNIVERSITY OF WISCONSIN-MADISON
  * MAKE NO MAKE NO REPRESENTATION THAT THE SOFTWARE, MODIFICATIONS,
  * ENHANCEMENTS OR DERIVATIVE WORKS THEREOF, WILL NOT INFRINGE ANY
  * PATENT, COPYRIGHT, TRADEMARK, TRADE SECRET OR OTHER PROPRIETARY
  * RIGHT.
  *
  ****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/

#define _CONDOR_ALLOW_OPEN 1   // because this is used in the test suite

/* the below is defined in test suite programs that use these files. */
#ifndef NO_CONDOR_COMMON
#include "condor_common.h"
#endif

#include "memory_file.h"
#include "condor_fix_iostream.h"

static const int DEFAULT_BUFFER_SIZE=1024;
static const int COMPARE_BUFFER_SIZE=10000;

memory_file::memory_file()
{
	buffer = new char[DEFAULT_BUFFER_SIZE];
	bufsize = DEFAULT_BUFFER_SIZE;
	memset(buffer, 0, bufsize);
	pointer = filesize = 0;
}

memory_file::~memory_file()
{
	if( buffer ) delete [] buffer;
}

/*
Compare this memory_file against a real file.
Return the number of errors found.
*/

int memory_file::compare( char *filename )
{
	int errors=0;
	off_t position=0, chunksize=0;
	char cbuffer[COMPARE_BUFFER_SIZE];

	int fd = open(filename,O_RDONLY);
	if( fd==-1 ) {
		cerr << "Couldn't open " << filename << endl;
		return 100;
	}

	while(1) {
		chunksize = ::read(fd,cbuffer,COMPARE_BUFFER_SIZE);
		if(chunksize<=0) break;

		errors += count_errors( cbuffer, &buffer[position], chunksize, position );
		position += chunksize;

		if( errors>10 ) {
			cout << "Too many errors, stopping.\n";
			break;
		}

	}

	if(position!=filesize) {
		cout << "SIZE ERROR:\nFile was " << position
		     << " bytes, but mem was " << filesize
		     << " bytes.\n";
		errors++;
	}

	::close(fd);

	return errors;
}

/*
Move the current seek pointer to a new position, as lseek(2).
Return the new pointer, or -1 in case of an error.
*/

off_t memory_file::seek( off_t offset, int whence )
{
	off_t newpointer;

	switch(whence) {
		case SEEK_SET:
		newpointer = offset;
		break;
		case SEEK_CUR:
		newpointer = pointer+offset;
		break;
		case SEEK_END:
		newpointer = filesize+offset;
		break;
	}

	if( newpointer<0 ) {
		return -1;
	} else {
		pointer = newpointer;
	}

	return pointer;
}

/*
Read from the simulated file, as read(2).
Returns the number of bytes read, or an error.
*/

ssize_t memory_file::read( char *data, size_t length )
{

	if( (data==0) || (pointer<0) ) return -1;
	if( pointer>=filesize ) return 0;

	if(length==0) return 0;

	if((pointer+(off_t)length)>filesize) length = filesize-pointer;
	memcpy(data,&buffer[pointer],length);

	pointer += length;
	return length;
}

/*
Write to the simulated file, as write(2).
Returns the number of bytes written, or an error.
*/

ssize_t memory_file::write( char *data, size_t length )
{
	if( (data==0) || (pointer<0) ) return -1;

	if(length==0) return 0;

	ensure(pointer+length);

	memcpy(&buffer[pointer],data,length);
	pointer+=length;
	if( pointer>filesize ) filesize=pointer;

	return length;
}

/*
Expand the buffer so that it can hold up to needed.
To minimize memory allocations, the buffer size is
increased by powers of two.
*/

void memory_file::ensure( int needed )
{
	if( needed>bufsize ) {
		int newsize = bufsize;
		while(newsize<needed) newsize*=2;

		char *newbuffer = new char[newsize];
		memcpy(newbuffer,buffer,bufsize);
		memset(&newbuffer[bufsize], 0, newsize-bufsize);
		delete [] buffer;
		buffer = newbuffer;
		bufsize = newsize;
	}
}

/*
Count the number of discrepancies between two buffers and
return that number.  Display any errors along the way.
*/

int count_errors( char *b1, char *b2, int length, int offset )
{
	int errors=0;

	for( int i=0; i<length; i++ ) {
		if( b1[i]!=b2[i] ) {
			if(!errors) cout << "FOUND ERROR:\npos\ta\tb\n";
			errors++;
			cout << (i+offset) << '\t' << (int)b1[i] << '\t' << (int)b2[i] << endl;
			if( errors>50 ) {
				cout << "Too many errors, stopping." << endl;
				return 50;
			}
		}
	}

	return errors;
}

<|endoftext|>


<commit_before>#include "texture.h"

#include "platform.h"
#include "util/geom.h"
#include "gl/renderState.h"

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

#include <cstring> // for memset

namespace Tangram {

int Texture::s_validGeneration = 0;

Texture::Texture(unsigned int _width, unsigned int _height, TextureOptions _options, bool _generateMipmaps)
    : m_options(_options), m_generateMipmaps(_generateMipmaps) {

    m_glHandle = 0;
    m_dirty = false;
    m_shouldResize = false;
    m_target = GL_TEXTURE_2D;
    m_generation = -1;

    resize(_width, _height);
}

Texture::Texture(const std::string& _file, TextureOptions _options, bool _generateMipmaps)
    : Texture(0, 0, _options, _generateMipmaps) {

    unsigned int size;
    unsigned char* data = bytesFromResource(_file.c_str(), &size);
    unsigned char* pixels;
    int width, height, comp;

    pixels = stbi_load_from_memory(data, size, &width, &height, &comp, STBI_rgb_alpha);

    resize(width, height);
    setData(reinterpret_cast<GLuint*>(pixels), width * height);
    update(0);

    free(data);
    stbi_image_free(pixels);
}

Texture::~Texture() {
    if (m_glHandle) {
        glDeleteTextures(1, &m_glHandle);

        // if the texture is bound, and deleted, the binding defaults to 0 according to the OpenGL
        // spec, in this case we need to force the currently bound texture to 0 in the render states
        if (RenderState::texture.compare(m_target, m_glHandle)) {
            RenderState::texture.init(m_target, 0, false);
        }
    }
}

void Texture::setData(const GLuint* _data, unsigned int _dataSize) {

    if (m_data.size() > 0) { m_data.clear(); }

    m_data.insert(m_data.begin(), _data, _data + _dataSize);

    m_dirty = true;
}

void Texture::setSubData(const GLuint* _subData, unsigned int _xoff, unsigned int _yoff, unsigned int _width,
                         unsigned int _height) {

    // update m_data with subdata
    size_t bpp = bytesPerPixel();
    size_t divisor = sizeof(GLuint) / bpp;
    for (size_t j = 0; j < _height; j++) {
        size_t dpos = ((j + _yoff) * m_width + _xoff) / divisor;
        size_t spos = (j * _width) / divisor;
        std::memcpy(&m_data[dpos], &_subData[spos], _width * bpp);
    }

    m_subData.push_back({{_subData, _subData + (_width * _height) / divisor}, _xoff, _yoff, _width, _height});

    m_dirty = true;
}

void Texture::bind(GLuint _unit) {
    RenderState::textureUnit(_unit);
    RenderState::texture(m_target, m_glHandle);
}

void Texture::generate(GLuint _textureUnit) {
    glGenTextures(1, &m_glHandle);

    bind(_textureUnit);

    if (m_generateMipmaps) {
        GLenum mipmapFlags = GL_LINEAR_MIPMAP_LINEAR | GL_LINEAR_MIPMAP_NEAREST | GL_NEAREST_MIPMAP_LINEAR | GL_NEAREST_MIPMAP_NEAREST;
        if (m_options.m_filtering.m_min & mipmapFlags) {
            logMsg("Warning: wrong options provided for the usage of mipmap generation\n");
        }
    }

    glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, m_options.m_filtering.m_min);
    glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, m_options.m_filtering.m_mag);

    glTexParameteri(m_target, GL_TEXTURE_WRAP_S, m_options.m_wrapping.m_wraps);
    glTexParameteri(m_target, GL_TEXTURE_WRAP_T, m_options.m_wrapping.m_wrapt);

    m_generation = s_validGeneration;
}

void Texture::checkValidity() {

    if (m_generation != s_validGeneration) {
        m_dirty = true;
        m_shouldResize = true;
        m_glHandle = 0;
    }
}

void Texture::update(GLuint _textureUnit) {

    checkValidity();

    if (!m_dirty) { return; }

    if (m_glHandle == 0) { // texture hasn't been initialized yet, generate it

        generate(_textureUnit);

        if (m_data.size() == 0) { m_data.assign(m_width * m_height, 0); }

    } else {
        bind(_textureUnit);
    }

    GLuint* data = m_data.size() > 0 ? m_data.data() : nullptr;

    // resize or push data
    if (m_shouldResize) {
        glTexImage2D(m_target, 0, m_options.m_internalFormat, m_width, m_height, 0, m_options.m_format, GL_UNSIGNED_BYTE, data);

        if (data && m_generateMipmaps) {
            // generate the mipmaps for this texture
            glGenerateMipmap(m_target);
        }

        m_shouldResize = false;
    }

    // process queued sub data updates
    while (m_subData.size() > 0) {
        TextureSubData& subData = m_subData.front();

        glTexSubImage2D(m_target, 0, subData.m_xoff, subData.m_yoff, subData.m_width, subData.m_height,
                        m_options.m_format, GL_UNSIGNED_BYTE, subData.m_data.data());

        m_subData.pop();
    }

    m_dirty = false;
}

void Texture::resize(const unsigned int _width, const unsigned int _height) {
    m_width = _width;
    m_height = _height;

    m_shouldResize = true;
    m_dirty = true;
}

size_t Texture::bytesPerPixel() {
    switch (m_options.m_internalFormat) {
        case GL_ALPHA:
        case GL_LUMINANCE:
            return 1;
        case GL_LUMINANCE_ALPHA:
            return 2;
        case GL_RGB:
            return 3;
        default:
            return 4;
    }
}

void Texture::invalidateAllTextures() {

    ++s_validGeneration;

}

}
<commit_msg>fix: initialization of Texture m_data<commit_after>#include "texture.h"

#include "platform.h"
#include "util/geom.h"
#include "gl/renderState.h"

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

#include <cstring> // for memset

namespace Tangram {

int Texture::s_validGeneration = 0;

Texture::Texture(unsigned int _width, unsigned int _height, TextureOptions _options, bool _generateMipmaps)
    : m_options(_options), m_generateMipmaps(_generateMipmaps) {

    m_glHandle = 0;
    m_dirty = false;
    m_shouldResize = false;
    m_target = GL_TEXTURE_2D;
    m_generation = -1;

    resize(_width, _height);
}

Texture::Texture(const std::string& _file, TextureOptions _options, bool _generateMipmaps)
    : Texture(0, 0, _options, _generateMipmaps) {

    unsigned int size;
    unsigned char* data = bytesFromResource(_file.c_str(), &size);
    unsigned char* pixels;
    int width, height, comp;

    pixels = stbi_load_from_memory(data, size, &width, &height, &comp, STBI_rgb_alpha);

    resize(width, height);
    setData(reinterpret_cast<GLuint*>(pixels), width * height);
    update(0);

    free(data);
    stbi_image_free(pixels);
}

Texture::~Texture() {
    if (m_glHandle) {
        glDeleteTextures(1, &m_glHandle);

        // if the texture is bound, and deleted, the binding defaults to 0 according to the OpenGL
        // spec, in this case we need to force the currently bound texture to 0 in the render states
        if (RenderState::texture.compare(m_target, m_glHandle)) {
            RenderState::texture.init(m_target, 0, false);
        }
    }
}

void Texture::setData(const GLuint* _data, unsigned int _dataSize) {

    if (m_data.size() > 0) { m_data.clear(); }

    m_data.insert(m_data.begin(), _data, _data + _dataSize);

    m_dirty = true;
}

void Texture::setSubData(const GLuint* _subData, unsigned int _xoff, unsigned int _yoff, unsigned int _width,
                         unsigned int _height) {
    size_t bpp = bytesPerPixel();
    size_t divisor = sizeof(GLuint) / bpp;

    // Init m_data if update() was not called after resize()
    if (m_data.size() != (m_width * m_height) / divisor) {
        m_data.resize((m_width * m_height) / divisor);
    }

    // update m_data with subdata
    for (size_t j = 0; j < _height; j++) {
        size_t dpos = ((j + _yoff) * m_width + _xoff) / divisor;
        size_t spos = (j * _width) / divisor;
        std::memcpy(&m_data[dpos], &_subData[spos], _width * bpp);
    }

    m_subData.push_back({{_subData, _subData + (_width * _height) / divisor}, _xoff, _yoff, _width, _height});

    m_dirty = true;
}

void Texture::bind(GLuint _unit) {
    RenderState::textureUnit(_unit);
    RenderState::texture(m_target, m_glHandle);
}

void Texture::generate(GLuint _textureUnit) {
    glGenTextures(1, &m_glHandle);

    bind(_textureUnit);

    if (m_generateMipmaps) {
        GLenum mipmapFlags = GL_LINEAR_MIPMAP_LINEAR | GL_LINEAR_MIPMAP_NEAREST | GL_NEAREST_MIPMAP_LINEAR | GL_NEAREST_MIPMAP_NEAREST;
        if (m_options.m_filtering.m_min & mipmapFlags) {
            logMsg("Warning: wrong options provided for the usage of mipmap generation\n");
        }
    }

    glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, m_options.m_filtering.m_min);
    glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, m_options.m_filtering.m_mag);

    glTexParameteri(m_target, GL_TEXTURE_WRAP_S, m_options.m_wrapping.m_wraps);
    glTexParameteri(m_target, GL_TEXTURE_WRAP_T, m_options.m_wrapping.m_wrapt);

    m_generation = s_validGeneration;
}

void Texture::checkValidity() {

    if (m_generation != s_validGeneration) {
        m_dirty = true;
        m_shouldResize = true;
        m_glHandle = 0;
    }
}

void Texture::update(GLuint _textureUnit) {

    checkValidity();

    if (!m_dirty) { return; }

    if (m_glHandle == 0) { // texture hasn't been initialized yet, generate it

        generate(_textureUnit);

        if (m_data.size() == 0) {
            size_t divisor = sizeof(GLuint) / bytesPerPixel();
            m_data.resize((m_width * m_height) / divisor, 0);
        }

    } else {
        bind(_textureUnit);
    }

    GLuint* data = m_data.size() > 0 ? m_data.data() : nullptr;

    // resize or push data
    if (m_shouldResize) {
        glTexImage2D(m_target, 0, m_options.m_internalFormat, m_width, m_height, 0, m_options.m_format, GL_UNSIGNED_BYTE, data);

        if (data && m_generateMipmaps) {
            // generate the mipmaps for this texture
            glGenerateMipmap(m_target);
        }

        m_shouldResize = false;
    }

    // process queued sub data updates
    while (m_subData.size() > 0) {
        TextureSubData& subData = m_subData.front();

        glTexSubImage2D(m_target, 0, subData.m_xoff, subData.m_yoff, subData.m_width, subData.m_height,
                        m_options.m_format, GL_UNSIGNED_BYTE, subData.m_data.data());

        m_subData.pop();
    }

    m_dirty = false;
}

void Texture::resize(const unsigned int _width, const unsigned int _height) {
    m_width = _width;
    m_height = _height;

    m_shouldResize = true;
    m_dirty = true;
}

size_t Texture::bytesPerPixel() {
    switch (m_options.m_internalFormat) {
        case GL_ALPHA:
        case GL_LUMINANCE:
            return 1;
        case GL_LUMINANCE_ALPHA:
            return 2;
        case GL_RGB:
            return 3;
        default:
            return 4;
    }
}

void Texture::invalidateAllTextures() {

    ++s_validGeneration;

}

}
<|endoftext|>