Looked at http://jenkins.gresil.org/jenkins/job/nit/tasks and did some work.
Pull-Request: #1077
Reviewed-by: Romain Chanoir <chanoir.romain@courrier.uqam.ca>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
void nit_gcollect(void); /* force a garbage collection */
void initialize_gc_option(void); /* Select the wanted GC using envvar `NIT_GC_OPTION` */
-void gc_set_finializer(void*); /* Tag a pointer for finalization */
+void gc_register_finalizer(void*); /* Tag a pointer for finalization */
void gc_finalize(void*, void*); /* Finalize a pointer, implemented in the generated code. */
#endif
../../bin/nitc -o bin/friendz src/friendz_linux.nit
android:
- mkdir -p bin
+ mkdir -p bin res
+ ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
../../bin/nitc -o bin/friendz.apk src/friendz_android.nit
doc:
../../bin/nitdoc -d doc/ src/friendz.nit src/friendz_linux.nit
clean:
- rm -rf bin/ doc/
+ rm -rf bin/ doc/ res/
This game was originally developed for the [Casual Gameplay Design Competition
\#9](http://jayisgames.com/cgdc9).
+
+# Artwork
+
+The artwork was created by Sam Hocevar <sam@zoy.org> for the Monsterz arcade
+puzzle game http://sam.zoy.org/monsterz/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="256"
+ height="256"
+ id="svg4386"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="icon.svg">
+ <defs
+ id="defs4388">
+ <radialGradient
+ r="7.7875042"
+ fy="141.32838"
+ fx="106.50102"
+ cy="141.3284"
+ cx="106.50099"
+ gradientTransform="scale(1.02976,0.9711)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient8339"
+ xlink:href="#linearGradient5606"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient5606">
+ <stop
+ id="stop5608"
+ offset="0.0000000"
+ style="stop-color:#000000;stop-opacity:1.0000000;" />
+ <stop
+ id="stop5614"
+ offset="0.20000000"
+ style="stop-color:#000000;stop-opacity:1.0000000;" />
+ <stop
+ id="stop5616"
+ offset="0.30000001"
+ style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+ <stop
+ id="stop5610"
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <filter
+ inkscape:label="Desaturate"
+ x="0"
+ y="0"
+ width="1"
+ height="1"
+ inkscape:menu="Color"
+ inkscape:menu-tooltip="Render in shades of gray by reducing saturation to zero"
+ color-interpolation-filters="sRGB"
+ id="filter3078">
+ <feColorMatrix
+ type="saturate"
+ values="0"
+ id="feColorMatrix3080" />
+ </filter>
+ <filter
+ inkscape:label="Desaturate"
+ x="0"
+ y="0"
+ width="1"
+ height="1"
+ inkscape:menu="Color"
+ inkscape:menu-tooltip="Render in shades of gray by reducing saturation to zero"
+ color-interpolation-filters="sRGB"
+ id="filter3082">
+ <feColorMatrix
+ type="saturate"
+ values="0"
+ id="feColorMatrix3084" />
+ </filter>
+ <filter
+ inkscape:label="Desaturate"
+ x="0"
+ y="0"
+ width="1"
+ height="1"
+ inkscape:menu="Color"
+ inkscape:menu-tooltip="Render in shades of gray by reducing saturation to zero"
+ color-interpolation-filters="sRGB"
+ id="filter3086">
+ <feColorMatrix
+ type="saturate"
+ values="0"
+ id="feColorMatrix3088" />
+ </filter>
+ <filter
+ inkscape:label="Desaturate"
+ x="0"
+ y="0"
+ width="1"
+ height="1"
+ inkscape:menu="Color"
+ inkscape:menu-tooltip="Render in shades of gray by reducing saturation to zero"
+ color-interpolation-filters="sRGB"
+ id="filter3090">
+ <feColorMatrix
+ type="saturate"
+ values="0.71980676328502413"
+ id="feColorMatrix3092" />
+ </filter>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.98994949"
+ inkscape:cx="76.110583"
+ inkscape:cy="101.8389"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1279"
+ inkscape:window-height="1377"
+ inkscape:window-x="1279"
+ inkscape:window-y="29"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata4391">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-796.36218)">
+ <g
+ inkscape:export-ydpi="72.000000"
+ inkscape:export-xdpi="72.000000"
+ inkscape:export-filename="/home/sam/monsterz/monsterz/tiles.png"
+ transform="matrix(4.2708842,0,0,4.1991018,0.37397342,-2109.743)"
+ id="g8300"
+ style="filter:url(#filter3090)">
+ <g
+ style="stroke:none"
+ inkscape:export-ydpi="72.000000"
+ inkscape:export-xdpi="72.000000"
+ inkscape:export-filename="/home/sam/monsterz/monsterz/test.png"
+ transform="matrix(0.823543,0,0,0.832736,-337.8784,464.3823)"
+ id="g8288">
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ id="path8290"
+ d="M 427.22149,306.26985 C 400,308.61218 417.5,276.66759 427.5,286.11218"
+ style="fill:#01ff03;fill-opacity:1;fill-rule:evenodd" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ id="path8292"
+ d="m 467.5,283.61218 c 18.75,-6.25 17.5,28.75 -2.5,18.75"
+ style="fill:#01ff03;fill-opacity:1;fill-rule:evenodd" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path8294"
+ d="M 428.58387,304.20437 C 406.97719,274.86218 485,259.86218 465,302.36218 c 53.75,37.5 -81.25,70 -36.41613,1.84219 z"
+ style="fill:#01ff03;fill-opacity:1;fill-rule:evenodd" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ id="path8296"
+ d="m 420,292.36218 c -1.95031,4.4858 0,6.25 1.25,7.5"
+ style="fill:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ id="path8298"
+ d="m 473.75,289.34798 c 0.60933,3.0142 1.25,4.2642 -1.25,7.44624"
+ style="fill:none" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path8275"
+ d="m 20,747.36218 c 23.207741,2.5 36.25,-13.75 31.25,-20 -1.25,10 -18.03209,20.56008 -31.25,20 z"
+ style="fill:#000000;fill-opacity:0.1372549;fill-rule:evenodd;stroke:none" />
+ <g
+ id="g8283">
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path8277"
+ d="M 14.300999,703.00709 C 5.5600809,697.36218 -4.2738645,716.11218 7.5,718.61218 c -5,-5.67209 -2.5,-13.75 6.800999,-15.60509 z"
+ style="fill:#ffffff;fill-opacity:0.41176471;fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path8279"
+ d="m 45,698.61218 c -13.75,-11.25 -42.5,-0.73064 -28.75,20 -3.75,-12.5 11.25,-25 28.75,-20 z"
+ style="fill:#ffffff;fill-opacity:0.41176471;fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path8281"
+ d="m 57.5,708.61218 c 1.25,-9.4761 -12.5,-11.25 -10,-4.41905 5.560081,-1.83095 7.321465,0.72043 10,4.41905 z"
+ style="fill:#ffffff;fill-opacity:0.41176471;fill-rule:evenodd;stroke:none" />
+ </g>
+ <g
+ style="fill:none"
+ inkscape:export-ydpi="72.000000"
+ inkscape:export-xdpi="72.000000"
+ inkscape:export-filename="/home/sam/monsterz/monsterz/test.png"
+ transform="matrix(0.823543,0,0,0.832736,-337.8784,464.3823)"
+ id="g7882">
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ id="path7659"
+ d="M 427.22149,306.26985 C 400,308.61218 417.5,276.66759 427.5,286.11218"
+ style="stroke:#000000;stroke-width:3.11108565;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ id="path7661"
+ d="m 467.5,283.61218 c 18.75,-6.25 17.5,28.75 -2.5,18.75"
+ style="stroke:#000000;stroke-width:3.11108565;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ id="path7657"
+ d="M 428.58387,304.20437 C 406.97719,274.86218 485,259.86218 465,302.36218 c 53.75,37.5 -81.25,70 -36.41613,1.84219 z"
+ style="stroke:#000000;stroke-width:3.11108565;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ id="path7663"
+ d="m 420,292.36218 c -1.95031,4.4858 0,6.25 1.25,7.5"
+ style="stroke:#000000;stroke-width:3.11108565;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ id="path7665"
+ d="m 473.75,289.34798 c 0.60933,3.0142 1.25,4.2642 -1.25,7.44624"
+ style="stroke:#000000;stroke-width:3.11108565;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+ </g>
+ </g>
+ <g
+ inkscape:export-ydpi="72.000000"
+ inkscape:export-xdpi="72.000000"
+ inkscape:export-filename="/home/sam/monsterz/monsterz/tiles.png"
+ transform="matrix(4.3642738,0,0,-0.17844664,-531.2477,940.61654)"
+ id="g8323"
+ style="filter:url(#filter3090)">
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ id="path8325"
+ d="M 150.47232,132.96909 150,134.86218"
+ style="fill:none;stroke:#000000;stroke-width:12.36332512;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc"
+ id="path8327"
+ d="m 153.75,132.96909 0.47232,1.89309"
+ style="fill:none;stroke:#000000;stroke-width:12.36332512;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+ </g>
+ <g
+ inkscape:export-ydpi="72.000000"
+ inkscape:export-xdpi="72.000000"
+ inkscape:export-filename="/home/sam/monsterz/monsterz/tiles.png"
+ transform="matrix(4.3642695,0,0,4.3642084,-733.54667,664.62487)"
+ id="g8329"
+ style="filter:url(#filter3090)">
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="72.000000"
+ inkscape:export-xdpi="72.000000"
+ inkscape:export-filename="/home/sam/monsterz/monsterz/test.png"
+ sodipodi:nodetypes="cc"
+ id="path8331"
+ d="m 191.8115,62.362183 c 2.83835,1.82034 7.56893,1.99609 11.3534,0"
+ style="fill:none;stroke:#ffffff;stroke-width:2.49998164;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.41176471" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="72.000000"
+ inkscape:export-xdpi="72.000000"
+ inkscape:export-filename="/home/sam/monsterz/monsterz/test.png"
+ sodipodi:nodetypes="cc"
+ id="path8333"
+ d="m 193.0615,64.152194 c 2.83835,1.82034 7.56893,1.99609 11.3534,0"
+ style="fill:none;stroke:#000000;stroke-width:2.49998164;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.1372549" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="72.000000"
+ inkscape:export-xdpi="72.000000"
+ inkscape:export-filename="/home/sam/monsterz/monsterz/test.png"
+ sodipodi:nodetypes="cc"
+ id="path8335"
+ d="m 192.5,63.430263 c 2.83835,1.82034 7.56893,1.99609 11.3534,0"
+ style="fill:none;stroke:#000000;stroke-width:2.49998164;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1" />
+ </g>
+ <path
+ inkscape:export-ydpi="72.000000"
+ inkscape:export-xdpi="72.000000"
+ inkscape:export-filename="/home/sam/monsterz/monsterz/tiles.png"
+ transform="matrix(4.2024883,1.3865396,-2.0345896,3.8609453,-52.336063,179.80496)"
+ d="m 115.86819,137.36218 a 6.1977272,6.1227274 0 1 1 -12.39545,0 6.1977272,6.1227274 0 1 1 12.39545,0 z"
+ sodipodi:ry="6.1227274"
+ sodipodi:rx="6.1977272"
+ sodipodi:cy="137.36218"
+ sodipodi:cx="109.67046"
+ id="path8337"
+ style="fill:url(#radialGradient8339);fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.49998115999999992;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;filter:url(#filter3090)"
+ sodipodi:type="arc" />
+ </g>
+</svg>
import realtime
import solver
import mnit::tileset
+import app::data_store
+import md5
intrude import grid
intrude import level
level = null
var i = levels.first
for l in levels do
- if l.get_state == l.l_open then break
i = l
+ if l.get_state == l.l_open then break
end
entities.push(new StartButton(self, i))
end
end
var ev = lastev
if ev isa Event then
- display.blit(img[4,0],ev.offset_x-42,ev.offset_y-6)
+ # Cursor, kept for debugging
+ #display.blit(img[4,0],ev.offset_x-42,ev.offset_y-6)
end
dirty_all = false
end
end
end
end
+
+ redef fun load_levels
+ do
+ super
+
+ for level in levels do
+ var score = app.data_store["s{level.str.md5}"]
+ if score isa Int then
+ level.score = score
+ end
+ end
+ end
end
# The spash title image
return "unknown"
end
end
+
+redef class Level
+ redef fun save
+ do
+ app.data_store["s{str.md5}"] = if score > 0 then score else null
+ end
+end
import friendz
import mnit_android
+import android::landscape
redef class App
+ # Zoom applied for the device display from the game logic coordinates
+ var zoom = 1.0
+
redef fun window_created
do
super
- var w = screen_width
- display.set_viewport(0,0,w,w*display.height/display.width)
+
+ var h = screen_height
+ display.set_viewport(0,0,h*display.width/display.height,h)
+
+ zoom = display.height.to_f / h.to_f
end
end
redef class AndroidPointerEvent
- redef fun is_motion do return not motion_event.just_went_down
+ redef fun is_motion do return not just_went_down
+
+ redef fun x do return super / app.zoom
+ redef fun y do return super / app.zoom
end
return true
end
- fun save
- do
- #save_cookie("s"+self.hash, self.score>0?self.score:"")
- end
+ # Save the score of the level
+ fun save do end
end
# main game object
for i in [0..levels_code.length[ do
var l = new Level(self,i, levels_code[i])
levels[i] = l
- #var v = read_cookie("s"+l.hash)
- #l = v
end
end
Jwrapper won't wrap a class that already is in the `lib/android` directory.
Can't use both -c and -w together, either you comment unknown types or you wrap them.
-
-## Limitations
-jwrapper support for java primitive array is limited to one parameter and the return value.
-
-If the method contains more than one primitive array parameter, the method will be commented with a `NOT SUPPORTED` notice.
-
-## TODO List
-* Generate static methods on top-level
-* Extend primitive array support
-* Enhance static overload support (currently, it suffixes the method name with a number)
do
var temp = new Array[String]
temp.add("extern class Native{jtype.id} in \"Java\" `\{ {jtype} `\}\n")
- temp.add("\tsuper JavaObject\n\tredef type SELF: Native{jtype.id}\n\n")
+ temp.add("\tsuper JavaObject\n\n")
return temp.join("")
end
var temp = new Array[String]
temp.add("extern class {nit_type} in \"Java\" `\{ {jtype.to_package_name} `\}\n")
- temp.add("\tsuper JavaObject\n\tredef type SELF: {nit_type}\n\nend\n")
+ temp.add("\tsuper JavaObject\n\nend\n")
return temp.join("")
end
nit_signature.add ": {return_type} "
end
- var param_to_copy = param_to_copy(jparam_list, nit_types)
-
var temp = new Array[String]
- if nb_params > 1 then
- comment = "#"
- temp.add("\t# NOT SUPPORTED: more than one parameter to copy\n")
- temp.add("\t# Has to be implemented manually\n")
- end
-
temp.add(comment + nit_signature.join(""))
# FIXME : This huge `if` block is only necessary to copy primitive arrays as long as there's no better way to do it
temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
# Methods with return type
else if return_type != null then
- if jreturn_type.is_primitive_array then
- # Copy one parameter and the return value
- if param_to_copy != null then
- var rtype_couple = new Couple[JavaType, NitType](jreturn_type, return_type)
- temp.add(code_warehouse.param_return_copy(rtype_couple, param_to_copy, jmethod_id, java_params))
- # Copy the return type
- else
- temp.add(code_warehouse.return_type_copy(jreturn_type, return_type, jmethod_id, java_params))
- end
- # Copy the parameter
- else if param_to_copy != null then
- temp.add(code_warehouse.param_type_copy(param_to_copy.first, param_to_copy.second, jmethod_id, java_params, true))
- # No copy
- else
- temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast} recv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
- end
+ temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast} recv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
# Methods without return type
else if jreturn_type.is_void then
- # Copy one parameter
- if param_to_copy != null then
- temp.add(code_warehouse.param_type_copy(param_to_copy.first, param_to_copy.second, jmethod_id, java_params, false))
- # No copy
- else
- temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
- end
+ temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
# No copy
else
temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
return temp.join("")
end
-
- # Only one primitive array parameter can be copied
- # If there's none or more than one then `null` is returned
- fun param_to_copy(jtypes: Array[JavaType], ntypes: Array[NitType]): nullable Couple[JavaType, NitType]
- do
- var counter = 0
- var couple = null
- for i in [0..jtypes.length[ do
- if jtypes[i].is_primitive_array then
- counter += 1
- couple = new Couple[JavaType, NitType](jtypes[i], ntypes[i])
- end
- end
-
- nb_params = counter
-
- if counter > 1 then return null
- return couple
- end
end
# Contains raw code mostly used to copy collections
class CodeWarehouse
- # Collection as return value
- fun return_type_copy(java_type: JavaType, nit_type: NitType, jmethod_id, params_id: String): String
- do
- var narray_id = "nit_array"
- var loop_ = create_loop(java_type, nit_type, false, "java_array", narray_id)
- var imports = create_imports(nit_type, false)
-
- return """{{{imports}}} in "Java" `{
- {{{java_type.to_s}}} java_array = recv.{{{jmethod_id}}}({{{params_id}}});
- int {{{narray_id}}} = new_{{{nit_type.id}}}_of_{{{nit_type.generic_params.join("_")}}}();
-
- {{{loop_}}}
-
- return {{{narray_id}}};
- `}
-"""
- end
-
- # Collection as parameter
- fun param_type_copy(java_type: JavaType, nit_type: NitType, jmethod_id, params_id: String, has_return: Bool): String
- do
- var narray_id = "nit_array"
- var jarray_id = "java_array"
- var loop_ = create_loop(java_type, nit_type, true, jarray_id, narray_id)
- var imports = create_imports(nit_type, true)
- var jinstanciation = create_array_instance(java_type, nit_type, jarray_id)
- var return_str = ""
-
- if has_return then
- return_str = "return "
- end
-
- params_id = params_id.replace(nit_type.arg_id, jarray_id)
-
- return """{{{imports}}} in "Java" `{
- {{{jinstanciation}}}
- int {{{narray_id}}} = new_{{{nit_type.id}}}_of_{{{nit_type.generic_params.join("_")}}}();
-
- {{{loop_}}}
-
- {{{return_str}}}recv.{{{jmethod_id}}}({{{params_id}}});
- `}
-"""
- end
-
- # One collection parameter and the return type will be copied
- fun param_return_copy(return_types, param_types: Couple[JavaType, NitType], jmethod_id, params_id: String): String
- do
- var narray_id = "nit_array"
- var narray_id2 = "nit_array2"
-
- var r_jtype = return_types.first
- var r_ntype = return_types.second
-
- var p_jtype = param_types.first
- var p_ntype = param_types.second
-
- var r_loop = create_loop(r_jtype, r_ntype, false, "java_array", narray_id)
- var p_loop = create_loop(p_jtype, p_ntype, true, "java_array2", narray_id2)
-
- var imports = new Array[String]
-
- # Avoid import duplication
- if p_ntype.to_s != r_ntype.to_s then
- imports.add create_imports(p_ntype, true)
- end
-
- imports.add create_imports(r_ntype, false)
-
- params_id = params_id.replace(p_ntype.arg_id, narray_id)
-
- var jinstanciation = create_array_instance(p_jtype, p_ntype, "java_array")
-
- return """{{{imports.join(", ")}}} in "Java" `{
- {{{jinstanciation}}}
-
- {{{p_loop}}}
-
- {{{r_jtype.to_s}}} java_array2 = recv.{{{jmethod_id}}}({{{params_id}}});
- int {{{narray_id2}}} = new_{{{r_ntype.id}}}_of_{{{r_ntype.generic_params.join("_")}}}();
-
- {{{r_loop}}}
-
- return {{{narray_id2}}};
- `}
-"""
- end
-
- private fun create_array_instance(java_type: JavaType, nit_type: NitType, jarray_id: String): String
- do
- var jtype = java_type.to_s
- var instanciation = ""
-
- if java_type.is_primitive_array then
- instanciation = "{jtype} {jarray_id} = new {java_type.full_id}[(int)Array_of_{nit_type.generic_params[0]}_length({nit_type.arg_id})];"
- else
- instanciation = "{jtype} {jarray_id} = new {jtype}();"
- end
-
- return instanciation
- end
-
private fun create_imports(nit_type: NitType, is_param: Bool): String
do
var imports = ""
return_cast_map["CharSequence"] = "(String)"
end
- init with_collections
- do
- self.init
- # Collections
- type_map["List"] = "Array"
- type_map["ArrayList"] = "Array"
- type_map["LinkedList"] = "List"
- type_map["Vector"] = "Array"
-
- type_map["Set"] = "HashSet"
- type_map["SortedSet"] = "Still have to make my mind on this one"
- type_map["HashSet"] = "HashSet"
- type_map["TreeSet"] = "HashSet"
- type_map["LinkedHashSet"] = "HashSet"
- type_map["Map"] = "HashMap"
- type_map["SortedMap"] = "RBTreeMap"
- type_map["HashMap"] = "HashMap"
- type_map["TreeMap"] = "RBTreeMap"
- type_map["Hashtable"] = "HashMap"
- type_map["LinkedHashMap"] = "HashMap"
- end
-
fun to_nit_type(java_type: String): nullable String
do
return self.type_map.get_or_null(java_type)
fun to_nit_type: NitType
do
var nit_type: NitType
+ var type_id = null
- if self.is_primitive_array then
- return self.convert_primitive_array
+ if not is_primitive_array then
+ type_id = converter.to_nit_type(self.id)
end
- var type_id = converter.to_nit_type(self.id)
-
if type_id == null then
nit_type = self.extern_name
nit_type.is_complete = false
return nit_type
end
- fun convert_primitive_array: NitType
- do
- var nit_type = new NitType("Array")
-
- var last_nit_type = nit_type
-
- for i in [1..array_dimension] do
- var temp: NitType
- last_nit_type.generic_params = new Array[NitType]
-
- if i == array_dimension then
- var temp_type = converter.to_nit_type(self.id)
-
- if temp_type == null then
- temp = self.extern_name
- nit_type.is_complete = false
- if temp.mod != null then nit_type.mod = temp.mod
- else
- temp = new NitType(temp_type)
- end
- else
- temp = new NitType("Array")
- end
-
- last_nit_type.generic_params.add(temp)
-
- last_nit_type = temp
- end
-
- return nit_type
- end
-
fun is_iterable: Bool do return iterable.has(self.id)
fun is_collection: Bool do return is_primitive_array or collections_list.has(self.id)
do
if is_wrapped then return new NitType.with_module(find_extern_class.as(not null).first, find_extern_class.as(not null).second)
- var name = "Native" + extern_class_name.join("")
- var nit_type: NitType
- if self.is_primitive_array then
- nit_type = new NitType.with_generic_params("Array", name)
+ var name
+ if is_primitive_array then
+ # Primitive arrays have a special naming convention
+ name = "Native" + extern_class_name.join("").capitalized + "Array"
else
- nit_type = new NitType("Native" + extern_class_name.join(""))
+ name = "Native" + extern_class_name.join("")
end
- nit_type.is_complete = false
+ var nit_type = new NitType(name)
+ nit_type.is_complete = false
return nit_type
end
# Search inside `lib/android` directory for already wrapped classes
# If found, contains the class identifier and the Nit Module name
- var find_extern_class: nullable Couple[String, NitModule] = find_extern_class_fun is lazy
+ var find_extern_class: nullable Couple[String, NitModule] is lazy do
- private fun find_extern_class_fun: nullable Couple[String, NitModule]
- do
- var regex = "extern class Native[a-zA-Z1-9]\\\+[ ]\\\+in[ ]\\\+\"Java\"[ ]*`\{[ ]*" + self.to_s + "\\\+[ ]*`\}"
- var grep = new IProcess("grep", "-r", regex, "{"NIT_DIR".environ}/lib/android/")
+ var regex = "extern class [a-zA-Z1-9]\\\+[ ]\\\+in[ ]\\\+\"Java\"[ ]*`\{[ ]*" + self.to_s + "\\\+[ ]*`\}"
+ var nit_dir = "NIT_DIR".environ
+ var grep = new IProcess("grep", "-r", regex, nit_dir/"lib/android/", nit_dir/"lib/java/")
var to_eat = ["private", "extern", "class"]
var output = grep.read_line
app_name("Ballz")
end
+import android::portrait
+
import game_logic
redef class App
import dino
import mnit_android
+import android::portrait
import android::vibration
redef class ImageSet
module moles_android
-import moles
import mnit_android
+import android::portrait
+
+import moles
redef class Game
redef fun columns do return 3
android_manifest("""<uses-permission android:name="android.permission.VIBRATE" />""")
end
-import simple
import mnit_android
+import android::portrait
import serialization
+import simple
+
in "Java" `{
import android.content.Context;
import android.widget.Toast;
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services from the Google Cardboard SDK for virtual reality on Android
+#
+# Projects using this module should keep the `cardboard.jar` archive in the
+# `libs` folder at the root of the project.
+#
+# External resources:
+# * Download `cardboard.jar` from
+# https://raw.githubusercontent.com/googlesamples/cardboard-java/master/CardboardSample/libs/cardboard.jar
+# * Read about Cardboard at
+# https://developers.google.com/cardboard/
+# * Find the Cardboard SDK documentation at
+# https://developers.google.com/cardboard/android/latest/reference/com/google/vrtoolkit/cardboard/package-summary
+module cardboard
+
+import java::collections
+import native_app_glue
+
+in "Java" `{
+ import com.google.vrtoolkit.cardboard.CardboardActivity;
+ import com.google.vrtoolkit.cardboard.sensors.HeadTracker;
+`}
+
+# Provides head tracking information from the device IMU
+#
+# The corresponding Java class is no longer documented, but it is still useful.
+extern class NativeHeadTracker in "Java" `{ com.google.vrtoolkit.cardboard.sensors.HeadTracker `}
+ super JavaObject
+
+ # Instantiate a new `NativeHeadTracker` for the given `context`
+ new (context: NativeContext) in "Java" `{
+ return HeadTracker.createFromContext(context);
+ `}
+
+ # Start tracking head movement
+ fun start_tracking in "Java" `{ recv.startTracking(); `}
+
+ # Stop tracking head movement
+ fun stop_tracking in "Java" `{ recv.stopTracking(); `}
+
+ # Apply correction to the gyroscope values
+ fun gyro_bias=(matrix: JavaFloatArray) in "Java" `{
+ recv.setGyroBias(matrix);
+ `}
+
+ # Enable finer analysis using the neck as center of movement
+ fun neck_model_enabled=(value: Bool) in "Java" `{
+ recv.setNeckModelEnabled(value);
+ `}
+
+ # Fill `matrix` with the last rotation matrix calculated from head movements
+ #
+ # Require: matrix.length >= offset + 16
+ fun last_head_view(matrix: JavaFloatArray, offset: Int) in "Java" `{
+ recv.getLastHeadView(matrix, (int)offset);
+ `}
+end
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2012-2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Pointer and hardware key events
+module input_events
+
+import mnit_input
+import android
+
+in "C header" `{
+ #include <android/log.h>
+ #include <android_native_app_glue.h>
+
+ #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "mnit", __VA_ARGS__))
+ #ifdef DEBUG
+ #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "mnit", __VA_ARGS__))
+ #else
+ #define LOGI(...) (void)0
+ #endif
+`}
+
+in "C" `{
+ /* Handle inputs from the Android platform and sort them before
+ sending them in the Nit App */
+ static int32_t mnit_handle_input(struct android_app* app, AInputEvent* event) {
+ App nit_app = app->userData;
+ LOGI("handle input %i", (int)pthread_self());
+ if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) {
+ LOGI("key");
+ return App_native_input_key(nit_app, event);
+ }
+ else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
+ LOGI("motion");
+ return App_native_input_motion(nit_app, event);
+ }
+
+ return 0;
+ }
+`}
+
+private extern class NativeAndroidMotionEvent `{AInputEvent *`}
+
+ fun pointers_count: Int `{
+ return AMotionEvent_getPointerCount(recv);
+ `}
+
+ # Did this motion event just started?
+ fun just_went_down: Bool `{
+ return (AMotionEvent_getAction(recv) & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN;
+ `}
+
+ fun edge: Int `{
+ return AMotionEvent_getEdgeFlags(recv);
+ `}
+
+ # Get the non-primary pointer id that just went down (returns -1 or > 0)
+ fun index_down_pointer: Int `{
+ int a = AMotionEvent_getAction(recv);
+ if ((a & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN)
+ return (a & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+ else return -1;
+ `}
+
+ fun action: AMotionEventAction `{ return AMotionEvent_getAction(recv); `}
+end
+
+private extern class AMotionEventAction `{ int32_t `}
+ fun action: Int `{ return recv & AMOTION_EVENT_ACTION_MASK; `}
+
+ fun is_down: Bool do return action == 0
+ fun is_up: Bool do return action == 1
+ fun is_move: Bool do return action == 2
+ fun is_cancel: Bool do return action == 3
+ fun is_outside: Bool do return action == 4
+ fun is_pointer_down: Bool do return action == 5
+ fun is_pointer_up: Bool do return action == 6
+end
+
+# An input event on Android
+interface AndroidInputEvent
+ super InputEvent
+end
+
+# A motion event concerning a single or more `pointers`
+class AndroidMotionEvent
+ super AndroidInputEvent
+ super MotionEvent
+
+ private var native: NativeAndroidMotionEvent
+
+ private var pointers_cache: nullable Array[AndroidPointerEvent] = null
+
+ # Pointers (or fingers) composing this motion event
+ fun pointers: Array[AndroidPointerEvent]
+ do
+ if pointers_cache != null then
+ return pointers_cache.as(not null)
+ else
+ var pointers = new Array[AndroidPointerEvent]
+ var pointers_count = native.pointers_count
+ for i in [0 .. pointers_count [do
+ var pointer_event = new AndroidPointerEvent(self, i)
+ pointers.add(pointer_event)
+ end
+ pointers_cache = pointers
+ return pointers
+ end
+ end
+
+ redef fun just_went_down: Bool do return native.just_went_down
+
+ # Was the top edge of the screen intersected by this event?
+ fun touch_to_edge: Bool do return native.edge == 1
+
+ # Was the bottom edge of the screen intersected by this event?
+ fun touch_bottom_edge: Bool do return native.edge == 2
+
+ # Was the left edge of the screen intersected by this event?
+ fun touch_left_edge: Bool do return native.edge == 4
+
+ # Was the right edge of the screen intersected by this event?
+ fun touch_right_edge: Bool do return native.edge == 8
+
+ redef fun down_pointer: nullable AndroidPointerEvent
+ do
+ if just_went_down then
+ # The primary pointer went down
+ return pointers[0]
+ end
+
+ var i = native.index_down_pointer
+ if i > 0 then
+ # A secondary pointer went down
+ return pointers[i]
+ else
+ return null
+ end
+ end
+end
+
+# A pointer event
+class AndroidPointerEvent
+ super PointerEvent
+ super AndroidInputEvent
+
+ private var motion_event: AndroidMotionEvent
+
+ private var pointer_id: Int
+
+ redef fun x: Float do return native_x(motion_event.native, pointer_id)
+
+ private fun native_x(motion_event: NativeAndroidMotionEvent, pointer_id: Int): Float `{
+ return AMotionEvent_getX(motion_event, pointer_id);
+ `}
+
+ redef fun y: Float do return native_y(motion_event.native, pointer_id)
+
+ private fun native_y(motion_event: NativeAndroidMotionEvent, pointer_id: Int): Float `{
+ return AMotionEvent_getY(motion_event, pointer_id);
+ `}
+
+ # Pressure applied by this pointer
+ fun pressure: Float do return native_pressure(motion_event.native, pointer_id)
+
+ private fun native_pressure(motion_event: NativeAndroidMotionEvent, pointer_id: Int): Float `{
+ return AMotionEvent_getPressure(motion_event, pointer_id);
+ `}
+
+ redef fun pressed
+ do
+ var action = motion_event.native.action
+ return action.is_down or action.is_move
+ end
+
+ redef fun depressed do return not pressed
+
+ # Does this pointer just began touching the screen?
+ fun just_went_down: Bool
+ do
+ return motion_event.down_pointer == self
+ end
+end
+
+# An hardware key event
+extern class AndroidKeyEvent `{AInputEvent *`}
+ super KeyEvent
+ super AndroidInputEvent
+
+ private fun action: Int `{ return AKeyEvent_getAction(recv); `}
+
+ redef fun is_down: Bool do return action == 0
+ redef fun is_up: Bool do return action == 1
+
+ # Hardware code of the key raising this event
+ fun key_code: Int `{ return AKeyEvent_getKeyCode(recv); `}
+
+ redef fun to_c `{
+ int code = AKeyEvent_getKeyCode(recv);
+ if (code >= AKEYCODE_0 && code <= AKEYCODE_9)
+ return '0'+code-AKEYCODE_0;
+ if (code >= AKEYCODE_A && code <= AKEYCODE_Z)
+ return 'a'+code-AKEYCODE_A;
+ return 0;
+ `}
+
+ # Was this event raised by the back key?
+ fun is_back_key: Bool do return key_code == 4
+
+ # Was this event raised by the menu key?
+ fun is_menu_key: Bool do return key_code == 82
+
+ # Was this event raised by the search key?
+ fun is_search_key: Bool do return key_code == 84
+
+ # Was this event raised by the volume up key?
+ fun is_volume_up: Bool do return key_code == 24
+
+ # Was this event raised by the volume down key?
+ fun is_volume_down: Bool do return key_code == 25
+end
+
+redef class App
+
+ redef fun init_window
+ do
+ set_as_input_handler native_app_glue
+ super
+ end
+
+ private fun set_as_input_handler(app_glue: NativeAppGlue)
+ import native_input_key, native_input_motion `{
+ app_glue->onInputEvent = mnit_handle_input;
+ `}
+
+ # these are used as a callback from native to type incoming events
+ private fun native_input_key(event: AndroidKeyEvent): Bool is abstract
+
+ private fun native_input_motion(event: NativeAndroidMotionEvent): Bool is abstract
+end
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config to set the landscape orientation
+module landscape is android_manifest_activity """
+ android:screenOrientation="landscape"
+"""
+
+import platform
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config to set the portrait orientation
+module portrait is android_manifest_activity """
+ android:screenOrientation="portrait"
+"""
+
+import platform
## GLESv2
#
-print "Can compile shaders? {gl_shader_compiler}"
+print "Can compile shaders? {gl.shader_compiler}"
assert_no_gl_error
-assert gl_shader_compiler else print "Cannot compile shaders"
+assert gl.shader_compiler else print "Cannot compile shaders"
# gl program
-print gl_error.to_s
+print gl.error.to_s
var program = new GLProgram
if not program.is_ok then
- print "Program is not ok: {gl_error.to_s}\nLog:"
+ print "Program is not ok: {gl.error.to_s}\nLog:"
print program.info_log
abort
end
# vertex shader
var vertex_shader = new GLVertexShader
-assert vertex_shader.is_ok else print "Vertex shader is not ok: {gl_error}"
+assert vertex_shader.is_ok else print "Vertex shader is not ok: {gl.error}"
vertex_shader.source = """
attribute vec4 vPosition;
void main()
{
gl_Position = vPosition;
-} """
+}
+""".to_cstring
vertex_shader.compile
assert vertex_shader.is_compiled else print "Vertex shader compilation failed with: {vertex_shader.info_log} {program.info_log}"
assert_no_gl_error
# fragment shader
var fragment_shader = new GLFragmentShader
-assert fragment_shader.is_ok else print "Fragment shader is not ok: {gl_error}"
+assert fragment_shader.is_ok else print "Fragment shader is not ok: {gl.error}"
fragment_shader.source = """
precision mediump float;
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
-"""
+""".to_cstring
fragment_shader.compile
assert fragment_shader.is_compiled else print "Fragment shader compilation failed with: {fragment_shader.info_log}"
assert_no_gl_error
var vertices = [0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0]
var vertex_array = new VertexArray(0, 3, vertices)
vertex_array.attrib_pointer
-gl_clear_color(0.5, 0.0, 0.5, 1.0)
+gl.clear_color(0.5, 0.0, 0.5, 1.0)
for i in [0..10000[ do
printn "."
assert_no_gl_error
- gl_viewport(0, 0, width, height)
- gl_clear_color_buffer
+ gl.viewport(0, 0, width, height)
+ gl.clear((new GLBuffer).color)
program.use
vertex_array.enable
vertex_array.draw_arrays_triangles
# Abstract OpenGL ES shader object, implemented by `GLFragmentShader` and `GLVertexShader`
extern class GLShader `{GLuint`}
# Set the source of the shader
- fun source=(code: String) import String.to_cstring, String.length `{
- GLchar *c_code = String_to_cstring(code);
- glShaderSource(recv, 1, (const GLchar * const*)&c_code, NULL);
+ fun source=(code: NativeString) `{
+ glShaderSource(recv, 1, (GLchar const **)&code, NULL);
`}
# Source of the shader, if available
`}
end
+# General type for OpenGL enumerations
+extern class GLEnum `{ GLenum `}
+
+ redef fun hash `{ return recv; `}
+
+ redef fun ==(o) do return o != null and is_same_type(o) and o.hash == self.hash
+end
+
# An OpenGL ES 2.0 error code
-extern class GLError `{ GLenum `}
+extern class GLError
+ super GLEnum
+
+ # Is there no error?
fun is_ok: Bool do return is_no_error
+
+ # Is this not an error?
fun is_no_error: Bool `{ return recv == GL_NO_ERROR; `}
+
fun is_invalid_enum: Bool `{ return recv == GL_INVALID_ENUM; `}
fun is_invalid_value: Bool `{ return recv == GL_INVALID_VALUE; `}
fun is_invalid_operation: Bool `{ return recv == GL_INVALID_OPERATION; `}
end
end
-# Clear the color buffer with `r`, `g`, `b`, `a`
-protected fun gl_clear_color(r, g, b, a: Float) `{ glClearColor(r, g, b, a); `}
-
-# Set the viewport
-protected fun gl_viewport(x, y, width, height: Int) `{ glViewport(x, y, width, height); `}
-
-# Direct call to `glClear`, call with a combinaison of `gl_clear_color_buffer`,
-# `gl_stencil_buffer_bit` and `gl_color_buffer_bit`.
-private fun gl_clear(flag: Int) `{ glClear(flag); `}
-
-protected fun gl_depth_buffer_bit: Int do return 0x0100
-protected fun gl_stencil_buffer_bit: Int do return 0x0400
-protected fun gl_color_buffer_bit: Int do return 0x4000
-
-protected fun gl_clear_color_buffer do gl_clear(gl_color_buffer_bit)
-protected fun gl_clear_depth_buffer do gl_clear(gl_depth_buffer_bit)
-protected fun gl_clear_stencil_buffer do gl_clear(gl_stencil_buffer_bit)
-
-protected fun gl_error: GLError `{ return glGetError(); `}
protected fun assert_no_gl_error
do
- var error = gl_error
+ var error = gl.error
if not error.is_ok then
print "GL error: {error}"
abort
end
end
-# Query the boolean value at `key`
-private fun gl_get_bool(key: Int): Bool `{
- GLboolean val;
- glGetBooleanv(key, &val);
- return val == GL_TRUE;
-`}
+# Texture minifying function
+#
+# Used by: `GLES::tex_parameter_min_filter`
+extern class GLTextureMinFilter
+ super GLEnum
-# Query the floating point value at `key`
-private fun gl_get_float(key: Int): Float `{
- GLfloat val;
- glGetFloatv(key, &val);
- return val;
-`}
+ new nearest `{ return GL_NEAREST; `}
+ new linear `{ return GL_LINEAR; `}
+end
-# Query the integer value at `key`
-private fun gl_get_int(key: Int): Int `{
- GLint val;
- glGetIntegerv(key, &val);
- return val;
-`}
+# Texture magnification function
+#
+# Used by: `GLES::tex_parameter_mag_filter`
+extern class GLTextureMagFilter
+ super GLEnum
+
+ new nearest `{ return GL_NEAREST; `}
+ new linear `{ return GL_LINEAR; `}
+ new nearest_mipmap_nearest `{ return GL_NEAREST_MIPMAP_NEAREST; `}
+ new linear_mipmap_nearest `{ return GL_LINEAR_MIPMAP_NEAREST; `}
+ new nearest_mipmap_linear `{ return GL_NEAREST_MIPMAP_LINEAR; `}
+ new linear_mipmap_linear `{ return GL_LINEAR_MIPMAP_LINEAR; `}
+end
+
+# Wrap parameter of a texture
+#
+# Used by: `tex_parameter_wrap_*`
+extern class GLTextureWrap
+ super GLEnum
-# Does this driver support shader compilation?
+ new clamp_to_edge `{ return GL_CLAMP_TO_EDGE; `}
+ new mirrored_repeat `{ return GL_MIRRORED_REPEAT; `}
+ new repeat `{ return GL_REPEAT; `}
+end
+
+# Target texture
#
-# Should always return `true` in OpenGL ES 2.0 and 3.0.
-fun gl_shader_compiler: Bool do return gl_get_bool(0x8DFA)
+# Used by: `tex_parameter_*`
+extern class GLTextureTarget
+ super GLEnum
+
+ new flat `{ return GL_TEXTURE_2D; `}
+ new cube_map `{ return GL_TEXTURE_CUBE_MAP; `}
+end
+
+# A server-side capability
+class GLCap
+
+ # TODO private init
+
+ # Internal OpenGL integer for this capability
+ private var val: Int
+
+ # Enable this server-side capability
+ fun enable do enable_native(val)
+ private fun enable_native(cap: Int) `{ glEnable(cap); `}
+
+ # Disable this server-side capability
+ fun disable do disable_native(val)
+ private fun disable_native(cap: Int) `{ glDisable(cap); `}
+
+ redef fun hash do return val
+ redef fun ==(o) do return o != null and is_same_type(o) and o.hash == self.hash
+end
+redef class Sys
+ private var gles = new GLES is lazy
+end
+
+# Entry points to OpenGL ES 2.0 services
+fun gl: GLES do return sys.gles
+
+# OpenGL ES 2.0 services
+class GLES
+
+ # Clear the color buffer to `red`, `green`, `blue` and `alpha`
+ fun clear_color(red, green, blue, alpha: Float) `{
+ glClearColor(red, green, blue, alpha);
+ `}
+
+ # Set the viewport
+ fun viewport(x, y, width, height: Int) `{ glViewport(x, y, width, height); `}
+
+ # Specify mapping of depth values from normalized device coordinates to window coordinates
+ #
+ # Default at `gl_depth_range(0.0, 1.0)`
+ fun depth_range(near, far: Float) `{ glDepthRangef(near, far); `}
+
+ # Define front- and back-facing polygons
+ #
+ # Front-facing polygons are clockwise if `value`, counter-clockwise otherwise.
+ fun front_face=(value: Bool) `{ glFrontFace(value? GL_CW: GL_CCW); `}
+
+ # Specify whether front- or back-facing polygons can be culled, default is `back` only
+ #
+ # One or both of `front` or `back` must be `true`. If you want to deactivate culling
+ # use `(new GLCap.cull_face).disable`.
+ #
+ # Require: `front or back`
+ fun cull_face(front, back: Bool)
+ do
+ assert not (front or back)
+ cull_face_native(front, back)
+ end
+
+ private fun cull_face_native(front, back: Bool) `{
+ glCullFace(front? back? GL_FRONT_AND_BACK: GL_BACK: GL_FRONT);
+ `}
+
+ # Clear the `buffer`
+ fun clear(buffer: GLBuffer) `{ glClear(buffer); `}
+
+ # Last error from OpenGL ES 2.0
+ fun error: GLError `{ return glGetError(); `}
+
+ # Query the boolean value at `key`
+ private fun get_bool(key: Int): Bool `{
+ GLboolean val;
+ glGetBooleanv(key, &val);
+ return val == GL_TRUE;
+ `}
+
+ # Query the floating point value at `key`
+ private fun get_float(key: Int): Float `{
+ GLfloat val;
+ glGetFloatv(key, &val);
+ return val;
+ `}
+
+ # Query the integer value at `key`
+ private fun get_int(key: Int): Int `{
+ GLint val;
+ glGetIntegerv(key, &val);
+ return val;
+ `}
+
+ # Does this driver support shader compilation?
+ #
+ # Should always return `true` in OpenGL ES 2.0 and 3.0.
+ fun shader_compiler: Bool do return get_bool(0x8DFA)
+
+ # Enable or disable writing into the depth buffer
+ fun depth_mask(value: Bool) `{ glDepthMask(value); `}
+
+ # Set the scale and units used to calculate depth values
+ fun polygon_offset(factor, units: Float) `{ glPolygonOffset(factor, units); `}
+
+ # Specify the width of rasterized lines
+ fun line_width(width: Float) `{ glLineWidth(width); `}
+
+ # Set the pixel arithmetic for the blending operations
+ #
+ # Defaultvalues before assignation:
+ # * `src_factor`: `GLBlendFactor::one`
+ # * `dst_factor`: `GLBlendFactor::zero`
+ fun blend_func(src_factor, dst_factor: GLBlendFactor) `{
+ glBlendFunc(src_factor, dst_factor);
+ `}
+
+ # Specify the value used for depth buffer comparisons
+ #
+ # Default value is `GLDepthFunc::less`
+ #
+ # Foreign: glDepthFunc
+ fun depth_func(func: GLDepthFunc) `{ glDepthFunc(func); `}
+
+ # Copy a block of pixels from the framebuffer of `fomat` and `typ` at `data`
+ #
+ # Foreign: glReadPixel
+ fun read_pixels(x, y, width, height: Int, format: GLPixelFormat, typ: GLPixelType, data: Pointer) `{
+ glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ `}
+
+ # Set the texture minifying function
+ #
+ # Foreign: glTexParameter with GL_TEXTURE_MIN_FILTER
+ fun tex_parameter_min_filter(target: GLTextureTarget, value: GLTextureMinFilter) `{
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, value);
+ `}
+
+ # Set the texture magnification function
+ #
+ # Foreign: glTexParameter with GL_TEXTURE_MAG_FILTER
+ fun tex_parameter_mag_filter(target: GLTextureTarget, value: GLTextureMagFilter) `{
+ glTexParameteri(target, GL_TEXTURE_MAG_FILTER, value);
+ `}
+
+ # Set the texture wrap parameter for coordinates _s_
+ #
+ # Foreign: glTexParameter with GL_TEXTURE_WRAP_S
+ fun tex_parameter_wrap_s(target: GLTextureTarget, value: GLTextureWrap) `{
+ glTexParameteri(target, GL_TEXTURE_WRAP_S, value);
+ `}
+
+ # Set the texture wrap parameter for coordinates _t_
+ #
+ # Foreign: glTexParameter with GL_TEXTURE_WRAP_T
+ fun tex_parameter_wrap_t(target: GLTextureTarget, value: GLTextureWrap) `{
+ glTexParameteri(target, GL_TEXTURE_WRAP_T, value);
+ `}
+
+ # Render primitives from array data
+ #
+ # Foreign: glDrawArrays
+ fun draw_arrays(mode: GLDrawMode, from, count: Int) `{ glDrawArrays(mode, from, count); `}
+
+ # OpenGL server-side capabilities
+ var capabilities = new GLCapabilities is lazy
+end
+
+# Entry point to OpenGL server-side capabilities
+class GLCapabilities
+
+ # GL capability: blend the computed fragment color values
+ #
+ # Foreign: GL_BLEND
+ fun blend: GLCap is lazy do return new GLCap(0x0BE2)
+
+ # GL capability: cull polygons based of their winding in window coordinates
+ #
+ # Foreign: GL_CULL_FACE
+ fun cull_face: GLCap is lazy do return new GLCap(0x0B44)
+
+ # GL capability: do depth comparisons and update the depth buffer
+ #
+ # Foreign: GL_DEPTH_TEST
+ fun depth_test: GLCap is lazy do return new GLCap(0x0B71)
+
+ # GL capability: dither color components or indices before they are written to the color buffer
+ #
+ # Foreign: GL_DITHER
+ fun dither: GLCap is lazy do return new GLCap(0x0BE2)
+
+ # GL capability: add an offset to depth values of a polygon fragment before depth test
+ #
+ # Foreign: GL_POLYGON_OFFSET_FILL
+ fun polygon_offset_fill: GLCap is lazy do return new GLCap(0x8037)
+
+ # GL capability: compute a temporary coverage value where each bit is determined by the alpha value at the corresponding location
+ #
+ # Foreign: GL_SAMPLE_ALPHA_TO_COVERAGE
+ fun sample_alpha_to_coverage: GLCap is lazy do return new GLCap(0x809E)
+
+ # GL capability: AND the fragment coverage with the temporary coverage value
+ #
+ # Foreign: GL_SAMPLE_COVERAGE
+ fun sample_coverage: GLCap is lazy do return new GLCap(0x80A0)
+
+ # GL capability: discard fragments that are outside the scissor rectangle
+ #
+ # Foreign: GL_SCISSOR_TEST
+ fun scissor_test: GLCap is lazy do return new GLCap(0x0C11)
+
+ # GL capability: do stencil testing and update the stencil buffer
+ #
+ # Foreign: GL_STENCIL_TEST
+ fun stencil_test: GLCap is lazy do return new GLCap(0x0B90)
+end
# Float related data types of OpenGL ES 2.0 shaders
#
# Only data types supported by shader attributes, as seen with
# `GLProgram::active_attrib_type`.
-extern class GLFloatDataType `{ GLenum `}
+extern class GLFloatDataType
+ super GLEnum
+
fun is_float: Bool `{ return recv == GL_FLOAT; `}
fun is_float_vec2: Bool `{ return recv == GL_FLOAT_VEC2; `}
fun is_float_vec3: Bool `{ return recv == GL_FLOAT_VEC3; `}
fun is_float_mat2: Bool `{ return recv == GL_FLOAT_MAT2; `}
fun is_float_mat3: Bool `{ return recv == GL_FLOAT_MAT3; `}
fun is_float_mat4: Bool `{ return recv == GL_FLOAT_MAT4; `}
+
+ # Instances of `GLFloatDataType` can be equal to instances of `GLDataType`
+ redef fun ==(o)
+ do
+ return o != null and o isa GLFloatDataType and o.hash == self.hash
+ end
end
# All data types of OpenGL ES 2.0 shaders
fun is_sampler_2d: Bool `{ return recv == GL_SAMPLER_2D; `}
fun is_sampler_cube: Bool `{ return recv == GL_SAMPLER_CUBE; `}
end
+
+# Kind of primitives to render with `GLES::draw_arrays`
+extern class GLDrawMode
+ super GLEnum
+
+ new points `{ return GL_POINTS; `}
+ new line_strip `{ return GL_LINE_STRIP; `}
+ new line_loop `{ return GL_LINE_LOOP; `}
+ new lines `{ return GL_LINES; `}
+ new triangle_strip `{ return GL_TRIANGLE_STRIP; `}
+ new triangle_fan `{ return GL_TRIANGLE_FAN; `}
+ new triangles `{ return GL_TRIANGLES; `}
+end
+
+# Pixel arithmetic for blending operations
+#
+# Used by `GLES::blend_func`
+extern class GLBlendFactor
+ super GLEnum
+
+ new zero `{ return GL_ZERO; `}
+ new one `{ return GL_ONE; `}
+ new src_color `{ return GL_SRC_COLOR; `}
+ new one_minus_src_color `{ return GL_ONE_MINUS_SRC_COLOR; `}
+ new dst_color `{ return GL_DST_COLOR; `}
+ new one_minus_dst_color `{ return GL_ONE_MINUS_DST_COLOR; `}
+ new src_alpha `{ return GL_SRC_ALPHA; `}
+ new one_minus_src_alpha `{ return GL_ONE_MINUS_SRC_ALPHA; `}
+ new dst_alpha `{ return GL_DST_ALPHA; `}
+ new one_minus_dst_alpha `{ return GL_ONE_MINUS_DST_ALPHA; `}
+ new constant_color `{ return GL_CONSTANT_COLOR; `}
+ new one_minus_constant_color `{ return GL_ONE_MINUS_CONSTANT_COLOR; `}
+ new constant_alpha `{ return GL_CONSTANT_ALPHA; `}
+ new one_minus_constant_alpha `{ return GL_ONE_MINUS_CONSTANT_ALPHA; `}
+
+ # Used for destination only
+ new src_alpha_saturate `{ return GL_SRC_ALPHA_SATURATE; `}
+end
+
+# Condition under which a pixel will be drawn
+#
+# Used by `GLES::depth_func`
+extern class GLDepthFunc
+ super GLEnum
+
+ new never `{ return GL_NEVER; `}
+ new less `{ return GL_LESS; `}
+ new equal `{ return GL_EQUAL; `}
+ new lequal `{ return GL_LEQUAL; `}
+ new greater `{ return GL_GREATER; `}
+ new not_equal `{ return GL_NOTEQUAL; `}
+ new gequal `{ return GL_GEQUAL; `}
+ new always `{ return GL_ALWAYS; `}
+end
+
+# Format of pixel data
+#
+# Used by `GLES::read_pixels`
+extern class GLPixelFormat
+ super GLEnum
+
+ new alpha `{ return GL_ALPHA; `}
+ new rgb `{ return GL_RGB; `}
+ new rgba `{ return GL_RGBA; `}
+end
+
+# Data type of pixel data
+#
+# Used by `GLES::read_pixels`
+extern class GLPixelType
+ super GLEnum
+
+ new unsigned_byte `{ return GL_UNSIGNED_BYTE; `}
+ new unsigned_short_5_6_5 `{ return GL_UNSIGNED_SHORT_5_6_5; `}
+ new unsigned_short_4_4_4_4 `{ return GL_UNSIGNED_SHORT_4_4_4_4; `}
+ new unsigned_short_5_5_5_1 `{ return GL_UNSIGNED_SHORT_5_5_5_1; `}
+end
+
+# Set of buffers as a bitwise OR mask, used by `GLES::clear`
+#
+# ~~~
+# var buffers = (new GLBuffer).color.depth
+# gl.clear buffers
+# ~~~
+extern class GLBuffer `{ GLbitfield `}
+ # Get an empty set of buffers
+ new `{ return 0; `}
+
+ # Add the color buffer to the returned buffer set
+ fun color: GLBuffer `{ return recv | GL_COLOR_BUFFER_BIT; `}
+
+ # Add the depth buffer to the returned buffer set
+ fun depth: GLBuffer `{ return recv | GL_DEPTH_BUFFER_BIT; `}
+
+ # Add the stencil buffer to the returned buffer set
+ fun stencil: GLBuffer `{ return recv | GL_STENCIL_BUFFER_BIT; `}
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Basic Java collections
+#
+# ~~~
+# var coll = new JavaArray(2)
+#
+# assert coll[0].is_java_null
+# coll[0] = "zero".to_java_string
+# coll[1] = "one".to_java_string
+#
+# assert coll.length == 2
+# assert coll.first.to_s == "zero"
+# assert coll[1].to_s == "one"
+# assert [for e in coll do e.to_s] == ["zero", "one"]
+# ~~~
+module collections
+
+import java
+
+# Java primitive array
+#
+# These have fixed size so they offer the same services as `SequenceRead` and
+# `[]=`, but would not support `Sequence::add`.
+extern class AbstractJavaArray[E: Object]
+ super SequenceRead[E]
+ super JavaObject
+
+ # Set the `value` at `key`
+ fun []=(key: Int, value: E) is abstract
+
+ redef fun iterator do return new JavaArrayIterator[E](self)
+
+ redef fun reverse_iterator do return new JavaArrayReverseIterator[E](self)
+end
+
+# Java primitive array `float[]`
+#
+# Note that Nit `Float` is the size of a double, so storing them in a
+# `JavaFloatArray` may lead to a loss of precision.
+extern class JavaFloatArray in "Java" `{ float[] `}
+ super AbstractJavaArray[Float]
+
+ # Get a new array of the given `size`
+ new(size: Int) in "Java" `{ return new float[(int)size]; `}
+
+ redef fun [](i) in "Java" `{ return (double)recv[(int)i]; `}
+
+ redef fun []=(i, e) in "Java" `{ recv[(int)i] = (float)e; `}
+
+ redef fun length in "Java" `{ return recv.length; `}
+end
+
+# Java primitive array `double[]`
+extern class JavaDoubleArray in "Java" `{ double[] `}
+ super AbstractJavaArray[Float]
+
+ # Get a new array of the given `size`
+ new(size: Int) in "Java" `{ return new double[(int)size]; `}
+
+ redef fun [](i) in "Java" `{ return recv[(int)i]; `}
+
+ redef fun []=(i, e) in "Java" `{ recv[(int)i] = (float)e; `}
+
+ redef fun length in "Java" `{ return recv.length; `}
+end
+
+# Java primitive array `Object[]`
+extern class JavaArray in "Java" `{ java.lang.Object[] `}
+ super AbstractJavaArray[JavaObject]
+
+ # Get a new array of the given `size`
+ new(size: Int) in "Java" `{ return new Object[(int)size]; `}
+
+ redef fun [](i) in "Java" `{ return recv[(int)i]; `}
+
+ redef fun []=(i, e) in "Java" `{ recv[(int)i] = e; `}
+
+ redef fun length in "Java" `{ return recv.length; `}
+end
+
+# TODO other primitive arrays:
+# * Java primitive array `byte[]`
+# * Java primitive array `short[]`
+# * Java primitive array `int[]`
+# * Java primitive array `long[]`
+# * Java primitive array `boolean[]`
+# * Java primitive array `char[]`
+
+# An `Iterator` on Java primitive arrays
+private class JavaArrayIterator[E: Object]
+ super IndexedIterator[E]
+
+ var array: AbstractJavaArray[E]
+
+ redef fun item do return array[index]
+
+ redef fun is_ok do return index < array.length
+
+ redef fun next do index += 1
+
+ redef var index = 0
+end
+
+# A reverse `Iterator` on Java primitive arrays
+private class JavaArrayReverseIterator[E: Object]
+ super IndexedIterator[E]
+
+ var array: AbstractJavaArray[E]
+
+ redef fun item do return array[index]
+
+ redef fun is_ok do return index >= 0
+
+ redef fun next do index -= 1
+
+ redef var index = array.length - 1
+end
EGLConfig mnit_config;
int32_t mnit_width;
int32_t mnit_height;
- float mnit_zoom;
struct mnit_opengles_Texture {
GLuint texture;
mnit_config = config;
mnit_width = w;
mnit_height = h;
- mnit_zoom = 1.0f;
LOGI("surface", (int)surface);
LOGI("display", (int)display);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(x, x+w, y+h, y, 0.0f, 1.0f);
- mnit_zoom = ((float)w)/mnit_width;
glMatrixMode(GL_MODELVIEW);
glFrontFace( GL_CW );
`}
# limitations under the License.
# Impements the services of `mnit:app` using the API from the Android ndk
-module android_app is
- android_manifest_activity """
+module android_app is android_manifest_activity """
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:configChanges="orientation|keyboardHidden"
- android:screenOrientation="portrait""""
-end
+"""
import mnit
import android
import mnit::opengles1
-
-in "C header" `{
- #include <jni.h>
- #include <errno.h>
- #include <android/log.h>
- #include <android_native_app_glue.h>
-
- #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "mnit", __VA_ARGS__))
- #ifdef DEBUG
- #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "mnit", __VA_ARGS__))
- #else
- #define LOGI(...) (void)0
- #endif
-`}
+intrude import ::android::input_events
in "C" `{
#include <EGL/egl.h>
- #include <GLES/gl.h>
- #define GL_GLEXT_PROTOTYPES 1
- #include <GLES/glext.h>
- #include <errno.h>
extern EGLDisplay mnit_display;
extern EGLSurface mnit_surface;
extern EGLConfig mnit_config;
extern int32_t mnit_width;
extern int32_t mnit_height;
- extern float mnit_zoom;
-
- //int mnit_orientation_changed;
- float mnit_zoom;
-
- /* Handle inputs from the Android platform and sort them before
- sending them in the Nit App */
- static int32_t mnit_handle_input(struct android_app* app, AInputEvent* event) {
- App nit_app = app->userData;
- LOGI("handle input %i", (int)pthread_self());
- if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) {
- LOGI("key");
- return App_extern_input_key(nit_app, event);
- }
- else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
- LOGI("motion");
- return App_extern_input_motion(nit_app, event);
- }
-
- return 0;
- }
`}
-
-extern class InnerAndroidMotionEvent in "C" `{AInputEvent *`}
- super Pointer
- private fun pointers_count: Int is extern `{
- return AMotionEvent_getPointerCount(recv);
- `}
- private fun just_went_down: Bool is extern `{
- return (AMotionEvent_getAction(recv) & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN;
- `}
- private fun edge: Int is extern `{
- return AMotionEvent_getEdgeFlags(recv);
- `}
- private fun index_down_pointer: Int is extern `{
- int a = AMotionEvent_getAction(recv);
- if ((a & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN)
- return (a & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
- else return -1;
- `}
-
- private fun action: AMotionEventAction `{ return AMotionEvent_getAction(recv); `}
-end
-
-extern class AMotionEventAction `{ int32_t `}
- protected fun action: Int `{ return recv & AMOTION_EVENT_ACTION_MASK; `}
- fun is_down: Bool do return action == 0
- fun is_up: Bool do return action == 1
- fun is_move: Bool do return action == 2
- fun is_cancel: Bool do return action == 3
- fun is_outside: Bool do return action == 4
- fun is_pointer_down: Bool do return action == 5
- fun is_pointer_up: Bool do return action == 6
-end
-
-interface AndroidInputEvent
- super InputEvent
-end
-
-class AndroidMotionEvent
- super AndroidInputEvent
- super MotionEvent
-
- private init(ie: InnerAndroidMotionEvent) do inner_event = ie
- private var inner_event: InnerAndroidMotionEvent
-
- private var pointers_cache: nullable Array[AndroidPointerEvent] = null
- fun pointers: Array[AndroidPointerEvent]
- do
- if pointers_cache != null then
- return pointers_cache.as(not null)
- else
- var pointers = new Array[AndroidPointerEvent]
- var pointers_count = inner_event.pointers_count
- for i in [0 .. pointers_count [do
- var pointer_event = new AndroidPointerEvent(self, i)
- pointers.add(pointer_event)
- end
- pointers_cache = pointers
- return pointers
- end
- end
-
- redef fun just_went_down: Bool do return inner_event.just_went_down
- fun edge: Int do return inner_event.edge
-
- redef fun down_pointer: nullable AndroidPointerEvent
- do
- var i = inner_event.index_down_pointer
- if i > 0 then
- return pointers[i]
- else
- return null
- end
- end
-end
-
-class AndroidPointerEvent
- super PointerEvent
- super AndroidInputEvent
-
- protected var motion_event: AndroidMotionEvent
- protected var pointer_id: Int
-
- redef fun x: Float do return extern_x(motion_event.inner_event, pointer_id)
- private fun extern_x(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
- return ((int) AMotionEvent_getX(motion_event, pointer_id));
- `}
-
- redef fun y: Float do return extern_y(motion_event.inner_event, pointer_id)
- private fun extern_y(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
- return ((int) AMotionEvent_getY(motion_event, pointer_id));
- `}
-
- fun pressure: Float do return extern_pressure(motion_event.inner_event, pointer_id)
- private fun extern_pressure(motion_event: InnerAndroidMotionEvent, pointer_id: Int): Float is extern `{
- return AMotionEvent_getPressure(motion_event, pointer_id);
- `}
-
- redef fun pressed
- do
- var action = motion_event.inner_event.action
- return action.is_down or action.is_move
- end
-
- redef fun depressed do return not pressed
-end
-
-extern class AndroidKeyEvent in "C" `{AInputEvent *`}
- super KeyEvent
- super AndroidInputEvent
-
- fun action: Int is extern `{
- return AKeyEvent_getAction(recv);
- `}
- redef fun is_down: Bool do return action == 0
- redef fun is_up: Bool do return action == 1
-
- fun key_code: Int is extern `{
- return AKeyEvent_getKeyCode(recv);
- `}
-
- redef fun to_c `{
- int code = AKeyEvent_getKeyCode(recv);
- if (code >= AKEYCODE_0 && code <= AKEYCODE_9)
- return '0'+code-AKEYCODE_0;
- if (code >= AKEYCODE_A && code <= AKEYCODE_Z)
- return 'a'+code-AKEYCODE_A;
- return 0;
- `}
-
- fun is_back_key: Bool do return key_code == 4
- fun is_menu_key: Bool do return key_code == 82
- fun is_search_key: Bool do return key_code == 84
-
- fun is_volume_up: Bool do return key_code == 24
- fun is_volume_down: Bool do return key_code == 25
-end
-
redef class App
redef type D: Opengles1Display
redef fun init_window
do
- set_as_input_handler native_app_glue
display = new Opengles1Display
super
end
- private fun set_as_input_handler(app_glue: NativeAppGlue) import extern_input_key, extern_input_motion `{
- app_glue->onInputEvent = mnit_handle_input;
- `}
-
redef fun full_frame do if not paused then super
- # these are used as a callback from native to type incoming events
- private fun extern_input_key(event: AndroidKeyEvent): Bool
+ redef fun generate_input do poll_looper 0
+
+ redef fun native_input_key(event)
do
return input(event)
end
- private fun extern_input_motion(event: InnerAndroidMotionEvent): Bool
+
+ redef fun native_input_motion(event)
do
var ie = new AndroidMotionEvent(event)
var handled = input(ie)
return handled
end
-
- redef fun generate_input do poll_looper 0
end
/* calls */
execvp(prog, arg);
- abort();
+ _exit(127);
}
else if (id > 0)
{ /* father */
self.realmainmodule = mainmodule
end
+ # Do the full code generation of the program `mainmodule`
+ # It is the main method usually called after the instantiation
+ fun do_compilation is abstract
+
# Force the creation of a new file
# The point is to avoid contamination between must-be-compiled-separately files
fun new_file(name: String): CodeFile
do
var externname
var at = self.get_single_annotation("extern", v.compiler.modelbuilder)
- if at != null then
+ if at != null and at.n_args.length == 1 then
externname = at.arg_as_string(v.compiler.modelbuilder)
if externname == null then return false
else
end
end
- ### copy resources (for android)
- # This will be accessed from `android_project_root`
- var res_dir
+ ### Copy resources and libs where expected by the SDK
+ var project_root
if compiler.mainmodule.location.file != null then
# it is a real file, use "{file}/../res"
- res_dir = "{compiler.mainmodule.location.file.filename.dirname}/../res"
+ project_root = "{compiler.mainmodule.location.file.filename.dirname}/.."
else
# probably used -m, use "."
- res_dir = "res"
+ project_root = "."
end
+
+ # Android resources folder
+ var res_dir = project_root / "res"
if res_dir.file_exists then
# copy the res folder to .nit_compile
res_dir = res_dir.realpath
- var target_res_dir = "{android_project_root}"
- toolcontext.exec_and_check(["cp", "-R", res_dir, target_res_dir], "Android project error")
+ toolcontext.exec_and_check(["cp", "-R", res_dir, android_project_root], "Android project error")
end
if not res_dir.file_exists or not "{res_dir}/values/strings.xml".file_exists then
<string name="app_name">{{{app_name}}}</string>
</resources>""".write_to_file "{dir}/res/values/strings.xml"
end
+
+ # Android libs folder
+ var libs_dir = project_root / "libs"
+ if libs_dir.file_exists then
+ toolcontext.exec_and_check(["cp", "-r", libs_dir, android_project_root], "Android project error")
+ end
end
redef fun write_makefile(compiler, compile_dir, cfiles)
self.toolcontext.info("*** GENERATING C ***", 1)
var compiler = new GlobalCompiler(mainmodule, self, runtime_type_analysis)
+ compiler.do_compilation
+ compiler.display_stats
+
+ var time1 = get_time
+ self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
+ write_and_make(compiler)
+ end
+end
+
+# Compiler that use global compilation and perform hard optimisations like:
+# * customization
+# * switch dispatch
+# * inlining
+class GlobalCompiler
+ super AbstractCompiler
+
+ redef type VISITOR: GlobalCompilerVisitor
+
+ # The result of the RTA (used to know live types and methods)
+ var runtime_type_analysis: RapidTypeAnalysis
+
+ init
+ do
+ var file = new_file("{mainmodule.c_name}.nitgg")
+ self.header = new CodeWriter(file)
+ self.live_primitive_types = new Array[MClassType]
+ for t in runtime_type_analysis.live_types do
+ if t.ctype != "val*" or t.mclass.name == "Pointer" then
+ self.live_primitive_types.add(t)
+ end
+ end
+ end
+
+ redef fun do_compilation
+ do
+ var compiler = self
+
compiler.compile_header
if mainmodule.model.get_mclasses_by_name("Pointer") != null then
# Compile until all runtime_functions are visited
while not compiler.todos.is_empty do
var m = compiler.todos.shift
- self.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
+ modelbuilder.toolcontext.info("Compile {m} ({compiler.seen.length-compiler.todos.length}/{compiler.seen.length})", 3)
m.compile_to_c(compiler)
end
- self.toolcontext.info("Total methods to compile to C: {compiler.seen.length}", 2)
-
- compiler.display_stats
-
- var time1 = get_time
- self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
- write_and_make(compiler)
- end
-end
-
-# Compiler that use global compilation and perform hard optimisations like:
-# * customization
-# * switch dispatch
-# * inlining
-class GlobalCompiler
- super AbstractCompiler
-
- redef type VISITOR: GlobalCompilerVisitor
-
- # The result of the RTA (used to know live types and methods)
- var runtime_type_analysis: RapidTypeAnalysis
+ modelbuilder.toolcontext.info("Total methods to compile to C: {compiler.seen.length}", 2)
- init
- do
- var file = new_file("{mainmodule.c_name}.nitgg")
- self.header = new CodeWriter(file)
- self.live_primitive_types = new Array[MClassType]
- for t in runtime_type_analysis.live_types do
- if t.ctype != "val*" or t.mclass.name == "Pointer" then
- self.live_primitive_types.add(t)
- end
- end
end
# Compile class names (for the class_name and output_class_name methods)
self.toolcontext.info("*** GENERATING C ***", 1)
var compiler = new SeparateCompiler(mainmodule, self, runtime_type_analysis)
+ compiler.do_compilation
+ compiler.display_stats
+
+ var time1 = get_time
+ self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
+ write_and_make(compiler)
+ end
+
+ # Count number of invocations by VFT
+ private var nb_invok_by_tables = 0
+ # Count number of invocations by direct call
+ private var nb_invok_by_direct = 0
+ # Count number of invocations by inlining
+ private var nb_invok_by_inline = 0
+end
+
+# Singleton that store the knowledge about the separate compilation process
+class SeparateCompiler
+ super AbstractCompiler
+
+ redef type VISITOR: SeparateCompilerVisitor
+
+ # The result of the RTA (used to know live types and methods)
+ var runtime_type_analysis: nullable RapidTypeAnalysis
+
+ private var undead_types: Set[MType] = new HashSet[MType]
+ private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
+
+ private var type_ids: Map[MType, Int] is noinit
+ private var type_colors: Map[MType, Int] is noinit
+ private var opentype_colors: Map[MType, Int] is noinit
+ protected var method_colors: Map[PropertyLayoutElement, Int] is noinit
+ protected var attr_colors: Map[MAttribute, Int] is noinit
+
+ init do
+ var file = new_file("nit.common")
+ self.header = new CodeWriter(file)
+ self.compile_box_kinds
+ end
+
+ redef fun do_compilation
+ do
+ var compiler = self
compiler.compile_header
var c_name = mainmodule.c_name
# compile class structures
- self.toolcontext.info("Property coloring", 2)
+ modelbuilder.toolcontext.info("Property coloring", 2)
compiler.new_file("{c_name}.classes")
compiler.do_property_coloring
for m in mainmodule.in_importation.greaters do
# compile methods
for m in mainmodule.in_importation.greaters do
- self.toolcontext.info("Generate C for module {m.full_name}", 2)
+ modelbuilder.toolcontext.info("Generate C for module {m.full_name}", 2)
compiler.new_file("{m.c_name}.sep")
compiler.compile_module_to_c(m)
end
# compile live & cast type structures
- self.toolcontext.info("Type coloring", 2)
+ modelbuilder.toolcontext.info("Type coloring", 2)
compiler.new_file("{c_name}.types")
+ compiler.compile_types
+ end
+
+ # Color and compile type structures and cast information
+ fun compile_types
+ do
+ var compiler = self
+
var mtypes = compiler.do_type_coloring
for t in mtypes do
compiler.compile_type_to_c(t)
compiler.compile_type_to_c(t)
end
- compiler.display_stats
-
- var time1 = get_time
- self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
- write_and_make(compiler)
- end
-
- # Count number of invocations by VFT
- private var nb_invok_by_tables = 0
- # Count number of invocations by direct call
- private var nb_invok_by_direct = 0
- # Count number of invocations by inlining
- private var nb_invok_by_inline = 0
-end
-
-# Singleton that store the knowledge about the separate compilation process
-class SeparateCompiler
- super AbstractCompiler
-
- redef type VISITOR: SeparateCompilerVisitor
-
- # The result of the RTA (used to know live types and methods)
- var runtime_type_analysis: nullable RapidTypeAnalysis
-
- private var undead_types: Set[MType] = new HashSet[MType]
- private var live_unresolved_types: Map[MClassDef, Set[MType]] = new HashMap[MClassDef, HashSet[MType]]
-
- private var type_ids: Map[MType, Int] is noinit
- private var type_colors: Map[MType, Int] is noinit
- private var opentype_colors: Map[MType, Int] is noinit
- protected var method_colors: Map[PropertyLayoutElement, Int] is noinit
- protected var attr_colors: Map[MAttribute, Int] is noinit
-
- init do
- var file = new_file("nit.common")
- self.header = new CodeWriter(file)
- self.compile_box_kinds
end
redef fun compile_header_structs do
self.toolcontext.info("*** GENERATING C ***", 1)
var compiler = new SeparateErasureCompiler(mainmodule, self, runtime_type_analysis)
- compiler.compile_header
-
- var c_name = mainmodule.c_name
-
- # compile class structures
- self.toolcontext.info("Property coloring", 2)
- compiler.new_file("{c_name}.tables")
- compiler.do_property_coloring
- for m in mainmodule.in_importation.greaters do
- for mclass in m.intro_mclasses do
- compiler.compile_class_to_c(mclass)
- end
- end
- compiler.compile_color_consts(compiler.vt_colors)
-
- # The main function of the C
- compiler.new_file("{c_name}.main")
- compiler.compile_nitni_global_ref_functions
- compiler.compile_main_function
-
- # compile methods
- for m in mainmodule.in_importation.greaters do
- self.toolcontext.info("Generate C for module {m.full_name}", 2)
- compiler.new_file("{m.c_name}.sep")
- compiler.compile_module_to_c(m)
- end
-
+ compiler.do_compilation
compiler.display_stats
-
var time1 = get_time
self.toolcontext.info("*** END GENERATING C: {time1-time0} ***", 2)
write_and_make(compiler)
self.header.add_decl("\};")
#Build BOX
- self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype});")
+ self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype_extern});")
v.add_decl("/* allocate {mtype} */")
v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
v.add("struct instance_{c_name}*res = nit_alloc(sizeof(struct instance_{c_name}));")
end
end
+ redef fun compile_types
+ do
+ compile_color_consts(vt_colors)
+ end
+
redef fun new_visitor do return new SeparateErasureCompilerVisitor(self)
# Stats
else break
end
+ # Change `float[]` to `[float`
+ if jni_type.has('[') then
+ var depth = jni_type.chars.count('[')
+ var java_type = jni_type.replace("[]", "")
+ var short
+
+ if java_type == "boolean" then
+ short = "Z"
+ else if java_type == "byte" then
+ short = "B"
+ else if java_type == "char" then
+ short = "C"
+ else if java_type == "short" then
+ short = "S"
+ else if java_type == "int" then
+ short = "I"
+ else if java_type == "long" then
+ short = "J"
+ else if java_type == "float" then
+ short = "F"
+ else if java_type == "double" then
+ short = "D"
+ else
+ short = "L{java_type};"
+ end
+
+ return "["*depth + short
+ end
+
return "L{jni_type};"
end
if mclass.name == "Bool" then return "Z"
redef fun jni_signature_alt
do
var ftype = mclass.ftype
+
if ftype isa ForeignJavaType then return "Object"
if mclass.name == "Bool" then return "Boolean"
if mclass.name == "Char" then return "Char"
var mmodule = nmodule.mmodule
assert mmodule != null
+ var source = nmodule.location.file
+
# If no decl block then quit
var nmoduledecl = nmodule.n_moduledecl
- if nmoduledecl == null then return
+ if nmoduledecl == null then
+ # Disable `missing-doc` if there is no `module` clause
+ # Rationale: the presence of a `module` clause is a good heuristic to
+ # discriminate quick and dirty prototypes from nice and clean modules
+ if source != null then toolcontext.warning_blacklist[source].add("missing-doc")
+ return
+ end
var modelbuilder = toolcontext.modelbuilder
- var source = nmodule.location.file
-
# Disable `missing-doc` for `test_suite`
if source != null and not nmoduledecl.get_annotations("test_suite").is_empty then
toolcontext.warning_blacklist[source].add("missing-doc")
end
-
# Get all the `no_warning` annotations
var name = "no_warning"
var annots = nmoduledecl.get_annotations(name)
return mmodules.to_a
end
+ # Load recursively all modules of the group `mgroup`.
+ # See `parse` for details.
+ fun parse_group(mgroup: MGroup): Array[MModule]
+ do
+ var res = new Array[MModule]
+ visit_group(mgroup)
+ for mg in mgroup.in_nesting.smallers do
+ for mp in mg.module_paths do
+ var nmodule = self.load_module(mp.filepath)
+ if nmodule == null then continue # Skip error
+ # Load imported module
+ build_module_importation(nmodule)
+
+ res.add(nmodule.mmodule.as(not null))
+ end
+ end
+ return res
+ end
+
+ # Load a bunch of modules and groups.
+ # Each name can be a module or a group.
+ # If it is a group then recursively all its modules are parsed.
+ # See `parse` for details.
+ fun parse_full(names: Sequence[String]): Array[MModule]
+ do
+ var time0 = get_time
+ # Parse and recursively load
+ self.toolcontext.info("*** PARSE ***", 1)
+ var mmodules = new ArraySet[MModule]
+ for a in names do
+ var mgroup = self.get_mgroup(a)
+ if mgroup != null then
+ mmodules.add_all parse_group(mgroup)
+ continue
+ end
+ var nmodule = self.load_module(a)
+ if nmodule == null then continue # Skip error
+ # Load imported module
+ build_module_importation(nmodule)
+
+ mmodules.add(nmodule.mmodule.as(not null))
+ end
+ var time1 = get_time
+ self.toolcontext.info("*** END PARSE: {time1-time0} ***", 2)
+
+ self.toolcontext.check_errors
+
+ if toolcontext.opt_only_parse.value then
+ self.toolcontext.info("*** ONLY PARSE...", 1)
+ exit(0)
+ end
+
+ return mmodules.to_a
+ end
+
# The list of directories to search for top level modules
# The list is initially set with:
#
# Retrieve the associated AST node of a mpropertydef.
# This method is used to associate model entity with syntactic entities.
#
- # If the property definition is not associated with a node, returns node.
+ # If the property definition is not associated with a node, returns `null`.
fun mpropdef2node(mpropdef: MPropDef): nullable ANode
do
- var res: nullable ANode = mpropdef2npropdef.get_or_null(mpropdef)
- if res != null then return res
+ var res
+ res = mpropdef2npropdef.get_or_null(mpropdef)
+ if res != null then
+ # Run the phases on it
+ toolcontext.run_phases_on_npropdef(res)
+ return res
+ end
if mpropdef isa MMethodDef and mpropdef.mproperty.is_root_init then
res = mclassdef2nclassdef.get_or_null(mpropdef.mclassdef)
if res != null then return res
if n == null then return res
for npropdef in n.n_propdefs do
if npropdef isa AAttrPropdef then
+ # Run the phases on it
+ toolcontext.run_phases_on_npropdef(npropdef)
res.add(npropdef)
end
end
# build model
var model = new Model
var mbuilder = new ModelBuilder(model, toolcontext)
-var mmodules = mbuilder.parse(arguments)
+var mmodules = mbuilder.parse_full(arguments)
if mmodules.is_empty then return
mbuilder.run_phases
var args = toolcontext.option_context.rest
-var mmodules = modelbuilder.parse(args)
+var mmodules = modelbuilder.parse_full(args)
modelbuilder.run_phases
if opt_full.value then mmodules = model.mmodules
var modelbuilder = new ModelBuilder(model, toolcontext)
# Here we load an process all modules passed on the command line
-var mmodules = modelbuilder.parse(arguments)
+var mmodules = modelbuilder.parse_full(arguments)
modelbuilder.run_phases
print "*** METRICS ***"
var modelbuilder = new ModelBuilder(model, toolcontext)
# Here we load an process all modules passed on the command line
-var mmodules = modelbuilder.parse(arguments)
+var mmodules = modelbuilder.parse_full(arguments)
toolcontext.mmodules_to_check.add_all mmodules
modelbuilder.run_phases
var model = new Model
var modelbuilder = new ModelBuilder(model, toolcontext)
-var mmodules = modelbuilder.parse(arguments)
+var mmodules = modelbuilder.parse_full(arguments)
modelbuilder.run_phases
# Create a distinct support module per targetted modules
# build model
var model = new Model
var mbuilder = new ModelBuilder(model, toolcontext)
-var mmodules = mbuilder.parse(arguments)
+var mmodules = mbuilder.parse_full(arguments)
if mmodules.is_empty then return
mbuilder.run_phases
var model = new Model
var modelbuilder = new ModelBuilder(model, toolcontext)
-var mmodules = modelbuilder.parse(args)
+var mmodules = modelbuilder.parse_full(args)
modelbuilder.run_phases
if toolcontext.opt_gen_unit.value then
# --disable-phase
var opt_disable_phase = new OptionArray("DEBUG: Disable a specific phase; use `list` to get the list.", "--disable-phase")
+ # --disable-phase
+ var opt_sloppy = new OptionBool("DEBUG: force lazy semantic analysis of the source-code", "--sloppy")
+
redef init
do
super
- option_context.add_option(opt_disable_phase)
+ option_context.add_option(opt_disable_phase, opt_sloppy)
end
redef fun process_options(args)
end
if not found then fatal_error(null, "Error: no phase named `{v}`. Use `list` to list all phases.")
end
+
+ if opt_sloppy.value then semantize_is_lazy = true
end
# The list of registered phases in the application order.
- fun phases_list: Sequence[Phase]
- do
+ var phases_list: Sequence[Phase] is lazy do
var phases = self.phases.to_a
self.phases.sort(phases)
return phases
end
+ # Is `phase_process_npropdef` not called automatically by `run_phases`?
+ #
+ # When set to true, it is the responsibility of the tools
+ #
+ # Is false by default.
+ var semantize_is_lazy = false is writable
+
# Set of already analyzed modules.
private var phased_modules = new HashSet[AModule]
for nclassdef in nmodule.n_classdefs do
assert phase.toolcontext == self
phase.process_nclassdef(nclassdef)
- for npropdef in nclassdef.n_propdefs do
+ if not semantize_is_lazy then for npropdef in nclassdef.n_propdefs do
assert phase.toolcontext == self
phase_process_npropdef(phase, npropdef)
end
do
phase.process_npropdef(npropdef)
end
+
+ # Run the phase on the given npropdef.
+ # Does nothing if `semantize_is_lazy` is false.
+ fun run_phases_on_npropdef(npropdef: APropdef)
+ do
+ if not semantize_is_lazy then return
+ if npropdef.is_phased then return
+ npropdef.is_phased = true
+
+ #self.info("Semantic analysis of property {npropdef.location.file.filename}", 0)
+
+ var phases = phases_list
+ for phase in phases do
+ if phase.disabled then continue
+ assert phase.toolcontext == self
+ phase_process_npropdef(phase, npropdef)
+ self.check_errors
+ end
+ end
+end
+
+redef class APropdef
+ # Is the propdef already analyzed by `run_phases_on_npropdef`.
+ # Unused unless `semantize_is_lazy` is true.
+ private var is_phased = false
end
# Collect all annotation
if mtype == null then
mtype = v.merge_types(self, mtypes)
end
- if mtype == null then
+ if mtype == null or mtype isa MNullType then
v.error(self, "Type Error: ambiguous array type {mtypes.join(" ")}")
return
end
end
#alt1# var b = [10, true]
+#alt2# var c = [null, null]
--- /dev/null
+alt/base_array_alt2.nit:28,9--20: Type Error: ambiguous array type null null
-Caught signal : Aborted
alt/error_annot_c_compiler_alt5.nit:21,57--79: Annotation error: Something went wrong executing the argument of annotation "c_compiler_option", make sure the command is valid.
A hello world!
+0
+
+B hello world!0
+
C hello world!
-B hello world!D hello world!
\ No newline at end of file
+0
+
+D hello world!0
+
+E
+1
+
+127
var hw = new Process("echo", "A", "hello", "world!")
hw.wait
+print hw.status
+
+print ""
var ip = new IProcess("echo", "B hello world!")
ip.read_line.output
ip.wait
+print ip.status
+
+print ""
var op = new OProcess.from_a("cat", null)
op.write("C hello world!\n")
op.close
op.wait
+print op.status
+
+print ""
var iop = new IOProcess.from_a("cat", null)
iop.write("D hello world!\n")
iop.read_line.output
iop.close
iop.wait
+print iop.status
+
+print ""
+
+var e1 = new Process("sh", "-c", "echo E; exit 1")
+e1.wait
+print e1.status
+
+print ""
+var ioperr = new IOProcess.from_a("bad command", null)
+ioperr.write("D hello world!\n")
+ioperr.read_line.output
+ioperr.close
+ioperr.wait
+print ioperr.status