view client/main.cpp @ 26:56cc058200b5

Client: add basic mlk-client code with an example, #472
author David Demelier <markand@malikania.fr>
date Fri, 08 Apr 2016 14:16:47 +0200
parents e33b246ac2d3
children 0a1adf7dcca0
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-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);

	return ctx;
}

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

	if (duk::is<duk::Function>(ctx, -1)) {
		duk::getGlobal<void>(ctx, "\xff""\xff""window");
		duk::pcall(ctx, 1);
		duk::pop(ctx);
	} else {
		duk::pop(ctx);
	}
}

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

	if (duk::is<duk::Function>(ctx, -1)) {
		duk::pcall(ctx, 0);
		duk::pop(ctx);
	} else {
		duk::pop(ctx);
	}
}

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

	if (duk::is<duk::Function>(ctx, -1)) {
		duk::getGlobal<void>(ctx, "\xff""\xff""window");
		duk::pcall(ctx, 1);
		duk::pop(ctx);
	} else {
		duk::pop(ctx);
	}
}

int run(duk::Context &ctx)
{
	bool running = true;

	/* js-window use duk::Pointer at the moment so store it from there temporarily */
	duk::putGlobal(ctx, "\xff""\xff""window", duk::Pointer<Window>{new Window});

	Window *window = duk::getGlobal<duk::Pointer<Window>>(ctx, "\xff""\xff""window");

	window->setOnQuit([&] () {
		running = false;
	});
	window->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);
		}
	});
	window->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);

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

		update(ctx);
		draw(ctx);

		// 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", duk::RawPointer<ClientResourcesLoader>{&loader});

	if (duk::pevalFile(ctx, path) != 0) {
		duk::ErrorInfo info = duk::error(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]);
}