1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2025-05-04 08:14:08 +00:00

structurized textures.cpp

This commit is contained in:
Zeno Rogue 2018-03-17 21:12:46 +01:00
parent 5188e3649d
commit 2c09c5ee56
9 changed files with 298 additions and 277 deletions

View File

@ -3112,7 +3112,7 @@ void warpfloor(cell *c, const transmatrix& V, int col, int prio, bool warp) {
if(shmup::on || nonbitrunc) warp = false; if(shmup::on || nonbitrunc) warp = false;
#if CAP_TEXTURE #if CAP_TEXTURE
if(qfi.tinf) { if(qfi.tinf) {
queuetable(V*qfi.spin, qfi.tinf->vertices, size(qfi.tinf->vertices), 0, texture::recolor(col), prio); queuetable(V*qfi.spin, qfi.tinf->vertices, size(qfi.tinf->vertices), 0, texture::config.recolor(col), prio);
lastptd().u.poly.tinf = qfi.tinf; lastptd().u.poly.tinf = qfi.tinf;
} }
else else
@ -3460,7 +3460,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
#if CAP_TEXTURE #if CAP_TEXTURE
if(texture::saving) { if(texture::saving) {
texture::apply(c, V, 0xFFFFFFFF); texture::config.apply(c, V, 0xFFFFFFFF);
return; return;
} }
#endif #endif
@ -3817,7 +3817,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
#endif #endif
#if CAP_TEXTURE #if CAP_TEXTURE
else if(texture::apply(c, Vf, darkena(fcol, fd, 0xFF))) ; else if(texture::config.apply(c, Vf, darkena(fcol, fd, 0xFF))) ;
#endif #endif
else if(c->land == laMirrorWall) { else if(c->land == laMirrorWall) {
@ -5547,8 +5547,8 @@ void gamescreen(int _darken) {
darken = 0; darken = 0;
#if CAP_TEXTURE #if CAP_TEXTURE
if(texture::tstate == texture::tsAdjusting) if(texture::config.tstate == texture::tsAdjusting)
texture::drawRawTexture(); texture::config.drawRawTexture();
#endif #endif
} }

93
hyper.h
View File

@ -2431,18 +2431,87 @@ namespace texture {
tsOff, tsAdjusting, tsActive tsOff, tsAdjusting, tsActive
}; };
extern eTextureState tstate, tstate_max; struct texture_data {
extern unsigned paint_color; GLuint textureid = 0;
extern ld penwidth;
extern transmatrix itt;
extern int twidth;
extern bool saving;
extern vector<unsigned> texture_pixels; int twidth = 2048;
vector<unsigned> texture_pixels;
unsigned& get_texture_pixel(int x, int y) {
return texture_pixels[(y&(twidth-1))*twidth+(x&(twidth-1))];
}
vector<pair<unsigned*, unsigned>> undos;
vector<tuple<cell*, hyperpoint, int> > pixels_to_draw;
bool loadTextureGL();
bool whitetexture();
bool readtexture(string tn);
void saveRawTexture(string tn);
void undo();
void undoLock();
void update();
};
struct texture_config {
string texturename = "textures/hyperrogue-texture.png";
string configname = "textures/hyperrogue.txc";
unsigned paint_color = 0x000000FF;
eTextureState tstate;
eTextureState tstate_max;
transmatrix itt = Id;
unsigned grid_color = 0;
unsigned mesh_color = 0;
unsigned master_color = 0xFFFFFF30;
unsigned slave_color = 0xFF000008;
int color_alpha = 128;
int gsplits = 1;
int recolor(int col);
typedef tuple<eGeometry, bool, char, int, eModel, ld, ld> texture_parameters;
texture_parameters orig_texture_parameters;
map<int, textureinfo> texture_map, texture_map_orig;
set<cell*> models;
bool texture_tuned = false;
string texture_tuner;
vector<hyperpoint*> tuned_vertices;
bool apply(cell *c, const transmatrix &V, int col);
void mark_triangles();
void clear_texture_map();
void perform_mapping();
void mapTextureTriangle(textureinfo &mi, const array<hyperpoint, 3>& v, const array<hyperpoint, 3>& tv, int splits);
void mapTextureTriangle(textureinfo &mi, const array<hyperpoint, 3>& v, const array<hyperpoint, 3>& tv) { mapTextureTriangle(mi, v, tv, gsplits); }
void mapTexture2(textureinfo& mi);
void finish_mapping();
void remap(eTextureState old_tstate, eTextureState old_tstate_max);
void drawRawTexture();
void saveFullTexture(string tn);
bool save();
bool load();
texture_data data;
};
extern texture_config config;
extern ld penwidth;
extern bool saving;
void showMenu(); void showMenu();
void update();
void drawPixel(cell *c, hyperpoint h, int col); void drawPixel(cell *c, hyperpoint h, int col);
extern cell *where; extern cell *where;
@ -2450,15 +2519,7 @@ namespace texture {
void drawPixel(hyperpoint h, int col); void drawPixel(hyperpoint h, int col);
void drawLine(hyperpoint h1, hyperpoint h2, int col, int steps = 10); void drawLine(hyperpoint h1, hyperpoint h2, int col, int steps = 10);
void remap(eTextureState old_tstate, eTextureState old_tstate_max);
void perform_mapping();
void finish_mapping();
void undoLock();
void undo();
extern bool texturesym; extern bool texturesym;
extern cpatterntype cgroup; extern cpatterntype cgroup;
} }

View File

@ -368,6 +368,7 @@ extern "C" {
#include <queue> #include <queue>
#include <stdexcept> #include <stdexcept>
#include <array> #include <array>
#include <set>
#ifdef USE_UNORDERED_MAP #ifdef USE_UNORDERED_MAP
#include <unordered_map> #include <unordered_map>

View File

@ -43,12 +43,12 @@ namespace mapeditor {
// printf("scale = " LDF "\n", vid.scale); // printf("scale = " LDF "\n", vid.scale);
#if CAP_TEXTURE #if CAP_TEXTURE
// display(texture::itt); // display(texture::itt);
texture::itt = xyscale(texture::itt, 1/z); texture::config.itt = xyscale(texture::config.itt, 1/z);
if(false && texture::tstate) { if(false && texture::config.tstate) {
calcparam(); calcparam();
texture::perform_mapping(); texture::config.perform_mapping();
if(texture::tstate == texture::tsAdjusting) if(texture::config.tstate == texture::tsAdjusting)
texture::finish_mapping(); texture::config.finish_mapping();
} }
#endif #endif
} }
@ -952,11 +952,11 @@ namespace mapeditor {
bool intexture = false; bool intexture = false;
#if CAP_TEXTURE #if CAP_TEXTURE
if(texture::tstate == texture::tsActive) { if(texture::config.tstate == texture::tsActive) {
sg = 16; sg = 16;
line1 = "texture"; line1 = "texture";
line2 = ""; line2 = "";
texture::update(); texture::config.data.update();
intexture = true; intexture = true;
} }
#else #else
@ -1038,7 +1038,7 @@ namespace mapeditor {
} }
#if CAP_TEXTURE #if CAP_TEXTURE
else if(texture::tstate == texture::tsActive) { else if(texture::config.tstate == texture::tsActive) {
displayButton(8, 8+fs*2, XLAT(texture::texturesym ? "0 = symmetry" : "0 = asymmetry"), '0', 0); displayButton(8, 8+fs*2, XLAT(texture::texturesym ? "0 = symmetry" : "0 = asymmetry"), '0', 0);
if(mousekey == 'g') if(mousekey == 'g')
displayButton(8, 8+fs*16, XLAT("p = grid color"), 'p', 0); displayButton(8, 8+fs*16, XLAT("p = grid color"), 'p', 0);
@ -1069,7 +1069,7 @@ namespace mapeditor {
getcstat = 2000+i; getcstat = 2000+i;
} }
if(texture::tstate != texture::tsActive) if(texture::config.tstate != texture::tsActive)
displaymm('e', vid.xres-8, 8+fs, 2, vid.fsize, XLAT("e = edit this"), 16); displaymm('e', vid.xres-8, 8+fs, 2, vid.fsize, XLAT("e = edit this"), 16);
#endif #endif
@ -1455,16 +1455,16 @@ namespace mapeditor {
if(sym == SDLK_F10) popScreen(); if(sym == SDLK_F10) popScreen();
#if CAP_TEXTURE #if CAP_TEXTURE
if(texture::tstate == texture::tsActive) { if(texture::config.tstate == texture::tsActive) {
int tcolor = (texture::paint_color >> 8) | ((texture::paint_color & 0xFF) << 24); int tcolor = (texture::config.paint_color >> 8) | ((texture::config.paint_color & 0xFF) << 24);
if(uni == '-' && !clickused) { if(uni == '-' && !clickused) {
if(mousekey == 'l' || mousekey == 'c') { if(mousekey == 'l' || mousekey == 'c') {
if(!holdmouse) lstart = mouseh, lstartcell = mouseover, holdmouse = true; if(!holdmouse) lstart = mouseh, lstartcell = mouseover, holdmouse = true;
} }
else { else {
if(!holdmouse) texture::undoLock(); if(!holdmouse) texture::config.data.undoLock();
texture::drawPixel(mouseover, mouseh, tcolor); texture::drawPixel(mouseover, mouseh, tcolor);
holdmouse = true; lstartcell = NULL; holdmouse = true; lstartcell = NULL;
} }
@ -1473,14 +1473,14 @@ namespace mapeditor {
if(sym == PSEUDOKEY_RELEASE) { if(sym == PSEUDOKEY_RELEASE) {
printf("release\n"); printf("release\n");
if(mousekey == 'l') { if(mousekey == 'l') {
texture::undoLock(); texture::config.data.undoLock();
texture::where = mouseover; texture::where = mouseover;
texture::drawPixel(mouseover, mouseh, tcolor); texture::drawPixel(mouseover, mouseh, tcolor);
texture::drawLine(mouseh, lstart, tcolor); texture::drawLine(mouseh, lstart, tcolor);
lstartcell = NULL; lstartcell = NULL;
} }
if(mousekey == 'c') { if(mousekey == 'c') {
texture::undoLock(); texture::config.data.undoLock();
ld rad = hdist(lstart, mouseh); ld rad = hdist(lstart, mouseh);
int circp = int(1 + 3 * (circlelength(rad) / texture::penwidth)); int circp = int(1 + 3 * (circlelength(rad) / texture::penwidth));
if(circp > 1000) circp = 1000; if(circp > 1000) circp = 1000;
@ -1493,7 +1493,7 @@ namespace mapeditor {
} }
if(uni >= 1000 && uni < 1010) if(uni >= 1000 && uni < 1010)
texture::paint_color = texture_colors[uni - 1000 + 1]; texture::config.paint_color = texture_colors[uni - 1000 + 1];
if(uni >= 2000 && uni < 2010) if(uni >= 2000 && uni < 2010)
texture::penwidth = brush_sizes[uni - 2000]; texture::penwidth = brush_sizes[uni - 2000];
@ -1502,12 +1502,12 @@ namespace mapeditor {
texture::texturesym = !texture::texturesym; texture::texturesym = !texture::texturesym;
if(uni == 'u') { if(uni == 'u') {
texture::undo(); texture::config.data.undo();
} }
if(uni == 'p') { if(uni == 'p') {
if(!clickused) if(!clickused)
dialog::openColorDialog(texture::paint_color, texture_colors); dialog::openColorDialog(texture::config.paint_color, texture_colors);
} }
if(uni == 'b') if(uni == 'b')
@ -1619,7 +1619,7 @@ namespace mapeditor {
for(int j=0; j<circp; j++) for(int j=0; j<circp; j++)
pts.push_back(Ctr * tC0(spin(M_PI*j*2/circp) * xpush(radius))); pts.push_back(Ctr * tC0(spin(M_PI*j*2/circp) * xpush(radius)));
for(int j=0; j<circp; j++) for(int j=0; j<circp; j++)
queueline(pts[j], pts[(j+1)%circp], texture::paint_color, 0, PPR_LINE); queueline(pts[j], pts[(j+1)%circp], texture::config.paint_color, 0, PPR_LINE);
} }
#endif #endif
@ -1645,7 +1645,7 @@ namespace mapeditor {
if(cmode & sm::DRAW) { if(cmode & sm::DRAW) {
#if CAP_TEXTURE #if CAP_TEXTURE
if(texture::tstate == texture::tsActive && lmouseover && !mouseout() && (lstartcell || !holdmouse)) { if(texture::config.tstate == texture::tsActive && lmouseover && !mouseout() && (lstartcell || !holdmouse)) {
cell *ls = lstartcell ? lstartcell : lmouseover; cell *ls = lstartcell ? lstartcell : lmouseover;
auto sio = patterns::getpatterninfo0(ls); auto sio = patterns::getpatterninfo0(ls);
auto sih = patterns::getpatterninfo0(c); auto sih = patterns::getpatterninfo0(c);
@ -1666,7 +1666,7 @@ namespace mapeditor {
queue_hcircle(M2 * ml, hdist(lstart, mouseh)); queue_hcircle(M2 * ml, hdist(lstart, mouseh));
break; break;
case 'l': case 'l':
queueline(M2 * mh * C0, M2 * ml * C0, texture::paint_color, 4, PPR_LINE); queueline(M2 * mh * C0, M2 * ml * C0, texture::config.paint_color, 4, PPR_LINE);
break; break;
default: default:
queue_hcircle(M2 * mh, texture::penwidth); queue_hcircle(M2 * mh, texture::penwidth);

View File

@ -340,7 +340,7 @@ void showDisplayMode() {
#endif #endif
#if CAP_TEXTURE #if CAP_TEXTURE
dialog::addBoolItem(XLAT("texture mode"), texture::tstate == texture::tsActive, 't'); dialog::addBoolItem(XLAT("texture mode"), texture::config.tstate == texture::tsActive, 't');
#endif #endif

View File

@ -1446,7 +1446,7 @@ namespace patterns {
for(int i=0; i<size(cpatterns); i++) { for(int i=0; i<size(cpatterns); i++) {
dialog::addBoolItem(XLAT(cpatterns[i].name), cgroup == i, '0'+i); dialog::addBoolItem(XLAT(cpatterns[i].name), cgroup == i, '0'+i);
#if CAP_TEXTURE #if CAP_TEXTURE
if(texture::tstate == texture::tsActive && !compatible(texture::cgroup, (cpatterntype) i)) if(texture::config.tstate == texture::tsActive && !compatible(texture::cgroup, (cpatterntype) i))
dialog::lastItem().value = XLAT("BAD"); dialog::lastItem().value = XLAT("BAD");
#endif #endif
} }
@ -1476,8 +1476,8 @@ namespace patterns {
cgroup = cpatterntype(uni - '0'); cgroup = cpatterntype(uni - '0');
else if(cgroup != cpUnknown && uni >= 'a' && uni < 'a' + size(cpatterns[cgroup].geometries)) { else if(cgroup != cpUnknown && uni >= 'a' && uni < 'a' + size(cpatterns[cgroup].geometries)) {
#if CAP_TEXTURE #if CAP_TEXTURE
auto old_tstate = texture::tstate; auto old_tstate = texture::config.tstate;
auto old_tstate_max = texture::tstate_max; auto old_tstate_max = texture::config.tstate_max;
#endif #endif
auto &g = cpatterns[cgroup].geometries[uni - 'a']; auto &g = cpatterns[cgroup].geometries[uni - 'a'];
if(g.geo != geometry) { targetgeometry = g.geo; restartGame('g', false, true); } if(g.geo != geometry) { targetgeometry = g.geo; restartGame('g', false, true); }
@ -1485,7 +1485,7 @@ namespace patterns {
whichPattern = g.whichPattern; whichPattern = g.whichPattern;
subpattern_flags = g.subpattern_flags; subpattern_flags = g.subpattern_flags;
#if CAP_TEXTURE #if CAP_TEXTURE
texture::remap(old_tstate, old_tstate_max); texture::config.remap(old_tstate, old_tstate_max);
#endif #endif
} }
else if(doexiton(sym, uni)) else if(doexiton(sym, uni))

View File

@ -210,9 +210,10 @@ void drawTexturedTriangle(SDL_Surface *s, int *px, int *py, glvertex *tv, int co
hyperpoint h = isource * hpxyz(mx, my, 1); hyperpoint h = isource * hpxyz(mx, my, 1);
if(h[0] >= -1e-7 && h[1] >= -1e-7 && h[2] >= -1e-7) { if(h[0] >= -1e-7 && h[1] >= -1e-7 && h[2] >= -1e-7) {
hyperpoint ht = target * h; hyperpoint ht = target * h;
int x = int(ht[0] * texture::twidth) & (texture::twidth-1); int tw = texture::config.data.twidth;
int y = int(ht[1] * texture::twidth) & (texture::twidth-1); int x = int(ht[0] * tw) & (tw-1);
int c = texture::texture_pixels[y * texture::twidth + x]; int y = int(ht[1] * tw) & (tw-1);
int c = texture::config.data.texture_pixels[y * tw + x];
auto& pix = qpixel(s, mx, my); auto& pix = qpixel(s, mx, my);
for(int p=0; p<3; p++) { for(int p=0; p<3; p++) {
int alpha = part(c, 3) * part(col, 0); int alpha = part(c, 3) * part(col, 0);

View File

@ -1107,10 +1107,10 @@ void restartGame(char switchWhat, bool push, bool keep_screens) {
nonbitrunc = !nonbitrunc; nonbitrunc = !nonbitrunc;
resetGeometry(); resetGeometry();
#if CAP_TEXTURE #if CAP_TEXTURE
if(texture::tstate == texture::tsActive) if(texture::config.tstate == texture::tsActive)
texture::tstate = texture::tsAdjusting; texture::config.tstate = texture::tsAdjusting;
if(texture::tstate_max == texture::tsActive) if(texture::config.tstate_max == texture::tsActive)
texture::tstate = texture::tsAdjusting; texture::config.tstate = texture::tsAdjusting;
#endif #endif
} }
if(switchWhat == 'g') { if(switchWhat == 'g') {
@ -1121,10 +1121,10 @@ void restartGame(char switchWhat, bool push, bool keep_screens) {
resetGeometry(); resetGeometry();
#if CAP_TEXTURE #if CAP_TEXTURE
if(texture::tstate == texture::tsActive) if(texture::config.tstate == texture::tsActive)
texture::tstate = texture::tsOff; texture::config.tstate = texture::tsOff;
if(texture::tstate_max == texture::tsActive) if(texture::config.tstate_max == texture::tsActive)
texture::tstate = texture::tsAdjusting; texture::config.tstate = texture::tsAdjusting;
#endif #endif
} }
if(switchWhat == 'y') { if(switchWhat == 'y') {

View File

@ -10,8 +10,6 @@
#if CAP_TEXTURE #if CAP_TEXTURE
namespace texture { namespace texture {
GLuint textureid = 0;
cpatterntype cgroup; cpatterntype cgroup;
SDL_Surface *convertSurface(SDL_Surface* s) { SDL_Surface *convertSurface(SDL_Surface* s) {
@ -39,45 +37,28 @@ SDL_Surface *convertSurface(SDL_Surface* s) {
return SDL_ConvertSurface(s, &fmt, SDL_SWSURFACE); return SDL_ConvertSurface(s, &fmt, SDL_SWSURFACE);
} }
int twidth = 2048;
unsigned paint_color = 0x000000FF;
vector<unsigned> texture_pixels;
unsigned& get_texture_pixel(int x, int y) {
return texture_pixels[(y&(twidth-1))*twidth+(x&(twidth-1))];
}
string texturename = "textures/hyperrogue-texture.png";
string configname = "textures/hyperrogue.txc";
bool saving = false;
eTextureState tstate;
eTextureState tstate_max;
struct undo { struct undo {
unsigned* pix; unsigned* pix;
unsigned last; unsigned last;
}; };
vector<pair<unsigned*, unsigned>> undos; texture_config config;
vector<tuple<cell*, hyperpoint, int> > pixels_to_draw;
template<class T, class U> void scale_colorarray(int origdim, const T& src, const U& dest) { bool saving = false;
template<class T, class U> void scale_colorarray(int origdim, int targetdim, const T& src, const U& dest) {
int ox = 0, tx = 0, partials[4]; int ox = 0, tx = 0, partials[4];
int omissing = twidth, tmissing = origdim; int omissing = targetdim, tmissing = origdim;
for(int p=0; p<4; p++) partials[p] = 0; for(int p=0; p<4; p++) partials[p] = 0;
while(tx < twidth) { while(tx < targetdim) {
int fv = min(omissing, tmissing); int fv = min(omissing, tmissing);
int c = src(ox); int c = src(ox);
for(int p=0; p<4; p++) for(int p=0; p<4; p++)
partials[p] += part(c, p) * fv; partials[p] += part(c, p) * fv;
omissing -= fv; tmissing -= fv; omissing -= fv; tmissing -= fv;
if(omissing == 0) { if(omissing == 0) {
ox++; omissing = twidth; ox++; omissing = targetdim;
} }
if(tmissing == 0) { if(tmissing == 0) {
int target; int target;
@ -91,11 +72,11 @@ template<class T, class U> void scale_colorarray(int origdim, const T& src, cons
} }
} }
bool loadTextureGL() { bool texture_data::loadTextureGL() {
if(textureid == 0) glGenTextures(1, &textureid ); if(textureid == 0) glGenTextures(1, &textureid);
glBindTexture( GL_TEXTURE_2D, textureid); glBindTexture( GL_TEXTURE_2D, config.data.textureid);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
@ -106,7 +87,7 @@ bool loadTextureGL() {
return true; return true;
} }
bool whitetexture() { bool texture_data::whitetexture() {
undos.clear(); undos.clear();
texture_pixels.resize(0); texture_pixels.resize(0);
texture_pixels.resize(twidth * twidth, 0xFFFFFFFF); texture_pixels.resize(twidth * twidth, 0xFFFFFFFF);
@ -114,13 +95,13 @@ bool whitetexture() {
return true; return true;
} }
bool readtexture() { bool texture_data::readtexture(string tn) {
undos.clear(); undos.clear();
texture_pixels.resize(twidth * twidth); texture_pixels.resize(twidth * twidth);
#if CAP_SDL_IMG #if CAP_SDL_IMG
SDL_Surface *txt = IMG_Load(texturename.c_str()); SDL_Surface *txt = IMG_Load(tn.c_str());
if(!txt) { if(!txt) {
addMessage(XLAT("Failed to load %1", texturename)); addMessage(XLAT("Failed to load %1", texturename));
return false; return false;
@ -134,7 +115,7 @@ bool readtexture() {
#elif CAP_PNG #elif CAP_PNG
FILE *f = fopen(texturename.c_str(), "rb"); FILE *f = fopen(tn.c_str(), "rb");
if(!f) { printf("failed to open file\n"); return false; } if(!f) { printf("failed to open file\n"); return false; }
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png) { printf("failed to create_read_struct\n"); return false; } if(!png) { printf("failed to create_read_struct\n"); return false; }
@ -205,13 +186,13 @@ bool readtexture() {
vector<int> half_expanded(twidth * ty); vector<int> half_expanded(twidth * ty);
for(int y=0; y<ty; y++) for(int y=0; y<ty; y++)
scale_colorarray(origdim, scale_colorarray(origdim, twidth,
[&] (int x) { return pix(base_x + x,y); }, [&] (int x) { return pix(base_x + x,y); },
[&] (int x, int v) { half_expanded[twidth * y + x] = v; } [&] (int x, int v) { half_expanded[twidth * y + x] = v; }
); );
for(int x=0; x<twidth; x++) for(int x=0; x<twidth; x++)
scale_colorarray(origdim, scale_colorarray(origdim, twidth,
[&] (int y) { return base_y+y < 0 || base_y+y >= ty ? 0 : half_expanded[x + (base_y + y) * twidth]; }, [&] (int y) { return base_y+y < 0 || base_y+y >= ty ? 0 : half_expanded[x + (base_y + y) * twidth]; },
[&] (int y, int v) { get_texture_pixel(x, y) = v; } [&] (int y, int v) { get_texture_pixel(x, y) = v; }
); );
@ -225,28 +206,17 @@ bool readtexture() {
return true; return true;
} }
void saveRawTexture() { void texture_data::saveRawTexture(string tn) {
SDL_Surface *sraw = SDL_CreateRGBSurface(SDL_SWSURFACE,twidth,twidth,32,0,0,0,0); SDL_Surface *sraw = SDL_CreateRGBSurface(SDL_SWSURFACE,twidth,twidth,32,0,0,0,0);
for(int y=0; y<twidth; y++) for(int y=0; y<twidth; y++)
for(int x=0; x<twidth; x++) for(int x=0; x<twidth; x++)
qpixel(sraw,x,y) = get_texture_pixel(x, y); qpixel(sraw,x,y) = get_texture_pixel(x, y);
IMAGESAVE(sraw, texturename.c_str()); IMAGESAVE(sraw, tn.c_str());
SDL_FreeSurface(sraw); SDL_FreeSurface(sraw);
addMessage(XLAT("Saved the raw texture to %1", texturename)); addMessage(XLAT("Saved the raw texture to %1", tn));
} }
transmatrix itt = Id; void texture_config::mapTextureTriangle(textureinfo &mi, const array<hyperpoint, 3>& v, const array<hyperpoint, 3>& tv, int splits) {
unsigned grid_color = 0;
unsigned mesh_color = 0;
unsigned master_color = 0xFFFFFF30;
unsigned slave_color = 0xFF000008;
int color_alpha = 128;
int gsplits = 1;
void mapTextureTriangle(textureinfo &mi, const array<hyperpoint, 3>& v, const array<hyperpoint, 3>& tv, int splits = gsplits) {
if(splits) { if(splits) {
array<hyperpoint, 3> v2 = make_array( mid(v[1], v[2]), mid(v[2], v[0]), mid(v[0], v[1]) ); array<hyperpoint, 3> v2 = make_array( mid(v[1], v[2]), mid(v[2], v[0]), mid(v[0], v[1]) );
@ -272,12 +242,6 @@ void mapTextureTriangle(textureinfo &mi, const array<hyperpoint, 3>& v, const ar
texture_triangle *edited_triangle; texture_triangle *edited_triangle;
textureinfo *edited_tinfo; textureinfo *edited_tinfo;
vector<hyperpoint*> tuned_vertices;
map<int, textureinfo> texture_map, texture_map_orig;
set<cell*> models;
array<hyperpoint, 3> findTextureTriangle(cell *c, patterns::patterninfo& si, int i) { array<hyperpoint, 3> findTextureTriangle(cell *c, patterns::patterninfo& si, int i) {
// auto si = getpatterninfo0(c); // auto si = getpatterninfo0(c);
transmatrix M = shmup::ggmatrix(c) * applyPatterndir(c, si); transmatrix M = shmup::ggmatrix(c) * applyPatterndir(c, si);
@ -318,27 +282,27 @@ void mapTexture(cell *c, textureinfo& mi, patterns::patterninfo &si, const trans
} }
} }
void mapTexture2(textureinfo& mi) { void texture_config::mapTexture2(textureinfo& mi) {
mi.vertices.clear(); mi.vertices.clear();
mi.tvertices.clear(); mi.tvertices.clear();
for(auto& t: mi.triangles) for(auto& t: mi.triangles)
mapTextureTriangle(mi, t.v, t.tv); mapTextureTriangle(mi, t.v, t.tv);
} }
int recolor(int col) { int texture_config::recolor(int col) {
if(color_alpha == 0) return col; if(color_alpha == 0) return col;
for(int i=1; i<4; i++) for(int i=1; i<4; i++)
part(col, i) = color_alpha + ((255-color_alpha) * part(col,i) + 127) / 255; part(col, i) = color_alpha + ((255-color_alpha) * part(col,i) + 127) / 255;
return col; return col;
} }
bool apply(cell *c, const transmatrix &V, int col) { bool texture_config::apply(cell *c, const transmatrix &V, int col) {
if(tstate == tsOff) return false; if(config.tstate == tsOff) return false;
using namespace patterns; using namespace patterns;
auto si = getpatterninfo0(c); auto si = getpatterninfo0(c);
if(tstate == tsAdjusting) { if(config.tstate == tsAdjusting) {
queuepolyat(V, shFullCross[ctof(c)], 0, PPR_LINE); queuepolyat(V, shFullCross[ctof(c)], 0, PPR_LINE);
lastptd().u.poly.outline = slave_color; lastptd().u.poly.outline = slave_color;
queuepolyat(V, shFullFloor[ctof(c)], 0, PPR_LINE); queuepolyat(V, shFullFloor[ctof(c)], 0, PPR_LINE);
@ -385,9 +349,9 @@ bool apply(cell *c, const transmatrix &V, int col) {
for(int j=0; j<2; j++) for(int k=0; k<3; k++) for(int j=0; j<2; j++) for(int k=0; k<3; k++)
v[j] += mi.tvertices[i+k][j] * p[k]; v[j] += mi.tvertices[i+k][j] * p[k];
int vi[2] = {int(v[0] * twidth), int(v[1] * twidth)}; int vi[2] = {int(v[0] * config.data.twidth), int(v[1] * config.data.twidth)};
col = get_texture_pixel(vi[0], vi[1]); col = config.data.get_texture_pixel(vi[0], vi[1]);
hyperpoint h = glhr::gltopoint(mi.vertices[i]); hyperpoint h = glhr::gltopoint(mi.vertices[i]);
addaura(V*h, col, 0); addaura(V*h, col, 0);
} }
@ -401,8 +365,8 @@ bool apply(cell *c, const transmatrix &V, int col) {
} }
} }
void mark_triangles() { void texture_config::mark_triangles() {
if(tstate == tsAdjusting) if(config.tstate == tsAdjusting)
for(auto& mi: texture_map) { for(auto& mi: texture_map) {
for(auto& t: mi.second.triangles) { for(auto& t: mi.second.triangles) {
vector<hyperpoint> t2; vector<hyperpoint> t2;
@ -413,16 +377,9 @@ void mark_triangles() {
} }
} }
typedef tuple<eGeometry, bool, char, int, eModel, ld, ld> texture_parameters;
static const auto current_texture_parameters = tie(geometry, nonbitrunc, patterns::whichPattern, patterns::subpattern_flags, pmodel, vid.scale, vid.alpha); static const auto current_texture_parameters = tie(geometry, nonbitrunc, patterns::whichPattern, patterns::subpattern_flags, pmodel, vid.scale, vid.alpha);
texture_parameters orig_texture_parameters; void texture_config::clear_texture_map() {
bool texture_tuned = false;
string texture_tuner;
void clear_texture_map() {
texture_map.clear(); texture_map.clear();
edited_triangle = nullptr; edited_triangle = nullptr;
edited_tinfo = nullptr; edited_tinfo = nullptr;
@ -432,7 +389,7 @@ void clear_texture_map() {
texture_tuner = ""; texture_tuner = "";
} }
void perform_mapping() { void texture_config::perform_mapping() {
if(gsplits < 0) gsplits = 0; if(gsplits < 0) gsplits = 0;
if(gsplits > 4) gsplits = 4; if(gsplits > 4) gsplits = 4;
using namespace patterns; using namespace patterns;
@ -454,7 +411,7 @@ void perform_mapping() {
if(replace) { if(replace) {
auto& mi = texture_map[si.id]; auto& mi = texture_map[si.id];
mapTexture(c, mi, si, p.second); mapTexture(c, mi, si, p.second);
mi.texture_id = textureid; mi.texture_id = config.data.textureid;
} }
} }
@ -476,28 +433,28 @@ void perform_mapping() {
texture::cgroup = patterns::cgroup; texture::cgroup = patterns::cgroup;
texture_map_orig = texture_map; texture_map_orig = texture_map;
orig_texture_parameters = current_texture_parameters; orig_texture_parameters = current_texture_parameters;
// printf("texture_map has %d elements (S%d)\n", size(texture_map), tstate); // printf("texture_map has %d elements (S%d)\n", size(texture_map), config.tstate);
} }
void finish_mapping() { void texture_config::finish_mapping() {
if(tstate == tsActive) if(config.tstate == tsActive)
for(auto& mi: texture_map) for(auto& mi: texture_map)
mapTexture2(mi.second); mapTexture2(mi.second);
} }
void saveFullTexture() { void texture_config::saveFullTexture(string tn) {
addMessage(XLAT("Saving full texture to %1...", texturename)); addMessage(XLAT("Saving full texture to %1...", tn));
dynamicval<unsigned> dd(grid_color, 0); dynamicval<unsigned> dd(grid_color, 0);
dynamicval<unsigned> dm(mesh_color, 0); dynamicval<unsigned> dm(mesh_color, 0);
texture::saving = true; texture::saving = true;
drawscreen(); drawscreen();
dynamicval<int> dv(pngres, twidth); dynamicval<int> dv(pngres, data.twidth);
saveHighQualityShot(texturename.c_str()); saveHighQualityShot(tn.c_str());
texture::saving = false; texture::saving = false;
drawscreen(); drawscreen();
if(readtexture() && loadTextureGL()) { if(data.readtexture(tn) && data.loadTextureGL()) {
itt = Id; // xyscale(Id, vid.scrsize * 1. / vid.radius); itt = Id; // xyscale(Id, vid.scrsize * 1. / vid.radius);
perform_mapping(); perform_mapping();
finish_mapping(); finish_mapping();
@ -508,10 +465,10 @@ bool newmove = false;
vector<glhr::textured_vertex> rtver(4); vector<glhr::textured_vertex> rtver(4);
void drawRawTexture() { void texture_config::drawRawTexture() {
glhr::be_textured(); glhr::be_textured();
glhr::color2(0xFFFFFF20); glhr::color2(0xFFFFFF20);
glBindTexture(GL_TEXTURE_2D, textureid); glBindTexture(GL_TEXTURE_2D, config.data.textureid);
for(int i=0; i<4; i++) { for(int i=0; i<4; i++) {
int cx[4] = {2, -2, -2, 2}; int cx[4] = {2, -2, -2, 2};
int cy[4] = {2, 2, -2, -2}; int cy[4] = {2, 2, -2, -2};
@ -587,7 +544,7 @@ struct magic_param {
transmatrix Ti = inverse(T); transmatrix Ti = inverse(T);
for(auto& p: amp) for(auto& p: amp)
p.texture_coords = Ti * p.texture_coords; p.texture_coords = Ti * p.texture_coords;
itt = itt * T; config.itt = config.itt * T;
} }
void apply(ld delta) { void apply(ld delta) {
@ -672,21 +629,21 @@ void mousemovement() {
case tpsModel: case tpsModel:
if(!newmove && mouseh[2] < 50 && lastmouse[2] < 50) { if(!newmove && mouseh[2] < 50 && lastmouse[2] < 50) {
panning(lastmouse, mouseh); panning(lastmouse, mouseh);
perform_mapping(); config.perform_mapping();
} }
lastmouse = mouseh; newmove = false; lastmouse = mouseh; newmove = false;
break; break;
case tpsMove: { case tpsMove: {
if(!newmove) if(!newmove)
itt = itt * inverse(eupush(mouseeu)) * eupush(lastmouse); config.itt = config.itt * inverse(eupush(mouseeu)) * eupush(lastmouse);
lastmouse = mouseeu; newmove = false; lastmouse = mouseeu; newmove = false;
break; break;
} }
case tpsScale: { case tpsScale: {
if(nonzero && !newmove) if(nonzero && !newmove)
itt = itt * inverse(euscalezoom(mouseeu)) * euscalezoom(lastmouse); config.itt = config.itt * inverse(euscalezoom(mouseeu)) * euscalezoom(lastmouse);
if(nonzero) lastmouse = mouseeu; if(nonzero) lastmouse = mouseeu;
newmove = false; newmove = false;
break; break;
@ -694,7 +651,7 @@ void mousemovement() {
case tpsAffine: { case tpsAffine: {
if(!newmove) if(!newmove)
itt = itt * inverse(euaffine(mouseeu)) * euaffine(lastmouse); config.itt = config.itt * inverse(euaffine(mouseeu)) * euaffine(lastmouse);
lastmouse = mouseeu; newmove = false; lastmouse = mouseeu; newmove = false;
break; break;
} }
@ -725,15 +682,15 @@ void mousemovement() {
auto si = patterns::getpatterninfo0(c); auto si = patterns::getpatterninfo0(c);
if(newmove) { if(newmove) {
edited_tinfo = NULL; edited_tinfo = NULL;
if(texture_map.count(si.id)) { if(config.texture_map.count(si.id)) {
edited_tinfo = &texture_map[si.id]; edited_tinfo = &config.texture_map[si.id];
newmove = false; newmove = false;
} }
} }
if(edited_tinfo && size(edited_tinfo->triangles) == c->type) { if(edited_tinfo && size(edited_tinfo->triangles) == c->type) {
for(int i=0; i<c->type; i++) for(int i=0; i<c->type; i++)
edited_tinfo->triangles[i].tv = findTextureTriangle(c, si, i); edited_tinfo->triangles[i].tv = findTextureTriangle(c, si, i);
texture_tuned = true; config.texture_tuned = true;
} }
break; break;
} }
@ -745,14 +702,14 @@ void mousemovement() {
int i = getTriangleID(c, si, mouseh); int i = getTriangleID(c, si, mouseh);
if(newmove) { if(newmove) {
edited_triangle = NULL; edited_triangle = NULL;
if(texture_map.count(si.id)) { if(config.texture_map.count(si.id)) {
edited_triangle = &texture_map[si.id].triangles[i]; edited_triangle = &config.texture_map[si.id].triangles[i];
newmove = false; newmove = false;
} }
} }
if(edited_triangle) { if(edited_triangle) {
edited_triangle->tv = findTextureTriangle(c, si, i); edited_triangle->tv = findTextureTriangle(c, si, i);
texture_tuned = true; config.texture_tuned = true;
} }
break; break;
} }
@ -760,22 +717,22 @@ void mousemovement() {
case tpsTune: { case tpsTune: {
ld tdist = 1e20; ld tdist = 1e20;
if(newmove) { if(newmove) {
tuned_vertices.clear(); config.tuned_vertices.clear();
for(auto& a: texture_map) for(auto& a: config.texture_map)
for(auto& t: a.second.triangles) for(auto& t: a.second.triangles)
for(auto& v: t.tv) for(auto& v: t.tv)
if(intval(v, mouseh) < tdist) if(intval(v, mouseh) < tdist)
tdist = intval(v, mouseh); tdist = intval(v, mouseh);
for(auto& a: texture_map) for(auto& a: config.texture_map)
for(auto& t: a.second.triangles) for(auto& t: a.second.triangles)
for(auto& v: t.tv) for(auto& v: t.tv)
if(intval(v, mouseh) < tdist * (1.000001)) if(intval(v, mouseh) < tdist * (1.000001))
tuned_vertices.push_back(&v); config.tuned_vertices.push_back(&v);
newmove = false; newmove = false;
} }
for(auto v: tuned_vertices) { for(auto v: config.tuned_vertices) {
*v = mouseh; *v = mouseh;
texture_tuned = true; config.texture_tuned = true;
} }
break; break;
} }
@ -794,7 +751,7 @@ void init_textureconfig() {
texturesavers = move(savers); texturesavers = move(savers);
for(int i=0; i<3; i++) for(int i=0; i<3; i++)
for(int j=0; j<3; j++) for(int j=0; j<3; j++)
addsaver(itt[i][j], "texturematrix_" + its(i) + its(j), i==j ? 1 : 0); addsaver(config.itt[i][j], "texturematrix_" + its(i) + its(j), i==j ? 1 : 0);
for(int i=0; i<3; i++) for(int i=0; i<3; i++)
for(int j=0; j<3; j++) for(int j=0; j<3; j++)
@ -819,30 +776,30 @@ void init_textureconfig() {
addsaver(si_save.dir, "center direction", 0); addsaver(si_save.dir, "center direction", 0);
addsaver(si_save.reflect, "center reflection", false); addsaver(si_save.reflect, "center reflection", false);
addsaver(viewctr.spin, "center spin", 0); addsaver(viewctr.spin, "center spin", 0);
addsaver(twidth, "texture resolution", 2048); addsaver(config.data.twidth, "texture resolution", 2048);
addsaver(gsplits, "precision", 1); addsaver(config.gsplits, "precision", 1);
addsaver(grid_color, "grid color", 0); addsaver(config.grid_color, "grid color", 0);
addsaver(color_alpha, "alpha color", 0); addsaver(config.color_alpha, "alpha color", 0);
addsaver(mesh_color, "mesh color", 0); addsaver(config.mesh_color, "mesh color", 0);
addsaver(vid.alpha, "projection", 1); addsaver(vid.alpha, "projection", 1);
addsaver(vid.scale, "scale", 1); addsaver(vid.scale, "scale", 1);
addsaver(texturename, "texture filename", ""); addsaver(config.texturename, "texture filename", "");
addsaver(texture_tuner, "texture tuning", ""); addsaver(config.texture_tuner, "texture tuning", "");
swap(texturesavers, savers); swap(texturesavers, savers);
} }
bool save_textureconfig() { bool texture_config::save() {
init_textureconfig(); init_textureconfig();
FILE *f = fopen(configname.c_str(), "wt"); FILE *f = fopen(configname.c_str(), "wt");
if(!f) return false; if(!f) return false;
if(texture_tuned) { if(texture_tuned) {
texture_tuner = ""; texture_tuner = "";
for(auto& a: texture_map) for(auto& a: config.texture_map)
for(auto& t: a.second.triangles) for(auto& t: a.second.triangles)
for(auto& v: t.tv) for(auto& v: t.tv)
for(int i=0; i<3; i++) { for(int i=0; i<3; i++) {
@ -861,7 +818,7 @@ bool save_textureconfig() {
return true; return true;
} }
bool load_textureconfig() { bool texture_config::load() {
init_textureconfig(); init_textureconfig();
FILE *f = fopen(configname.c_str(), "rt"); FILE *f = fopen(configname.c_str(), "rt");
@ -878,7 +835,7 @@ bool load_textureconfig() {
if(targetgeometry != geometry) { if(targetgeometry != geometry) {
restartGame('g'); restartGame('g');
return load_textureconfig(); return config.load();
} }
if(nonbitrunc != target_nonbitru) { if(nonbitrunc != target_nonbitru) {
@ -903,11 +860,11 @@ bool load_textureconfig() {
addMessage(XLAT("warning: unable to find the center")); addMessage(XLAT("warning: unable to find the center"));
} }
if(!readtexture()) return false; if(!data.readtexture(texturename)) return false;
if(!loadTextureGL()) return false; if(!data.loadTextureGL()) return false;
calcparam(); calcparam();
drawthemap(); drawthemap();
tstate = tstate_max = tsActive; config.tstate = config.tstate_max = tsActive;
string s = move(texture_tuner); string s = move(texture_tuner);
perform_mapping(); perform_mapping();
@ -916,7 +873,7 @@ bool load_textureconfig() {
if(texture_tuner != "") { if(texture_tuner != "") {
texture_tuned = true; texture_tuned = true;
vector<ld*> coords; vector<ld*> coords;
for(auto& a: texture_map) for(auto& a: config.texture_map)
for(auto& t: a.second.triangles) for(auto& t: a.second.triangles)
for(auto& v: t.tv) for(auto& v: t.tv)
for(int i=0; i<3; i++) for(int i=0; i<3; i++)
@ -973,7 +930,7 @@ void showMagicMenu() {
amp.back().texture_coords = mouseeu; amp.back().texture_coords = mouseeu;
} }
if(tstate == tsAdjusting) { if(config.tstate == tsAdjusting) {
initquickqueue(); initquickqueue();
char letter = 'A'; char letter = 'A';
for(auto& am: amp) { for(auto& am: amp) {
@ -1000,7 +957,7 @@ void showMagicMenu() {
// handlePanning(sym, uni); // handlePanning(sym, uni);
dialog::handleNavigation(sym, uni); dialog::handleNavigation(sym, uni);
if(uni == '-' && tstate == tsAdjusting) { if(uni == '-' && config.tstate == tsAdjusting) {
if(!holdmouse) { if(!holdmouse) {
holdmouse = true; holdmouse = true;
newmove = true; newmove = true;
@ -1032,25 +989,25 @@ string texturehelp =
void showMenu() { void showMenu() {
cmode = sm::SIDE | sm::MAYDARK | sm::DIALOG_STRICT_X; cmode = sm::SIDE | sm::MAYDARK | sm::DIALOG_STRICT_X;
gamescreen(0); gamescreen(0);
if(tstate == tsAdjusting) { if(config.tstate == tsAdjusting) {
ptds.clear(); ptds.clear();
texture::mark_triangles(); config.mark_triangles();
drawqueue(); drawqueue();
} }
if(tstate == tsOff) { if(config.tstate == tsOff) {
dialog::init(XLAT("texture mode (off)")); dialog::init(XLAT("texture mode (off)"));
dialog::addItem(XLAT("select geometry/pattern"), 'r'); dialog::addItem(XLAT("select geometry/pattern"), 'r');
if(tstate_max == tsAdjusting || tstate_max == tsActive) if(config.tstate_max == tsAdjusting || config.tstate_max == tsActive)
dialog::addItem(XLAT("reactivate the texture"), 't'); dialog::addItem(XLAT("reactivate the texture"), 't');
dialog::addItem(XLAT("open PNG as texture"), 'o'); dialog::addItem(XLAT("open PNG as texture"), 'o');
dialog::addItem(XLAT("load texture config"), 'l'); dialog::addItem(XLAT("load texture config"), 'l');
dialog::addSelItem(XLAT("texture size"), its(twidth), 'w'); dialog::addSelItem(XLAT("texture size"), its(config.data.twidth), 'w');
dialog::addItem(XLAT("paint a new texture"), 'n'); dialog::addItem(XLAT("paint a new texture"), 'n');
dialog::addSelItem(XLAT("precision"), its(gsplits), 'P'); dialog::addSelItem(XLAT("precision"), its(config.gsplits), 'P');
} }
if(tstate == tsAdjusting) { if(config.tstate == tsAdjusting) {
dialog::init(XLAT("texture mode (overlay)")); dialog::init(XLAT("texture mode (overlay)"));
dialog::addItem(XLAT("select the texture's pattern"), 'r'); dialog::addItem(XLAT("select the texture's pattern"), 'r');
dialog::addItem(XLAT("enable the texture"), 't'); dialog::addItem(XLAT("enable the texture"), 't');
@ -1069,16 +1026,16 @@ void showMenu() {
dialog::addBoolItem(XLAT("select master triangles"), panstate == tpsTriangle, 'X'); dialog::addBoolItem(XLAT("select master triangles"), panstate == tpsTriangle, 'X');
dialog::addBoolItem(XLAT("fine tune vertices"), panstate == tpsTune, 'F'); dialog::addBoolItem(XLAT("fine tune vertices"), panstate == tpsTune, 'F');
dialog::addColorItem(XLAT("grid color (master)"), master_color, 'M'); dialog::addColorItem(XLAT("grid color (master)"), config.master_color, 'M');
dialog::addColorItem(XLAT("grid color (copy)"), slave_color, 'C'); dialog::addColorItem(XLAT("grid color (copy)"), config.slave_color, 'C');
dialog::addBreak(50); dialog::addBreak(50);
dialog::addSelItem(XLAT("precision"), its(gsplits), 'P'); dialog::addSelItem(XLAT("precision"), its(config.gsplits), 'P');
dialog::addItem(XLAT("save the raw texture"), 'S'); dialog::addItem(XLAT("save the raw texture"), 'S');
} }
if(tstate == tsActive) { if(config.tstate == tsActive) {
dialog::init(XLAT("texture mode (active)")); dialog::init(XLAT("texture mode (active)"));
/* dialog::addSelItem(XLAT("texture scale"), fts(iscale), 's'); /* dialog::addSelItem(XLAT("texture scale"), fts(iscale), 's');
dialog::addSelItem(XLAT("texture angle"), fts(irotate), 'a'); dialog::addSelItem(XLAT("texture angle"), fts(irotate), 'a');
@ -1087,10 +1044,10 @@ void showMenu() {
dialog::addItem(XLAT("deactivate the texture"), 't'); dialog::addItem(XLAT("deactivate the texture"), 't');
dialog::addItem(XLAT("back to overlay mode"), 'T'); dialog::addItem(XLAT("back to overlay mode"), 'T');
dialog::addItem(XLAT("change the geometry"), 'r'); dialog::addItem(XLAT("change the geometry"), 'r');
dialog::addColorItem(XLAT("grid color"), grid_color, 'g'); dialog::addColorItem(XLAT("grid color"), config.grid_color, 'g');
dialog::addColorItem(XLAT("mesh color"), mesh_color, 'm'); dialog::addColorItem(XLAT("mesh color"), config.mesh_color, 'm');
dialog::addSelItem(XLAT("color alpha"), its(color_alpha), 'c'); dialog::addSelItem(XLAT("color alpha"), its(config.color_alpha), 'c');
dialog::addSelItem(XLAT("precision"), its(gsplits), 'P'); dialog::addSelItem(XLAT("precision"), its(config.gsplits), 'P');
dialog::addItem(XLAT("edit the texture"), 'e'); dialog::addItem(XLAT("edit the texture"), 'e');
dialog::addItem(XLAT("save the full texture image"), 'S'); dialog::addItem(XLAT("save the full texture image"), 'S');
dialog::addItem(XLAT("save texture config"), 's'); dialog::addItem(XLAT("save texture config"), 's');
@ -1109,121 +1066,122 @@ void showMenu() {
// handlePanning(sym, uni); // handlePanning(sym, uni);
dialog::handleNavigation(sym, uni); dialog::handleNavigation(sym, uni);
if(uni == '-' && tstate == tsAdjusting) { if(uni == '-' && config.tstate == tsAdjusting) {
if(!holdmouse) { if(!holdmouse) {
holdmouse = true; holdmouse = true;
newmove = true; newmove = true;
} }
} }
else if(uni == 'm' && tstate == tsAdjusting) panstate = tpsModel; else if(uni == 'm' && config.tstate == tsAdjusting) panstate = tpsModel;
else if(uni == 'a' && tstate == tsAdjusting) panstate = tpsMove; else if(uni == 'a' && config.tstate == tsAdjusting) panstate = tpsMove;
else if(uni == 'x' && tstate == tsAdjusting) panstate = tpsScale; else if(uni == 'x' && config.tstate == tsAdjusting) panstate = tpsScale;
else if(uni == 'y' && tstate == tsAdjusting) panstate = tpsAffine; else if(uni == 'y' && config.tstate == tsAdjusting) panstate = tpsAffine;
else if(uni == 'z' && tstate == tsAdjusting) panstate = tpsZoom; else if(uni == 'z' && config.tstate == tsAdjusting) panstate = tpsZoom;
else if(uni == 'p' && tstate == tsAdjusting) panstate = tpsProjection; else if(uni == 'p' && config.tstate == tsAdjusting) panstate = tpsProjection;
else if(uni == 'C' && tstate == tsAdjusting) panstate = tpsCell; else if(uni == 'C' && config.tstate == tsAdjusting) panstate = tpsCell;
else if(uni == 'X' && tstate == tsAdjusting) panstate = tpsTriangle; else if(uni == 'X' && config.tstate == tsAdjusting) panstate = tpsTriangle;
else if(uni == 'F' && tstate == tsAdjusting) panstate = tpsTune; else if(uni == 'F' && config.tstate == tsAdjusting) panstate = tpsTune;
else if(uni == 'A' && tstate == tsAdjusting) else if(uni == 'A' && config.tstate == tsAdjusting)
pushScreen(showMagicMenu); pushScreen(showMagicMenu);
else if(uni == 's' && tstate == tsActive) else if(uni == 's' && config.tstate == tsActive)
dialog::openFileDialog(configname, XLAT("save texture config"), ".txc", dialog::openFileDialog(config.configname, XLAT("save texture config"), ".txc",
[] () { [] () {
return save_textureconfig(); return config.save();
}); });
else if(uni == 'l' && tstate == tsOff) else if(uni == 'l' && config.tstate == tsOff)
dialog::openFileDialog(configname, XLAT("load texture config"), ".txc", dialog::openFileDialog(config.configname, XLAT("load texture config"), ".txc",
[] () { [] () {
return load_textureconfig(); return config.load();
}); });
else if(uni == 'r') else if(uni == 'r')
patterns::pushChangeablePatterns(); patterns::pushChangeablePatterns();
else if(uni == 'o' && tstate == tsOff) else if(uni == 'o' && config.tstate == tsOff)
dialog::openFileDialog(texturename, XLAT("open PNG as texture"), ".png", dialog::openFileDialog(config.texturename, XLAT("open PNG as texture"), ".png",
[] () { [] () {
if(readtexture() && loadTextureGL()) { if(config.data.readtexture(config.texturename) && config.data.loadTextureGL()) {
if(tstate_max == tsOff) tstate_max = tsAdjusting; if(config.tstate_max == tsOff) config.tstate_max = tsAdjusting;
tstate = tstate_max; config.tstate = config.tstate_max;
perform_mapping(); config.perform_mapping();
finish_mapping(); config.finish_mapping();
return true; return true;
} }
else return false; else return false;
}); });
else if(uni == 'w' && tstate == tsOff) { else if(uni == 'w' && config.tstate == tsOff) {
twidth *= 2; config.data.twidth *= 2;
if(twidth > 9000) twidth = 256; if(config.data.twidth > 9000) config.data.twidth = 256;
tstate_max = tsOff; config.tstate_max = tsOff;
} }
else if(uni == 'e' && tstate == tsActive) { else if(uni == 'e' && config.tstate == tsActive) {
mapeditor::initdraw(cwt.c); mapeditor::initdraw(cwt.c);
pushScreen(mapeditor::showDrawEditor); pushScreen(mapeditor::showDrawEditor);
} }
else if(uni == 'n' && tstate == tsOff) { else if(uni == 'n' && config.tstate == tsOff) {
addMessage("white"); addMessage("white");
if(whitetexture() && loadTextureGL()) { if(config.data.whitetexture() && config.data.loadTextureGL()) {
tstate = tstate_max = tsActive; config.tstate = config.tstate_max = tsActive;
perform_mapping(); config.perform_mapping();
finish_mapping(); config.finish_mapping();
mapeditor::initdraw(cwt.c); mapeditor::initdraw(cwt.c);
pushScreen(mapeditor::showDrawEditor); pushScreen(mapeditor::showDrawEditor);
} }
} }
else if(uni == 't' && tstate == tsOff) else if(uni == 't' && config.tstate == tsOff)
tstate = tstate_max; config.tstate = config.tstate_max;
else if(uni == 't' && tstate == tsAdjusting) { else if(uni == 't' && config.tstate == tsAdjusting) {
tstate = tstate_max = tsActive; config.tstate = config.tstate_max = tsActive;
finish_mapping(); config.finish_mapping();
} }
else if(uni == 't' && tstate == tsActive) else if(uni == 't' && config.tstate == tsActive)
tstate = tsOff; config.tstate = tsOff;
else if(uni == 'T' && tstate == tsAdjusting) else if(uni == 'T' && config.tstate == tsAdjusting)
tstate = tsOff; config.tstate = tsOff;
else if(uni == 'T' && tstate == tsActive) else if(uni == 'T' && config.tstate == tsActive)
tstate = tsAdjusting; config.tstate = tsAdjusting;
else if(uni == 'g' && tstate == tsActive) else if(uni == 'g' && config.tstate == tsActive)
dialog::openColorDialog(grid_color, NULL); dialog::openColorDialog(config.grid_color, NULL);
else if(uni == 'm' && tstate == tsActive) else if(uni == 'm' && config.tstate == tsActive)
dialog::openColorDialog(mesh_color, NULL); dialog::openColorDialog(config.mesh_color, NULL);
else if(uni == 'M' && tstate == tsAdjusting) else if(uni == 'M' && config.tstate == tsAdjusting)
dialog::openColorDialog(master_color, NULL); dialog::openColorDialog(config.master_color, NULL);
else if(uni == 'C' && tstate == tsAdjusting) else if(uni == 'C' && config.tstate == tsAdjusting)
dialog::openColorDialog(slave_color, NULL); dialog::openColorDialog(config.slave_color, NULL);
else if(uni == 'c' && tstate == tsActive) { else if(uni == 'c' && config.tstate == tsActive) {
dialog::editNumber(color_alpha, 0, 255, 15, 0, XLAT("color alpha"), dialog::editNumber(config.color_alpha, 0, 255, 15, 0, XLAT("color alpha"),
XLAT("The higher the value, the less important the color of underlying terrain is.")); XLAT("The higher the value, the less important the color of underlying terrain is."));
} }
else if(uni == 'P') { else if(uni == 'P') {
dialog::editNumber(gsplits, 0, 4, 1, 1, XLAT("precision"), dialog::editNumber(config.gsplits, 0, 4, 1, 1, XLAT("precision"),
XLAT("precision")); XLAT("precision"));
if(tstate == tsActive) dialog::reaction = [] () { finish_mapping(); if(config.tstate == tsActive) dialog::reaction = [] () { config.finish_mapping();
}; };
} }
else if(uni == 'S' && tstate == tsAdjusting) else if(uni == 'S' && config.tstate == tsAdjusting)
dialog::openFileDialog(texturename, XLAT("save the raw texture"), ".png", dialog::openFileDialog(config.texturename, XLAT("save the raw texture"), ".png",
[] () { [] () {
saveRawTexture(); return true; config.data.saveRawTexture(config.texturename); return true;
}); });
else if(uni == 'S' && tstate == tsActive) else if(uni == 'S' && config.tstate == tsActive)
dialog::openFileDialog(texturename, XLAT("save the full texture image"), ".png", dialog::openFileDialog(config.texturename, XLAT("save the full texture image"), ".png",
[] () { [] () {
saveFullTexture(); return true; config.saveFullTexture(config.texturename);
return true;
}); });
else if(uni == SDLK_F1) else if(uni == SDLK_F1)
gotoHelp(texturehelp); gotoHelp(texturehelp);
@ -1237,11 +1195,11 @@ typedef pair<int,int> point;
point ptc(hyperpoint h) { point ptc(hyperpoint h) {
hyperpoint inmodel; hyperpoint inmodel;
applymodel(h, inmodel); applymodel(h, inmodel);
inmodel = itt * inmodel; inmodel = config.itt * inmodel;
inmodel[0] *= vid.radius * 1. / vid.scrsize; inmodel[0] *= vid.radius * 1. / vid.scrsize;
inmodel[1] *= vid.radius * 1. / vid.scrsize; inmodel[1] *= vid.radius * 1. / vid.scrsize;
int x = (1 + inmodel[0]) * twidth / 2; int x = (1 + inmodel[0]) * config.data.twidth / 2;
int y = (1 + inmodel[1]) * twidth / 2; int y = (1 + inmodel[1]) * config.data.twidth / 2;
return make_pair(x,y); return make_pair(x,y);
} }
@ -1256,15 +1214,15 @@ int texture_distance(pair<int, int> p1, pair<int, int> p2) {
} }
void fillpixel(int x, int y, unsigned col) { void fillpixel(int x, int y, unsigned col) {
if(x<0 || y<0 || x >= twidth || y >= twidth) return; if(x<0 || y<0 || x >= config.data.twidth || y >= config.data.twidth) return;
auto& pix = get_texture_pixel(x, y); auto& pix = config.data.get_texture_pixel(x, y);
if(pix != col) { if(pix != col) {
undos.emplace_back(&pix, pix); config.data.undos.emplace_back(&pix, pix);
pix = col; pix = col;
} }
} }
void undo() { void texture_data::undo() {
while(!undos.empty()) { while(!undos.empty()) {
auto p = undos.back(); auto p = undos.back();
undos.pop_back(); undos.pop_back();
@ -1276,7 +1234,7 @@ void undo() {
} }
} }
void undoLock() { void texture_data::undoLock() {
printf("undos size = %d\n", size(undos)); printf("undos size = %d\n", size(undos));
if(size(undos) > 2000000) { if(size(undos) > 2000000) {
// limit undo memory // limit undo memory
@ -1356,7 +1314,7 @@ void actDrawPixel(cell *c, hyperpoint h, int col) {
transmatrix M = gmatrix.at(c); transmatrix M = gmatrix.at(c);
auto si = patterns::getpatterninfo0(c); auto si = patterns::getpatterninfo0(c);
h = inverse(M * applyPatterndir(c, si)) * h; h = inverse(M * applyPatterndir(c, si)) * h;
auto& tinf = texture_map[si.id]; auto& tinf = config.texture_map[si.id];
for(auto& M2: tinf.matrices) for(int i = 0; i<c->type; i += si.symmetries) { for(auto& M2: tinf.matrices) for(int i = 0; i<c->type; i += si.symmetries) {
fillcircle(M2 * spin(2 * M_PI * i / c->type) * h, col); fillcircle(M2 * spin(2 * M_PI * i / c->type) * h, col);
if(texturesym) if(texturesym)
@ -1367,7 +1325,7 @@ void actDrawPixel(cell *c, hyperpoint h, int col) {
} }
void drawPixel(cell *c, hyperpoint h, int col) { void drawPixel(cell *c, hyperpoint h, int col) {
pixels_to_draw.emplace_back(c, h, col); config.data.pixels_to_draw.emplace_back(c, h, col);
} }
cell *where; cell *where;
@ -1404,12 +1362,12 @@ void drawLine(hyperpoint h1, hyperpoint h2, int col, int steps) {
drawPixel(h2, col); drawPixel(h2, col);
} }
void remap(eTextureState old_tstate, eTextureState old_tstate_max) { void texture_config::remap(eTextureState old_tstate, eTextureState old_tstate_max) {
clear_texture_map(); clear_texture_map();
if(old_tstate == tsActive && patterns::compatible(texture::cgroup, patterns::cgroup)) { if(old_tstate == tsActive && patterns::compatible(texture::cgroup, patterns::cgroup)) {
tstate = old_tstate; config.tstate = old_tstate;
tstate_max = old_tstate_max; config.tstate_max = old_tstate_max;
for(cell *c: dcal) { for(cell *c: dcal) {
auto si = patterns::getpatterninfo0(c); auto si = patterns::getpatterninfo0(c);
@ -1443,13 +1401,13 @@ void remap(eTextureState old_tstate, eTextureState old_tstate_max) {
catch(out_of_range) { catch(out_of_range) {
printf("Unexpected missing cell #%d/%d", si.id, oldid); printf("Unexpected missing cell #%d/%d", si.id, oldid);
addMessage(XLAT("Unexpected missing cell #%d/%d", its(si.id), its(oldid))); addMessage(XLAT("Unexpected missing cell #%d/%d", its(si.id), its(oldid)));
tstate_max = tstate = tsAdjusting; config.tstate_max = config.tstate = tsAdjusting;
return; return;
} }
} }
} }
else if(old_tstate >= tsAdjusting) { else if(old_tstate >= tsAdjusting) {
printf("perform_mapping %d/%d\n", tstate, tstate_max); printf("perform_mapping %d/%d\n", config.tstate, config.tstate_max);
calcparam(); calcparam();
drawthemap(); drawthemap();
perform_mapping(); perform_mapping();
@ -1463,24 +1421,24 @@ int textureArgs() {
if(0) ; if(0) ;
else if(argis("-txpic")) { else if(argis("-txpic")) {
shift(); texturename = args(); shift(); config.texturename = args();
} }
else if(argis("-txp")) { else if(argis("-txp")) {
shift(); gsplits = argf(); shift(); config.gsplits = argf();
} }
else if(argis("-txc")) { else if(argis("-txc")) {
shift(); configname = args(); shift(); config.configname = args();
} }
else if(argis("-txc")) { else if(argis("-txc")) {
shift(); configname = args(); shift(); config.configname = args();
} }
else if(argis("-txcl")) { else if(argis("-txcl")) {
PHASE(3); drawscreen(); PHASE(3); drawscreen();
load_textureconfig(); config.load();
} }
else return 1; else return 1;
@ -1489,11 +1447,11 @@ int textureArgs() {
auto texture_hook = auto texture_hook =
addHook(hooks_args, 100, textureArgs) addHook(hooks_args, 100, textureArgs)
+ addHook(clearmemory, 100, [] () { pixels_to_draw.clear(); }); + addHook(clearmemory, 100, [] () { config.data.pixels_to_draw.clear(); });
int lastupdate; int lastupdate;
void update() { void texture_data::update() {
if(!pixels_to_draw.empty()) { if(!pixels_to_draw.empty()) {
auto t = SDL_GetTicks(); auto t = SDL_GetTicks();
while(SDL_GetTicks() < t + 75 && !pixels_to_draw.empty()) { while(SDL_GetTicks() < t + 75 && !pixels_to_draw.empty()) {