dfhack/plugins/rendermax/renderer_light.hpp

280 lines
8.2 KiB
C++

2013-06-23 10:25:42 -06:00
#ifndef RENDERER_LIGHT_INCLUDED
#define RENDERER_LIGHT_INCLUDED
#include "renderer_opengl.hpp"
#include "Types.h"
#include <map>
2013-06-25 16:18:26 -06:00
#include <tuple>
2013-06-29 11:55:07 -06:00
#include <stack>
#include <memory>
2013-06-24 15:59:32 -06:00
#include "modules/MapCache.h"
2013-06-29 11:55:07 -06:00
bool isInRect(const df::coord2d& pos,const DFHack::rect2d& rect);
2013-06-23 10:25:42 -06:00
struct renderer_light : public renderer_wrap {
private:
void colorizeTile(int x,int y)
{
const int tile = x*(df::global::gps->dimy) + y;
old_opengl* p=reinterpret_cast<old_opengl*>(parent);
float *fg = p->fg + tile * 4 * 6;
float *bg = p->bg + tile * 4 * 6;
float *tex = p->tex + tile * 2 * 6;
2013-06-30 06:05:59 -06:00
rgbf light=lightGrid[tile];
2013-06-23 10:25:42 -06:00
for (int i = 0; i < 6; i++) {
*(fg++) *= light.r;
*(fg++) *= light.g;
*(fg++) *= light.b;
*(fg++) = 1;
*(bg++) *= light.r;
*(bg++) *= light.g;
*(bg++) *= light.b;
*(bg++) = 1;
}
}
void reinitLightGrid(int w,int h)
{
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex);
lightGrid.resize(w*h);
}
void reinitLightGrid()
{
reinitLightGrid(df::global::gps->dimy,df::global::gps->dimx);
}
public:
tthread::fast_mutex dataMutex;
2013-06-30 06:05:59 -06:00
std::vector<rgbf> lightGrid;
2013-06-23 10:25:42 -06:00
renderer_light(renderer* parent):renderer_wrap(parent)
{
reinitLightGrid();
}
virtual void update_tile(int32_t x, int32_t y) {
renderer_wrap::update_tile(x,y);
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex);
colorizeTile(x,y);
};
virtual void update_all() {
renderer_wrap::update_all();
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex);
for (int x = 0; x < df::global::gps->dimx; x++)
for (int y = 0; y < df::global::gps->dimy; y++)
colorizeTile(x,y);
};
virtual void grid_resize(int32_t w, int32_t h) {
renderer_wrap::grid_resize(w,h);
reinitLightGrid(w,h);
};
virtual void resize(int32_t w, int32_t h) {
renderer_wrap::resize(w,h);
reinitLightGrid();
2013-06-23 10:25:42 -06:00
}
};
class lightingEngine
{
public:
lightingEngine(renderer_light* target):myRenderer(target){}
2013-06-30 13:03:07 -06:00
virtual ~lightingEngine(){}
2013-06-23 10:25:42 -06:00
virtual void reinit()=0;
virtual void calculate()=0;
virtual void updateWindow()=0;
virtual void loadSettings()=0;
2013-06-25 11:36:53 -06:00
virtual void clear()=0;
virtual void setHour(float h)=0;
virtual void debug(bool enable)=0;
2013-06-23 10:25:42 -06:00
protected:
renderer_light* myRenderer;
};
struct lightSource
{
2013-06-30 06:05:59 -06:00
rgbf power;
2013-06-23 10:25:42 -06:00
int radius;
bool flicker;
lightSource():power(0,0,0),radius(0),flicker(false)
{
}
2013-06-30 06:05:59 -06:00
lightSource(rgbf power,int radius);
float powerSquared()const
{
return power.r*power.r+power.g*power.g+power.b*power.b;
}
void combine(const lightSource& other);
2013-06-23 10:25:42 -06:00
};
struct matLightDef
{
bool isTransparent;
2013-06-30 06:05:59 -06:00
rgbf transparency;
bool isEmiting;
bool flicker;
2013-06-30 06:05:59 -06:00
rgbf emitColor;
int radius;
matLightDef():isTransparent(false),isEmiting(false),transparency(0,0,0),emitColor(0,0,0),radius(0){}
2013-06-30 06:05:59 -06:00
matLightDef(rgbf transparency,rgbf emit,int rad):isTransparent(true),isEmiting(true),
transparency(transparency),emitColor(emit),radius(rad){}
2013-06-30 06:05:59 -06:00
matLightDef(rgbf emit,int rad):isTransparent(false),isEmiting(true),emitColor(emit),radius(rad),transparency(0,0,0){}
matLightDef(rgbf transparency):isTransparent(true),isEmiting(false),transparency(transparency){}
lightSource makeSource(float size=1) const
{
if(size>0.999 && size<1.001)
return lightSource(emitColor,radius);
else
return lightSource(emitColor*size,radius*size);//todo check if this is sane
}
};
2013-06-25 16:18:26 -06:00
struct buildingLightDef
{
matLightDef light;
bool poweredOnly;
bool useMaterial;
float thickness;
float size;
buildingLightDef():poweredOnly(false),useMaterial(true),thickness(1.0f),size(1.0f){}
2013-06-25 16:18:26 -06:00
};
2013-06-29 11:55:07 -06:00
class lightThread;
class lightingEngineViewscreen;
class lightThreadDispatch
{
lightingEngineViewscreen *parent;
public:
DFHack::rect2d viewPort;
std::vector<std::unique_ptr<lightThread> > threadPool;
std::vector<lightSource>& lights;
tthread::mutex occlusionMutex;
tthread::condition_variable occlusionDone; //all threads wait for occlusion to finish
2013-06-30 13:03:07 -06:00
bool occlusionReady;
2013-06-29 11:55:07 -06:00
tthread::mutex unprocessedMutex;
std::stack<DFHack::rect2d> unprocessed; //stack of parts of map where lighting is not finished
2013-06-30 06:05:59 -06:00
std::vector<rgbf>& occlusion;
2013-06-29 11:55:07 -06:00
tthread::mutex writeLock; //mutex for lightMap
2013-06-30 06:05:59 -06:00
std::vector<rgbf>& lightMap;
2013-06-29 11:55:07 -06:00
tthread::condition_variable writesDone;
int writeCount;
lightThreadDispatch(lightingEngineViewscreen* p);
2013-06-30 13:03:07 -06:00
~lightThreadDispatch();
2013-06-29 11:55:07 -06:00
void signalDoneOcclusion();
void shutdown();
void waitForWrites();
int getW();
int getH();
void start(int count);
};
class lightThread
{
2013-06-30 06:05:59 -06:00
std::vector<rgbf> canvas;
2013-06-29 11:55:07 -06:00
lightThreadDispatch& dispatch;
DFHack::rect2d myRect;
void work(); //main light calculation function
void combine(); //combine existing canvas into global lightmap
public:
tthread::thread *myThread;
bool isDone; //no mutex, because bool is atomic
lightThread(lightThreadDispatch& dispatch);
~lightThread();
void run();
private:
void doLight(int x,int y);
2013-06-30 06:05:59 -06:00
void doRay(rgbf power,int cx,int cy,int tx,int ty);
rgbf lightUpCell(rgbf power,int dx,int dy,int tx,int ty);
2013-06-29 11:55:07 -06:00
};
2013-06-23 10:25:42 -06:00
class lightingEngineViewscreen:public lightingEngine
{
public:
lightingEngineViewscreen(renderer_light* target);
~lightingEngineViewscreen();
2013-06-23 10:25:42 -06:00
void reinit();
void calculate();
void updateWindow();
void loadSettings();
2013-06-25 11:36:53 -06:00
void clear();
void debug(bool enable){doDebug=enable;};
2013-06-23 10:25:42 -06:00
private:
2013-06-24 15:59:32 -06:00
df::coord2d worldToViewportCoord(const df::coord2d& in,const DFHack::rect2d& r,const df::coord2d& window2d) ;
2013-06-29 11:55:07 -06:00
2013-06-24 15:59:32 -06:00
void doSun(const lightSource& sky,MapExtras::MapCache& map);
void doOcupancyAndLights();
2013-06-30 06:05:59 -06:00
rgbf propogateSun(MapExtras::Block* b, int x,int y,const rgbf& in,bool lastLevel);
void doRay(std::vector<rgbf> & target, rgbf power,int cx,int cy,int tx,int ty);
2013-06-23 10:25:42 -06:00
void doFovs();
2013-06-30 06:05:59 -06:00
void doLight(std::vector<rgbf> & target, int index);
rgbf lightUpCell(std::vector<rgbf> & target, rgbf power,int dx,int dy,int tx,int ty);
bool addLight(int tileId,const lightSource& light);
2013-06-30 06:05:59 -06:00
void addOclusion(int tileId,const rgbf& c,float thickness);
2013-06-24 15:59:32 -06:00
matLightDef* getMaterial(int matType,int matIndex);
2013-06-25 16:18:26 -06:00
buildingLightDef* getBuilding(df::building* bld);
//apply material to cell
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.
bool applyMaterial(int tileId,int matType,int matIndex,float size=1,float thickness = 1,const matLightDef* def=NULL);
2013-06-25 16:18:26 -06:00
2013-06-23 10:25:42 -06:00
size_t inline getIndex(int x,int y)
{
return x*h+y;
}
df::coord2d inline getCoords(int index)
{
return df::coord2d(index/h, index%h);
}
//maps
2013-06-30 06:05:59 -06:00
std::vector<rgbf> lightMap;
std::vector<rgbf> ocupancy;
2013-06-23 10:25:42 -06:00
std::vector<lightSource> lights;
//Threading stuff
2013-06-29 11:55:07 -06:00
lightThreadDispatch threading;
//misc
void setHour(float h){dayHour=h;};
2013-06-29 11:55:07 -06:00
int getW()const {return w;}
int getH()const {return h;}
public:
void lightWorkerThread(void * arg);
private:
2013-06-30 06:05:59 -06:00
rgbf getSkyColor(float v);
bool doDebug;
//settings
float daySpeed;
float dayHour; //<0 to cycle
2013-06-30 06:05:59 -06:00
std::vector<rgbf> dayColors; // a gradient of colors, first to 0, last to 24
///set up sane settings if setting file does not exist.
void defaultSettings();
static int parseMaterials(lua_State* L);
static int parseSpecial(lua_State* L);
2013-06-25 16:18:26 -06:00
static int parseBuildings(lua_State* L);
//special stuff
matLightDef matLava;
matLightDef matIce;
matLightDef matAmbience;
matLightDef matCursor;
2013-06-24 15:59:32 -06:00
matLightDef matWall;
matLightDef matWater;
matLightDef matCitizen;
float levelDim;
//materials
std::map<std::pair<int,int>,matLightDef> matDefs;
2013-06-25 16:18:26 -06:00
//buildings
std::map<std::tuple<int,int,int>,buildingLightDef> buildingDefs;
2013-06-23 10:25:42 -06:00
int w,h;
DFHack::rect2d mapPort;
2013-06-29 11:55:07 -06:00
friend lightThreadDispatch;
2013-06-23 10:25:42 -06:00
};
2013-06-30 06:05:59 -06:00
rgbf blend(rgbf a,rgbf b);
rgbf blendMax(rgbf a,rgbf b);
#endif