tests: Add test_astbuilder to the skip list of nitcg niti nitvm
[nit.git] / contrib / inkscape_tools / src / svg_to_png_and_nit.nit
index db6631f..b8a3157 100644 (file)
@@ -20,7 +20,7 @@ module svg_to_png_and_nit
 import opts
 import template
 
-# Image info extracted from the SVG file
+# Image information extracted from the SVG file
 class Image
        # Name extracted from the object ID minus the `0` prefix and Nit safe
        var name: String
@@ -46,35 +46,126 @@ class Image
        redef fun to_s do return name
 end
 
+# Document being processed, concerns both the source and the target
+class Document
+       # Name of the source file
+       var drawing_name: String
+
+       # Name of the class to generate
+       var nit_class_name: String = drawing_name.capitalized + "Images" is lazy
+
+       # Scaling to apply to the exported image
+       var scale: Float
+
+       # Source minimum X
+       var min_x: Int
+
+       # Source maximum X
+       var max_x: Int
+
+       # Source minimum Y
+       var min_y: Int
+
+       # Source maximum Y
+       var max_y: Int
+
+       # Get the coordinates for `image` as `"x, y, w, h"`
+       fun coordinates(image: Image): String
+       do
+               var x = image.x.adapt(min_x, scale)
+               var y = image.y.adapt(min_y, scale)
+               var w = (image.w.to_f*scale).to_i
+               var h = (image.h.to_f*scale).to_i
+
+               return "{x}, {y}, {w}, {h}"
+       end
+end
+
 # Nit module with a single class to retrieve to access the extracted images
-class ImageSetSrc
+abstract class ImageSetSrc
        super Template
 
-       var name: String
+       # Target document
+       var document: Document
+
+       # Images found in the source document
+       var images: Array[Image]
+end
+
+# Nit module targeting the Gamnit framework
+#
+# Gamnit's `Texture` already manage the lazy loading, no need to do it here.
+class GamnitImageSetSrc
+       super ImageSetSrc
+
+       private fun attributes: Array[String]
+       do
+               # Separate the images from the arrays of images
+               var single_images = new Array[Image]
+               var arrays_of_images = new HashMap[String, Array[Image]]
+
+               for image in images do
+                       var nit_name = image.name
+                       var last_char = nit_name.chars.last
+                       if last_char.to_s.is_numeric then
+
+                               # Is an array
+                               nit_name = nit_name.substring(0, nit_name.length-1)
+                               if not arrays_of_images.keys.has(nit_name) then
+                                       # Create a new array
+                                       var array = new Array[Image]
+                                       arrays_of_images[nit_name] = array
+                               end
+
+                               arrays_of_images[nit_name].add image
+                       else
+                               # Is a single image
+                               single_images.add image
+                       end
+               end
+
+               # Attributes of the class
+               var attributes = new Array[String]
+               attributes.add "\tprivate var root_texture = new Texture(\"images/{document.drawing_name}.png\")\n"
+
+               # Add single images to Nit source file
+               for image in single_images do
+                       # Adapt coordinates to new top left and scale
+                       var coordinates = document.coordinates(image)
 
-       var attributes = new Array[String]
-       var load_exprs = new Array[String]
+                       attributes.add "\tvar {image.name}: Texture = root_texture.subtexture({coordinates})\n"
+               end
+
+               # Add array of images too
+               for name, images in arrays_of_images do
+
+                       var lines = new Array[String]
+                       for image in images do
+                               var coordinates = document.coordinates(image)
+                               lines.add "\t\troot_texture.subtexture({coordinates})"
+                       end
+
+                       attributes.add """
+       var {{{name}}} = new Array[Texture].with_items(
+{{{lines.join(",\n")}}})
+"""
+               end
+
+               return attributes
+       end
 
        redef fun rendering
        do
                add """
 # File generated by svg_to_png_and_nit, do not modify, redef instead
 
-import mnit::image_set
+import gamnit::textures
 
-class {{{name}}}
-       super ImageSet
+class {{{document.nit_class_name}}}
 
 """
                add_all attributes
                add """
-
-       redef fun load_all(app: App)
-       do
-"""
-               add_all load_exprs
-               add """
-       end
 end
 """
        end
@@ -99,11 +190,13 @@ end
 
 var opt_out_src = new OptionString("Path to output source file (folder or file)", "--src", "-s")
 var opt_assets = new OptionString("Path to assert dir where to put PNG files", "--assets", "-a")
-var opt_scale = new OptionFloat("Apply scaling to exported images (default at 1.0 of 90dpi)", 1.0, "--scale", "-x")
+var opt_scale = new OptionFloat("Apply scaling to exported images (default at 1.0)", 1.0, "--scale", "-x")
+var opt_gamnit = new OptionBool("Target the Gamnit framework (the default, kept for compatibility)", "--gamnit", "-g")
+var opt_pow2 = new OptionBool("Round the image size to the next power of 2", "--pow2")
 var opt_help = new OptionBool("Print this help message", "--help", "-h")
 
 var opt_context = new OptionContext
-opt_context.add_option(opt_out_src, opt_assets, opt_scale, opt_help)
+opt_context.add_option(opt_out_src, opt_assets, opt_scale, opt_gamnit, opt_pow2, opt_help)
 
 opt_context.parse(args)
 var rest = opt_context.rest
@@ -122,6 +215,23 @@ if not "inkscape".program_is_in_path then
        exit 1
 end
 
+# Get the inkscape version
+var p = new ProcessReader("inkscape", "--version")
+var version_string = p.read_all
+p.wait
+p.close
+var version_re = "([0-9]+)\\.([0-9]+)".to_re
+var match = version_string.search(version_re)
+assert match != null
+var major = match[1]
+var minor = match[2]
+assert major != null and minor != null
+
+# Set the default API using the version as heuristic
+var default_dpi = 96.0
+if major.to_s.to_i == 0 and minor.to_s.to_i < 92 then default_dpi = 90.0
+
+# Collect source files
 var drawings = rest
 for drawing in drawings do
        if not drawing.file_exists then
@@ -146,8 +256,6 @@ end
 
 var scale = opt_scale.value
 
-var arrays_of_images = new Array[String]
-
 for drawing in drawings do
        var drawing_name = drawing.basename(".svg")
 
@@ -173,8 +281,10 @@ for drawing in drawings do
        end
        svg_file.close
 
-       assert page_width != -1
-       assert page_height != -1
+       if page_width == -1 or page_height == -1 then
+               stderr.write "Source drawing file '{drawing}' doesn't look like an SVG file\n"
+               exit 1
+       end
 
        # Query Inkscape
        var prog = "inkscape"
@@ -216,42 +326,14 @@ for drawing in drawings do
        end
        proc.close
 
-       # Nit class
-       var nit_class_name = drawing_name.chars.first.to_s.to_upper + drawing_name.substring_from(1) + "Images"
-       var nit_src = new ImageSetSrc(nit_class_name)
-       nit_src.attributes.add "\tprivate var main_image: Image is noinit\n"
-       nit_src.load_exprs.add "\t\tmain_image = app.load_image(\"images/{drawing_name}.png\")\n"
 
        # Sort images by name, it prevents Array errors and looks better
        alpha_comparator.sort(images)
 
-       # Add images to Nit source file
-       for image in images do
-               # Adapt coordinates to new top left and scale
-               var x = image.x.adapt(min_x, scale)
-               var y = image.y.adapt(min_y, scale)
-               var w = (image.w.to_f*scale).to_i
-               var h = (image.h.to_f*scale).to_i
+       var document = new Document(drawing_name, scale, min_x, max_x, min_y, max_y)
 
-               var nit_name = image.name
-               var last_char = nit_name.chars.last
-               if last_char.to_s.is_numeric then
-                       # Array of images
-                       # TODO support more than 10 images in an array
-
-                       nit_name = nit_name.substring(0, nit_name.length-1)
-                       if not arrays_of_images.has(nit_name) then
-                               # Create class attribute to store Array
-                               arrays_of_images.add(nit_name)
-                               nit_src.attributes.add "\tvar {nit_name} = new Array[Image]\n"
-                       end
-                       nit_src.load_exprs.add "\t\t{nit_name}.add(main_image.subimage({x}, {y}, {w}, {h}))\n"
-               else
-                       # Single image
-                       nit_src.attributes.add "\tvar {nit_name}: Image is noinit\n"
-                       nit_src.load_exprs.add "\t\t{nit_name} = main_image.subimage({x}, {y}, {w}, {h})\n"
-               end
-       end
+       # Nit class
+       var nit_src = new GamnitImageSetSrc(document, images)
 
        if not src_path.file_extension == "nit" then
                src_path = src_path/drawing_name+".nit"
@@ -262,12 +344,14 @@ for drawing in drawings do
        nit_src.write_to(src_file)
        src_file.close
 
-       # Find closest power of 2
-       var dx = max_x - min_x
-       max_x = dx.next_pow2 + min_x
+       # Find next power of 2
+       if opt_pow2.value then
+               var dx = max_x - min_x
+               max_x = dx.next_pow2 + min_x
 
-       var dy = max_y - min_y
-       max_y = dy.next_pow2 + min_y
+               var dy = max_y - min_y
+               max_y = dy.next_pow2 + min_y
+       end
 
        # Inkscape's --export-area inverts the Y axis. It uses the lower left corner of
        # the drawing area where as queries return coordinates from the top left.
@@ -277,7 +361,7 @@ for drawing in drawings do
        # Output png file to assets
        var png_path = "{assets_path}/images/{drawing_name}.png"
        var proc2 = new Process.from_a(prog, [drawing, "--without-gui",
-               "--export-dpi={(90.0*scale).to_i}",
+               "--export-dpi={(default_dpi*scale).to_i}",
                "--export-png={png_path}",
                "--export-area={min_x}:{y0}:{max_x}:{y1}",
                "--export-background=#000000", "--export-background-opacity=0.0"])