#
# This value is applied to both X and Y, so it has an exponential effect on
# the number of pixels.
- var dynamic_resolution_ratio = 1.0
+ var dynamic_resolution_ratio = 1.0 is writable
# Minimum dynamic screen resolution
var min_dynamic_resolution_ratio = 0.0125 is writable
private var perf_clock_dynamic_resolution = new Clock is lazy
- redef fun on_create
+ # Real screen framebuffer
+ private var screen_framebuffer_cache: Int = -1
+
+ # Real screen framebuffer name
+ fun screen_framebuffer: Int
+ do
+ var cache = screen_framebuffer_cache
+ if cache != -1 then return cache
+
+ cache = glGetIntegerv(gl_FRAMEBUFFER_BINDING, 0)
+ self.screen_framebuffer_cache = cache
+ return cache
+ end
+
+ redef fun create_gamnit
do
super
program.compile_and_link
var error = program.error
assert error == null else print_error error
+
+ dynamic_context_cache = null
+ end
+
+ redef fun on_resize(display)
+ do
+ if dynamic_context_cache != null then dynamic_context.resize(display, max_dynamic_resolution_ratio)
+ super
end
# Prepare to draw to the dynamic screen if `dynamic_resolution_ratio != 1.0`
if dynamic_resolution_ratio == 1.0 then
# Draw directly to the screen framebuffer
- glBindFramebuffer(gl_FRAMEBUFFER, dynamic_context.screen_framebuffer)
+ bind_screen_framebuffer screen_framebuffer
glViewport(0, 0, display.width, display.height)
+ glClear gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT
- var gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print_error gl_error
+ assert glGetError == gl_NO_ERROR
return
end
# Draw to our dynamic framebuffer
glBindFramebuffer(gl_FRAMEBUFFER, dynamic_context.dynamic_framebuffer)
- glClear gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT
var ratio = dynamic_resolution_ratio
ratio = ratio.clamp(min_dynamic_resolution_ratio, max_dynamic_resolution_ratio)
glViewport(0, 0, (display.width.to_f*ratio).to_i,
(display.height.to_f*ratio).to_i)
- var gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print_error gl_error
+ glClear gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT
+
+ assert glGetError == gl_NO_ERROR
end
# Draw the dynamic screen to the real screen if `dynamic_resolution_ratio != 1.0`
var ratio = dynamic_resolution_ratio
ratio = ratio.clamp(min_dynamic_resolution_ratio, max_dynamic_resolution_ratio)
- glBindFramebuffer(gl_FRAMEBUFFER, dynamic_context.screen_framebuffer)
+ bind_screen_framebuffer screen_framebuffer
glBindBuffer(gl_ARRAY_BUFFER, dynamic_context.buffer_array)
glViewport(0, 0, display.width, display.height)
glClear gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT
n_floats = 2
glEnableVertexAttribArray dynres_program.tex_coord.location
glVertexAttribPointeri(dynres_program.tex_coord.location, n_floats, gl_FLOAT, false, 0, offset)
- var gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print_error gl_error
+ assert glGetError == gl_NO_ERROR
# Draw
glDrawArrays(gl_TRIANGLE_STRIP, 0, 4)
+ assert glGetError == gl_NO_ERROR
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print_error gl_error
+ # Take down
+ glBindBuffer(gl_ARRAY_BUFFER, 0)
+ assert glGetError == gl_NO_ERROR
sys.perfs["gamnit flat dyn res"].add app.perf_clock_dynamic_resolution.lapse
end
# Framebuffer and texture for dynamic resolution intermediate drawing
- private var dynamic_context: DynamicContext = create_dynamic_context is lazy
+ private fun dynamic_context: DynamicContext
+ do
+ var cache = dynamic_context_cache
+ if cache != null then return cache
+
+ cache = create_dynamic_context
+ dynamic_context_cache = cache
+ return cache
+ end
+
+ private var dynamic_context_cache: nullable DynamicContext = null
private fun create_dynamic_context: DynamicContext
do
end
end
-# Program drawing the dynamic screen to the real screen
+# Handles to reused GL buffers and texture
private class DynamicContext
- # Real screen framebuffer
- var screen_framebuffer: Int = -1
-
# Dynamic screen framebuffer
var dynamic_framebuffer: Int = -1
# Buffer name for vertex data
var buffer_array: Int = -1
- var float_per_vertex: Int is lazy do return 4 + 4 + 3
-
# Prepare all attributes once per resolution change
fun prepare_once(display: GamnitDisplay, max_dynamic_resolution_ratio: Float)
do
# TODO enable antialiasing.
- var width = (display.width.to_f * max_dynamic_resolution_ratio).to_i
- var height = (display.height.to_f * max_dynamic_resolution_ratio).to_i
-
- # Set aside the real screen framebuffer name
- var screen_framebuffer = glGetIntegerv(gl_FRAMEBUFFER_BINDING, 0)
- self.screen_framebuffer = screen_framebuffer
-
# Framebuffer
var framebuffer = glGenFramebuffers(1).first
glBindFramebuffer(gl_FRAMEBUFFER, framebuffer)
assert glIsFramebuffer(framebuffer)
self.dynamic_framebuffer = framebuffer
+ assert glGetError == gl_NO_ERROR
- # Depth
+ # Depth & texture/color
var depthbuffer = glGenRenderbuffers(1).first
- glBindRenderbuffer(gl_RENDERBUFFER, depthbuffer)
- assert glIsRenderbuffer(depthbuffer)
- glRenderbufferStorage(gl_RENDERBUFFER, gl_DEPTH_COMPNENT16, width, height)
- glFramebufferRenderbuffer(gl_FRAMEBUFFER, gl_DEPTH_ATTACHMENT, gl_RENDERBUFFER, depthbuffer)
self.depth_renderbuffer = depthbuffer
-
- # Texture
var texture = glGenTextures(1).first
- glBindTexture(gl_TEXTURE_2D, texture)
- glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_LINEAR)
- glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_LINEAR)
- glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_S, gl_CLAMP_TO_EDGE)
- glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_T, gl_CLAMP_TO_EDGE)
- glTexImage2D(gl_TEXTURE_2D, 0, gl_RGB, width, height,
- 0, gl_RGB, gl_UNSIGNED_BYTE, new Pointer.nul)
- glFramebufferTexture2D(gl_FRAMEBUFFER, gl_COLOR_ATTACHMENT0, gl_TEXTURE_2D, texture, 0)
self.texture = texture
+ assert glGetError == gl_NO_ERROR
- var gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print_error gl_error
+ resize(display, max_dynamic_resolution_ratio)
assert glCheckFramebufferStatus(gl_FRAMEBUFFER) == gl_FRAMEBUFFER_COMPLETE
- # Take down
- glBindRenderbuffer(gl_RENDERBUFFER, 0)
- glBindFramebuffer(gl_FRAMEBUFFER, 0)
-
# Array buffer
buffer_array = glGenBuffers(1).first
glBindBuffer(gl_ARRAY_BUFFER, buffer_array)
assert glIsBuffer(buffer_array)
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print_error gl_error
+ assert glGetError == gl_NO_ERROR
## coord
var data = new Array[Float]
glBindBuffer(gl_ARRAY_BUFFER, 0)
- gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print_error gl_error
+ assert glGetError == gl_NO_ERROR
+ end
+
+ # Init size or resize `depth_renderbuffer` and `texture`
+ fun resize(display: GamnitDisplay, max_dynamic_resolution_ratio: Float)
+ do
+ var width = (display.width.to_f * max_dynamic_resolution_ratio).to_i
+ var height = (display.height.to_f * max_dynamic_resolution_ratio).to_i
+
+ glBindFramebuffer(gl_FRAMEBUFFER, dynamic_framebuffer)
+
+ var depthbuffer = self.depth_renderbuffer
+ var texture = self.texture
+
+ # Depth
+ glBindRenderbuffer(gl_RENDERBUFFER, depthbuffer)
+ assert glIsRenderbuffer(depthbuffer)
+ glRenderbufferStorage(gl_RENDERBUFFER, gl_DEPTH_COMPONENT16, width, height)
+ glFramebufferRenderbuffer(gl_FRAMEBUFFER, gl_DEPTH_ATTACHMENT, gl_RENDERBUFFER, depthbuffer)
+ assert glGetError == gl_NO_ERROR
+
+ # Texture
+ glBindTexture(gl_TEXTURE_2D, texture)
+ glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_LINEAR)
+ glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_LINEAR)
+ glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_S, gl_CLAMP_TO_EDGE)
+ glTexParameteri(gl_TEXTURE_2D, gl_TEXTURE_WRAP_T, gl_CLAMP_TO_EDGE)
+ glTexImage2D(gl_TEXTURE_2D, 0, gl_RGB, width, height,
+ 0, gl_RGB, gl_UNSIGNED_BYTE, new Pointer.nul)
+ glFramebufferTexture2D(gl_FRAMEBUFFER, gl_COLOR_ATTACHMENT0, gl_TEXTURE_2D, texture, 0)
+
+ assert glGetError == gl_NO_ERROR
+
+ # Take down
+ glBindRenderbuffer(gl_RENDERBUFFER, 0)
+ glBindFramebuffer(gl_FRAMEBUFFER, 0)
+
+ assert glGetError == gl_NO_ERROR
end
var destroyed = false
# Free the buffer
glDeleteBuffers([buffer_array])
- var gl_error = glGetError
- assert gl_error == gl_NO_ERROR else print_error gl_error
+ assert glGetError == gl_NO_ERROR
buffer_array = -1
# Free the dynamic framebuffer and its attachments