Merge: gamnit: miscellaneous services and a few fixes
authorJean Privat <jean@pryen.org>
Sat, 21 May 2016 05:40:41 +0000 (01:40 -0400)
committerJean Privat <jean@pryen.org>
Sat, 21 May 2016 05:40:41 +0000 (01:40 -0400)
This PR groups features required by my recent unpublished tech demos built on gamnit.

Here are more details on the less intuitive commits:

* The change to `current_fps` lets a program use it right from the beginning and gives a value which is somewhat realistic (vs returning 0).
* The `placeholder_model` can be useful when quickly writing the prototype of a game to get something visible in the 3D space.
* The doc of `subtexture` clarifies an ambiguity as to whether the method expected pixel offsets or proportional values out of 1.0.
* The tool `texture_atlas_parser` can be useful to other games.
* `draw_mode` is very useful to create optimized `Mesh`, using `gl_TRIANGLE_STRIP` and `gl_TRIANGLE_FAN`.
* The old API of `triangulate` was counter-intuitive. The result was put in a parameter and the list of points was cleared in the process. This PR offers a simple method and the recursive implementation as an optimized alternative. ping @BlackMinou
* `tinks_vr` is not playable but it shows how to convert a gamnit game to a basic VR version.

Pull-Request: #2115
Reviewed-by: Jean Privat <jean@pryen.org>

src/nitweb.nit
src/platform/app_annotations.nit
src/web/web_actions.nit
src/web/web_base.nit
src/web/web_views.nit

index b924ec2..c055ee9 100644 (file)
@@ -47,15 +47,15 @@ private class NitwebPhase
                var host = toolcontext.opt_host.value or else "localhost"
                var port = toolcontext.opt_port.value
 
-               var srv = new NitServer(host, port.to_i)
-               srv.routes.add new Route("/random", new RandomAction(srv, model))
-               srv.routes.add new Route("/doc/:namespace", new DocAction(srv, model, modelbuilder))
-               srv.routes.add new Route("/code/:namespace", new CodeAction(srv, model, modelbuilder))
-               srv.routes.add new Route("/search/:namespace", new SearchAction(srv, model))
-               srv.routes.add new Route("/uml/:namespace", new UMLDiagramAction(srv, model, mainmodule))
-               srv.routes.add new Route("/", new TreeAction(srv, model))
+               var app = new App
+               app.use("/random", new RandomAction(model))
+               app.use("/doc/:namespace", new DocAction(model, modelbuilder))
+               app.use("/code/:namespace", new CodeAction(model, modelbuilder))
+               app.use("/search/:namespace", new SearchAction(model))
+               app.use("/uml/:namespace", new UMLDiagramAction(model, mainmodule))
+               app.use("/", new TreeAction(model))
 
-               srv.listen
+               app.listen(host, port.to_i)
        end
 end
 
index 62fbbb0..1d60f15 100644 (file)
@@ -88,8 +88,6 @@ redef class AAnnotation
                        return ""
                else
                        for arg in args do
-                               var format_error = "Syntax Eror: `{name}` expects its arguments to be of type Int or a call to `git_revision`."
-
                                var value
                                value = arg.as_int
                                if value != null then
@@ -107,7 +105,13 @@ redef class AAnnotation
                                        # Get Git short revision
                                        var proc = new ProcessReader("git", "rev-parse", "--short", "HEAD")
                                        proc.wait
-                                       assert proc.status == 0
+                                       if proc.status != 0 then
+                                               # Fallback if this is not a git repository or git bins are missing
+                                               version_fields.add "0"
+                                               modelbuilder.warning(self, "git_revision", "Warning: `git_revision` used outside of a git repository or git binaries not available")
+                                               continue
+                                       end
+
                                        var lines = proc.read_all
                                        var revision = lines.split("\n").first
 
@@ -122,6 +126,7 @@ redef class AAnnotation
                                        continue
                                end
 
+                               var format_error = "Syntax Error: `{name}` expects its arguments to be of type Int or a call to `git_revision`."
                                modelbuilder.error(self, format_error)
                                return ""
                        end
index 60d39c2..e9198ae 100644 (file)
@@ -22,10 +22,10 @@ import uml
 class TreeAction
        super ModelAction
 
-       redef fun answer(request, url) do
-               var model = init_model_view(request)
+       redef fun get(req, res) do
+               var model = init_model_view(req)
                var view = new HtmlHomePage(model.to_tree)
-               return render_view(view)
+               res.send_view(view)
        end
 end
 
@@ -34,18 +34,20 @@ class SearchAction
        super ModelAction
 
        # TODO handle more than full namespaces.
-       redef fun answer(request, url) do
-               var namespace = request.param("namespace")
-               var model = init_model_view(request)
+       redef fun get(req, res) do
+               var namespace = req.param("namespace")
+               var model = init_model_view(req)
                var mentity = find_mentity(model, namespace)
                if mentity == null then
-                       return render_error(404, "No mentity found")
+                       res.error(404)
+                       return
                end
-               if request.is_json_asked then
-                       return render_json(mentity.to_json)
+               if req.is_json_asked then
+                       res.json(mentity.to_json)
+                       return
                end
                var view = new HtmlResultPage(namespace or else "null", [mentity])
-               return render_view(view)
+               res.send_view(view)
        end
 end
 
@@ -56,15 +58,16 @@ class CodeAction
        # Modelbuilder used to access sources.
        var modelbuilder: ModelBuilder
 
-       redef fun answer(request, url) do
-               var namespace = request.param("namespace")
-               var model = init_model_view(request)
+       redef fun get(req, res) do
+               var namespace = req.param("namespace")
+               var model = init_model_view(req)
                var mentity = find_mentity(model, namespace)
                if mentity == null then
-                       return render_error(404, "No mentity found")
+                       res.error(404)
+                       return
                end
                var view = new HtmlSourcePage(modelbuilder, mentity)
-               return render_view(view)
+               res.send_view(view)
        end
 end
 
@@ -75,16 +78,21 @@ class DocAction
        # Modelbuilder used to access sources.
        var modelbuilder: ModelBuilder
 
-       # TODO handle more than full namespaces.
-       redef fun answer(request, url) do
-               var namespace = request.param("namespace")
-               var model = init_model_view(request)
+       redef fun get(req, res) do
+               var namespace = req.param("namespace")
+               var model = init_model_view(req)
                var mentity = find_mentity(model, namespace)
                if mentity == null then
-                       return render_error(404, "No mentity found")
+                       res.error(404)
+                       return
+               end
+               if req.is_json_asked then
+                       res.json(mentity.to_json)
+                       return
                end
+
                var view = new HtmlDocPage(modelbuilder, mentity)
-               return render_view(view)
+               res.send_view(view)
        end
 end
 
@@ -95,12 +103,13 @@ class UMLDiagramAction
        # Mainmodule used for hierarchy flattening.
        var mainmodule: MModule
 
-       redef fun answer(request, url) do
-               var namespace = request.param("namespace")
-               var model = init_model_view(request)
+       redef fun get(req, res) do
+               var namespace = req.param("namespace")
+               var model = init_model_view(req)
                var mentity = find_mentity(model, namespace)
                if mentity == null then
-                       return render_error(404, "No mentity found")
+                       res.error(404)
+                       return
                end
 
                var dot
@@ -112,10 +121,11 @@ class UMLDiagramAction
                        var uml = new UMLModel(model, mentity)
                        dot = uml.generate_package_uml.write_to_string
                else
-                       return render_error(404, "No diagram matching this namespace.")
+                       res.error(404)
+                       return
                end
                var view = new HtmlDotPage(dot, mentity.as(not null).html_name)
-               return render_view(view)
+               res.send_view(view)
        end
 end
 
@@ -123,11 +133,10 @@ end
 class RandomAction
        super ModelAction
 
-       # TODO handle more than full namespaces.
-       redef fun answer(request, url) do
-               var n = request.int_arg("n") or else 10
-               var k = request.string_arg("k") or else "modules"
-               var model = init_model_view(request)
+       redef fun get(req, res) do
+               var n = req.int_arg("n") or else 10
+               var k = req.string_arg("k") or else "modules"
+               var model = init_model_view(req)
                var mentities: Array[MEntity]
                if k == "modules" then
                        mentities = model.mmodules.to_a
@@ -138,14 +147,15 @@ class RandomAction
                end
                mentities.shuffle
                mentities = mentities.sub(0, n)
-               if request.is_json_asked then
+               if req.is_json_asked then
                        var json = new JsonArray
                        for mentity in mentities do
                                json.add mentity.to_json
                        end
-                       return render_json(json)
+                       res.json(json)
+                       return
                end
                var view = new HtmlResultPage("random", mentities)
-               return render_view(view)
+               res.send_view(view)
        end
 end
index f37bdb4..258ec60 100644 (file)
@@ -17,77 +17,11 @@ module web_base
 
 import model::model_views
 import model::model_json
-import nitcorn
-
-# Nitcorn server runned by `nitweb`.
-#
-# Usage:
-#
-# ~~~nitish
-# var srv = new NitServer("localhost", 3000)
-# srv.routes.add new Route("/", new MyAction)
-# src.listen
-# ~~~
-class NitServer
-
-       # Host to bind.
-       var host: String
-
-       # Port to use.
-       var port: Int
-
-       # Routes knwon by the server.
-       var routes = new Array[Route]
-
-       # Start listen on `host:port`.
-       fun listen do
-               var iface = "{host}:{port}"
-               print "Launching server on http://{iface}/"
-
-               var vh = new VirtualHost(iface)
-               for route in routes do vh.routes.add route
-
-               var fac = new HttpFactory.and_libevent
-               fac.config.virtual_hosts.add vh
-               fac.run
-       end
-end
-
-# Specific nitcorn Action for nitweb.
-class NitAction
-       super Action
-
-       # Link to the NitServer that runs this action.
-       var srv: NitServer
-
-       # Build a custom http response for errors.
-       fun render_error(code: Int, message: String): HttpResponse do
-               var response = new HttpResponse(code)
-               var tpl = new Template
-               tpl.add "<h1>Error {code}</h1>"
-               tpl.add "<pre><code>{message.html_escape}</code></pre>"
-               response.body = tpl.write_to_string
-               return response
-       end
-
-       # Render a view as a HttpResponse 200.
-       fun render_view(view: NitView): HttpResponse do
-               var response = new HttpResponse(200)
-               response.body = view.render(srv).write_to_string
-               return response
-       end
-
-       # Return a HttpResponse containing `json`.
-       fun render_json(json: Jsonable): HttpResponse do
-               var response = new HttpResponse(200)
-               response.body = json.to_json
-               return response
-       end
-end
+import popcorn
 
 # Specific nitcorn Action that uses a Model
 class ModelAction
-       super NitAction
+       super Handler
 
        # Model to use.
        var model: Model
@@ -116,7 +50,12 @@ end
 # A NitView is rendered by an action.
 interface NitView
        # Renders this view and returns something that can be written to a HTTP response.
-       fun render(srv: NitServer): Writable is abstract
+       fun render: Writable is abstract
+end
+
+redef class HttpResponse
+       # Render a NitView as response.
+       fun send_view(view: NitView, status: nullable Int) do send(view.render, status)
 end
 
 redef class HttpRequest
index 7273187..58016e2 100644 (file)
@@ -27,7 +27,7 @@ class HtmlHomePage
        # Loaded model to display.
        var tree: MEntityTree
 
-       redef fun render(srv) do
+       redef fun render do
                var tpl = new Template
                tpl.add new Header(1, "Loaded model")
                tpl.add tree.html_list
@@ -45,7 +45,7 @@ class HtmlResultPage
        # Result set
        var results: Array[MEntity]
 
-       redef fun render(srv) do
+       redef fun render do
                var tpl = new Template
                tpl.add new Header(1, "Results for {query}")
                if results.is_empty then
@@ -76,7 +76,7 @@ class HtmlSourcePage
        # HiglightVisitor used to hilight the source code
        var hl = new HighlightVisitor
 
-       redef fun render(srv) do
+       redef fun render do
                var tpl = new Template
                tpl.add new Header(1, "Source Code")
                tpl.add render_source
@@ -103,7 +103,7 @@ end
 class HtmlDocPage
        super HtmlSourcePage
 
-       redef fun render(srv) do
+       redef fun render do
                var tpl = new Template
                tpl.add new Header(1, mentity.html_name)
                tpl.add "<p>"
@@ -130,7 +130,7 @@ class HtmlDotPage
        # Page title.
        var title: String
 
-       redef fun render(srv) do
+       redef fun render do
                var tpl = new Template
                tpl.add new Header(1, title)
                tpl.add render_dot