<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "mediasource.h"
#include "mediasource_p.h"
#include "iodevicestream.h"
#include "abstractmediastream_p.h"

#include <QtCore/QFileInfo>
#include <QtCore/QFile>
#include <QtCore/QFSFileEngine>

QT_BEGIN_NAMESPACE

namespace Phonon
{

MediaSource::MediaSource(MediaSourcePrivate &dd)
    : d(&dd)
{
}

MediaSource::MediaSource()
    : d(new MediaSourcePrivate(Invalid))
{
}

MediaSource::MediaSource(const QString &filename)
    : d(new MediaSourcePrivate(LocalFile))
{
    const QFileInfo fileInfo(filename);
    if (fileInfo.exists()) {
        bool localFs = QFSFileEngine(filename).fileFlags(QAbstractFileEngine::LocalDiskFlag);
        if (localFs) {
            d->url = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
        } else {
            // it's a Qt resource -> use QFile
            d->type = Stream;
            d->ioDevice = new QFile(filename);
            d->stream = new IODeviceStream(d->ioDevice, d->ioDevice);
        }
    } else if (QUrl(filename).isValid()) {
        d->url = filename;
        d->type = Url;
    } else {
        d->type = Invalid;
    }
}

MediaSource::MediaSource(const QUrl &url)
    : d(new MediaSourcePrivate(Url))
{
    if (url.isValid()) {
        d->url = url;
    } else {
        d->type = Invalid;
    }
}

MediaSource::MediaSource(Phonon::DiscType dt, const QString &deviceName)
    : d(new MediaSourcePrivate(Disc))
{
    if (dt == NoDisc) {
        d->type = Invalid;
        return;
    }
    d->discType = dt;
    d->deviceName = deviceName;
}

MediaSource::MediaSource(AbstractMediaStream *stream)
    : d(new MediaSourcePrivate(Stream))
{
    if (stream) {
        d->stream = stream;
    } else {
        d->type = Invalid;
    }
}

MediaSource::MediaSource(QIODevice *ioDevice)
    : d(new MediaSourcePrivate(Stream))
{
    if (ioDevice) {
        d->stream = new IODeviceStream(ioDevice, ioDevice);
        d->ioDevice = ioDevice;
    } else {
        d->type = Invalid;
    }
}

/* post 4.0
MediaSource::MediaSource(const QList<MediaSource> &mediaList)
    : d(new MediaSourcePrivate(Link))
{
    d->linkedSources = mediaList;
    foreach (MediaSource ms, mediaList) {
        Q_ASSERT(ms.type() != Link);
    }
}

QList<MediaSource> MediaSource::substreams() const
{
    return d->linkedSources;
}
*/

MediaSource::~MediaSource()
{
}

MediaSource::MediaSource(const MediaSource &rhs)
    : d(rhs.d)
{
}

MediaSource &MediaSource::operator=(const MediaSource &rhs)
{
    d = rhs.d;
    return *this;
}

bool MediaSource::operator==(const MediaSource &rhs) const
{
    return d == rhs.d;
}

void MediaSource::setAutoDelete(bool autoDelete)
{
    d->autoDelete = autoDelete;
}

bool MediaSource::autoDelete() const
{
    return d->autoDelete;
}

MediaSource::Type MediaSource::type() const
{
    if (d->type == Stream && d->stream == 0) {
        return Invalid;
    }
    return d->type;
}

QString MediaSource::fileName() const
{
    return d->url.toLocalFile();
}

QUrl MediaSource::url() const
{
    return d->url;
}

Phonon::DiscType MediaSource::discType() const
{
    return d->discType;
}

QString MediaSource::deviceName() const
{
    return d->deviceName;
}

AbstractMediaStream *MediaSource::stream() const
{
    return d->stream;
}

//X AudioCaptureDevice MediaSource::audioCaptureDevice() const
//X {
//X     return d->audioCaptureDevice;
//X }
//X
//X VideoCaptureDevice MediaSource::videoCaptureDevice() const
//X {
//X     return d->videoCaptureDevice;
//X }

} // namespace Phonon

QT_END_NAMESPACE

// vim: sw=4 sts=4 et tw=100
<commit_msg>small perf improvement (QUrl is only parsed once)<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "mediasource.h"
#include "mediasource_p.h"
#include "iodevicestream.h"
#include "abstractmediastream_p.h"

#include <QtCore/QFileInfo>
#include <QtCore/QFile>
#include <QtCore/QFSFileEngine>

QT_BEGIN_NAMESPACE

namespace Phonon
{

MediaSource::MediaSource(MediaSourcePrivate &dd)
    : d(&dd)
{
}

MediaSource::MediaSource()
    : d(new MediaSourcePrivate(Invalid))
{
}

MediaSource::MediaSource(const QString &filename)
    : d(new MediaSourcePrivate(LocalFile))
{
    const QFileInfo fileInfo(filename);
    if (fileInfo.exists()) {
        bool localFs = QFSFileEngine(filename).fileFlags(QAbstractFileEngine::LocalDiskFlag);
        if (localFs) {
            d->url = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
        } else {
            // it's a Qt resource -> use QFile
            d->type = Stream;
            d->ioDevice = new QFile(filename);
            d->stream = new IODeviceStream(d->ioDevice, d->ioDevice);
        }
    } else {
        d->url = filename;
        if (d->url.isValid()) {
            d->type = Url;
        } else {
            d->type = Invalid;
        }
    }
}

MediaSource::MediaSource(const QUrl &url)
    : d(new MediaSourcePrivate(Url))
{
    if (url.isValid()) {
        d->url = url;
    } else {
        d->type = Invalid;
    }
}

MediaSource::MediaSource(Phonon::DiscType dt, const QString &deviceName)
    : d(new MediaSourcePrivate(Disc))
{
    if (dt == NoDisc) {
        d->type = Invalid;
        return;
    }
    d->discType = dt;
    d->deviceName = deviceName;
}

MediaSource::MediaSource(AbstractMediaStream *stream)
    : d(new MediaSourcePrivate(Stream))
{
    if (stream) {
        d->stream = stream;
    } else {
        d->type = Invalid;
    }
}

MediaSource::MediaSource(QIODevice *ioDevice)
    : d(new MediaSourcePrivate(Stream))
{
    if (ioDevice) {
        d->stream = new IODeviceStream(ioDevice, ioDevice);
        d->ioDevice = ioDevice;
    } else {
        d->type = Invalid;
    }
}

/* post 4.0
MediaSource::MediaSource(const QList<MediaSource> &mediaList)
    : d(new MediaSourcePrivate(Link))
{
    d->linkedSources = mediaList;
    foreach (MediaSource ms, mediaList) {
        Q_ASSERT(ms.type() != Link);
    }
}

QList<MediaSource> MediaSource::substreams() const
{
    return d->linkedSources;
}
*/

MediaSource::~MediaSource()
{
}

MediaSource::MediaSource(const MediaSource &rhs)
    : d(rhs.d)
{
}

MediaSource &MediaSource::operator=(const MediaSource &rhs)
{
    d = rhs.d;
    return *this;
}

bool MediaSource::operator==(const MediaSource &rhs) const
{
    return d == rhs.d;
}

void MediaSource::setAutoDelete(bool autoDelete)
{
    d->autoDelete = autoDelete;
}

bool MediaSource::autoDelete() const
{
    return d->autoDelete;
}

MediaSource::Type MediaSource::type() const
{
    if (d->type == Stream && d->stream == 0) {
        return Invalid;
    }
    return d->type;
}

QString MediaSource::fileName() const
{
    return d->url.toLocalFile();
}

QUrl MediaSource::url() const
{
    return d->url;
}

Phonon::DiscType MediaSource::discType() const
{
    return d->discType;
}

QString MediaSource::deviceName() const
{
    return d->deviceName;
}

AbstractMediaStream *MediaSource::stream() const
{
    return d->stream;
}

//X AudioCaptureDevice MediaSource::audioCaptureDevice() const
//X {
//X     return d->audioCaptureDevice;
//X }
//X
//X VideoCaptureDevice MediaSource::videoCaptureDevice() const
//X {
//X     return d->videoCaptureDevice;
//X }

} // namespace Phonon

QT_END_NAMESPACE

// vim: sw=4 sts=4 et tw=100
<|endoftext|>


<commit_before>/**
 *  Purity in C++17
 *  ===============
 *
 *  Very naive attempt.
 *
 *  Note: Compile with -std=c++17.
 */

#include <tuple>

namespace ppio {

template <auto F()>
static constexpr auto
fapply() noexcept
{
	static_assert(noexcept(F()), "constant function required");

	if constexpr (!std::is_same<decltype(F()), void>::value) {
		constexpr auto ret = F();
		return ret;
	}

	F();
}

template <auto F()>
static constexpr bool
is_f_pure() noexcept
{
	return noexcept(F());
}

template <typename F, typename G>
static constexpr auto
lapply(F f, G g) noexcept
{
	static_assert(noexcept(g()), "no-param lambda required at arg#1");

	// `else' branch cannot be omitted with `constexpr'.
	if constexpr (std::is_same<decltype(g()), void>::value) {
		if constexpr (std::is_same<decltype(f()), void>::value) {
			f();
			return;
		} else {
			constexpr auto ret = f();
			return ret;
		}
	} else {
		if constexpr (std::is_same<decltype(f(g())), void>::value) {
			f(g());
			return;
		}

		constexpr auto ret = f(g());
		return ret;
	}
}

template <typename F, typename G>
static constexpr bool
is_l_pure(F f, G g) noexcept
{
	constexpr bool is_g = noexcept(g());
	if constexpr (std::is_same<decltype(g()), void>::value) {
		return noexcept(f());
	} else {
		return noexcept(f(g())) && is_g;
	}
}

} /* namespace ppio */

template <auto N>
constexpr auto
foo()
{
	return N * 2;
}

template <auto X, auto Y>
constexpr auto
bar()
{
	return foo<X + Y>();
}

template <auto N>
constexpr auto
baz()
{
	return N + 1;
}

constexpr void
qux()
{
	/* nop */
}

int i = 0;

void
quux() noexcept
{
	++i;
}

int
main()
{
	/**
	 *  Basic.
	 */

	constexpr auto n0 = ppio::fapply<bar<0, 42>>();
	static_assert(n0 == 84, "foo bar oops");
	static_assert(ppio::fapply<baz<n0>>() == 85, "baz oops");

	auto f_vals = [] {
		return std::make_tuple(0, 42);
	};
	auto f_swap = [](auto args) {
		auto [a, b] = args;
		return std::make_tuple(b, a);
	};
	constexpr auto n1 = ppio::lapply(f_swap, f_vals);
	static_assert(std::get<0>(n1) == 42 && std::get<1>(n1) == 0,
				  "lambda oops");

	/**
	 *  Test functions/lambdas with return type `void'.
	 */

	ppio::fapply<qux>();

	auto f_return_nil = [] {};
	auto f_invoke_nil = [] {};
	ppio::lapply(f_invoke_nil, f_return_nil);

	/**
	 *  Test functions/lambdas with side-effects.
	 */

	static_assert(!ppio::is_f_pure<quux>(), "don't touch i yo");

	auto f = [] { return 42; };
	auto f_inc_i = [](auto n) {
		++i;
		return n;
	};
	static_assert(!ppio::is_l_pure(f_inc_i, f), "don't touch i yo");

	return 0;
}
<commit_msg>updated purity1z: constexpr on return type guarantees a core const expr<commit_after>/**
 *  Purity in C++17
 *  ===============
 *
 *  Very naive attempt.
 *
 *  Note: Compile with -std=c++17.
 */

#include <tuple>

namespace ppio {

template <auto F()>
static constexpr auto
fapply() noexcept
{
	static_assert(noexcept(F()), "constant function required");
	return F();
}

template <auto F()>
static constexpr bool
is_f_pure() noexcept
{
	return noexcept(F());
}

template <typename F, typename G>
static constexpr auto
lapply(F f, G g) noexcept
{
	static_assert(noexcept(g()), "no-param lambda required at arg#1");

	// `else' branch cannot be omitted with `constexpr'.
	if constexpr (std::is_same<decltype(g()), void>::value) {
		return f();
	} else {
		return f(g());
	}
}

template <typename F, typename G>
static constexpr bool
is_l_pure(F f, G g) noexcept
{
	constexpr bool is_g = noexcept(g());
	if constexpr (std::is_same<decltype(g()), void>::value) {
		return noexcept(f());
	} else {
		return noexcept(f(g())) && is_g;
	}
}

} /* namespace ppio */

template <auto N>
constexpr auto
foo()
{
	return N * 2;
}

template <auto X, auto Y>
constexpr auto
bar()
{
	return foo<X + Y>();
}

template <auto N>
constexpr auto
baz()
{
	return N + 1;
}

constexpr void
qux()
{
	/* nop */
}

int i = 0;

void
quux() noexcept
{
	++i;
}

int
main()
{
	/**
	 *  Basic.
	 */

	constexpr auto n0 = ppio::fapply<bar<0, 42>>();
	static_assert(n0 == 84, "foo bar oops");
	static_assert(ppio::fapply<baz<n0>>() == 85, "baz oops");

	auto f_vals = [] {
		return std::make_tuple(0, 42);
	};
	auto f_swap = [](auto args) {
		auto [a, b] = args;
		return std::make_tuple(b, a);
	};
	constexpr auto n1 = ppio::lapply(f_swap, f_vals);
	static_assert(std::get<0>(n1) == 42 && std::get<1>(n1) == 0,
				  "lambda oops");

	/**
	 *  Test functions/lambdas with return type `void'.
	 */

	ppio::fapply<qux>();

	auto f_return_nil = [] {};
	auto f_invoke_nil = [] {};
	ppio::lapply(f_invoke_nil, f_return_nil);

	/**
	 *  Test functions/lambdas with side-effects.
	 */

	static_assert(!ppio::is_f_pure<quux>(), "don't touch i yo");

	auto f = [] { return 42; };
	auto f_inc_i = [](auto n) {
		++i;
		return n;
	};
	static_assert(!ppio::is_l_pure(f_inc_i, f), "don't touch i yo");

	return 0;
}
<|endoftext|>


<commit_before>/*
 * Menu creation and other helper functions.
 * By 2MB Solutions (https://2mb.solutions)
 * Provided under the MIT license. See license.txt for details.
 * Billy: https://stormdragon.tk
 * Michael: https://michaeltaboada.me
*/
#include <dynamic_menu.h>
#include <string>
#include <vector>
#include <misc.h>
#include <soundplayer.h>
using std::string;
using std::vector;

dynamic_menu* create_menu(vector<string> items, vector<string> sounditems, vector<int(*)(dynamic_menu*, int, void*)> vec = vector<int(*)(dynamic_menu*, int, void*)>(), vector<void*> vec2 = vector<void*>()) {
int soundnumber = sounditems.size();
int numberofitems = items.size();
dynamic_menu* menu = new dynamic_menu((numberofitems > soundnumber)?numberofitems:soundnumber);
for(int x = 1; x <= numberofitems; x++) {
if(items[x-1] != "") {
menu->add_item_text(items[x-1], x, ((vec.size() >= x)?vec[x-1]:NULL), ((vec2.size() >= x)?vec2[x-1]:NULL));
}
}
for(int y = 1; y <= soundnumber; y++) {
if(sounditems[y-1] != "") {
menu->add_item_sound(sounditems[y-1], y, ((vec.size() >= y)?vec[y-1]:NULL), ((vec2.size() >= y)?vec2[y-1]:NULL));
}
}
return menu;
}

vector<string>* get_dir_children(string dir, int dir_or_file) {
ALLEGRO_FS_ENTRY *f = al_create_fs_entry((((string)(al_path_cstr(al_get_standard_path(ALLEGRO_RESOURCES_PATH), '/')))+dir).c_str());
if(!f) {
return NULL;
}
if(al_open_directory(f)) {
vector<string>* vec = new vector<string>();
ALLEGRO_FS_ENTRY *fs = al_read_directory(f);
while(fs) {
const char* fn = al_get_fs_entry_name(fs);
string fsn = "";
int x;
for(x = strlen(fn)-1; x >= 0; x--) {
if(fn[x] == '/' || fn[x] == '\\') {
break;
}
}
for(int y = x+1; y < strlen(fn); y++) {
fsn += fn[y];
}
if(dir_or_file == 0) {
vec->push_back(fsn);
}
else if(dir_or_file == 1 && (al_get_fs_entry_mode(fs) & ALLEGRO_FILEMODE_ISFILE) == ALLEGRO_FILEMODE_ISFILE) {
vec->push_back(fsn);
}
else if(dir_or_file == 2 && (al_get_fs_entry_mode(fs) & ALLEGRO_FILEMODE_ISDIR) == ALLEGRO_FILEMODE_ISDIR){
vec->push_back(fsn);
}
if(fs) {
al_destroy_fs_entry(fs);
}
fs = al_read_directory(f);
}
al_close_directory(f);
al_destroy_fs_entry(f);
return vec;
}
else {
al_destroy_fs_entry(f);
return NULL;
}
}

string generic_menu(vector<string> extra_items, string music = "") {
sound menu_music;
if(music != "") {
menu_music.load(music);
menu_music.set_loop(true);
menu_music.play();
}
	vector<string> real_items;
real_items.push_back("Play game");
real_items.push_back("View instructions");
real_items.push_back("Learn game sounds.");
for (int x = 0; x < extra_items.size(); x++) {
real_items.push_back(extra_items[x]);
}
real_items.push_back("view credits");
real_items.push_back("Exit game");
dynamic_menu* menu = create_menu(real_items, vector<string>());
int pos = -1;
do {
	pos = menu->run_extended("", "Use your arrow keys to navigate the menu, and enter to select.", 1, true);
if(pos == 1) {
if(music != "")
	fade(&menu_music);
	return "play";
}
else if(pos == extra_items.size()+4) {
credits();
}
else if(pos == 2) {
instructions();
}
else if(pos == 3) {
if(music != "")
	fade(&menu_music);
	learn_sounds();
if(music != "") {
	menu_music.set_gain(0);
menu_music.play();
}
}
else if (pos == extra_items.size()+5) {
if(music != "")
	fade(&menu_music);
	return "exit";
}
else {
if(music != "")
	fade(&menu_music);
	return extra_items[pos-3];
}
}
while (pos != -1 && pos != 0 & pos != extra_items.size()+5);
if(music != "")
menu_music.stop();
return "invalid";
}

<commit_msg>Fixed crash in generic_menu<commit_after>/*
 * Menu creation and other helper functions.
 * By 2MB Solutions (https://2mb.solutions)
 * Provided under the MIT license. See license.txt for details.
 * Billy: https://stormdragon.tk
 * Michael: https://michaeltaboada.me
*/
#include <dynamic_menu.h>
#include <string>
#include <vector>
#include <misc.h>
#include <soundplayer.h>
using std::string;
using std::vector;

dynamic_menu* create_menu(vector<string> items, vector<string> sounditems, vector<int(*)(dynamic_menu*, int, void*)> vec = vector<int(*)(dynamic_menu*, int, void*)>(), vector<void*> vec2 = vector<void*>()) {
int soundnumber = sounditems.size();
int numberofitems = items.size();
dynamic_menu* menu = new dynamic_menu((numberofitems > soundnumber)?numberofitems:soundnumber);
for(int x = 1; x <= numberofitems; x++) {
if(items[x-1] != "") {
menu->add_item_text(items[x-1], x, ((vec.size() >= x)?vec[x-1]:NULL), ((vec2.size() >= x)?vec2[x-1]:NULL));
}
}
for(int y = 1; y <= soundnumber; y++) {
if(sounditems[y-1] != "") {
menu->add_item_sound(sounditems[y-1], y, ((vec.size() >= y)?vec[y-1]:NULL), ((vec2.size() >= y)?vec2[y-1]:NULL));
}
}
return menu;
}

vector<string>* get_dir_children(string dir, int dir_or_file) {
ALLEGRO_FS_ENTRY *f = al_create_fs_entry((((string)(al_path_cstr(al_get_standard_path(ALLEGRO_RESOURCES_PATH), '/')))+dir).c_str());
if(!f) {
return NULL;
}
if(al_open_directory(f)) {
vector<string>* vec = new vector<string>();
ALLEGRO_FS_ENTRY *fs = al_read_directory(f);
while(fs) {
const char* fn = al_get_fs_entry_name(fs);
string fsn = "";
int x;
for(x = strlen(fn)-1; x >= 0; x--) {
if(fn[x] == '/' || fn[x] == '\\') {
break;
}
}
for(int y = x+1; y < strlen(fn); y++) {
fsn += fn[y];
}
if(dir_or_file == 0) {
vec->push_back(fsn);
}
else if(dir_or_file == 1 && (al_get_fs_entry_mode(fs) & ALLEGRO_FILEMODE_ISFILE) == ALLEGRO_FILEMODE_ISFILE) {
vec->push_back(fsn);
}
else if(dir_or_file == 2 && (al_get_fs_entry_mode(fs) & ALLEGRO_FILEMODE_ISDIR) == ALLEGRO_FILEMODE_ISDIR){
vec->push_back(fsn);
}
if(fs) {
al_destroy_fs_entry(fs);
}
fs = al_read_directory(f);
}
al_close_directory(f);
al_destroy_fs_entry(f);
return vec;
}
else {
al_destroy_fs_entry(f);
return NULL;
}
}

string generic_menu(vector<string> extra_items, string music = "") {
sound menu_music;
if(music != "") {
menu_music.load(music);
menu_music.set_loop(true);
menu_music.play();
}
	vector<string> real_items;
real_items.push_back("Play game");
real_items.push_back("View instructions");
real_items.push_back("Learn game sounds.");
for (int x = 0; x < extra_items.size(); x++) {
real_items.push_back(extra_items[x]);
}
real_items.push_back("view credits");
real_items.push_back("Exit game");
dynamic_menu* menu = create_menu(real_items, vector<string>());
int pos = -1;
do {
	pos = menu->run_extended("", "Use your arrow keys to navigate the menu, and enter to select.", 1, true);
if(pos == 1) {
if(music != "")
	fade(&menu_music);
	return "play";
}
else if(pos == extra_items.size()+4) {
credits();
}
else if(pos == 2) {
instructions();
}
else if(pos == 3) {
if(music != "")
	fade(&menu_music);
	learn_sounds();
if(music != "") {
	menu_music.set_gain(0);
menu_music.play();
}
}
else if (pos == extra_items.size()+5) {
if(music != "")
	fade(&menu_music);
	return "exit";
}
else {
if(music != "")
	fade(&menu_music);
	return extra_items[pos-4];
}
}
while (pos != -1 && pos != 0 & pos != extra_items.size()+5);
if(music != "")
menu_music.stop();
return "invalid";
}

<|endoftext|>


<commit_before>/*
  Q Light Controller Plus
  audiotriggerfactory.cpp

  Copyright (c) Massimo Callegari

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  Version 2 as published by the Free Software Foundation.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details. The license is
  in the file "COPYING".

  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "audiotriggerfactory.h"
#include "ui_audiotriggerfactory.h"

#if defined(__APPLE__)
  #include "audiocapture_portaudio.h"
#elif defined(WIN32)
  #include "audiocapture_waveout.h"
#else
  #include "audiocapture_alsa.h"
#endif

AudioTriggerFactory::AudioTriggerFactory(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AudioTriggerFactory)
{
    ui->setupUi(this);

    m_spectrum = new AudioTriggerWidget(this);
    m_spectrum->setBarsNumber(AudioCapture::bandsNumber());

    ui->m_gridLayout->addWidget(m_spectrum);

    connect(ui->m_enableBox, SIGNAL(toggled(bool)),
            this, SLOT(slotEnableCapture(bool)));
}

AudioTriggerFactory::~AudioTriggerFactory()
{
    delete ui;
}

void AudioTriggerFactory::slotEnableCapture(bool enable)
{
    if (enable == true)
    {
#if defined(__APPLE__)
        m_inputCapture = new AudioCapturePortAudio();
#elif defined(WIN32)
        m_inputCapture = new AudioCaptureWaveIn();
#else
        m_inputCapture = new AudioCaptureAlsa();
#endif
        connect(m_inputCapture, SIGNAL(dataProcessed(double *,quint32)),
                m_spectrum, SLOT(displaySpectrum(double *,quint32)));
        m_inputCapture->initialize(44100, 1, 2048);
        m_inputCapture->start();
    }
    else
    {
        m_inputCapture->stop();
        delete m_inputCapture;
    }
}
<commit_msg>Fixed windows wrong include<commit_after>/*
  Q Light Controller Plus
  audiotriggerfactory.cpp

  Copyright (c) Massimo Callegari

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  Version 2 as published by the Free Software Foundation.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details. The license is
  in the file "COPYING".

  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "audiotriggerfactory.h"
#include "ui_audiotriggerfactory.h"

#if defined(__APPLE__)
  #include "audiocapture_portaudio.h"
#elif defined(WIN32)
  #include "audiocapture_wavein.h"
#else
  #include "audiocapture_alsa.h"
#endif

AudioTriggerFactory::AudioTriggerFactory(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AudioTriggerFactory)
{
    ui->setupUi(this);

    m_spectrum = new AudioTriggerWidget(this);
    m_spectrum->setBarsNumber(AudioCapture::bandsNumber());

    ui->m_gridLayout->addWidget(m_spectrum);

    connect(ui->m_enableBox, SIGNAL(toggled(bool)),
            this, SLOT(slotEnableCapture(bool)));
}

AudioTriggerFactory::~AudioTriggerFactory()
{
    delete ui;
}

void AudioTriggerFactory::slotEnableCapture(bool enable)
{
    if (enable == true)
    {
#if defined(__APPLE__)
        m_inputCapture = new AudioCapturePortAudio();
#elif defined(WIN32)
        m_inputCapture = new AudioCaptureWaveIn();
#else
        m_inputCapture = new AudioCaptureAlsa();
#endif
        connect(m_inputCapture, SIGNAL(dataProcessed(double *,quint32)),
                m_spectrum, SLOT(displaySpectrum(double *,quint32)));
        m_inputCapture->initialize(44100, 1, 2048);
        m_inputCapture->start();
    }
    else
    {
        m_inputCapture->stop();
        delete m_inputCapture;
    }
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

#include "config.h"

#if CROWN_PLATFORM_ANDROID

#include "allocator.h"
#include "device.h"
#include "log.h"
#include "os_event_queue.h"
#include "os_window_android.h"
#include "thread.h"
#include "touch.h"
#include <jni.h>
#include <android/sensor.h>
#include <android_native_app_glue.h>
#include <bgfxplatform.h>

extern "C"
{
#include <android_native_app_glue.c>
}

namespace crown
{

ANativeWindow* g_android_window;
AAssetManager* g_android_asset_manager;

class AndroidDevice : public Device
{
public:

	//-----------------------------------------------------------------------------
	AndroidDevice()
	{
		#if defined(CROWN_DEBUG)
			m_fileserver = 1;
		#endif
	}

	//-----------------------------------------------------------------------------
	void display_modes(Array<DisplayMode>& /*modes*/)
	{
		// Do nothing
	}

	//-----------------------------------------------------------------------------
	void set_display_mode(uint32_t /*id*/)
	{
		// Do nothing
	}

	//-----------------------------------------------------------------------------
	void set_fullscreen(bool /*full*/)
	{
		// Do nothing
	}

	void run(struct android_app* app)
	{
		app->userData = this;
		app->onAppCmd = crown::AndroidDevice::on_app_cmd;
		app->onInputEvent = crown::AndroidDevice::on_input_event;
		g_android_asset_manager = app->activity->assetManager;

		while (app->destroyRequested == 0)
		{
			int32_t num;
			android_poll_source* source;
			/*int32_t id =*/ ALooper_pollAll(-1, NULL, &num, (void**)&source);

			if (NULL != source)
			{
				source->process(app, source);
			}
		}

		m_game_thread.stop();
	}

	//-----------------------------------------------------------------------------
	int32_t run(int, char**)
	{
		return 0;
	}

	//-----------------------------------------------------------------------------
	int32_t loop()
	{
		#if defined(CROWN_DEBUG)
			m_console = CE_NEW(default_allocator(), ConsoleServer)();
			m_console->init(m_console_port, false);
		#endif

		Device::init();

		// Push metrics here since Android does not trigger APP_CMD_WINDOW_RESIZED
		const int32_t width = ANativeWindow_getWidth(g_android_window);
		const int32_t height = ANativeWindow_getHeight(g_android_window);
		m_queue.push_metrics_event(0, 0, width, height);

		while (is_running() && !process_events())
		{
			#if defined(CROWN_DEBUG)
				m_console->update();
			#endif

			Device::frame();
			m_touch->update();
			m_keyboard->update();
		}

		Device::shutdown();

		#if defined(CROWN_DEBUG)
			m_console->shutdown();
			CE_DELETE(default_allocator(), m_console);
		#endif

		exit(EXIT_SUCCESS);
		return 0;
	}

	//-----------------------------------------------------------------------------
	static int32_t main_loop(void* thiz)
	{
		return ((AndroidDevice*) thiz)->loop();
	}

	//-----------------------------------------------------------------------------
	bool process_events()
	{
		OsEvent event;

		while (m_queue.pop_event(event))
		{
			if (event.type == OsEvent::NONE) continue;

			switch (event.type)
			{
				case OsEvent::TOUCH:
				{
					const OsTouchEvent& ev = event.touch;
					switch (ev.type)
					{
						case OsTouchEvent::POINTER: m_touch->set_pointer_state(ev.x, ev.y, ev.pointer_id, ev.pressed); break;
						case OsTouchEvent::MOVE: m_touch->set_position(ev.pointer_id, ev.x, ev.y); break;
						default: CE_FATAL("Oops, unknown touch event type"); break;
					}

					break;
				}
				case OsEvent::KEYBOARD:
				{
					const OsKeyboardEvent& ev = event.keyboard;
					m_keyboard->set_button_state(ev.button, ev.pressed);
					break;
				}
				case OsEvent::METRICS:
				{
					const OsMetricsEvent& ev = event.metrics;
					m_window->m_x = ev.x;
					m_window->m_y = ev.y;
					m_window->m_width = ev.width;
					m_window->m_height = ev.height;
					break;
				}
				case OsEvent::EXIT:
				{
					return true;
				}
				case OsEvent::PAUSE:
				{
					pause();
					break;
				}
				case OsEvent::RESUME:
				{
					unpause();
					break;
				}
				default:
				{
					CE_FATAL("Unknown Os Event");
					break;
				}
			}
		}

		return false;
	}

	//-----------------------------------------------------------------------------
	static void on_app_cmd(struct android_app* app, int32_t cmd)
	{
		((AndroidDevice*) app->userData)->process_command(app, cmd);
	}

	//-----------------------------------------------------------------------------
	void process_command(struct android_app* app, int32_t cmd)
	{
		switch (cmd)
		{
			case APP_CMD_SAVE_STATE:
			{
				// // The system has asked us to save our current state.  Do so.
				// engine->app->savedState = malloc(sizeof(struct saved_state));
				// *((struct saved_state*)engine->app->savedState) = engine->state;
				// engine->app->savedStateSize = sizeof(struct saved_state);
				break;
			}
			case APP_CMD_INIT_WINDOW:
			{
				CE_ASSERT(app->window != NULL, "Android window is NULL");
				g_android_window = app->window;
				bgfx::androidSetWindow(app->window);
				m_game_thread.start(main_loop, (void*)this);
				break;
			}
			case APP_CMD_TERM_WINDOW:
			{
				// The window is being hidden or closed, clean it up.
				break;
			}
			case APP_CMD_WINDOW_RESIZED:
			{
				// Not triggered by Android
				break;
			}
			case APP_CMD_GAINED_FOCUS:
			{
				break;
			}
			case APP_CMD_LOST_FOCUS:
			{
				break;
			}
			case APP_CMD_DESTROY:
			{
				m_queue.push_exit_event(0);
				break;
			}
		}
	}

	//-----------------------------------------------------------------------------
	static int32_t on_input_event(struct android_app* app, AInputEvent* event)
	{
		return ((AndroidDevice*) app->userData)->process_input(app, event);
	}

	//-----------------------------------------------------------------------------
	int32_t process_input(struct android_app* app, AInputEvent* event)
	{
		if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
		{
			const int32_t action = AMotionEvent_getAction(event);
			const int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
			const int32_t pointerCount = AMotionEvent_getPointerCount(event);

			const int32_t pointerId = AMotionEvent_getPointerId(event, pointerIndex);
			const float x = AMotionEvent_getX(event, pointerIndex);
			const float y = AMotionEvent_getY(event, pointerIndex);

			const int32_t actionMasked = (action & AMOTION_EVENT_ACTION_MASK);

			switch (actionMasked)
			{
				case AMOTION_EVENT_ACTION_DOWN:
				case AMOTION_EVENT_ACTION_POINTER_DOWN:
				{
					m_queue.push_touch_event((uint16_t) x, (uint16_t) y, (uint8_t) pointerId, true);
					break;
				}
				case AMOTION_EVENT_ACTION_UP:
				case AMOTION_EVENT_ACTION_POINTER_UP:
				{
					m_queue.push_touch_event((uint16_t) x, (uint16_t) y, (uint8_t) pointerId, false);
					break;
				}
				case AMOTION_EVENT_ACTION_OUTSIDE:
				case AMOTION_EVENT_ACTION_CANCEL:
				{
					m_queue.push_touch_event((uint16_t) x, (uint16_t) y, (uint8_t) pointerId, false);
					break;
				}
				case AMOTION_EVENT_ACTION_MOVE:
				{
					for (int index = 0; index < pointerCount; index++)
					{
						const float xx = AMotionEvent_getX(event, index);
						const float yy = AMotionEvent_getY(event, index);
						const int32_t id = AMotionEvent_getPointerId(event, index);
						m_queue.push_touch_event((uint16_t) xx, (uint16_t) yy, (uint8_t) id);
					}
					break;
				}
			}

			return 1;
		}
		else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
		{
			const int32_t keycode = AKeyEvent_getKeyCode(event);
			const int32_t keyaction = AKeyEvent_getAction(event);

			if (keycode == AKEYCODE_BACK)
			{
				m_queue.push_keyboard_event(0, KeyboardButton::ESCAPE, keyaction == AKEY_EVENT_ACTION_DOWN ? true : false);
			}

			return 1;
		}

		return 0;
	}

private:

	OsEventQueue m_queue;
	Thread m_game_thread;
};

} // namespace crown

void android_main(struct android_app* app)
{
	// Make sure glue isn't stripped.
	app_dummy();

	crown::memory::init();
	crown::AndroidDevice* engine = CE_NEW(crown::default_allocator(), crown::AndroidDevice)();
	crown::set_device(engine);

	engine->run(app);

	CE_DELETE(crown::default_allocator(), engine);
	crown::memory::shutdown();
}

#endif // CROWN_PLATFORM_ANDROID
<commit_msg>Rewrite android main<commit_after>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

#include "config.h"

#if CROWN_PLATFORM_ANDROID

#include "os_event_queue.h"
#include "os_window_android.h"
#include "thread.h"
#include "main.h"
#include "apk_filesystem.h"
#include "crown.h"
#include <jni.h>
#include <android/sensor.h>
#include <android_native_app_glue.h>
#include <bgfxplatform.h>

extern "C"
{
#include <android_native_app_glue.c>
}

namespace crown
{

// //-----------------------------------------------------------------------------
// void display_modes(Array<DisplayMode>& /*modes*/)
// {
// 	// Do nothing
// }

// //-----------------------------------------------------------------------------
// void set_display_mode(uint32_t /*id*/)
// {
// 	// Do nothing
// }

// //-----------------------------------------------------------------------------
// void set_fullscreen(bool /*full*/)
// {
// 	// Do nothing
// }

static bool s_exit = false;

struct MainThreadArgs
{
	Filesystem* fs;
	ConfigSettings* cs;
};

int32_t func(void* data)
{
	MainThreadArgs* args = (MainThreadArgs*) data;
	crown::init(*args->fs, *args->cs);
	crown::update();
	crown::shutdown();
	s_exit = true;
	return EXIT_SUCCESS;
}

struct AndroidDevice
{
	void run(struct android_app* app, Filesystem& fs, ConfigSettings& cs)
	{
		_margs.fs = &fs;
		_margs.cs = &cs;

		app->userData = this;
		app->onAppCmd = crown::AndroidDevice::on_app_cmd;
		app->onInputEvent = crown::AndroidDevice::on_input_event;

		while (app->destroyRequested == 0)
		{
			int32_t num;
			android_poll_source* source;
			/*int32_t id =*/ ALooper_pollAll(-1, NULL, &num, (void**)&source);

			if (NULL != source)
			{
				source->process(app, source);
			}
		}

		_main_thread.stop();
	}

	//-----------------------------------------------------------------------------
	void process_command(struct android_app* app, int32_t cmd)
	{
		switch (cmd)
		{
			case APP_CMD_SAVE_STATE:
			{
				break;
			}
			case APP_CMD_INIT_WINDOW:
			{
				CE_ASSERT(app->window != NULL, "Android window is NULL");
				bgfx::androidSetWindow(app->window);
				// Push metrics here since Android does not trigger APP_CMD_WINDOW_RESIZED
				const int32_t width = ANativeWindow_getWidth(app->window);
				const int32_t height = ANativeWindow_getHeight(app->window);
				_queue.push_metrics_event(0, 0, width, height);
				_main_thread.start(func, &_margs);
				break;
			}
			case APP_CMD_TERM_WINDOW:
			{
				// The window is being hidden or closed, clean it up.
				break;
			}
			case APP_CMD_WINDOW_RESIZED:
			{
				// Not triggered by Android
				break;
			}
			case APP_CMD_GAINED_FOCUS:
			{
				break;
			}
			case APP_CMD_LOST_FOCUS:
			{
				break;
			}
			case APP_CMD_DESTROY:
			{
				_queue.push_exit_event(0);
				break;
			}
		}
	}

	//-----------------------------------------------------------------------------
	int32_t process_input(struct android_app* app, AInputEvent* event)
	{
		if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
		{
			const int32_t action = AMotionEvent_getAction(event);
			const int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
			const int32_t pointerCount = AMotionEvent_getPointerCount(event);

			const int32_t pointerId = AMotionEvent_getPointerId(event, pointerIndex);
			const float x = AMotionEvent_getX(event, pointerIndex);
			const float y = AMotionEvent_getY(event, pointerIndex);

			const int32_t actionMasked = (action & AMOTION_EVENT_ACTION_MASK);

			switch (actionMasked)
			{
				case AMOTION_EVENT_ACTION_DOWN:
				case AMOTION_EVENT_ACTION_POINTER_DOWN:
				{
					_queue.push_touch_event((uint16_t) x, (uint16_t) y, (uint8_t) pointerId, true);
					break;
				}
				case AMOTION_EVENT_ACTION_UP:
				case AMOTION_EVENT_ACTION_POINTER_UP:
				{
					_queue.push_touch_event((uint16_t) x, (uint16_t) y, (uint8_t) pointerId, false);
					break;
				}
				case AMOTION_EVENT_ACTION_OUTSIDE:
				case AMOTION_EVENT_ACTION_CANCEL:
				{
					_queue.push_touch_event((uint16_t) x, (uint16_t) y, (uint8_t) pointerId, false);
					break;
				}
				case AMOTION_EVENT_ACTION_MOVE:
				{
					for (int index = 0; index < pointerCount; index++)
					{
						const float xx = AMotionEvent_getX(event, index);
						const float yy = AMotionEvent_getY(event, index);
						const int32_t id = AMotionEvent_getPointerId(event, index);
						_queue.push_touch_event((uint16_t) xx, (uint16_t) yy, (uint8_t) id);
					}
					break;
				}
			}

			return 1;
		}
		else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
		{
			const int32_t keycode = AKeyEvent_getKeyCode(event);
			const int32_t keyaction = AKeyEvent_getAction(event);

			if (keycode == AKEYCODE_BACK)
			{
				_queue.push_keyboard_event(0, KeyboardButton::ESCAPE, keyaction == AKEY_EVENT_ACTION_DOWN ? true : false);
			}

			return 1;
		}

		return 0;
	}

	//-----------------------------------------------------------------------------
	static int32_t on_input_event(struct android_app* app, AInputEvent* event)
	{
		return ((AndroidDevice*) app->userData)->process_input(app, event);
	}

	//-----------------------------------------------------------------------------
	static void on_app_cmd(struct android_app* app, int32_t cmd)
	{
		((AndroidDevice*) app->userData)->process_command(app, cmd);
	}

public:

	OsEventQueue _queue;
	Thread _main_thread;
	MainThreadArgs _margs;
};

static AndroidDevice s_advc;

bool next_event(OsEvent& ev)
{
	return s_advc._queue.pop_event(ev);
}

} // namespace crown

void android_main(struct android_app* app)
{
	using namespace crown;

	// Make sure glue isn't stripped.
	app_dummy();

	memory_globals::init();
	// DiskFilesystem src_fs(cls.source_dir);
	ApkFilesystem src_fs(app->activity->assetManager);
	ConfigSettings cs = parse_config_file(src_fs);

	console_server_globals::init();
	console_server_globals::console().init(cs.console_port, false);

	crown::s_advc.run(app, src_fs, cs);

	console_server_globals::shutdown();
	memory_globals::shutdown();
}

#endif // CROWN_PLATFORM_ANDROID
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

#include "config.h"

#if CROWN_PLATFORM_WINDOWS

#include "os_event_queue.h"
#include "os_window_windows.h"
#include "thread.h"
#include "crown.h"
#include "command_line.h"
#include "keyboard.h"
#include "console_server.h"
#include "bundle_compiler.h"
#include "disk_filesystem.h"
#include <bgfxplatform.h>
#include <winsock2.h>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windowsx.h>

namespace crown
{

static bool s_exit = false;

struct MainThreadArgs
{
	Filesystem* fs;
	ConfigSettings* cs;
};

int32_t func(void* data)
{
	MainThreadArgs* args = (MainThreadArgs*)data;
	crown::init(*args->fs, *args->cs);
	crown::update();
	crown::shutdown();
	s_exit = true;
	return EXIT_SUCCESS;
}

//-----------------------------------------------------------------------------
static KeyboardButton::Enum win_translate_key(int32_t winKey)
{
	if ((winKey > 0x40 && winKey < 0x5B) || (winKey > 0x60 && winKey < 0x7B) || (winKey > 0x2F && winKey < 0x3A))
	{
		return (KeyboardButton::Enum)winKey;
	}

	switch (winKey)
	{
		case VK_BACK:		return KeyboardButton::BACKSPACE;
		case VK_TAB:		return KeyboardButton::TAB;
		case VK_SPACE:		return KeyboardButton::SPACE;
		case VK_ESCAPE:		return KeyboardButton::ESCAPE;
		case VK_RETURN:		return KeyboardButton::ENTER;
		case VK_F1:			return KeyboardButton::F1;
		case VK_F2:			return KeyboardButton::F2;
		case VK_F3:			return KeyboardButton::F3;
		case VK_F4:			return KeyboardButton::F4;
		case VK_F5:			return KeyboardButton::F5;
		case VK_F6:			return KeyboardButton::F6;
		case VK_F7:			return KeyboardButton::F7;
		case VK_F8:			return KeyboardButton::F8;
		case VK_F9:			return KeyboardButton::F9;
		case VK_F10:		return KeyboardButton::F10;
		case VK_F11:		return KeyboardButton::F11;
		case VK_F12:		return KeyboardButton::F12;
		case VK_HOME:		return KeyboardButton::HOME;
		case VK_LEFT:		return KeyboardButton::LEFT;
		case VK_UP:			return KeyboardButton::UP;
		case VK_RIGHT:		return KeyboardButton::RIGHT;
		case VK_DOWN:		return KeyboardButton::DOWN;
		case VK_PRIOR:		return KeyboardButton::PAGE_UP;
		case VK_NEXT:		return KeyboardButton::PAGE_DOWN;
		case VK_LSHIFT:		return KeyboardButton::LSHIFT;
		case VK_RSHIFT:		return KeyboardButton::RSHIFT;
		case VK_LCONTROL:	return KeyboardButton::LCONTROL;
		case VK_RCONTROL:	return KeyboardButton::RCONTROL;
		case VK_CAPITAL:	return KeyboardButton::CAPS_LOCK;
		case VK_LMENU:		return KeyboardButton::LALT;
		case VK_RMENU:		return KeyboardButton::RALT;
		case VK_LWIN:		return KeyboardButton::LSUPER;
		case VK_RWIN:		return KeyboardButton::RSUPER;
		case VK_NUMPAD0:	return KeyboardButton::KP_0;
		case VK_NUMPAD1:	return KeyboardButton::KP_1;
		case VK_NUMPAD2:	return KeyboardButton::KP_2;
		case VK_NUMPAD3:	return KeyboardButton::KP_3;
		case VK_NUMPAD4:	return KeyboardButton::KP_4;
		case VK_NUMPAD5:	return KeyboardButton::KP_5;
		case VK_NUMPAD6:	return KeyboardButton::KP_6;
		case VK_NUMPAD7:	return KeyboardButton::KP_7;
		case VK_NUMPAD8:	return KeyboardButton::KP_8;
		case VK_NUMPAD9:	return KeyboardButton::KP_9;
		default:			return KeyboardButton::NONE;
	}
}

struct WindowsDevice
{
	WindowsDevice()
		: m_hwnd(0)
	{
	}

	//-----------------------------------------------------------------------------
	int32_t	run(Filesystem* fs, ConfigSettings* cs)
	{
		HINSTANCE instance = (HINSTANCE)GetModuleHandle(NULL);
		WNDCLASSEX wnd;
		memset(&wnd, 0, sizeof(wnd));
		wnd.cbSize = sizeof(wnd);
		wnd.style = CS_HREDRAW | CS_VREDRAW;
		wnd.lpfnWndProc = window_proc;
		wnd.hInstance = instance;
		wnd.hIcon = LoadIcon(instance, IDI_APPLICATION);
		wnd.hCursor = LoadCursor(instance, IDC_ARROW);
		wnd.lpszClassName = "crown";
		wnd.hIconSm = LoadIcon(instance, IDI_APPLICATION);
		RegisterClassExA(&wnd);

		m_hwnd = CreateWindowA(
					"crown",
					"Crown",
					WS_OVERLAPPEDWINDOW|WS_VISIBLE,
					0,
					0,
					cs->window_width,
					cs->window_height,
					0,
					NULL,
					instance,
					0);

		bgfx::winSetHwnd(m_hwnd);

		// Start main thread
		MainThreadArgs mta;
		mta.fs = fs;
		mta.cs = cs;

		Thread main_thread;
		main_thread.start(func, &mta);

		MSG msg;
		msg.message = WM_NULL;

		while (!s_exit)
		{
			while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) != 0)
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}

		main_thread.stop();
		DestroyWindow(m_hwnd);
		return EXIT_SUCCESS;
	}

	//-----------------------------------------------------------------------------
	LRESULT pump_events(HWND hwnd, UINT id, WPARAM wparam, LPARAM lparam)
	{
		switch (id)
		{
			case WM_DESTROY:
			{
				break;
			}
			case WM_QUIT:
			case WM_CLOSE:
			{
				m_queue.push_exit_event(0);
				break;
			}
			case WM_SIZE:
			{
				uint32_t width = GET_X_LPARAM(lparam);
				uint32_t height = GET_Y_LPARAM(lparam);
				m_queue.push_metrics_event(0, 0, width, height);
				break;
			}
			case WM_SYSCOMMAND:
			{
				switch (wparam)
				{
					case SC_MINIMIZE:
					case SC_RESTORE:
					{
						HWND parent = GetWindow(hwnd, GW_OWNER);
						if (NULL != parent)
						{
							PostMessage(parent, id, wparam, lparam);
						}
					}
				}
				break;
			}
			case WM_MOUSEMOVE:
			{
				int32_t mx = GET_X_LPARAM(lparam);
				int32_t my = GET_Y_LPARAM(lparam);
				m_queue.push_mouse_event(mx, my);
				break;
			}
			case WM_LBUTTONDOWN:
			case WM_LBUTTONUP:
			{
				int32_t mx = GET_X_LPARAM(lparam);
				int32_t my = GET_Y_LPARAM(lparam);
				m_queue.push_mouse_event(mx, my, MouseButton::LEFT, id == WM_LBUTTONDOWN);
				break;
			}
			case WM_RBUTTONUP:
			case WM_RBUTTONDOWN:
			{
				int32_t mx = GET_X_LPARAM(lparam);
				int32_t my = GET_Y_LPARAM(lparam);
				m_queue.push_mouse_event(mx, my, MouseButton::RIGHT, id == WM_RBUTTONDOWN);
				break;
			}
			case WM_MBUTTONDOWN:
			case WM_MBUTTONUP:
			{
				int32_t mx = GET_X_LPARAM(lparam);
				int32_t my = GET_Y_LPARAM(lparam);
				m_queue.push_mouse_event(mx, my, MouseButton::MIDDLE, id == WM_MBUTTONDOWN);
				break;
			}
			case WM_KEYDOWN:
			case WM_SYSKEYDOWN:
			case WM_KEYUP:
			case WM_SYSKEYUP:
			{
				KeyboardButton::Enum kb = win_translate_key(wparam & 0xff);

				int32_t modifier_mask = 0;

				if (kb == KeyboardButton::LSHIFT || kb == KeyboardButton::RSHIFT)
				{
					(id == WM_KEYDOWN || id == WM_SYSKEYDOWN) ? modifier_mask |= ModifierButton::SHIFT : modifier_mask &= ~ModifierButton::SHIFT;
				}
				else if (kb == KeyboardButton::LCONTROL || kb == KeyboardButton::RCONTROL)
				{
					(id == WM_KEYDOWN || id == WM_SYSKEYDOWN) ? modifier_mask |= ModifierButton::CTRL : modifier_mask &= ~ModifierButton::CTRL;
				}
				else if (kb == KeyboardButton::LALT || kb == KeyboardButton::RALT)
				{
					(id == WM_KEYDOWN || id == WM_SYSKEYDOWN) ? modifier_mask |= ModifierButton::ALT : modifier_mask &= ~ModifierButton::ALT;
				}

				m_queue.push_keyboard_event(modifier_mask, kb, (id == WM_KEYDOWN || id == WM_SYSKEYDOWN));
				break;
			}
			default:
				break;
		}
		return DefWindowProc(hwnd, id, wparam, lparam);
	}

private:

	static LRESULT CALLBACK window_proc(HWND hwnd, UINT id, WPARAM wparam, LPARAM lparam);

public:

	HWND m_hwnd;
	HDC m_hdc;
	uint32_t m_parent_window_handle;
	OsEventQueue m_queue;
};

static WindowsDevice s_wdvc;

LRESULT CALLBACK WindowsDevice::window_proc(HWND hwnd, UINT id, WPARAM wparam, LPARAM lparam)
{
	return s_wdvc.pump_events(hwnd, id, wparam, lparam);
}

bool next_event(OsEvent& ev)
{
	return s_wdvc.m_queue.pop_event(ev);
}
} // namespace crown

int main(int argc, char** argv)
{
	using namespace crown;

	WSADATA WsaData;
	int res = WSAStartup(MAKEWORD(2, 2), &WsaData);
	CE_ASSERT(res == 0, "Unable to initialize socket");
	CE_UNUSED(WsaData);
	CE_UNUSED(res);

	CommandLineSettings cls = parse_command_line(argc, argv);

	memory_globals::init();
	DiskFilesystem src_fs(cls.source_dir);
	ConfigSettings cs = parse_config_file(src_fs);

	console_server_globals::init();
	console_server_globals::console().init(cs.console_port, cls.wait_console);

	bundle_compiler_globals::init();

	bool do_continue = true;
	int exitcode = EXIT_SUCCESS;

	do_continue = bundle_compiler::main(cls);

	if (do_continue)
	{
		DiskFilesystem dst_fs(cls.bundle_dir);
		exitcode = crown::s_wdvc.run(&dst_fs, &cs);
	}

	bundle_compiler_globals::shutdown();
	console_server_globals::shutdown();
	memory_globals::shutdown();
	WSACleanup();
	return exitcode;
}

#endif // CROWN_PLATFORM_WINDOWS
<commit_msg>Fix win_translate_key<commit_after>/*
Copyright (c) 2013 Daniele Bartolini, Michele Rossi
Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

#include "config.h"

#if CROWN_PLATFORM_WINDOWS

#include "os_event_queue.h"
#include "os_window_windows.h"
#include "thread.h"
#include "crown.h"
#include "command_line.h"
#include "keyboard.h"
#include "console_server.h"
#include "bundle_compiler.h"
#include "disk_filesystem.h"
#include <bgfxplatform.h>
#include <winsock2.h>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windowsx.h>

namespace crown
{

static bool s_exit = false;

struct MainThreadArgs
{
	Filesystem* fs;
	ConfigSettings* cs;
};

int32_t func(void* data)
{
	MainThreadArgs* args = (MainThreadArgs*)data;
	crown::init(*args->fs, *args->cs);
	crown::update();
	crown::shutdown();
	s_exit = true;
	return EXIT_SUCCESS;
}

//-----------------------------------------------------------------------------
static KeyboardButton::Enum win_translate_key(int32_t winkey)
{
	switch (winkey)
	{
		case VK_BACK:		return KeyboardButton::BACKSPACE;
		case VK_TAB:		return KeyboardButton::TAB;
		case VK_SPACE:		return KeyboardButton::SPACE;
		case VK_ESCAPE:		return KeyboardButton::ESCAPE;
		case VK_RETURN:		return KeyboardButton::ENTER;
		case VK_F1:			return KeyboardButton::F1;
		case VK_F2:			return KeyboardButton::F2;
		case VK_F3:			return KeyboardButton::F3;
		case VK_F4:			return KeyboardButton::F4;
		case VK_F5:			return KeyboardButton::F5;
		case VK_F6:			return KeyboardButton::F6;
		case VK_F7:			return KeyboardButton::F7;
		case VK_F8:			return KeyboardButton::F8;
		case VK_F9:			return KeyboardButton::F9;
		case VK_F10:		return KeyboardButton::F10;
		case VK_F11:		return KeyboardButton::F11;
		case VK_F12:		return KeyboardButton::F12;
		case VK_HOME:		return KeyboardButton::HOME;
		case VK_LEFT:		return KeyboardButton::LEFT;
		case VK_UP:			return KeyboardButton::UP;
		case VK_RIGHT:		return KeyboardButton::RIGHT;
		case VK_DOWN:		return KeyboardButton::DOWN;
		case VK_PRIOR:		return KeyboardButton::PAGE_UP;
		case VK_NEXT:		return KeyboardButton::PAGE_DOWN;
		case VK_LSHIFT:		return KeyboardButton::LSHIFT;
		case VK_RSHIFT:		return KeyboardButton::RSHIFT;
		case VK_LCONTROL:	return KeyboardButton::LCONTROL;
		case VK_RCONTROL:	return KeyboardButton::RCONTROL;
		case VK_CAPITAL:	return KeyboardButton::CAPS_LOCK;
		case VK_LMENU:		return KeyboardButton::LALT;
		case VK_RMENU:		return KeyboardButton::RALT;
		case VK_LWIN:		return KeyboardButton::LSUPER;
		case VK_RWIN:		return KeyboardButton::RSUPER;
		case VK_NUMPAD0:	return KeyboardButton::KP_0;
		case VK_NUMPAD1:	return KeyboardButton::KP_1;
		case VK_NUMPAD2:	return KeyboardButton::KP_2;
		case VK_NUMPAD3:	return KeyboardButton::KP_3;
		case VK_NUMPAD4:	return KeyboardButton::KP_4;
		case VK_NUMPAD5:	return KeyboardButton::KP_5;
		case VK_NUMPAD6:	return KeyboardButton::KP_6;
		case VK_NUMPAD7:	return KeyboardButton::KP_7;
		case VK_NUMPAD8:	return KeyboardButton::KP_8;
		case VK_NUMPAD9:	return KeyboardButton::KP_9;
		case '0':			return KeyboardButton::NUM_0;
		case '1':			return KeyboardButton::NUM_1;
		case '2':			return KeyboardButton::NUM_2;
		case '3':			return KeyboardButton::NUM_3;
		case '4':			return KeyboardButton::NUM_4;
		case '5':			return KeyboardButton::NUM_5;
		case '6':			return KeyboardButton::NUM_6;
		case '7':			return KeyboardButton::NUM_7;
		case '8':			return KeyboardButton::NUM_8;
		case '9':			return KeyboardButton::NUM_9;
		case 'A':			return KeyboardButton::A;
		case 'B':			return KeyboardButton::B;
		case 'C':			return KeyboardButton::C;
		case 'D':			return KeyboardButton::D;
		case 'E':			return KeyboardButton::E;
		case 'F':			return KeyboardButton::F;
		case 'G':			return KeyboardButton::G;
		case 'H':			return KeyboardButton::H;
		case 'I':			return KeyboardButton::I;
		case 'J':			return KeyboardButton::J;
		case 'K':			return KeyboardButton::K;
		case 'L':			return KeyboardButton::L;
		case 'M':			return KeyboardButton::M;
		case 'N':			return KeyboardButton::N;
		case 'O':			return KeyboardButton::O;
		case 'P':			return KeyboardButton::P;
		case 'Q':			return KeyboardButton::Q;
		case 'R':			return KeyboardButton::R;
		case 'S':			return KeyboardButton::S;
		case 'T':			return KeyboardButton::T;
		case 'U':			return KeyboardButton::U;
		case 'V':			return KeyboardButton::V;
		case 'W':			return KeyboardButton::W;
		case 'X':			return KeyboardButton::X;
		case 'Y':			return KeyboardButton::Y;
		case 'Z':			return KeyboardButton::Z;
		default:			return KeyboardButton::NONE;
	}
}

struct WindowsDevice
{
	WindowsDevice()
		: m_hwnd(0)
	{
	}

	//-----------------------------------------------------------------------------
	int32_t	run(Filesystem* fs, ConfigSettings* cs)
	{
		HINSTANCE instance = (HINSTANCE)GetModuleHandle(NULL);
		WNDCLASSEX wnd;
		memset(&wnd, 0, sizeof(wnd));
		wnd.cbSize = sizeof(wnd);
		wnd.style = CS_HREDRAW | CS_VREDRAW;
		wnd.lpfnWndProc = window_proc;
		wnd.hInstance = instance;
		wnd.hIcon = LoadIcon(instance, IDI_APPLICATION);
		wnd.hCursor = LoadCursor(instance, IDC_ARROW);
		wnd.lpszClassName = "crown";
		wnd.hIconSm = LoadIcon(instance, IDI_APPLICATION);
		RegisterClassExA(&wnd);

		m_hwnd = CreateWindowA(
					"crown",
					"Crown",
					WS_OVERLAPPEDWINDOW|WS_VISIBLE,
					0,
					0,
					cs->window_width,
					cs->window_height,
					0,
					NULL,
					instance,
					0);

		bgfx::winSetHwnd(m_hwnd);

		// Start main thread
		MainThreadArgs mta;
		mta.fs = fs;
		mta.cs = cs;

		Thread main_thread;
		main_thread.start(func, &mta);

		MSG msg;
		msg.message = WM_NULL;

		while (!s_exit)
		{
			while (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) != 0)
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}

		main_thread.stop();
		DestroyWindow(m_hwnd);
		return EXIT_SUCCESS;
	}

	//-----------------------------------------------------------------------------
	LRESULT pump_events(HWND hwnd, UINT id, WPARAM wparam, LPARAM lparam)
	{
		switch (id)
		{
			case WM_DESTROY:
			{
				break;
			}
			case WM_QUIT:
			case WM_CLOSE:
			{
				m_queue.push_exit_event(0);
				break;
			}
			case WM_SIZE:
			{
				uint32_t width = GET_X_LPARAM(lparam);
				uint32_t height = GET_Y_LPARAM(lparam);
				m_queue.push_metrics_event(0, 0, width, height);
				break;
			}
			case WM_SYSCOMMAND:
			{
				switch (wparam)
				{
					case SC_MINIMIZE:
					case SC_RESTORE:
					{
						HWND parent = GetWindow(hwnd, GW_OWNER);
						if (NULL != parent)
						{
							PostMessage(parent, id, wparam, lparam);
						}
					}
				}
				break;
			}
			case WM_MOUSEMOVE:
			{
				int32_t mx = GET_X_LPARAM(lparam);
				int32_t my = GET_Y_LPARAM(lparam);
				m_queue.push_mouse_event(mx, my);
				break;
			}
			case WM_LBUTTONDOWN:
			case WM_LBUTTONUP:
			{
				int32_t mx = GET_X_LPARAM(lparam);
				int32_t my = GET_Y_LPARAM(lparam);
				m_queue.push_mouse_event(mx, my, MouseButton::LEFT, id == WM_LBUTTONDOWN);
				break;
			}
			case WM_RBUTTONUP:
			case WM_RBUTTONDOWN:
			{
				int32_t mx = GET_X_LPARAM(lparam);
				int32_t my = GET_Y_LPARAM(lparam);
				m_queue.push_mouse_event(mx, my, MouseButton::RIGHT, id == WM_RBUTTONDOWN);
				break;
			}
			case WM_MBUTTONDOWN:
			case WM_MBUTTONUP:
			{
				int32_t mx = GET_X_LPARAM(lparam);
				int32_t my = GET_Y_LPARAM(lparam);
				m_queue.push_mouse_event(mx, my, MouseButton::MIDDLE, id == WM_MBUTTONDOWN);
				break;
			}
			case WM_KEYDOWN:
			case WM_SYSKEYDOWN:
			case WM_KEYUP:
			case WM_SYSKEYUP:
			{
				KeyboardButton::Enum kb = win_translate_key(wparam & 0xff);

				int32_t modifier_mask = 0;

				if (kb == KeyboardButton::LSHIFT || kb == KeyboardButton::RSHIFT)
				{
					(id == WM_KEYDOWN || id == WM_SYSKEYDOWN) ? modifier_mask |= ModifierButton::SHIFT : modifier_mask &= ~ModifierButton::SHIFT;
				}
				else if (kb == KeyboardButton::LCONTROL || kb == KeyboardButton::RCONTROL)
				{
					(id == WM_KEYDOWN || id == WM_SYSKEYDOWN) ? modifier_mask |= ModifierButton::CTRL : modifier_mask &= ~ModifierButton::CTRL;
				}
				else if (kb == KeyboardButton::LALT || kb == KeyboardButton::RALT)
				{
					(id == WM_KEYDOWN || id == WM_SYSKEYDOWN) ? modifier_mask |= ModifierButton::ALT : modifier_mask &= ~ModifierButton::ALT;
				}

				m_queue.push_keyboard_event(modifier_mask, kb, (id == WM_KEYDOWN || id == WM_SYSKEYDOWN));
				break;
			}
			default:
				break;
		}
		return DefWindowProc(hwnd, id, wparam, lparam);
	}

private:

	static LRESULT CALLBACK window_proc(HWND hwnd, UINT id, WPARAM wparam, LPARAM lparam);

public:

	HWND m_hwnd;
	HDC m_hdc;
	uint32_t m_parent_window_handle;
	OsEventQueue m_queue;
};

static WindowsDevice s_wdvc;

LRESULT CALLBACK WindowsDevice::window_proc(HWND hwnd, UINT id, WPARAM wparam, LPARAM lparam)
{
	return s_wdvc.pump_events(hwnd, id, wparam, lparam);
}

bool next_event(OsEvent& ev)
{
	return s_wdvc.m_queue.pop_event(ev);
}
} // namespace crown

int main(int argc, char** argv)
{
	using namespace crown;

	WSADATA WsaData;
	int res = WSAStartup(MAKEWORD(2, 2), &WsaData);
	CE_ASSERT(res == 0, "Unable to initialize socket");
	CE_UNUSED(WsaData);
	CE_UNUSED(res);

	CommandLineSettings cls = parse_command_line(argc, argv);

	memory_globals::init();
	DiskFilesystem src_fs(cls.source_dir);
	ConfigSettings cs = parse_config_file(src_fs);

	console_server_globals::init();
	console_server_globals::console().init(cs.console_port, cls.wait_console);

	bundle_compiler_globals::init();

	bool do_continue = true;
	int exitcode = EXIT_SUCCESS;

	do_continue = bundle_compiler::main(cls);

	if (do_continue)
	{
		DiskFilesystem dst_fs(cls.bundle_dir);
		exitcode = crown::s_wdvc.run(&dst_fs, &cs);
	}

	bundle_compiler_globals::shutdown();
	console_server_globals::shutdown();
	memory_globals::shutdown();
	WSACleanup();
	return exitcode;
}

#endif // CROWN_PLATFORM_WINDOWS
<|endoftext|>


<commit_before>#include <string.h> // memset

#include "Common.h"
#include "OpenGL.h"
#include "MeshBuffer.h"
#include "Reference.h"
#include "Mesh.h"

struct Mesh
{
    ReferenceCounter refCounter;
    GLuint vertexBuffer;
    GLuint indexBuffer;
    int primitiveType;
    int size;
};

Mesh* CreateMesh( const MeshBuffer* buffer )
{
    const int vertexCount = GetMeshBufferVertexCount(buffer);
    const int indexCount = GetMeshBufferIndexCount(buffer);

    if(!vertexCount)
        Error("Creating an empty mesh.");

    Mesh* mesh = new Mesh;
    memset(mesh, 0, sizeof(Mesh));

    InitReferenceCounter(&mesh->refCounter);

    mesh->primitiveType = GL_TRIANGLES; // Default to triangles (can be changed later)

    glGenBuffers(1, &mesh->vertexBuffer);

    glBindBuffer(GL_ARRAY_BUFFER, mesh->vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER,
                 vertexCount*sizeof(Vertex),
                 GetMeshBufferVertices(buffer),
                 GL_STATIC_DRAW);

    if(indexCount)
    {
        glGenBuffers(1, &mesh->indexBuffer);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->indexBuffer);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                     indexCount*sizeof(unsigned short),
                     GetMeshBufferIndices(buffer),
                     GL_STATIC_DRAW);

        mesh->size = indexCount;
    }
    else
    {
        mesh->size = vertexCount;
    }

    return mesh;
}

static void BindMesh( const Mesh* mesh )
{
    glBindBuffer(GL_ARRAY_BUFFER, mesh->vertexBuffer);

    if(mesh->indexBuffer)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->indexBuffer);

    SetVertexAttributePointers(NULL);
}

static const Mesh* CurrentMesh = NULL;

void DrawMesh( const Mesh* mesh )
{
    if(mesh != CurrentMesh)
    {
        BindMesh(mesh);
        CurrentMesh = mesh;
    }

    if(mesh->indexBuffer)
        glDrawElements(mesh->primitiveType, mesh->size, GL_UNSIGNED_SHORT, 0);
    else
        glDrawArrays(mesh->primitiveType, 0, mesh->size);
}

static void FreeMesh( Mesh* mesh )
{
    FreeReferenceCounter(&mesh->refCounter);

    glDeleteBuffers(1, &mesh->vertexBuffer);

    if(mesh->indexBuffer)
        glDeleteBuffers(1, &mesh->indexBuffer);

    delete mesh;
}

void ReferenceMesh( Mesh* mesh )
{
    Reference(&mesh->refCounter);
}

void ReleaseMesh( Mesh* mesh )
{
    Release(&mesh->refCounter);
    if(!HasReferences(&mesh->refCounter))
        FreeMesh(mesh);
}
<commit_msg>Debug mode for mesh normals, tangents and bitangents.<commit_after>#include <string.h> // memset

#include "Common.h"
#include "OpenGL.h"
#include "MeshBuffer.h"
#include "Reference.h"
#include "Mesh.h"

struct Mesh
{
    ReferenceCounter refCounter;
    GLuint vertexBuffer;
    GLuint indexBuffer;
    int primitiveType;
    int size;
#if defined(APOAPSIS_DEBUG_MESH)
    GLuint debugVertexBuffer;
    int debugVertexCount;
#endif
};

#if defined(APOAPSIS_DEBUG_MESH)
static void BuildDebugMesh( const MeshBuffer* buffer, Mesh* mesh );
static void DrawDebugMesh( const Mesh* mesh );
#endif

Mesh* CreateMesh( const MeshBuffer* buffer )
{
    const int vertexCount = GetMeshBufferVertexCount(buffer);
    const int indexCount = GetMeshBufferIndexCount(buffer);

    if(!vertexCount)
        Error("Creating an empty mesh.");

    Mesh* mesh = new Mesh;
    memset(mesh, 0, sizeof(Mesh));

    InitReferenceCounter(&mesh->refCounter);

    mesh->primitiveType = GL_TRIANGLES; // Default to triangles (can be changed later)

    glGenBuffers(1, &mesh->vertexBuffer);

    glBindBuffer(GL_ARRAY_BUFFER, mesh->vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER,
                 vertexCount*sizeof(Vertex),
                 GetMeshBufferVertices(buffer),
                 GL_STATIC_DRAW);

    if(indexCount)
    {
        glGenBuffers(1, &mesh->indexBuffer);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->indexBuffer);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                     indexCount*sizeof(unsigned short),
                     GetMeshBufferIndices(buffer),
                     GL_STATIC_DRAW);

        mesh->size = indexCount;
    }
    else
    {
        mesh->size = vertexCount;
    }

#if defined(APOAPSIS_DEBUG_MESH)
    BuildDebugMesh(buffer, mesh);
#endif

    return mesh;
}

static void BindMesh( const Mesh* mesh )
{
    glBindBuffer(GL_ARRAY_BUFFER, mesh->vertexBuffer);

    if(mesh->indexBuffer)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->indexBuffer);

    SetVertexAttributePointers(NULL);
}

static const Mesh* CurrentMesh = NULL;

void DrawMesh( const Mesh* mesh )
{
    if(mesh != CurrentMesh)
    {
        BindMesh(mesh);
        CurrentMesh = mesh;
    }

    if(mesh->indexBuffer)
        glDrawElements(mesh->primitiveType, mesh->size, GL_UNSIGNED_SHORT, 0);
    else
        glDrawArrays(mesh->primitiveType, 0, mesh->size);

#if defined(APOAPSIS_DEBUG_MESH)
    DrawDebugMesh(mesh);
#endif
}

static void FreeMesh( Mesh* mesh )
{
    FreeReferenceCounter(&mesh->refCounter);

    glDeleteBuffers(1, &mesh->vertexBuffer);

    if(mesh->indexBuffer)
        glDeleteBuffers(1, &mesh->indexBuffer);

    delete mesh;
}

void ReferenceMesh( Mesh* mesh )
{
    Reference(&mesh->refCounter);
}

void ReleaseMesh( Mesh* mesh )
{
    Release(&mesh->refCounter);
    if(!HasReferences(&mesh->refCounter))
        FreeMesh(mesh);
}

#if defined(APOAPSIS_DEBUG_MESH)
const int DebugVerticesPerVertex = 6;

static void CalcDebugVertices( const Vertex* input, Vertex* outputs )
{
    using namespace glm;

    const float scale = 0.03f;

    outputs[0].position = input->position;
    outputs[1].position = input->position + input->normal * scale;
    outputs[1].color = vec3(0,0,1);

    outputs[2].position = input->position;
    outputs[3].position = input->position + input->tangent * scale;
    outputs[3].color = vec3(1,0,0);

    outputs[4].position = input->position;
    outputs[5].position = input->position + input->bitangent * scale;
    outputs[5].color = vec3(0,1,0);
}

static void BuildDebugMesh( const MeshBuffer* buffer, Mesh* mesh )
{
    const int vertexCount      = GetMeshBufferVertexCount(buffer);
    const int indexCount       = GetMeshBufferIndexCount(buffer);
    const Vertex* vertices     = GetMeshBufferVertices(buffer);
    const VertexIndex* indices = GetMeshBufferIndices(buffer);

    const int elementCount = (indexCount > 0) ? indexCount : vertexCount;
    const int debugVertexCount = elementCount * DebugVerticesPerVertex;
    Vertex* debugVertices = new Vertex[debugVertexCount];
    memset(debugVertices, 0, sizeof(Vertex)*debugVertexCount);

    if(indexCount > 0)
    {
        for(int i = 0; i < indexCount; i++)
        {
            const VertexIndex index = indices[i];
            const Vertex* input = &vertices[index];
            Vertex* outputs = &debugVertices[i*DebugVerticesPerVertex];
            CalcDebugVertices(input, outputs);
        }
    }
    else
    {
        for(int i = 0; i < vertexCount; i++)
        {
            const Vertex* input = &vertices[i];
            Vertex* outputs = &debugVertices[i*DebugVerticesPerVertex];
            CalcDebugVertices(input, outputs);
        }
    }

    glGenBuffers(1, &mesh->debugVertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, mesh->debugVertexBuffer);
    glBufferData(GL_ARRAY_BUFFER,
                 debugVertexCount*sizeof(Vertex),
                 debugVertices,
                 GL_STATIC_DRAW);

    delete[] debugVertices;

    mesh->debugVertexCount = debugVertexCount;
}

static void DrawDebugMesh( const Mesh* mesh )
{
    CurrentMesh = NULL; // Make sure the render function always gets called.
    glBindBuffer(GL_ARRAY_BUFFER, mesh->debugVertexBuffer);
    SetVertexAttributePointers(NULL);
    glDrawArrays(GL_LINES, 0, mesh->debugVertexCount);
}
#endif
<|endoftext|>


<commit_before>// Copyright 2009, Squish Tech, LLC.

#include <node.h>

#include <libxml/xmlsave.h>

#include "xml_node.h"
#include "xml_document.h"
#include "xml_namespace.h"
#include "xml_element.h"
#include "xml_attribute.h"

namespace libxmljs {

v8::Persistent<v8::FunctionTemplate> XmlNode::constructor_template;

v8::Handle<v8::Value>
XmlNode::Doc(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode* node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->get_doc());
}

v8::Handle<v8::Value>
XmlNode::Namespace(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode* node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  // #namespace() Get the node's namespace
  if (args.Length() == 0) {
      return scope.Close(node->get_namespace());
  }

  if (args[0]->IsNull())
      return scope.Close(node->remove_namespace());

  XmlNamespace* ns = NULL;

  // #namespace(ns) libxml.Namespace object was provided
  // TODO(sprsquish): check that it was actually given a namespace obj
  if (args[0]->IsObject())
    ns = ObjectWrap::Unwrap<XmlNamespace>(args[0]->ToObject());

  // #namespace(href) or #namespace(prefix, href)
  // if the namespace has already been defined on the node, just set it
  if (args[0]->IsString()) {
    v8::String::Utf8Value ns_to_find(args[0]->ToString());
    xmlNs* found_ns = node->find_namespace(*ns_to_find);
    if (found_ns) {
        // maybe build
        v8::Handle<v8::Object> existing = XmlNamespace::New(found_ns);
        ns = ObjectWrap::Unwrap<XmlNamespace>(existing);
    }
  }

  // Namespace does not seem to exist, so create it.
  if (!ns) {
      const unsigned int argc = 3;
      v8::Handle<v8::Value> argv[argc];
      argv[0] = args.Holder();

      if (args.Length() == 1) {
          argv[1] = v8::Null();
          argv[2] = args[0];
      } else {
          argv[1] = args[0];
          argv[2] = args[1];
      }

      v8::Handle<v8::Function> define_namespace =
          XmlNamespace::constructor_template->GetFunction();

      // will create a new namespace attached to this node
      // since we keep the document around, the namespace, like the node, won't be
      // garbage collected
      v8::Handle<v8::Value> new_ns = define_namespace->NewInstance(argc, argv);
      ns = ObjectWrap::Unwrap<XmlNamespace>(new_ns->ToObject());
  }

  node->set_namespace(ns->xml_obj);
  return scope.Close(node->get_namespace());
}

v8::Handle<v8::Value>
XmlNode::Namespaces(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode* node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->get_all_namespaces());
}

v8::Handle<v8::Value>
XmlNode::Parent(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode* node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->get_parent());
}

v8::Handle<v8::Value>
XmlNode::PrevSibling(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode *node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->get_prev_sibling());
}

v8::Handle<v8::Value>
XmlNode::NextSibling(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode *node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->get_next_sibling());
}

v8::Handle<v8::Value>
XmlNode::Type(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode *node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->get_type());
}

v8::Handle<v8::Value>
XmlNode::ToString(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode *node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->to_string());
}

v8::Handle<v8::Value>
XmlNode::Remove(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode *node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  node->remove();

  return scope.Close(args.Holder());
}

v8::Handle<v8::Value>
XmlNode::Clone(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode *node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  bool recurse = true;

  if (args.Length() == 1 && args[0]->IsBoolean())
      recurse = args[0]->ToBoolean()->BooleanValue();

  return scope.Close(node->clone(recurse));
}

v8::Handle<v8::Value>
XmlNode::New(xmlNode* node)
{
  switch (node->type) {
  case XML_ATTRIBUTE_NODE:
    return XmlAttribute::New(reinterpret_cast<xmlAttr *>(node));

  default:
    // if we don't know how to convert to specific libxmljs wrapper,
    // wrap in an XmlElement.  There should probably be specific
    // wrapper types for text nodes etc., but this is what existing
    // code expects.
    return XmlElement::New(node);
  }
}

XmlNode::XmlNode(xmlNode* node) : xml_obj(node) {
    xml_obj->_private = this;

    // this will prevent the document from being cleaned up
    // we keep the document if any of the nodes attached to it are still alive
    XmlDocument* doc = static_cast<XmlDocument*>(xml_obj->doc->_private);
    doc->ref();
}

XmlNode::~XmlNode() {
    xml_obj->_private = NULL;

    // release the hold and allow the document to be freed
    XmlDocument* doc = static_cast<XmlDocument*>(xml_obj->doc->_private);
    doc->unref();

  // We do not free the xmlNode here. It could still be part of a document
  // It will be freed when the doc is freed
  // xmlFree(xml_obj);
}

v8::Handle<v8::Value>
XmlNode::get_doc() {
    return XmlDocument::New(xml_obj->doc);
}

v8::Handle<v8::Value>
XmlNode::remove_namespace() {
  xml_obj->ns = NULL;
  return v8::Null();
}

v8::Handle<v8::Value>
XmlNode::get_namespace() {
  v8::HandleScope scope;
  if (!xml_obj->ns)
  {
      return v8::Null();
  }

  return scope.Close(XmlNamespace::New(xml_obj->ns));
}

void
XmlNode::set_namespace(xmlNs* ns) {
  xmlSetNs(xml_obj, ns);
  assert(xml_obj->ns);
}

xmlNs*
XmlNode::find_namespace(const char* search_str) {
  xmlNs* ns = NULL;

  // Find by prefix first
  ns = xmlSearchNs(xml_obj->doc, xml_obj, (const xmlChar*)search_str);

  // Or find by href
  if (!ns)
    ns = xmlSearchNsByHref(xml_obj->doc, xml_obj, (const xmlChar*)search_str);

  return ns;
}

v8::Handle<v8::Value>
XmlNode::get_all_namespaces() {
  v8::HandleScope scope;

  // Iterate through namespaces
  v8::Local<v8::Array> namespaces = v8::Array::New();
  xmlNs** nsList = xmlGetNsList(xml_obj->doc, xml_obj);
  if (nsList != NULL) {
    for (int i = 0; nsList[i] != NULL; i++) {
      v8::Handle<v8::Number> index = v8::Number::New(i);
      v8::Handle<v8::Object> ns = XmlNamespace::New(nsList[i]);
      namespaces->Set(index, ns);
    }
  }

  return scope.Close(namespaces);
}

v8::Handle<v8::Value>
XmlNode::get_parent() {
  v8::HandleScope scope;

  if (xml_obj->parent) {
      return scope.Close(XmlElement::New(xml_obj->parent));
  }

  return scope.Close(XmlDocument::New(xml_obj->doc));
}

v8::Handle<v8::Value>
XmlNode::get_prev_sibling() {
  v8::HandleScope scope;
  if (xml_obj->prev) {
      return scope.Close(XmlNode::New(xml_obj->prev));
  }

  return v8::Null();
}

v8::Handle<v8::Value>
XmlNode::get_next_sibling() {
  v8::HandleScope scope;
  if (xml_obj->next) {
      return scope.Close(XmlNode::New(xml_obj->next));
  }

  return v8::Null();
}

v8::Handle<v8::Value>
XmlNode::clone(bool recurse) {
  v8::HandleScope scope;

  return scope.Close(XmlNode::New(xmlCopyNode(xml_obj, recurse)));
}

v8::Handle<v8::Value>
XmlNode::to_string() {
  v8::HandleScope scope;

  xmlBuffer* buf = xmlBufferCreate();
  const char* enc = "UTF-8";

  xmlSaveCtxt* savectx = xmlSaveToBuffer(buf, enc, 0);
  xmlSaveTree(savectx, xml_obj);
  xmlSaveFlush(savectx);

  const xmlChar* xmlstr = xmlBufferContent(buf);

  if(xmlstr) {
      v8::Handle<v8::String> str = v8::String::New((char*)xmlstr, xmlBufferLength(buf));
      xmlSaveClose(savectx);

      xmlBufferFree(buf);

      return scope.Close(str);
  } else {
      xmlSaveClose(savectx);

      xmlBufferFree(buf);

      return v8::Null();
  }
}

void
XmlNode::remove() {
  xmlUnlinkNode(xml_obj);
}

v8::Handle<v8::Value>
XmlNode::get_type() {
  switch (xml_obj->type) {
  case  XML_ELEMENT_NODE:
    return v8::String::NewSymbol("element");
  case XML_ATTRIBUTE_NODE:
    return v8::String::NewSymbol("attribute");
  case XML_TEXT_NODE:
    return v8::String::NewSymbol("text");
  case XML_CDATA_SECTION_NODE:
    return v8::String::NewSymbol("cdata");
  case XML_ENTITY_REF_NODE:
    return v8::String::NewSymbol("entity_ref");
  case XML_ENTITY_NODE:
    return v8::String::NewSymbol("entity");
  case XML_PI_NODE:
    return v8::String::NewSymbol("pi");
  case XML_COMMENT_NODE:
    return v8::String::NewSymbol("comment");
  case XML_DOCUMENT_NODE:
    return v8::String::NewSymbol("document");
  case XML_DOCUMENT_TYPE_NODE:
    return v8::String::NewSymbol("document_type");
  case XML_DOCUMENT_FRAG_NODE:
    return v8::String::NewSymbol("document_frag");
  case XML_NOTATION_NODE:
    return v8::String::NewSymbol("notation");
  case XML_HTML_DOCUMENT_NODE:
    return v8::String::NewSymbol("html_document");
  case XML_DTD_NODE:
    return v8::String::NewSymbol("dtd");
  case XML_ELEMENT_DECL:
    return v8::String::NewSymbol("element_decl");
  case XML_ATTRIBUTE_DECL:
    return v8::String::NewSymbol("attribute_decl");
  case XML_ENTITY_DECL:
    return v8::String::NewSymbol("entity_decl");
  case XML_NAMESPACE_DECL:
    return v8::String::NewSymbol("namespace_decl");
  case XML_XINCLUDE_START:
    return v8::String::NewSymbol("xinclude_start");
  case XML_XINCLUDE_END:
    return v8::String::NewSymbol("xinclude_end");
  case XML_DOCB_DOCUMENT_NODE:
    return v8::String::NewSymbol("docb_document");
  }

  return v8::Null();
}

void
XmlNode::Initialize(v8::Handle<v8::Object> target) {
  v8::HandleScope scope;
  constructor_template =
    v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New());
  constructor_template->InstanceTemplate()->SetInternalFieldCount(1);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "doc",
                        XmlNode::Doc);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "parent",
                        XmlNode::Parent);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "namespace",
                        XmlNode::Namespace);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "namespaces",
                        XmlNode::Namespaces);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "prevSibling",
                        XmlNode::PrevSibling);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "nextSibling",
                        XmlNode::NextSibling);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "type",
                        XmlNode::Type);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "remove",
                        XmlNode::Remove);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "clone",
                        XmlNode::Clone);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "toString",
                        XmlNode::ToString);

  XmlElement::Initialize(target);
  XmlAttribute::Initialize(target);
}
}  // namespace libxmljs
<commit_msg>fix leak of xmlNodes when not linked to a document<commit_after>// Copyright 2009, Squish Tech, LLC.

#include <node.h>

#include <libxml/xmlsave.h>

#include "xml_node.h"
#include "xml_document.h"
#include "xml_namespace.h"
#include "xml_element.h"
#include "xml_attribute.h"

namespace libxmljs {

v8::Persistent<v8::FunctionTemplate> XmlNode::constructor_template;

v8::Handle<v8::Value>
XmlNode::Doc(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode* node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->get_doc());
}

v8::Handle<v8::Value>
XmlNode::Namespace(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode* node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  // #namespace() Get the node's namespace
  if (args.Length() == 0) {
      return scope.Close(node->get_namespace());
  }

  if (args[0]->IsNull())
      return scope.Close(node->remove_namespace());

  XmlNamespace* ns = NULL;

  // #namespace(ns) libxml.Namespace object was provided
  // TODO(sprsquish): check that it was actually given a namespace obj
  if (args[0]->IsObject())
    ns = ObjectWrap::Unwrap<XmlNamespace>(args[0]->ToObject());

  // #namespace(href) or #namespace(prefix, href)
  // if the namespace has already been defined on the node, just set it
  if (args[0]->IsString()) {
    v8::String::Utf8Value ns_to_find(args[0]->ToString());
    xmlNs* found_ns = node->find_namespace(*ns_to_find);
    if (found_ns) {
        // maybe build
        v8::Handle<v8::Object> existing = XmlNamespace::New(found_ns);
        ns = ObjectWrap::Unwrap<XmlNamespace>(existing);
    }
  }

  // Namespace does not seem to exist, so create it.
  if (!ns) {
      const unsigned int argc = 3;
      v8::Handle<v8::Value> argv[argc];
      argv[0] = args.Holder();

      if (args.Length() == 1) {
          argv[1] = v8::Null();
          argv[2] = args[0];
      } else {
          argv[1] = args[0];
          argv[2] = args[1];
      }

      v8::Handle<v8::Function> define_namespace =
          XmlNamespace::constructor_template->GetFunction();

      // will create a new namespace attached to this node
      // since we keep the document around, the namespace, like the node, won't be
      // garbage collected
      v8::Handle<v8::Value> new_ns = define_namespace->NewInstance(argc, argv);
      ns = ObjectWrap::Unwrap<XmlNamespace>(new_ns->ToObject());
  }

  node->set_namespace(ns->xml_obj);
  return scope.Close(node->get_namespace());
}

v8::Handle<v8::Value>
XmlNode::Namespaces(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode* node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->get_all_namespaces());
}

v8::Handle<v8::Value>
XmlNode::Parent(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode* node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->get_parent());
}

v8::Handle<v8::Value>
XmlNode::PrevSibling(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode *node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->get_prev_sibling());
}

v8::Handle<v8::Value>
XmlNode::NextSibling(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode *node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->get_next_sibling());
}

v8::Handle<v8::Value>
XmlNode::Type(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode *node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->get_type());
}

v8::Handle<v8::Value>
XmlNode::ToString(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode *node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  return scope.Close(node->to_string());
}

v8::Handle<v8::Value>
XmlNode::Remove(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode *node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  node->remove();

  return scope.Close(args.Holder());
}

v8::Handle<v8::Value>
XmlNode::Clone(const v8::Arguments& args) {
  v8::HandleScope scope;
  XmlNode *node = ObjectWrap::Unwrap<XmlNode>(args.Holder());
  assert(node);

  bool recurse = true;

  if (args.Length() == 1 && args[0]->IsBoolean())
      recurse = args[0]->ToBoolean()->BooleanValue();

  return scope.Close(node->clone(recurse));
}

v8::Handle<v8::Value>
XmlNode::New(xmlNode* node)
{
  switch (node->type) {
  case XML_ATTRIBUTE_NODE:
    return XmlAttribute::New(reinterpret_cast<xmlAttr *>(node));

  default:
    // if we don't know how to convert to specific libxmljs wrapper,
    // wrap in an XmlElement.  There should probably be specific
    // wrapper types for text nodes etc., but this is what existing
    // code expects.
    return XmlElement::New(node);
  }
}

XmlNode::XmlNode(xmlNode* node) : xml_obj(node) {
    xml_obj->_private = this;

    // this will prevent the document from being cleaned up
    // we keep the document if any of the nodes attached to it are still alive
    XmlDocument* doc = static_cast<XmlDocument*>(xml_obj->doc->_private);
    doc->ref();
}

XmlNode::~XmlNode() {
    xml_obj->_private = NULL;

    // release the hold and allow the document to be freed
    XmlDocument* doc = static_cast<XmlDocument*>(xml_obj->doc->_private);
    doc->unref();

    // We do not free the xmlNode here if it is linked to a document
    // It will be freed when the doc is freed
    if (xml_obj->parent == NULL)
      xmlFreeNode(xml_obj);
}

v8::Handle<v8::Value>
XmlNode::get_doc() {
    return XmlDocument::New(xml_obj->doc);
}

v8::Handle<v8::Value>
XmlNode::remove_namespace() {
  xml_obj->ns = NULL;
  return v8::Null();
}

v8::Handle<v8::Value>
XmlNode::get_namespace() {
  v8::HandleScope scope;
  if (!xml_obj->ns)
  {
      return v8::Null();
  }

  return scope.Close(XmlNamespace::New(xml_obj->ns));
}

void
XmlNode::set_namespace(xmlNs* ns) {
  xmlSetNs(xml_obj, ns);
  assert(xml_obj->ns);
}

xmlNs*
XmlNode::find_namespace(const char* search_str) {
  xmlNs* ns = NULL;

  // Find by prefix first
  ns = xmlSearchNs(xml_obj->doc, xml_obj, (const xmlChar*)search_str);

  // Or find by href
  if (!ns)
    ns = xmlSearchNsByHref(xml_obj->doc, xml_obj, (const xmlChar*)search_str);

  return ns;
}

v8::Handle<v8::Value>
XmlNode::get_all_namespaces() {
  v8::HandleScope scope;

  // Iterate through namespaces
  v8::Local<v8::Array> namespaces = v8::Array::New();
  xmlNs** nsList = xmlGetNsList(xml_obj->doc, xml_obj);
  if (nsList != NULL) {
    for (int i = 0; nsList[i] != NULL; i++) {
      v8::Handle<v8::Number> index = v8::Number::New(i);
      v8::Handle<v8::Object> ns = XmlNamespace::New(nsList[i]);
      namespaces->Set(index, ns);
    }
  }

  return scope.Close(namespaces);
}

v8::Handle<v8::Value>
XmlNode::get_parent() {
  v8::HandleScope scope;

  if (xml_obj->parent) {
      return scope.Close(XmlElement::New(xml_obj->parent));
  }

  return scope.Close(XmlDocument::New(xml_obj->doc));
}

v8::Handle<v8::Value>
XmlNode::get_prev_sibling() {
  v8::HandleScope scope;
  if (xml_obj->prev) {
      return scope.Close(XmlNode::New(xml_obj->prev));
  }

  return v8::Null();
}

v8::Handle<v8::Value>
XmlNode::get_next_sibling() {
  v8::HandleScope scope;
  if (xml_obj->next) {
      return scope.Close(XmlNode::New(xml_obj->next));
  }

  return v8::Null();
}

v8::Handle<v8::Value>
XmlNode::clone(bool recurse) {
  v8::HandleScope scope;

  return scope.Close(XmlNode::New(xmlCopyNode(xml_obj, recurse)));
}

v8::Handle<v8::Value>
XmlNode::to_string() {
  v8::HandleScope scope;

  xmlBuffer* buf = xmlBufferCreate();
  const char* enc = "UTF-8";

  xmlSaveCtxt* savectx = xmlSaveToBuffer(buf, enc, 0);
  xmlSaveTree(savectx, xml_obj);
  xmlSaveFlush(savectx);

  const xmlChar* xmlstr = xmlBufferContent(buf);

  if(xmlstr) {
      v8::Handle<v8::String> str = v8::String::New((char*)xmlstr, xmlBufferLength(buf));
      xmlSaveClose(savectx);

      xmlBufferFree(buf);

      return scope.Close(str);
  } else {
      xmlSaveClose(savectx);

      xmlBufferFree(buf);

      return v8::Null();
  }
}

void
XmlNode::remove() {
  xmlUnlinkNode(xml_obj);
}

v8::Handle<v8::Value>
XmlNode::get_type() {
  switch (xml_obj->type) {
  case  XML_ELEMENT_NODE:
    return v8::String::NewSymbol("element");
  case XML_ATTRIBUTE_NODE:
    return v8::String::NewSymbol("attribute");
  case XML_TEXT_NODE:
    return v8::String::NewSymbol("text");
  case XML_CDATA_SECTION_NODE:
    return v8::String::NewSymbol("cdata");
  case XML_ENTITY_REF_NODE:
    return v8::String::NewSymbol("entity_ref");
  case XML_ENTITY_NODE:
    return v8::String::NewSymbol("entity");
  case XML_PI_NODE:
    return v8::String::NewSymbol("pi");
  case XML_COMMENT_NODE:
    return v8::String::NewSymbol("comment");
  case XML_DOCUMENT_NODE:
    return v8::String::NewSymbol("document");
  case XML_DOCUMENT_TYPE_NODE:
    return v8::String::NewSymbol("document_type");
  case XML_DOCUMENT_FRAG_NODE:
    return v8::String::NewSymbol("document_frag");
  case XML_NOTATION_NODE:
    return v8::String::NewSymbol("notation");
  case XML_HTML_DOCUMENT_NODE:
    return v8::String::NewSymbol("html_document");
  case XML_DTD_NODE:
    return v8::String::NewSymbol("dtd");
  case XML_ELEMENT_DECL:
    return v8::String::NewSymbol("element_decl");
  case XML_ATTRIBUTE_DECL:
    return v8::String::NewSymbol("attribute_decl");
  case XML_ENTITY_DECL:
    return v8::String::NewSymbol("entity_decl");
  case XML_NAMESPACE_DECL:
    return v8::String::NewSymbol("namespace_decl");
  case XML_XINCLUDE_START:
    return v8::String::NewSymbol("xinclude_start");
  case XML_XINCLUDE_END:
    return v8::String::NewSymbol("xinclude_end");
  case XML_DOCB_DOCUMENT_NODE:
    return v8::String::NewSymbol("docb_document");
  }

  return v8::Null();
}

void
XmlNode::Initialize(v8::Handle<v8::Object> target) {
  v8::HandleScope scope;
  constructor_template =
    v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New());
  constructor_template->InstanceTemplate()->SetInternalFieldCount(1);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "doc",
                        XmlNode::Doc);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "parent",
                        XmlNode::Parent);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "namespace",
                        XmlNode::Namespace);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "namespaces",
                        XmlNode::Namespaces);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "prevSibling",
                        XmlNode::PrevSibling);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "nextSibling",
                        XmlNode::NextSibling);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "type",
                        XmlNode::Type);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "remove",
                        XmlNode::Remove);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "clone",
                        XmlNode::Clone);

  NODE_SET_PROTOTYPE_METHOD(constructor_template,
                        "toString",
                        XmlNode::ToString);

  XmlElement::Initialize(target);
  XmlAttribute::Initialize(target);
}
}  // namespace libxmljs
<|endoftext|>