Merge: gamnit: new services and a lot of bug fixes and performance improvements
[nit.git] / lib / gamnit / dynamic_resolution.nit
index 40ea221..0219db4 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,7 @@ redef class App
 
        private var perf_clock_dynamic_resolution = new Clock is lazy
 
-       redef fun on_create
+       redef fun create_scene
        do
                super
 
@@ -64,6 +64,12 @@ redef class App
                assert error == null else print_error error
        end
 
+       redef fun on_resize(display)
+       do
+               dynamic_context.resize(display, max_dynamic_resolution_ratio)
+               super
+       end
+
        # Prepare to draw to the dynamic screen if `dynamic_resolution_ratio != 1.0`
        protected fun frame_core_dynamic_resolution_before(display: GamnitDisplay)
        do
@@ -73,6 +79,7 @@ redef class App
                        # Draw directly to the screen framebuffer
                        glBindFramebuffer(gl_FRAMEBUFFER, dynamic_context.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
@@ -81,13 +88,14 @@ redef class App
 
                # 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)
 
+               glClear gl_COLOR_BUFFER_BIT | gl_DEPTH_BUFFER_BIT
+
                var gl_error = glGetError
                assert gl_error == gl_NO_ERROR else print_error gl_error
        end
@@ -128,7 +136,11 @@ redef class App
 
                # Draw
                glDrawArrays(gl_TRIANGLE_STRIP, 0, 4)
+               gl_error = glGetError
+               assert gl_error == gl_NO_ERROR else print_error gl_error
 
+               # Take down
+               glBindBuffer(gl_ARRAY_BUFFER, 0)
                gl_error = glGetError
                assert gl_error == gl_NO_ERROR else print_error gl_error
 
@@ -151,7 +163,7 @@ 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
@@ -169,16 +181,11 @@ 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
@@ -188,34 +195,19 @@ private class DynamicContext
                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
 
-               # 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
-
-               var gl_error = glGetError
+               gl_error = glGetError
                assert gl_error == gl_NO_ERROR else print_error gl_error
-               assert glCheckFramebufferStatus(gl_FRAMEBUFFER) == gl_FRAMEBUFFER_COMPLETE
 
-               # Take down
-               glBindRenderbuffer(gl_RENDERBUFFER, 0)
-               glBindFramebuffer(gl_FRAMEBUFFER, 0)
+               resize(display, max_dynamic_resolution_ratio)
+               assert glCheckFramebufferStatus(gl_FRAMEBUFFER) == gl_FRAMEBUFFER_COMPLETE
 
                # Array buffer
                buffer_array = glGenBuffers(1).first
@@ -244,6 +236,46 @@ private class DynamicContext
                assert gl_error == gl_NO_ERROR else print_error gl_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)
+               var gl_error = glGetError
+               assert gl_error == gl_NO_ERROR else print_error gl_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)
+
+               gl_error = glGetError
+               assert gl_error == gl_NO_ERROR else print_error gl_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
+       end
+
        var destroyed = false
        fun destroy
        do