/ fbo_example.lua
fbo_example.lua
  1  -- File: fbo_example.lua
  2  
  3  --[[
  4  Copyright (C) 2024 chmod777
  5  
  6  This program is free software: you can redistribute it and/or modify it under
  7  the terms of the GNU Affero General Public License version 3 as published by the
  8  Free Software Foundation.
  9  
 10  This program is distributed in the hope that it will be useful, but WITHOUT ANY
 11  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 12  PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
 13  
 14  You should have received a copy of the GNU Affero General Public License along
 15  with this program. If not, see <https://www.gnu.org/licenses/>. 
 16  ]]
 17  
 18  function widget:GetInfo()
 19  	return {
 20  		name    = 'FBO example',
 21  		desc    = 'A minimal FBO example. Requires chmod777_includes/utilites_GL4.lua',
 22  		author  = 'chmod777',
 23  		date    = 'May 2024',
 24  		license = 'GNU AGPL v3',
 25  		layer   = 0,
 26  		enabled = true,
 27  	}
 28  end
 29  
 30  local luaWidgetDir = 'LuaUI/Widgets/'
 31  local luaIncludeDir = luaWidgetDir..'Include/'
 32  local LuaShader = VFS.Include(luaIncludeDir..'LuaShader.lua')
 33  local Quad, FBO = VFS.Include(luaWidgetDir..'chmod777_includes/utilities_GL4.lua')
 34  
 35  local quadVsSrc = [[
 36  	#version 420
 37  
 38  	layout (location = 0) in vec2 coords;
 39  	layout (location = 1) in vec2 uv;
 40  	
 41  	uniform vec2 viewGeometry;
 42  	uniform vec2 screenPos;
 43  	uniform float imgSize;
 44  	
 45  	out DataVS {
 46  		vec2 uv;
 47  	} vs_out;
 48  	
 49  	void main() {
 50  		vs_out.uv = uv;
 51  	
 52  		vec2 coord = coords;
 53  	
 54  		coord = fma(coord, vec2(imgSize*0.5), screenPos) / viewGeometry;
 55  		coord = fma(coord, vec2(2.0), vec2(-1.0));
 56  	
 57  		gl_Position = vec4(coord, 0.0, 1.0);
 58  	}
 59  ]]
 60  local quadFsSrc = [[
 61  	#version 420
 62  
 63  	#extension GL_ARB_uniform_buffer_object : require
 64  	#extension GL_ARB_shading_language_420pack: require
 65  	
 66  	layout (binding = 0) uniform sampler2D img;
 67  	
 68  	in DataVS {
 69  		vec2 uv;
 70  	} vs_in;
 71  	
 72  	out vec4 fragColor;
 73  	
 74  	void main() {
 75  		fragColor = texture(img, vs_in.uv);
 76  	}
 77  ]]
 78  
 79  local vsSrc = [[
 80  #version 420
 81  
 82  layout (location = 0) in vec2 coords;
 83  layout (location = 1) in vec2 uv;
 84  
 85  out DataVS {
 86  	vec2 uv;
 87  } vs_out;
 88  
 89  void main() {
 90  	vs_out.uv = uv;
 91  	gl_Position = vec4(coords, 0.0, 1.0);
 92  }
 93  ]]
 94  
 95  local fsSrc = [[
 96  #version 420
 97  
 98  #extension GL_ARB_uniform_buffer_object : require
 99  #extension GL_ARB_shading_language_420pack: require
100  
101  layout (binding = 0) uniform sampler2D imgTop;
102  layout (binding = 1) uniform sampler2D imgLeft;
103  layout (binding = 2) uniform sampler2D imgRight;
104  
105  const vec2 OFFSET_TOP = vec2(0.0, 0.0);
106  const vec2 OFFSET_LEFT = vec2(0.4, 0.0);
107  const vec2 OFFSET_RIGHT = vec2(-0.3, 0.0);
108  
109  in DataVS {
110  	vec2 uv;
111  } vs_in;
112  
113  out vec4 fragColor;
114  
115  void main() {
116  	vec2 uv = vs_in.uv;
117  	vec4 top = texture(imgTop, uv + OFFSET_TOP);
118  	vec4 left = texture(imgLeft, uv + OFFSET_LEFT);
119  	vec4 right = texture(imgRight, uv + OFFSET_RIGHT);
120  
121  	if (uv.y < 0.5) {
122  		fragColor = top;
123  		if (1 - uv.x < uv.y) {
124  			fragColor = right;
125  		}
126  		if (uv.x < uv.y) {
127  			fragColor = left;
128  		}
129  	} else if (uv.x > 0.5) {
130  		fragColor = right;
131  	} else {
132  		fragColor = left;
133  	}
134  }
135  ]]
136  
137  local fbo
138  
139  local combiningShader
140  local combiningQuad
141  local imgSize = 256
142  
143  local screenQuadShader
144  local screenQuadUniformLocs = {}
145  local screenQuad
146  
147  local glViewport = gl.Viewport
148  local glClear = gl.Clear
149  local glTexture = gl.Texture
150  local glUniform = gl.Uniform
151  local GL_COLOR_BUFFER_BIT = GL.COLOR_BUFFER_BIT
152  
153  function widget:Initialize()
154  	combiningShader = LuaShader({
155  		vertex = vsSrc,
156  		fragment = fsSrc,
157  	}, 'Combining Shader')
158  	local combiningShaderCompiled = combiningShader:Initialize()
159  	if not combiningShaderCompiled then
160  		Spring.Echo('Img Shader: compilation failed')
161  		widgetHandler:RemoveWidget()
162  	end
163  	combiningQuad = Quad:new(-1,-1, 1, 1, true)
164  
165  	screenQuadShader = LuaShader({
166  		vertex = quadVsSrc,
167  		fragment = quadFsSrc,
168  	}, 'Quad Shader')
169  	local quadShaderCompiled = screenQuadShader:Initialize()
170  	if not quadShaderCompiled then
171  		Spring.Echo('Quad Shader: compilation failed')
172  		widgetHandler:RemoveWidget()
173  	end
174  
175  	local shader = screenQuadShader.shaderObj;
176  	screenQuadUniformLocs['screenPos'] = gl.GetUniformLocation(shader, 'screenPos')
177  	screenQuadUniformLocs['imgSize'] = gl.GetUniformLocation(shader, 'imgSize')
178  	screenQuadUniformLocs['viewGeometry'] = gl.GetUniformLocation(shader, 'viewGeometry')
179  
180  	screenQuad = Quad:new()
181  
182  	fbo = FBO:new(imgSize, imgSize, false)
183  end
184  
185  function widget:Shutdown()
186  	if fbo ~= nil then fbo:Delete() end
187  
188  	if screenQuadShader ~= nil then screenQuadShader:Delete() end
189  	if combineShader ~= nil then combineShader:Delete() end
190  
191  	if screenQuad ~= nil then screenQuad:Delete() end
192  	if combiningQuad ~= nil then combiningQuad:Delete() end
193  end
194  
195  function DrawCombined()
196  	combiningShader:Activate()
197  		glTexture(0, "unitpics/armcom.dds")
198  		glTexture(1, "unitpics/corcom.dds")
199  		glTexture(2, "unitpics/armgeo.dds")
200  		combiningQuad:draw()
201  		glTexture(0, false)
202  		glTexture(1, false)
203  		glTexture(2, false)
204  	combiningShader:Deactivate()
205  end
206  
207  function widget:DrawScreen()
208  	local viewGeometryX,viewGeometryY = Spring.GetViewGeometry()
209  
210  	glViewport(0, 0, imgSize, imgSize)
211  		-- Show preview in bottom of screen
212  		DrawCombined()
213  
214  		-- render to a texture(fbo.tex)
215  		fbo:bind()
216  			glClear(GL_COLOR_BUFFER_BIT, 0,0,0,0)
217  			DrawCombined()
218  		fbo:unbind()
219  	glViewport(0, 0, viewGeometryX, viewGeometryY)
220  
221  	-- display the texture on a quad in the center of the screen
222  	screenQuadShader:Activate()
223  		glTexture(0, fbo.tex)
224  		glUniform(screenQuadUniformLocs['imgSize'], imgSize)
225  		glUniform(screenQuadUniformLocs['screenPos'], viewGeometryX/2, viewGeometryY/2)
226  		glUniform(screenQuadUniformLocs['viewGeometry'], viewGeometryX, viewGeometryY)
227  		screenQuad:draw()
228  		glTexture(0, false)
229  	screenQuadShader:Deactivate()
230  end