Added creature lights and item lights.

develop
Warmist 2013-09-22 14:50:03 +03:00
parent 830d9900fb
commit 72259c8eba
3 changed files with 263 additions and 33 deletions

@ -24,6 +24,9 @@
#include "df/building_floodgatest.h"
#include "df/plant.h"
#include "df/plant_raw.h"
#include "df/item.h"
#include "df/items_other_id.h"
#include "df/unit.h"
#include <vector>
@ -219,11 +222,11 @@ void plotLineAA(int x0, int y0, int x1, int y1,rgbf power,const std::function<rg
power=sumPower;
}
}
rgbf blendMax(rgbf a,rgbf b)
rgbf blendMax(const rgbf& a,const rgbf& b)
{
return rgbf(std::max(a.r,b.r),std::max(a.g,b.g),std::max(a.b,b.b));
}
rgbf blend(rgbf a,rgbf b)
rgbf blend(const rgbf& a,const rgbf& b)
{
return blendMax(a,b);
}
@ -274,8 +277,6 @@ void lightingEngineViewscreen::updateWindow()
rect2d vp=getMapViewport();
myRenderer->invalidateRect(vp.first.x,vp.first.y,vp.second.x-vp.first.x,vp.second.y-vp.first.y);
//myRenderer->invalidate();
//std::copy(lightMap.begin(),lightMap.end(),myRenderer->lightGrid.begin());
}
static size_t max_list_size = 100000; // Avoid iterating over huge lists
@ -324,7 +325,7 @@ void addPlant(const std::string& id,std::map<int,lightSource>& map,const lightSo
map[nId]=v;
}
}
matLightDef* lightingEngineViewscreen::getMaterial(int matType,int matIndex)
matLightDef* lightingEngineViewscreen::getMaterialDef( int matType,int matIndex )
{
auto it=matDefs.find(std::make_pair(matType,matIndex));
if(it!=matDefs.end())
@ -332,7 +333,7 @@ matLightDef* lightingEngineViewscreen::getMaterial(int matType,int matIndex)
else
return NULL;
}
buildingLightDef* lightingEngineViewscreen::getBuilding(df::building* bld)
buildingLightDef* lightingEngineViewscreen::getBuildingDef( df::building* bld )
{
auto it=buildingDefs.find(std::make_tuple((int)bld->getType(),(int)bld->getSubtype(),(int)bld->getCustomType()));
if(it!=buildingDefs.end())
@ -340,6 +341,34 @@ buildingLightDef* lightingEngineViewscreen::getBuilding(df::building* bld)
else
return NULL;
}
creatureLightDef* lightingEngineViewscreen::getCreatureDef(df::unit* u)
{
auto it=creatureDefs.find(std::make_pair(int(u->race),int(u->caste)));
if(it!=creatureDefs.end())
return &it->second;
else
{
auto it2=creatureDefs.find(std::make_pair(int(u->race),int(-1)));
if(it2!=creatureDefs.end())
return &it2->second;
else
return NULL;
}
}
itemLightDef* lightingEngineViewscreen::getItemDef(df::item* it)
{
auto iter=itemDefs.find(std::make_pair(int(it->getType()),int(it->getSubtype())));
if(iter!=itemDefs.end())
return &iter->second;
else
{
auto iter2=itemDefs.find(std::make_pair(int(it->getType()),int(-1)));
if(iter2!=itemDefs.end())
return &iter2->second;
else
return NULL;
}
}
void lightingEngineViewscreen::applyMaterial(int tileId,const matLightDef& mat,float size, float thickness)
{
if(mat.isTransparent)
@ -353,7 +382,7 @@ void lightingEngineViewscreen::applyMaterial(int tileId,const matLightDef& mat,f
}
bool lightingEngineViewscreen::applyMaterial(int tileId,int matType,int matIndex,float size,float thickness,const matLightDef* def)
{
matLightDef* m=getMaterial(matType,matIndex);
matLightDef* m=getMaterialDef(matType,matIndex);
if(m)
{
applyMaterial(tileId,*m,size,thickness);
@ -392,7 +421,7 @@ rgbf lightingEngineViewscreen::propogateSun(MapExtras::Block* b, int x,int y,con
ret*=matIce.transparency.pow(1.0f/7.0f);
}
lightDef=getMaterial(mat.mat_type,mat.mat_index);
lightDef=getMaterialDef(mat.mat_type,mat.mat_index);
if(!lightDef || !lightDef->isTransparent)
lightDef=&matWall;
@ -502,8 +531,6 @@ rgbf lightingEngineViewscreen::getSkyColor(float v)
}
void lightingEngineViewscreen::doOcupancyAndLights()
{
// TODO better curve (+red dawn ?)
float daycol;
if(dayHour<0)
{
@ -516,11 +543,6 @@ void lightingEngineViewscreen::doOcupancyAndLights()
rgbf sky_col=getSkyColor(daycol);
lightSource sky(sky_col, -1);//auto calculate best size
lightSource candle(rgbf(0.96f,0.84f,0.03f),5);
lightSource torch(rgbf(0.9f,0.75f,0.3f),8);
//perfectly blocking material
MapExtras::MapCache cache;
doSun(sky,cache);
@ -573,7 +595,7 @@ void lightingEngineViewscreen::doOcupancyAndLights()
DFHack::t_matpair mat=b->staticMaterialAt(gpos);
matLightDef* lightDef=getMaterial(mat.mat_type,mat.mat_index);
matLightDef* lightDef=getMaterialDef(mat.mat_type,mat.mat_index);
if(!lightDef || !lightDef->isTransparent)
lightDef=&matWall;
if(shape==df::tiletype_shape::BROOK_BED )
@ -643,6 +665,7 @@ void lightingEngineViewscreen::doOcupancyAndLights()
}
}
}
//plants
for(int i=0;i<block->plants.size();i++)
{
@ -665,7 +688,7 @@ void lightingEngineViewscreen::doOcupancyAndLights()
if(ev_type==df::block_square_event_type::material_spatter)
{
df::block_square_event_material_spatterst* spatter=static_cast<df::block_square_event_material_spatterst*>(ev);
matLightDef* m=getMaterial(spatter->mat_type,spatter->mat_index);
matLightDef* m=getMaterialDef(spatter->mat_type,spatter->mat_index);
if(!m)
continue;
if(!m->isEmiting)
@ -696,15 +719,47 @@ void lightingEngineViewscreen::doOcupancyAndLights()
applyMaterial(tile,matCursor);
}
//citizen only emit light, if defined
if(matCitizen.isEmiting)
//or other creatures
if(matCitizen.isEmiting || creatureDefs.size()>0)
for (int i=0;i<df::global::world->units.active.size();++i)
{
df::unit *u = df::global::world->units.active[i];
coord2d pos=worldToViewportCoord(coord2d(u->pos.x,u->pos.y),vp,window2d);
if(u->pos.z==window_z && isInRect(pos,vp))
{
if (DFHack::Units::isCitizen(u) && !u->counters.unconscious)
addLight(getIndex(pos.x,pos.y),matCitizen.makeSource());
creatureLightDef *def=getCreatureDef(u);
if(def && !u->flags1.bits.dead)
{
addLight(getIndex(pos.x,pos.y),def->light.makeSource());
}
}
}
//items
if(itemDefs.size()>0)
{
std::vector<df::item*>& vec=df::global::world->items.other[items_other_id::IN_PLAY];
for(size_t i=0;i<vec.size();i++)
{
df::item* curItem=vec[i];
df::coord itemPos=DFHack::Items::getPosition(curItem);
coord2d pos=worldToViewportCoord(itemPos,vp,window2d);
itemLightDef* mat=0;
if( itemPos.z==window_z && isInRect(pos,vp) && (mat=getItemDef(curItem)) )
{
if( ((mat->equiped || mat->haul ||mat->inBuilding ||mat->inContainer) && curItem->flags.bits.in_inventory)|| //TODO split this up
(mat->onGround && curItem->flags.bits.on_ground) )
{
if(mat->light.isEmiting)
addLight(getIndex(pos.x,pos.y),mat->light.makeSource());
if(!mat->light.isTransparent)
addOclusion(getIndex(pos.x,pos.y),mat->light.transparency,1);
}
}
}
}
//buildings
for(size_t i = 0; i < df::global::world->buildings.all.size(); i++)
{
@ -728,7 +783,7 @@ void lightingEngineViewscreen::doOcupancyAndLights()
else
tile=getIndex(p2.x,p2.y);
df::building_type type = bld->getType();
buildingLightDef* def=getBuilding(bld);
buildingLightDef* def=getBuildingDef(bld);
if(!def)
continue;
if(type==df::enums::building_type::Door)
@ -747,7 +802,7 @@ void lightingEngineViewscreen::doOcupancyAndLights()
if(def->useMaterial)
{
matLightDef* mat=getMaterial(bld->mat_type,bld->mat_index);
matLightDef* mat=getMaterialDef(bld->mat_type,bld->mat_index);
if(!mat)mat=&matWall;
if(!def->poweredOnly || !bld->isUnpowered()) //not powered. Add occlusion only.
{
@ -906,6 +961,72 @@ int lightingEngineViewscreen::parseSpecial(lua_State* L)
return 0;
}
#undef LOAD_SPECIAL
int lightingEngineViewscreen::parseItems(lua_State* L)
{
auto engine= (lightingEngineViewscreen*)lua_touserdata(L, 1);
engine->itemDefs.clear();
Lua::StackUnwinder unwinder(L);
lua_getfield(L,2,"items");
if(!lua_istable(L,-1))
{
luaL_error(L,"Items table not found.");
return 0;
}
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
if(!lua_istable(L,-1))
luaL_error(L,"Broken item definitions.");
lua_getfield(L,-1,"type");
int type=lua_tonumber(L,-1);
lua_pop(L,1);
lua_getfield(L,-1,"subtype");
int subtype=luaL_optinteger(L,-1,-1);
lua_pop(L,1);
itemLightDef item;
lua_getfield(L,-1,"light");
item.light=lua_parseMatDef(L);
GETLUAFLAG(item.haul,"hauling");
GETLUAFLAG(item.equiped,"equiped");
GETLUAFLAG(item.inBuilding,"inBuilding");
GETLUAFLAG(item.inContainer,"contained");
GETLUAFLAG(item.onGround,"onGround");
GETLUAFLAG(item.useMaterial,"useMaterial");
engine->itemDefs[std::make_pair(type,subtype)]=item;
lua_pop(L,2);
}
lua_pop(L,1);
return 0;
}
int lightingEngineViewscreen::parseCreatures(lua_State* L)
{
auto engine= (lightingEngineViewscreen*)lua_touserdata(L, 1);
engine->creatureDefs.clear();
Lua::StackUnwinder unwinder(L);
lua_getfield(L,2,"creatures");
if(!lua_istable(L,-1))
{
luaL_error(L,"Creatures table not found.");
return 0;
}
lua_pushnil(L);
while (lua_next(L, -2) != 0) {
if(!lua_istable(L,-1))
luaL_error(L,"Broken creature definitions.");
lua_getfield(L,-1,"race");
int race=lua_tonumber(L,-1);
lua_pop(L,1);
lua_getfield(L,-1,"caste");
int caste=lua_tonumber(L,-1);
lua_pop(L,1);
creatureLightDef cr;
lua_getfield(L,-1,"light");
cr.light=lua_parseMatDef(L);
engine->creatureDefs[std::make_pair(race,caste)]=cr;
lua_pop(L,2);
}
lua_pop(L,1);
return 0;
}
int lightingEngineViewscreen::parseBuildings(lua_State* L)
{
auto engine= (lightingEngineViewscreen*)lua_touserdata(L, 1);
@ -1018,6 +1139,18 @@ void lightingEngineViewscreen::loadSettings()
lua_pushvalue(s,env);
Lua::SafeCall(out,s,2,0);
out.print("%d buildings loaded\n",buildingDefs.size());
lua_pushcfunction(s, parseCreatures);
lua_pushlightuserdata(s, this);
lua_pushvalue(s,env);
Lua::SafeCall(out,s,2,0);
out.print("%d creatures loaded\n",creatureDefs.size());
lua_pushcfunction(s, parseItems);
lua_pushlightuserdata(s, this);
lua_pushvalue(s,env);
Lua::SafeCall(out,s,2,0);
out.print("%d items loaded\n",itemDefs.size());
}
}
@ -1147,7 +1280,7 @@ rgbf lightThread::lightUpCell(rgbf power,int dx,int dy,int tx,int ty)
else
return rgbf();
}
void lightThread::doRay(rgbf power,int cx,int cy,int tx,int ty)
void lightThread::doRay(const rgbf& power,int cx,int cy,int tx,int ty)
{
using namespace std::placeholders;

@ -166,6 +166,22 @@ struct buildingLightDef
float size;
buildingLightDef():poweredOnly(false),useMaterial(true),thickness(1.0f),size(1.0f){}
};
struct itemLightDef
{
matLightDef light;
bool haul;
bool equiped;
bool onGround;
bool inBuilding;
bool inContainer;
bool useMaterial;
itemLightDef():haul(true),equiped(true),onGround(true),inBuilding(false),inContainer(false),useMaterial(true){}
};
struct creatureLightDef
{
matLightDef light;
};
class lightThread;
class lightingEngineViewscreen;
class lightThreadDispatch
@ -215,7 +231,7 @@ public:
void run();
private:
void doLight(int x,int y);
void doRay(rgbf power,int cx,int cy,int tx,int ty);
void doRay(const rgbf& power,int cx,int cy,int tx,int ty);
rgbf lightUpCell(rgbf power,int dx,int dy,int tx,int ty);
};
class lightingEngineViewscreen:public lightingEngine
@ -247,8 +263,10 @@ private:
bool addLight(int tileId,const lightSource& light);
void addOclusion(int tileId,const rgbf& c,float thickness);
matLightDef* getMaterial(int matType,int matIndex);
buildingLightDef* getBuilding(df::building* bld);
matLightDef* getMaterialDef(int matType,int matIndex);
buildingLightDef* getBuildingDef(df::building* bld);
creatureLightDef* getCreatureDef(df::unit* u);
itemLightDef* getItemDef(df::item* it);
//apply material to cell
void applyMaterial(int tileId,const matLightDef& mat,float size=1, float thickness = 1);
@ -291,6 +309,8 @@ private:
static int parseMaterials(lua_State* L);
static int parseSpecial(lua_State* L);
static int parseBuildings(lua_State* L);
static int parseItems(lua_State* L);
static int parseCreatures(lua_State* L);
//special stuff
matLightDef matLava;
matLightDef matIce;
@ -304,10 +324,14 @@ private:
std::unordered_map<std::pair<int,int>,matLightDef> matDefs;
//buildings
std::unordered_map<std::tuple<int,int,int>,buildingLightDef> buildingDefs;
//creatures
std::unordered_map<std::pair<int,int>,creatureLightDef> creatureDefs;
//items
std::unordered_map<std::pair<int,int>,itemLightDef> itemDefs;
int w,h;
DFHack::rect2d mapPort;
friend lightThreadDispatch;
};
rgbf blend(rgbf a,rgbf b);
rgbf blendMax(rgbf a,rgbf b);
rgbf blend(const rgbf& a,const rgbf& b);
rgbf blendMax(const rgbf& a,const rgbf& b);
#endif

@ -4,6 +4,8 @@ ret=ret[1]
ret.materials={}
ret.buildings={}
ret.special={}
ret.items={}
ret.creatures={}
for k,v in pairs(ret) do
_ENV[k]=v
end
@ -28,7 +30,7 @@ end
function buildingLookUp(id)
local tokens={}
local lookup={ Workshop=df.workshop_type,Furnace=df.furnace_type,Trap=df.trap_type,
SiegeEngine=siegeengine_type}
SiegeEngine=df.siegeengine_type}
for i in string.gmatch(id, "[^:]+") do
table.insert(tokens,i)
end
@ -44,20 +46,85 @@ function buildingLookUp(id)
for k,v in pairs(df.global.world.raws.buildings.workshops) do
if v.code==tokens[3] then
ret.custom=v.id
break
return ret
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
return ret
end
end
end
end
qerror("Invalid custom building:"..tokens[3])
end
return ret
end
function itemLookup(id)
local ret={}
local tokens={}
for i in string.gmatch(id, "[^:]+") do
table.insert(tokens,i)
end
ret.type=df.item_type[tokens[1]]
ret.subtype=-1
if tokens[2] then
for k,v in ipairs(df.global.world.raws.itemdefs.all) do --todo lookup correct itemdef
if v.id==tokens[2] then
ret.subtype=v.subtype
return ret
end
end
qerror("Failed item subtype lookup:"..tokens[2])
end
return ret
end
function creatureLookup(id)
local ret={}
local tokens={}
for i in string.gmatch(id, "[^:]+") do
table.insert(tokens,i)
end
for k,v in ipairs(df.global.world.raws.creatures.all) do
if v.creature_id==tokens[1] then
ret.type=k
if tokens[2] then
for k,v in ipairs(v.caste) do
if v.caste_id==tokens[2] then
ret.subtype=k
break
end
end
if ret.subtype==nil then
qerror("caste "..tokens[2].." for "..tokens[1].." not found")
end
end
return ret
end
end
qerror("Failed to find race:"..tokens[1])
end
-- add creature by id ("DWARF" or "DWARF:MALE")
-- supported flags:
function addCreature(id,transparency,emitance,radius,flags)
local crId=creatureLookup(id)
local mat=makeMaterialDef(transparency,emitance,radius,flags)
table.insert(creatures,{race=crId.type,caste=crId.subtype or -1, light=mat})
end
-- add item by id ( "TOTEM" or "WEAPON:PICK" or "WEAPON" for all the weapon types)
-- supported flags:
-- hauling --active when hauled TODO::currently all mean same thing...
-- equiped --active while equiped TODO::currently all mean same thing...
-- inBuilding --active in building TODO::currently all mean same thing...
-- contained --active in container TODO::currently all mean same thing...
-- onGround --active on ground
-- useMaterial --uses material, but the defined things overwrite
function addItem(id,transparency,emitance,radius,flags)
local itemId=itemLookup(id)
local mat=makeMaterialDef(transparency,emitance,radius,flags)
table.insert(items,{["type"]=itemId.type,subtype=itemId.subtype,light=mat})
end
-- add building by id (string e.g. "Statue" or "Workshop:Masons", flags is a table of strings
-- supported flags:
@ -147,3 +214,9 @@ 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
addBuilding("Floodgate",nil,nil,0,{"useMaterial"}) -- special case, only closed door obstruct/emit light
--creatures
addCreature("ELEMENTMAN_MAGMA",{0.8,0.2,0.2},{0.8,0.2,0.2},5)
--items
addItem("GEM",nil,nil,{"useMaterial","onGround"})
addItem("ROUGH",nil,nil,{"useMaterial","onGround"})
addItem("SMALLGEM",nil,nil,{"useMaterial","onGround"})