From 6c4538df69ff36ca0dae6ccab95f080ac83f42c5 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Thu, 14 Dec 2017 02:53:29 +0100 Subject: [PATCH] further work on textures --- graph.cpp | 13 +- hyperpoint.cpp | 30 +++- menus.cpp | 6 +- pattern2.cpp | 142 +++++++-------- polygons.cpp | 19 +- textures.cpp | 464 +++++++++++++++++++++++++++++++++++++------------ 6 files changed, 473 insertions(+), 201 deletions(-) diff --git a/graph.cpp b/graph.cpp index c5c8f685..4d3ea0b3 100644 --- a/graph.cpp +++ b/graph.cpp @@ -2912,7 +2912,7 @@ int wavephase; void warpfloor(cell *c, const transmatrix& V, int col, int prio, bool warp) { if(shmup::on || nontruncated) warp = false; if(qfi.tinf) { - queuetable(V*qfi.spin, &qfi.tinf->vertices[0], size(qfi.tinf->vertices) / 3, 0, col, prio); + queuetable(V*qfi.spin, &qfi.tinf->vertices[0], size(qfi.tinf->vertices) / 3, 0, texture::recolor(col), prio); lastptd().u.poly.tinf = qfi.tinf; } else if(wmescher && qfi.special) @@ -3532,7 +3532,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { } #endif - else if(applyTextureMap(c, Vf, darkena(fcol, fd, 0xFF))) ; + else if(texture::apply(c, Vf, darkena(fcol, fd, 0xFF))) ; else if(c->land == laMirrorWall) { int d = mirror::mirrordir(c); @@ -3899,7 +3899,10 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { auto si = patterns::getpatterninfo(c, patterns::whichPattern, pf); - queuepoly(V * applyPatterndir(c,si), shAsymmetric, darkena(0x000000, 0, 0xC0)); + for(int i=0; itype; i += si.symmetries) { + queuepoly(V * applyPatterndir(c,si), shAsymmetric, darkena(0x000000, 0, 0xC0)); + si.dir += si.symmetries; + } string label = its(si.id); queuestr(V, .5, label, 0xFF000000 + forecolor); @@ -5073,8 +5076,10 @@ void calcparam() { vid.ycenter = vid.yres / 2; int realradius = min(vid.xcenter, vid.ycenter); + + vid.scrsize = vid.ycenter - (ISANDROID ? 2 : ISIOS ? 40 : 40); - vid.radius = int(vid.scale * vid.ycenter) - (ISANDROID ? 2 : ISIOS ? 40 : 40); + vid.radius = vid.scale * vid.scrsize; realradius = min(realradius, vid.radius); diff --git a/hyperpoint.cpp b/hyperpoint.cpp index 5a6916d5..093caa07 100644 --- a/hyperpoint.cpp +++ b/hyperpoint.cpp @@ -150,13 +150,6 @@ const transmatrix MirrorX = {{{-1,0,0}, {0,1,0}, {0,0,1}}}; // rotate by PI const transmatrix pispin = {{{-1,0,0}, {0,-1,0}, {0,0,1}}}; -// T * C0, optimized -inline hyperpoint tC0(const transmatrix &T) { - hyperpoint z; - z[0] = T[0][2]; z[1] = T[1][2]; z[2] = T[2][2]; - return z; - } - // rotate by alpha degrees transmatrix spin(ld alpha) { transmatrix T = Id; @@ -173,6 +166,29 @@ transmatrix eupush(ld x, ld y) { return T; } +transmatrix eupush(hyperpoint h) { + transmatrix T = Id; + T[0][2] = h[0]; + T[1][2] = h[1]; + return T; + } + +transmatrix euscalezoom(hyperpoint h) { + transmatrix T = Id; + T[0][0] = h[0]; + T[0][1] = -h[1]; + T[1][0] = h[1]; + T[1][1] = h[0]; + return T; + } + +transmatrix euaffine(hyperpoint h) { + transmatrix T = Id; + T[1][0] = h[0]; + T[1][2] = h[1]; + return T; + } + // push alpha units to the right transmatrix xpush(ld alpha) { if(euclid) return eupush(alpha, 0); diff --git a/menus.cpp b/menus.cpp index 13f8c128..63f2de8d 100644 --- a/menus.cpp +++ b/menus.cpp @@ -346,7 +346,7 @@ void showDisplayMode() { #endif #if CAP_TEXTURE - dialog::addBoolItem(XLAT("texture mode"), texture_on, 't'); + dialog::addBoolItem(XLAT("texture mode"), texture::tstate == texture::tsActive, 't'); #endif @@ -372,8 +372,8 @@ void showDisplayMode() { if(xuni == 'z') editScale(); - if(xuni == 't') pushScreen(showTextureMenu); - + if(xuni == 't') pushScreen(texture::showMenu); + if(xuni == 'm') { vid.monmode += 60 + (shiftmul > 0 ? 1 : -1); vid.monmode %= 6; } if(xuni == '9') pushScreen(show3D); diff --git a/pattern2.cpp b/pattern2.cpp index 56472b36..01f96b00 100644 --- a/pattern2.cpp +++ b/pattern2.cpp @@ -552,77 +552,79 @@ namespace patterns { else si.symmetries = ctof(c) ? 1 : 2; } - void val_warped(cell *c, patterninfo& si, int sub) { + void val_warped(cell *c, patterninfo& si) { + int u = ishept(c)?1:0; + int qhex = 0; + for(int v=0; vtype; v++) if(c->mov[v] && !isWarped(c->mov[v])) { + u += 2; + if(!ishept(c->mov[v])) qhex++; + } + if(u == 8 && qhex == 2) si.id = 12; + else if(u == 2 && qhex == 1) si.id = 8; + else if(u == 6 && qhex == 2) si.id = 10; + si.id = u; + + if(u == 6) { + for(int i=1; itype; i+=2) if(!isWarped(createMov(c,i))) + si.dir = i; + } + + else if(u == 2 || u == 3 || u == 8) { + for(int i=0; itype; i++) if(!isWarped(createMov(c,i))) + si.dir = i; + } + + else if(u == 4 || u == 10) { + for(int i=0; itype; i+=2) if(!isWarped(createMov(c,i))) + si.dir = i; + if(u == 4) + si.reflect = !isWarped(createMov(c, (si.dir+1)%6)); + } + + else if(u == 6) { + for(int i=1; itype; i+=2) if(!isWarped(createMov(c,i))) + si.dir = i; + } + + else if(u == 5) { + for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+3)%7)) && !isWarped(createMov(c,(i+4)%7))) + si.dir = i; + } + + else if(u == 9) { + for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+2)%7)) && !isWarped(createMov(c,(i+5)%7))) + si.dir = i; + } + + else if(u == 11) { + for(int i=0; itype; i++) if(isWarped(createMov(c,(i)%7)) && isWarped(createMov(c,(i+1)%7))) + si.dir = i; + } + + else if(u == 12) { + for(int i=0; itype; i+=2) if(isWarped(createMov(c,i))) { + si.dir = i; + si.reflect = !isWarped(createMov(c, (i+1)%6)); + } + } + + else if(u == 7) { + for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+1)%7)) && !isWarped(createMov(c,(i+6)%7))) + si.dir = i; + } + } + + void val_nopattern(cell *c, patterninfo& si, int sub) { // use val_all for nicer rotation val_all(c, si, 0, 0); // get id: - if(stdhyperbolic && isWarped(c)) { - int u = ishept(c)?1:0; - int qhex = 0; - for(int v=0; vtype; v++) if(c->mov[v] && !isWarped(c->mov[v])) { - u += 2; - if(!ishept(c->mov[v])) qhex++; - } - if(u == 8 && qhex == 2) si.id = 12; - else if(u == 2 && qhex == 1) si.id = 8; - else if(u == 6 && qhex == 2) si.id = 10; - si.id = u; - - if(u == 6) { - for(int i=1; itype; i+=2) if(!isWarped(createMov(c,i))) - si.dir = i; - } - - else if(u == 2 || u == 3 || u == 8) { - for(int i=0; itype; i++) if(!isWarped(createMov(c,i))) - si.dir = i; - } - - else if(u == 4 || u == 10) { - for(int i=0; itype; i+=2) if(!isWarped(createMov(c,i))) - si.dir = i; - if(u == 4) - si.reflect = !isWarped(createMov(c, (si.dir+1)%6)); - } - - else if(u == 6) { - for(int i=1; itype; i+=2) if(!isWarped(createMov(c,i))) - si.dir = i; - } - - else if(u == 5) { - for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+3)%7)) && !isWarped(createMov(c,(i+4)%7))) - si.dir = i; - } - - else if(u == 9) { - for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+2)%7)) && !isWarped(createMov(c,(i+5)%7))) - si.dir = i; - } - - else if(u == 11) { - for(int i=0; itype; i++) if(isWarped(createMov(c,(i)%7)) && isWarped(createMov(c,(i+1)%7))) - si.dir = i; - } - - else if(u == 12) { - for(int i=0; itype; i+=2) if(isWarped(createMov(c,i))) { - si.dir = i; - si.reflect = !isWarped(createMov(c, (i+1)%6)); - } - } - - else if(u == 7) { - for(int i=0; itype; i++) if(!isWarped(createMov(c,(i+1)%7)) && !isWarped(createMov(c,(i+6)%7))) - si.dir = i; - } - - } + if(stdhyperbolic && isWarped(c)) + val_warped(c, si); else { si.id = ishept(c) ? 1 : 0; if(euclid) { - si.dir = ishex1(c) ? 3 : 0; + si.dir = ishex1(c) ? 0 : 3; if(ctof(c)) si.symmetries = 3; if(subpattern_flags & SPF_EXTRASYM) si.symmetries /= 3; @@ -803,7 +805,7 @@ namespace patterns { } else - val_warped(c, si, sub); + val_nopattern(c, si, sub); return si; } @@ -870,7 +872,7 @@ int pattern_threecolor(cell *c) { } if(S7 == 3 && nontruncated) return c->master->fiftyval; - if(euclid) return eupattern(c); + if(euclid) return (eupattern(c)+1) % 3; return !ishept(c); } @@ -1099,7 +1101,7 @@ namespace patterns { } if((euclid && whichPattern == PAT_COLORING) || - (a38 && nontruncated && whichPattern == PAT_COLORING) || + (a38 && whichPattern == PAT_COLORING) || (S3 == 4 && nontruncated && whichPattern == PAT_COLORING)) dialog::addBoolItem(XLAT("edit all three colors"), subpattern_flags & SPF_ROT, '0'); @@ -1139,16 +1141,20 @@ namespace patterns { keyhandler = [] (int sym, int uni) { dialog::handleNavigation(sym, uni); + printf("uni = %c\n", uni); + if(among(uni, PAT_EMERALD, PAT_PALACE, PAT_ZEBRA, PAT_DOWN, PAT_FIELD, PAT_COLORING, PAT_SIBLING)) { if(whichPattern == uni) whichPattern = 0; else whichPattern = uni; mapeditor::modelcell.clear(); } + else if(printf("not among\n"), 0) ; + else if(uni >= '0' && uni <= '5') subpattern_flags ^= (1 << (uni - '0')); - else if(uni >= '=') + else if(uni == '=') subpattern_flags ^= SPF_EXTRASYM; else if(uni == '6' || uni == '7' || uni == '8') { diff --git a/polygons.cpp b/polygons.cpp index 458588a8..d45e6a64 100644 --- a/polygons.cpp +++ b/polygons.cpp @@ -340,7 +340,7 @@ void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline glStencilOp( GL_INVERT, GL_INVERT, GL_INVERT); glStencilFunc( GL_ALWAYS, 0x1, 0x1 ); glColor4f(1,1,1,1); - glDrawArrays(GL_TRIANGLE_FAN, ps, pq); + glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, ps, pq); if(flags & POLY_INVERSE) { selectEyeMask(ed); @@ -356,7 +356,7 @@ void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline GLfloat *cur = currentvertices; activateVertexArray(scr, 4); if(useV) glPopMatrix(); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, 0, 4); activateVertexArray(cur, 0); draw = false; goto again; } @@ -365,7 +365,7 @@ void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline glcolor2(col); glStencilOp( GL_ZERO, GL_ZERO, GL_ZERO); glStencilFunc( GL_EQUAL, 1, 1); - glDrawArrays(GL_TRIANGLE_FAN, ps, pq); + glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, ps, pq); } glDisable(GL_STENCIL_TEST); @@ -892,7 +892,7 @@ void drawqueue() { hpcshape shFloorSide[SIDEPARS][2], shSemiFloorSide[SIDEPARS], shTriheptaSide[SIDEPARS][2], shMFloorSide[SIDEPARS][2], shFullFloorSide[SIDEPARS][2], - shFullFloor[2], + shFullFloor[2], shFullCross[2], shSeabed[2], shCloudSeabed[3], shCaveSeabed[3], shWave[8][2], shFloor[2], shBFloor[2], shMFloor2[2], shMFloor3[2], shMFloor4[2], @@ -1270,6 +1270,17 @@ void buildpolys() { for(int t=0; t<=S7; t++) hpcpush(ddi(t*S12+td, x) * C0); } + {double x = hexvdist; + bshape(shFullCross[0], PPR_FLOOR); + x *= bscale6; + for(int t=0; t<=S6; t++) { hpcpush(C0); if(t) hpcpush(ddi(S7 + t*S14, x) * C0); } + + x = rhexf; + x *= bscale7; + bshape(shFullCross[1], PPR_FLOOR); + for(int t=0; t<=S7; t++) { hpcpush(C0); if(t) hpcpush(ddi(t*S12+td, x) * C0); } + } + bool strict = false; if(a4 && nontruncated) fac94 *= 1.1; diff --git a/textures.cpp b/textures.cpp index 75ef4559..6cb3607d 100644 --- a/textures.cpp +++ b/textures.cpp @@ -1,6 +1,8 @@ #include -glfont_t textures; +namespace texture { + +GLuint textureid; SDL_Surface *convertSurface(SDL_Surface* s) { SDL_PixelFormat fmt; @@ -29,102 +31,201 @@ SDL_Surface *convertSurface(SDL_Surface* s) { bool texture_read = false; +int twidth = 2048; + vector expanded_data; string texturename; -void sdltogl_bmp(SDL_Surface *txt, glfont_t& f, int ch) { +eTextureState tstate; - int dim = min(txt->w, txt->h); - int otwidth = dim; - int otheight = dim; +template void scale_colorarray(int origdim, const T& src, const U& dest) { + int ox = 0, tx = 0, partials[4]; + int omissing = twidth, tmissing = origdim; + for(int p=0; p<4; p++) partials[p] = 0; - int twidth = next_p2( otwidth ); - int theight = next_p2( otheight ); - - expanded_data.resize(twidth * theight); - - for(int j=0; j w, ty = txt->h; + + SDL_FreeSurface(txt); - for(int ch=1; ch half_expanded(twidth * ty); + expanded_data.resize(twidth * twidth); + + int origdim = max(tx, ty); + int base_x = tx/2 - origdim/2; + int base_y = ty/2 - origdim/2; + ZZ = 0; - sdltogl_bmp(txt2, f, ch); - SDL_FreeSurface(txt); - SDL_FreeSurface(txt2); - } +/* for(int y=0; y= ty ? 0 : half_expanded[x + (base_y + y) * twidth]; }, + [&] (int y, int v) { expanded_data[twidth * y + x] = v; } + ); + + glBindTexture( GL_TEXTURE_2D, textureid); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, twidth, twidth, 0, + GL_BGRA, GL_UNSIGNED_BYTE, + &expanded_data[0] ); + } -ld iscale = 1; -ld irotate = 0; +transmatrix itt = Id; + +int grid_alpha = 0; +int mesh_alpha = 0; +int color_alpha = 0; unsigned int glc = 0xFFFFFFDD; -void mapTextureTriangle(textureinfo &mi, array v) { +int gsplits = 1; - int tabid = 1; - - glfont_t& f(textures); - float fx=f.tx[tabid]; - float fy=f.ty[tabid]; +void mapTextureTriangle(textureinfo &mi, array vview, array vmap, int splits = gsplits) { + if(splits) { + array vview2 = { mid(vview[1], vview[2]), mid(vview[2], vview[0]), mid(vview[0], vview[1]) }; + array vmap2 = { mid(vmap [1], vmap [2]), mid(vmap [2], vmap [0]), mid(vmap [0], vmap [1]) }; + mapTextureTriangle(mi, {vview[0], vview2[1], vview2[2]}, {vmap[0], vmap2[1], vmap2[2]}, splits-1); + mapTextureTriangle(mi, {vview[1], vview2[2], vview2[0]}, {vmap[1], vmap2[2], vmap2[0]}, splits-1); + mapTextureTriangle(mi, {vview[2], vview2[0], vview2[1]}, {vmap[2], vmap2[0], vmap2[1]}, splits-1); + mapTextureTriangle(mi, {vview2[0], vview2[1], vview2[2]}, {vmap2[0], vmap2[1], vmap2[2]}, splits-1); + return; + } + for(int i=0; i<3; i++) { for(int j=0; j<3; j++) - mi.vertices.push_back(v[i][j]); + mi.vertices.push_back(vview[i][j]); hyperpoint inmodel; - applymodel(mi.M * v[i], inmodel); - inmodel = spin(M_PI * irotate / 180) * inmodel; - mi.tvertices.push_back(fx * (iscale * inmodel[0]+1)/2); - mi.tvertices.push_back(fy * (iscale * inmodel[1]+1)/2); + applymodel(mi.M * vmap[i], inmodel); + inmodel = itt * inmodel; + inmodel[0] *= vid.radius * 1. / vid.scrsize; + inmodel[1] *= vid.radius * 1. / vid.scrsize; + mi.tvertices.push_back((inmodel[0]+1)/2); + mi.tvertices.push_back((inmodel[1]+1)/2); mi.tvertices.push_back(0); } } map texture_map; +set models; + +void mapTexture(cell *c, textureinfo& mi, patterns::patterninfo &si, const transmatrix& T) { + mi.c = c; + mi.vertices.clear(); + mi.tvertices.clear(); + mi.symmetries = si.symmetries; + mi.current_type = c->type; + mi.current_geometry = geometry; + mi.current_trunc = nontruncated; + + mi.M = T * applyPatterndir(c, si); + + if(tstate == tsAdjusting) return; + + ld z = ctof(c) ? rhexf : hexvdist; + + int sym = si.symmetries; + + for(int i=0; itype; i++) { + int is = i % sym; + hyperpoint h1 = spin(M_PI + M_PI * (2*i +1) / c->type) * xpush(z) * C0; + hyperpoint h2 = spin(M_PI + M_PI * (2*i -1) / c->type) * xpush(z) * C0; + hyperpoint hm1 = spin(M_PI + M_PI * (2*is+1) / c->type) * xpush(z) * C0; + hyperpoint hm2 = spin(M_PI + M_PI * (2*is-1) / c->type) * xpush(z) * C0; + mapTextureTriangle(mi, {C0, h1, h2}, {C0, hm1, hm2}); + } + } + +int recolor(int col) { + if(color_alpha == 0) return col; + if(color_alpha == 255) return col | 0xFFFFFF00; + for(int i=1; i<4; i++) + part(col, i) = color_alpha + ((255-color_alpha) * part(col,i) + 127) / 255; + return col; + } + +bool apply(cell *c, const transmatrix &V, int col) { + if(tstate == tsOff) return false; -bool applyTextureMap(cell *c, const transmatrix &V, int col) { using namespace patterns; auto si = getpatterninfo0(c); + + if(tstate == tsAdjusting) { + queuepolyat(V, shFullCross[ctof(c)], 0, PPR_LINE); + lastptd().u.poly.outline = models.count(c) ? 0xFFFFFF08 : 0xFF000008; + queuepolyat(V, shFullFloor[ctof(c)], 0, PPR_LINE); + lastptd().u.poly.outline = models.count(c) ? 0xFFFFFF10 : 0xFF000010; + return false; + } try { auto& mi = texture_map.at(si.id); + qfi.spin = applyPatterndir(c, si); int n = mi.vertices.size() / 3; + + if(geometry != mi.current_geometry || nontruncated != mi.current_trunc) { + // we can easily make it more symmetric + mi.symmetries = gcd(mi.symmetries, si.symmetries); + + printf("Redrawing tile #%d from %d to %d\n", si.id, mi.current_type, c->type); + int nbase = n * mi.symmetries / mi.current_type; + int ntarget = nbase * c->type / mi.symmetries; + printf("n = %d nbase = %d ntarget = %d\n", n, nbase, ntarget); + vector new_tvertices = move(mi.tvertices); + new_tvertices.resize(3*ntarget); + for(int i=3*nbase; i<3*ntarget; i++) { + new_tvertices[i] = new_tvertices[i - 3*nbase]; + } + + mapTexture(c, mi, si, Id); + mi.tvertices = move(new_tvertices); + n = mi.vertices.size() / 3; + printf("new n = %d\n", n); + } qfi.special = false; qfi.shape = &shFullFloor[ctof(c)]; @@ -133,74 +234,52 @@ bool applyTextureMap(cell *c, const transmatrix &V, int col) { if(chasmg == 2) return false; else if(chasmg && wmspatial) { if(detaillevel == 0) return false; - queuetable(V * qfi.spin, &mi.vertices[0], n, 0, c->land == laCocytus ? 0x080808FF : 0x101010FF, PPR_LAKEBOTTOM); + queuetable(V * qfi.spin, &mi.vertices[0], n, mesh_alpha, recolor(c->land == laCocytus ? 0x080808FF : 0x101010FF), PPR_LAKEBOTTOM); } else { - queuetable(V * qfi.spin, &mi.vertices[0], n, 0, col, PPR_FLOOR); + queuetable(V * qfi.spin, &mi.vertices[0], n, mesh_alpha, recolor(col), PPR_FLOOR); } lastptd().u.poly.tinf = &mi; + if(grid_alpha) { + queuepolyat(V, shFullFloor[ctof(c)], 0, PPR_FLOOR); + lastptd().u.poly.outline = grid_alpha; + } return true; } catch(out_of_range) { + // printf("Ignoring tile #%d : not mapped\n", si.id); return false; } } void perform_mapping() { + if(gsplits < 0) gsplits = 0; + if(gsplits > 4) gsplits = 4; using namespace patterns; if(!texture_read) readtexture(); texture_map.clear(); - glfont_t& f(textures); int tabid = 1; for(auto p: gmatrix) { cell *c = p.first; auto si = getpatterninfo0(c); bool replace = false; - int sgn = sphere ? -1 : 1; + // int sgn = sphere ? -1 : 1; if(!texture_map.count(si.id)) replace = true; - else if(sgn * p.second[2][2] < sgn * texture_map[si.id].M[2][2]) + else if(hdist0(p.second*C0) < hdist0(texture_map[si.id].M * C0)) replace = true; if(replace) { auto& mi = texture_map[si.id]; - mi.M = p.second; - mi.vertices.clear(); - mi.tvertices.clear(); - - mi.M = mi.M * applyPatterndir(c, si); - - ld z = ctof(c) ? rhexf : hexvdist; - ld base = ctof(c) ? 0 : 0; // -hexshift; - if(!ctof(c) || nontruncated) base -= M_PI / c->type; - - for(int i=0; itype; i++) { - hyperpoint h1 = spin(base + M_PI * (2*i) / c->type) * xpush(z) * C0; - hyperpoint h2 = spin(base + M_PI * (2*i+2) / c->type) * xpush(z) * C0; - mapTextureTriangle(mi, {C0, h1, h2}); - } - - mi.texture_id = f.textures[tabid]; - } + mapTexture(c, mi, si, p.second); + mi.texture_id = textureid; + } } - } - -bool forge_handleKey(int sym, int uni) { - - if(sym == SDLK_F4) { - glc += 0x11; - return true; - } - - if(sym == SDLK_F5) { - glc -= 0x11; - return true; - } - - return false; + models.clear(); + for(auto& t: texture_map) models.insert(t.second.c); } int forgeArgs() { @@ -211,55 +290,206 @@ int forgeArgs() { shift(); texturename = args(); } + else if(argis("-fsp")) { + shift(); gsplits = argf(); + } + else return 1; return 0; } +bool newmove = false; + auto texture_hook = - addHook(hooks_args, 100, forgeArgs) -+ addHook(hooks_handleKey, 100, forge_handleKey); + addHook(hooks_args, 100, forgeArgs); -bool texture_on = false; +void drawRawTexture() { + if(!texture_read) readtexture(); + glDisable(GL_LIGHTING); + glEnable(GL_TEXTURE_2D); + glMatrixMode(GL_MODELVIEW); + glcolor2(0xFFFFFF20); + glPushMatrix(); + glTranslatef(0, 0, vid.scrdist); + glBindTexture(GL_TEXTURE_2D, textureid); + vector tver, sver; + for(int i=0; i<4; i++) { + int cx[4] = {1, -1, -1, 1}; + int cy[4] = {1, 1, -1, -1}; + int x = cx[i]; + int y = cy[i]; + hyperpoint inmodel = hpxyz(x, y, 1); + inmodel = itt * inmodel; + tver.push_back((inmodel[0]+1)/2); + tver.push_back((inmodel[1]+1)/2); + tver.push_back(0); + sver.push_back(x * vid.scrsize); + sver.push_back(y * vid.scrsize); + sver.push_back(0); + } + activateVertexArray(&sver[0], 4); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(3, GL_FLOAT, 0, &tver[0]); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glPopMatrix(); + glDisable(GL_TEXTURE_2D); + } -void showTextureMenu() { - cmode = sm::SIDE | sm::MAYDARK; +enum eTexturePanstate {tpsModel, tpsMove, tpsScale, tpsAffine, tpsZoom, tpsProjection}; +eTexturePanstate panstate; + +void showMenu() { + cmode = sm::SIDE | sm::MAYDARK | sm::DIALOG_STRICT_X; gamescreen(0); + if(tstate == tsAdjusting) + drawRawTexture(); + dialog::init(XLAT("texture mode")); dialog::addSelItem(XLAT("select the texture's pattern"), XLAT("..."), 'r'); dialog::addSelItem(XLAT("texture file"), texturename, 'f'); - dialog::addBoolItem(XLAT("texture mode enabled"), texture_on, 'm'); + dialog::addSelItem(XLAT("texture mode enabled"), its(tstate), 't'); + + if(tstate == tsAdjusting) { + dialog::addBoolItem(XLAT("move the model"), panstate == tpsModel, 'm'); + dialog::addBoolItem(XLAT("move the texture"), panstate == tpsMove, 'a'); + dialog::addBoolItem(XLAT("zoom/scale the texture"), panstate == tpsScale, 'x'); + dialog::addBoolItem(XLAT("zoom/scale the model"), panstate == tpsZoom, 'z'); + dialog::addBoolItem(XLAT("projection"), panstate == tpsProjection, 'p'); + dialog::addBoolItem(XLAT("affine transformations"), panstate == tpsAffine, 'y'); + } - if(texture_on) { - dialog::addSelItem(XLAT("texture scale"), fts(iscale), 's'); - dialog::addSelItem(XLAT("texture rotation"), fts(irotate), 'p'); + if(tstate == tsActive) { + /* dialog::addSelItem(XLAT("texture scale"), fts(iscale), 's'); + dialog::addSelItem(XLAT("texture angle"), fts(irotate), 'a'); + dialog::addSelItem(XLAT("texture position X"), fts(ix), 'x'); + dialog::addSelItem(XLAT("texture position Y"), fts(iy), 'y'); */ + dialog::addSelItem(XLAT("grid alpha"), its(grid_alpha), 'g'); + dialog::addSelItem(XLAT("mesh alpha"), its(mesh_alpha), 'm'); + dialog::addSelItem(XLAT("precision"), its(gsplits), 'p'); + dialog::addSelItem(XLAT("color alpha"), its(color_alpha), 'c'); } dialog::addItem(XLAT("help"), SDLK_F1); dialog::addItem(XLAT("back"), '0'); + getcstat = '-'; + dialog::display(); + if(holdmouse) { + static hyperpoint lastmouse; + + hyperpoint mouseeu = hpxyz((mousex - vid.xcenter + .0) / vid.scrsize, (mousey - vid.ycenter + .0) / vid.scrsize, 1); + bool nonzero = mouseeu[0] || mouseeu[1]; + + switch(panstate) { + case tpsModel: + if(!newmove && mouseh[2] < 50 && lastmouse[2] < 50) { + panning(lastmouse, mouseh); + perform_mapping(); + } + lastmouse = mouseh; newmove = false; + break; + + case tpsMove: { + if(!newmove) + itt = itt * inverse(eupush(mouseeu)) * eupush(lastmouse); + lastmouse = mouseeu; newmove = false; + break; + } + + case tpsScale: { + if(nonzero && !newmove) + itt = itt * inverse(euscalezoom(mouseeu)) * euscalezoom(lastmouse); + if(nonzero) lastmouse = mouseeu; + newmove = false; + break; + } + + case tpsAffine: { + if(!newmove) + itt = itt * inverse(euaffine(mouseeu)) * euaffine(lastmouse); + lastmouse = mouseeu; newmove = false; + break; + } + + case tpsZoom: { + // do not zoom in portrait! + if(nonzero && !newmove) { + View = View * inverse(spintox(mouseeu)) * spintox(lastmouse); + vid.scale = vid.scale * sqrt(intvalxy(C0, mouseeu)) / sqrt(intvalxy(C0, lastmouse)); + } + if(nonzero) lastmouse = mouseeu; + newmove = false; + break; + } + + case tpsProjection: { + if(nonzero && !newmove) { + vid.alpha = vid.alpha * sqrt(intvalxy(C0, mouseeu)) / sqrt(intvalxy(C0, lastmouse)); + } + if(nonzero) lastmouse = mouseeu; + newmove = false; + } + + default: break; + } + } + keyhandler = [] (int sym, int uni) { + // handlePanning(sym, uni); dialog::handleNavigation(sym, uni); - if(uni == 'r') + + if(uni == '-' && tstate == tsAdjusting) { + if(!holdmouse) { + holdmouse = true; + newmove = true; + } + } + + else if(uni == 'm' && tstate == tsAdjusting) panstate = tpsModel; + else if(uni == 'a' && tstate == tsAdjusting) panstate = tpsMove; + else if(uni == 'x' && tstate == tsAdjusting) panstate = tpsScale; + else if(uni == 'y' && tstate == tsAdjusting) panstate = tpsAffine; + else if(uni == 'z' && tstate == tsAdjusting) panstate = tpsZoom; + else if(uni == 'p' && tstate == tsAdjusting) panstate = tpsProjection; + + else if(uni == 'r') pushScreen(patterns::showPattern); else if(uni == 'f') dialog::openFileDialog(texturename, XLAT("texture to load:"), ".png"); - else if(uni == 'm') { - texture_on = !texture_on; - if(texture_on) perform_mapping(); - else texture_map.clear(); + else if(uni == 't') { + if(tstate == tsOff) { + tstate = tsAdjusting; + perform_mapping(); + } + else if(tstate == tsAdjusting) { + tstate = tsActive; + perform_mapping(); + } + else { + tstate = tsOff; + texture_map.clear(); + } } - else if(uni == 's') { - dialog::editNumber(iscale, 0, 2, .01, 1, XLAT("texture scale"), - XLAT("Texture scale.")); - dialog::reaction = perform_mapping; + else if(uni == 'g') { + dialog::editNumber(grid_alpha, 0, 255, 15, 0, XLAT("grid alpha"), + XLAT("Grid alpha.")); + } + else if(uni == 'm') { + dialog::editNumber(mesh_alpha, 0, 255, 15, 0, XLAT("mesh alpha"), + XLAT("Mesh alpha.")); + } + else if(uni == 'c') { + dialog::editNumber(color_alpha, 0, 255, 15, 0, XLAT("color alpha"), + XLAT("The higher the value, the less important the color of underlying terrain is.")); } else if(uni == 'p') { - dialog::editNumber(irotate, -360, 360, 15, 0, XLAT("texture rotation"), - XLAT("Texture rotation.")); + dialog::editNumber(gsplits, 0, 4, 1, 1, XLAT("precision"), + XLAT("precision")); dialog::reaction = perform_mapping; } else if(doexiton(sym, uni)) @@ -267,3 +497,7 @@ void showTextureMenu() { }; } +} +// - dual grid +// todo save/load texture configuration +// todo texture editor