lib/core/stream: LineIterator use CachedIterator
[nit.git] / lib / gamnit / dynamic_resolution.nit
index e7c2def..2c6a4c8 100644 (file)
@@ -42,7 +42,7 @@ redef class App
        #
        # 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
@@ -54,7 +54,21 @@ redef class App
 
        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
 
@@ -62,6 +76,14 @@ redef class App
                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`
@@ -71,12 +93,11 @@ redef class App
 
                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
 
@@ -90,8 +111,7 @@ redef class App
 
                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
        end
 
        # Draw the dynamic screen to the real screen if `dynamic_resolution_ratio != 1.0`
@@ -103,7 +123,7 @@ redef class App
                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
@@ -125,20 +145,31 @@ redef class App
                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
@@ -153,12 +184,9 @@ redef class App
        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
 
@@ -171,60 +199,33 @@ private class DynamicContext
        # 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]
@@ -242,8 +243,44 @@ private class DynamicContext
 
                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
@@ -254,8 +291,7 @@ private class DynamicContext
 
                # 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