changeset 210:1599919b5de6

client: allow starting a Javascript file
author David Demelier <markand@malikania.fr>
date Fri, 07 Dec 2018 19:31:10 +0100
parents b788b6a20eea
children ac99f440ee44
files libmlk-client-js/malikania/client/js/painter_js_api.cpp libmlk-client-js/malikania/client/js/texture_js_api.cpp libmlk-client-js/malikania/client/js/texture_js_api.hpp libmlk-client-js/malikania/client/js/window_js_api.cpp libmlk-client-js/malikania/client/js/window_js_api.hpp mlk-client/CMakeLists.txt mlk-client/main.cpp
diffstat 7 files changed, 177 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/libmlk-client-js/malikania/client/js/painter_js_api.cpp	Tue Dec 18 12:38:21 2018 +0100
+++ b/libmlk-client-js/malikania/client/js/painter_js_api.cpp	Fri Dec 07 19:31:10 2018 +0100
@@ -95,6 +95,22 @@
 	return 0;
 }
 
+auto Painter_prototype_use(duk_context* ctx) -> duk_ret_t
+{
+	try {
+		if (auto* w = mlk::js::duk::get<window>(ctx, 0); w)
+			self(ctx).use(*w);
+		else if (auto* t = mlk::js::duk::get<texture>(ctx, 0); t)
+			self(ctx).use(*t);
+		else
+			throw std::runtime_error("expected Window or Texture");
+	} catch (const std::exception& ex) {
+		duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what());
+	}
+
+	return 0;
+}
+
 auto Painter_prototype_present(duk_context* ctx) -> duk_ret_t
 {
 	try {
@@ -175,14 +191,15 @@
 } // !namespace
 
 const duk_function_list_entry methods[] = {
-	{ "clear",              Painter_prototype_clear,                 0 },
-	{ "drawingColor",       Painter_prototype_drawingColor,          0 },
-	{ "drawLine",           Painter_prototype_drawLine,              1 },
-	{ "drawPoint",          Painter_prototype_drawPoint,             1 },
-	{ "drawRectangle",      Painter_prototype_drawRectangle,         1 },
-	{ "fillRectangle",      Painter_prototype_fillRectangle,         1 },
-	{ "present",            Painter_prototype_present,               0 },
-	{ "setDrawingColor",    Painter_prototype_setDrawingColor,       1 },
+	{ "clear",              Painter_prototype_clear,                0 },
+	{ "use",                Painter_prototype_use,                  1 },
+	{ "drawingColor",       Painter_prototype_drawingColor,         0 },
+	{ "drawLine",           Painter_prototype_drawLine,             1 },
+	{ "drawPoint",          Painter_prototype_drawPoint,            1 },
+	{ "drawRectangle",      Painter_prototype_drawRectangle,        1 },
+	{ "fillRectangle",      Painter_prototype_fillRectangle,        1 },
+	{ "present",            Painter_prototype_present,              0 },
+	{ "setDrawingColor",    Painter_prototype_setDrawingColor,      1 },
 	{ nullptr,              nullptr,                                0 }
 };
 
--- a/libmlk-client-js/malikania/client/js/texture_js_api.cpp	Tue Dec 18 12:38:21 2018 +0100
+++ b/libmlk-client-js/malikania/client/js/texture_js_api.cpp	Fri Dec 07 19:31:10 2018 +0100
@@ -123,13 +123,7 @@
 
 auto type_traits<mlk::client::texture>::require(duk_context* ctx, duk_idx_t index) -> mlk::client::texture&
 {
-	assert(ctx);
-
-        mlk::js::duk::stack_guard sa(ctx);
-
-	duk_get_prop_string(ctx, index, mlk::client::js::signature.data());
-	auto ptr = duk_to_pointer(ctx, -1);
-	duk_pop(ctx);
+	auto ptr = get(ctx, index);
 
 	if (!ptr)
 		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Texture object");
@@ -137,4 +131,17 @@
 	return *static_cast<mlk::client::texture*>(ptr);
 }
 
+auto type_traits<mlk::client::texture>::get(duk_context* ctx, duk_idx_t index) -> mlk::client::texture*
+{
+	assert(ctx);
+
+        stack_guard sa(ctx);
+
+	duk_get_prop_string(ctx, index, mlk::client::js::signature.data());
+	auto ptr = duk_to_pointer(ctx, -1);
+	duk_pop(ctx);
+
+	return static_cast<mlk::client::texture*>(ptr);
+}
+
 } // !mlk::js::duk
--- a/libmlk-client-js/malikania/client/js/texture_js_api.hpp	Tue Dec 18 12:38:21 2018 +0100
+++ b/libmlk-client-js/malikania/client/js/texture_js_api.hpp	Fri Dec 07 19:31:10 2018 +0100
@@ -36,17 +36,38 @@
  */
 void load_texture_api(duk_context* ctx);
 
-} // !client
+} // !js
 
-} // !js
+} // !client
 
 } // !mlk
 
 namespace mlk::js::duk {
 
+/**
+ * \brief Specialize type_traits with mlk::client::texture.
+ */
 template <>
 struct type_traits<client::texture> {
+	/**
+	 * Require a texture at the given index or throw a Javascript error
+	 * instead.
+	 *
+	 * \param ctx the context
+	 * \param index the index
+	 * \return the texture
+	 */
         static auto require(duk_context* ctx, duk_idx_t index) -> client::texture&;
+
+	/**
+	 * Get a texture or return nullptr if not.
+	 *
+	 * \param ctx the context
+	 * \param index the index
+	 * \return the texture
+	 * \warning don't delete the texture
+	 */
+	static auto get(duk_context* ctx, duk_idx_t index) -> client::texture*;
 };
 
 } // !mlk::js::duk
--- a/libmlk-client-js/malikania/client/js/window_js_api.cpp	Tue Dec 18 12:38:21 2018 +0100
+++ b/libmlk-client-js/malikania/client/js/window_js_api.cpp	Fri Dec 07 19:31:10 2018 +0100
@@ -17,6 +17,8 @@
  */
 
 #include <cassert>
+#include <chrono>
+#include <thread>
 
 #include <malikania/client/window.hpp>
 
@@ -64,6 +66,18 @@
 	return 0;
 }
 
+auto Window_prototype_sleep(duk_context* ctx) -> duk_ret_t
+{
+	std::this_thread::sleep_for(std::chrono::seconds(mlk::js::duk::get<unsigned>(ctx, 0)));
+
+	return 0;
+}
+
+const duk_function_list_entry methods[] = {
+	{ "sleep",      Window_prototype_sleep,         1 },
+	{ nullptr,      nullptr,                        0 }
+};
+
 } // !namespace
 
 void load_window_api(duk_context* ctx)
@@ -73,9 +87,7 @@
 	duk_get_global_string(ctx, "Malikania");
 	duk_push_c_function(ctx, Window_constructor, 0);
 	duk_push_object(ctx);
-#if 0
 	duk_put_function_list(ctx, -1, methods);
-#endif
 	duk_put_prop_string(ctx, -2, "prototype");
 	duk_put_prop_string(ctx, -2, "Window");
 	duk_pop(ctx);
@@ -87,13 +99,7 @@
 
 auto type_traits<mlk::client::window>::require(duk_context* ctx, duk_idx_t index) -> mlk::client::window&
 {
-	assert(ctx);
-
-        mlk::js::duk::stack_guard sa(ctx);
-
-	duk_get_prop_string(ctx, index, mlk::client::js::signature.data());
-	auto ptr = duk_to_pointer(ctx, -1);
-	duk_pop(ctx);
+	auto ptr = get(ctx, index);
 
 	if (!ptr)
 		duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Window object");
@@ -101,4 +107,17 @@
 	return *static_cast<mlk::client::window*>(ptr);
 }
 
+auto type_traits<mlk::client::window>::get(duk_context* ctx, duk_idx_t index) -> mlk::client::window*
+{
+	assert(ctx);
+
+        stack_guard sa(ctx);
+
+	duk_get_prop_string(ctx, index, mlk::client::js::signature.data());
+	auto ptr = duk_to_pointer(ctx, -1);
+	duk_pop(ctx);
+
+	return static_cast<mlk::client::window*>(ptr);
+}
+
 } // !mlk::js::duk
--- a/libmlk-client-js/malikania/client/js/window_js_api.hpp	Tue Dec 18 12:38:21 2018 +0100
+++ b/libmlk-client-js/malikania/client/js/window_js_api.hpp	Fri Dec 07 19:31:10 2018 +0100
@@ -36,17 +36,38 @@
  */
 void load_window_api(duk_context* ctx);
 
-} // !client
+} // !js
 
-} // !js
+} // !client
 
 } // !mlk
 
 namespace mlk::js::duk {
 
+/**
+ * \brief Specialize type_traits with mlk::client::window.
+ */
 template <>
 struct type_traits<client::window> {
+	/**
+	 * Require a window at the given index or throw a Javascript error
+	 * instead.
+	 *
+	 * \param ctx the context
+	 * \param index the index
+	 * \return the window
+	 */
         static auto require(duk_context* ctx, duk_idx_t index) -> client::window&;
+
+	/**
+	 * Get a texture or return nullptr if not.
+	 *
+	 * \param ctx the context
+	 * \param index the index
+	 * \return the texture
+	 * \warning don't delete the texture
+	 */
+	static auto get(duk_context* ctx, duk_idx_t index) -> client::window*;
 };
 
 } // !mlk::js::duk
--- a/mlk-client/CMakeLists.txt	Tue Dec 18 12:38:21 2018 +0100
+++ b/mlk-client/CMakeLists.txt	Fri Dec 07 19:31:10 2018 +0100
@@ -32,5 +32,6 @@
 	LIBRARIES
 		${SDL2MAIN_LIBRARIES}
 		Threads::Threads
-		libmlk-client
+		libmlk-js
+		libmlk-client-js
 )
--- a/mlk-client/main.cpp	Tue Dec 18 12:38:21 2018 +0100
+++ b/mlk-client/main.cpp	Fri Dec 07 19:31:10 2018 +0100
@@ -16,64 +16,79 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <cerrno>
+#include <cstring>
+#include <fstream>
 #include <iostream>
-#include <chrono>
-#include <thread>
+#include <iterator>
 
-#include <malikania/client/color.hpp>
-#include <malikania/client/button.hpp>
-#include <malikania/client/window.hpp>
-#include <malikania/client/sprite.hpp>
-#include <malikania/client/theme.hpp>
-#include <malikania/client/painter.hpp>
-
-#include <assets/ui.hpp>
+#include <malikania/js/elapsed_timer_js_api.hpp>
+#include <malikania/js/line_js_api.hpp>
+#if 0
+#include <malikania/js/loader_js_api.hpp>
+#endif
+#include <malikania/js/point_js_api.hpp>
+#include <malikania/js/rectangle_js_api.hpp>
+#include <malikania/js/size_js_api.hpp>
 
-using namespace std::chrono_literals;
+#include <malikania/client/js/animation_js_api.hpp>
+#include <malikania/client/js/animator_js_api.hpp>
+#include <malikania/client/js/color_js_api.hpp>
+#include <malikania/client/js/font_js_api.hpp>
+#include <malikania/client/js/image_js_api.hpp>
+#if 0
+#include <malikania/client/js/loader_js_api.hpp>
+#endif
+#include <malikania/client/js/painter_js_api.hpp>
+#include <malikania/client/js/sprite_js_api.hpp>
+#include <malikania/client/js/texture_js_api.hpp>
+#include <malikania/client/js/window_js_api.hpp>
 
-int main(int, char**)
+int main(int argc, char** argv)
 {
-	mlk::client::window win(1920/2, 1080/2, "Hello");
-	mlk::client::image image(std::string(ui, sizeof (ui)));
-	mlk::client::sprite sprite(std::move(image), {16, 16});
-	mlk::client::painter painter(win);
-
-	for (;;) {
-		while (auto ev = win.poll()) {
-			if (std::holds_alternative<mlk::client::quit_event>(ev))
-				return 0;
-		}
+	-- argc;
+	++ argv;
 
-		painter.clear();
-		painter.set_drawing_color(mlk::client::color::from_hex(0xffffffff));
+	if (argc == 0) {
+		std::cerr << "usage: mlk-client main.js" << std::endl;
+		return 1;
+	}
 
-		const auto width = 200;
-		const auto height = 150;
+	try {
+		mlk::js::duk::context ctx;
 
-		// top
-		sprite.draw(painter, 0, mlk::point{10, 10});
-		sprite.draw(painter, 1, mlk::rectangle{10 + 16, 10, width, 16});
-		sprite.draw(painter, 2, mlk::point{10 + 16 + width, 10});
+		mlk::js::load_elapsed_timer_api(ctx);
+		mlk::js::load_line_api(ctx);
+		mlk::js::load_point_api(ctx);
+		mlk::js::load_rectangle_api(ctx);
+		mlk::js::load_size_api(ctx);
 
-		// middle
-		sprite.draw(painter, 32, mlk::rectangle{10, 10 + 16, 16, height});
-		sprite.draw(painter, 33, mlk::rectangle{10 + 16, 10 + 16, width, height});
-		sprite.draw(painter, 34, mlk::rectangle{10 + 16 + width, 10 + 16, 16, height});
-
-		// bottom
-		sprite.draw(painter, 64, mlk::point{10, 10 + 16 + height});
-		sprite.draw(painter, 65, mlk::rectangle{10 + 16, 10 + 16 + height, width, 16});
-		sprite.draw(painter, 66, mlk::point{10 + 16 + width, 10 + 16 + height});
+		mlk::client::js::load_animation_api(ctx);
+		mlk::client::js::load_animator_api(ctx);
+		mlk::client::js::load_color_api(ctx);
+		mlk::client::js::load_image_api(ctx);
+		mlk::client::js::load_painter_api(ctx);
+		mlk::client::js::load_sprite_api(ctx);
+		mlk::client::js::load_texture_api(ctx);
+		mlk::client::js::load_window_api(ctx);
 
-		// input
-		sprite.draw(painter, 3, mlk::point{10 + 8, 10 + 8});
-		sprite.draw(painter, 4, mlk::rectangle{10 + 8 + 16, 10 + 8, width - 16, 16});
-		sprite.draw(painter, 5, mlk::point{10 + 8 + width, 10 + 8});
-		sprite.draw(painter, 35, mlk::point{10 + 8, 10 + 8 + 16});
-		sprite.draw(painter, 36, mlk::rectangle{10 + 8 + 16, 10 + 8 + 16, width - 16, 16});
-		sprite.draw(painter, 37, mlk::point{10 + 8 + width, 10 + 8 + 16});
+		std::ifstream input(argv[0]);
+		std::string script(
+			std::istreambuf_iterator<char>(input.rdbuf()),
+			std::istreambuf_iterator<char>()
+		);
 
-		painter.present();
+		if (!input)
+			throw std::runtime_error(std::strerror(errno));
+		if (duk_peval_string(ctx, script.c_str()))
+			throw mlk::js::duk::get_stack(ctx, -1);
+	} catch (const mlk::js::duk::stack_info& ex) {
+		std::cerr << argv[0] << ":" << ex.get_line_number() << ": " << ex.what() << std::endl;
+		std::cerr << ex.get_stack() << std::endl;
+		return 1;
+	} catch (const std::exception& ex) {
+		std::cerr << "abort: " << ex.what() << std::endl;
+		return 1;
 	}
 
 	return 0;