redef fun draw(actor, model, camera)
do
- var program = app.versatile_program
+ var program = app.blinn_phong_program
program.use
program.mvp.uniform camera.mvp_matrix
var mesh = model.mesh
# Actor specs
+ glDisableVertexAttribArray program.translation.location
+ glDisableVertexAttribArray program.scale.location
+
program.translation.uniform(actor.center.x, actor.center.y, actor.center.z, 0.0)
program.scale.uniform actor.scale
- program.rotation.uniform new Matrix.gamnit_euler_rotation(actor.pitch, actor.yaw, actor.roll)
+ program.alpha.uniform actor.alpha
+ program.rotation = new Matrix.gamnit_euler_rotation(actor.pitch, actor.yaw, actor.roll)
# From mesh
program.coord.array_enabled = true
program.camera.uniform(camera.position.x, camera.position.y, camera.position.z)
# Colors from the material
- 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.ambient_color.uniform(ambient_color[0], ambient_color[1],
+ ambient_color[2], ambient_color[3])
+ program.diffuse_color.uniform(diffuse_color[0], diffuse_color[1],
+ diffuse_color[2], diffuse_color[3])
+ program.specular_color.uniform(specular_color[0], specular_color[1],
+ specular_color[2], specular_color[3])
- setup_lights(actor, model, camera, program)
+ setup_lights(camera, program)
# Execute draw
if mesh.indices.is_empty then
else
glDrawElements(mesh.draw_mode, mesh.indices.length, gl_UNSIGNED_SHORT, mesh.indices_c.native_array)
end
+
+ assert glGetError == gl_NO_ERROR
end
- private fun setup_lights(actor: Actor, model: LeafModel, camera: Camera, program: BlinnPhongProgram)
+ private fun setup_lights(camera: Camera, program: BlinnPhongProgram)
do
# TODO use a list of lights
do
var mesh = model.mesh
- var program = app.versatile_program
+ var program = app.blinn_phong_program
program.use
# One of the textures used, if any
program.use_map_bump.uniform false
end
+ glDisableVertexAttribArray program.translation.location
+ glDisableVertexAttribArray program.scale.location
+
program.mvp.uniform camera.mvp_matrix
program.translation.uniform(actor.center.x, actor.center.y, actor.center.z, 0.0)
program.scale.uniform actor.scale
+ program.alpha.uniform actor.alpha
# If using a texture, set `texture_coords`
program.tex_coord.array_enabled = sample_used_texture != null
program.coord.array_enabled = true
program.coord.array(mesh.vertices, 3)
- program.rotation.uniform new Matrix.gamnit_euler_rotation(actor.pitch, actor.yaw, actor.roll)
+ program.rotation = new Matrix.gamnit_euler_rotation(actor.pitch, actor.yaw, actor.roll)
- 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.ambient_color.uniform(ambient_color[0], ambient_color[1],
+ ambient_color[2], ambient_color[3])
+ program.diffuse_color.uniform(diffuse_color[0], diffuse_color[1],
+ diffuse_color[2], diffuse_color[3])
+ program.specular_color.uniform(specular_color[0], specular_color[1],
+ specular_color[2], specular_color[3])
program.normal.array_enabled = true
program.normal.array(mesh.normals, 3)
# Light
- setup_lights(actor, model, camera, program)
+ setup_lights(camera, program)
# Camera
program.camera.uniform(camera.position.x, camera.position.y, camera.position.z)
program.coord.array_enabled = true
program.coord.array(mesh.vertices, 3)
- program.rotation.uniform new Matrix.gamnit_euler_rotation(actor.pitch, actor.yaw, actor.roll)
+ program.rotation = new Matrix.gamnit_euler_rotation(actor.pitch, actor.yaw, actor.roll)
program.normal.array_enabled = true
program.normal.array(mesh.normals, 3)
attribute vec4 coord;
// Vertex translation
- uniform vec4 translation;
+ attribute vec4 translation;
// Vertex scaling
- uniform float scale;
+ attribute float scale;
+
+ attribute float alpha;
// Vertex coordinates on textures
attribute vec2 tex_coord;
// Camera model view projection matrix
uniform mat4 mvp;
- uniform mat4 rotation;
+ // Actor rotation
+ attribute vec4 rotation_row0;
+ attribute vec4 rotation_row1;
+ attribute vec4 rotation_row2;
+ attribute vec4 rotation_row3;
+
+ mat4 rotation()
+ {
+ return mat4(rotation_row0, rotation_row1, rotation_row2, rotation_row3);
+ }
// Lights config
uniform lowp int light_kind;
varying vec4 v_to_light;
varying vec4 v_to_camera;
varying vec4 v_depth_pos;
+ varying float v_alpha;
void main()
{
+ mat4 rotation = rotation();
vec4 pos = (vec4(coord.xyz * scale, 1.0) * rotation + translation);
gl_Position = pos * mvp;
v_depth_pos = (pos * light_mvp) * 0.5 + 0.5;
// Point light (and others?)
v_to_light = normalize(vec4(light_center, 1.0) - pos);
}
+
+ v_alpha = alpha;
}
""" @ glsl_vertex_shader
varying vec4 v_to_light;
varying vec4 v_to_camera;
varying vec4 v_depth_pos;
+ varying float v_alpha;
// Colors
uniform vec4 ambient_color;
uniform lowp int light_kind;
uniform bool use_shadows;
uniform sampler2D depth_texture;
- uniform float depth_texture_size;
- uniform int depth_texture_taps;
+ uniform float depth_size;
+ uniform int depth_taps;
// Shadow effect on the diffuse colors of the fragment at offset `x, y`
float shadow_lookup(vec2 depth_coord, float x, float y) {
float tap_width = 1.0;
- float pixel_size = tap_width/depth_texture_size;
+ float pixel_size = tap_width/depth_size;
vec2 offset = vec2(x * pixel_size * v_depth_pos.w,
y * pixel_size * v_depth_pos.w);
vec2 depth_coord = v_depth_pos.xy/v_depth_pos.w;
- float taps = float(depth_texture_taps);
+ float taps = float(depth_taps);
float tap_step = 2.00/taps;
float sum = 0.0;
for (float x = -1.0; x <= 0.99; x += tap_step)
}
// Ambient light
- vec4 ambient = ambient_color;
+ vec4 ambient = ambient_color * v_alpha;
if (use_map_ambient) ambient *= texture2D(map_ambient, v_tex_coord);
if (light_kind == 0) {
// No light, show diffuse and ambient
- vec4 diffuse = diffuse_color;
+ vec4 diffuse = diffuse_color * v_alpha;
if (use_map_diffuse) diffuse *= texture2D(map_diffuse, v_tex_coord);
gl_FragColor = ambient + diffuse;
diffuse *= shadow();
}
- vec4 specular = s * specular_color;
+ vec4 specular = s * specular_color * v_alpha;
if (use_map_specular) specular *= texture2D(map_specular, v_tex_coord).x;
gl_FragColor = ambient + diffuse + specular;
var depth_texture = uniforms["depth_texture"].as(UniformSampler2D) is lazy
# Size, in pixels, of `depth_texture`
- var depth_texture_size = uniforms["depth_texture_size"].as(UniformFloat) is lazy
+ var depth_texture_size = uniforms["depth_size"].as(UniformFloat) is lazy
# Times to tap the `depth_texture`, square root (set to 3 for a total of 9 taps)
- var depth_texture_taps = uniforms["depth_texture_taps"].as(UniformInt) is lazy
+ var depth_texture_taps = uniforms["depth_taps"].as(UniformInt) is lazy
# Camera position
var camera = uniforms["camera"].as(UniformVec3) is lazy
# Translation applied to each vertex
- var translation = uniforms["translation"].as(UniformVec4) is lazy
+ var translation = attributes["translation"].as(AttributeVec4) is lazy # TODO attribute
- # Rotation matrix
- var rotation = uniforms["rotation"].as(UniformMat4) is lazy
+ # Set `mat` at the uniform rotation matrix
+ fun rotation=(mat: Matrix)
+ do
+ var i = 0
+ for r in [rotation_row0, rotation_row1, rotation_row2, rotation_row3] do
+ if r.is_active then
+ glDisableVertexAttribArray r.location
+ r.uniform(mat[0, i], mat[1, i], mat[2, i], mat[3, i])
+ end
+ i += 1
+ end
+ var gl_error = glGetError
+ assert gl_error == gl_NO_ERROR else print_error gl_error
+ end
+
+ # Rotation matrix, row0
+ var rotation_row0 = attributes["rotation_row0"].as(AttributeVec4) is lazy
+
+ # Rotation matrix, row 1
+ var rotation_row1 = attributes["rotation_row1"].as(AttributeVec4) is lazy
+
+ # Rotation matrix, row 2
+ var rotation_row2 = attributes["rotation_row2"].as(AttributeVec4) is lazy
+
+ # Rotation matrix, row 3
+ var rotation_row3 = attributes["rotation_row3"].as(AttributeVec4) is lazy
+
+ # Scaling per vertex
+ var scale = attributes["scale"].as(AttributeFloat) is lazy
# Scaling per vertex
- var scale = uniforms["scale"].as(UniformFloat) is lazy
+ var alpha = attributes["alpha"].as(AttributeFloat) is lazy
# Camera model view projection matrix
var mvp = uniforms["mvp"].as(UniformMat4) is lazy
end
redef class App
- private var versatile_program = new BlinnPhongProgram is lazy
+ private var blinn_phong_program = new BlinnPhongProgram is lazy
private var normals_program = new NormalProgram is lazy
end
var texture: Texture is writable(texture_direct=)
# Texture drawn to screen
- fun texture=(value: Texture)
+ fun texture=(texture: Texture)
do
- if isset _texture and value != texture then
+ if isset _texture and texture != self.texture then
needs_update
- if value.root != texture.root then needs_remap
+ if texture.root != self.texture.root then needs_remap
end
- texture_direct = value
+ texture_direct = texture
end
# Center position of this sprite in world coordinates
var center: Point3d[Float] is writable(center_direct=), noautoinit
# Center position of this sprite in world coordinates
- fun center=(value: Point3d[Float]) is autoinit do
- if isset _center and value != center then
+ fun center=(center: Point3d[Float]) is autoinit do
+ if isset _center and center != self.center then
needs_update
- center.sprites_remove self
+ self.center.sprites_remove self
end
- value.sprites_add self
- center_direct = value
+ center.sprites_add self
+ center_direct = center
end
# Last animation set with `animate`
# Second performance clock for smaller operations
private var perf_clock_sprites = new Clock is lazy
- redef fun on_create
+ redef fun create_gamnit
do
super
+ create_flat
+ end
+ # Prepare the flat framework services
+ fun create_flat
+ do
var display = display
assert display != null
glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_LINEAR)
glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_LINEAR)
end
+
+ sprites.reset
+ ui_sprites.reset
end
redef fun on_stop
do
+ super
+
# Clean up
simple_2d_program.delete
# draw
sprite_set.draw
+
+ assert glGetError == gl_NO_ERROR
end
# Draw world sprites from `sprites`
for sprite in sprites_to_remap do
# Skip if it was removed from this set after being modified
- if sprite.context != self then continue
+ if sprite.sprite_set != self then continue
unmap_sprite sprite
map_sprite sprite
for c in contexts_items do c.destroy
contexts_map.clear
contexts_items.clear
+ sprites_to_remap.clear
+ end
+
+ private fun reset
+ do
+ for sprite in self do
+ sprite.context = null
+ end
+
+ for c in contexts_items do c.destroy
+ contexts_map.clear
+ contexts_items.clear
+ sprites_to_remap.clear
+
+ for sprite in self do
+ map_sprite sprite
+ end
end
end
redef class GLfloatArray
private fun fill_from_matrix(matrix: Matrix, dst_offset: nullable Int)
do
- dst_offset = dst_offset or else 0
+ dst_offset = dst_offset or else add_index
var mat_len = matrix.width*matrix.height
assert length >= mat_len + dst_offset
native_array.fill_from_matrix_native(matrix.items, dst_offset, mat_len)
+ add_index += mat_len
end
end
# Texture composed of pixels, loaded from the assets folder by default
#
# Most textures should be created with `App` (as attributes)
-# for the method `on_create` to load them.
+# for the method `create_scene` to load them.
#
# ~~~
# import gamnit::flat
# # Create the texture object, it will be loaded automatically
# var texture = new Texture("path/in/assets.png")
#
-# redef fun on_create()
+# redef fun create_scene()
# do
-# # Let `on_create` load the texture
+# # Let `create_scene` load the texture
# super
#
# # Use the texture
# end
# ~~~
#
-# Otherwise, they can be loaded and error checked explicitly after `on_create`.
+# Otherwise, they can be loaded and error checked explicitly after `create_scene`.
#
# ~~~nitish
# var texture = new Texture("path/in/assets.png")
# The argument `color` should be an array of up to 4 floats (RGBA).
# If `color` has less than 4 items, the missing items are replaced by 1.0.
#
- # Require: `not loaded and x < width.to_i and y < height.to_i`
+ # Require: `x < width.to_i and y < height.to_i`
fun []=(x, y: Int, color: Array[Float])
do
- assert not loaded else print_error "{class_name}::[]= already loaded"
assert x < width.to_i and y < height.to_i else print_error "{class_name}::[] out of bounds"
# Simple conversion from [0.0..1.0] to [0..255]
var offset = 4*(x + y*width.to_i)
for i in [0..4[ do cpixels[offset+i] = bytes[i]
+
+ loaded = false
end
# Overwrite all pixels with `color`, return `self`
#
# The argument `color` should be an array of up to 4 floats (RGBA).
# If `color` has less than 4 items, the missing items are replaced by 1.0.
- #
- # Require: `not loaded`
fun fill(color: Array[Float]): SELF
do
- assert not loaded else print_error "{class_name}::fill already loaded"
-
# Simple conversion from [0.0..1.0] to [0..255]
var bytes = [for c in color do (c*255.0).round.to_i.clamp(0, 255).to_bytes.last]
while bytes.length < 4 do bytes.add 255u8
end
end
+ loaded = false
return self
end
redef fun load(force)
do
- if loaded then return
+ force = force or else false
+ if loaded and not force then return
+
+ if force and glIsTexture(gl_texture) then
+ # Was already loaded, free the previous GL name
+ glDeleteTextures([gl_texture])
+ end
+ gl_texture = -1
# Round down the desired dimension
var width = width.to_i
load_from_pixels(cpixels.native_array, width, height, gl_RGBA)
- cpixels.destroy
loaded = true
end
end
# Parent texture, from which this texture was created
var parent: Texture
- redef var root = parent.root is lateinit
+ redef fun root do return parent.root
redef fun load(force) do root.load(force)
end
end
redef class Pointer
- # Multiply RBG values by their alpha value
+ # Multiply RGB values by their alpha value
private fun premultiply_alpha(width, height: Int) `{
uint8_t *bytes = (uint8_t *)self;
int x, y, i = 0;