Merge remote-tracking branch 'warmist/dev-rendermax' into develop
commit
ae8d630cfa
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
@ -0,0 +1,4 @@
|
||||
local _ENV = mkmodule('plugins.rendermax')
|
||||
|
||||
|
||||
return _ENV
|
@ -0,0 +1,41 @@
|
||||
PROJECT (rendermax)
|
||||
|
||||
# A list of source files
|
||||
SET(PROJECT_SRCS
|
||||
rendermax.cpp
|
||||
renderer_light.cpp
|
||||
)
|
||||
# A list of headers
|
||||
SET(PROJECT_HDRS
|
||||
renderer_opengl.hpp
|
||||
renderer_light.hpp
|
||||
)
|
||||
SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
# mash them together (headers are marked as headers and nothing will try to compile them)
|
||||
LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS})
|
||||
|
||||
|
||||
#linux
|
||||
IF(UNIX)
|
||||
add_definitions(-DLINUX_BUILD)
|
||||
SET(PROJECT_LIBS
|
||||
# add any extra linux libs here
|
||||
lua
|
||||
dfhack-tinythread
|
||||
${PROJECT_LIBS}
|
||||
)
|
||||
# windows
|
||||
ELSE(UNIX)
|
||||
SET(PROJECT_LIBS
|
||||
# add any extra windows libs here
|
||||
lua
|
||||
dfhack-tinythread
|
||||
${PROJECT_LIBS}
|
||||
$(NOINHERIT)
|
||||
)
|
||||
ENDIF(UNIX)
|
||||
# this makes sure all the stuff is put in proper places and linked to dfhack
|
||||
DFHACK_PLUGIN(rendermax ${PROJECT_SRCS} LINK_LIBRARIES ${PROJECT_LIBS})
|
||||
install(FILES rendermax.lua
|
||||
DESTINATION ${DFHACK_DATA_DESTINATION}/raw)
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,377 @@
|
||||
#ifndef RENDERER_LIGHT_INCLUDED
|
||||
#define RENDERER_LIGHT_INCLUDED
|
||||
#include "renderer_opengl.hpp"
|
||||
#include "Types.h"
|
||||
#include <tuple>
|
||||
#include <stack>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
// we are not using boost so let's cheat:
|
||||
template <class T>
|
||||
inline void hash_combine(std::size_t & seed, const T & v)
|
||||
{
|
||||
std::hash<T> hasher;
|
||||
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<typename S, typename T> struct hash<pair<S, T>>
|
||||
{
|
||||
inline size_t operator()(const pair<S, T> & v) const
|
||||
{
|
||||
size_t seed = 0;
|
||||
::hash_combine(seed, v.first);
|
||||
::hash_combine(seed, v.second);
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
template<typename S, typename T,typename V> struct hash<tuple<S, T, V>>
|
||||
{
|
||||
inline size_t operator()(const tuple<S, T, V> & v) const
|
||||
{
|
||||
size_t seed = 0;
|
||||
::hash_combine(seed,get<0>(v));
|
||||
::hash_combine(seed,get<1>(v));
|
||||
::hash_combine(seed,get<2>(v));
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
}
|
||||
// now we can hash pairs and tuples
|
||||
|
||||
#include "modules/MapCache.h"
|
||||
bool isInRect(const df::coord2d& pos,const DFHack::rect2d& rect);
|
||||
struct renderer_light : public renderer_wrap {
|
||||
private:
|
||||
float light_adaptation;
|
||||
rgbf adapt_to_light(const rgbf& light)
|
||||
{
|
||||
const float influence=0.0001f;
|
||||
const float max_adapt=1;
|
||||
const float min_adapt=0;
|
||||
float intensity=(light.r+light.g+light.b)/3.0;
|
||||
light_adaptation=intensity*influence+light_adaptation*(1-influence);
|
||||
float delta=light_adaptation-intensity;
|
||||
|
||||
rgbf ret;
|
||||
ret.r=light.r-delta;
|
||||
ret.g=light.g-delta;
|
||||
ret.b=light.b-delta;
|
||||
return ret;
|
||||
//if light_adaptation/intensity~1 then draw 1,1,1 (i.e. totally adapted)
|
||||
/*
|
||||
1. adapted -> 1,1,1 (full bright everything okay) delta=0 multiplier=?
|
||||
2. light adapted, real=dark -> darker delta>0 multiplier<1
|
||||
3. dark adapted, real=light -> lighter delta<0 multiplier>1
|
||||
*/
|
||||
//if light_adaptation/intensity!=0 then draw
|
||||
|
||||
}
|
||||
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;
|
||||
rgbf light=lightGrid[tile];//for light adaptation: rgbf light=adapt_to_light(lightGrid[tile]);
|
||||
|
||||
for (int i = 0; i < 6; i++) { //oh how sse would do wonders here, or shaders...
|
||||
*(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,rgbf(1,1,1));
|
||||
}
|
||||
void reinitLightGrid()
|
||||
{
|
||||
reinitLightGrid(df::global::gps->dimy,df::global::gps->dimx);
|
||||
}
|
||||
|
||||
public:
|
||||
tthread::fast_mutex dataMutex;
|
||||
std::vector<rgbf> lightGrid;
|
||||
renderer_light(renderer* parent):renderer_wrap(parent),light_adaptation(1)
|
||||
{
|
||||
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();
|
||||
}
|
||||
virtual void set_fullscreen()
|
||||
{
|
||||
renderer_wrap::set_fullscreen();
|
||||
reinitLightGrid();
|
||||
}
|
||||
virtual void zoom(df::zoom_commands z)
|
||||
{
|
||||
renderer_wrap::zoom(z);
|
||||
reinitLightGrid();
|
||||
}
|
||||
};
|
||||
class lightingEngine
|
||||
{
|
||||
public:
|
||||
lightingEngine(renderer_light* target):myRenderer(target){}
|
||||
virtual ~lightingEngine(){}
|
||||
virtual void reinit()=0;
|
||||
virtual void calculate()=0;
|
||||
|
||||
virtual void updateWindow()=0;
|
||||
virtual void preRender()=0;
|
||||
|
||||
virtual void loadSettings()=0;
|
||||
virtual void clear()=0;
|
||||
|
||||
virtual void setHour(float h)=0;
|
||||
virtual void debug(bool enable)=0;
|
||||
protected:
|
||||
renderer_light* myRenderer;
|
||||
};
|
||||
struct lightSource
|
||||
{
|
||||
rgbf power;
|
||||
int radius;
|
||||
bool flicker;
|
||||
lightSource():power(0,0,0),radius(0),flicker(false)
|
||||
{
|
||||
|
||||
}
|
||||
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);
|
||||
|
||||
};
|
||||
struct matLightDef
|
||||
{
|
||||
bool isTransparent;
|
||||
rgbf transparency;
|
||||
bool isEmiting;
|
||||
bool flicker;
|
||||
rgbf emitColor;
|
||||
int radius;
|
||||
matLightDef():isTransparent(false),isEmiting(false),transparency(0,0,0),emitColor(0,0,0),radius(0){}
|
||||
matLightDef(rgbf transparency,rgbf emit,int rad):isTransparent(true),isEmiting(true),
|
||||
transparency(transparency),emitColor(emit),radius(rad){}
|
||||
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
|
||||
}
|
||||
};
|
||||
struct buildingLightDef
|
||||
{
|
||||
matLightDef light;
|
||||
bool poweredOnly;
|
||||
bool useMaterial;
|
||||
float thickness;
|
||||
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
|
||||
{
|
||||
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
|
||||
bool occlusionReady;
|
||||
tthread::mutex unprocessedMutex;
|
||||
std::stack<DFHack::rect2d> unprocessed; //stack of parts of map where lighting is not finished
|
||||
std::vector<rgbf>& occlusion;
|
||||
int& num_diffusion;
|
||||
|
||||
tthread::mutex writeLock; //mutex for lightMap
|
||||
std::vector<rgbf>& lightMap;
|
||||
|
||||
tthread::condition_variable writesDone;
|
||||
int writeCount;
|
||||
|
||||
lightThreadDispatch(lightingEngineViewscreen* p);
|
||||
~lightThreadDispatch();
|
||||
void signalDoneOcclusion();
|
||||
void shutdown();
|
||||
void waitForWrites();
|
||||
|
||||
int getW();
|
||||
int getH();
|
||||
void start(int count);
|
||||
};
|
||||
class lightThread
|
||||
{
|
||||
std::vector<rgbf> canvas;
|
||||
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);
|
||||
void doRay(const rgbf& power,int cx,int cy,int tx,int ty,int num_diffuse);
|
||||
rgbf lightUpCell(rgbf power,int dx,int dy,int tx,int ty);
|
||||
};
|
||||
class lightingEngineViewscreen:public lightingEngine
|
||||
{
|
||||
public:
|
||||
lightingEngineViewscreen(renderer_light* target);
|
||||
~lightingEngineViewscreen();
|
||||
void reinit();
|
||||
void calculate();
|
||||
|
||||
void updateWindow();
|
||||
void preRender();
|
||||
void loadSettings();
|
||||
void clear();
|
||||
|
||||
void debug(bool enable){doDebug=enable;};
|
||||
private:
|
||||
void fixAdvMode(int mode);
|
||||
df::coord2d worldToViewportCoord(const df::coord2d& in,const DFHack::rect2d& r,const df::coord2d& window2d) ;
|
||||
|
||||
|
||||
void doSun(const lightSource& sky,MapExtras::MapCache& map);
|
||||
void doOcupancyAndLights();
|
||||
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);
|
||||
void doFovs();
|
||||
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);
|
||||
void addOclusion(int tileId,const rgbf& c,float thickness);
|
||||
|
||||
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);
|
||||
//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);
|
||||
|
||||
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
|
||||
std::vector<rgbf> lightMap;
|
||||
std::vector<rgbf> ocupancy;
|
||||
std::vector<lightSource> lights;
|
||||
|
||||
//Threading stuff
|
||||
int num_diffuse; //under same lock as ocupancy
|
||||
lightThreadDispatch threading;
|
||||
//misc
|
||||
void setHour(float h){dayHour=h;};
|
||||
|
||||
int getW()const {return w;}
|
||||
int getH()const {return h;}
|
||||
public:
|
||||
void lightWorkerThread(void * arg);
|
||||
private:
|
||||
rgbf getSkyColor(float v);
|
||||
bool doDebug;
|
||||
|
||||
//settings
|
||||
float daySpeed;
|
||||
float dayHour; //<0 to cycle
|
||||
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);
|
||||
static int parseBuildings(lua_State* L);
|
||||
static int parseItems(lua_State* L);
|
||||
static int parseCreatures(lua_State* L);
|
||||
//special stuff
|
||||
matLightDef matLava;
|
||||
matLightDef matIce;
|
||||
matLightDef matAmbience;
|
||||
matLightDef matCursor;
|
||||
matLightDef matWall;
|
||||
matLightDef matWater;
|
||||
matLightDef matCitizen;
|
||||
float levelDim;
|
||||
int adv_mode;
|
||||
//materials
|
||||
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 class lightThreadDispatch;
|
||||
};
|
||||
rgbf blend(const rgbf& a,const rgbf& b);
|
||||
rgbf blendMax(const rgbf& a,const rgbf& b);
|
||||
#endif
|
@ -0,0 +1,417 @@
|
||||
//original file from https://github.com/Baughn/Dwarf-Fortress--libgraphics-
|
||||
#ifndef RENDERER_OPENGL_INCLUDED
|
||||
#define RENDERER_OPENGL_INCLUDED
|
||||
|
||||
#include "tinythread.h"
|
||||
#include "fast_mutex.h"
|
||||
|
||||
#include "Core.h"
|
||||
#include <VTableInterpose.h>
|
||||
#include "df/renderer.h"
|
||||
#include "df/init.h"
|
||||
#include "df/enabler.h"
|
||||
#include "df/zoom_commands.h"
|
||||
#include "df/texture_handler.h"
|
||||
#include "df/graphic.h"
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
using df::renderer;
|
||||
using df::init;
|
||||
using df::enabler;
|
||||
|
||||
struct old_opengl:public renderer
|
||||
{
|
||||
void* sdlSurface;
|
||||
int32_t dispx,dispy;
|
||||
float *vertexes, *fg, *bg, *tex;
|
||||
int32_t zoom_steps,forced_steps,natural_w,natural_h;
|
||||
int32_t off_x,off_y,size_x,size_y;
|
||||
};
|
||||
struct renderer_wrap : public renderer {
|
||||
private:
|
||||
void set_to_null() {
|
||||
screen = NULL;
|
||||
screentexpos = NULL;
|
||||
screentexpos_addcolor = NULL;
|
||||
screentexpos_grayscale = NULL;
|
||||
screentexpos_cf = NULL;
|
||||
screentexpos_cbr = NULL;
|
||||
screen_old = NULL;
|
||||
screentexpos_old = NULL;
|
||||
screentexpos_addcolor_old = NULL;
|
||||
screentexpos_grayscale_old = NULL;
|
||||
screentexpos_cf_old = NULL;
|
||||
screentexpos_cbr_old = NULL;
|
||||
}
|
||||
|
||||
void copy_from_inner() {
|
||||
screen = parent->screen;
|
||||
screentexpos = parent->screentexpos;
|
||||
screentexpos_addcolor = parent->screentexpos_addcolor;
|
||||
screentexpos_grayscale = parent->screentexpos_grayscale;
|
||||
screentexpos_cf = parent->screentexpos_cf;
|
||||
screentexpos_cbr = parent->screentexpos_cbr;
|
||||
screen_old = parent->screen_old;
|
||||
screentexpos_old = parent->screentexpos_old;
|
||||
screentexpos_addcolor_old = parent->screentexpos_addcolor_old;
|
||||
screentexpos_grayscale_old = parent->screentexpos_grayscale_old;
|
||||
screentexpos_cf_old = parent->screentexpos_cf_old;
|
||||
screentexpos_cbr_old = parent->screentexpos_cbr_old;
|
||||
}
|
||||
|
||||
void copy_to_inner() {
|
||||
parent->screen = screen;
|
||||
parent->screentexpos = screentexpos;
|
||||
parent->screentexpos_addcolor = screentexpos_addcolor;
|
||||
parent->screentexpos_grayscale = screentexpos_grayscale;
|
||||
parent->screentexpos_cf = screentexpos_cf;
|
||||
parent->screentexpos_cbr = screentexpos_cbr;
|
||||
parent->screen_old = screen_old;
|
||||
parent->screentexpos_old = screentexpos_old;
|
||||
parent->screentexpos_addcolor_old = screentexpos_addcolor_old;
|
||||
parent->screentexpos_grayscale_old = screentexpos_grayscale_old;
|
||||
parent->screentexpos_cf_old = screentexpos_cf_old;
|
||||
parent->screentexpos_cbr_old = screentexpos_cbr_old;
|
||||
}
|
||||
public:
|
||||
renderer_wrap(renderer* parent):parent(parent)
|
||||
{
|
||||
copy_from_inner();
|
||||
}
|
||||
virtual void update_tile(int32_t x, int32_t y) {
|
||||
|
||||
copy_to_inner();
|
||||
parent->update_tile(x,y);
|
||||
};
|
||||
virtual void update_all() {
|
||||
copy_to_inner();
|
||||
parent->update_all();
|
||||
};
|
||||
virtual void render() {
|
||||
copy_to_inner();
|
||||
parent->render();
|
||||
};
|
||||
virtual void set_fullscreen() {
|
||||
copy_to_inner();
|
||||
parent->set_fullscreen();
|
||||
copy_from_inner();
|
||||
};
|
||||
virtual void zoom(df::zoom_commands z) {
|
||||
copy_to_inner();
|
||||
parent->zoom(z);
|
||||
copy_from_inner();
|
||||
};
|
||||
virtual void resize(int32_t w, int32_t h) {
|
||||
copy_to_inner();
|
||||
parent->resize(w,h);
|
||||
copy_from_inner();
|
||||
};
|
||||
virtual void grid_resize(int32_t w, int32_t h) {
|
||||
copy_to_inner();
|
||||
parent->grid_resize(w,h);
|
||||
copy_from_inner();
|
||||
};
|
||||
virtual ~renderer_wrap() {
|
||||
df::global::enabler->renderer=parent;
|
||||
};
|
||||
virtual bool get_mouse_coords(int32_t* x, int32_t* y) {
|
||||
return parent->get_mouse_coords(x,y);
|
||||
};
|
||||
virtual bool uses_opengl() {
|
||||
return parent->uses_opengl();
|
||||
};
|
||||
void invalidateRect(int32_t x,int32_t y,int32_t w,int32_t h)
|
||||
{
|
||||
for(int i=x;i<x+w;i++)
|
||||
for(int j=y;j<y+h;j++)
|
||||
{
|
||||
int index=i*df::global::gps->dimy + j;
|
||||
screen_old[index*4]=screen[index*4]+1;//ensure tile is different
|
||||
}
|
||||
};
|
||||
void invalidate()
|
||||
{
|
||||
invalidateRect(0,0,df::global::gps->dimx,df::global::gps->dimy);
|
||||
//df::global::gps->force_full_display_count++;
|
||||
};
|
||||
protected:
|
||||
renderer* parent;
|
||||
};
|
||||
struct renderer_trippy : public renderer_wrap {
|
||||
private:
|
||||
float rFloat()
|
||||
{
|
||||
return rand()/(float)RAND_MAX;
|
||||
}
|
||||
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;
|
||||
const float val=1/2.0;
|
||||
|
||||
float r=rFloat()*val - val/2;
|
||||
float g=rFloat()*val - val/2;
|
||||
float b=rFloat()*val - val/2;
|
||||
|
||||
float backr=rFloat()*val - val/2;
|
||||
float backg=rFloat()*val - val/2;
|
||||
float backb=rFloat()*val - val/2;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
*(fg++) += r;
|
||||
*(fg++) += g;
|
||||
*(fg++) += b;
|
||||
*(fg++) = 1;
|
||||
|
||||
*(bg++) += backr;
|
||||
*(bg++) += backg;
|
||||
*(bg++) += backb;
|
||||
*(bg++) = 1;
|
||||
}
|
||||
}
|
||||
public:
|
||||
renderer_trippy(renderer* parent):renderer_wrap(parent)
|
||||
{
|
||||
}
|
||||
virtual void update_tile(int32_t x, int32_t y) {
|
||||
renderer_wrap::update_tile(x,y);
|
||||
colorizeTile(x,y);
|
||||
};
|
||||
virtual void update_all() {
|
||||
renderer_wrap::update_all();
|
||||
for (int x = 0; x < df::global::gps->dimx; x++)
|
||||
for (int y = 0; y < df::global::gps->dimy; y++)
|
||||
colorizeTile(x,y);
|
||||
};
|
||||
};
|
||||
|
||||
struct rgbf
|
||||
{
|
||||
float r,g,b;
|
||||
rgbf():r(0),g(0),b(0)
|
||||
{
|
||||
|
||||
}
|
||||
rgbf(float r,float g,float b):r(r),g(g),b(b)
|
||||
{
|
||||
|
||||
}
|
||||
rgbf operator-(const rgbf& cell) const
|
||||
{
|
||||
return rgbf(r-cell.r,g-cell.g,b-cell.b);
|
||||
}
|
||||
rgbf operator*(float val)const
|
||||
{
|
||||
return rgbf(r*val,g*val,b*val);
|
||||
}
|
||||
rgbf operator/(float val) const
|
||||
{
|
||||
return rgbf(r/val,g/val,b/val);
|
||||
}
|
||||
rgbf operator*(const rgbf& cell) const
|
||||
{
|
||||
return rgbf(r*cell.r,g*cell.g,b*cell.b);
|
||||
}
|
||||
rgbf operator*=(float val)
|
||||
{
|
||||
r*=val;
|
||||
g*=val;
|
||||
b*=val;
|
||||
return *this;
|
||||
}
|
||||
rgbf operator*=(const rgbf& cell)
|
||||
{
|
||||
r*=cell.r;
|
||||
g*=cell.g;
|
||||
b*=cell.b;
|
||||
return *this;
|
||||
}
|
||||
rgbf operator+=(const rgbf& cell)
|
||||
{
|
||||
r+=cell.r;
|
||||
g+=cell.g;
|
||||
b+=cell.b;
|
||||
return *this;
|
||||
}
|
||||
rgbf operator+(const rgbf& other) const
|
||||
{
|
||||
return rgbf(r+other.r,g+other.g,b+other.b);
|
||||
}
|
||||
bool operator<=(const rgbf& other) const
|
||||
{
|
||||
return r<=other.r && g<=other.g && b<=other.b;
|
||||
}
|
||||
float dot(const rgbf& other) const
|
||||
{
|
||||
return r*other.r+g*other.g+b*other.b;
|
||||
}
|
||||
rgbf pow(const float exp) const
|
||||
{
|
||||
return rgbf(std::pow(r, exp), std::pow(g, exp), std::pow(b, exp));
|
||||
}
|
||||
rgbf pow(const int exp) const
|
||||
{
|
||||
return rgbf(std::pow(r, exp), std::pow(g, exp), std::pow(b, exp));
|
||||
}
|
||||
};
|
||||
struct renderer_test : 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;
|
||||
rgbf light=lightGrid[tile];
|
||||
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;
|
||||
std::vector<rgbf> lightGrid;
|
||||
renderer_test(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);
|
||||
//some sort of mutex or sth?
|
||||
//and then map read
|
||||
};
|
||||
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);
|
||||
//some sort of mutex or sth?
|
||||
//and then map read
|
||||
//same stuff for all of them i guess...
|
||||
};
|
||||
virtual void set_fullscreen()
|
||||
{
|
||||
renderer_wrap::set_fullscreen();
|
||||
reinitLightGrid();
|
||||
}
|
||||
virtual void zoom(df::zoom_commands z)
|
||||
{
|
||||
renderer_wrap::zoom(z);
|
||||
reinitLightGrid();
|
||||
}
|
||||
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(w,h);
|
||||
}
|
||||
};
|
||||
|
||||
struct rgba
|
||||
{
|
||||
float r,g,b,a;
|
||||
};
|
||||
struct renderer_lua : public renderer_wrap {
|
||||
private:
|
||||
void overwriteTile(int x,int y)
|
||||
{
|
||||
const int tile = xyToTile(x,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;
|
||||
rgbf fm=foreMult[tile];
|
||||
rgbf fo=foreOffset[tile];
|
||||
|
||||
rgbf bm=backMult[tile];
|
||||
rgbf bo=backOffset[tile];
|
||||
for (int i = 0; i < 6; i++) {
|
||||
rgba* fore=reinterpret_cast<rgba*>(fg);
|
||||
fore->r=fore->r*fm.r+fo.r;
|
||||
fore->g=fore->g*fm.g+fo.g;
|
||||
fore->b=fore->b*fm.b+fo.b;
|
||||
|
||||
fg+=4;
|
||||
rgba* back=reinterpret_cast<rgba*>(bg);
|
||||
back->r=back->r*bm.r+bo.r;
|
||||
back->g=back->g*bm.g+bo.g;
|
||||
back->b=back->b*bm.b+bo.b;
|
||||
bg+=4;
|
||||
}
|
||||
}
|
||||
void reinitGrids(int w,int h)
|
||||
{
|
||||
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex);
|
||||
foreOffset.resize(w*h);
|
||||
foreMult.resize(w*h);
|
||||
backOffset.resize(w*h);
|
||||
backMult.resize(w*h);
|
||||
}
|
||||
void reinitGrids()
|
||||
{
|
||||
reinitGrids(df::global::gps->dimy,df::global::gps->dimx);
|
||||
}
|
||||
public:
|
||||
tthread::fast_mutex dataMutex;
|
||||
std::vector<rgbf> foreOffset,foreMult;
|
||||
std::vector<rgbf> backOffset,backMult;
|
||||
inline int xyToTile(int x, int y)
|
||||
{
|
||||
return x*(df::global::gps->dimy) + y;
|
||||
}
|
||||
renderer_lua(renderer* parent):renderer_wrap(parent)
|
||||
{
|
||||
reinitGrids();
|
||||
}
|
||||
virtual void update_tile(int32_t x, int32_t y) {
|
||||
renderer_wrap::update_tile(x,y);
|
||||
tthread::lock_guard<tthread::fast_mutex> guard(dataMutex);
|
||||
overwriteTile(x,y);
|
||||
//some sort of mutex or sth?
|
||||
//and then map read
|
||||
};
|
||||
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++)
|
||||
overwriteTile(x,y);
|
||||
//some sort of mutex or sth?
|
||||
//and then map read
|
||||
//same stuff for all of them i guess...
|
||||
};
|
||||
virtual void grid_resize(int32_t w, int32_t h) {
|
||||
renderer_wrap::grid_resize(w,h);
|
||||
reinitGrids(w,h);
|
||||
};
|
||||
virtual void resize(int32_t w, int32_t h) {
|
||||
renderer_wrap::resize(w,h);
|
||||
reinitGrids(w,h);
|
||||
}
|
||||
};
|
||||
#endif
|
@ -0,0 +1,457 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <LuaTools.h>
|
||||
|
||||
#include <VTableInterpose.h>
|
||||
|
||||
#include "Core.h"
|
||||
#include "Console.h"
|
||||
#include "Export.h"
|
||||
#include "PluginManager.h"
|
||||
|
||||
#include <VTableInterpose.h>
|
||||
#include "df/renderer.h"
|
||||
#include "df/enabler.h"
|
||||
|
||||
#include "renderer_opengl.hpp"
|
||||
#include "renderer_light.hpp"
|
||||
|
||||
#include "df/viewscreen_dwarfmodest.h"
|
||||
#include "df/viewscreen_dungeonmodest.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using df::viewscreen_dungeonmodest;
|
||||
using df::viewscreen_dwarfmodest;
|
||||
|
||||
using namespace DFHack;
|
||||
using std::vector;
|
||||
using std::string;
|
||||
enum RENDERER_MODE
|
||||
{
|
||||
MODE_DEFAULT,MODE_TRIPPY,MODE_TRUECOLOR,MODE_LUA,MODE_LIGHT
|
||||
};
|
||||
RENDERER_MODE current_mode=MODE_DEFAULT;
|
||||
lightingEngine *engine=NULL;
|
||||
|
||||
static command_result rendermax(color_ostream &out, vector <string> & parameters);
|
||||
|
||||
DFHACK_PLUGIN("rendermax");
|
||||
|
||||
|
||||
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
|
||||
{
|
||||
commands.push_back(PluginCommand(
|
||||
"rendermax", "switch rendering engine.", rendermax, false,
|
||||
" rendermax trippy\n"
|
||||
" rendermax truecolor red|green|blue|white\n"
|
||||
" rendermax lua\n"
|
||||
" rendermax light - lighting engine\n"
|
||||
" rendermax light reload - reload the settings file\n"
|
||||
" rendermax light sun <x>|cycle - set time to x (in hours) or cycle (same effect if x<0)\n"
|
||||
" rendermax light occlusionON|occlusionOFF - debug the occlusion map\n"
|
||||
" rendermax disable\n"
|
||||
));
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
struct dwarmode_render_hook : viewscreen_dwarfmodest{
|
||||
typedef df::viewscreen_dwarfmodest interpose_base;
|
||||
DEFINE_VMETHOD_INTERPOSE(void,render,())
|
||||
{
|
||||
CoreSuspendClaimer suspend;
|
||||
engine->preRender();
|
||||
INTERPOSE_NEXT(render)();
|
||||
engine->calculate();
|
||||
engine->updateWindow();
|
||||
}
|
||||
};
|
||||
IMPLEMENT_VMETHOD_INTERPOSE(dwarmode_render_hook, render);
|
||||
|
||||
struct dungeon_render_hook : viewscreen_dungeonmodest{
|
||||
typedef df::viewscreen_dungeonmodest interpose_base;
|
||||
DEFINE_VMETHOD_INTERPOSE(void,render,())
|
||||
{
|
||||
CoreSuspendClaimer suspend;
|
||||
engine->preRender();
|
||||
INTERPOSE_NEXT(render)();
|
||||
engine->calculate();
|
||||
engine->updateWindow();
|
||||
}
|
||||
};
|
||||
IMPLEMENT_VMETHOD_INTERPOSE(dungeon_render_hook, render);
|
||||
|
||||
void removeOld()
|
||||
{
|
||||
CoreSuspender lock;
|
||||
if(engine)
|
||||
{
|
||||
INTERPOSE_HOOK(dwarmode_render_hook,render).apply(false);
|
||||
INTERPOSE_HOOK(dungeon_render_hook,render).apply(false);
|
||||
delete engine;
|
||||
engine=0;
|
||||
}
|
||||
if(current_mode!=MODE_DEFAULT)
|
||||
delete df::global::enabler->renderer;
|
||||
|
||||
current_mode=MODE_DEFAULT;
|
||||
}
|
||||
void installNew(df::renderer* r,RENDERER_MODE newMode)
|
||||
{
|
||||
df::global::enabler->renderer=r;
|
||||
current_mode=newMode;
|
||||
}
|
||||
static void lockGrids()
|
||||
{
|
||||
if(current_mode!=MODE_LUA)
|
||||
return ;
|
||||
renderer_lua* r=reinterpret_cast<renderer_lua*>(df::global::enabler->renderer);
|
||||
r->dataMutex.lock();
|
||||
}
|
||||
static void unlockGrids()
|
||||
{
|
||||
if(current_mode!=MODE_LUA)
|
||||
return ;
|
||||
renderer_lua* r=reinterpret_cast<renderer_lua*>(df::global::enabler->renderer);
|
||||
r->dataMutex.unlock();
|
||||
}
|
||||
static void resetGrids()
|
||||
{
|
||||
if(current_mode!=MODE_LUA)
|
||||
return ;
|
||||
renderer_lua* r=reinterpret_cast<renderer_lua*>(df::global::enabler->renderer);
|
||||
for(size_t i=0;i<r->foreMult.size();i++)
|
||||
{
|
||||
r->foreMult[i]=rgbf(1,1,1);
|
||||
r->foreOffset[i]=rgbf(0,0,0);
|
||||
r->backMult[i]=rgbf(1,1,1);
|
||||
r->backOffset[i]=rgbf(0,0,0);
|
||||
}
|
||||
}
|
||||
static int getGridsSize(lua_State* L)
|
||||
{
|
||||
if(current_mode!=MODE_LUA)
|
||||
return -1;
|
||||
renderer_lua* r=reinterpret_cast<renderer_lua*>(df::global::enabler->renderer);
|
||||
lua_pushnumber(L,df::global::gps->dimx);
|
||||
lua_pushnumber(L,df::global::gps->dimy);
|
||||
return 2;
|
||||
}
|
||||
static int getCell(lua_State* L)
|
||||
{
|
||||
if(current_mode!=MODE_LUA)
|
||||
return 0;
|
||||
renderer_lua* r=reinterpret_cast<renderer_lua*>(df::global::enabler->renderer);
|
||||
int x=luaL_checknumber(L,1);
|
||||
int y=luaL_checknumber(L,2);
|
||||
int id=r->xyToTile(x,y);
|
||||
rgbf fo=r->foreOffset[id];
|
||||
rgbf fm=r->foreMult[id];
|
||||
rgbf bo=r->backOffset[id];
|
||||
rgbf bm=r->backMult[id];
|
||||
lua_newtable(L);
|
||||
|
||||
lua_newtable(L);
|
||||
lua_pushnumber(L,fo.r);
|
||||
lua_setfield(L,-2,"r");
|
||||
lua_pushnumber(L,fo.g);
|
||||
lua_setfield(L,-2,"g");
|
||||
lua_pushnumber(L,fo.b);
|
||||
lua_setfield(L,-2,"b");
|
||||
lua_setfield(L,-2,"fo");
|
||||
|
||||
lua_newtable(L);
|
||||
lua_pushnumber(L,fm.r);
|
||||
lua_setfield(L,-2,"r");
|
||||
lua_pushnumber(L,fm.g);
|
||||
lua_setfield(L,-2,"g");
|
||||
lua_pushnumber(L,fm.b);
|
||||
lua_setfield(L,-2,"b");
|
||||
lua_setfield(L,-2,"fm");
|
||||
|
||||
lua_newtable(L);
|
||||
lua_pushnumber(L,bo.r);
|
||||
lua_setfield(L,-2,"r");
|
||||
lua_pushnumber(L,bo.g);
|
||||
lua_setfield(L,-2,"g");
|
||||
lua_pushnumber(L,bo.b);
|
||||
lua_setfield(L,-2,"b");
|
||||
lua_setfield(L,-2,"bo");
|
||||
|
||||
lua_newtable(L);
|
||||
lua_pushnumber(L,bm.r);
|
||||
lua_setfield(L,-2,"r");
|
||||
lua_pushnumber(L,bm.g);
|
||||
lua_setfield(L,-2,"g");
|
||||
lua_pushnumber(L,bm.b);
|
||||
lua_setfield(L,-2,"b");
|
||||
lua_setfield(L,-2,"bm");
|
||||
return 1;
|
||||
}
|
||||
static int setCell(lua_State* L)
|
||||
{
|
||||
if(current_mode!=MODE_LUA)
|
||||
return 0;
|
||||
renderer_lua* r=reinterpret_cast<renderer_lua*>(df::global::enabler->renderer);
|
||||
int x=luaL_checknumber(L,1);
|
||||
int y=luaL_checknumber(L,2);
|
||||
|
||||
rgbf fo;
|
||||
lua_getfield(L,3,"fo");
|
||||
lua_getfield(L,-1,"r");
|
||||
fo.r=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
lua_getfield(L,-1,"g");
|
||||
fo.g=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
lua_getfield(L,-1,"b");
|
||||
fo.b=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
rgbf fm;
|
||||
lua_getfield(L,3,"fm");
|
||||
lua_getfield(L,-1,"r");
|
||||
fm.r=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
lua_getfield(L,-1,"g");
|
||||
fm.g=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
lua_getfield(L,-1,"b");
|
||||
fm.b=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
|
||||
rgbf bo;
|
||||
lua_getfield(L,3,"bo");
|
||||
lua_getfield(L,-1,"r");
|
||||
bo.r=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
lua_getfield(L,-1,"g");
|
||||
bo.g=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
lua_getfield(L,-1,"b");
|
||||
bo.b=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
|
||||
rgbf bm;
|
||||
lua_getfield(L,3,"bm");
|
||||
lua_getfield(L,-1,"r");
|
||||
bm.r=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
lua_getfield(L,-1,"g");
|
||||
bm.g=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
lua_getfield(L,-1,"b");
|
||||
bm.b=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
int id=r->xyToTile(x,y);
|
||||
r->foreMult[id]=fm;
|
||||
r->foreOffset[id]=fo;
|
||||
r->backMult[id]=bm;
|
||||
r->backOffset[id]=bo;
|
||||
return 0;
|
||||
}
|
||||
static int invalidate(lua_State* L)
|
||||
{
|
||||
if(current_mode!=MODE_LUA)
|
||||
return 0;
|
||||
renderer_lua* r=reinterpret_cast<renderer_lua*>(df::global::enabler->renderer);
|
||||
if(lua_gettop(L)==0)
|
||||
{
|
||||
r->invalidate();
|
||||
}
|
||||
else
|
||||
{
|
||||
int x,y,w,h;
|
||||
lua_getfield(L,1,"x");
|
||||
x=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
lua_getfield(L,1,"y");
|
||||
y=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
lua_getfield(L,1,"w");
|
||||
w=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
lua_getfield(L,1,"h");
|
||||
h=lua_tonumber(L,-1);lua_pop(L,1);
|
||||
r->invalidateRect(x,y,w,h);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
bool isEnabled()
|
||||
{
|
||||
return current_mode==MODE_LUA;
|
||||
}
|
||||
DFHACK_PLUGIN_LUA_FUNCTIONS {
|
||||
DFHACK_LUA_FUNCTION(isEnabled),
|
||||
DFHACK_LUA_FUNCTION(lockGrids),
|
||||
DFHACK_LUA_FUNCTION(unlockGrids),
|
||||
DFHACK_LUA_FUNCTION(resetGrids),
|
||||
DFHACK_LUA_END
|
||||
};
|
||||
DFHACK_PLUGIN_LUA_COMMANDS {
|
||||
DFHACK_LUA_COMMAND(getCell),
|
||||
DFHACK_LUA_COMMAND(setCell),
|
||||
DFHACK_LUA_COMMAND(getGridsSize),
|
||||
DFHACK_LUA_COMMAND(invalidate),
|
||||
DFHACK_LUA_END
|
||||
};
|
||||
|
||||
static void enable_hooks(bool enable)
|
||||
{
|
||||
INTERPOSE_HOOK(dwarmode_render_hook,render).apply(enable);
|
||||
INTERPOSE_HOOK(dungeon_render_hook,render).apply(enable);
|
||||
if(enable && engine)
|
||||
{
|
||||
engine->loadSettings();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
|
||||
{
|
||||
if(current_mode!=MODE_LIGHT)
|
||||
return CR_OK;
|
||||
switch(event)
|
||||
{
|
||||
case SC_VIEWSCREEN_CHANGED:
|
||||
{
|
||||
CoreSuspendClaimer suspender;
|
||||
if(current_mode==MODE_LIGHT)
|
||||
{
|
||||
engine->clear();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SC_WORLD_LOADED:
|
||||
enable_hooks(true);
|
||||
break;
|
||||
case SC_WORLD_UNLOADED:
|
||||
enable_hooks(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
|
||||
static command_result rendermax(color_ostream &out, vector <string> & parameters)
|
||||
{
|
||||
if(parameters.size()==0)
|
||||
return CR_WRONG_USAGE;
|
||||
if(!df::global::enabler->renderer->uses_opengl())
|
||||
{
|
||||
out.printerr("Sorry, this plugin needs open gl enabled printmode. Try STANDARD or other non-2d");
|
||||
return CR_FAILURE;
|
||||
}
|
||||
string cmd=parameters[0];
|
||||
if(cmd=="trippy")
|
||||
{
|
||||
removeOld();
|
||||
installNew(new renderer_trippy(df::global::enabler->renderer),MODE_TRIPPY);
|
||||
return CR_OK;
|
||||
}
|
||||
else if(cmd=="truecolor")
|
||||
{
|
||||
if(current_mode!=MODE_TRUECOLOR)
|
||||
{
|
||||
removeOld();
|
||||
installNew(new renderer_test(df::global::enabler->renderer),MODE_TRUECOLOR);
|
||||
}
|
||||
if(current_mode==MODE_TRUECOLOR && parameters.size()==2)
|
||||
{
|
||||
rgbf red(1,0,0),green(0,1,0),blue(0,0,1),white(1,1,1);
|
||||
rgbf cur=white;
|
||||
rgbf dim(0.2f,0.2f,0.2f);
|
||||
string col=parameters[1];
|
||||
if(col=="red")
|
||||
cur=red;
|
||||
else if(col=="green")
|
||||
cur=green;
|
||||
else if(col=="blue")
|
||||
cur=blue;
|
||||
|
||||
renderer_test* r=reinterpret_cast<renderer_test*>(df::global::enabler->renderer);
|
||||
tthread::lock_guard<tthread::fast_mutex> guard(r->dataMutex);
|
||||
int h=df::global::gps->dimy;
|
||||
int w=df::global::gps->dimx;
|
||||
int cx=w/2;
|
||||
int cy=h/2;
|
||||
int rad=cx;
|
||||
if(rad>cy)rad=cy;
|
||||
rad/=2;
|
||||
int radsq=rad*rad;
|
||||
for(size_t i=0;i<r->lightGrid.size();i++)
|
||||
{
|
||||
r->lightGrid[i]=dim;
|
||||
}
|
||||
for(int i=-rad;i<rad;i++)
|
||||
for(int j=-rad;j<rad;j++)
|
||||
{
|
||||
if((i*i+j*j)<radsq)
|
||||
{
|
||||
float val=(radsq-i*i-j*j)/(float)radsq;
|
||||
r->lightGrid[(cx+i)*h+(cy+j)]=dim+cur*val;
|
||||
}
|
||||
}
|
||||
return CR_OK;
|
||||
}
|
||||
}
|
||||
else if(cmd=="lua")
|
||||
{
|
||||
removeOld();
|
||||
installNew(new renderer_lua(df::global::enabler->renderer),MODE_LUA);
|
||||
lockGrids();
|
||||
resetGrids();
|
||||
unlockGrids();
|
||||
return CR_OK;
|
||||
}
|
||||
else if(cmd=="light")
|
||||
{
|
||||
if(current_mode!=MODE_LIGHT)
|
||||
{
|
||||
removeOld();
|
||||
renderer_light *myRender=new renderer_light(df::global::enabler->renderer);
|
||||
installNew(myRender,MODE_LIGHT);
|
||||
engine=new lightingEngineViewscreen(myRender);
|
||||
|
||||
if (Core::getInstance().isWorldLoaded())
|
||||
plugin_onstatechange(out, SC_WORLD_LOADED);
|
||||
}
|
||||
else if(current_mode==MODE_LIGHT && parameters.size()>1)
|
||||
{
|
||||
if(parameters[1]=="reload")
|
||||
{
|
||||
enable_hooks(true);
|
||||
}
|
||||
else if(parameters[1]=="sun" && parameters.size()==3)
|
||||
{
|
||||
if(parameters[2]=="cycle")
|
||||
{
|
||||
engine->setHour(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss<<parameters[2];
|
||||
float h;
|
||||
ss>>h;
|
||||
engine->setHour(h);
|
||||
}
|
||||
}
|
||||
else if(parameters[1]=="occlusionON")
|
||||
{
|
||||
engine->debug(true);
|
||||
}else if(parameters[1]=="occlusionOFF")
|
||||
{
|
||||
engine->debug(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
out.printerr("Light mode already enabled");
|
||||
|
||||
return CR_OK;
|
||||
}
|
||||
else if(cmd=="disable")
|
||||
{
|
||||
if(current_mode==MODE_DEFAULT)
|
||||
out.print("%s\n","Not installed, doing nothing.");
|
||||
else
|
||||
removeOld();
|
||||
CoreSuspender guard;
|
||||
df::global::gps->force_full_display_count++;
|
||||
return CR_OK;
|
||||
}
|
||||
return CR_WRONG_USAGE;
|
||||
}
|
||||
|
||||
DFhackCExport command_result plugin_shutdown(color_ostream &)
|
||||
{
|
||||
removeOld();
|
||||
return CR_OK;
|
||||
}
|
@ -0,0 +1,225 @@
|
||||
--scroll down to the end for configuration
|
||||
ret={...}
|
||||
ret=ret[1]
|
||||
ret.materials={}
|
||||
ret.buildings={}
|
||||
ret.special={}
|
||||
ret.items={}
|
||||
ret.creatures={}
|
||||
for k,v in pairs(ret) do
|
||||
_ENV[k]=v
|
||||
end
|
||||
-- add material by id (index,mat pair or token string or a type number), flags is a table of strings
|
||||
-- supported flags (but not implemented):
|
||||
-- flicker
|
||||
function addMaterial(id,transparency,emitance,radius,flags)
|
||||
local matinfo
|
||||
if type(id)=="string" then
|
||||
matinfo=dfhack.matinfo.find(id)
|
||||
elseif type(id)=="table" then
|
||||
matinfo=dfhack.matinfo.decode(id[1],id[2])
|
||||
else
|
||||
matinfo=dfhack.matinfo.decode(id,0)
|
||||
end
|
||||
if matinfo==nil then
|
||||
error("Material not found")
|
||||
end
|
||||
materials[matinfo.type]=materials[matinfo.type] or {}
|
||||
materials[matinfo.type][matinfo.index]=makeMaterialDef(transparency,emitance,radius,flags)
|
||||
end
|
||||
function buildingLookUp(id)
|
||||
local tokens={}
|
||||
local lookup={ Workshop=df.workshop_type,Furnace=df.furnace_type,Trap=df.trap_type,
|
||||
SiegeEngine=df.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
|
||||
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
|
||||
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:
|
||||
-- useMaterial --uses material, but the defined things overwrite
|
||||
-- poweredOnly --glow only when powered
|
||||
function addBuilding(id,transparency,emitance,radius,flags,size,thickness)
|
||||
size=size or 1
|
||||
thickness=thickness or 1
|
||||
local bld=buildingLookUp(id)
|
||||
local mat=makeMaterialDef(transparency,emitance,radius,flags)
|
||||
mat.size=size
|
||||
mat.thickness=thickness
|
||||
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
|
||||
function makeMaterialDef(transparency,emitance,radius,flags)
|
||||
local flg
|
||||
if flags then
|
||||
flg={}
|
||||
for k,v in ipairs(flags) do
|
||||
flg[v]=true
|
||||
end
|
||||
end
|
||||
return {tr=transparency,em=emitance,rad=radius,flags=flg}
|
||||
end
|
||||
function colorFrom16(col16)
|
||||
local col=df.global.enabler.ccolor[col16]
|
||||
return {col[0],col[1],col[2]}
|
||||
end
|
||||
function addGems()
|
||||
for k,v in pairs(df.global.world.raws.inorganics) do
|
||||
if v.material.flags.IS_GEM then
|
||||
addMaterial("INORGANIC:"..v.id,colorFrom16(v.material.tile_color[0]+v.material.tile_color[2]*8))
|
||||
end
|
||||
end
|
||||
end
|
||||
------------------------------------------------------------------------
|
||||
---------------- Configuration Starts Here -------------------------
|
||||
------------------------------------------------------------------------
|
||||
is_computer_quantum=false -- will enable more costly parts in the future
|
||||
--special things
|
||||
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.FROZEN_LIQUID=makeMaterialDef({0.2,0.7,0.9}) -- ice
|
||||
special.AMBIENT=makeMaterialDef({0.85,0.85,0.85}) --ambient fog
|
||||
special.CURSOR=makeMaterialDef({1,1,1},{0.96,0.84,0.03},11, {"flicker"})
|
||||
special.CITIZEN=makeMaterialDef(nil,{0.80,0.80,0.90},6)
|
||||
special.LevelDim=0.2 -- darkness. Do not set to 0
|
||||
special.dayHour=-1 -- <0 cycle, else hour of the day
|
||||
special.dayColors={ {0,0,0}, --dark at 0 hours
|
||||
{0.6,0.5,0.5}, --reddish twilight
|
||||
{1,1,1}, --fullbright at 12 hours
|
||||
{0.5,0.5,0.5},
|
||||
{0,0,0}} --dark at 24 hours
|
||||
special.daySpeed=1 -- 1->1200 cur_year_ticks per day. 2->600 ticks
|
||||
special.diffusionCount=1 -- split beam max 1 times to mimic diffuse lights
|
||||
special.advMode=0 -- 1 or 0 different modes for adv mode. 0-> use df vision system,
|
||||
-- 1(does not work)->everything visible, let rendermax light do the work
|
||||
--TODO dragonfire
|
||||
--materials
|
||||
|
||||
|
||||
-- glasses
|
||||
addMaterial("GLASS_GREEN",{0.1,0.9,0.5})
|
||||
addMaterial("GLASS_CLEAR",{0.5,0.95,0.9})
|
||||
addMaterial("GLASS_CRYSTAL",{0.75,0.95,0.95})
|
||||
-- Plants
|
||||
addMaterial("PLANT:TOWER_CAP",nil,{0.65,0.65,0.65},6)
|
||||
addMaterial("PLANT:MUSHROOM_CUP_DIMPLE",nil,{0.03,0.03,0.5},3)
|
||||
addMaterial("PLANT:CAVE MOSS",nil,{0.1,0.1,0.4},2)
|
||||
addMaterial("PLANT:MUSHROOM_HELMET_PLUMP",nil,{0.2,0.1,0.6},2)
|
||||
-- inorganics
|
||||
addMaterial("INORGANIC:ADAMANTINE",{0.1,0.3,0.3},{0.1,0.3,0.3},4)
|
||||
-- creature stuff
|
||||
addMaterial("CREATURE:DRAGON:BLOOD",nil,{0.6,0.1,0.1},4)
|
||||
addGems()
|
||||
--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
|
||||
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"})
|
@ -0,0 +1,377 @@
|
||||
-- an experimental lighting engine for df. param: "static" to not recalc when in game. press "~" to recalculate. "`" to exit
|
||||
local gui = require 'gui'
|
||||
local guidm = require 'gui.dwarfmode'
|
||||
local render = require 'plugins.rendermax'
|
||||
|
||||
local levelDim=0.05
|
||||
local tile_attrs = df.tiletype.attrs
|
||||
|
||||
local args={...}
|
||||
|
||||
function setCell(x,y,cell)
|
||||
cell=cell or {}
|
||||
cell.fm=cell.fm or {r=1,g=1,b=1}
|
||||
cell.bm=cell.bm or {r=1,g=1,b=1}
|
||||
cell.fo=cell.fo or {r=0,g=0,b=0}
|
||||
cell.bo=cell.bo or {r=0,g=0,b=0}
|
||||
render.setCell(x,y,cell)
|
||||
end
|
||||
function getCursorPos()
|
||||
local g_cursor=df.global.cursor
|
||||
if g_cursor.x ~= -30000 then
|
||||
return copyall(g_cursor)
|
||||
end
|
||||
end
|
||||
function falloff(color,sqDist,maxdist)
|
||||
local v1=1/(sqDist/maxdist+1)
|
||||
local v2=v1-1/(1+maxdist*maxdist)
|
||||
local v=v2/(1-1/(1+maxdist*maxdist))
|
||||
return {r=v*color.r,g=v*color.g,b=v*color.b}
|
||||
end
|
||||
function blend(c1,c2)
|
||||
return {r=math.max(c1.r,c2.r),
|
||||
g=math.max(c1.g,c2.g),
|
||||
b=math.max(c1.b,c2.b)}
|
||||
end
|
||||
LightOverlay=defclass(LightOverlay,guidm.DwarfOverlay)
|
||||
LightOverlay.ATTRS {
|
||||
lightMap={},
|
||||
dynamic=true,
|
||||
dirty=false,
|
||||
}
|
||||
function LightOverlay:init(args)
|
||||
|
||||
self.tick=df.global.cur_year_tick_advmode
|
||||
end
|
||||
|
||||
function lightPassable(shape)
|
||||
if shape==df.tiletype_shape.WALL or
|
||||
shape==df.tiletype_shape.BROOK_BED or
|
||||
shape==df.tiletype_shape.TREE then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
function circle(xm, ym,r,plot)
|
||||
local x = -r
|
||||
local y = 0
|
||||
local err = 2-2*r -- /* II. Quadrant */
|
||||
repeat
|
||||
plot(xm-x, ym+y);--/* I. Quadrant */
|
||||
plot(xm-y, ym-x);--/* II. Quadrant */
|
||||
plot(xm+x, ym-y);--/* III. Quadrant */
|
||||
plot(xm+y, ym+x);--/* IV. Quadrant */
|
||||
r = err;
|
||||
if (r <= y) then
|
||||
y=y+1
|
||||
err =err+y*2+1; --/* e_xy+e_y < 0 */
|
||||
end
|
||||
if (r > x or err > y) then
|
||||
x=x+1
|
||||
err =err+x*2+1; --/* e_xy+e_x > 0 or no 2nd y-step */
|
||||
end
|
||||
until (x >= 0);
|
||||
end
|
||||
function line(x0, y0, x1, y1,plot)
|
||||
local dx = math.abs(x1-x0)
|
||||
local dy = math.abs(y1-y0)
|
||||
local sx,sy
|
||||
if x0 < x1 then sx = 1 else sx = -1 end
|
||||
if y0 < y1 then sy = 1 else sy = -1 end
|
||||
local err = dx-dy
|
||||
|
||||
while true do
|
||||
if not plot(x0,y0) then
|
||||
return
|
||||
end
|
||||
if x0 == x1 and y0 == y1 then
|
||||
break
|
||||
end
|
||||
local e2 = 2*err
|
||||
if e2 > -dy then
|
||||
err = err - dy
|
||||
x0 = x0 + sx
|
||||
end
|
||||
if x0 == x1 and y0 == y1 then
|
||||
if not plot(x0,y0) then
|
||||
return
|
||||
end
|
||||
break
|
||||
end
|
||||
if e2 < dx then
|
||||
err = err + dx
|
||||
y0 = y0 + sy
|
||||
end
|
||||
end
|
||||
end
|
||||
function LightOverlay:calculateFovs()
|
||||
self.fovs=self.fovs or {}
|
||||
self.precalc=self.precalc or {}
|
||||
for k,v in ipairs(self.fovs) do
|
||||
self:calculateFov(v.pos,v.radius,v.color)
|
||||
end
|
||||
end
|
||||
function LightOverlay:calculateFov(pos,radius,color)
|
||||
local vp=self:getViewport()
|
||||
local map = self.df_layout.map
|
||||
local ray=function(tx,ty)
|
||||
local power=copyall(color)
|
||||
local lx=pos.x
|
||||
local ly=pos.y
|
||||
local setTile=function(x,y)
|
||||
if x>0 and y>0 and x<=map.width and y<=map.height then
|
||||
local dtsq=(lx-x)*(lx-x)+(ly-y)*(ly-y)
|
||||
local dt=math.sqrt(dtsq)
|
||||
local tile=x+y*map.width
|
||||
if self.precalc[tile] then
|
||||
local tcol=blend(self.precalc[tile],power)
|
||||
if tcol.r==self.precalc[tile].r and tcol.g==self.precalc[tile].g and self.precalc[tile].b==self.precalc[tile].b
|
||||
and dtsq>0 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
local ocol=self.lightMap[tile] or {r=0,g=0,b=0}
|
||||
local ncol=blend(power,ocol)
|
||||
|
||||
self.lightMap[tile]=ncol
|
||||
local v=self.ocupancy[tile]
|
||||
if dtsq>0 then
|
||||
power.r=power.r*(v.r^dt)
|
||||
power.g=power.g*(v.g^dt)
|
||||
power.b=power.b*(v.b^dt)
|
||||
end
|
||||
lx=x
|
||||
ly=y
|
||||
local pwsq=power.r*power.r+power.g*power.g+power.b*power.b
|
||||
return pwsq>levelDim*levelDim
|
||||
end
|
||||
return false
|
||||
end
|
||||
line(pos.x,pos.y,tx,ty,setTile)
|
||||
end
|
||||
circle(pos.x,pos.y,radius,ray)
|
||||
end
|
||||
function LightOverlay:placeLightFov(pos,radius,color)
|
||||
local map = self.df_layout.map
|
||||
local tile=pos.x+pos.y*map.width
|
||||
local ocol=self.precalc[tile] or {r=0,g=0,b=0}
|
||||
local ncol=blend(color,ocol)
|
||||
self.precalc[tile]=ncol
|
||||
local ocol=self.lightMap[tile] or {r=0,g=0,b=0}
|
||||
local ncol=blend(color,ocol)
|
||||
self.lightMap[tile]=ncol
|
||||
table.insert(self.fovs,{pos=pos,radius=radius,color=color})
|
||||
end
|
||||
function LightOverlay:placeLightFov2(pos,radius,color,f,rays)
|
||||
f=f or falloff
|
||||
local raycount=rays or 25
|
||||
local vp=self:getViewport()
|
||||
local map = self.df_layout.map
|
||||
local off=math.random(0,math.pi)
|
||||
local done={}
|
||||
for d=0,math.pi*2,math.pi*2/raycount do
|
||||
local dx,dy
|
||||
dx=math.cos(d+off)
|
||||
dy=math.sin(d+off)
|
||||
local cx=0
|
||||
local cy=0
|
||||
|
||||
for dt=0,radius,0.01 do
|
||||
if math.abs(math.floor(dt*dx)-cx)>0 or math.abs(math.floor(dt*dy)-cy)> 0then
|
||||
local x=cx+pos.x
|
||||
local y=cy+pos.y
|
||||
|
||||
if x>0 and y>0 and x<=map.width and y<=map.height and not done[tile] then
|
||||
local tile=x+y*map.width
|
||||
done[tile]=true
|
||||
local ncol=f(color,dt*dt,radius)
|
||||
local ocol=self.lightMap[tile] or {r=0,g=0,b=0}
|
||||
ncol=blend(ncol,ocol)
|
||||
self.lightMap[tile]=ncol
|
||||
|
||||
|
||||
if --(ncol.r==ocol.r and ncol.g==ocol.g and ncol.b==ocol.b) or
|
||||
not self.ocupancy[tile] then
|
||||
break
|
||||
end
|
||||
end
|
||||
cx=math.floor(dt*dx)
|
||||
cy=math.floor(dt*dy)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
function LightOverlay:placeLight(pos,radius,color,f)
|
||||
f=f or falloff
|
||||
local vp=self:getViewport()
|
||||
local map = self.df_layout.map
|
||||
|
||||
for i=-radius,radius do
|
||||
for j=-radius,radius do
|
||||
local x=pos.x+i+1
|
||||
local y=pos.y+j+1
|
||||
if x>0 and y>0 and x<=map.width and y<=map.height then
|
||||
local tile=x+y*map.width
|
||||
local ncol=f(color,(i*i+j*j),radius)
|
||||
local ocol=self.lightMap[tile] or {r=0,g=0,b=0}
|
||||
self.lightMap[tile]=blend(ncol,ocol)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
function LightOverlay:calculateLightLava()
|
||||
local vp=self:getViewport()
|
||||
local map = self.df_layout.map
|
||||
for i=map.x1,map.x2 do
|
||||
for j=map.y1,map.y2 do
|
||||
local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z}
|
||||
local pos2={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z-1}
|
||||
local t1=dfhack.maps.getTileFlags(pos)
|
||||
local tt=dfhack.maps.getTileType(pos)
|
||||
if tt then
|
||||
local shape=tile_attrs[tt].shape
|
||||
local t2=dfhack.maps.getTileFlags(pos2)
|
||||
if (t1 and t1.liquid_type and t1.flow_size>0) or
|
||||
(shape==df.tiletype_shape.EMPTY and t2 and t2.liquid_type and t2.flow_size>0) then
|
||||
--self:placeLight({x=i,y=j},5,{r=0.8,g=0.2,b=0.2})
|
||||
self:placeLightFov({x=i,y=j},5,{r=0.8,g=0.2,b=0.2},nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
function LightOverlay:calculateLightSun()
|
||||
local vp=self:getViewport()
|
||||
local map = self.df_layout.map
|
||||
for i=map.x1,map.x2+1 do
|
||||
for j=map.y1,map.y2+1 do
|
||||
local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z}
|
||||
|
||||
local t1=dfhack.maps.getTileFlags(pos)
|
||||
|
||||
if (t1 and t1.outside ) then
|
||||
|
||||
self:placeLightFov({x=i,y=j},15,{r=1,g=1,b=1},nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
function LightOverlay:calculateLightCursor()
|
||||
local c=getCursorPos()
|
||||
|
||||
if c then
|
||||
|
||||
local vp=self:getViewport()
|
||||
local pos=vp:tileToScreen(c)
|
||||
--self:placeLight(pos,11,{r=0.96,g=0.84,b=0.03})
|
||||
self:placeLightFov({x=pos.x+1,y=pos.y+1},11,{r=0.96,g=0.84,b=0.03})
|
||||
|
||||
end
|
||||
end
|
||||
function LightOverlay:buildOcupancy()
|
||||
self.ocupancy={}
|
||||
local vp=self:getViewport()
|
||||
local map = self.df_layout.map
|
||||
for i=map.x1,map.x2+1 do
|
||||
for j=map.y1,map.y2+1 do
|
||||
local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z}
|
||||
local tile=i+j*map.width
|
||||
local tt=dfhack.maps.getTileType(pos)
|
||||
local t1=dfhack.maps.getTileFlags(pos)
|
||||
if tt then
|
||||
local shape=tile_attrs[tt].shape
|
||||
if not lightPassable(shape) then
|
||||
self.ocupancy[tile]={r=0,g=0,b=0}
|
||||
else
|
||||
if t1 and not t1.liquid_type and t1.flow_size>2 then
|
||||
self.ocupancy[tile]={r=0.5,g=0.5,b=0.7}
|
||||
else
|
||||
self.ocupancy[tile]={r=0.8,g=0.8,b=0.8}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
function LightOverlay:changed()
|
||||
if self.dirty or self.tick~=df.global.cur_year_tick_advmode then
|
||||
self.dirty=false
|
||||
self.tick=df.global.cur_year_tick_advmode
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
function LightOverlay:makeLightMap()
|
||||
if not self:changed() then
|
||||
return
|
||||
end
|
||||
self.fovs={}
|
||||
self.precalc={}
|
||||
self.lightMap={}
|
||||
|
||||
self:buildOcupancy()
|
||||
self:calculateLightCursor()
|
||||
self:calculateLightLava()
|
||||
self:calculateLightSun()
|
||||
|
||||
self:calculateFovs()
|
||||
end
|
||||
function LightOverlay:onIdle()
|
||||
self._native.parent:logic()
|
||||
end
|
||||
function LightOverlay:render(dc)
|
||||
if self.dynamic then
|
||||
self:makeLightMap()
|
||||
end
|
||||
self:renderParent()
|
||||
local vp=self:getViewport()
|
||||
local map = self.df_layout.map
|
||||
|
||||
self.lightMap=self.lightMap or {}
|
||||
render.lockGrids()
|
||||
render.invalidate({x=map.x1,y=map.y1,w=map.width,h=map.height})
|
||||
render.resetGrids()
|
||||
for i=map.x1,map.x2 do
|
||||
for j=map.y1,map.y2 do
|
||||
local v=self.lightMap[i+j*map.width]
|
||||
if v then
|
||||
setCell(i,j,{fm=v,bm=v})
|
||||
else
|
||||
local dimRgb={r=levelDim,g=levelDim,b=levelDim}
|
||||
setCell(i,j,{fm=dimRgb,bm=dimRgb})
|
||||
end
|
||||
end
|
||||
end
|
||||
render.unlockGrids()
|
||||
|
||||
end
|
||||
function LightOverlay:onDismiss()
|
||||
render.lockGrids()
|
||||
render.resetGrids()
|
||||
render.invalidate()
|
||||
render.unlockGrids()
|
||||
|
||||
end
|
||||
function LightOverlay:onInput(keys)
|
||||
if keys.STRING_A096 then
|
||||
self:dismiss()
|
||||
else
|
||||
self:sendInputToParent(keys)
|
||||
|
||||
if keys.CHANGETAB then
|
||||
self:updateLayout()
|
||||
end
|
||||
if keys.STRING_A126 and not self.dynamic then
|
||||
self:makeLightMap()
|
||||
end
|
||||
self.dirty=true
|
||||
end
|
||||
end
|
||||
if not render.isEnabled() then
|
||||
qerror("Lua rendermode not enabled!")
|
||||
end
|
||||
local dyn=true
|
||||
if #args>0 and args[1]=="static" then dyn=false end
|
||||
local lview = LightOverlay{ dynamic=dyn}
|
||||
lview:show()
|
Loading…
Reference in New Issue