android & benitlux: use NitObject in clients
[nit.git] / lib / gamnit / dynamic_resolution.nit
index 5af305c..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,11 +76,13 @@ 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
-               dynamic_context.resize(display, max_dynamic_resolution_ratio)
+               if dynamic_context_cache != null then dynamic_context.resize(display, max_dynamic_resolution_ratio)
                super
        end
 
@@ -77,25 +93,25 @@ 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
 
                # 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`
@@ -107,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
@@ -129,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
@@ -157,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
 
@@ -175,32 +199,24 @@ 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.
 
-               # 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
-               var gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
 
                # Depth & texture/color
                var depthbuffer = glGenRenderbuffers(1).first
                self.depth_renderbuffer = depthbuffer
                var texture = glGenTextures(1).first
                self.texture = texture
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
 
                resize(display, max_dynamic_resolution_ratio)
                assert glCheckFramebufferStatus(gl_FRAMEBUFFER) == gl_FRAMEBUFFER_COMPLETE
@@ -209,8 +225,7 @@ private class DynamicContext
                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]
@@ -228,8 +243,7 @@ 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`
@@ -246,10 +260,9 @@ private class DynamicContext
                # Depth
                glBindRenderbuffer(gl_RENDERBUFFER, depthbuffer)
                assert glIsRenderbuffer(depthbuffer)
-               glRenderbufferStorage(gl_RENDERBUFFER, gl_DEPTH_COMPNENT16, width, height)
+               glRenderbufferStorage(gl_RENDERBUFFER, gl_DEPTH_COMPONENT16, width, height)
                glFramebufferRenderbuffer(gl_FRAMEBUFFER, gl_DEPTH_ATTACHMENT, gl_RENDERBUFFER, depthbuffer)
-               var gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
 
                # Texture
                glBindTexture(gl_TEXTURE_2D, texture)
@@ -261,15 +274,13 @@ private class DynamicContext
                             0, gl_RGB, gl_UNSIGNED_BYTE, new Pointer.nul)
                glFramebufferTexture2D(gl_FRAMEBUFFER, gl_COLOR_ATTACHMENT0, gl_TEXTURE_2D, texture, 0)
 
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
 
                # Take down
                glBindRenderbuffer(gl_RENDERBUFFER, 0)
                glBindFramebuffer(gl_FRAMEBUFFER, 0)
 
-               gl_error = glGetError
-               assert gl_error == gl_NO_ERROR else print_error gl_error
+               assert glGetError == gl_NO_ERROR
        end
 
        var destroyed = false
@@ -280,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