diff 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 diff
--- a/client/main.cpp	Wed Apr 06 13:33:30 2016 +0200
+++ b/client/main.cpp	Fri Apr 08 14:16:47 2016 +0200
@@ -1,7 +1,7 @@
 /*
- * main.cpp -- main client files
+ * main.cpp -- main client file
  *
- * Copyright (c) 2014 David Demelier <markand@malikania.fr>
+ * 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
@@ -16,225 +16,178 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#if 0
-
+#include <chrono>
 #include <iostream>
-#include <chrono>
 #include <thread>
-#include <map>
-#include <malikania/Json.h>
-#include <malikania/Window.h>
-#include <malikania/Size.h>
-#include <malikania/Sprite.h>
-#include <malikania/Image.h>
-#include <malikania/Point.h>
-#include <malikania/Label.h>
-#include <malikania/Animation.h>
-#include <malikania/Animator.h>
+
+#include <malikania/client-resources-loader.h>
+#include <malikania/resources-locator.h>
 
-using namespace std::literals::chrono_literals;
+#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>
 
-// TODO delete this... just for fun
-bool goRight = true;
-bool goDown = true;
-const int mokoSize = 300;
+using namespace malikania;
+
+namespace {
+
+int usage()
+{
+	std::cerr << "usage: mlk-client directory\n";
+
+	return 1;
+}
 
-void bounce(malikania::Window& window, int &x, int &y) {
-	malikania::Size resolution = window.getWindowResolution();
-	int width = resolution.width;
-	int height = resolution.height;
-	if (y < 10) {
-		goDown = true;
-		y += 1;
-	}
-	if (goDown && y < height - mokoSize) {
-		// Moko falls
-		y += 0.2 * y;
+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 {
-		// Moko will bounce!!!
-		goDown = false;
-	}
-	if (!goDown && y > 0) {
-		y -= 0.1 * y;
-	} else {
-		goDown = true;
-	}
-
-	if (goRight && x < width - mokoSize) {
-		x += 4;
-	} else {
-		goRight = false;
-	}
-	if (!goRight && x > 0) {
-		x -= 4;
-	} else {
-		goRight = true;
+		duk::pop(ctx);
 	}
 }
 
-// End TODO
+void update(duk::Context &ctx)
+{
+	duk::getGlobal<void>(ctx, "update");
 
-int main(void)
-{
-	malikania::Window mainWindow;
+	if (duk::is<duk::Function>(ctx, -1)) {
+		duk::pcall(ctx, 0);
+		duk::pop(ctx);
+	} else {
+		duk::pop(ctx);
+	}
+}
 
-	bool isBouncing = false;
+void draw(duk::Context &ctx)
+{
+	duk::getGlobal<void>(ctx, "draw");
 
-	int mokoPositionX = 0;
-	int mokoPositionY = 0;
+	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);
+	}
+}
 
-	std::map<int, bool> keyPressed = { {SDLK_UP, false}, {SDLK_DOWN, false}, {SDLK_RIGHT, false}, {SDLK_LEFT, false} };
+int run(duk::Context &ctx)
+{
+	bool running = true;
 
-	mainWindow.setOnKeyDown([&mainWindow, &mokoPositionX, &mokoPositionY, &isBouncing, &keyPressed](int sdlKey) {
-		switch (sdlKey) {
-		case SDLK_ESCAPE:
-			mainWindow.close();
-			break;
-		case SDLK_UP:
-			keyPressed[SDLK_UP] = true;
-			break;
-		case SDLK_DOWN:
-			keyPressed[SDLK_DOWN] = true;
-			break;
-		case SDLK_RIGHT:
-			keyPressed[SDLK_RIGHT] = true;
-			break;
-		case SDLK_LEFT:
-			keyPressed[SDLK_LEFT] = true;
-			break;
-		case SDLK_m:
-			isBouncing = !isBouncing;
-			break;
+	/* 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);
 		}
 	});
 
-	mainWindow.setOnKeyUp([&keyPressed](int sdlKey) {
-		switch (sdlKey) {
-		case SDLK_UP:
-			keyPressed[SDLK_UP] = false;
-			break;
-		case SDLK_DOWN:
-			keyPressed[SDLK_DOWN] = false;
-			break;
-		case SDLK_RIGHT:
-			keyPressed[SDLK_RIGHT] = false;
-			break;
-		case SDLK_LEFT:
-			keyPressed[SDLK_LEFT] = false;
-			break;
-		}
-	});
+	start(ctx);
 
-	int animationStep = 1;
-	mainWindow.setOnRefresh([&mainWindow, &keyPressed, &animationStep](){
-		if (keyPressed[SDLK_LEFT]) {
-			std::string animationState = "left" + std::to_string(animationStep > 4 ? 4 : animationStep++);
-		} else if (keyPressed[SDLK_RIGHT]) {
-			std::string animationState = "right" + std::to_string(animationStep > 4 ? 4 : animationStep++);
-		} else if (keyPressed[SDLK_DOWN]) {
-			std::string animationState = "down" + std::to_string(animationStep > 4 ? 4 : animationStep++);
-		} else {
-			animationStep = 1;
-		}
-	});
-
-	malikania::Sprite testSprite = malikania::Sprite::fromJson(mainWindow, malikania::JsonDocument(
-		"{\"image\": \"resources/images/mokodemo.png\", \"alias\": \"testSprite\", \"cell\": [300, 300], \"size\": [1200, 900]}"
-	).toObject());
-
-	std::shared_ptr<malikania::Font> font = std::make_shared<malikania::Font>("resources/fonts/DejaVuSans.ttf", 48);
-	malikania::Label testLabel("Malikania !!! Youpi !", font, {0, 0, 100, 50});
-
-	std::shared_ptr<malikania::Animation> testAnimation = std::make_shared<malikania::Animation>(malikania::Animation::fromJson(mainWindow, malikania::JsonDocument(
-		std::string("{\"sprite\": \"no-working-yet.json\", \"alias\": \"testAnimation\", \"frames\": [")
-		+ "{ \"delay\": 200, \"cell\": 0 }, { \"delay\": 10, \"cell\": 1 },"
-		+ "{ \"delay\": 10, \"cell\": 2 }, { \"delay\": 200, \"cell\": 3 },"
-		+ "{ \"delay\": 10, \"cell\": 1 }, { \"delay\": 10, \"cell\": 1 },"
-		+ "{ \"delay\": 200, \"cell\": 4 }, { \"delay\": 10, \"cell\": 5 },"
-		+ "{ \"delay\": 10, \"cell\": 6 }, { \"delay\": 200, \"cell\": 7 },"
-		+ "{ \"delay\": 10, \"cell\": 6 }, { \"delay\": 10, \"cell\": 5 },"
-		+ "{ \"delay\": 200, \"cell\": 8 }, { \"delay\": 10, \"cell\": 9 },"
-		+ "{ \"delay\": 10, \"cell\": 10 }, { \"delay\": 200, \"cell\": 11 },"
-		+ "{ \"delay\": 10, \"cell\": 10 }, { \"delay\": 10, \"cell\": 9 }"
-		+ "]}"
-	).toObject()));
-
-	std::shared_ptr<malikania::Animation> testAnimation2 =  std::make_shared<malikania::Animation>(malikania::Animation::fromJson(mainWindow, malikania::JsonDocument(
-		std::string("{\"sprite\": \"no-working-yet.json\", \"alias\": \"testAnimation\", \"frames\": [")
-		+ "{ \"delay\": 2000, \"cell\": 0 }, { \"delay\": 10, \"cell\": 1 },"
-		+ "{ \"delay\": 10, \"cell\": 2 }, { \"delay\": 2000, \"cell\": 3 },"
-		+ "{ \"delay\": 10, \"cell\": 1 }, { \"delay\": 10, \"cell\": 1 }"
-		+ "]}"
-	).toObject()));
+	while (running) {
+		window->poll();
 
-	malikania::Animator testAnimator1 = malikania::Animator(testAnimation);
-	malikania::Animator testAnimator2 = malikania::Animator(std::move(testAnimation));
-	malikania::Animator testAnimator3 = malikania::Animator(std::move(testAnimation2));
-
-	while (mainWindow.isOpen()) {
-
-		// TODO delete this, just for fun...
-		if (isBouncing) {
-			bounce(mainWindow, mokoPositionX, mokoPositionY);
-		}
-
-		mainWindow.processEvent();
-		mainWindow.setDrawingColor({255, 255, 255, 255});
-		mainWindow.clear();
-		mainWindow.update();
-
-		testSprite.draw(mainWindow, 0, {0, 0, 300, 300});
-		testSprite.draw(mainWindow, 1, {200, 200, 300, 300});
-		testSprite.draw(mainWindow, 2, {400, 400, 300, 300});
-		testSprite.draw(mainWindow, 11, {600, 400, 300, 300});
-
-		malikania::Color c{255, 50, 40, 255};
-		mainWindow.setDrawingColor(c);
-		mainWindow.drawLine({0, 0, 300, 300});
-
-		std::vector<malikania::Point> points{{20, 20}, {30, 50}, {100, 200}, {30, 60}, {20, 300}, {100, 20}};
-		mainWindow.drawLines(points);
+		update(ctx);
+		draw(ctx);
 
-		mainWindow.setDrawingColor({200, 50, 200, 255});
-		mainWindow.drawPoint({400, 400});
-		mainWindow.drawPoint({400, 402});
-		mainWindow.drawPoint({400, 405});
-		mainWindow.drawPoint({400, 407});
-		mainWindow.drawPoint({400, 410});
-
-		mainWindow.setDrawingColor({0, 0, 0, 255});
-		mainWindow.drawPoints(points);
-
-		mainWindow.setDrawingColor({30, 30, 30, 255});
-		mainWindow.drawRectangle({500, 500, 200, 100});
-
-		mainWindow.setDrawingColor({130, 30, 30, 255});
-		mainWindow.drawRectangles({{800, 800, 200, 100}, {700, 700, 200, 100}, {750, 750, 200, 100}});
-
-		mainWindow.drawRectangle({600, 200, 200, 100}, true, {0, 255, 0, 255});
-
-		mainWindow.drawRectangles(
-			{{800, 400, 200, 100}, {700, 450, 200, 100}, {750, 500, 200, 100}},
-			true,
-			{{255,0,0,255},{0,255,0,255},{0,0,255,255}}
-		);
-
-		testLabel.draw(mainWindow, {300, 300, 200, 50});
-
-		testAnimator1.draw(mainWindow, {1000, 0, 300, 300});
-		testAnimator2.draw(mainWindow, {100, 600, 300, 300});
-		testAnimator3.draw(mainWindow, {400, 600, 300, 300});
-
-		mainWindow.present();
-
-		std::this_thread::sleep_for(5ms);
+		// TODO: remove this with an appropriate FPS calculation.
+		std::this_thread::sleep_for(std::chrono::milliseconds(50));
 	}
 
-	//malikania::Window::quit();
-
 	return 0;
 }
 
-#endif
+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;
 
-int main() { return 0; }
+		return 1;
+	}
+
+	return run(ctx);
+}
+
+} // !namespace
+
+int main(int argc, char **argv)
+{
+	-- argc;
+	++ argv;
+
+	if (argc < 1) {
+		return usage();
+	}
+
+	return boot(argv[0]);
+}