gamnit :: SpriteContext :: draw
sprites
Call resize
and update_sprite
as needed before actual draw operation.
Require: app.simple_2d_program
and mvp
must be bound on the GPU
# Draw all `sprites`
#
# Call `resize` and `update_sprite` as needed before actual draw operation.
#
# Require: `app.simple_2d_program` and `mvp` must be bound on the GPU
fun draw
do
if buffer_array == -1 then prepare
assert buffer_array > 0 and buffer_element > 0 else
print_error "Internal error: {self} was destroyed"
end
# Setup
glBindBuffer(gl_ARRAY_BUFFER, buffer_array)
glBindBuffer(gl_ELEMENT_ARRAY_BUFFER, buffer_element)
# Resize GPU buffers?
var update_everything = false
if sprites.capacity > buffer_capacity then
# Try to defragment first
var moved = sprites.defragment
if sprites.capacity > buffer_capacity then
# Defragmentation wasn't enough, grow
resize
# We must update everything
update_everything = true
for s in sprites.items do if s != null then sprites_to_update.add s
else
# Just update the moved sprites
for s in moved do sprites_to_update.add s
end
else if sprites.available.not_empty then
# Defragment a bit anyway
# TODO defrag only when there's time left on a frame
var moved = sprites.defragment(1)
for s in moved do sprites_to_update.add s
end
# Update GPU sprites data
if sprites_to_update.not_empty or update_everything then
app.perf_clock_sprites.lapse
if update_everything then
for sprite in sprites.items do if sprite != null then
update_sprite(sprite)
end
else
for sprite in sprites_to_update do update_sprite(sprite)
end
sprites_to_update.clear
last_sprite_to_update = null
sys.perfs["gamnit flat gpu update"].add app.perf_clock_sprites.lapse
end
# Update uniforms specific to this context
var texture = texture
app.simple_2d_program.use_texture.uniform texture != null
if texture != null then
glActiveTexture gl_TEXTURE0
glBindTexture(gl_TEXTURE_2D, texture.gl_texture)
app.simple_2d_program.texture.uniform 0
end
assert glGetError == gl_NO_ERROR
var animation = animation_texture
if animation != null then
glActiveTexture gl_TEXTURE1
glBindTexture(gl_TEXTURE_2D, animation.gl_texture)
app.simple_2d_program.animation_texture.uniform 1
end
assert glGetError == gl_NO_ERROR
# Configure attributes, in order:
# vec4 translation, vec4 color, float scale, vec4 coord, vec2 tex_coord, vec4 rotation_row*,
# a_fps, a_n_frames, a_coord, a_tex_coord, a_tex_diff, a_start, a_loops
var offset = 0
var p = app.simple_2d_program
var sizeof_gl_float = 4 # sizeof(GL_FLOAT)
var size = 4 # Number of floats
glEnableVertexAttribArray p.translation.location
glVertexAttribPointeri(p.translation.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
offset += size * sizeof_gl_float
assert glGetError == gl_NO_ERROR
size = 4
glEnableVertexAttribArray p.color.location
glVertexAttribPointeri(p.color.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
offset += size * sizeof_gl_float
assert glGetError == gl_NO_ERROR
size = 1
glEnableVertexAttribArray p.scale.location
glVertexAttribPointeri(p.scale.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
offset += size * sizeof_gl_float
assert glGetError == gl_NO_ERROR
size = 4
glEnableVertexAttribArray p.coord.location
glVertexAttribPointeri(p.coord.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
offset += size * sizeof_gl_float
assert glGetError == gl_NO_ERROR
size = 2
glEnableVertexAttribArray p.tex_coord.location
glVertexAttribPointeri(p.tex_coord.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
offset += size * sizeof_gl_float
assert glGetError == gl_NO_ERROR
size = 4
for r in [p.rotation_row0, p.rotation_row1, p.rotation_row2, p.rotation_row3] do
if r.is_active then
glEnableVertexAttribArray r.location
glVertexAttribPointeri(r.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
end
offset += size * sizeof_gl_float
assert glGetError == gl_NO_ERROR
end
size = 1
glEnableVertexAttribArray p.animation_fps.location
glVertexAttribPointeri(p.animation_fps.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
offset += size * sizeof_gl_float
assert glGetError == gl_NO_ERROR
size = 1
glEnableVertexAttribArray p.animation_n_frames.location
glVertexAttribPointeri(p.animation_n_frames.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
offset += size * sizeof_gl_float
assert glGetError == gl_NO_ERROR
size = 2
glEnableVertexAttribArray p.animation_coord.location
glVertexAttribPointeri(p.animation_coord.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
offset += size * sizeof_gl_float
assert glGetError == gl_NO_ERROR
size = 2
glEnableVertexAttribArray p.animation_tex_coord.location
glVertexAttribPointeri(p.animation_tex_coord.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
offset += size * sizeof_gl_float
assert glGetError == gl_NO_ERROR
size = 2
glEnableVertexAttribArray p.animation_tex_diff.location
glVertexAttribPointeri(p.animation_tex_diff.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
offset += size * sizeof_gl_float
assert glGetError == gl_NO_ERROR
size = 1
glEnableVertexAttribArray p.animation_start.location
glVertexAttribPointeri(p.animation_start.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
offset += size * sizeof_gl_float
assert glGetError == gl_NO_ERROR
size = 1
glEnableVertexAttribArray p.animation_loops.location
glVertexAttribPointeri(p.animation_loops.location, size, gl_FLOAT, false, bytes_per_vertex, offset)
offset += size * sizeof_gl_float
assert glGetError == gl_NO_ERROR
# Actual draw
for s in sprites.starts, e in sprites.ends do
var l = e-s
glDrawElementsi(gl_TRIANGLES, l*indices_per_sprite, gl_UNSIGNED_SHORT, 2*s*indices_per_sprite)
assert glGetError == gl_NO_ERROR
end
# Take down
for attr in [p.translation, p.color, p.scale, p.coord, p.tex_coord,
p.rotation_row0, p.rotation_row1, p.rotation_row2, p.rotation_row3: Attribute] do
if not attr.is_active then continue
glDisableVertexAttribArray(attr.location)
assert glGetError == gl_NO_ERROR
end
glBindBuffer(gl_ARRAY_BUFFER, 0)
glBindBuffer(gl_ELEMENT_ARRAY_BUFFER, 0)
assert glGetError == gl_NO_ERROR
end
lib/gamnit/flat/flat_core.nit:1292,2--1477,4