├── input └── game.input_binding ├── assets ├── mockup.png ├── result.png ├── soft_light.png ├── soft_light_small.png ├── game.atlas └── lights.atlas ├── main ├── our.render ├── light.vp ├── light.fp ├── light.material ├── quad.fp ├── quad.vp ├── quad.material ├── main.collection └── our.render_script ├── .gitignore ├── game.project ├── README.md ├── LICENSE.md └── .gitattributes /input/game.input_binding: -------------------------------------------------------------------------------- 1 | mouse_trigger { 2 | input: MOUSE_BUTTON_1 3 | action: "touch" 4 | } 5 | -------------------------------------------------------------------------------- /assets/mockup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paweljarosz/unfolding_simple_lighting/HEAD/assets/mockup.png -------------------------------------------------------------------------------- /assets/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paweljarosz/unfolding_simple_lighting/HEAD/assets/result.png -------------------------------------------------------------------------------- /assets/soft_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paweljarosz/unfolding_simple_lighting/HEAD/assets/soft_light.png -------------------------------------------------------------------------------- /assets/soft_light_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paweljarosz/unfolding_simple_lighting/HEAD/assets/soft_light_small.png -------------------------------------------------------------------------------- /main/our.render: -------------------------------------------------------------------------------- 1 | script: "/main/our.render_script" 2 | materials { 3 | name: "lighting_quad" 4 | material: "/main/quad.material" 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.internal 2 | /build 3 | .externalToolBuilders 4 | .DS_Store 5 | Thumbs.db 6 | .lock-wscript 7 | *.pyc 8 | .project 9 | .cproject 10 | builtins -------------------------------------------------------------------------------- /assets/game.atlas: -------------------------------------------------------------------------------- 1 | images { 2 | image: "/assets/mockup.png" 3 | sprite_trim_mode: SPRITE_TRIM_MODE_OFF 4 | } 5 | margin: 0 6 | extrude_borders: 2 7 | inner_padding: 0 8 | -------------------------------------------------------------------------------- /assets/lights.atlas: -------------------------------------------------------------------------------- 1 | images { 2 | image: "/assets/soft_light.png" 3 | sprite_trim_mode: SPRITE_TRIM_MODE_OFF 4 | } 5 | images { 6 | image: "/assets/soft_light_small.png" 7 | sprite_trim_mode: SPRITE_TRIM_MODE_OFF 8 | } 9 | margin: 0 10 | extrude_borders: 2 11 | inner_padding: 0 12 | -------------------------------------------------------------------------------- /main/light.vp: -------------------------------------------------------------------------------- 1 | uniform highp mat4 view_proj; 2 | 3 | // positions are in world space 4 | attribute highp vec4 position; 5 | attribute mediump vec2 texcoord0; 6 | 7 | varying mediump vec2 var_texcoord0; 8 | 9 | void main() 10 | { 11 | gl_Position = view_proj * vec4(position.xyz, 1.0); 12 | var_texcoord0 = texcoord0; 13 | } 14 | -------------------------------------------------------------------------------- /main/light.fp: -------------------------------------------------------------------------------- 1 | varying mediump vec2 var_texcoord0; 2 | 3 | uniform lowp sampler2D texture_sampler; 4 | uniform lowp vec4 tint; 5 | 6 | void main() 7 | { 8 | // Pre-multiply alpha since all runtime textures already are 9 | lowp vec4 tint_pm = vec4(tint.xyz * tint.w, tint.w); 10 | gl_FragColor = texture2D(texture_sampler, var_texcoord0.xy) * tint_pm; 11 | } 12 | -------------------------------------------------------------------------------- /main/light.material: -------------------------------------------------------------------------------- 1 | name: "sprite" 2 | tags: "light" 3 | vertex_program: "/main/light.vp" 4 | fragment_program: "/main/light.fp" 5 | vertex_space: VERTEX_SPACE_WORLD 6 | vertex_constants { 7 | name: "view_proj" 8 | type: CONSTANT_TYPE_VIEWPROJ 9 | } 10 | fragment_constants { 11 | name: "tint" 12 | type: CONSTANT_TYPE_USER 13 | value { 14 | x: 1.0 15 | y: 1.0 16 | z: 1.0 17 | w: 1.0 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /game.project: -------------------------------------------------------------------------------- 1 | [bootstrap] 2 | main_collection = /main/main.collectionc 3 | render = /main/our.renderc 4 | 5 | [script] 6 | shared_state = 1 7 | 8 | [display] 9 | width = 1280 10 | height = 720 11 | 12 | [android] 13 | input_method = HiddenInputField 14 | 15 | [project] 16 | title = Simplest_2D_Lighting 17 | developer = Pawel Jarosz 18 | 19 | [graphics] 20 | default_texture_min_filter = nearest 21 | default_texture_mag_filter = nearest 22 | 23 | -------------------------------------------------------------------------------- /main/quad.fp: -------------------------------------------------------------------------------- 1 | varying highp vec4 var_position; 2 | varying mediump vec3 var_normal; 3 | varying mediump vec2 var_texcoord0; 4 | varying mediump vec4 var_light; 5 | 6 | uniform lowp sampler2D tex0; 7 | uniform lowp sampler2D tex1; 8 | uniform lowp vec4 tint; 9 | 10 | void main() 11 | { 12 | vec4 color_world = texture2D(tex0, var_texcoord0.xy); 13 | vec4 color_light = texture2D(tex1, var_texcoord0.xy); 14 | 15 | gl_FragColor = color_world * color_light; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unfolding Defold Tutorial - Simplest Lighting 2 | 3 | Then it was followed by tutorial on the [youtube.com/@unfolding_gamedev](https://youtube.com/@unfolding_gamedev) channel on making a simple lighting post-processing for games called "Screen Space Light Maps." 4 | 5 | Expected result: 6 | 7 | ![](assets/result.png) 8 | 9 | The idea is the same as presented and thoroughly explained here on [official Defold example](https://github.com/britzl/publicexamples/tree/master/examples/simple_lights). 10 | 11 | If you run into trouble, help is available in [Defold forum](https://forum.defold.com). 12 | 13 | You can use this project for all purposes, noncommercial and commercial! 14 | 15 | The visual assets ussed as a mockup are from Luis Zuno [ansimuz](https://ansimuz.itch.io/grotto-escape-game-art-pack) 16 | 17 | Happy Defolding! 18 | 19 | --- -------------------------------------------------------------------------------- /main/quad.vp: -------------------------------------------------------------------------------- 1 | 2 | // Positions can be world or local space, since world and normal 3 | // matrices are identity for world vertex space materials. 4 | // If world vertex space is selected, you can remove the 5 | // normal matrix multiplication for optimal performance. 6 | 7 | attribute highp vec4 position; 8 | attribute mediump vec2 texcoord0; 9 | attribute mediump vec3 normal; 10 | 11 | uniform mediump mat4 mtx_worldview; 12 | uniform mediump mat4 mtx_view; 13 | uniform mediump mat4 mtx_proj; 14 | uniform mediump mat4 mtx_normal; 15 | uniform mediump vec4 light; 16 | 17 | varying highp vec4 var_position; 18 | varying mediump vec3 var_normal; 19 | varying mediump vec2 var_texcoord0; 20 | varying mediump vec4 var_light; 21 | 22 | void main() 23 | { 24 | vec4 p = mtx_worldview * vec4(position.xyz, 1.0); 25 | var_light = mtx_view * vec4(light.xyz, 1.0); 26 | var_position = p; 27 | var_texcoord0 = texcoord0; 28 | var_normal = normalize((mtx_normal * vec4(normal, 0.0)).xyz); 29 | gl_Position = mtx_proj * p; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Pawel Jarosz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /main/quad.material: -------------------------------------------------------------------------------- 1 | name: "model" 2 | tags: "quad" 3 | vertex_program: "/main/quad.vp" 4 | fragment_program: "/main/quad.fp" 5 | vertex_space: VERTEX_SPACE_LOCAL 6 | vertex_constants { 7 | name: "mtx_worldview" 8 | type: CONSTANT_TYPE_WORLDVIEW 9 | } 10 | vertex_constants { 11 | name: "mtx_view" 12 | type: CONSTANT_TYPE_VIEW 13 | } 14 | vertex_constants { 15 | name: "mtx_proj" 16 | type: CONSTANT_TYPE_PROJECTION 17 | } 18 | vertex_constants { 19 | name: "mtx_normal" 20 | type: CONSTANT_TYPE_NORMAL 21 | } 22 | vertex_constants { 23 | name: "light" 24 | type: CONSTANT_TYPE_USER 25 | value { 26 | x: 1.0 27 | y: 1.0 28 | z: 1.0 29 | w: 1.0 30 | } 31 | } 32 | fragment_constants { 33 | name: "tint" 34 | type: CONSTANT_TYPE_USER 35 | value { 36 | x: 1.0 37 | y: 1.0 38 | z: 1.0 39 | w: 1.0 40 | } 41 | } 42 | samplers { 43 | name: "tex0" 44 | wrap_u: WRAP_MODE_CLAMP_TO_EDGE 45 | wrap_v: WRAP_MODE_CLAMP_TO_EDGE 46 | filter_min: FILTER_MODE_MIN_LINEAR 47 | filter_mag: FILTER_MODE_MAG_LINEAR 48 | max_anisotropy: 1.0 49 | } 50 | samplers { 51 | name: "tex1" 52 | wrap_u: WRAP_MODE_CLAMP_TO_EDGE 53 | wrap_v: WRAP_MODE_CLAMP_TO_EDGE 54 | filter_min: FILTER_MODE_MIN_LINEAR 55 | filter_mag: FILTER_MODE_MAG_LINEAR 56 | max_anisotropy: 0.0 57 | } 58 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Defold Protocol Buffer Text Files (https://github.com/github/linguist/issues/5091) 2 | *.animationset linguist-language=JSON5 3 | *.atlas linguist-language=JSON5 4 | *.camera linguist-language=JSON5 5 | *.collection linguist-language=JSON5 6 | *.collectionfactory linguist-language=JSON5 7 | *.collectionproxy linguist-language=JSON5 8 | *.collisionobject linguist-language=JSON5 9 | *.cubemap linguist-language=JSON5 10 | *.display_profiles linguist-language=JSON5 11 | *.factory linguist-language=JSON5 12 | *.font linguist-language=JSON5 13 | *.gamepads linguist-language=JSON5 14 | *.go linguist-language=JSON5 15 | *.gui linguist-language=JSON5 16 | *.input_binding linguist-language=JSON5 17 | *.label linguist-language=JSON5 18 | *.material linguist-language=JSON5 19 | *.mesh linguist-language=JSON5 20 | *.model linguist-language=JSON5 21 | *.particlefx linguist-language=JSON5 22 | *.render linguist-language=JSON5 23 | *.sound linguist-language=JSON5 24 | *.sprite linguist-language=JSON5 25 | *.spinemodel linguist-language=JSON5 26 | *.spinescene linguist-language=JSON5 27 | *.texture_profiles linguist-language=JSON5 28 | *.tilemap linguist-language=JSON5 29 | *.tilesource linguist-language=JSON5 30 | 31 | # Defold JSON Files 32 | *.buffer linguist-language=JSON 33 | 34 | # Defold GLSL Shaders 35 | *.fp linguist-language=GLSL 36 | *.vp linguist-language=GLSL 37 | 38 | # Defold Lua Files 39 | *.editor_script linguist-language=Lua 40 | *.render_script linguist-language=Lua 41 | *.script linguist-language=Lua 42 | *.gui_script linguist-language=Lua 43 | -------------------------------------------------------------------------------- /main/main.collection: -------------------------------------------------------------------------------- 1 | name: "main" 2 | scale_along_z: 0 3 | embedded_instances { 4 | id: "world" 5 | data: "embedded_components {\n" 6 | " id: \"sprite\"\n" 7 | " type: \"sprite\"\n" 8 | " data: \"tile_set: \\\"/assets/game.atlas\\\"\\n" 9 | "default_animation: \\\"mockup\\\"\\n" 10 | "material: \\\"/builtins/materials/sprite.material\\\"\\n" 11 | "blend_mode: BLEND_MODE_ALPHA\\n" 12 | "\"\n" 13 | " position {\n" 14 | " x: 0.0\n" 15 | " y: 0.0\n" 16 | " z: 0.0\n" 17 | " }\n" 18 | " rotation {\n" 19 | " x: 0.0\n" 20 | " y: 0.0\n" 21 | " z: 0.0\n" 22 | " w: 1.0\n" 23 | " }\n" 24 | "}\n" 25 | "" 26 | position { 27 | x: 541.0 28 | y: 391.0 29 | z: 0.0 30 | } 31 | rotation { 32 | x: 0.0 33 | y: 0.0 34 | z: 0.0 35 | w: 1.0 36 | } 37 | scale3 { 38 | x: 1.3 39 | y: 1.3 40 | z: 1.0 41 | } 42 | } 43 | embedded_instances { 44 | id: "lights" 45 | data: "embedded_components {\n" 46 | " id: \"sprite1\"\n" 47 | " type: \"sprite\"\n" 48 | " data: \"tile_set: \\\"/assets/lights.atlas\\\"\\n" 49 | "default_animation: \\\"soft_light_small\\\"\\n" 50 | "material: \\\"/main/light.material\\\"\\n" 51 | "blend_mode: BLEND_MODE_ALPHA\\n" 52 | "\"\n" 53 | " position {\n" 54 | " x: -30.0\n" 55 | " y: -32.167\n" 56 | " z: 0.0\n" 57 | " }\n" 58 | " rotation {\n" 59 | " x: 0.0\n" 60 | " y: 0.0\n" 61 | " z: 0.0\n" 62 | " w: 1.0\n" 63 | " }\n" 64 | "}\n" 65 | "embedded_components {\n" 66 | " id: \"sprite2\"\n" 67 | " type: \"sprite\"\n" 68 | " data: \"tile_set: \\\"/assets/lights.atlas\\\"\\n" 69 | "default_animation: \\\"soft_light_small\\\"\\n" 70 | "material: \\\"/main/light.material\\\"\\n" 71 | "blend_mode: BLEND_MODE_ALPHA\\n" 72 | "\"\n" 73 | " position {\n" 74 | " x: 199.666\n" 75 | " y: -19.333\n" 76 | " z: 0.0\n" 77 | " }\n" 78 | " rotation {\n" 79 | " x: 0.0\n" 80 | " y: 0.0\n" 81 | " z: 0.0\n" 82 | " w: 1.0\n" 83 | " }\n" 84 | "}\n" 85 | "embedded_components {\n" 86 | " id: \"sprite3\"\n" 87 | " type: \"sprite\"\n" 88 | " data: \"tile_set: \\\"/assets/lights.atlas\\\"\\n" 89 | "default_animation: \\\"soft_light_small\\\"\\n" 90 | "material: \\\"/main/light.material\\\"\\n" 91 | "blend_mode: BLEND_MODE_ALPHA\\n" 92 | "\"\n" 93 | " position {\n" 94 | " x: 94.667\n" 95 | " y: -18.333\n" 96 | " z: 0.0\n" 97 | " }\n" 98 | " rotation {\n" 99 | " x: 0.0\n" 100 | " y: 0.0\n" 101 | " z: 0.0\n" 102 | " w: 1.0\n" 103 | " }\n" 104 | "}\n" 105 | "embedded_components {\n" 106 | " id: \"sprite4\"\n" 107 | " type: \"sprite\"\n" 108 | " data: \"tile_set: \\\"/assets/lights.atlas\\\"\\n" 109 | "default_animation: \\\"soft_light\\\"\\n" 110 | "material: \\\"/main/light.material\\\"\\n" 111 | "blend_mode: BLEND_MODE_ALPHA\\n" 112 | "\"\n" 113 | " position {\n" 114 | " x: 149.834\n" 115 | " y: -54.5\n" 116 | " z: 0.0\n" 117 | " }\n" 118 | " rotation {\n" 119 | " x: 0.0\n" 120 | " y: 0.0\n" 121 | " z: 0.0\n" 122 | " w: 1.0\n" 123 | " }\n" 124 | "}\n" 125 | "" 126 | position { 127 | x: 569.0 128 | y: 274.0 129 | z: 0.2 130 | } 131 | rotation { 132 | x: 0.0 133 | y: 0.0 134 | z: 0.0 135 | w: 1.0 136 | } 137 | scale3 { 138 | x: 3.0 139 | y: 3.0 140 | z: 1.0 141 | } 142 | } 143 | embedded_instances { 144 | id: "quad" 145 | data: "embedded_components {\n" 146 | " id: \"model\"\n" 147 | " type: \"model\"\n" 148 | " data: \"mesh: \\\"/builtins/assets/meshes/quad_2x2.dae\\\"\\n" 149 | "material: \\\"/main/quad.material\\\"\\n" 150 | "textures: \\\"\\\"\\n" 151 | "skeleton: \\\"\\\"\\n" 152 | "animations: \\\"\\\"\\n" 153 | "default_animation: \\\"\\\"\\n" 154 | "name: \\\"{{NAME}}\\\"\\n" 155 | "\"\n" 156 | " position {\n" 157 | " x: 0.0\n" 158 | " y: 0.0\n" 159 | " z: 0.0\n" 160 | " }\n" 161 | " rotation {\n" 162 | " x: 0.0\n" 163 | " y: 0.0\n" 164 | " z: 0.0\n" 165 | " w: 1.0\n" 166 | " }\n" 167 | "}\n" 168 | "" 169 | position { 170 | x: 0.0 171 | y: 0.0 172 | z: 0.0 173 | } 174 | rotation { 175 | x: 0.0 176 | y: 0.0 177 | z: 0.0 178 | w: 1.0 179 | } 180 | scale3 { 181 | x: 1.0 182 | y: 1.0 183 | z: 1.0 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /main/our.render_script: -------------------------------------------------------------------------------- 1 | -- Copyright 2020-2023 The Defold Foundation 2 | -- Copyright 2014-2020 King 3 | -- Copyright 2009-2014 Ragnar Svensson, Christian Murray 4 | -- Licensed under the Defold License version 1.0 (the "License"); you may not use 5 | -- this file except in compliance with the License. 6 | -- 7 | -- You may obtain a copy of the License, together with FAQs at 8 | -- https://www.defold.com/license 9 | -- 10 | -- Unless required by applicable law or agreed to in writing, software distributed 11 | -- under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | -- CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | -- specific language governing permissions and limitations under the License. 14 | 15 | -- 16 | -- projection that centers content with maintained aspect ratio and optional zoom 17 | -- 18 | local function fixed_projection(near, far, zoom) 19 | local projected_width = render.get_window_width() / (zoom or 1) 20 | local projected_height = render.get_window_height() / (zoom or 1) 21 | local xoffset = -(projected_width - render.get_width()) / 2 22 | local yoffset = -(projected_height - render.get_height()) / 2 23 | return vmath.matrix4_orthographic(xoffset, xoffset + projected_width, yoffset, yoffset + projected_height, near, far) 24 | end 25 | -- 26 | -- projection that centers and fits content with maintained aspect ratio 27 | -- 28 | local function fixed_fit_projection(near, far) 29 | local width = render.get_width() 30 | local height = render.get_height() 31 | local window_width = render.get_window_width() 32 | local window_height = render.get_window_height() 33 | local zoom = math.min(window_width / width, window_height / height) 34 | return fixed_projection(near, far, zoom) 35 | end 36 | -- 37 | -- projection that stretches content 38 | -- 39 | local function stretch_projection(near, far) 40 | return vmath.matrix4_orthographic(0, render.get_width(), 0, render.get_height(), near, far) 41 | end 42 | 43 | local function get_projection(self) 44 | return self.projection_fn(self.near, self.far, self.zoom) 45 | end 46 | 47 | -- 48 | -- Convenience functions: 49 | -- 50 | 51 | 52 | -- Set given render target and draw to it, then get back to default target 53 | -- 54 | local function render_to_render_target(render_target, draw_function) 55 | render.set_render_target(render_target) 56 | draw_function() 57 | render.set_render_target(render.RENDER_TARGET_DEFAULT) 58 | end 59 | 60 | 61 | -- Default clearing of the screen buffers with a given clear color 62 | -- 63 | local function clear_with_color(clear_color) 64 | render.set_depth_mask(true) 65 | render.set_stencil_mask(0xff) 66 | render.clear({[render.BUFFER_COLOR_BIT] = clear_color, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0}) 67 | 68 | end 69 | 70 | -- Set renderer state to default (commonly used settings from default render script) 71 | -- 72 | local function set_default_renderer_state() 73 | render.set_depth_mask(false) 74 | render.disable_state(render.STATE_DEPTH_TEST) 75 | render.disable_state(render.STATE_STENCIL_TEST) 76 | render.enable_state(render.STATE_BLEND) 77 | render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA) 78 | render.disable_state(render.STATE_CULL_FACE) 79 | end 80 | 81 | function init(self) 82 | self.tile_pred = render.predicate({"tile"}) 83 | self.gui_pred = render.predicate({"gui"}) 84 | self.text_pred = render.predicate({"text"}) 85 | self.particle_pred = render.predicate({"particle"}) 86 | self.light_pred = render.predicate({"light"}) 87 | self.quad_pred = render.predicate({"quad"}) 88 | 89 | self.clear_color = vmath.vector4(0, 0, 0, 0) 90 | self.clear_color.x = sys.get_config("render.clear_color_red", 0) 91 | self.clear_color.y = sys.get_config("render.clear_color_green", 0) 92 | self.clear_color.z = sys.get_config("render.clear_color_blue", 0) 93 | self.clear_color.w = sys.get_config("render.clear_color_alpha", 0) 94 | 95 | self.ambient_color = vmath.vector4(0.05, 0.1, 0.3, 1) 96 | 97 | self.view = vmath.matrix4() 98 | 99 | -- default is stretch projection. copy from builtins and change for different projection 100 | -- or send a message to the render script to change projection: 101 | -- msg.post("@render:", "use_stretch_projection", { near = -1, far = 1 }) 102 | -- msg.post("@render:", "use_fixed_projection", { near = -1, far = 1, zoom = 2 }) 103 | -- msg.post("@render:", "use_fixed_fit_projection", { near = -1, far = 1 }) 104 | self.near = -1 105 | self.far = 1 106 | self.projection_fn = stretch_projection 107 | 108 | local color_params = { 109 | format = render.FORMAT_RGBA, 110 | width = render.get_window_width(), 111 | height = render.get_window_height(), 112 | min_filter = render.FILTER_LINEAR, 113 | mag_filter = render.FILTER_LINEAR, 114 | u_wrap = render.WRAP_CLAMP_TO_EDGE, 115 | v_wrap = render.WRAP_CLAMP_TO_EDGE 116 | } 117 | 118 | local parameters = { 119 | [render.BUFFER_COLOR_BIT] = color_params 120 | } 121 | 122 | self.render_target_world = render.render_target("world", parameters) 123 | self.render_target_lights = render.render_target("lights", parameters) 124 | end 125 | 126 | local IDENTITY_MATRIX = vmath.matrix4() 127 | 128 | function update(self) 129 | local window_width = render.get_window_width() 130 | local window_height = render.get_window_height() 131 | if window_width == 0 or window_height == 0 then 132 | return 133 | end 134 | 135 | local proj = get_projection(self) 136 | local frustum = proj * self.view 137 | render.set_viewport(0, 0, window_width, window_height) 138 | 139 | -- draw world to render target 140 | render_to_render_target(self.render_target_world, function() 141 | 142 | clear_with_color(self.clear_color) 143 | 144 | render.set_view(self.view) 145 | render.set_projection(proj) 146 | 147 | set_default_renderer_state() 148 | 149 | render.draw(self.tile_pred, {frustum = frustum}) 150 | render.draw(self.particle_pred, {frustum = frustum}) 151 | render.draw_debug3d() 152 | 153 | end) 154 | 155 | -- draw lights to render target 156 | render_to_render_target(self.render_target_lights, function() 157 | 158 | clear_with_color(self.ambient_color) 159 | 160 | render.set_view(self.view) 161 | render.set_projection(proj) 162 | 163 | set_default_renderer_state() 164 | 165 | render.draw(self.light_pred, {frustum = frustum}) 166 | 167 | end) 168 | 169 | -- render to quad 170 | -- 171 | render.set_view(IDENTITY_MATRIX) 172 | render.set_projection(IDENTITY_MATRIX) 173 | 174 | set_default_renderer_state() 175 | 176 | render.enable_material(hash("lighting_quad")) 177 | 178 | render.enable_texture(0, self.render_target_world, render.BUFFER_COLOR0_BIT) 179 | render.enable_texture(1, self.render_target_lights, render.BUFFER_COLOR0_BIT) 180 | 181 | render.draw(self.quad_pred) 182 | 183 | render.disable_texture(0) 184 | render.disable_texture(1) 185 | 186 | render.disable_material() 187 | 188 | 189 | -- render GUI 190 | -- 191 | local view_gui = vmath.matrix4() 192 | local proj_gui = vmath.matrix4_orthographic(0, window_width, 0, window_height, -1, 1) 193 | local frustum_gui = proj_gui * view_gui 194 | 195 | render.set_view(view_gui) 196 | render.set_projection(proj_gui) 197 | 198 | render.enable_state(render.STATE_STENCIL_TEST) 199 | render.draw(self.gui_pred, {frustum = frustum_gui}) 200 | render.draw(self.text_pred, {frustum = frustum_gui}) 201 | render.disable_state(render.STATE_STENCIL_TEST) 202 | end 203 | 204 | function on_message(self, message_id, message) 205 | if message_id == hash("clear_color") then 206 | self.clear_color = message.color 207 | elseif message_id == hash("set_view_projection") then 208 | self.view = message.view 209 | self.projection = message.projection 210 | elseif message_id == hash("use_camera_projection") then 211 | self.projection_fn = function() return self.projection or vmath.matrix4() end 212 | elseif message_id == hash("use_stretch_projection") then 213 | self.near = message.near or -1 214 | self.far = message.far or 1 215 | self.projection_fn = stretch_projection 216 | elseif message_id == hash("use_fixed_projection") then 217 | self.near = message.near or -1 218 | self.far = message.far or 1 219 | self.zoom = message.zoom or 1 220 | self.projection_fn = fixed_projection 221 | elseif message_id == hash("use_fixed_fit_projection") then 222 | self.near = message.near or -1 223 | self.far = message.far or 1 224 | self.projection_fn = fixed_fit_projection 225 | end 226 | end 227 | --------------------------------------------------------------------------------