changeset 191:633a25df450e

molko-js: miscellaneous fixes While here, import sphinx as experimental documentation.
author David Demelier <markand@malikania.fr>
date Sat, 07 Nov 2020 15:40:34 +0100
parents 5dc57029b9f1
children 4ad7420ab678
files CMakeLists.txt doc/CMakeLists.txt doc/about.rst doc/api-js-starter.rst doc/api-js.rst doc/api-molko-clock.rst doc/api-molko-event.rst doc/api-molko-font.rst doc/api-molko-painter.rst doc/api-molko-sprite.rst doc/api-molko-texture.rst doc/api-molko-util.rst doc/api-molko-window.rst doc/conf.py doc/getting-started.rst doc/index.rst libcore/core/texture.h molko-js/src/js-painter.c molko-js/src/js-sprite.c molko-js/src/js-texture.c molko-js/src/js-window.c
diffstat 21 files changed, 964 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Sat Nov 07 10:16:38 2020 +0100
+++ b/CMakeLists.txt	Sat Nov 07 15:40:34 2020 +0100
@@ -35,6 +35,7 @@
 endif ()
 
 option(MOLKO_WITH_DOXYGEN "Enable Doxygen build" On)
+option(MOLKO_WITH_DOC "Enable documentation (requires sphinx)" On)
 option(MOLKO_WITH_TESTS "Enable unit tests" On)
 option(MOLKO_WITH_EXAMPLES "Enable build of examples" On)
 
@@ -70,6 +71,10 @@
 add_subdirectory(molko)
 add_subdirectory(molko-js)
 
+if (MOLKO_WITH_DOC)
+	add_subdirectory(doc)
+endif ()
+
 if (MOLKO_WITH_EXAMPLES)
 	add_subdirectory(examples)
 endif ()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/CMakeLists.txt	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,49 @@
+#
+# CMakeLists.txt -- CMake build system for molko
+#
+# Copyright (c) 2020 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.
+#
+
+project(doc)
+
+find_program(SPHINX_EXE sphinx-build DOC "Path to sphinx-build")
+
+if (SPHINX_EXE)
+	set(
+		SOURCES
+ 		${doc_SOURCE_DIR}/about.rst
+ 		${doc_SOURCE_DIR}/api-js.rst
+ 		${doc_SOURCE_DIR}/api-molko-clock.rst
+ 		${doc_SOURCE_DIR}/api-molko-event.rst
+ 		${doc_SOURCE_DIR}/api-molko-font.rst
+ 		${doc_SOURCE_DIR}/api-molko-painter.rst
+ 		${doc_SOURCE_DIR}/api-molko-sprite.rst
+ 		${doc_SOURCE_DIR}/api-molko-texture.rst
+ 		${doc_SOURCE_DIR}/api-molko-util.rst
+ 		${doc_SOURCE_DIR}/api-molko-window.rst
+ 		${doc_SOURCE_DIR}/conf.py
+ 		${doc_SOURCE_DIR}/getting-started.rst
+ 		${doc_SOURCE_DIR}/index.rst
+	)
+
+	add_custom_target(
+		doc
+		ALL VERBATIM
+		SOURCES ${SOURCES}
+		COMMAND ${SPHINX_EXE} -q . ${doc_BINARY_DIR}
+		WORKING_DIRECTORY ${doc_SOURCE_DIR}
+		COMMENT "Generating documentation"
+	)
+endif ()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/about.rst	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,20 @@
+=====
+About
+=====
+
+Molko's Adventure is a 2D solo RPG game and an API in both C or Javascript to
+build more RPG games. It is designed with the following characteristics:
+
+- Turn based battle. Similar to old RPG games battle operate on a dedicated game
+  state where the player and enemies select actions to perform when the member
+  is ready to play.
+- Tile based maps using scrolling and pixel granularity movements.
+- Theme system to allow customization of some user interface components.
+- Set of predefined dialog windows to control the game.
+
+While the API is flexible and powerful enough to create different games, it is
+still kept as simple possible without cluttering the API with dozen of
+abstraction and generics all over the place. This means that there are
+predefined kinds of character status (poison, slow, etc) along with kind of
+spells (earth, neutral).
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/api-js-starter.rst	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,114 @@
+.. highlight:: javascript
+
+================
+Starter template
+================
+
+In this guide we will show you how to start developing. Open your favorite
+editor and create a Javascript file, in this example we will use ``main.js`` but
+the name does not matter.
+
+Opening a window
+----------------
+
+The very first thing to do is to open a window. To do this we use the
+:js:mod:`Molko.Window`. The function we are interested in is the window
+constructor :js:func:`Molko.Window.new`, it takes a title and a dimension.
+
+.. hint::
+   Altough the Javascript API does not expect a specific window size, the
+   default predefined objects make best fit using a resolution of 720p
+   (1280x720).
+
+Create a window::
+
+  var w = new Molko.Window("My first window", 1280, 720);
+
+Basic event handling
+--------------------
+
+Now that a window is opened, we need to dispatch user and events from the
+operating system to run and be able to draw our game to the screen.
+
+.. caution::
+   You must use this API at some point in your code otherwise your application
+   may look unresponsive on some platforms.
+
+To do this, we create an infinite loop and then at the beginning of our loop we
+will poll all events until it is empty. This is done with the
+:js:mod:`Molko.Event` API.
+
+::
+
+  var run = true;
+
+  while (run) {
+    for (var ev; ev = Molko.Event.poll(); ev) {
+      switch (ev.type) {
+      case Molko.Event.QUIT:
+        run = false;
+        break;
+      default:
+        break;
+      }
+    }
+  }
+
+Rendering
+---------
+
+Our window is now ready to render things to the user. For this we may use
+several APIs like :js:mod:`Molko.Texture`, :js:mod:`Molko.Painter` and such. We
+will focus on the latter for now.
+
+.. caution::
+   You must create a window before using a painter.
+
+In this example, we will clear the black in screen and draw a small square in
+the middle of the screen.
+
+::
+
+  var p = new Molko.Painter()
+
+  // Clear the screen.
+  p.color = 0x000000ff;
+  p.clear();
+  p.color = 0xffffffff;
+  p.drawRectangle((1280 - 50) / 2, (720 - 50) / 2, 50, 50);
+  p.present();
+
+Final word
+----------
+
+That's it for the core API! You are now able to run a small script that clear
+the screen and catch user quit event.
+
+This is the whole code or our file:
+
+::
+
+  var w = new Molko.Window("My first window", 1280, 720);
+  var p = new Molko.Painter()
+
+  var run = true;
+
+  while (run) {
+    // Poll pending events.
+    for (var ev; ev = Molko.Event.poll(); ev) {
+      switch (ev.type) {
+      case Molko.Event.QUIT:
+        run = false;
+        break;
+      default:
+        break;
+      }
+    }
+
+    // Clear the screen.
+    p.color = 0x000000ff;
+    p.clear();
+    p.color = 0xffffffff;
+    p.drawRectangle((1280 - 50) / 2, (720 - 50) / 2, 50, 50);
+    p.present();
+  }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/api-js.rst	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,41 @@
+==============
+Javascript API
+==============
+
+The Javascript API is designed to allow developing RPG games in a more
+convenient, quicker and more flexible way. By using the Javascript API you may
+deploy your game without having to compile the project for every platform.
+
+See the following topics to learn how to write your very first game.
+
+.. toctree::
+   :hidden:
+
+   api-js-starter
+
+Javascript modules
+------------------
+
+List of all available modules.
+
+.. toctree::
+   :maxdepth: 1
+
+   api-molko-clock
+   api-molko-event
+   api-molko-font
+   api-molko-painter
+   api-molko-sprite
+   api-molko-texture
+   api-molko-util
+   api-molko-window
+
+Conformance
+-----------
+
+The Javascript engine is powered by Duktape_, it supports ECMAScript 5.1 with
+some extensions of newer specifications. See the official `features tables`_ for
+more information.
+
+.. _Duktape: http://duktape.org
+.. _features tables: https://wiki.duktape.org/postes5features
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/api-molko-clock.rst	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,32 @@
+.. toctree::
+.. _api-molko-clock:
+
+Molko.Clock
+===========
+
+Keep track of elapsed time.
+
+Constructors
+------------
+
+.. js:function:: Molko.Clock()
+
+Create a new clock object and start collecting time from now. This function
+MUST be called as a constructor, not doing so will also raise an error.
+
+Methods
+-------
+
+.. js:method:: Molko.Clock.start()
+
+Reset the clock from now.
+
+Properties
+----------
+
+The following properties are available once an object has been constructed:
+
+.. js:attribute:: Molko.Clock.elapsed
+
+(Read-only) Number of milliseconds elapsed since construction of object or last
+call to start function.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/api-molko-event.rst	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,66 @@
+.. toctree::
+.. _api-molko-event:
+
+Molko.Event
+===========
+
+Poll user and kernel events from the main loop.
+
+.. caution::
+   Not polling events in the main loop may end in an unresponsive application on
+   some platforms.
+
+Constants
+---------
+
+.. js:data:: Molko.Event
+
+The following values are available into the object itself:
+
+``CLICK_DOWN``
+  Mouse click down.
+``CLICK_UP``
+  Mouse click release.
+``KEY_DOWN``
+  Keyboard key down.
+``KEY_UP``
+  Keyboard key release.
+``MOUSE``
+  Mouse motion.
+``QUIT``
+  User quit event.
+
+Functions
+---------
+
+.. js:function:: Molko.Event.poll()
+
+   :returns: An object or undefined if there are no more events.
+
+Get the next pending event in the queue. It is recommended to use this function
+in a loop to unqueue the whole list of events at once for performance reasons.
+
+The returned object has different properties depending on the event.
+
+For both ``CLICK_DOWN`` and ``CLICK_UP`` events:
+
+``x (int)``
+  Position in x.
+``y (int)``
+  Position in y.
+``button (int)``
+  Button number (1 through 5 are standards).
+
+For both ``KEY_DOWN`` and ``KEY_UP`` events:
+
+``key (int)``
+  Key number.
+
+For ``MOUSE`` event:
+
+``x (int)``
+  Position in x.
+``y (int)``
+  Position in y.
+``buttons (int)``
+  Bitmask of buttons currently pressed.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/api-molko-font.rst	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,47 @@
+.. toctree::
+.. _api-molko-font:
+
+Molko.Font
+==========
+
+.. js:module:: Molko.Font
+
+Module for loading fonts and rendering text with them.
+
+Functions
+---------
+
+.. js:function:: Molko.Font.fromPath(path, size)
+
+   :param string path: Path to the font to load.
+   :param size int: Desired size.
+   :throws: Error in case of loading error.
+   :returns: A font handle.
+
+Open the font specified by path
+
+Methods
+-------
+
+.. js:method:: Molko.Font.query(text)
+
+   :param string text: Text to use for computing size.
+   :throws: Error in case of error.
+   :returns: An object with w, h properties.
+
+Get the required bounding box size to render the given text. The returned object
+has the following properties:
+
+``w (int)``
+  The text's width.
+``h (int)``
+  The text's height.
+
+.. js:method:: Molko.Font.render(text, color)
+
+   :param string text: Text to render.
+   :param number color: The color.
+   :throws: Error in case of error.
+   :returns: A texture object.
+
+Render a text into a texture.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/api-molko-painter.rst	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,119 @@
+.. toctree::
+.. _api-molko-painter:
+
+Molko.Painter
+=============
+
+Module for drawing operation into the screen or a texture. It is a low level
+module with primitives operations.
+
+You must open a window before using this module. See :ref:`api-molko-window`.
+
+Constructors
+------------
+
+.. js:function:: Molko.Painter()
+
+Create a painter object. This function MUST be called as a constructor, not
+doing so will also raise an error.
+
+Methods
+-------
+
+.. js:method:: Molko.Painter.clear()
+
+Clear the rendering target with the current color.
+
+.. js:method:: Molko.Painter.drawLine(line)
+               Molko.Painter.drawLine(x1, x2, x2, y2)
+
+   :param object line: A line segment.
+   :param int x1: Start position in x.
+   :param int y1: Start position in y.
+   :param int x2: End position in x.
+   :param int y2: End position in y.
+
+Draw a line, two signatures are allowed.
+
+In the second form, each argument is passed individually, in the first form it
+it takes an object with the following properties:
+
+``x1 (int)``
+  Start position in x.
+``y1 (int)``
+  Start position in y.
+``x2 (int)``
+  End position in x.
+``y2 (int)``
+  End position in y.
+
+.. js:method:: Molko.Painter.drawPoint(point)
+               Molko.Painter.drawPoint(x, y)
+
+   :param object point: A point.
+   :param int x: Start position in x.
+   :param int y: Start position in y.
+
+Draw a unique point, two signatures are allowed.
+
+In the second form, each argument is passed individually, in the first form it
+it takes an object with the following properties:
+
+``x (int)``
+  Position in x.
+``y (int)``
+  Position in y.
+
+.. js:method:: Molko.Painter.drawRectangle(rectangle)
+               Molko.Painter.drawRectangle(x, y, w, h)
+
+   :param object rectangle: A rectangle.
+   :param int x: Position in x.
+   :param int y: Position in y.
+   :param int w: Rectangle width.
+   :param int h: Height width.
+
+Fill a rectangle region, two signatures are allowed.
+
+In the second form, each argument is passed individually, in the first form it
+it takes an object with the following properties:
+
+``x (int)``
+  Position in x.
+``y (int)``
+  Position in y.
+``w (int)``
+  Rectangle width.
+``h (int)``
+  Height width.
+
+.. js:method:: Molko.Painter.drawCircle(circle)
+               Molko.Painter.drawCircle(x, y, r)
+
+   :param object circle: A circle.
+   :param int x: Position in x.
+   :param int y: Position in y.
+   :param number radius: Radius.
+
+Draw a circle, two signatures are allowed.
+
+In the second form, each argument is passed individually, in the first form it
+it takes an object with the following properties:
+
+``x (int)``
+  Position in x.
+``y (int)``
+  Position in y;
+``radius (number)``
+  Radius.
+
+.. js:method:: Molko.Painter.present()
+
+Present the rendered operations to the screen.
+
+Properties
+----------
+
+.. js:attribute:: Molko.Painter.color
+
+(Read-write) Color for next drawing operation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/api-molko-sprite.rst	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,60 @@
+.. toctree::
+.. highlight:: js
+.. _api-molko-sprite:
+
+============
+Molko.Sprite
+============
+
+The sprite module let you draw specific regions of grid based textures with
+ease.
+
+Constructors
+------------
+
+.. js:function:: Molko.Sprite(texture, cellw, cellh)
+
+   :param Texture texture: The texture to use.
+   :param uint cellw: Per cell width.
+   :param uint cellh: Per cell height.
+
+Construct a sprite with the given texture and the cell grid dimensions. This
+function MUST be called as a constructor, not doing so will also raise an
+error.
+
+Methods
+-------
+
+.. js:method:: Molko.Sprite.draw(object)
+               Molko.Sprite.draw(row, column, x, y)
+
+  :param Object object: Description.
+  :param uint row: Row number.
+  :param uint column: Column number.
+  :param int x: Position in x.
+  :param int y: Position in y.
+
+Draw the given row/column cell from the sprite onto the screen. Two signatures
+are allowed.
+
+In the second form, each argument is passed individually, in the first form it
+it takes an object with the properties having the same name as individual
+arguments.
+
+Example:
+
+::
+
+  sprite.draw(1, 2, 100, 100);
+  sprite.draw({row: 1, column: 2, x: 100, y: 100});
+
+Properties
+----------
+
+.. js:attribute:: Molko.Sprite.rowCount
+
+(Read-only) Number of rows calculated from image dimension.
+
+.. js:attribute:: Molko.Sprite.columnCount
+
+(Read-only) Number of columns calculated from image dimension.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/api-molko-texture.rst	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,108 @@
+.. toctree::
+.. _api-molko-texture:
+
+=============
+Molko.Texture
+=============
+
+This module provides graphics primites for textures. Textures can be created by
+hand or loaded from files. It's possible to draw on a texture using the
+:ref:`api-molko-painter` API.
+
+Constants
+---------
+
+.. js:data:: Molko.Texture.BlendMode
+
+This enumeration constant contains the following blend mode that can be used as
+the ``blendMode`` property.
+
+``TEXTURE_BLEND_NONE``
+  No modification.
+
+``TEXTURE_BLEND_BLEND``
+  Alpha blend mode modulation.
+
+``TEXTURE_BLEND_ADD``
+  Additive modulation.
+
+``TEXTURE_BLEND_MODULATE``
+  Color modulation.
+
+Constructors
+------------
+
+.. js:function:: Molko.Texture(width, height)
+
+   :param uint width: Desired texture width.
+   :param uint height: Desired texture height.
+
+Construct a new texture with the given dimensions. This function MUST be called
+as a constructor, not doing so will also raise an error.
+
+Functions
+---------
+
+.. js:function:: Molko.Texture.fromImage(path)
+
+   :param string path: Path to the image file.
+   :throws: Error in case of error.
+   :returns: A Texture object.
+
+Try to open an image as a texture.
+
+Methods
+-------
+
+.. js:method:: Molko.Texture.draw(x, y)
+
+   :param int x: Position in x.
+   :param int y: Position in y.
+   :throws: Error on errors.
+
+Draw the whole texture at the given position.
+
+.. js:method:: Molko.Texture.scale(source, destination, angle = 0)
+
+   :param object source: Source rectangle.
+   :param object destination: Destination rectangle.
+   :param number angle: Angle rotation.
+   :throws: Error on errors.
+
+Scale the texture from the source region into the destination and apply an
+optional angle.
+
+The ``source`` and ``destination`` objects MUST contain the following
+properties:
+
+``x (int)``
+  Start position in x.
+``y (int)``
+  Start position in y.
+``h (int)``
+  Height to scale.
+``w (int)``
+  Width to scale.
+
+Properties
+----------
+
+.. js:attribute:: Molko.Texture.width
+
+(Read-only) Texture's width.
+
+.. js:attribute:: Molko.Texture.height
+
+(Read-only) Texture's height.
+
+.. js:attribute:: Molko.Texture.blendMode
+
+(Write-only) Change the blend mode.
+
+.. js:attribute:: Molko.Texture.alphaMod
+
+(Write-only) Change the alpha transparency modulation from 0 to 255.
+
+.. js:attribute:: Molko.Texture.colorMod
+
+(Write-only) Change color modulation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/api-molko-util.rst	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,17 @@
+.. toctree::
+.. _api-molko-util:
+
+==========
+Molko.Util
+==========
+
+Various core utilities.
+
+Functions
+---------
+
+.. js:functions:: Molko.Util.delay(delay)
+
+   :param uint delay: Time to wait in milliseconds.
+
+Pause the program for the given amount of milliseconds.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/api-molko-window.rst	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,54 @@
+.. toctree::
+.. _api-molko-window:
+
+Molko.Window
+============
+
+This module is dedicated to window management.
+
+Constants
+---------
+
+.. js:data:: Molko.Window.Cursor
+
+This is an enumeration of available cursor which you may choose from:
+
+``ARROW``
+  Default arrow.
+
+``EDIT``
+  Edit text cusror (like I-Beam)
+
+``WAIT``
+  Busy cursor, not available on all platforms.
+
+``CROSS_HAIR``
+  Cross.
+
+``SIZE``
+  Move and resizing cursor.
+
+``NO``
+  Action forbidden.
+
+``HAND``
+  Hand, mostly for moving.
+
+Constructors
+------------
+
+.. js:function:: Molko.Window(title, width, height)
+
+   :param string title: Title for the window.
+   :param int width: Desired window width.
+   :param int height: Desired window height.
+
+Open a window or raise an error if any. This function MUST be called as a
+constructor, not doing so will also raise an error.
+
+Properties
+----------
+
+.. js:data:: Molko.Window.cursor
+
+(Write-only) Change the global window cursor to a system predefined one.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/conf.py	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,31 @@
+#
+# conf.py -- sphinx documentation configuration
+#
+# Copyright (c) 2020 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.
+#
+
+# Project information.
+project = "Molko Javascript API"
+copyright = "2020, David Demelier"
+author = "David Demelier"
+release = '0.1.0'
+
+# General settings.
+templates_path = ["_templates"]
+exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
+
+# HTML output.
+html_theme = "sphinx_rtd_theme"
+html_static_path = ["_static"]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/getting-started.rst	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,25 @@
+Getting started
+===============
+
+Before developing your game in Javascript, make sure you've installed Molko's
+engine with Javascript support. This will provide the command line tool
+``molko-js`` which is the default loader.
+
+molko-js
+--------
+
+This executable loads the Javascript API and performs some modifications of the
+core API such as:
+
+- A panic handler is setup by default to show an error message if a programming
+  or runtime error is detected at runtime. It will simply print the message on
+  the screen and wait the user for action to quit.
+- It loads automatically the core, UI and RPG API at startup.
+
+The executable take only one argument, the path to the script file to run.
+
+Example of use
+
+.. code-block:: bash
+
+  $ molko-js script.js
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/index.rst	Sat Nov 07 15:40:34 2020 +0100
@@ -0,0 +1,28 @@
+Molko Javascript API
+====================
+
+Welcome to the Molko's Javascript API.
+
+Introduction
+------------
+
+The Molko project is a framework for developing 2D RPG games in C or in
+Javascript. It is designed in mind to be simple, fast, convenient, flexible and
+fun to use.
+
+Contents
+--------
+
+.. toctree::
+   :maxdepth: 1
+
+   about
+   getting-started
+   api-js
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
--- a/libcore/core/texture.h	Sat Nov 07 10:16:38 2020 +0100
+++ b/libcore/core/texture.h	Sat Nov 07 15:40:34 2020 +0100
@@ -47,7 +47,8 @@
 	TEXTURE_BLEND_NONE,     /*!< No pixel modulation. */
 	TEXTURE_BLEND_BLEND,    /*!< Blend transparency. */
 	TEXTURE_BLEND_ADD,      /*!< Additive blending. */
-	TEXTURE_BLEND_MODULATE  /*!< Color modulation. */
+	TEXTURE_BLEND_MODULATE, /*!< Color modulation. */
+	TEXTURE_BLEND_LAST      /*!< Unused. */
 };
 
 /**
--- a/molko-js/src/js-painter.c	Sat Nov 07 10:16:38 2020 +0100
+++ b/molko-js/src/js-painter.c	Sat Nov 07 15:40:34 2020 +0100
@@ -52,6 +52,7 @@
 	duk_push_c_function(ctx, js_painter_getColor, 0);
 	duk_push_c_function(ctx, js_painter_setColor, 1);
 	duk_def_prop(ctx, -4, DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
+	duk_pop(ctx);
 
 	return 0;
 }
--- a/molko-js/src/js-sprite.c	Sat Nov 07 10:16:38 2020 +0100
+++ b/molko-js/src/js-sprite.c	Sat Nov 07 15:40:34 2020 +0100
@@ -49,6 +49,22 @@
 }
 
 static duk_ret_t
+js_sprite_getRowCount(duk_context *ctx)
+{
+	duk_push_uint(ctx, js_sprite_this(ctx)->nrows);
+
+	return 1;
+}
+
+static duk_ret_t
+js_sprite_getColumnCount(duk_context *ctx)
+{
+	duk_push_uint(ctx, js_sprite_this(ctx)->ncols);
+
+	return 1;
+}
+
+static duk_ret_t
 js_sprite_new(duk_context *ctx)
 {
 	struct js *js = js_self(ctx);
@@ -69,6 +85,17 @@
 	duk_push_pointer(ctx, alloc_dup(&sprite, sizeof (sprite)));
 	duk_put_prop_string(ctx, -2, SYMBOL);
 
+	/*
+	 * Put rowCount/columnCount properties.
+	 */
+	duk_push_string(ctx, "rowCount");
+	duk_push_c_function(ctx, js_sprite_getRowCount, 0);
+	duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER);
+
+	duk_push_string(ctx, "columnCount");
+	duk_push_c_function(ctx, js_sprite_getColumnCount, 0);
+	duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER);
+
 	/* We store the texture into the sprite to avoid being collected. */
 	duk_dup(ctx, 0);
 	duk_put_prop_string(ctx, -2, TEXTURE_REF);
@@ -96,16 +123,24 @@
 	unsigned int r, c;
 	int x, y;
 
-	duk_require_object(ctx, 0);
-	duk_get_prop_string(ctx, 0, "r");
-	r = duk_to_int(ctx, -1);
-	duk_get_prop_string(ctx, 0, "c");
-	c = duk_to_int(ctx, -1);
-	duk_get_prop_string(ctx, 0, "x");
-	x = duk_to_int(ctx, -1);
-	duk_get_prop_string(ctx, 0, "y");
-	y = duk_to_int(ctx, -1);
-	duk_pop_n(ctx, 4);
+	if (duk_get_top(ctx) == 4) {
+		r = duk_require_uint(ctx, 0);
+		c = duk_require_uint(ctx, 1);
+		x = duk_require_int(ctx, 2);
+		y = duk_require_int(ctx, 3);
+	} else if (duk_get_top(ctx) == 1) {
+		duk_require_object(ctx, 0);
+		duk_get_prop_string(ctx, 0, "row");
+		r = duk_to_int(ctx, -1);
+		duk_get_prop_string(ctx, 0, "column");
+		c = duk_to_int(ctx, -1);
+		duk_get_prop_string(ctx, 0, "x");
+		x = duk_to_int(ctx, -1);
+		duk_get_prop_string(ctx, 0, "y");
+		y = duk_to_int(ctx, -1);
+		duk_pop_n(ctx, 4);
+	} else
+		return duk_error(ctx, DUK_ERR_ERROR, "Object or 4 numbers expected");
 
 	sprite_draw(sprite, r, c, x, y);
 	
--- a/molko-js/src/js-texture.c	Sat Nov 07 10:16:38 2020 +0100
+++ b/molko-js/src/js-texture.c	Sat Nov 07 15:40:34 2020 +0100
@@ -49,6 +49,62 @@
 }
 
 static duk_ret_t
+js_texture_getWidth(duk_context *ctx)
+{
+	duk_push_uint(ctx, js_texture_this(ctx)->w);
+
+	return 1;
+}
+
+static duk_ret_t
+js_texture_getHeight(duk_context *ctx)
+{
+	duk_push_uint(ctx, js_texture_this(ctx)->h);
+
+	return 1;
+}
+
+static duk_ret_t
+js_texture_setBlendMode(duk_context *ctx)
+{
+	struct texture *tex = js_texture_this(ctx);
+	enum texture_blend blend = duk_require_int(ctx, 0);
+
+	if (blend < 0 || blend >= TEXTURE_BLEND_MODULATE)
+		return duk_error(ctx, DUK_ERR_ERROR, "invalid blend mode: %d", blend);
+	if (!texture_set_blend_mode(tex, blend))
+		return duk_error(ctx, DUK_ERR_ERROR, "%s", error());
+
+	return 0;
+}
+
+static duk_ret_t
+js_texture_setAlphaMod(duk_context *ctx)
+{
+	struct texture *tex = js_texture_this(ctx);
+	unsigned int alpha = duk_require_uint(ctx, 0);
+
+	if (alpha > 255)
+		return duk_error(ctx, DUK_ERR_RANGE_ERROR, "%u is out of range [0..255]", alpha);
+	if (!texture_set_alpha_mod(tex, alpha))
+		return duk_error(ctx, DUK_ERR_ERROR, "%s", error());
+
+	return 0;
+}
+
+static duk_ret_t
+js_texture_setColorMod(duk_context *ctx)
+{
+	struct texture *tex = js_texture_this(ctx);
+	unsigned long color = duk_require_number(ctx, 0);
+
+	if (!texture_set_color_mod(tex, color))
+		return duk_error(ctx, DUK_ERR_ERROR, "%s", error());
+
+	return 0;
+}
+
+static duk_ret_t
 js_texture_new(duk_context *ctx)
 {
 	struct texture tex;
@@ -82,7 +138,8 @@
 	y = duk_to_int(ctx, -1);
 	duk_pop_n(ctx, 2);
 
-	texture_draw(tex, x, y);
+	if (!texture_draw(tex, x, y))
+		return duk_error(ctx, DUK_ERR_ERROR, "%s", error());
 
 	return 0;
 }
@@ -122,7 +179,8 @@
 	/* Angle. */
 	angle = duk_to_number(ctx, 2);
 
-	texture_scale(tex, srcx, srcy, srcw, srch, dstx, dsty, dstw, dsth, angle);
+	if (!texture_scale(tex, srcx, srcy, srcw, srch, dstx, dsty, dstw, dsth, angle))
+		return duk_error(ctx, DUK_ERR_ERROR, "%s", error());
 
 	return 0;
 }
@@ -198,6 +256,23 @@
 	duk_push_pointer(js->handle, alloc_dup(tex, sizeof (*tex)));
 	duk_put_prop_string(js->handle, -3, SYMBOL);
 	duk_set_prototype(js->handle, -2);
+
+	/* Put some properties. */
+	duk_push_string(js->handle, "width");
+	duk_push_c_function(js->handle, js_texture_getWidth, 0);
+	duk_def_prop(js->handle, -3, DUK_DEFPROP_HAVE_GETTER);
+	duk_push_string(js->handle, "height");
+	duk_push_c_function(js->handle, js_texture_getHeight, 0);
+	duk_def_prop(js->handle, -3, DUK_DEFPROP_HAVE_GETTER);
+	duk_push_string(js->handle, "blendMode");
+	duk_push_c_function(js->handle, js_texture_setBlendMode, 1);
+	duk_def_prop(js->handle, -3, DUK_DEFPROP_HAVE_SETTER);
+	duk_push_string(js->handle, "alphaMod");
+	duk_push_c_function(js->handle, js_texture_setAlphaMod, 1);
+	duk_def_prop(js->handle, -3, DUK_DEFPROP_HAVE_SETTER);
+	duk_push_string(js->handle, "colorMod");
+	duk_push_c_function(js->handle, js_texture_setColorMod, 1);
+	duk_def_prop(js->handle, -3, DUK_DEFPROP_HAVE_SETTER);
 }
 
 void
--- a/molko-js/src/js-window.c	Sat Nov 07 10:16:38 2020 +0100
+++ b/molko-js/src/js-window.c	Sat Nov 07 15:40:34 2020 +0100
@@ -27,6 +27,19 @@
 #include "js-window.h"
 
 static duk_ret_t
+js_window_setCursor(duk_context *ctx)
+{
+	enum window_cursor cursor = duk_require_int(ctx, 0);
+
+	if (cursor < 0 || cursor > WINDOW_CURSOR_LAST)
+		return duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid cursor type: %d", cursor);
+
+	window_set_cursor(cursor);
+
+	return 0;
+}
+
+static duk_ret_t
 js_window_new(duk_context *ctx)
 {
 	if (!duk_is_constructor_call(ctx))
@@ -39,18 +52,11 @@
 	if (!window_open(str, w, h))
 		duk_error(ctx, DUK_ERR_ERROR, "%s", error());
 
-	return 0;
-}
-
-static duk_ret_t
-js_window_setCursor(duk_context *ctx)
-{
-	enum window_cursor cursor = duk_require_int(ctx, 0);
-
-	if (cursor < 0 || cursor > WINDOW_CURSOR_LAST)
-		duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid cursor type: %d", cursor);
-
-	window_set_cursor(cursor);
+	duk_push_this(ctx);
+	duk_push_string(ctx, "cursor");
+	duk_push_c_function(ctx, js_window_setCursor, 1);
+	duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_SETTER);
+	duk_pop(ctx);
 
 	return 0;
 }
@@ -66,25 +72,17 @@
 	{ NULL,         0                               }
 };
 
-static const duk_function_list_entry methods[] = {
-	{ "setCursor",  js_window_setCursor,    1 },
-	{ NULL,         NULL,                   0 }
-};
-
 void
 js_window_load(struct js *js)
 {
 	assert(js);
 
-	duk_push_global_object(js->handle);
-	duk_get_prop_string(js->handle, -1, "Molko");
-	duk_push_c_function(js->handle, js_window_new, 3);
-	duk_push_object(js->handle);
-	duk_put_function_list(js->handle, -1, methods);
-	duk_put_prop_string(js->handle, -2, "prototype");
-	duk_push_object(js->handle);
+	duk_push_global_object(js->handle);                  // [g]
+	duk_get_prop_string(js->handle, -1, "Molko");        // [g] [Molko]
+	duk_push_c_function(js->handle, js_window_new, 3);   // [g] [Molko] [Window]
+	duk_push_object(js->handle);                         // [g] [Molko] [Window] [Cursor]
 	duk_put_number_list(js->handle, -1, cursors);
-	duk_put_prop_string(js->handle, -1, "Cursor");
+	duk_put_prop_string(js->handle, -2, "Cursor");       // [g] [Molko] [Window]
 	duk_put_prop_string(js->handle, -2, "Window");
 	duk_pop_n(js->handle, 2);
 }