Skip to content
Snippets Groups Projects
Commit 98faaaf8 authored by dg's avatar dg
Browse files

OpenGL Framebuffer Object (FBO) support available to modules

ToME now uses a FBO to do a full map shader that can blur, colorize, ...
Low hit point warning now displays a red "glow" around the map edges, intensifying as life gets lower


git-svn-id: http://svn.net-core.org/repos/t-engine4@841 51575b47-30f0-44d4-a5cc-537603b46e54
parent e263507b
No related branches found
No related tags found
No related merge requests found
......@@ -40,7 +40,7 @@ OBJECT = 1000
searchOrder = { TERRAIN, TRAP, OBJECT, ACTOR }
color_shown = { 1, 1, 1, 1 }
color_obscure = { 0.6, 0.6, 0.6, 1 }
color_obscure = { 1, 1, 1, 0.6 }
-- The minimap data
MM_FLOOR = 1
......@@ -434,7 +434,10 @@ end
--- Displays the map on a surface
-- @return a surface containing the drawn map
function _M:display()
function _M:display(x, y)
local ox, oy = self.display_x, self.display_y
self.display_x, self.display_y = x or self.display_x, y or self.display_y
self._map:toScreen(self.display_x, self.display_y)
-- Tactical display
......@@ -469,6 +472,8 @@ function _M:display()
self:displayEffects()
self:displayEmotes()
self.display_x, self.display_y = ox, oy
-- If nothing changed, return the same surface as before
if not self.changed then return end
self.changed = false
......
......@@ -109,6 +109,7 @@ function _M:loaded()
if _M.progs[self.totalname] then
self.shad = _M.progs[self.totalname]
print("[SHADER] using cached shader "..self.totalname)
self.shad = _M.progs[self.totalname]
else
print("[SHADER] Loading from /data/gfx/shaders/"..self.name..".lua")
local f, err = loadfile("/data/gfx/shaders/"..self.name..".lua")
......@@ -117,27 +118,31 @@ function _M:loaded()
local def = f()
_M.progs[self.totalname] = self:createProgram(def)
self.shad = _M.progs[self.totalname]
for k, v in pairs(def.args) do
if type(v) == "number" then
print("[SHADER] setting param", k, v)
_M.progs[self.totalname]:paramNumber(k, v)
elseif type(v) == "table" then
if v.texture then
print("[SHADER] setting texture param", k, v.texture)
_M.progs[self.totalname]:paramTexture(k, v.texture, v.is3d)
elseif #v == 2 then
print("[SHADER] setting vec2 param", k, v[1], v[2])
_M.progs[self.totalname]:paramNumber2(k, v[1], v[2])
elseif #v == 3 then
print("[SHADER] setting vec3 param", k, v[1], v[2], v[3])
_M.progs[self.totalname]:paramNumber3(k, v[1], v[2], v[3])
elseif #v == 4 then
print("[SHADER] setting vec4 param", k, v[1], v[2], v[3], v[4])
_M.progs[self.totalname]:paramNumber4(k, v[1], v[2], v[3], v[4])
end
end
self:setUniform(k, v)
end
end
end
self.shad = _M.progs[self.totalname]
function _M:setUniform(k, v)
if type(v) == "number" then
print("[SHADER] setting param", k, v)
self.shad:paramNumber(k, v)
elseif type(v) == "table" then
if v.texture then
print("[SHADER] setting texture param", k, v.texture)
self.shad:paramTexture(k, v.texture, v.is3d)
elseif #v == 2 then
print("[SHADER] setting vec2 param", k, v[1], v[2])
self.shad:paramNumber2(k, v[1], v[2])
elseif #v == 3 then
print("[SHADER] setting vec3 param", k, v[1], v[2], v[3])
self.shad:paramNumber3(k, v[1], v[2], v[3])
elseif #v == 4 then
print("[SHADER] setting vec4 param", k, v[1], v[2], v[3], v[4])
self.shad:paramNumber4(k, v[1], v[2], v[3], v[4])
end
end
end
......@@ -52,7 +52,7 @@ function _M:init(map, source_actor)
-- setmetatable(self.target, {__mode='v'})
end
function _M:display()
function _M:display(dispx, dispy)
-- Entity tracking, if possible and if visible
if self.target.entity and self.target.entity.x and self.target.entity.y and game.level.map.seens(self.target.entity.x, self.target.entity.y) then
self.target.x, self.target.y = self.target.entity.x, self.target.entity.y
......@@ -63,6 +63,9 @@ function _M:display()
-- Do not display if not requested
if not self.active then return end
local ox, oy = self.display_x, self.display_y
self.display_x, self.display_y = dispx or self.display_x, dispy or self.display_y
local s = self.sb
local l = line.new(self.source_actor.x, self.source_actor.y, self.target.x, self.target.y)
local lx, ly = l()
......@@ -94,6 +97,8 @@ function _M:display()
if not self.target_type.no_restrict and game.level.map:checkEntity(lx, ly, Map.TERRAIN, "block_move") then return true end
end, function()end, nil)
end
self.display_x, self.display_y = ox, oy
end
--- Returns data for the given target type
......
......@@ -31,6 +31,7 @@ local Level = require "engine.Level"
local Birther = require "engine.Birther"
local Astar = require "engine.Astar"
local DirectPath = require "engine.DirectPath"
local Shader = require "engine.Shader"
local Store = require "mod.class.Store"
local Trap = require "mod.class.Trap"
......@@ -213,6 +214,10 @@ function _M:setupDisplayMode()
end
self:setupMiniMap()
self:saveSettings("tome.gfxmode", ("tome.gfxmode = %d\n"):format(self.gfxmode))
-- Create the framebuffer
self.fbo = core.display.newFBO(Map.viewport.width, Map.viewport.height)
if self.fbo then self.fbo_shader = Shader.new("main_fbo") end
end
function _M:setupMiniMap()
......@@ -387,17 +392,26 @@ function _M:display()
self.player:playerFOV()
end
self.level.map:display()
-- Display using Framebuffer, sotaht we can use shaders and all
if self.fbo then
self.fbo:use(true)
self.level.map:display(0, 0)
self.target:display(0, 0)
self.fbo:use(false)
self.fbo:toScreen(
self.level.map.display_x, self.level.map.display_y,
self.level.map.viewport.width, self.level.map.viewport.height,
self.fbo_shader.shad
)
-- Display the targetting system if active
self.target:display()
-- Basic display
else
self.level.map:display()
self.target:display()
end
-- Display a tooltip if available
if self.tooltip_x then
local mx, my = self.tooltip_x , self.tooltip_y
local tmx, tmy = self.level.map:getMouseTile(mx, my)
self.tooltip:displayAtMap(tmx, tmy)
end
if self.tooltip_x then self.tooltip:displayAtMap(self.level.map:getMouseTile(self.tooltip_x , self.tooltip_y)) end
-- Move target around
if self.old_tmx ~= tmx or self.old_tmy ~= tmy then
......
......@@ -64,6 +64,7 @@ function _M:init(t, no_default)
t.lite = t.lite or 0
t.rank = t.rank or 3
t.old_life = 0
mod.class.Actor.init(self, t, no_default)
engine.interface.PlayerHotkeys.init(self, t)
......@@ -134,6 +135,13 @@ function _M:act()
end
end
-- Set shader HP warning
if game.fbo_shader and self.life ~= self.old_life then
if self.life < self.max_life / 2 then game.fbo_shader:setUniform("hp_warning", 1 - (self.life / self.max_life))
else game.fbo_shader:setUniform("hp_warning", 0) end
end
self.old_life = self.life
-- Clean log flasher
game.flash:empty()
......
uniform float hp_warning;
uniform float blur;
uniform sampler3D noiseVol;
uniform vec2 texSize;
uniform sampler2D tex;
uniform vec3 colorize;
void main(void)
{
gl_FragColor = texture2D(tex, gl_TexCoord[0].xy);
if (blur > 0.0)
{
int blursize = int(blur);
vec2 offset = 1.0/texSize;
// Center Pixel
vec4 sample = vec4(0.0,0.0,0.0,0.0);
float factor = ((float(blursize)*2.0)+1.0);
factor = factor*factor;
for(int i = -blursize; i <= blursize; i++)
{
for(int j = -blursize; j <= blursize; j++)
{
sample += texture2D(tex, vec2(gl_TexCoord[0].xy+vec2(float(i)*offset.x, float(j)*offset.y)));
}
}
sample /= float((blursize*2) * (blursize*2));
gl_FragColor = sample;
}
if (colorize.r > 0.0 || colorize.g > 0.0 || colorize.b > 0.0)
{
float grey = gl_FragColor.r*0.3+gl_FragColor.g*0.59+gl_FragColor.b*0.11;
gl_FragColor = vec4(vec3(colorize*grey),1.0);
}
if (hp_warning > 0.0)
{
vec4 hp_warning_color = vec4(hp_warning / 1.5, 0, 0, hp_warning / 1.5);
float dist = length(gl_TexCoord[0].xy - vec2(0.5)) / 2.0;
gl_FragColor = mix(gl_FragColor, hp_warning_color, dist);
}
}
/*uniform sampler2D tex;
uniform vec2 texSize;
int blursize = 5;
void main(void)
{
vec2 offset = 1.0/texSize;
// Center Pixel
vec4 sample = vec4(0.0,0.0,0.0,0.0);
float factor = ((float(blursize)*2.0)+1.0);
factor = factor*factor;
for(int i = -blursize; i <= blursize; i++)
{
for(int j = -blursize; j <= blursize; j++)
{
sample += texture2D(tex, vec2(gl_TexCoord[0].xy+vec2(float(i)*offset.x, float(j)*offset.y)));
}
}
sample /= float((blursize*2) * (blursize*2));
float grey = sample.r*0.3+sample.g*0.59+sample.b*0.11;
vec3 color = vec3(1, 0, 0);
gl_FragColor = vec4(vec3(color*grey),1.0);
}
*/
/*
uniform sampler2D tex;
uniform sampler3D noiseVol;
uniform float tick;
float do_blur = 3.0;
uniform vec2 texSize;
void main(void)
{
if (do_blur > 0.0)
{
vec2 offset = 1.0/texSize;
offset.y += texture3D(noiseVol, vec3(gl_TexCoord[0].xy, tick/100000))/30;
// Center Pixel
vec4 sample = vec4(0.0,0.0,0.0,0.0);
float factor = ((float(do_blur)*2.0)+1.0);
factor = factor*factor;
for(int i = -do_blur; i <= do_blur; i++)
{
for(int j = -do_blur; j <= do_blur; j++)
{
sample += texture2D(tex, vec2(gl_TexCoord[0].xy+vec2(float(i)*offset.x, float(j)*offset.y)));
}
}
sample /= float((do_blur*2) * (do_blur*2));
gl_FragColor = sample;
}
float grey = gl_FragColor.r*0.3+gl_FragColor.g*0.59+gl_FragColor.b*0.11;
vec3 color = vec3(1, 0, 0);
gl_FragColor = vec4(vec3(color*grey),1.0);
}
*/
-- ToME - Tales of Middle-Earth
-- Copyright (C) 2009, 2010 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
return {
frag = "main_fbo",
vert = nil,
args = {
tex = { texture = 0 },
noiseVol = { texture = 1 },
},
clone = false,
}
//uniform vec2 texSize;
uniform vec2 texSize;
uniform sampler2D tex;
uniform sampler3D noisevol;
uniform vec4 color;
uniform float tick;
int blursize = 7;
vec2 texSize = vec2(32,32);
void main(void)
{
......
......@@ -23,7 +23,6 @@ return {
args = {
noisevol = { texture = 1 },
color = color or {1,1,1,1},
-- texSize = size or {32, 32},
},
clone = false,
}
......@@ -31,7 +31,7 @@ return {
ambiant_music = "elven_town.ogg",
-- Apply a bluish tint to all the map
color_shown = {0.5, 1, 0.8, 1},
color_obscure = {0.5*0.6, 1*0.6, 0.8*0.6, 1},
color_obscure = {0.5*0.6, 1*0.6, 0.8*0.6, 0.6},
generator = {
map = {
class = "engine.generator.map.Cavern",
......
......@@ -1053,6 +1053,7 @@ static int sdl_texture_outline(lua_State *L)
glMatrixMode(GL_PROJECTION);
CHECKGL(glPopMatrix());
glMatrixMode( GL_MODELVIEW );
glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
return 1;
......@@ -1084,6 +1085,141 @@ static int sdl_redraw_screen(lua_State *L)
return 0;
}
/**************************************************************
* Framebuffer Objects
**************************************************************/
typedef struct
{
GLuint fbo;
GLuint texture;
int w, h;
} lua_fbo;
static int gl_new_fbo(lua_State *L)
{
if (!fbo_active) return 0;
int w = luaL_checknumber(L, 1);
int h = luaL_checknumber(L, 2);
lua_fbo *fbo = (lua_fbo*)lua_newuserdata(L, sizeof(lua_fbo));
auxiliar_setclass(L, "gl{fbo}", -1);
fbo->w = w;
fbo->h = h;
CHECKGL(glGenFramebuffersEXT(1, &(fbo->fbo)));
CHECKGL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->fbo));
// Now setup a texture to render to
CHECKGL(glGenTextures(1, &(fbo->texture)));
CHECKGL(glBindTexture(GL_TEXTURE_2D, fbo->texture));
CHECKGL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
CHECKGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
CHECKGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
CHECKGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
CHECKGL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo->texture, 0));
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if(status != GL_FRAMEBUFFER_COMPLETE_EXT) return 0;
CHECKGL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
return 1;
}
static int gl_free_fbo(lua_State *L)
{
lua_fbo *fbo = (lua_fbo*)auxiliar_checkclass(L, "gl{fbo}", 1);
CHECKGL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->fbo));
CHECKGL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0));
CHECKGL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
CHECKGL(glDeleteTextures(1, &(fbo->texture)));
CHECKGL(glDeleteFramebuffersEXT(1, &(fbo->fbo)));
lua_pushnumber(L, 1);
return 1;
}
static int gl_fbo_use(lua_State *L)
{
lua_fbo *fbo = (lua_fbo*)auxiliar_checkclass(L, "gl{fbo}", 1);
bool active = lua_toboolean(L, 2);
if (active)
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->fbo);
// Set the viewport and save the old one
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, fbo->w, fbo->h);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, fbo->w, fbo->h, 0, -100, 100);
glMatrixMode(GL_MODELVIEW);
// Reset The View
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
}
else
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
// Restore viewport
glPopAttrib();
// Unbind texture from FBO and then unbind FBO
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}
return 0;
}
static int gl_fbo_toscreen(lua_State *L)
{
lua_fbo *fbo = (lua_fbo*)auxiliar_checkclass(L, "gl{fbo}", 1);
int x = luaL_checknumber(L, 2);
int y = luaL_checknumber(L, 3);
int w = luaL_checknumber(L, 4);
int h = luaL_checknumber(L, 5);
float r = 1, g = 1, b = 1, a = 1;
if (lua_isnumber(L, 7))
{
r = luaL_checknumber(L, 7);
g = luaL_checknumber(L, 8);
b = luaL_checknumber(L, 9);
a = luaL_checknumber(L, 10);
glColor4f(r, g, b, a);
}
if (lua_isuserdata(L, 6))
{
GLuint *s = (GLuint*)auxiliar_checkclass(L, "gl{program}", 6);
useShader(*s, 0, 0, w, h, r, g, b, a);
}
glBindTexture(GL_TEXTURE_2D, fbo->texture);
glBegin( GL_QUADS ); /* Draw A Quad */
glTexCoord2f(0,1); glVertex2f(0 + x, 0 + y);
glTexCoord2f(0,0); glVertex2f(0 + x, h + y);
glTexCoord2f(1,0); glVertex2f(w + x, h + y);
glTexCoord2f(1,1); glVertex2f(w + x, 0 + y);
glEnd( ); /* Done Drawing The Quad */
if (lua_isuserdata(L, 6)) glUseProgramObjectARB(0);
if (lua_isnumber(L, 7)) glColor4f(1, 1, 1, 1);
return 0;
}
static const struct luaL_reg displaylib[] =
{
{"forceRedraw", sdl_redraw_screen},
......@@ -1092,6 +1228,7 @@ static const struct luaL_reg displaylib[] =
{"newFont", sdl_new_font},
{"newSurface", sdl_new_surface},
{"newTile", sdl_new_tile},
{"newFBO", gl_new_fbo},
{"drawStringNewSurface", sdl_surface_drawstring_newsurface},
{"drawStringBlendedNewSurface", sdl_surface_drawstring_newsurface_aa},
{"loadImage", sdl_load_image},
......@@ -1136,6 +1273,14 @@ static const struct luaL_reg sdl_font_reg[] =
{NULL, NULL},
};
static const struct luaL_reg gl_fbo_reg[] =
{
{"__gc", gl_free_fbo},
{"toScreen", gl_fbo_toscreen},
{"use", gl_fbo_use},
{NULL, NULL},
};
/******************************************************************
******************************************************************
* RNG *
......@@ -1810,6 +1955,7 @@ int luaopen_core(lua_State *L)
auxiliar_newclass(L, "fov{core}", fov_reg);
auxiliar_newclass(L, "fov{cache}", fovcache_reg);
auxiliar_newclass(L, "gl{texture}", sdl_texture_reg);
auxiliar_newclass(L, "gl{fbo}", gl_fbo_reg);
auxiliar_newclass(L, "sdl{surface}", sdl_surface_reg);
auxiliar_newclass(L, "sdl{font}", sdl_font_reg);
luaL_openlib(L, "core.fov", fovlib, 0);
......
......@@ -31,7 +31,7 @@
//#include "shaders.h"
extern bool shaders_active;
extern void useShader(GLuint p, int x, int y, float r, float g, float b, float a);
extern void useShader(GLuint p, int x, int y, int w, int h, float r, float g, float b, float a);
static int map_object_new(lua_State *L)
{
......@@ -431,7 +431,7 @@ void display_map_quad(map_type *map, int dx, int dy, map_object *m, int i, int j
}
glColor4f(r, g, b, a);
int z;
if (m->shader) useShader(m->shader, i, j, r, g, b, a);
if (m->shader) useShader(m->shader, i, j, map->tile_w, map->tile_h, r, g, b, a);
for (z = (!shaders_active) ? 0 : (m->nb_textures - 1); z >= 0; z--)
{
if (multitexture_active && shaders_active) glActiveTexture(GL_TEXTURE0+z);
......
......@@ -31,7 +31,7 @@
bool shaders_active = TRUE;
void useShader(GLuint p, int x, int y, float r, float g, float b, float a)
void useShader(GLuint p, int x, int y, int w, int h, float r, float g, float b, float a)
{
CHECKGL(glUseProgramObjectARB(p));
GLfloat t = SDL_GetTicks();
......@@ -47,6 +47,10 @@ void useShader(GLuint p, int x, int y, float r, float g, float b, float a)
c[0] = x;
c[1] = y;
CHECKGL(glUniform2fvARB(glGetUniformLocationARB(p, "mapCoord"), 1, c));
c[0] = w;
c[1] = h;
CHECKGL(glUniform2fvARB(glGetUniformLocationARB(p, "texSize"), 1, c));
}
static GLuint loadShader(const char* code, GLuint type)
......@@ -180,7 +184,7 @@ static int program_set_uniform_number2(lua_State *L)
i[1] = luaL_checknumber(L, 4);
CHECKGL(glUseProgramObjectARB(*p));
CHECKGL(glUniform2fvARB(glGetUniformLocationARB(*p, var), 2, i));
CHECKGL(glUniform2fvARB(glGetUniformLocationARB(*p, var), 1, i));
CHECKGL(glUseProgramObjectARB(0));
return 0;
}
......@@ -195,7 +199,7 @@ static int program_set_uniform_number3(lua_State *L)
i[2] = luaL_checknumber(L, 5);
CHECKGL(glUseProgramObjectARB(*p));
CHECKGL(glUniform3fvARB(glGetUniformLocationARB(*p, var), 3, i));
CHECKGL(glUniform3fvARB(glGetUniformLocationARB(*p, var), 1, i));
CHECKGL(glUseProgramObjectARB(0));
return 0;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment