Implemented building support.

develop
Warmist 2013-06-26 01:18:26 +03:00
parent 1d2accbe94
commit fbbae3e900
3 changed files with 181 additions and 21 deletions

@ -299,6 +299,14 @@ matLightDef* lightingEngineViewscreen::getMaterial(int matType,int matIndex)
else else
return NULL; return NULL;
} }
buildingLightDef* lightingEngineViewscreen::getBuilding(df::building* bld)
{
auto it=buildingDefs.find(std::make_tuple((int)bld->getType(),(int)bld->getSubtype(),(int)bld->getCustomType()));
if(it!=buildingDefs.end())
return &it->second;
else
return NULL;
}
void lightingEngineViewscreen::applyMaterial(int tileId,const matLightDef& mat,float size, float thickness) void lightingEngineViewscreen::applyMaterial(int tileId,const matLightDef& mat,float size, float thickness)
{ {
if(mat.isTransparent) if(mat.isTransparent)
@ -501,6 +509,11 @@ void lightingEngineViewscreen::doOcupancyAndLights()
df::tiletype type = b->tiletypeAt(gpos); df::tiletype type = b->tiletypeAt(gpos);
df::tile_designation d = b->DesignationAt(gpos); df::tile_designation d = b->DesignationAt(gpos);
if(d.bits.hidden)
{
curCell=lightCell(0,0,0);
continue; // do not process hidden stuff
}
//df::tile_occupancy o = b->OccupancyAt(gpos); //df::tile_occupancy o = b->OccupancyAt(gpos);
df::tiletype_shape shape = ENUM_ATTR(tiletype,shape,type); df::tiletype_shape shape = ENUM_ATTR(tiletype,shape,type);
df::tiletype_shape_basic basic_shape = ENUM_ATTR(tiletype_shape, basic_shape, shape); df::tiletype_shape_basic basic_shape = ENUM_ATTR(tiletype_shape, basic_shape, shape);
@ -511,7 +524,7 @@ void lightingEngineViewscreen::doOcupancyAndLights()
matLightDef* lightDef=getMaterial(mat.mat_type,mat.mat_index); matLightDef* lightDef=getMaterial(mat.mat_type,mat.mat_index);
if(!lightDef || !lightDef->isTransparent) if(!lightDef || !lightDef->isTransparent)
lightDef=&matWall; lightDef=&matWall;
if(shape==df::tiletype_shape::BROOK_BED || d.bits.hidden ) if(shape==df::tiletype_shape::BROOK_BED )
{ {
curCell=lightCell(0,0,0); curCell=lightCell(0,0,0);
} }
@ -643,34 +656,58 @@ void lightingEngineViewscreen::doOcupancyAndLights()
for(size_t i = 0; i < df::global::world->buildings.all.size(); i++) for(size_t i = 0; i < df::global::world->buildings.all.size(); i++)
{ {
df::building *bld = df::global::world->buildings.all[i]; df::building *bld = df::global::world->buildings.all[i];
if(window_z!=bld->z) if(window_z!=bld->z)
continue; continue;
if(bld->getBuildStage()<bld->getMaxBuildStage()) //only work if fully built
continue;
df::coord2d p1(bld->x1,bld->y1); df::coord2d p1(bld->x1,bld->y1);
df::coord2d p2(bld->x2,bld->y2); df::coord2d p2(bld->x2,bld->y2);
p1=worldToViewportCoord(p1,vp,window2d); p1=worldToViewportCoord(p1,vp,window2d);
p2=worldToViewportCoord(p1,vp,window2d); p2=worldToViewportCoord(p1,vp,window2d);
if(isInViewport(p1,vp)||isInViewport(p2,vp)) if(isInViewport(p1,vp)||isInViewport(p2,vp))
{ {
int tile=getIndex(p1.x,p1.y); //TODO multitile buildings. How they would work? int tile=getIndex(p1.x,p1.y); //TODO multitile buildings. How they would work?
df::building_type type = bld->getType(); df::building_type type = bld->getType();
buildingLightDef* def=getBuilding(bld);
if (type == df::enums::building_type::WindowGlass || type==df::enums::building_type::WindowGem) if(!def)
continue;
if(def->poweredOnly && bld->isUnpowered())
continue;
if(type==df::enums::building_type::Door)
{ {
applyMaterial(tile,bld->mat_type,bld->mat_index); df::building_doorst* door=static_cast<df::building_doorst*>(bld);
if(!door->door_flags.bits.closed)
continue;
} }
if (type == df::enums::building_type::Table)
if(def->useMaterial)
{ {
addLight(tile,candle); matLightDef* mat=getMaterial(bld->mat_type,bld->mat_index);
if(!mat)mat=&matWall;
if(def->light.isEmiting)
{
addLight(tile,def->light.makeSource());
}
else if(mat->isEmiting)
{
addLight(tile,mat->makeSource());
}
if(def->light.isTransparent)
{
ocupancy[tile]*=def->light.transparency;
}
else
{
ocupancy[tile]*=mat->transparency;
}
} }
if (type==df::enums::building_type::Statue) else
{ {
addLight(tile,torch); applyMaterial(tile,def->light);
}
if(type==df::enums::building_type::Door)
{
df::building_doorst* door=static_cast<df::building_doorst*>(bld);
if(door->door_flags.bits.closed)
applyMaterial(tile,bld->mat_type,bld->mat_index,1,&matWall);
} }
} }
} }
@ -698,6 +735,10 @@ lightCell lua_parseLightCell(lua_State* L)
//Lua::GetOutput(L)->print("got cell(%f,%f,%f)\n",ret.r,ret.g,ret.b); //Lua::GetOutput(L)->print("got cell(%f,%f,%f)\n",ret.r,ret.g,ret.b);
return ret; return ret;
} }
#define GETLUAFLAG(field,name) lua_getfield(L,-1,"flags");\
if(lua_isnil(L,-1)){field=false;}\
else{lua_getfield(L,-1,#name);field=lua_isnil(L,-1);lua_pop(L,1);}\
lua_pop(L,1)
matLightDef lua_parseMatDef(lua_State* L) matLightDef lua_parseMatDef(lua_State* L)
{ {
@ -726,7 +767,10 @@ matLightDef lua_parseMatDef(lua_State* L)
} }
else else
lua_pop(L,1); lua_pop(L,1);
//todo flags GETLUAFLAG(ret.flicker,"flicker");
GETLUAFLAG(ret.useThickness,"useThickness");
GETLUAFLAG(ret.sizeModifiesPower,"sizeModifiesPower");
GETLUAFLAG(ret.sizeModifiesRange,"sizeModifiesRange");
return ret; return ret;
} }
int lightingEngineViewscreen::parseMaterials(lua_State* L) int lightingEngineViewscreen::parseMaterials(lua_State* L)
@ -783,6 +827,48 @@ int lightingEngineViewscreen::parseSpecial(lua_State* L)
return 0; return 0;
} }
#undef LOAD_SPECIAL #undef LOAD_SPECIAL
int lightingEngineViewscreen::parseBuildings(lua_State* L)
{
auto engine= (lightingEngineViewscreen*)lua_touserdata(L, 1);
engine->buildingDefs.clear();
Lua::StackUnwinder unwinder(L);
lua_getfield(L,2,"buildings");
if(!lua_istable(L,-1))
{
luaL_error(L,"Buildings table not found.");
return 0;
}
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
int type=lua_tonumber(L,-2);
if(!lua_istable(L,-1))
{
luaL_error(L,"Broken building definitions.");
}
//os->print("Processing type:%d\n",type);
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
int subtype=lua_tonumber(L,-2);
//os->print("\tProcessing subtype:%d\n",index);
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
int custom=lua_tonumber(L,-2);
//os->print("\tProcessing custom:%d\n",index);
buildingLightDef current;
current.light=lua_parseMatDef(L);
engine->buildingDefs[std::make_tuple(type,subtype,custom)]=current;
GETLUAFLAG(current.poweredOnly,"poweredOnly");
GETLUAFLAG(current.useMaterial,"useMaterial");
lua_pop(L, 1);
}
lua_pop(L, 1);
}
lua_pop(L, 1);
}
lua_pop(L,1);
return 0;
}
void lightingEngineViewscreen::defaultSettings() void lightingEngineViewscreen::defaultSettings()
{ {
matAmbience=matLightDef(lightCell(0.85f,0.85f,0.85f)); matAmbience=matLightDef(lightCell(0.85f,0.85f,0.85f));
@ -833,6 +919,11 @@ void lightingEngineViewscreen::loadSettings()
lua_pushvalue(s,env); lua_pushvalue(s,env);
Lua::SafeCall(out,s,2,0); Lua::SafeCall(out,s,2,0);
lua_pushcfunction(s, parseBuildings);
lua_pushlightuserdata(s, this);
lua_pushvalue(s,env);
Lua::SafeCall(out,s,2,0);
out.print("%d buildings loaded\n",buildingDefs.size());
} }
} }
@ -843,3 +934,4 @@ void lightingEngineViewscreen::loadSettings()
} }
lua_pop(s,1); lua_pop(s,1);
} }
#undef GETLUAFLAG

@ -3,6 +3,7 @@
#include "renderer_opengl.hpp" #include "renderer_opengl.hpp"
#include "Types.h" #include "Types.h"
#include <map> #include <map>
#include <tuple>
#include "modules/MapCache.h" #include "modules/MapCache.h"
struct renderer_light : public renderer_wrap { struct renderer_light : public renderer_wrap {
@ -102,11 +103,10 @@ struct lightSource
}; };
struct matLightDef struct matLightDef
{ {
int mat_index;
int mat_type;
bool isTransparent; bool isTransparent;
lightCell transparency; lightCell transparency;
bool isEmiting; bool isEmiting;
bool useThickness;
bool sizeModifiesPower; bool sizeModifiesPower;
bool sizeModifiesRange; bool sizeModifiesRange;
bool flicker; bool flicker;
@ -123,6 +123,12 @@ struct matLightDef
return lightSource(emitColor,radius); return lightSource(emitColor,radius);
} }
}; };
struct buildingLightDef
{
matLightDef light;
bool poweredOnly;
bool useMaterial;
};
class lightingEngineViewscreen:public lightingEngine class lightingEngineViewscreen:public lightingEngine
{ {
public: public:
@ -149,10 +155,13 @@ private:
bool addLight(int tileId,const lightSource& light); bool addLight(int tileId,const lightSource& light);
matLightDef* getMaterial(int matType,int matIndex); matLightDef* getMaterial(int matType,int matIndex);
buildingLightDef* getBuilding(df::building* bld);
//apply material to cell //apply material to cell
void applyMaterial(int tileId,const matLightDef& mat,float size=1, float thickness = 1); void applyMaterial(int tileId,const matLightDef& mat,float size=1, float thickness = 1);
//try to find and apply material, if failed return false, and if def!=null then apply def. //try to find and apply material, if failed return false, and if def!=null then apply def.
bool applyMaterial(int tileId,int matType,int matIndex,float size=1,const matLightDef* def=NULL); bool applyMaterial(int tileId,int matType,int matIndex,float size=1,const matLightDef* def=NULL);
size_t inline getIndex(int x,int y) size_t inline getIndex(int x,int y)
{ {
return x*h+y; return x*h+y;
@ -168,6 +177,7 @@ private:
static int parseMaterials(lua_State* L); static int parseMaterials(lua_State* L);
static int parseSpecial(lua_State* L); static int parseSpecial(lua_State* L);
static int parseBuildings(lua_State* L);
//special stuff //special stuff
matLightDef matLava; matLightDef matLava;
matLightDef matIce; matLightDef matIce;
@ -179,7 +189,8 @@ private:
float levelDim; float levelDim;
//materials //materials
std::map<std::pair<int,int>,matLightDef> matDefs; std::map<std::pair<int,int>,matLightDef> matDefs;
//buildings
std::map<std::tuple<int,int,int>,buildingLightDef> buildingDefs;
int w,h; int w,h;
DFHack::rect2d mapPort; DFHack::rect2d mapPort;
}; };

@ -8,8 +8,9 @@ for k,v in pairs(ret) do
_ENV[k]=v _ENV[k]=v
end end
-- add material by id (index,mat pair or token string or a type number), flags is a table of strings -- add material by id (index,mat pair or token string or a type number), flags is a table of strings
-- supported flags: -- supported flags (but not implemented):
-- flicker -- flicker
-- useThickness -- use thickness of stuff in transparency calculation
-- sizeModifiesPower -- sizeModifiesPower
-- sizeModifiesRange -- sizeModifiesRange
function addMaterial(id,transparency,emitance,radius,flags) function addMaterial(id,transparency,emitance,radius,flags)
@ -27,8 +28,58 @@ function addMaterial(id,transparency,emitance,radius,flags)
materials[matinfo.type]=materials[matinfo.type] or {} materials[matinfo.type]=materials[matinfo.type] or {}
materials[matinfo.type][matinfo.index]=makeMaterialDef(transparency,emitance,radius,flags) materials[matinfo.type][matinfo.index]=makeMaterialDef(transparency,emitance,radius,flags)
end end
function buildingLookUp(id)
local tokens={}
local lookup={ Workshop=df.workshop_type,Furnace=df.furnace_type,Trap=df.trap_type,
SiegeEngine=siegeengine_type}
for i in string.gmatch(id, "[^:]+") do
table.insert(tokens,i)
end
local ret={}
ret.type=df.building_type[tokens[1]]
if tokens[2] then
local type_array=lookup[tokens[1]]
if type_array then
ret.subtype=type_array[tokens[2]]
end
if tokens[2]=="Custom" and tokens[3] then --TODO cache for faster lookup
if ret.type==df.building_type.Workshop then
for k,v in pairs(df.global.world.raws.buildings.workshops) do
if v.code==tokens[3] then
ret.custom=v.id
break
end
end
elseif ret.type==df.building_type.Furnace then
for k,v in pairs(df.global.world.raws.buildings.furnaces) do
if v.code==tokens[3] then
ret.custom=v.id
break
end
end
end
end
end
return ret
end
-- add building by id (string e.g. "Statue" or "Workshop:Masons", flags is a table of strings
-- supported flags:
-- useMaterial --uses material, but the defined things overwrite
-- poweredOnly --glow only when powered
function addBuilding(id,transparency,emitance,radius,flags) function addBuilding(id,transparency,emitance,radius,flags)
--stuff local bld=buildingLookUp(id)
local mat=makeMaterialDef(transparency,emitance,radius,flags)
buildings[bld.type]=buildings[bld.type] or {}
if bld.subtype then
if bld.custom then
buildings[bld.type][bld.subtype]=buildings[bld.type][bld.subtype] or {}
buildings[bld.type][bld.subtype][bld.custom]=mat
else
buildings[bld.type][bld.subtype]={[-1]=mat}
end
else
buildings[bld.type][-1]={[-1]=mat}
end
end end
function makeMaterialDef(transparency,emitance,radius,flags) function makeMaterialDef(transparency,emitance,radius,flags)
local flg local flg
@ -43,6 +94,7 @@ end
------------------------------------------------------------------------ ------------------------------------------------------------------------
---------------- Configuration Starts Here ------------------------- ---------------- Configuration Starts Here -------------------------
------------------------------------------------------------------------ ------------------------------------------------------------------------
is_computer_quantum=false -- will enable more costly parts in the future
--special things --special things
special.LAVA=makeMaterialDef({0.8,0.2,0.2},{0.8,0.2,0.2},5) special.LAVA=makeMaterialDef({0.8,0.2,0.2},{0.8,0.2,0.2},5)
special.WATER=makeMaterialDef({0.5,0.5,0.8}) special.WATER=makeMaterialDef({0.5,0.5,0.8})
@ -71,3 +123,8 @@ addMaterial("INORGANIC:ADAMANTINE",{0.1,0.3,0.3},{0.1,0.3,0.3},4)
addMaterial("CREATURE:DRAGON:BLOOD",nil,{0.6,0.1,0.1},4) addMaterial("CREATURE:DRAGON:BLOOD",nil,{0.6,0.1,0.1},4)
-- TODO gems -- TODO gems
--buildings --buildings
addBuilding("Statue",{1,1,1},{0.9,0.75,0.3},8)
addBuilding("Bed",{1,1,1},{0.3,0.2,0.0},2)
addBuilding("WindowGlass",nil,nil,0,{"useMaterial"})
addBuilding("WindowGem",nil,nil,0,{"useMaterial"})
addBuilding("Door",nil,nil,0,{"useMaterial"}) -- special case, only closed door obstruct/emit light