From ecf631976f23b53056c2328bfe1ece8615345fa9 Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Sat, 9 Dec 2017 02:20:10 +0100 Subject: [PATCH] texture mode -- first commit --- compileunits.h | 1 + graph.cpp | 36 ++----- hyper.h | 13 ++- init.cpp | 4 + menus.cpp | 7 ++ pattern2.cpp | 2 +- polygons.cpp | 48 +++++++-- textures.cpp | 280 +++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 357 insertions(+), 34 deletions(-) create mode 100644 textures.cpp diff --git a/compileunits.h b/compileunits.h index 4adfa012..bbd96359 100644 --- a/compileunits.h +++ b/compileunits.h @@ -71,6 +71,7 @@ bool inv::on; #include "control.cpp" #include "hud.cpp" #include "hypgraph.cpp" +#include "textures.cpp" #include "graph.cpp" #include "sound.cpp" #include "achievement.cpp" diff --git a/graph.cpp b/graph.cpp index 6f7e29b7..d799a020 100644 --- a/graph.cpp +++ b/graph.cpp @@ -2896,28 +2896,6 @@ void plainfloor(cell *c, bool warp, const transmatrix &V, int col, int prio) { } } -void fullplainfloor(cell *c, bool warp, const transmatrix &V, int col, int prio) { - if(warp) { - if(euclid) { - if(ishex1(c)) - queuepolyat(V * pispin, shTriheptaFloor[0], col, prio); - else - queuepolyat(V, shTriheptaFloor[ctof(c)], col, prio); - } - else - queuepolyat(V * applyPatterndir(c), shTriheptaFloor[sphere ? ctof(c) : mapeditor::nopattern(c)], col, prio); - } - else if(c->land == laDual && !nontruncated) { - if(euclid && ishex1(c)) - queuepolyat(V * pispin, shBigTriangle, col, prio); - else - queuepolyat(V, shBigTriangle, col, prio); - } - else { - queuepolyat(V, shFullFloor[ctof(c)], col, prio); - } - } - void qfloor_eswap(cell *c, const transmatrix& V, const hpcshape& sh, int col); void qplainfloor(cell *c, bool warp, const transmatrix &V, int col) { @@ -2942,7 +2920,11 @@ int wavephase; void warpfloor(cell *c, const transmatrix& V, int col, int prio, bool warp) { if(shmup::on || nontruncated) warp = false; - if(wmescher && qfi.special) + if(qfi.tinf) { + queuetable(V*qfi.spin, &qfi.tinf->vertices[0], size(qfi.tinf->vertices) / 3, 0, col, prio); + lastptd().u.poly.tinf = qfi.tinf; + } + else if(wmescher && qfi.special) queuepolyat(V*qfi.spin, *qfi.shape, col, prio); else plainfloor(c, warp, V, col, prio); } @@ -3013,7 +2995,7 @@ void placeSidewall(cell *c, int i, int sidepar, const transmatrix& V, bool warp, // prio += c->cpdist - c->mov[i]->cpdist; queuepolyat(V2, - (mirr?shMFloorSide:warp?shTriheptaSide:(c->land == laDual&&!nontruncated)?shBigTriSide:shFloorSide)[sidepar][ctof(c)], col, prio); + (qfi.tinf?shFullFloorSide:mirr?shMFloorSide:warp?shTriheptaSide:(c->land == laDual&&!nontruncated)?shBigTriSide:shFloorSide)[sidepar][ctof(c)], col, prio); } bool openorsafe(cell *c) { @@ -3143,7 +3125,7 @@ void qfloor_eswap(cell *c, const transmatrix& V, const hpcshape& sh, int col) { else qfloor(c, V, sh, col); }; - + // how much to darken int getfd(cell *c) { switch(c->land) { @@ -3515,7 +3497,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { } poly_outline = OUTLINE_DEFAULT; - + if(!wmascii) { // floor @@ -3558,6 +3540,8 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { shBigTriangle, darkena(fcol, fd, 0xFF)); } #endif + + else if(applyTextureMap(c, Vf, darkena(fcol, fd, 0xFF))) ; else if(c->land == laMirrorWall) { int d = mirror::mirrordir(c); diff --git a/hyper.h b/hyper.h index 7e699f5b..7b5c30db 100644 --- a/hyper.h +++ b/hyper.h @@ -1902,6 +1902,13 @@ void drawqueue(); typedef float GLfloat; #endif +struct textureinfo { + transmatrix M; + int texture_id; + vector vertices; + vector tvertices; + }; + struct qpoly { transmatrix V; GLfloat *tab; @@ -1910,6 +1917,7 @@ struct qpoly { int outline; double minwidth; int flags; + textureinfo *tinf; }; struct qline { @@ -1930,7 +1938,7 @@ struct qcir { int x, y, size; }; -enum eKind { pkPoly, pkLine, pkString, pkCircle, pkShape, pkResetModel }; +enum eKind { pkPoly, pkLine, pkString, pkCircle, pkShape, pkResetModel, pkSpecial }; struct polytodraw { eKind kind; @@ -2300,3 +2308,6 @@ int inpair(cell *c, int colorpair); int snake_pair(cell *c); extern const unsigned int nestcolors[8]; + +extern bool texture_on; +void showTextureMenu(); diff --git a/init.cpp b/init.cpp index c50256bc..f1870421 100644 --- a/init.cpp +++ b/init.cpp @@ -120,6 +120,10 @@ #define CAP_EDIT (CAP_FILES && !ISWEB && !ISMINI) #endif +#ifndef CAP_TEXTURE +#define CAP_TEXTURE CAP_PNG +#endif + #ifndef CAP_MODEL #define CAP_MODEL (!ISMOBWEB && !ISMINI && CAP_SDLGFX) #endif diff --git a/menus.cpp b/menus.cpp index a3f0dc76..c7da477e 100644 --- a/menus.cpp +++ b/menus.cpp @@ -345,6 +345,11 @@ void showDisplayMode() { dialog::addBoolItem(XLAT("vector graphics editor"), (false), 'g'); #endif +#if CAP_TEXTURE + dialog::addBoolItem(XLAT("texture mode"), texture_on, 't'); +#endif + + // display modes #if CAP_RUG dialog::addBoolItem(XLAT("hypersian rug mode"), (rug::rugged), 'u'); @@ -367,6 +372,8 @@ void showDisplayMode() { if(xuni == 'z') editScale(); + if(xuni == 't') pushScreen(showTextureMenu); + 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 ec5a7e7b..8614e1e0 100644 --- a/pattern2.cpp +++ b/pattern2.cpp @@ -677,7 +677,7 @@ int pattern_threecolor(cell *c) { if(S7 == 3 && nontruncated) return c->master->fiftyval; if(euclid) return eupattern(c); - return ishept(c); + return !ishept(c); } // returns ishept in the normal tiling; diff --git a/polygons.cpp b/polygons.cpp index 228980ca..94910f13 100644 --- a/polygons.cpp +++ b/polygons.cpp @@ -43,7 +43,6 @@ struct hpcshape { int flags; }; - hpcshape *last = NULL; vector ptds; @@ -288,7 +287,15 @@ void glapplymatrix(const transmatrix& V) { glMultMatrixf(mat); } -void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline, int flags) { +void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline, int flags, textureinfo *tinf) { + + if(tinf) { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tinf->texture_id); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(3, GL_FLOAT, 0, &tinf->tvertices[0]); + } + for(int ed = vid.goteyes ? -1 : 0; ed<2; ed+=2) { if(ed) selectEyeGL(ed); bool draw = col; @@ -371,6 +378,12 @@ void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline if(useV) glPopMatrix(); } + + if(tinf) { + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisable(GL_TEXTURE_2D); + } + } #endif @@ -491,8 +504,8 @@ void drawpolyline(polytodraw& p) { if(currentvertices != pp.tab) activateVertexArray(pp.tab, pq); const int ps=0; - glLineWidth(linewidthat(tC0(pp.V), pp.minwidth)); - gldraw(1, pp.V, ps, pq, p.col, pp.outline, 0); + glLineWidth(linewidthat(tC0(pp.V), pp.minwidth)); + gldraw(1, pp.V, ps, pq, p.col, pp.outline, 0, pp.tinf); return; } #endif @@ -570,7 +583,7 @@ void drawpolyline(polytodraw& p) { if(vid.usingGL) { // if(pmodel == 0) for(int i=0; i curvedata; int curvestart = 0; bool keep_curvedata = false; +hookset *hooks_specialdraw; + void drawqueueitem(polytodraw& ptd) { #if CAP_ROGUEVIZ svg::info = ptd.info; @@ -669,6 +685,10 @@ void drawqueueitem(polytodraw& ptd) { // if(ptd.prio == 46) printf("eye size %d\n", polyi); + if(ptd.kind == pkSpecial) { + callhooks(hooks_specialdraw, ptd); + } + if(ptd.kind == pkResetModel) { pmodel = eModel(ptd.col); return; @@ -748,7 +768,10 @@ ld xintval(const hyperpoint& h) { ld backbrightness = .25; +purehookset hook_drawqueue; + void drawqueue() { + callhooks(hook_drawqueue); int siz = size(ptds); @@ -868,7 +891,7 @@ void drawqueue() { } hpcshape - shFloorSide[SIDEPARS][2], shSemiFloorSide[SIDEPARS], shTriheptaSide[SIDEPARS][2], shMFloorSide[SIDEPARS][2], + shFloorSide[SIDEPARS][2], shSemiFloorSide[SIDEPARS], shTriheptaSide[SIDEPARS][2], shMFloorSide[SIDEPARS][2], shFullFloorSide[SIDEPARS][2], shFullFloor[2], shSeabed[2], shCloudSeabed[3], shCaveSeabed[3], shWave[8][2], @@ -1296,6 +1319,14 @@ void buildpolys() { for(int t=0; t<=1; t++) hpcpush(ddi(t*S12-S6, floorrad1) * C0); chasmifyPoly(dlow, dhi, k); + bshape(shFullFloorSide[k][0], PPR_LAKEWALL); + for(int t=0; t<=1; t++) hpcpush(ddi(t*S14-S7, hexvdist) * C0); + chasmifyPoly(dlow, dhi, k); + + bshape(shFullFloorSide[k][1], PPR_LAKEWALL); + for(int t=0; t<=1; t++) hpcpush(ddi(t*S12-S6, rhexf) * C0); + chasmifyPoly(dlow, dhi, k); + bshape(shSemiFloorSide[k], PPR_LAKEWALL); for(int t=0; t<=3; t+=3) hpcpush(ddi(S7 + (3+t)*S14, floorrad0) * C0); chasmifyPoly(dlow, dhi, k); @@ -2176,6 +2207,7 @@ void queuepolyat(const transmatrix& V, const hpcshape& h, int col, int prio) { ptd.u.poly.outline = poly_outline; ptd.u.poly.minwidth = minwidth_global; ptd.u.poly.flags = h.flags; + ptd.u.poly.tinf = NULL; } void addfloats(vector& v, hyperpoint h) { @@ -2201,6 +2233,7 @@ void queuetable(const transmatrix& V, GLfloat *f, int cnt, int linecol, int fill ptd.u.poly.outline = linecol; ptd.u.poly.minwidth = minwidth_global; ptd.u.poly.flags = 0; + ptd.u.poly.tinf = NULL; } void queuepoly(const transmatrix& V, const hpcshape& h, int col) { @@ -2215,6 +2248,7 @@ struct qfloorinfo { bool special; transmatrix spin; const hpcshape *shape; + textureinfo *tinf; }; qfloorinfo qfi; @@ -2259,12 +2293,14 @@ void qfloor(cell *c, const transmatrix& V, const hpcshape& h, int col) { qfloor0(c, V, h, col); qfi.special = isSpecial(h); qfi.shape = &h, qfi.spin = Id; + qfi.tinf = NULL; } void qfloor(cell *c, const transmatrix& V, const transmatrix& Vspin, const hpcshape& h, int col) { qfloor0(c, V*Vspin, h, col); qfi.special = isSpecial(h); qfi.shape = &h, qfi.spin = Vspin; + qfi.tinf = NULL; } void curvepoint(const hyperpoint& H1) { diff --git a/textures.cpp b/textures.cpp new file mode 100644 index 00000000..9fd46fd8 --- /dev/null +++ b/textures.cpp @@ -0,0 +1,280 @@ +#include + +glfont_t textures; + +SDL_Surface *convertSurface(SDL_Surface* s) { + SDL_PixelFormat fmt; + // fmt.format = SDL_PIXELFORMAT_BGRA8888; + fmt.BitsPerPixel = 32; + fmt.BytesPerPixel = 4; + + fmt.Ashift=24; + fmt.Rshift=16; + fmt.Gshift=8; + fmt.Bshift=0; + fmt.Amask=0xff<<24; + fmt.Rmask=0xff<<16; + fmt.Gmask=0xff<<8; + fmt.Bmask=0xff; + fmt.Aloss = fmt.Rloss = fmt.Gloss = fmt.Bloss = 0; + fmt.palette = NULL; + +#ifndef SDL2 + fmt.alpha = 0; + fmt.colorkey = 0x1ffffff; +#endif + + return SDL_ConvertSurface(s, &fmt, SDL_SWSURFACE); + } + +bool texture_read = false; + +vector expanded_data; + +string texturename; + +void sdltogl_bmp(SDL_Surface *txt, glfont_t& f, int ch) { + + int dim = min(txt->w, txt->h); + int otwidth = dim; + int otheight = dim; + + int twidth = next_p2( otwidth ); + int theight = next_p2( otheight ); + + expanded_data.resize(twidth * theight); + + for(int j=0; j v) { + + int tabid = 1; + + glfont_t& f(textures); + float fx=f.tx[tabid]; + float fy=f.ty[tabid]; + + for(int i=0; i<3; i++) { + for(int j=0; j<3; j++) + mi.vertices.push_back(v[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); + mi.tvertices.push_back(0); + } + } + +map texture_map; + +bool applyTextureMap(cell *c, const transmatrix &V, int col) { + using namespace mapeditor; + int t = subpattern(c, whichPattern); + try { + auto& mi = texture_map.at(t); + qfi.spin = Id; + + int d = patterndir(c, whichPattern); + qfi.spin = qfi.spin * spin(-M_PI * 2 * d / c->type); + if(reflectPatternAt(c)) + qfi.spin = qfi.spin * Mirror; + + int n = mi.vertices.size() / 3; + + qfi.special = false; + qfi.shape = &shFullFloor[ctof(c)]; + qfi.tinf = &mi; + + 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); + } + else { + queuetable(V * qfi.spin, &mi.vertices[0], n, 0, col, PPR_FLOOR); + } + + lastptd().u.poly.tinf = &mi; + + return true; + } + catch(out_of_range) { + return false; + } + } + +void perform_mapping() { + using namespace mapeditor; + if(!texture_read) readtexture(); + texture_map.clear(); + glfont_t& f(textures); int tabid = 1; + for(auto p: gmatrix) { + cell *c = p.first; + int t = subpattern(c, whichPattern); + bool replace = false; + + if(!texture_map.count(t)) + replace = true; + else if(p.second[2][2] < texture_map[t].M[2][2]) + replace = true; + + if(replace) { + auto& mi = texture_map[t]; + mi.M = p.second; + mi.vertices.clear(); + mi.tvertices.clear(); + + int d = patterndir(c, whichPattern); + if(d) + mi.M = mi.M * spin(-M_PI * 2 * d / c->type); + if(reflectPatternAt(c, whichPattern)) + mi.M = mi.M * Mirror; + + ld z = ctof(c) ? rhexf : hexvdist; + ld base = ctof(c) ? 0 : 0; // -hexshift; + if(!ctof(c)) 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]; + } + } + } + +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; + } + +int forgeArgs() { + using namespace arg; + + if(0) ; + else if(argis("-forge")) { + shift(); texturename = args(); + } + + else return 1; + return 0; + } + +auto texture_hook = + addHook(hooks_args, 100, forgeArgs) ++ addHook(hooks_handleKey, 100, forge_handleKey); + +bool texture_on = false; + +void showTextureMenu() { + cmode = sm::SIDE | sm::MAYDARK; + gamescreen(0); + + 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'); + + if(texture_on) { + dialog::addSelItem(XLAT("texture scale"), fts(iscale), 's'); + dialog::addSelItem(XLAT("texture rotation"), fts(irotate), 'p'); + } + + dialog::addItem(XLAT("help"), SDLK_F1); + dialog::addItem(XLAT("back"), '0'); + + dialog::display(); + + keyhandler = [] (int sym, int uni) { + dialog::handleNavigation(sym, uni); + if(uni == 'r') + pushScreen(mapeditor::showPattern); + else if(uni == 'f') { + mapeditor::cfileptr = &texturename; + mapeditor::filecaption = XLAT("texture to load:"); + mapeditor::cfileext = ".png"; + pushScreen(mapeditor::drawFileDialog); + } + else if(uni == 'm') { + texture_on = !texture_on; + if(texture_on) perform_mapping(); + else 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 == 'p') { + dialog::editNumber(irotate, -360, 360, 0, 60, XLAT("texture rotation"), + XLAT("Texture rotation.")); + dialog::reaction = perform_mapping; + } + else if(doexiton(sym, uni)) + popScreen(); + }; + } +