-NITC=nitc
-NITLS=nitls
-
all: bin/action_nitro
-bin/action_nitro: $(shell ${NITLS} -M src/action_nitro.nit -m linux) pre-build
- ${NITC} src/action_nitro.nit -m linux -o $@
+bin/action_nitro: $(shell nitls -M src/action_nitro.nit -m linux) pre-build
+ nitc src/action_nitro.nit -m linux -o $@
+
+android: bin/action_nitro.apk
+bin/action_nitro.apk: $(shell nitls -M src/action_nitro.nit -m gamnit::android19 -m src/touch_ui.nit) pre-build android/res/
+ nitc src/action_nitro.nit -m gamnit::android19 -m src/touch_ui.nit -o $@
-android:
-bin/action_nitro.apk: $(shell ${NITLS} -M src/action_nitro.nit -m android -m src/touch_ui.nit) pre-build android/res/
- ${NITC} src/action_nitro.nit -m android -m src/touch_ui.nit -o $@
+android-release: $(shell nitls -M src/action_nitro.nit -m gamnit::android19 -m src/touch_ui.nit) pre-build android/res/
+ nitc src/action_nitro.nit -m gamnit::android19 -m src/touch_ui.nit -o bin/action_nitro.apk --release
src/gen/texts.nit: art/texts.svg
make -C ../inkscape_tools/
id="layer1"
transform="translate(-286.05811,81.477047)">
<image
- sodipodi:absref="/home/xymus/projects/nit/contrib/action_nitro/art/../assets/particles/explosion00.png"
- xlink:href="../assets/particles/explosion00.png"
+ sodipodi:absref="icon_background.png"
+ xlink:href="icon_background.png"
width="479.1073"
height="439.72864"
id="image3062"
git.directory=contrib/action_nitro/
homepage=http://nitlanguage.org
issues=https://github.com/nitlang/nit/issues
+apk=http://nitlanguage.org/fdroid/apk/action_nitro.apk
app_version(1, 0, git_revision)
android_manifest_activity """android:screenOrientation="sensorLandscape""""
- android_api_target 10
end
import gamnit::depth
# Particle effects
# Explosion particles
- var explosions = new ParticleSystem(20, explosion_program,
+ var explosions = new ParticleSystem(100, explosion_program,
new Texture("particles/explosion00.png"))
# Blood explosion particles
- var blood = new ParticleSystem(20, explosion_program,
+ var blood = new ParticleSystem(100, explosion_program,
new Texture("particles/blood07.png"))
# Smoke for the background
redef fun on_create
do
+ blood.texture.as(RootTexture).premultiply_alpha = false
+ explosions.texture.as(RootTexture).premultiply_alpha = false
+
super
show_splash_screen new Texture("textures/splash.jpg")
ui_camera.reset_height 1080.0
# Register particle systems
- particle_systems.add explosions
- particle_systems.add blood
particle_systems.add smoke
particle_systems.add clouds
+ particle_systems.add blood
+ particle_systems.add explosions
# Stars background
sprites.add stars
# Show death animation (explosion)
fun death_animation
do
- var force = 4.0
+ var force = 2.0
health = 0.0
- for i in 32.times do
+ for i in 16.times do
app.blood.add(
new Point3d[Float](center.x & force, center.y & force, center.z & force),
- (2048.0 & 4096.0) * force, 0.3 & 0.1)
+ (4096.0 & 2048.0) * force, 0.3 & 0.1)
end
end
end
super
# Particles
- app.explosions.add(center, 8192.0 * force, 0.3)
- for i in (4.0*force).to_i.times do
+ var range = 0.5 * force
+ app.explosions.add(center, 4096.0 * force, 0.3)
+ for i in (2.0*force).to_i.times do
app.explosions.add(
- new Point3d[Float](center.x & force, center.y & force/2.0, center.z & force),
- (4096.0 & 2048.0) * force, 0.3 & 0.3, 0.5.rand)
+ new Point3d[Float](center.x & range, center.y & range, center.z & range),
+ (2048.0 & 1024.0) * force, 0.3 & 0.3, 0.5.rand)
end
end
end
-redef class Int
- # Pad a number with `0`s on the left side to reach `size` digits
- private fun pad(size: Int): String
- do
- var s = to_s
- var d = size - s.length
- if d > 0 then s = "0"*d + s
- return s
- end
-end
-
# Manager to display numbers in sprite
class CounterSprites
gl_PointSize = scale / gl_Position.z * (pt+0.1);
if (pt < 0.1)
- v_color.a = pt / 0.1;
+ v_color *= pt / 0.1;
else
- v_color.a = 1.0 - pt*0.9;
+ v_color *= 1.0 - pt*0.9;
"""
end
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.5])
+ init clouds do init(4, false, [1.0*clouds_a, 1.0*clouds_a, 1.0*clouds_a, clouds_a])
+ private var clouds_a = 0.5
# Create and configure a material for the visible atmosphere
- init atmo do init(null, false, [0.0, 0.8, 1.0, 0.05])
+ init atmo do init(null, false, [0.0, 0.8*atmo_a, 1.0*atmo_a, atmo_a])
+ private var atmo_a = 0.05
redef fun draw(actor, model)
do
s += 0.05 * texture2D(tex_displace, tex_coord).r;
gl_Position = (vec4(coord.xyz * s, 1.0) * rotation + translation) * mvp;
-
}
""" @ glsl_vertex_shader
--- /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.
+
+# Variation using features from Android API 19
+#
+# Add support for `TextureAsset::premultiply_alpha = false` on Android.
+module android19 is
+ android_api_min 19
+ android_api_target 22
+end
+
+import android
+intrude import display_android
+intrude import android::load_image
+
+in "Java" `{
+ import android.graphics.Bitmap;
+ import android.graphics.BitmapFactory;
+`}
+
+redef class TextureAsset
+
+ redef fun load_bitmap(asset_manager, path)
+ do
+ var stream = asset_manager.native_assets_manager.open(path.to_java_string)
+ return new NativeBitmap.from_stream_ex(stream, premultiply_alpha)
+ end
+end
+
+redef class NativeCByteArray
+
+ # The data was not premultiplied, don't unmultiply it
+ redef fun unmultiply(w, h) do end
+end
+
+redef class NativeBitmap
+
+ # Load from `input_stream` with optional `premultiply_alpha`
+ new from_stream_ex(input_stream: NativeInputStream, premultiply_alpha: Bool) in "Java" `{
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inPremultiplied = premultiply_alpha; // API 19
+ return BitmapFactory.decodeStream(input_stream, null, opts);
+ `}
+end
super Material
# Ambient color, always visible
+ #
+ # The RGB values should be premultiplied by the alpha value.
var ambient_color: Array[Float] is writable
# Diffuse color when covered by a light source
+ #
+ # The RGB values should be premultiplied by the alpha value.
var diffuse_color: Array[Float] is writable
# Specular color affecting reflections
+ #
+ # The RGB values should be premultiplied by the alpha value.
var specular_color: Array[Float] is writable
redef fun draw(actor, model)
program.camera.uniform(app.world_camera.position.x, app.world_camera.position.y, app.world_camera.position.z)
# Colors from the material
- program.ambient_color.uniform(ambient_color[0], ambient_color[1], ambient_color[2], ambient_color[3]*actor.alpha)
- program.diffuse_color.uniform(diffuse_color[0], diffuse_color[1], diffuse_color[2], diffuse_color[3]*actor.alpha)
- program.specular_color.uniform(specular_color[0], specular_color[1], specular_color[2], specular_color[3]*actor.alpha)
+ var a = actor.alpha
+ program.ambient_color.uniform(ambient_color[0]*a, ambient_color[1]*a,
+ ambient_color[2]*a, ambient_color[3]*a)
+ program.diffuse_color.uniform(diffuse_color[0]*a, diffuse_color[1]*a,
+ diffuse_color[2]*a, diffuse_color[3]*a)
+ program.specular_color.uniform(specular_color[0]*a, specular_color[1]*a,
+ specular_color[2]*a, specular_color[3]*a)
# Execute draw
if mesh.indices.is_empty then
program.rotation.uniform new Matrix.gamnit_euler_rotation(actor.pitch, actor.yaw, actor.roll)
- program.ambient_color.uniform(ambient_color[0], ambient_color[1], ambient_color[2], ambient_color[3]*actor.alpha)
- program.diffuse_color.uniform(diffuse_color[0], diffuse_color[1], diffuse_color[2], diffuse_color[3]*actor.alpha)
- program.specular_color.uniform(specular_color[0], specular_color[1], specular_color[2], specular_color[3]*actor.alpha)
+ var a = actor.alpha
+ program.ambient_color.uniform(ambient_color[0]*a, ambient_color[1]*a,
+ ambient_color[2]*a, ambient_color[3]*a)
+ program.diffuse_color.uniform(diffuse_color[0]*a, diffuse_color[1]*a,
+ diffuse_color[2]*a, diffuse_color[3]*a)
+ program.specular_color.uniform(specular_color[0]*a, specular_color[1]*a,
+ specular_color[2]*a, specular_color[3]*a)
program.normal.array_enabled = true
program.normal.array(mesh.normals, 3)
{
if (use_texture) {
gl_FragColor = texture2D(texture0, gl_PointCoord) * v_color;
- if (gl_FragColor.a <= 0.01) discard;
} else {
gl_FragColor = v_color;
}
gl_Position = center * mvp;
gl_PointSize = scale / gl_Position.z * pt;
- if (pt > 0.8) v_color.a = (1.0-pt)/0.2;
+ if (pt > 0.8) v_color *= (1.0-pt)/0.2;
"""
end
gl_PointSize = scale / gl_Position.z * (pt+0.1);
if (pt < 0.1)
- v_color.a = pt / 0.1;
+ v_color *= pt / 0.1;
else
- v_color.a = 1.0 - pt*0.9;
+ v_color *= 1.0 - pt*0.9;
"""
end
redef class TextureAsset
+ private fun load_bitmap(asset_manager: AssetManager, path: String): NativeBitmap
+ do
+ return asset_manager.bitmap(path)
+ end
+
redef fun load_from_platform
do
jni_env.push_local_frame 4
var asset_manager = app.asset_manager
- var bmp = asset_manager.bitmap(path)
+ var bmp = load_bitmap(asset_manager, path)
if bmp.is_java_null then
error = new Error("Failed to load texture at '{path}'")
jni_env.pop_local_frame
return
end
- var buf = bmp.copy_pixels
+ var buf = bmp.copy_pixels(unmultiply=not premultiply_alpha)
loaded = true
width = bmp.width.to_f
height = bmp.height.to_f
# Enable blending
gl.capabilities.blend.enable
- glBlendFunc(gl_SRC_ALPHA, gl_ONE_MINUS_SRC_ALPHA)
+ glBlendFunc(gl_ONE, gl_ONE_MINUS_SRC_ALPHA)
# Enable depth test
gl.capabilities.depth_test.enable
}
gl_Position = (vec4(c * scale, 1.0) * rotation() + translation)* mvp;
- v_color = color;
+ v_color = vec4(color.rgb*color.a, color.a);
}
""" @ glsl_vertex_shader
end
end
-# Texture with its own pixels
+# Texture with its own pixel data
class RootTexture
super Texture
init do all_root_textures.add self
+ # Should the pixels RGB values be premultiplied by their alpha value at loading?
+ #
+ # All gamnit textures must have premultiplied alpha, it provides a better
+ # alpha blending, avoids artifacts and allows for additive blending.
+ #
+ # When at `true`, the default, pixels RGB values are premultiplied
+ # at loading. Set to `false` if pixels RGB values are already
+ # premultiplied in the source data.
+ #
+ # This value must be set before calling `load`.
+ var premultiply_alpha = true is writable
+
private fun load_from_pixels(pixels: Pointer, width, height: Int, format: GLPixelFormat)
do
var max_texture_size = glGetIntegerv(gl_MAX_TEXTURE_SIZE, 0)
return
end
+ # Premultiply alpha?
+ if premultiply_alpha and format == gl_RGBA then
+ pixels.premultiply_alpha(width, height)
+ end
+
glPixelStorei(gl_UNPACK_ALIGNEMENT, 1)
var tex = glGenTextures(1)[0]
gl_texture = tex
glHint(gl_GENERATE_MIPMAP_HINT, gl_NICEST)
glGenerateMipmap(gl_TEXTURE_2D)
+ glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_LINEAR_MIPMAP_LINEAR)
+
+ glBindTexture(gl_TEXTURE_2D, 0)
end
private fun load_checker(size: Int)
# Load all texture of this set
fun load_all do for t in self do t.load
end
+
+redef class Pointer
+ # Multiply RBG values by their alpha value
+ private fun premultiply_alpha(width, height: Int) `{
+ uint8_t *bytes = (uint8_t *)self;
+ int x, y, i = 0;
+ for(y = 0; y < height; y ++) {
+ for(x = 0; x < width; x ++) {
+ int a = bytes[i+3];
+ bytes[i ] = bytes[i ] * a / 255;
+ bytes[i+1] = bytes[i+1] * a / 255;
+ bytes[i+2] = bytes[i+2] * a / 255;
+ i += 4;
+ }
+ }
+ `}
+end