view client/main.cpp @ 27:0a1adf7dcca0

Common: update libjs and adapt code
author David Demelier <markand@malikania.fr>
date Tue, 12 Apr 2016 13:53:11 +0200
parents 56cc058200b5
children 80736513d699
line wrap: on
line source

/*
 * main.cpp -- main client file
 *
 * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <chrono>
#include <iostream>
#include <thread>

#include <malikania/client-resources-loader.h>
#include <malikania/resources-locator.h>

#include <malikania/js-animation.h>
#include <malikania/js-animator.h>
#include <malikania/js-client.h>
#include <malikania/js-client-target.h>
#include <malikania/js-color.h>
#include <malikania/js-font.h>
#include <malikania/js-image.h>
#include <malikania/js-line.h>
#include <malikania/js-point.h>
#include <malikania/js-rectangle.h>
#include <malikania/js-size.h>
#include <malikania/js-sprite.h>
#include <malikania/js-window.h>

using namespace malikania;

namespace {

int usage()
{
	std::cerr << "usage: mlk-client directory\n";

	return 1;
}

duk::Context init()
{
	duk::Context ctx;

	/* TODO: Put Malikania global somewhere else */
	duk::putGlobal(ctx, "Malikania", duk::Object());

	loadMalikaniaAnimation(ctx);
	loadMalikaniaAnimator(ctx);
	loadMalikaniaColor(ctx);
	loadMalikaniaFont(ctx);
	loadMalikaniaImage(ctx);
	loadMalikaniaLine(ctx);
	loadMalikaniaPoint(ctx);
	loadMalikaniaRectangle(ctx);
	loadMalikaniaSize(ctx);
	loadMalikaniaSprite(ctx);
	loadMalikaniaWindow(ctx);
	loadMalikaniaClient(ctx);
	loadMalikaniaClientTarget(ctx);

	return ctx;
}

void start(duk::Context &ctx, std::shared_ptr<Client> client)
{
	duk::getGlobal<void>(ctx, "start");

	if (duk::is<duk::Function>(ctx, -1)) {
		duk::push(ctx, std::move(client));
		duk::pcall(ctx, 1);
		duk::pop(ctx);
	} else {
		duk::pop(ctx);
	}
}

void update(duk::Context &ctx, std::shared_ptr<Client> client)
{
	duk::getGlobal<void>(ctx, "update");

	if (duk::is<duk::Function>(ctx, -1)) {
		duk::push(ctx, std::move(client));
		duk::pcall(ctx, 1);
		duk::pop(ctx);
	} else {
		duk::pop(ctx);
		client->update();
	}
}

void draw(duk::Context &ctx, std::shared_ptr<Client> client)
{
	duk::getGlobal<void>(ctx, "draw");

	if (duk::is<duk::Function>(ctx, -1)) {
		duk::push(ctx, std::move(client));
		duk::pcall(ctx, 1);
		duk::pop(ctx);
	} else {
		duk::pop(ctx);
		client->draw();
	}
}

int run(duk::Context &ctx)
{
	auto running = true;
	auto client = std::make_shared<Client>();

	client->setOnQuit([&] () {
		running = false;
	});
	client->setOnKeyDown([&] (unsigned key) {
		duk::getGlobal<void>(ctx, "keyDown");

		if (duk::is<duk::Function>(ctx, -1)) {
			duk::push(ctx, static_cast<int>(key));
			duk::pcall(ctx, 1);
			duk::pop(ctx);
		} else {
			duk::pop(ctx);
		}
	});
	client->setOnKeyDown([&] (unsigned key) {
		duk::getGlobal<void>(ctx, "keyUp");

		if (duk::is<duk::Function>(ctx, -1)) {
			duk::push(ctx, static_cast<int>(key));
			duk::pcall(ctx, 1);
			duk::pop(ctx);
		} else {
			duk::pop(ctx);
		}
	});

	start(ctx, client);

	while (running) {
		client->poll();

		update(ctx, client);
		draw(ctx, client);

		// TODO: remove this with an appropriate FPS calculation.
		std::this_thread::sleep_for(std::chrono::milliseconds(50));
	}

	return 0;
}

int boot(const std::string &directory)
{
	std::string path = directory + "/client.js";
	duk::Context ctx = init();

	/* Store the loader */
	ResourcesLocatorDirectory locator(directory);
	ClientResourcesLoader loader(locator);

	duk::putGlobal(ctx, "\xff""\xff""loader", &loader);

	if (duk::pevalFile(ctx, path) != 0) {
		duk::Exception info = duk::exception(ctx, -1);

		std::cerr << info.fileName << ":" << info.lineNumber << ": " << info.stack << std::endl;

		return 1;
	}

	return run(ctx);
}

} // !namespace

int main(int argc, char **argv)
{
	-- argc;
	++ argv;

	if (argc < 1) {
		return usage();
	}

	return boot(argv[0]);
}