|
|
|
@ -1,6 +1,7 @@
|
|
|
|
|
#include "renderer_light.hpp"
|
|
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
|
|
#include "Types.h"
|
|
|
|
|
|
|
|
|
@ -13,7 +14,9 @@
|
|
|
|
|
#include "df/flow_info.h"
|
|
|
|
|
#include "df/world.h"
|
|
|
|
|
#include "df/building.h"
|
|
|
|
|
|
|
|
|
|
#include "df/building_doorst.h"
|
|
|
|
|
#include "df/plant.h"
|
|
|
|
|
#include "df/plant_raw.h"
|
|
|
|
|
|
|
|
|
|
using df::global::gps;
|
|
|
|
|
using namespace DFHack;
|
|
|
|
@ -54,6 +57,7 @@ rect2d getMapViewport()
|
|
|
|
|
lightingEngineViewscreen::lightingEngineViewscreen(renderer_light* target):lightingEngine(target)
|
|
|
|
|
{
|
|
|
|
|
reinit();
|
|
|
|
|
initRawSpecific();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void lightingEngineViewscreen::reinit()
|
|
|
|
@ -65,6 +69,7 @@ void lightingEngineViewscreen::reinit()
|
|
|
|
|
size_t size=w*h;
|
|
|
|
|
lightMap.resize(size,lightCell(1,1,1));
|
|
|
|
|
ocupancy.resize(size);
|
|
|
|
|
lights.resize(size);
|
|
|
|
|
}
|
|
|
|
|
void plotCircle(int xm, int ym, int r,std::function<void(int,int)> setPixel)
|
|
|
|
|
{
|
|
|
|
@ -107,18 +112,23 @@ bool lightingEngineViewscreen::lightUpCell(lightCell& power,int dx,int dy,int tx
|
|
|
|
|
{
|
|
|
|
|
size_t tile=getIndex(tx,ty);
|
|
|
|
|
float dsq=dx*dx+dy*dy;
|
|
|
|
|
float dt=sqrt(dsq);
|
|
|
|
|
lightCell& v=ocupancy[tile];
|
|
|
|
|
lightSource& ls=lights[tile];
|
|
|
|
|
bool wallhack=false;
|
|
|
|
|
bool outsidehack=false;
|
|
|
|
|
if(v.r+v.g+v.b==0)
|
|
|
|
|
wallhack=true;
|
|
|
|
|
if(v.r<0)
|
|
|
|
|
outsidehack=true;
|
|
|
|
|
if (dsq>0 && !wallhack && !outsidehack)
|
|
|
|
|
|
|
|
|
|
if (dsq>0 && !wallhack)
|
|
|
|
|
{
|
|
|
|
|
power.r=power.r*(pow(v.r,dt));
|
|
|
|
|
power.g=power.g*(pow(v.g,dt));
|
|
|
|
|
power.b=power.b*(pow(v.b,dt));
|
|
|
|
|
}
|
|
|
|
|
if(ls.radius>0 && dsq>0)
|
|
|
|
|
{
|
|
|
|
|
power.r=power.r*(pow(v.r,dsq));
|
|
|
|
|
power.g=power.g*(pow(v.g,dsq));
|
|
|
|
|
power.b=power.b*(pow(v.b,dsq));
|
|
|
|
|
if(power<ls.power)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
//float dt=sqrt(dsq);
|
|
|
|
|
lightCell oldCol=lightMap[tile];
|
|
|
|
@ -127,8 +137,6 @@ bool lightingEngineViewscreen::lightUpCell(lightCell& power,int dx,int dy,int tx
|
|
|
|
|
|
|
|
|
|
if(wallhack)
|
|
|
|
|
return false;
|
|
|
|
|
if(dsq>0 && outsidehack)
|
|
|
|
|
return false;
|
|
|
|
|
float pwsq=power.r*power.r+power.g*power.g+power.b*power.b;
|
|
|
|
|
return pwsq>levelDim*levelDim;
|
|
|
|
|
}
|
|
|
|
@ -145,17 +153,32 @@ void lightingEngineViewscreen::doFovs()
|
|
|
|
|
{
|
|
|
|
|
mapPort=getMapViewport();
|
|
|
|
|
using namespace std::placeholders;
|
|
|
|
|
for(size_t i=0;i<lights.size();i++)
|
|
|
|
|
{
|
|
|
|
|
lightSource& csource=lights[i];
|
|
|
|
|
plotCircle(csource.pos.x,csource.pos.y,csource.radius,std::bind(&lightingEngineViewscreen::doRay,this,csource.power,csource.pos.x,csource.pos.y,_1,_2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(int i=mapPort.first.x;i<mapPort.second.x;i++)
|
|
|
|
|
for(int j=mapPort.first.y;j<mapPort.second.y;j++)
|
|
|
|
|
{
|
|
|
|
|
lightSource& csource=lights[getIndex(i,j)];
|
|
|
|
|
if(csource.radius>0)
|
|
|
|
|
{
|
|
|
|
|
lightCell power=csource.power;
|
|
|
|
|
int radius =csource.radius;
|
|
|
|
|
if(csource.flicker)
|
|
|
|
|
{
|
|
|
|
|
float flicker=(rand()/(float)RAND_MAX)/2.0f+0.5f;
|
|
|
|
|
radius*=flicker;
|
|
|
|
|
power=power*flicker;
|
|
|
|
|
}
|
|
|
|
|
plotCircle(i,j,radius,
|
|
|
|
|
std::bind(&lightingEngineViewscreen::doRay,this,power,i,j,_1,_2));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void lightingEngineViewscreen::calculate()
|
|
|
|
|
{
|
|
|
|
|
rect2d vp=getMapViewport();
|
|
|
|
|
const lightCell dim(levelDim,levelDim,levelDim);
|
|
|
|
|
lightMap.assign(lightMap.size(),lightCell(1,1,1));
|
|
|
|
|
lights.assign(lights.size(),lightSource());
|
|
|
|
|
for(int i=vp.first.x;i<vp.second.x;i++)
|
|
|
|
|
for(int j=vp.first.y;j<vp.second.y;j++)
|
|
|
|
|
{
|
|
|
|
@ -171,6 +194,7 @@ void lightingEngineViewscreen::updateWindow()
|
|
|
|
|
if(lightMap.size()!=myRenderer->lightGrid.size())
|
|
|
|
|
{
|
|
|
|
|
reinit();
|
|
|
|
|
myRenderer->invalidate();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
std::swap(lightMap,myRenderer->lightGrid);
|
|
|
|
@ -180,14 +204,60 @@ void lightingEngineViewscreen::updateWindow()
|
|
|
|
|
myRenderer->invalidate();
|
|
|
|
|
//std::copy(lightMap.begin(),lightMap.end(),myRenderer->lightGrid.begin());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void lightSource::combine(const lightSource& other)
|
|
|
|
|
{
|
|
|
|
|
power=blend(power,other.power);
|
|
|
|
|
radius=std::max(other.radius,radius);//hack... but who cares
|
|
|
|
|
}
|
|
|
|
|
bool lightingEngineViewscreen::addLight(int tileId,const lightSource& light)
|
|
|
|
|
{
|
|
|
|
|
bool wasLight=lights[tileId].radius>0;
|
|
|
|
|
lights[tileId].combine(light);
|
|
|
|
|
if(light.flicker)
|
|
|
|
|
lights[tileId].flicker=true;
|
|
|
|
|
return wasLight;
|
|
|
|
|
}
|
|
|
|
|
lightCell getStandartColor(int colorId)
|
|
|
|
|
{
|
|
|
|
|
return lightCell(df::global::enabler->ccolor[colorId][0]/255.0f,
|
|
|
|
|
df::global::enabler->ccolor[colorId][1]/255.0f,
|
|
|
|
|
df::global::enabler->ccolor[colorId][2]/255.0f);
|
|
|
|
|
}
|
|
|
|
|
int getPlantNumber(const std::string& id)
|
|
|
|
|
{
|
|
|
|
|
std::vector<df::plant_raw*>& vec=df::plant_raw::get_vector();
|
|
|
|
|
for(int i=0;i<vec.size();i++)
|
|
|
|
|
{
|
|
|
|
|
if(vec[i]->id==id)
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
void addPlant(const std::string& id,std::map<int,lightSource>& map,const lightSource& v)
|
|
|
|
|
{
|
|
|
|
|
int nId=getPlantNumber(id);
|
|
|
|
|
if(nId>0)
|
|
|
|
|
{
|
|
|
|
|
map[nId]=v;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void lightingEngineViewscreen::initRawSpecific()
|
|
|
|
|
{
|
|
|
|
|
addPlant("TOWER_CAP",glowPlants,lightSource(lightCell(0.65,0.65,0.65),6));
|
|
|
|
|
addPlant("MUSHROOM_CUP_DIMPLE",glowPlants,lightSource(lightCell(0.03,0.03,0.5),3));
|
|
|
|
|
addPlant("CAVE MOSS",glowPlants,lightSource(lightCell(0.1,0.1,0.4),2));
|
|
|
|
|
addPlant("MUSHROOM_HELMET_PLUMP",glowPlants,lightSource(lightCell(0.2,0.1,0.6),2));
|
|
|
|
|
}
|
|
|
|
|
static size_t max_list_size = 100000; // Avoid iterating over huge lists
|
|
|
|
|
|
|
|
|
|
void lightingEngineViewscreen::doOcupancyAndLights()
|
|
|
|
|
{
|
|
|
|
|
lights.clear();
|
|
|
|
|
lightSource sun(lightCell(1,1,1),15);
|
|
|
|
|
lightSource lava(lightCell(0.8f,0.2f,0.2f),5);
|
|
|
|
|
lightSource candle(lightCell(0.96f,0.84f,0.03f),5);
|
|
|
|
|
lightSource torch(lightCell(0.9f,0.75f,0.3f),8);
|
|
|
|
|
rect2d vp=getMapViewport();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int window_x=*df::global::window_x;
|
|
|
|
|
int window_y=*df::global::window_y;
|
|
|
|
|
int window_z=*df::global::window_z;
|
|
|
|
@ -259,8 +329,9 @@ void lightingEngineViewscreen::doOcupancyAndLights()
|
|
|
|
|
|
|
|
|
|
if(cellArray[block_x][block_y].r >= 0.003f && cellArray[block_x][block_y].g >= 0.003f && cellArray[block_x][block_y].b >= 0.003f)
|
|
|
|
|
{
|
|
|
|
|
lightSource sun={cellArray[block_x][block_y],25,coord2d(wx,wy)};
|
|
|
|
|
lights.push_back(sun);
|
|
|
|
|
int tile=getIndex(wx,wy);
|
|
|
|
|
lightSource sun(cellArray[block_x][block_y],25);
|
|
|
|
|
addLight(tile,sun);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -270,19 +341,23 @@ void lightingEngineViewscreen::doOcupancyAndLights()
|
|
|
|
|
{
|
|
|
|
|
int wx=x-window_x+vp.first.x;
|
|
|
|
|
int wy=y-window_y+vp.first.y;
|
|
|
|
|
lightCell& curCell=ocupancy[getIndex(wx,wy)];
|
|
|
|
|
curCell=lightCell(0.8f,0.8f,0.8f);
|
|
|
|
|
int tile=getIndex(wx,wy);
|
|
|
|
|
lightCell& curCell=ocupancy[tile];
|
|
|
|
|
curCell=lightCell(0.85f,0.85f,0.85f);
|
|
|
|
|
df::tiletype* type = Maps::getTileType(x,y,window_z);
|
|
|
|
|
if(!type)
|
|
|
|
|
continue;
|
|
|
|
|
//if(!type)
|
|
|
|
|
//{
|
|
|
|
|
// //unallocated, do sky
|
|
|
|
|
// addLight(tile,sun);
|
|
|
|
|
// continue;
|
|
|
|
|
//}
|
|
|
|
|
df::tiletype_shape shape = ENUM_ATTR(tiletype,shape,*type);
|
|
|
|
|
df::tile_designation* d=Maps::getTileDesignation(x,y,window_z);
|
|
|
|
|
df::tile_designation* d2=Maps::getTileDesignation(x,y,window_z-1);
|
|
|
|
|
df::tile_occupancy* o=Maps::getTileOccupancy(x,y,window_z);
|
|
|
|
|
if(!o || !d )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if(shape==df::tiletype_shape::BROOK_BED || shape==df::tiletype_shape::WALL || shape==df::tiletype_shape::TREE /*|| o->bits.building*/)
|
|
|
|
|
if(shape==df::tiletype_shape::BROOK_BED || shape==df::tiletype_shape::WALL || shape==df::tiletype_shape::TREE || d->bits.hidden )
|
|
|
|
|
{
|
|
|
|
|
curCell=lightCell(0,0,0);
|
|
|
|
|
}
|
|
|
|
@ -317,33 +392,55 @@ void lightingEngineViewscreen::doOcupancyAndLights()
|
|
|
|
|
curCell*=lightCell(0.75f,0.95f,0.95f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (type == df::enums::building_type::Table)
|
|
|
|
|
{
|
|
|
|
|
addLight(tile,candle);
|
|
|
|
|
}
|
|
|
|
|
if (type==df::enums::building_type::Statue)
|
|
|
|
|
{
|
|
|
|
|
addLight(tile,torch);
|
|
|
|
|
}
|
|
|
|
|
if (type==df::enums::building_type::WindowGem)
|
|
|
|
|
{
|
|
|
|
|
DFHack::MaterialInfo mat(bld->mat_index,bld->mat_type);
|
|
|
|
|
if(mat.isInorganic())
|
|
|
|
|
{
|
|
|
|
|
int color=mat.inorganic->material.basic_color[0]+8*mat.inorganic->material.basic_color[2];
|
|
|
|
|
curCell*=getStandartColor(color);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(type==df::enums::building_type::Door)
|
|
|
|
|
{
|
|
|
|
|
df::building_doorst* door=static_cast<df::building_doorst*>(bld);
|
|
|
|
|
if(door->door_flags.bits.closed)
|
|
|
|
|
curCell*=lightCell(0,0,0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(!d->bits.liquid_type && d->bits.flow_size>3 )
|
|
|
|
|
{
|
|
|
|
|
curCell=lightCell(0.5f,0.5f,0.6f);
|
|
|
|
|
curCell*=lightCell(0.7f,0.7f,0.8f);
|
|
|
|
|
}
|
|
|
|
|
//todo constructions
|
|
|
|
|
|
|
|
|
|
//lights
|
|
|
|
|
if((d->bits.liquid_type && d->bits.flow_size>0)|| (d2 && d2->bits.liquid_type && d2->bits.flow_size>0))
|
|
|
|
|
{
|
|
|
|
|
lightSource lava={lightCell(0.8f,0.2f,0.2f),5,coord2d(wx,wy)};
|
|
|
|
|
lights.push_back(lava);
|
|
|
|
|
}
|
|
|
|
|
if(d->bits.outside && d->bits.flow_size==0)
|
|
|
|
|
if((d->bits.liquid_type && d->bits.flow_size>0)||
|
|
|
|
|
(
|
|
|
|
|
(shape==df::tiletype_shape::EMPTY || shape==df::tiletype_shape::RAMP_TOP || shape==df::tiletype_shape::STAIR_DOWN || shape==df::tiletype_shape::STAIR_UPDOWN )
|
|
|
|
|
&& d2 && d2->bits.liquid_type && d2->bits.flow_size>0)
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
curCell=lightCell(-1,-1,-1);//Marking as outside so no calculation is done on it
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addLight(tile,lava);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(int blockx=window_x/16;blockx<=endBlockx;blockx++)
|
|
|
|
|
for(int blocky=window_y/16;blocky<=endBlocky;blocky++)
|
|
|
|
|
{
|
|
|
|
|
df::map_block* block=Maps::getBlock(blockx,blocky,window_z);
|
|
|
|
|
|
|
|
|
|
if(!block)
|
|
|
|
|
continue;
|
|
|
|
|
for(int i=0;i<block->flows.size();i++)
|
|
|
|
@ -354,6 +451,7 @@ void lightingEngineViewscreen::doOcupancyAndLights()
|
|
|
|
|
df::coord2d pos=f->pos;
|
|
|
|
|
int wx=pos.x-window_x+vp.first.x;
|
|
|
|
|
int wy=pos.y-window_y+vp.first.y;
|
|
|
|
|
int tile=getIndex(wx,wy);
|
|
|
|
|
if(wx>=vp.first.x && wy>=vp.first.y && wx<=vp.second.x && wy<=vp.second.y)
|
|
|
|
|
{
|
|
|
|
|
lightCell fireColor;
|
|
|
|
@ -369,10 +467,36 @@ void lightingEngineViewscreen::doOcupancyAndLights()
|
|
|
|
|
{
|
|
|
|
|
fireColor=lightCell(0.64f,0.0f,0.0f);
|
|
|
|
|
}
|
|
|
|
|
lightSource fire={fireColor,f->density/5,coord2d(wx,wy)};
|
|
|
|
|
lights.push_back(fire);
|
|
|
|
|
lightSource fire(fireColor,f->density/5);
|
|
|
|
|
addLight(tile,fire);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(int i=0;i<block->plants.size();i++)
|
|
|
|
|
{
|
|
|
|
|
df::plant* cPlant=block->plants[i];
|
|
|
|
|
|
|
|
|
|
df::coord2d pos=cPlant->pos;
|
|
|
|
|
int wx=pos.x-window_x+vp.first.x;
|
|
|
|
|
int wy=pos.y-window_y+vp.first.y;
|
|
|
|
|
int tile=getIndex(wx,wy);
|
|
|
|
|
if(wx>=vp.first.x && wy>=vp.first.y && wx<=vp.second.x && wy<=vp.second.y)
|
|
|
|
|
{
|
|
|
|
|
auto it=glowPlants.find(cPlant->material);
|
|
|
|
|
if(it!=glowPlants.end())
|
|
|
|
|
{
|
|
|
|
|
addLight(tile,it->second);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(df::global::cursor->x>-30000)
|
|
|
|
|
{
|
|
|
|
|
lightSource cursor(lightCell(0.96f,0.84f,0.03f),11);
|
|
|
|
|
cursor.flicker=true;
|
|
|
|
|
int wx=df::global::cursor->x-window_x+vp.first.x;
|
|
|
|
|
int wy=df::global::cursor->y-window_y+vp.first.y;
|
|
|
|
|
int tile=getIndex(wx,wy);
|
|
|
|
|
addLight(tile,cursor);
|
|
|
|
|
}
|
|
|
|
|
}
|