convert -resize 96x96 art/icon.png res/drawable-xhdpi/icon.png
convert -resize 144x144 art/icon.png res/drawable-xxhdpi/icon.png
convert -resize 192x192 art/icon.png res/drawable-xxxhdpi/icon.png
+
+bin/model_viewer_vr.apk: $(shell ${NITLS} -M src/model_viewer.nit android) ${NITC} res/drawable-hdpi/icon.png libs/cardboard.jar
+ ${NITC} src/model_viewer.nit -m android -m ../../lib/gamnit/depth/vr.nit -o $@
+
+libs/cardboard.jar:
+ curl --progress-bar -o libs/cardboard.jar \
+ https://raw.githubusercontent.com/googlesamples/cardboard-java/master/CardboardSample/libs/cardboard.jar
Sample portable 3D app implemented with the gamnit depth framework
+This application uses the _depth_ framework to load and display 3D models.
+It also applies the _flat_ framework to display the static UI elements (like the "Next model" label).
+
+The pretty earth model (`GlobeModel`) is implemented by a material with a custom graphical program.
+It renders the earth with an displaced surface, a cloud layer, city lights and Phong lighting effects on the water.
+
+# Variations
+
+* The standard application is compiled to a desktop executable at `bin/model_viewer` and an Android package at `bin/model_viewer.apk`.
+* The virtual reality variant `bin/model_viewer_vr.apk` targets Android and uses Google Cardboard for head tracking.
+
# Art
* 3D models `Tree_01` and `Oak_Fall_01` were created by Kenney.nl and published under CC0.
* 3D model `Quandtum_BA-2_v1_1` was created by Quandtum and published under CC0.
* Some textures on the `Quandtum_BA-2_v1_1` model have been created with images from goodtextures.com.
These images can be used in free softwares, some restrictions still applies for modifications and other uses.
+* Globe textures credit: NASA, Visible Earth
--- /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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="744.09448819"
+ height="1052.3622047"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="next-prev-model.svg">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow2Lend"
+ style="overflow:visible;">
+ <path
+ id="path3798"
+ style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
+ transform="scale(1.1) rotate(180) translate(1,0)" />
+ </marker>
+ </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="475.81167"
+ inkscape:cy="821.81226"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="2558"
+ inkscape:window-height="1379"
+ inkscape:window-x="2560"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ showguides="true"
+ inkscape:guide-bbox="true" />
+ <metadata
+ id="metadata7">
+ <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></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ id="0next"
+ inkscape:label="#g4700"
+ transform="matrix(2.0963119,0,0,2.0963119,-813.43954,-216.81189)"
+ inkscape:export-filename="/home/xymus/Downloads/next.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <g
+ style="fill:#000000"
+ id="g4593">
+ <path
+ style="fill:#000000;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="m 656,188.90625 c -4.32878,5.37465 3.34038,10.18188 3.40625,15.71875 2.11338,8.14548 -1.48782,16.2744 -4.84474,23.31198 0.88119,5.68482 8.54841,3.67576 11.96974,1.43802 14.12986,-6.05994 29.36922,-9.67603 43.15625,-16.65625 3.09218,-4.66997 -4.21022,-8.11493 -8.09375,-8.84375 -14.77463,-4.36086 -28.82072,-11.74328 -43.96875,-15.28125 L 656.64299,188.7826 656,188.90625 z"
+ id="path4368"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 451.9375,188.75 c -5.34509,0.008 -7.99849,5.96579 -6.5,10.59375 -2.09613,-4.05624 -3.52928,-10.07737 -9.15625,-10.1875 -3.25871,0.18236 -10.20635,-1.84089 -9.15625,3 0,11.41667 0,22.83333 0,34.25 5.19971,1.80199 13.79841,1.01116 13.96875,-6.03125 0.0985,-2.71165 -0.65681,-5.2049 1.1875,-1.28125 0.95441,5.53108 6.4523,8.77 11.875,7.8125 7.80009,1.72283 4.14251,-7.33165 4.9375,-12.1875 0,-8.41667 0,-16.83333 0,-25.25 -2.38217,-0.41148 -4.72323,-0.9443 -7.15625,-0.71875 z"
+ id="path4306"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 470.1875,196.0625 c -12.64808,-0.34066 -20.11359,17.60573 -10.75,26.3125 8.0188,9.16453 26.01035,4.48792 26.9375,-8.09375 0.99174,-9.39292 -6.03753,-19.20046 -16.1875,-18.21875 z"
+ id="path4308"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 501.21875,196.3125 c -3.06208,-0.84258 -4.55021,2.38155 -6.46875,3.09375 -3.60528,-3.57788 -9.01254,-3.18847 -13.78125,-2.6875 -4.31554,2.98948 1.80217,7.05639 3.125,9.9375 2.32397,2.54568 3.39397,7.04813 -0.375,9 -2.90112,2.4991 -7.19482,9.00555 -1.65625,11.09375 4.68687,1.15044 10.36095,-0.12207 13.1875,-3.96875 0.63175,4.0438 3.24534,4.04893 6.78125,3.9375 3.18505,0.59869 10.28931,0.56244 8.5625,-4.46875 -2.26088,-4.29397 -8.73602,-8.18074 -7.03125,-13.53125 2.8755,-2.71034 8.79074,-8.79581 3.1875,-11.875 -1.74801,-0.66881 -3.67873,-0.64433 -5.53125,-0.53125 z"
+ id="path4310"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 513.78125,189.21875 c -3.33439,-0.75172 -10.33032,-0.65853 -8.65625,4.65625 -0.17239,4.73607 -5.5168,9.38156 -1.75,14.125 5.1229,4.49173 -1.633,13.36405 3.15625,17.75 5.21197,3.74978 14.2168,-0.4073 12.375,-7.34375 -1.90033,-4.01966 -1.1284,-8.16273 1.65625,-11.5 2.77063,-5.04265 -1.77316,-10.1534 -3.25,-14.96875 -0.87015,-1.02399 -1.78424,-3.96455 -3.53125,-2.71875 z"
+ id="path4312"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 541.34375,196.0625 c -4.51875,0.9964 -9.26842,0.30548 -13.90625,0.5 0,9.92708 0,19.85417 0,29.78125 5.13396,1.96096 13.57717,1.03604 13.78125,-5.90625 -1.81001,8.33947 12.68142,8.90492 14,1.40625 -0.42099,3.09677 0.48653,5.58173 4,5.21875 5.40653,1.4676 11.17404,-3.02327 9.90625,-8.78125 -0.45179,-7.2473 0.77332,-17.36508 -7.28125,-21.03125 -4.16728,-1.88732 -9.44992,-1.43054 -13.28125,0.53125 -2.1367,-1.34503 -4.71152,-1.89845 -7.21875,-1.71875 z m -0.1875,13.09375 c 1.01687,3.52054 0.14248,7.35414 0.0625,11.03125 0.1247,-3.44655 -1.45369,-8.40998 -0.0625,-11.03125 z M 555.09375,209 c 0.70347,2.88457 0.38291,7.67655 0.1875,9.40625 -0.81188,-2.93279 -1.20072,-6.55095 -0.1875,-9.40625 z"
+ id="path4314"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 579.0625,196.0625 c -12.68715,-0.2598 -20.18845,17.60259 -10.71875,26.34375 11.3117,13.0977 34.85871,-2.7399 25.40625,-18.03125 -2.76217,-5.26347 -8.69083,-8.82111 -14.6875,-8.3125 z m 0.90625,12.875 c 4.01822,0.26803 1.85946,7.85333 -1.71875,4.78125 -1.56836,-1.57678 -0.79054,-4.96738 1.71875,-4.78125 z"
+ id="path4316"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 618.5,189.21875 c -3.55137,0.0451 -11.28032,-1.87634 -10.8125,4.125 0.43375,2.36323 0.51137,3.57824 -2.0625,2.40625 -13.14309,-1.26298 -21.17669,16.91961 -12.21875,26.25 4.0564,5.1833 11.47205,6.13633 17.21875,4.4375 5.46388,2.80037 12.18721,-2.12647 10.9375,-8.21875 -1.31434,-9.72996 -0.19193,-19.77143 -0.5625,-29.625 -0.83333,0.20833 -1.66667,0.41667 -2.5,0.625 z m -13,19.4375 c 4.33286,-0.20831 2.30424,8.15282 -1.46875,5.125 -1.679,-1.39982 -1.18008,-5.30155 1.46875,-5.125 z"
+ id="path4318"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 631.0625,196.0625 c -12.42272,-0.34784 -19.99093,17.04802 -11.125,25.875 7.69336,9.79997 26.70839,5.09691 27.28125,-7.9375 0.93983,-9.40212 -6.13947,-18.79793 -16.15625,-17.9375 z m 1.84375,9.25 c -3.76495,-1.48752 -3.33258,5.1691 0.1875,3.75 0.90612,-0.24028 0.54495,-3.3012 -0.1875,-3.75 z"
+ id="path4320"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 653.5,189.21875 c -3.5107,0.13642 -11.08255,-1.95561 -10.84375,3.9375 0,11.0625 0,22.125 0,33.1875 5.17254,1.98449 13.72774,1.02119 13.8125,-6.03125 -0.85413,-10.49846 -0.32956,-21.14442 -0.46875,-31.71875 -0.83333,0.20833 -1.66667,0.41667 -2.5,0.625 z"
+ id="path4322"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="fill:#ffffff"
+ id="g4566">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4239"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 431.13342,222.72359 5.48,0 0,-21.48 12.36,21.48 6.12,0 0,-29.56 -5.48,0 0,21.52 -12.24,-21.52 -6.24,0 0,29.56" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4241"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 482.1428,214.00359 c 0.16,-0.76 0.2,-1.24 0.2,-2.04 0,-6.88 -4.84001,-11.92 -11.44,-11.92 -6.52,0 -11.68,5.16 -11.68,11.68 0,6.47999 5.24,11.52 12,11.52 3.63999,0 6.48,-1.32001 8.8,-4 0.84,-1.04 1.4,-1.96 1.76,-3.08 l -5.8,0 c -1.36,1.6 -2.68001,2.2 -4.88,2.2 -3.16,0 -5.48,-1.68001 -6.12,-4.36 l 17.16,0 m -17.32,-4.68 c 0.84,-2.84 3,-4.4 6.16,-4.4 3.27999,0 5.44,1.56 6.12,4.4 l -12.28,0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4243"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 483.6878,222.72359 6.4,0 4.64,-7.6 4.64,7.6 6.4,0 -7.88,-11.44 6.76,-10.72 -6,0 -3.92,6.68 -4,-6.68 -6,0 6.8,10.72 -7.84,11.44" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4245"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 509.02967,222.72359 5.32,0 0,-17.32 3.2,0 0,-4.84 -3.2,0 0,-7.4 -5.32,0 0,7.4 -2.6,0 0,4.84 2.6,0 0,17.32" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4247"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 531.4328,222.72359 5.32,0 0,-10.92 c 0,-2.2 0.2,-3.68 0.56,-4.6 0.64,-1.44 2,-2.28 3.76,-2.28 1.44,0 2.68,0.52 3.4,1.4 0.64,0.84 0.92,2.16 0.92,4.24 l 0,12.16 5.32,0 0,-10.92 c 0,-2.48 0.2,-3.72 0.76,-4.76 0.68,-1.36 2.04,-2.12 3.72,-2.12 1.32,0 2.44,0.48 3.16,1.36 0.72,0.84 1,2.08 1,4.28 l 0,12.16 5.32,0 0,-12.8 c 0,-2.68 -0.48,-4.84 -1.44,-6.36 -1.4,-2.24 -4.20001,-3.52 -7.52,-3.52 -3.12,0 -5.32001,1.04 -7.12,3.44 -1.52,-2.4 -3.48001,-3.44 -6.52,-3.44 -2.6,0 -4.2,0.72 -5.76,2.6 l 0,-2.08 -4.88,0 0,22.16" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4249"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 579.77092,200.04359 c -6.43999,0 -11.72,5.24 -11.72,11.6 0,6.39999 5.28001,11.6 11.76,11.6 6.44,0 11.8,-5.20001 11.8,-11.44 0,-6.6 -5.16001,-11.76 -11.84,-11.76 m 0.04,4.88 c 3.56,0 6.44,3.04 6.44,6.72 0,3.71999 -2.88,6.72 -6.4,6.72 -3.59999,0 -6.44,-3.00001 -6.44,-6.8 0,-3.64 2.92001,-6.64 6.4,-6.64" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4251"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 616.99592,193.16359 -5.32,0 0,9.36 c -1.56,-1.72 -4.12,-2.76 -6.92,-2.76 -6.19999,0 -11.08,5.2 -11.08,11.84 0,6.55999 4.84001,11.64 11.12,11.64 3,0 5.2,-1.00001 7.32,-3.4 l 0,2.88 4.88,0 0,-29.56 m -11.48,11.48 c 3.72,0 6.56,3 6.56,6.88 0,3.83999 -2.84,6.84 -6.44,6.84 -3.71999,0 -6.6,-3.08001 -6.6,-7 0,-3.76 2.84001,-6.72 6.48,-6.72" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4253"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 643.00217,214.00359 c 0.16,-0.76 0.2,-1.24 0.2,-2.04 0,-6.88 -4.84,-11.92 -11.44,-11.92 -6.51999,0 -11.68,5.16 -11.68,11.68 0,6.47999 5.24001,11.52 12,11.52 3.64,0 6.48,-1.32001 8.8,-4 0.84,-1.04 1.4,-1.96 1.76,-3.08 l -5.8,0 c -1.36,1.6 -2.68,2.2 -4.88,2.2 -3.16,0 -5.48,-1.68001 -6.12,-4.36 l 17.16,0 m -17.32,-4.68 c 0.84,-2.84 3,-4.4 6.16,-4.4 3.28,0 5.44,1.56 6.12,4.4 l -12.28,0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4255"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 646.66717,222.72359 5.32,0 0,-29.56 -5.32,0 0,29.56" />
+ <g
+ id="g4650">
+ <path
+ inkscape:connector-curvature="0"
+ id="path3003"
+ d="m 676.09375,208.28125 0,4.03125 25.40625,0 0,-4.03125 -25.40625,0 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.05724525;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4656"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="m 658.13707,192.29293 48.76186,17.93097 -48.76187,17.93097 c 7.79011,-10.58644 7.74522,-25.07052 10e-6,-35.86194 z" />
+ </g>
+ </g>
+ </g>
+ <g
+ id="0prev"
+ inkscape:label="#g4666"
+ inkscape:export-filename="/home/xymus/Downloads/prev.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ transform="matrix(2.0963119,0,0,2.0963119,-87.104484,-388.33708)">
+ <g
+ style="fill:#000000"
+ id="g4605">
+ <path
+ style="fill:#000000;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="m 93.03125,188.90625 c -6.672841,1.5995 -12.604304,5.44802 -19.351519,7.03986 -9.962295,4.08128 -20.797763,6.80119 -30.210981,11.74139 -3.185255,5.30141 3.906347,8.54538 8.153116,9.00997 14.54548,4.65727 28.641598,11.70524 43.659384,15.30253 5.95503,-1.61287 1.419816,-8.86058 -0.71875,-12 -3.30648,-8.69739 -1.325001,-18.75649 3.71875,-26.34375 0.871021,-3.03836 -2.624351,-5.10497 -5.25,-4.75 z"
+ id="path4360"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 94.78125,191.15625 c 0,11.75 0,23.5 0,35.25 5.199709,1.80199 13.79841,1.01116 13.96875,-6.03125 0.73785,-2.0285 -2.2096,-6.16156 1.6875,-5.15625 10.13737,-0.0717 14.44247,-13.62233 8.65625,-21 -5.45932,-7.76372 -16.32167,-4.22406 -24.3125,-5.09375 0,0.67708 0,1.35417 0,2.03125 z"
+ id="path4324"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 130.5,195.84375 c -4.47817,1.15007 -9.21902,0.63554 -13.84375,0.6875 0,9.9375 0,19.875 0,29.8125 5.13396,1.96096 13.57717,1.03604 13.78125,-5.90625 0.40744,-3.56077 -2.00329,-8.76162 0.28125,-11.40625 4.9013,0.27685 4.85349,-7.16544 3.6875,-10.84375 -0.57967,-1.52305 -2.25227,-2.63172 -3.90625,-2.34375 z"
+ id="path4326"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="M 143.84375,196.03125 C 131.29559,195.39471 123.3737,212.99969 132.375,222 c 7.74413,9.50241 26.10134,5.23632 27.21875,-7.5 1.46522,-9.18478 -6.03486,-19.22017 -15.75,-18.46875 z"
+ id="path4328"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 176.21875,196.34375 c -3.56118,-0.0722 -7.36531,1.85845 -8.4375,5.40625 -0.53483,-3.8326 -4.08839,-6.2915 -7.65625,-5.0625 -3.03486,-0.93228 -9.63906,-0.47023 -7.5625,4.28125 4.45743,8.06732 6.41912,18.39383 11.4375,25.65625 5.69264,2.56918 11.28354,-2.36473 12.25,-7.90625 2.52212,-7.43896 5.81803,-14.60939 8.65625,-21.9375 -2.89275,-0.19539 -5.78232,-0.60468 -8.6875,-0.4375 z"
+ id="path4330"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 188.34375,189.21875 c -3.5107,0.13642 -11.08255,-1.95561 -10.84375,3.9375 0,11.0625 0,22.125 0,33.1875 5.17254,1.98449 13.72774,1.02119 13.8125,-6.03125 -0.85413,-10.49846 -0.32956,-21.14442 -0.46875,-31.71875 -0.83333,0.20833 -1.66667,0.41667 -2.5,0.625 z"
+ id="path4332"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 201.1875,196.0625 c -12.69297,-0.27971 -20.18387,17.60578 -10.75,26.34375 8.33738,9.52576 26.52717,3.73426 27.25,-9.03125 1.17854,-9.18651 -7.18577,-18.17636 -16.5,-17.3125 z m 0.875,12.875 c 4.55645,0.381 1.07641,8.56275 -2.09375,4.28125 -0.9976,-1.64086 -0.15837,-4.46179 2.09375,-4.28125 z"
+ id="path4334"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 233.75,196.03125 c -4.81989,-0.42567 -7.81764,4.16091 -6.8125,8.59375 -0.0779,3.04011 1.21947,7.20274 -0.1875,9.625 -1.74567,-1.30416 -0.30176,-6.13336 -0.5625,-8.53125 0.23061,-3.58321 0.0464,-10.31908 -4.84375,-9 -3.18683,-0.77679 -9.36318,-0.83945 -8.59375,4.03125 0.57984,8.2257 -2.53038,19.36453 5.8125,24.6875 5.63017,3.57116 12.46231,0.43796 18.53125,1.0625 6.33372,-2.68182 2.60959,-11.04236 3.125,-16.15625 0.95881,-5.34847 1.62363,-14.9854 -6.46875,-14.3125 z"
+ id="path4336"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 245.53125,196.09375 c -7.55584,0.65612 -11.50164,10.28973 -8.1875,16.125 -4.72943,2.09654 -1.32143,7.88385 0.59375,10.875 6.12857,7.46668 20.7748,4.10946 21.40625,-6.125 1.03821,-2.70123 -1.80871,-5.51051 -1.09375,-7.625 2.9228,-7.47873 -5.48162,-14.59712 -12.71875,-13.25 z"
+ id="path4338"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 292.1875,196 c -3.17064,-0.0125 -5.54316,3.46156 -8.1875,0.46875 -6.02876,-1.14078 -12.35065,0.93994 -18.53125,0.0937 0,9.92708 0,19.85417 0,29.78125 4.60888,1.94997 12.12496,0.77468 13.46875,-3.65625 1.83044,6.9394 15.2086,5.76758 14,-2.125 -0.0462,-1.89173 0.26329,3.85684 2.09375,4.78125 3.76518,3.31061 11.9811,2.47436 11.71875,-3.625 -0.19537,-6.00494 0.69952,-12.27863 -0.875,-18.09375 -2.25403,-5.2589 -8.10856,-8.20536 -13.6875,-7.625 z m -13,12.90625 c 1.1987,2.90344 -0.19863,6.21519 0.0625,9.28125 -0.3425,-2.92895 -1.09356,-6.57759 -0.0625,-9.28125 z m 14.09375,0.0625 c 0.62659,3.29448 -0.0508,6.7046 -0.3125,10 0.0889,-3.28543 -1.26563,-7.00095 0.3125,-10 z m -14,9.65625 c 0.17144,1.67745 -0.0842,-0.2242 0,0 z"
+ id="path4340"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 317.125,196.0625 c -12.69297,-0.27971 -20.18387,17.60578 -10.75,26.34375 8.33738,9.52576 26.52717,3.73426 27.25,-9.03125 1.17854,-9.18651 -7.18577,-18.17636 -16.5,-17.3125 z m 0.875,12.875 c 4.55645,0.381 1.07641,8.56275 -2.09375,4.28125 -0.9976,-1.64086 -0.15837,-4.46179 2.09375,-4.28125 z"
+ id="path4342"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 356.53125,189.21875 c -3.66512,-0.0965 -11.6229,-1.76238 -10.8125,4.46875 1.26863,4.08017 -3.49927,1.02615 -5.78125,2.25 -11.5878,2.30296 -16.50311,18.59696 -7.875,26.78125 4.21779,4.55956 11.08624,5.32421 16.59375,3.71875 5.46388,2.80037 12.18721,-2.12647 10.9375,-8.21875 -1.31434,-9.72996 -0.19193,-19.77143 -0.5625,-29.625 -0.83333,0.20833 -1.66667,0.41667 -2.5,0.625 z m -12.84375,19.4375 c 4.57248,0.35151 1.71186,8.45181 -1.84375,4.90625 -1.3651,-1.60613 -0.77522,-5.19193 1.84375,-4.90625 z"
+ id="path4344"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="M 369.46875,196.03125 C 356.92059,195.39471 348.9987,212.99969 358,222 c 7.74413,9.50241 26.10134,5.23632 27.21875,-7.5 1.46522,-9.18478 -6.03486,-19.22017 -15.75,-18.46875 z"
+ id="path4346"
+ inkscape:connector-curvature="0" />
+ <path
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 391.53125,189.21875 c -3.55206,0.0423 -11.28168,-1.87282 -10.8125,4.125 0,11 0,22 0,33 5.13396,1.96096 13.57717,1.03604 13.78125,-5.90625 -0.82876,-10.54724 -0.34724,-21.22452 -0.46875,-31.84375 -0.83333,0.20833 -1.66667,0.41667 -2.5,0.625 z"
+ id="path4348"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="fill:#ffffff"
+ transform="translate(0,40)"
+ id="g4634">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4258"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 98.793227,182.72359 5.480003,0 0,-11.24 1.76,0 c 4.19999,0 6.12,-0.32 7.76,-1.32 2.39999,-1.48 3.88,-4.48001 3.88,-7.88 0,-3.4 -1.44001,-6.2 -4,-7.76 -1.68,-1 -3.64001,-1.36 -7.56,-1.36 l -7.320003,0 0,29.56 m 5.480003,-16.48 0,-7.84 1.84,0 c 1.8,0 2.6,0.08 3.48,0.28 1.6,0.44 2.56,1.84 2.56,3.68 0,1.44 -0.64,2.56 -1.8,3.2 -0.84,0.44 -2.36001,0.68 -4.48,0.68 l -1.6,0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4260"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 120.6551,182.72359 5.32,0 0,-12.32 c 0,-3.44 1.56001,-5.16 4.76,-5.24 l 0,-5.12 -0.4,0 c -2.28,0 -3.4,0.64 -4.8,2.68 l 0,-2.16 -4.88,0 0,22.16" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4262"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 155.4276,174.00359 c 0.16,-0.76 0.2,-1.24 0.2,-2.04 0,-6.88 -4.84,-11.92 -11.44,-11.92 -6.51999,0 -11.68,5.16 -11.68,11.68 0,6.47999 5.24001,11.52 12,11.52 3.64,0 6.48,-1.32001 8.8,-4 0.84,-1.04 1.4,-1.96 1.76,-3.08 l -5.8,0 c -1.36,1.6 -2.68,2.2 -4.88,2.2 -3.15999,0 -5.48,-1.68001 -6.12,-4.36 l 17.16,0 m -17.32,-4.68 c 0.84,-2.84 3.00001,-4.4 6.16,-4.4 3.28,0 5.44,1.56 6.12,4.4 l -12.28,0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4264"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 165.8926,182.72359 4.24,0 8.92,-22.16 -6,0 -5.04,14.68 -5.12,-14.68 -5.92,0 8.92,22.16" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4266"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 181.51448,182.72359 5.32,0 0,-22.16 -5.32,0 0,22.16 m 0,-24.56 5.32,0 0,-5 -5.32,0 0,5" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4268"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 201.88385,160.04359 c -6.43999,0 -11.72,5.24 -11.72,11.6 0,6.39999 5.28001,11.6 11.76,11.6 6.44,0 11.8,-5.20001 11.8,-11.44 0,-6.6 -5.16,-11.76 -11.84,-11.76 m 0.04,4.88 c 3.56,0 6.44,3.04 6.44,6.72 0,3.71999 -2.88,6.72 -6.4,6.72 -3.59999,0 -6.44,-3.00001 -6.44,-6.8 0,-3.64 2.92001,-6.64 6.4,-6.64" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4270"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 236.46885,160.56359 -5.32,0 0,10.44 c 0,2.91999 -0.2,4.36 -0.84,5.32 -0.76,1.28 -2.24,2.04 -4.04,2.04 -1.36,0 -2.4,-0.44 -3.12,-1.4 -0.76,-0.96 -1.08,-2.60001 -1.08,-5.56 l 0,-10.84 -5.32,0 0,11.88 c 0,3.75999 0.44,5.68 1.68,7.52 1.48,2.11999 3.88,3.28 6.76,3.28 2.68,0 4.36,-0.68 6.36,-2.64 l 0,2.12 4.92,0 0,-22.16" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4272"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 239.33323,175.68359 c 0.24,2.15999 0.6,3.28 1.48,4.48 1.44,1.92 3.96,3.08 6.64,3.08 4.43999,0 7.92,-3.32001 7.92,-7.56 0,-1.92 -0.72,-3.52 -2.08,-4.6 -0.84,-0.72 -2.16,-1.28 -4.08,-1.88 -2.16,-0.68 -2.16,-0.68 -2.68,-0.92 -0.72,-0.32 -1.08,-0.84 -1.08,-1.48 0,-1.08 0.88,-1.88 2.04,-1.88 1.12,0 1.84,0.6 2.08,1.76 l 5.2,0 c -0.08,-1.88 -0.52,-3 -1.6,-4.2 -1.4,-1.56 -3.48001,-2.44 -5.68,-2.44 -4.12,0 -7.36,2.96 -7.36,6.76 0,3.23999 1.76,5.08 6.16,6.56 2.03999,0.68 2.2,0.76 2.76,1.12 0.64,0.4 1,1 1,1.72 0,1.24 -1.04,2.16 -2.4,2.16 -1.56,0 -2.44,-0.8 -2.96,-2.68 l -5.36,0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4274"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 269.48323,182.72359 5.32,0 0,-10.92 c 0,-2.2 0.2,-3.68 0.56,-4.6 0.64,-1.44 2,-2.28 3.76,-2.28 1.44,0 2.68,0.52 3.4,1.4 0.64,0.84 0.92,2.16 0.92,4.24 l 0,12.16 5.32,0 0,-10.92 c 0,-2.48 0.2,-3.72 0.76,-4.76 0.68,-1.36 2.04,-2.12 3.72,-2.12 1.32,0 2.44,0.48 3.16,1.36 0.72,0.84 1,2.08 1,4.28 l 0,12.16 5.32,0 0,-12.8 c 0,-2.68 -0.48,-4.84 -1.44,-6.36 -1.4,-2.24 -4.20001,-3.52 -7.52,-3.52 -3.12,0 -5.32,1.04 -7.12,3.44 -1.52,-2.4 -3.48001,-3.44 -6.52,-3.44 -2.6,0 -4.2,0.72 -5.76,2.6 l 0,-2.08 -4.88,0 0,22.16" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4276"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 317.82135,160.04359 c -6.43999,0 -11.72,5.24 -11.72,11.6 0,6.39999 5.28001,11.6 11.76,11.6 6.44,0 11.8,-5.20001 11.8,-11.44 0,-6.6 -5.16,-11.76 -11.84,-11.76 m 0.04,4.88 c 3.56,0 6.44,3.04 6.44,6.72 0,3.71999 -2.88,6.72 -6.4,6.72 -3.59999,0 -6.44,-3.00001 -6.44,-6.8 0,-3.64 2.92001,-6.64 6.4,-6.64" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4278"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 355.04635,153.16359 -5.32,0 0,9.36 c -1.56,-1.72 -4.12,-2.76 -6.92,-2.76 -6.19999,0 -11.08,5.2 -11.08,11.84 0,6.55999 4.84001,11.64 11.12,11.64 3,0 5.2,-1.00001 7.32,-3.4 l 0,2.88 4.88,0 0,-29.56 m -11.48,11.48 c 3.72,0 6.56,3 6.56,6.88 0,3.83999 -2.84,6.84 -6.44,6.84 -3.71999,0 -6.6,-3.08001 -6.6,-7 0,-3.76 2.84001,-6.72 6.48,-6.72" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4280"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 381.0526,174.00359 c 0.16,-0.76 0.2,-1.24 0.2,-2.04 0,-6.88 -4.84,-11.92 -11.44,-11.92 -6.51999,0 -11.68,5.16 -11.68,11.68 0,6.47999 5.24001,11.52 12,11.52 3.64,0 6.48,-1.32001 8.8,-4 0.84,-1.04 1.4,-1.96 1.76,-3.08 l -5.8,0 c -1.36,1.6 -2.68,2.2 -4.88,2.2 -3.15999,0 -5.48,-1.68001 -6.12,-4.36 l 17.16,0 m -17.32,-4.68 c 0.84,-2.84 3.00001,-4.4 6.16,-4.4 3.28,0 5.44,1.56 6.12,4.4 l -12.28,0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4282"
+ style="font-size:40px;font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:URW Gothic L;-inkscape-font-specification:URW Gothic L Semi-Bold"
+ d="m 384.7176,182.72359 5.32,0 0,-29.56 -5.32,0 0,29.56" />
+ <g
+ id="g4658">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4217"
+ d="m 51.375,168.28125 0,4.03125 25.40625,0 0,-4.03125 -25.40625,0 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.05724525;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path4664"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 94.74648,188.2978 45.984619,170.36683 94.746482,152.43586 c -7.790106,10.58644 -7.74522,25.07052 -2e-6,35.86194 z" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
--- /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.
+
+# Intro a custom model, material and graphics program to draw a globe
+module globe
+
+intrude import gamnit::depth # To access `Mesh::indices_c`
+
+# Number of vertices to create parallels, meridians are double of this
+#
+# The minimum should be 3 for an octahedron planet.
+fun n_parallels: Int do return 25
+
+redef class App
+
+ # Program for the graphic card
+ private var globe_program = new GlobeProgram
+
+ # Texture of the reflexive surface of the earth (with the seas in white)
+ private var texture_seas = new Texture("globe/seas.jpg")
+
+ # Texture of the surface of the earth
+ private var texture_earth = new Texture("globe/earth.jpg")
+
+ # Texture of the lights at night on earth
+ private var texture_night = new Texture("globe/lights.jpg")
+
+ # Elevation map of earth
+ private var texture_elevation = new Texture("globe/elevation.jpg")
+
+ # Texture of the clouds above the earth
+ private var texture_clouds = new Texture("globe/clouds.png")
+
+ redef fun on_create
+ do
+ super
+
+ # Compile globe_program
+ var program = app.globe_program
+ program.compile_and_link
+
+ # Catch any errors
+ var gamnit_error = program.error
+ assert gamnit_error == null else print_error gamnit_error
+ end
+end
+
+# Full model of a globe, with a surface, clouds layer and atmosphere
+class GlobeModel
+ super CompositeModel
+
+ redef fun load
+ do
+ leaves.add new LeafModel(
+ new Mesh.uv_sphere(1.0, 2*n_parallels, n_parallels),
+ new GlobeMaterial.surface)
+ leaves.add new LeafModel(
+ new Mesh.uv_sphere(1.1, 2*n_parallels, n_parallels),
+ new GlobeMaterial.clouds)
+ leaves.add new LeafModel(
+ new Mesh.uv_sphere(1.2, 2*n_parallels, n_parallels),
+ new GlobeMaterial.atmo)
+ end
+end
+
+# Parameterizable material to draw the 3 layers of the globe
+class GlobeMaterial
+ super Material
+
+ # Id of the texture for diffuse colors, if any
+ var texture_id: nullable Int
+
+ # Draw as a surface, using the elevation map and the night lights
+ var is_surface: Bool
+
+ # Ambient color
+ var color: Array[Float]
+
+ # Create and configure a material for the earth surface
+ init surface do init(0, true, [1.0, 1.0, 1.0, 1.0])
+
+ # Create and configure a material for the cloud layer
+ init clouds do init(4, false, [1.0, 1.0, 1.0, 0.25])
+
+ # Create and configure a material for the visible atmosphere
+ init atmo do init(null, false, [0.0, 0.8, 1.0, 0.05])
+
+ redef fun draw(actor, model)
+ do
+ var gl_error = glGetError
+ assert gl_error == gl_NO_ERROR else print gl_error
+
+ var mesh = model.mesh
+
+ var program = app.globe_program
+ program.use
+
+ # Set constant program values
+ program.use
+
+ # Bind textures
+ glActiveTexture gl_TEXTURE0
+ glBindTexture(gl_TEXTURE_2D, app.texture_earth.gl_texture)
+
+ glActiveTexture gl_TEXTURE1
+ glBindTexture(gl_TEXTURE_2D, app.texture_seas.gl_texture)
+
+ glActiveTexture gl_TEXTURE2
+ glBindTexture(gl_TEXTURE_2D, app.texture_night.gl_texture)
+
+ glActiveTexture gl_TEXTURE3
+ glBindTexture(gl_TEXTURE_2D, app.texture_elevation.gl_texture)
+
+ glActiveTexture gl_TEXTURE4
+ glBindTexture(gl_TEXTURE_2D, app.texture_clouds.gl_texture)
+
+ # Set samplers
+ program.tex_specular.uniform 1
+ program.tex_night.uniform 2
+ program.tex_displace.uniform 3
+
+ # Update camera view and light
+ var p = app.world_camera.position
+ program.camera.uniform(p.x, p.y, p.z)
+ program.mvp.uniform app.world_camera.mvp_matrix
+ program.light_center.uniform(app.light.position.x, app.light.position.y, app.light.position.z)
+
+ # Set attributes
+ program.coord.array_enabled = true
+ program.coord.array(mesh.vertices, 3)
+
+ program.tex_coord.array_enabled = true
+ program.tex_coord.array(mesh.texture_coords, 2)
+
+ program.normal.array_enabled = true
+ program.normal.array(mesh.normals, 3)
+
+ # Set uniforms
+ program.scale.uniform 1.0
+ program.rotation.uniform new Matrix.rotation(actor.rotation, 0.0, 1.0, 0.0)
+ program.translation.uniform(actor.center.x, -actor.center.y, actor.center.z, 0.0)
+ program.color.uniform(color[0], color[1], color[2], color[3])
+ program.is_surface.uniform is_surface
+
+ # Set the color texture?
+ var tex = texture_id
+ if tex == null then
+ program.use_texture.uniform false
+ else
+ program.use_texture.uniform true
+ program.tex.uniform tex
+ end
+
+ # Execute draw, support only meshes with `indices`
+ glDrawElements(gl_TRIANGLES, mesh.indices.length, gl_UNSIGNED_SHORT, mesh.indices_c.native_array)
+
+ # Catch any errors
+ gl_error = glGetError
+ assert gl_error == gl_NO_ERROR else print gl_error
+ end
+end
+
+# Graphical program to draw a planet with Phong lighting
+class GlobeProgram
+ super GamnitProgramFromSource
+
+ redef var vertex_shader_source = """
+ // Vertex coordinates
+ attribute vec4 coord;
+
+ // Vertex color tint
+ uniform vec4 color;
+
+ // Vertex translation
+ uniform vec4 translation;
+
+ // Vertex scaling
+ uniform float scale;
+
+ // Vertex coordinates on textures
+ attribute vec2 tex_coord;
+
+ // Vertex normal
+ attribute vec3 normal;
+
+ // Model view projection matrix
+ uniform mat4 mvp;
+
+ // Model rotation
+ uniform mat4 rotation;
+
+ // Lights config
+ uniform vec3 light_center;
+
+ // Texture of surface elevation to displace vertices
+ uniform sampler2D tex_displace;
+
+ // Draw this as a planet surface?
+ uniform bool is_surface;
+
+ // Output for the fragment shader
+ varying vec4 v_color;
+ varying vec2 v_tex_coord;
+ varying vec3 v_normal;
+ varying vec4 v_light_center;
+
+ void main()
+ {
+ v_color = color;
+ v_tex_coord = tex_coord;
+ v_normal = normalize(vec4(normal, 0.0) * rotation * mvp).xyz;
+ v_light_center = vec4(light_center, 0.0) * mvp;
+
+ // Apply displacement map
+ float s = scale;
+ if (is_surface)
+ s += 0.05 * texture2D(tex_displace, tex_coord).r;
+
+ gl_Position = (vec4(coord.xyz * s, 1.0) * rotation + translation) * mvp;
+
+ }
+ """ @ glsl_vertex_shader
+
+ redef var fragment_shader_source = """
+ precision mediump float;
+
+ // Input from the vertex shader
+ varying vec4 v_color;
+ varying vec2 v_tex_coord;
+ varying vec3 v_normal;
+ varying vec4 v_light_center;
+
+ // Coordinates of the camera
+ uniform vec3 camera;
+
+ // Does this object use a texture?
+ uniform bool use_texture;
+
+ // Texture to apply on this object
+ uniform sampler2D tex;
+
+ // Reflection map to apply to the Phong logic
+ uniform sampler2D tex_specular;
+
+ // Texture for the dark side of the earth
+ uniform sampler2D tex_night;
+
+ // Draw this as a planet surface?
+ uniform bool is_surface;
+
+ // Colors config
+ vec4 ambient_color = vec4(0.2, 0.2, 0.2, 1.0);
+ vec4 diffuse_color = vec4(1.0, 1.0, 1.0, 1.0);
+ vec4 specular_color = vec4(1.0, 1.0, 1.0, 1.0);
+
+ void main()
+ {
+ // Lambert diffusion
+ vec3 to_light = normalize(v_light_center.xyz);
+ float lambert = max(dot(to_light, v_normal), 0.0);
+
+ // Phong specular
+ float specular = 0.0;
+ if (lambert > 0.0) {
+ vec3 to_camera = normalize(camera);
+ vec3 normal = normalize(v_normal);
+ vec3 light_reflect = reflect(to_light, normal);
+ float spec_angle = max(dot(light_reflect, to_camera), 0.0);
+ specular = pow(spec_angle, 16.0);
+
+ if (is_surface)
+ specular *= texture2D(tex_specular, v_tex_coord).x;
+ else specular *= 0.2;
+ }
+
+ if(use_texture) {
+ gl_FragColor = v_color * texture2D(tex, v_tex_coord);
+ } else {
+ gl_FragColor = v_color;
+ }
+
+ gl_FragColor *= ambient_color + lambert * diffuse_color;
+ gl_FragColor += specular * specular_color;
+
+ if (is_surface && lambert < 0.2) {
+ // Show city lights at night
+ float p_night = (0.2 - lambert) * 5.0;
+ gl_FragColor += p_night*texture2D(tex_night, v_tex_coord);
+ }
+ }
+ """ @ glsl_fragment_shader
+
+ # Vertices coordinates
+ var coord = attributes["coord"].as(AttributeVec4) is lazy
+
+ # Color tint per vertex
+ var color = uniforms["color"].as(UniformVec4) is lazy
+
+ # Scaling per vertex
+ var scale = uniforms["scale"].as(UniformFloat) is lazy
+
+ # Coordinates on the textures, per vertex
+ var tex_coord = attributes["tex_coord"].as(AttributeVec2) is lazy
+
+ # Normal per vertex
+ var normal = attributes["normal"].as(AttributeVec3) is lazy
+
+ # Model view projection matrix
+ var mvp = uniforms["mvp"].as(UniformMat4) is lazy
+
+ # Should this program use the texture `tex`?
+ var use_texture = uniforms["use_texture"].as(UniformBool) is lazy
+
+ # Main visible texture unit
+ var tex = uniforms["tex"].as(UniformSampler2D) is lazy
+
+ # Texture unit for reflection effect
+ var tex_specular = uniforms["tex_specular"].as(UniformSampler2D) is lazy
+
+ # Texture of the earth at night
+ var tex_night = uniforms["tex_night"].as(UniformSampler2D) is lazy
+
+ # Texture with elevation data
+ var tex_displace = uniforms["tex_displace"].as(UniformSampler2D) is lazy
+
+ # Position of the camera
+ var camera = uniforms["camera"].as(UniformVec3) is lazy
+
+ # Execute this program to draw a planet surface?
+ var is_surface = uniforms["is_surface"].as(UniformBool) is lazy
+
+ # Translation applied to each vertex
+ var translation = uniforms["translation"].as(UniformVec4) is lazy
+
+ # Rotation matrix
+ var rotation = uniforms["rotation"].as(UniformMat4) is lazy
+
+ # Center position of the light
+ var light_center = uniforms["light_center"].as(UniformVec3) is lazy
+end
import gamnit::depth
+import globe
+
redef class App
# All available models
new LeafModel(new Mesh.uv_sphere(4.0, 32, 16), new NormalsMaterial),
new Model("models/Tree_01.obj"),
new Model("models/Oak_Fall_01.obj"),
- new Model("models/Quandtum_BA-2_v1_1.obj")]
+ new Model("models/Quandtum_BA-2_v1_1.obj"),
+ new GlobeModel]
# Index of the current model in `models`
var model_index = 0
actor.center.z -= model.mesh.center.z
var height = model.mesh.dimensions.y
- world_camera.reset_height(height * 4.0)
+ world_camera.reset_height(height * 3.0)
actors.clear
actors.add actor
# Stop tracking head movement
fun stop_tracking in "Java" `{ self.stopTracking(); `}
- # Apply correction to the gyroscope values
- fun gyro_bias=(matrix: JavaFloatArray) in "Java" `{
- self.setGyroBias(matrix);
- `}
-
# Enable finer analysis using the neck as center of movement
fun neck_model_enabled=(value: Bool) in "Java" `{
self.setNeckModelEnabled(value);
--- /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.
+
+# Update the orientation of `world_camera` at each frame using the head position given by `android::cardboard`
+#
+# This module is Android specific.
+module cardboard
+
+import ::android::cardboard
+
+import depth
+intrude import cameras
+
+redef class EulerCamera
+ # Do not use `yaw` and `pitch`, the value will instead originate from the Cardboard API
+ redef var rotation_matrix = new Matrix.identity(4)
+
+ # Get the angle value from the `rotation_matrix`
+ redef fun pitch
+ do
+ var a = rotation_matrix[0, 1]
+ var b = rotation_matrix[1, 1]
+ return -atan2(a, b)
+ end
+
+ # Get the angle value from the `rotation_matrix`
+ redef fun yaw
+ do
+ var a = rotation_matrix[2, 0]
+ var b = rotation_matrix[2, 2]
+ return -atan2(a, b)
+ end
+end
+
+redef class App
+
+ # Cardboard's head tacker instance
+ private var head_tracker: nullable NativeHeadTracker = null
+
+ # Rotation matrix read from `head_tracker`, reusing the same structure as a buffer
+ private var java_rotation_matrix = new JavaFloatArray(16) is lazy
+
+ # Initialize and set `head_tracker`
+ fun initialize_head_tracker
+ do
+ # Initialize the Cardboard head orientation tracker service
+ var head_tracker = new NativeHeadTracker(app.native_activity)
+ head_tracker.neck_model_enabled = true
+ head_tracker.start_tracking
+ self.head_tracker = head_tracker
+
+ # Set a wide field of view
+ world_camera.field_of_view_y = 1.0
+ end
+
+ # Read the rotation matrix from Cardboard and update `world_camera`
+ private fun update_from_head_tracker
+ do
+ var head_tracker = head_tracker
+ if head_tracker == null then return
+
+ head_tracker.last_head_view(java_rotation_matrix, 0)
+
+ # Copy values from the Java array to our matrix
+ for y in [0..4[ do
+ for x in [0..4[ do
+ world_camera.rotation_matrix[y, x] = java_rotation_matrix[y*4+x]
+ end
+ end
+ end
+
+ redef fun on_create
+ do
+ super
+ initialize_head_tracker
+ end
+
+ redef fun update(dt)
+ do
+ super
+ update_from_head_tracker
+ end
+
+ redef fun pause
+ do
+ super
+ var tracker = head_tracker
+ if tracker != null then tracker.stop_tracking
+ end
+
+ redef fun resume
+ do
+ super
+ var tracker = head_tracker
+ if tracker != null then tracker.start_tracking
+ end
+end
assert gamnit_error == null else print_error gamnit_error
end
- # Draw all element in `actors`
- redef fun frame_core_draw(display)
- do
- super
+ redef fun frame_core_draw(display) do frame_core_depth display
+ # Draw all elements of `actors` and then call `frame_core_flat`
+ protected fun frame_core_depth(display: GamnitDisplay)
+ do
# Update cameras on both our programs
versatile_program.use
versatile_program.mvp.uniform world_camera.mvp_matrix
leaf.material.draw(actor, leaf)
end
end
+
+ frame_core_flat display
end
end
attribute vec4 coord;
// Vertex translation
- attribute vec4 translation;
+ uniform vec4 translation;
// Vertex scaling
- attribute float scale;
+ uniform float scale;
// Vertex coordinates on textures
attribute vec2 tex_coord;
var camera = uniforms["camera"].as(UniformVec3) is lazy
# Translation applied to each vertex
- var translation = attributes["translation"].as(AttributeVec4) is lazy
+ var translation = uniforms["translation"].as(UniformVec4) is lazy
# Rotation matrix
var rotation = uniforms["rotation"].as(UniformMat4) is lazy
# Scaling per vertex
- var scale = attributes["scale"].as(AttributeFloat) is lazy
+ var scale = uniforms["scale"].as(UniformFloat) is lazy
# Model view projection matrix
var mvp = uniforms["mvp"].as(UniformMat4) is lazy
end
redef var center = new Point3d[Float](0.0, 0.0, 0.0) is lazy
+
+ init do indices.add_all([0, 1, 2, 2, 1, 3])
+ # TODO use gl_TRIANGLE_FAN instead
end
# Cube, with 6 faces
return normals
end
+ redef var texture_coords: Array[Float] is lazy do
+ var a = [0.0, 1.0]
+ var b = [1.0, 1.0]
+ var c = [0.0, 0.0]
+ var d = [1.0, 0.0]
+
+ var texture_coords = new Array[Float]
+ for v in [c, d, a, a, d, b] do for i in 6.times do texture_coords.add_all v
+ return texture_coords
+ end
+
redef var center = new Point3d[Float](0.0, 0.0, 0.0) is lazy
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.
+
+# Refine `EulerCamera` and `App::frame_core_draw` to get a stereoscopic view
+module stereoscopic_view
+
+import depth
+intrude import cameras
+
+redef class EulerCamera
+ redef var mvp_matrix = new Matrix.identity(4)
+
+ # Half of the distance between the eyes
+ var eye_separation: Float = 0.03125
+
+ # MVP matrix for the left eye
+ fun mvp_matrix_left: Matrix do return mvp_matrix_eye(eye_separation)
+
+ # MVP matrix for the right eye
+ fun mvp_matrix_right: Matrix do return mvp_matrix_eye(-eye_separation)
+
+ # Get an MVP matrix for an eye at `diff` world unit from the center
+ private fun mvp_matrix_eye(diff: Float): Matrix
+ do
+ var view = new Matrix.identity(4)
+
+ # Translate the world away from the camera
+ view.translate(-position.x/2.0, -position.y/2.0, -position.z/2.0)
+
+ # Rotate the camera, first by looking left or right, then up or down
+ view = view * rotation_matrix
+
+ # Apply eye transformation
+ var translation = new Matrix.identity(4)
+ translation.translate(diff, 0.0, 0.0)
+ view = view * translation
+
+ # Use a projection matrix with a depth
+ var projection = new Matrix.perspective(pi*field_of_view_y/2.0,
+ display.aspect_ratio, near, far)
+
+ return view * projection
+ end
+end
+
+redef class GamnitDisplay
+
+ # With stereoscopic view, the aspect ratio (in each eye) is half of the screen
+ redef fun aspect_ratio do return super / 2.0
+end
+
+redef class App
+ redef fun frame_core_draw(display) do frame_core_stereoscopic display
+
+ # Split the screen in two, and call `frame_core_depth` for each eyes
+ protected fun frame_core_stereoscopic(display: GamnitDisplay)
+ do
+ var half_width = display.width / 2
+
+ # Left eye
+ glViewport(0, 0, half_width, display.height)
+ world_camera.mvp_matrix = world_camera.mvp_matrix_left
+ frame_core_depth display
+
+ # Right eye
+ glViewport(half_width, 0, half_width, display.height)
+ world_camera.mvp_matrix = world_camera.mvp_matrix_right
+ frame_core_depth display
+
+ # We reset the viewport for selection
+ glViewport(0, 0, display.width, display.height)
+
+ # Check for errors
+ var gl_error = glGetError
+ assert gl_error == gl_NO_ERROR else print gl_error
+ end
+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.
+
+# VR support for gamnit depth, for Android only
+module vr
+
+import cardboard
+import stereoscopic_view
+++ /dev/null
-NITC=../../../../bin/nitc
-NITLS=../../../../bin/nitls
-
-all: bin/globe
-
-bin/globe: $(shell ${NITLS} -M src/globe.nit linux) ${NITC}
- ${NITC} src/globe.nit -m linux -o $@ -D n_parallels=100
-
-check: bin/globe
- bin/globe
-
-# ---
-# Android
-
-android: bin/globe.apk
-bin/globe.apk: $(shell ${NITLS} -M src/globe.nit android) ${NITC} res/drawable-hdpi/icon.png assets/ld/earth.jpg
- ${NITC} src/globe.nit -m android -o $@
-
-android-release: $(shell ${NITLS} -M src/globe.nit android) ${NITC} res/drawable-hdpi/icon.png assets/ld/earth.jpg
- ${NITC} src/globe.nit -m android -o bin/globe.apk --release
-
-android-wear: $(shell ${NITLS} -M src/globe.nit android) ${NITC} res/drawable-hdpi/icon.png assets/ld/earth.jpg
- ${NITC} src/globe.nit -m android -o bin/planet_wear.apk -D n_parallels=10
-
-res/drawable-hdpi/icon.png: art/icon.png
- mkdir -p res/drawable-ldpi/ res/drawable-mdpi/ res/drawable-hdpi/ \
- res/drawable-xhdpi/ res/drawable-xxhdpi/ res/drawable-xxxhdpi/
- convert -resize 36x36 art/icon.png res/drawable-ldpi/icon.png
- convert -resize 48x48 art/icon.png res/drawable-mdpi/icon.png
- convert -resize 72x72 art/icon.png res/drawable-hdpi/icon.png
- convert -resize 96x96 art/icon.png res/drawable-xhdpi/icon.png
- convert -resize 144x144 art/icon.png res/drawable-xxhdpi/icon.png
- convert -resize 192x192 art/icon.png res/drawable-xxxhdpi/icon.png
-
-assets/ld/earth.jpg:
- mkdir -p assets/ld
- convert -resize 2048x1024 assets/hd/earth.jpg assets/ld/earth.jpg
- convert -resize 2048x1024 assets/hd/seas.jpg assets/ld/seas.jpg
- convert -resize 2048x1024 assets/hd/clouds.png assets/ld/clouds.png
- convert -resize 2048x1024 assets/hd/elevation.jpg assets/ld/elevation.jpg
- convert -resize 2048x1024 assets/hd/lights.jpg assets/ld/lights.jpg
+++ /dev/null
-Sample gamnit app rendering the earth with elevated surface, cloud layer, city lights and Phong lighting.
-
-# Possible variations
-
-It would have been possible to achieve the same result with different approaches.
-They should be explored as they could provide better performances or be easier to understand.
-
-* Use a single set of vertices, normals and indices because we only need spheres.
-* Alternatively, use one program per sphere.
-
-# Art
-
-Images credit: NASA, Visible Earth
+++ /dev/null
-Categories:Nit,Multimedia
-License:Apache2
-Web Site:http://nitlanguage.org
-Source Code:http://nitlanguage.org/nit.git/tree/HEAD:/lib/gamnit/examples/globe
-Issue Tracker:https://github.com/nitlang/nit/issues
-
-Summary:Simple rotating globe of the earth
-Description:
-Non-interactive sample gamnit app rendering the earth with elevated surface, cloud layer, city lights and Phong lighting.
-.
+++ /dev/null
-[package]
-name=globe
-tags=example
-maintainer=Alexis Laferrière <alexis.laf@xymus.net>
-license=Apache-2.0
-[upstream]
-browse=https://github.com/nitlang/nit/tree/master/lib/gamnit/examples/globe/
-git=https://github.com/nitlang/nit.git
-git.directory=lib/gamnit/examples/globe/
-homepage=http://nitlanguage.org
-issues=https://github.com/nitlang/nit/issues
-apk=http://nitlanguage.org/fdroid/apk/globe.apk
+++ /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.
-
-# Portable app using gamnit textures and programs with custom calls to OpenGL ES 2.0
-module globe is
- app_name "gamnit Globe"
- app_namespace "org.nitlanguage.globe"
- app_version(1, 0, git_revision)
-
- android_manifest_activity """android:screenOrientation="portrait""""
- android_api_target 15
-end
-
-import realtime
-import matrix::projection
-
-import gamnit
-import gamnit::cameras
-import gamnit::limit_fps
-
-private import more_collections
-
-# Graphical program to draw a planet with Phong lighting
-class GlobeProgram
- super GamnitProgramFromSource
-
- redef var vertex_shader_source = """
- // Vertex coordinates
- attribute vec4 coord;
-
- // Vertex color tint
- attribute vec4 color;
-
- // Vertex translation
- attribute vec4 translation;
-
- // Vertex scaling
- attribute float scale;
-
- // Vertex coordinates on textures
- attribute vec2 tex_coord;
-
- // Vertex normal
- attribute vec3 normal;
-
- // Model view projection matrix
- uniform mat4 mvp;
-
- // Texture of surface elevation to displace vertices
- uniform sampler2D tex_displace;
-
- // Draw this as a planet surface?
- uniform bool is_surface;
-
- // Output for the fragment shader
- varying vec4 v_color;
- varying vec2 v_tex_coord;
- varying vec3 v_normal;
-
- void main()
- {
- // Pass varyings to the fragment shader
- v_color = color;
- v_tex_coord = tex_coord;
- v_normal = normal;
-
- // Apply bump map
- float s = scale;
- if (is_surface)
- s += 0.05 * texture2D(tex_displace, tex_coord).r;
-
- gl_Position = (vec4(coord.xyz * s, 1.0) + translation) * mvp;
- }
- """ @ glsl_vertex_shader
-
- redef var fragment_shader_source = """
- precision mediump float;
-
- // Input from the vertex shader
- varying vec4 v_color;
- varying vec2 v_tex_coord;
- varying vec3 v_normal;
-
- // Coordinates of the camera
- uniform vec3 camera;
-
- // Does this object use a texture?
- uniform bool use_texture;
-
- // Texture to apply on this object
- uniform sampler2D tex;
-
- // Reflection map to apply the the phong logic
- uniform sampler2D tex_shiny;
-
- // Texture for the dark side of the earth
- uniform sampler2D tex_night;
-
- // Draw this as a planet surface?
- uniform bool is_surface;
-
- // Lights config
- // TODO configure from outside the shader
- vec3 light_dir = normalize(vec3(-1.0, 0.0, -1.0));
- vec4 ambient_color = vec4(0.2, 0.2, 0.2, 1.0);
- vec4 diffuse_color = vec4(1.0, 1.0, 1.0, 1.0);
- vec4 specular_color = vec4(1.0, 1.0, 1.0, 1.0);
-
- void main()
- {
- if(use_texture) {
- gl_FragColor = v_color * texture2D(tex, v_tex_coord);
- } else {
- gl_FragColor = v_color;
- }
-
- // Lambert diffusion
- float lambert = max(dot(light_dir, v_normal), 0.0);
-
- // Phong specular
- float specular = 0.0;
- if (lambert > 0.0) {
- vec3 to_camera = normalize(camera);
- vec3 light_reflect = reflect(light_dir, v_normal);
- float specularAngle = max(dot(light_reflect, to_camera), 0.0);
- specular = pow(specularAngle, 16.0);
-
- if (is_surface)
- specular *= texture2D(tex_shiny, v_tex_coord).x;
- else specular *= 0.2;
- }
-
- gl_FragColor *= ambient_color + lambert * diffuse_color;
- gl_FragColor += specular * specular_color;
-
- if (is_surface && lambert < 0.2) {
- // Show city lights at night
- float p_night = (0.2 - lambert) * 5.0;
- gl_FragColor += p_night*texture2D(tex_night, v_tex_coord);
- }
- }
- """ @ glsl_fragment_shader
-
- # Vertices coordinates
- var coord = attributes["coord"].as(AttributeVec4) is lazy
-
- # Color tint per vertex
- var color = attributes["color"].as(AttributeVec4) is lazy
-
- # Scaling per vertex
- var scale = attributes["scale"].as(AttributeFloat) is lazy
-
- # Coordinates on the textures, per vertex
- var tex_coord = attributes["tex_coord"].as(AttributeVec2) is lazy
-
- # Normal per vertex
- var normal = attributes["normal"].as(AttributeVec3) is lazy
-
- # Model view projection matrix
- var mvp = uniforms["mvp"].as(UniformMat4) is lazy
-
- # Should this program use the texture `tex`?
- var use_texture = uniforms["use_texture"].as(UniformBool) is lazy
-
- # Main visible texture unit
- var tex = uniforms["tex"].as(UniformSampler2D) is lazy
-
- # Texture unit for reflection effect
- var tex_shiny = uniforms["tex_shiny"].as(UniformSampler2D) is lazy
-
- # Texture of the earth at night
- var tex_night = uniforms["tex_night"].as(UniformSampler2D) is lazy
-
- # Texture with elevation data
- var tex_displace = uniforms["tex_displace"].as(UniformSampler2D) is lazy
-
- # Position of the camera
- var camera = uniforms["camera"].as(UniformVec3) is lazy
-
- # Execute this program to draw a planet surface?
- var is_surface = uniforms["is_surface"].as(UniformBool) is lazy
-end
-
-# Mesh with all information for drawing
-class Mesh
-
- # Vertices coordinates
- var vertices: Array[Float]
-
- # Indices to draw triangles
- var indices: Array[Int]
-
- private var indices_c = new CUInt16Array.from(indices) is lazy
-
- # Normals on each vertex
- var normals: Array[Float]
-
- # Coordinates on the texture per vertex
- var texture_coords: Array[Float]
-
- # Create an UV sphere of `radius` with `n_meridians` and `n_parallels`
- init uv_sphere(radius: Float, n_meridians, n_parallels: Int)
- do
- var w = n_meridians
- var h = n_parallels
-
- var vertices = new Array[Float].with_capacity(w*h*3)
- var texture_coords = new Array[Float].with_capacity(w*h*2)
- var normals = new Array[Float].with_capacity(w*h*3)
-
- # Build vertices
- for m in [0..w[ do
- for p in [0..h[ do
- var u = m.to_f * 2.0 * pi / (w-1).to_f
- var v = p.to_f * pi / (h-1).to_f
-
- vertices.add radius * u.cos * v.sin
- vertices.add radius * v.cos
- vertices.add radius * u.sin * v.sin
-
- texture_coords.add (1.0 - m.to_f/(w-1).to_f)
- texture_coords.add(p.to_f/(h-1).to_f)
-
- normals.add u.cos * v.sin
- normals.add v.cos
- normals.add u.sin * v.sin
- end
- end
-
- # Build faces
- var indices = new Array[Int].with_capacity((w-1)*(h-1)*6)
- for m in [0..w-1[ do
- for p in [0..h-1[ do
- var a = m*h + p
-
- indices.add a
- indices.add(a+h)
- indices.add(a+1)
-
- indices.add(a+h)
- indices.add(a+h+1)
- indices.add(a+1)
- end
- end
-
- init(vertices, indices, normals, texture_coords)
- end
-end
-
-# Number of vertices to create parallels, meridians are double of this
-#
-# The minimum should be 3 for an octahedron planet.
-fun n_parallels: Int do return 25
-
-redef class GamnitAssetTexture
- # All images are either within the hd or ld folder
- redef fun path do return app.definition / super
-end
-
-redef class App
-
- # Earth
- var planet = new Mesh.uv_sphere(2.0, 2*n_parallels, n_parallels)
-
- # Cloud layer
- var clouds = new Mesh.uv_sphere(2.08, 2*n_parallels, n_parallels)
-
- # Visible atmosphere
- var atmo = new Mesh.uv_sphere(2.16, 2*n_parallels, n_parallels)
-
- # Program for the graphic card
- var program = new GlobeProgram
-
- private var definition: String is lazy do
- var max_texture_size = glGetIntegerv(gl_MAX_TEXTURE_SIZE)
-
- # HD textures max sizes reange from 2048 px to 5400 px
- if max_texture_size < 5400 then
- return "ld"
- else return "hd"
- end
-
- # Texture of the reflexive surface of the earth (with the seas in white)
- var texture_seas = new Texture("seas.jpg")
-
- # Texture of the surface of the earth
- var texture_earth = new Texture("earth.jpg")
-
- # Texture of the lights at night on earth
- var texture_night = new Texture("lights.jpg")
-
- # Elevation map of earth
- var texture_elevation = new Texture("elevation.jpg")
-
- # Texture of the clouds above the earth
- var texture_clouds = new Texture("clouds.png")
-
- # Camera for the only view
- var camera: EulerCamera is lazy do
- var camera = new EulerCamera(app.display.as(not null))
- camera.move(0.0, 0.1, -5.0)
- return camera
- end
-
- redef fun on_create
- do
- super
-
- var display = display
- assert display != null
-
- var gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
-
- # Prepare program
- var program = program
- program.compile_and_link
-
- var gamnit_error = program.error
- assert gamnit_error == null else print_error gamnit_error
-
- # Blend
- gl.capabilities.blend.enable
- glBlendFunc(gl_SRC_ALPHA, gl_ONE_MINUS_SRC_ALPHA)
-
- gl.capabilities.depth_test.enable
- glDepthFunc gl_LEQUAL
- glDepthMask true
-
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
-
- # Prepare to draw
- for tex in all_root_textures do
- tex.load
- glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_LINEAR)
- glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_LINEAR)
-
- gamnit_error = tex.error
- assert gamnit_error == null else print_error gamnit_error
- end
-
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
-
- program.use
-
- glViewport(0, 0, display.width, display.height)
- glClearColor(0.0, 0.02, 0.0, 1.0)
-
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
-
- # Assign all textures to a unit
- glActiveTexture gl_TEXTURE0
- glBindTexture(gl_TEXTURE_2D, texture_earth.gl_texture)
-
- glActiveTexture gl_TEXTURE1
- glBindTexture(gl_TEXTURE_2D, texture_seas.gl_texture)
-
- glActiveTexture gl_TEXTURE2
- glBindTexture(gl_TEXTURE_2D, texture_night.gl_texture)
-
- glActiveTexture gl_TEXTURE3
- glBindTexture(gl_TEXTURE_2D, texture_elevation.gl_texture)
-
- glActiveTexture gl_TEXTURE4
- glBindTexture(gl_TEXTURE_2D, texture_clouds.gl_texture)
-
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
-
- # Constant program values
- program.coord.array_enabled = true
- program.tex_coord.array_enabled = true
- program.normal.array_enabled = true
-
- program.scale.uniform 1.0
-
- program.use_texture.uniform true
-
- program.tex_shiny.uniform 1
- program.tex_night.uniform 2
- program.tex_displace.uniform 3
-
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
- end
-
- private var clock = new Clock
-
- redef fun frame_core(display)
- do
- var t = clock.total.to_f/3.0 + 0.75*pi
-
- var gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
-
- glClear(gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT)
- program.use
-
- # Rotate world
- # FIXME do this cleanly by moving the camera
- var mvp = new Matrix.rotation(t, 0.0, 1.0, 0.0) * camera.mvp_matrix
- program.mvp.uniform mvp
- program.camera.uniform(-t.sin, -0.8, -t.cos)
-
- # Planet
- program.coord.array(planet.vertices, 3)
- program.tex_coord.array(planet.texture_coords, 2)
- program.normal.array(planet.normals, 3)
- program.tex.uniform 0
- program.use_texture.uniform true
- program.color.uniform(1.0, 1.0, 1.0, 1.0)
- program.is_surface.uniform true
- glDrawElements(gl_TRIANGLES, planet.indices.length, gl_UNSIGNED_SHORT, planet.indices_c.native_array)
-
- # Clouds
- program.coord.array(clouds.vertices, 3)
- program.tex_coord.array(clouds.texture_coords, 2)
- program.normal.array(clouds.normals, 3)
- program.tex.uniform 4
- program.color.uniform(1.0, 1.0, 1.0, 0.5) # Half transparency
- program.is_surface.uniform false
- glDrawElements(gl_TRIANGLES, clouds.indices.length, gl_UNSIGNED_SHORT, clouds.indices_c.native_array)
-
- # Atmo
- program.coord.array(atmo.vertices, 3)
- program.tex_coord.array(atmo.texture_coords, 2)
- program.normal.array(atmo.normals, 3)
- program.color.uniform(0.0, 0.8, 1.0, 0.02) # Blueish
- program.is_surface.uniform false
- program.use_texture.uniform false
- glDrawElements(gl_TRIANGLES, atmo.indices.length, gl_UNSIGNED_SHORT, atmo.indices_c.native_array)
- assert program.use_texture.is_active
-
- display.flip
-
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print gl_error
- end
-
- redef fun on_stop
- do
- # Clean up
- program.delete
-
- # Close gamnit
- var display = display
- if display != null then display.close
- end
-end
glActiveTexture gl_TEXTURE0
glBindTexture(gl_TEXTURE_2D, texture.root.gl_texture)
+ simple_2d_program.translation.array_enabled = false
+ simple_2d_program.color.array_enabled = false
+ simple_2d_program.scale.array_enabled = false
+
simple_2d_program.translation.uniform(center.x, -center.y, center.z, 0.0)
simple_2d_program.color.uniform(1.0, 1.0, 1.0, alpha)
simple_2d_program.scale.uniform scale
assert gl_error == gl_NO_ERROR else print gl_error
end
+ # Draw the whole screen, all `glDraw...` calls should be executed here
+ protected fun frame_core_draw(display: GamnitDisplay) do frame_core_flat display
+
# Draw sprites in `sprites` and `ui_sprites`
- protected fun frame_core_draw(display: GamnitDisplay)
+ protected fun frame_core_flat(display: GamnitDisplay)
do
simple_2d_program.use
--- /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.
+
+# Simple service keeping track of which keys are currently pressed
+#
+# This service revolves around `app.pressed_keys`, a `Set` of the names of currently pressed keys.
+# As a `Set`, `app.pressed_keys` can be iterated and queried with `has`.
+#
+# Limitations: The keys names are platform dependent.
+module keys
+
+import mnit::input
+import gamnit
+
+redef class App
+ # Currently pressed keys
+ var pressed_keys = new Set[String] is lazy
+
+ # Register `event` to update `app.pressed_keys`
+ private fun register_key_event(event: KeyEvent)
+ do
+ var key = event.name
+ if event.is_down then
+ app.pressed_keys.add key
+ else if app.pressed_keys.has(key) then
+ app.pressed_keys.remove key
+ end
+ end
+
+ redef fun accept_event(event)
+ do
+ if event isa KeyEvent then register_key_event event
+
+ return super
+ end
+end