diff --git a/Aquaria/DSQ.cpp b/Aquaria/DSQ.cpp index 444db02..dab9dde 100644 --- a/Aquaria/DSQ.cpp +++ b/Aquaria/DSQ.cpp @@ -3512,10 +3512,9 @@ bool DSQ::loadTileset(std::string pack, const unsigned char *usedIdx, size_t use const float cell = 64.0f/512.0f; for (int i = 0; i < 27; i++) { - ElementTemplate t; - t.idx = 1024+i; - t.tex = aqtex; - t.loaded = true; + ElementTemplate *et = new ElementTemplate; + et->idx = 1024+i; + et->tex = aqtex; int x = i,y=0; while (x >= 6) { @@ -3523,19 +3522,20 @@ bool DSQ::loadTileset(std::string pack, const unsigned char *usedIdx, size_t use y++; } - t.tu1 = x*cell; - t.tv1 = y*cell; - t.tu2 = t.tu1 + cell; - t.tv2 = t.tv1 + cell; + et->tu1 = x*cell; + et->tv1 = y*cell; + et->tu2 = et->tu1 + cell; + et->tv2 = et->tv1 + cell; - t.tv2 = 1 - t.tv2; - t.tv1 = 1 - t.tv1; - std::swap(t.tv1,t.tv2); + et->tv2 = 1 - et->tv2; + et->tv1 = 1 - et->tv1; + std::swap(et->tv1,et->tv2); - t.w = 512*cell; - t.h = 512*cell; + et->w = 512*cell; + et->h = 512*cell; - tilemgr.tileset.elementTemplates.push_back(t); + et->finalize(); + tilemgr.tileset.elementTemplates.push_back(et); } } diff --git a/Aquaria/SceneEditor.cpp b/Aquaria/SceneEditor.cpp index 6d5726c..527b936 100644 --- a/Aquaria/SceneEditor.cpp +++ b/Aquaria/SceneEditor.cpp @@ -703,7 +703,7 @@ void SceneEditor::init() if (curElement < dsq->tilemgr.tileset.elementTemplates.size()) { - placer->setTexture(dsq->tilemgr.tileset.elementTemplates[curElement].gfx); + placer->setTexture(dsq->tilemgr.tileset.elementTemplates[curElement]->gfx); placer->scale = Vector(1,1); } else @@ -888,7 +888,7 @@ void SceneEditor::editModeElements() editType = ET_ELEMENTS; if (curElement < dsq->tilemgr.tileset.elementTemplates.size()) { - placer->setTexture(dsq->tilemgr.tileset.elementTemplates[curElement].gfx); + placer->setTexture(dsq->tilemgr.tileset.elementTemplates[curElement]->gfx); placer->scale = Vector(1,1); } placer->alpha = 0.5; @@ -2002,7 +2002,6 @@ void SceneEditor::cycleSelectedTiles(int direction) const int maxn = (int)dsq->tilemgr.tileset.elementTemplates.size(); if(!maxn) return; - const ElementTemplate * const base = &dsq->tilemgr.tileset.elementTemplates[0]; for(size_t i = 0; i < n; ++i) { TileData& t = ts.tiles[selectedTiles[i]]; @@ -2093,9 +2092,9 @@ void SceneEditor::cyclePlacer(int direction) if(nextidx >= maxn) nextidx -= maxn; - if (maxn && dsq->tilemgr.tileset.elementTemplates[curElement].idx < 1024) + if (maxn && dsq->tilemgr.tileset.elementTemplates[curElement]->idx < 1024) { - placer->setTexture(dsq->tilemgr.tileset.elementTemplates[curElement].gfx); + placer->setTexture(dsq->tilemgr.tileset.elementTemplates[curElement]->gfx); curElement = nextidx; } } @@ -2108,7 +2107,7 @@ void SceneEditor::selectZero() { if (dsq->tilemgr.tileset.elementTemplates.empty()) return; curElement = 0; - placer->setTexture(dsq->tilemgr.tileset.elementTemplates[curElement].gfx); + placer->setTexture(dsq->tilemgr.tileset.elementTemplates[curElement]->gfx); } } @@ -2122,14 +2121,14 @@ void SceneEditor::selectEnd() size_t largest = 0; for (size_t i = 0; i < dsq->tilemgr.tileset.elementTemplates.size(); i++) { - ElementTemplate et = dsq->tilemgr.tileset.elementTemplates[i]; - if (et.idx < 1024 && i > largest) + ElementTemplate *et = dsq->tilemgr.tileset.elementTemplates[i]; + if (et->idx < 1024 && i > largest) { largest = i; } } curElement = largest; - placer->setTexture(dsq->tilemgr.tileset.elementTemplates[curElement].gfx); + placer->setTexture(dsq->tilemgr.tileset.elementTemplates[curElement]->gfx); } } @@ -2139,7 +2138,7 @@ void SceneEditor::placeElement() { if (!core->getShiftState() && !core->getKeyState(KEY_LALT)) { - unsigned tilesetID = dsq->tilemgr.tileset.elementTemplates[curElement].idx; + unsigned tilesetID = dsq->tilemgr.tileset.elementTemplates[curElement]->idx; dsq->tilemgr.createOneTile(tilesetID, bgLayer, placer->position.x, placer->position.y); // FIXME: need to update grid or no? updateText(); diff --git a/Aquaria/TileMgr.cpp b/Aquaria/TileMgr.cpp index c37afa1..2206138 100644 --- a/Aquaria/TileMgr.cpp +++ b/Aquaria/TileMgr.cpp @@ -187,8 +187,8 @@ TileData* TileMgr::_createTile(unsigned tilesetID, unsigned layer, float x, flo t.texscaleY = 1; t.scalex = 1; t.scaley = 1; - t.beforeScaleOffsetX = 0; - t.beforeScaleOffsetY = 0; + //t.beforeScaleOffsetX = 0; + //t.beforeScaleOffsetY = 0; t.flags = GetTileFlags(ef); t.tag = 0; t.et = tileset.getByIdx(tilesetID); diff --git a/BBGE/OpenGLStubs.h b/BBGE/OpenGLStubs.h index cd17466..91d838a 100644 --- a/BBGE/OpenGLStubs.h +++ b/BBGE/OpenGLStubs.h @@ -70,6 +70,7 @@ GL_FUNC(void,glCallList,(GLuint list),(list),) GL_FUNC(void,glClearDepth,(GLclampd x),(x),) GL_FUNC(void,glColor3f,(GLfloat r,GLfloat g,GLfloat b),(r,g,b),) GL_FUNC(void,glDeleteLists,(GLuint list, GLsizei range),(list,range),) +GL_FUNC(void,glDrawArrays,(GLenum mode, GLint first, GLsizei count), (mode,first,count),) GL_FUNC(void,glDrawPixels,(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels),(width,height,format,type,pixels),) GL_FUNC(GLuint,glGenLists,(GLsizei range),(range),return) GL_FUNC(void,glNewList,(GLuint list, GLenum mode),(list,mode),) diff --git a/BBGE/Tile.h b/BBGE/Tile.h index 1dbe01d..d3997af 100644 --- a/BBGE/Tile.h +++ b/BBGE/Tile.h @@ -134,7 +134,7 @@ private: struct TileData { float x, y, scalex, scaley, texscaleX, texscaleY; - float beforeScaleOffsetX, beforeScaleOffsetY; // almost always 0. // TODO: this is nasty, ideally get rid of this + //float beforeScaleOffsetX, beforeScaleOffsetY; // almost always 0. // TODO: this is nasty, ideally get rid of this float rotation; unsigned flags; // TileFlags unsigned tag; // FIXME: make this int diff --git a/BBGE/TileRender.cpp b/BBGE/TileRender.cpp index f2f62ce..63f5859 100644 --- a/BBGE/TileRender.cpp +++ b/BBGE/TileRender.cpp @@ -41,9 +41,26 @@ static inline const Vector& getTagColor(int tag) } +static const float s_quadVerts[] = +{ + -0.5f, +0.5f, + +0.5f, +0.5f, + +0.5f, -0.5f, + -0.5f, -0.5f, +}; void TileRender::onRender(const RenderState& rs) const { + if(storage.tiles.empty()) + return; + + glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, s_quadVerts); + + RenderState rx(rs); + // prepare. get parallax scroll factors const RenderObjectLayer& rl = core->renderObjectLayers[this->layer]; const Vector M = rl.followCameraMult; // affected by parallaxLock @@ -58,8 +75,10 @@ void TileRender::onRender(const RenderState& rs) const unsigned lastTexRepeat = false; unsigned lastTexId = 0; - const bool renderBorders = this->renderBorders; - //bool mustSetColor = false; + const bool renderExtras = renderBorders || RenderObject::renderCollisionShape; + const TileEffectData *prevEff = ((TileEffectData*)NULL)+1; // initial value is different from anything else + const RenderGrid *grid = NULL; + const float *lastTexcoordBuf = NULL; for(size_t i = 0; i < storage.tiles.size(); ++i) { @@ -75,13 +94,12 @@ void TileRender::onRender(const RenderState& rs) const } const ElementTemplate * const et = tile.et; + const float sw = et->w * tile.scalex; + const float sh = et->h * tile.scaley; // adapted from RenderObject::isOnScreen() { - const float cw = et->w * tile.scalex; - const float ch = et->h * tile.scaley; - const float cullRadiusSqr = ((cw*cw + ch*ch) * core->invGlobalScaleSqr) + core->cullRadiusSqr; - + const float cullRadiusSqr = ((sw*sw + sh*sh) * core->invGlobalScaleSqr) + core->cullRadiusSqr; if ((pos - core->cullCenter).getSquaredLength2D() >= cullRadiusSqr) continue; } @@ -107,104 +125,92 @@ void TileRender::onRender(const RenderState& rs) const glTranslatef(pos.x, pos.y, pos.z); glRotatef(tile.rotation, 0, 0, 1); - if(tile.flags & TILEFLAG_FH) // TODO: This is not necessary! Since we have no children, flipped texcoords are fine + if(tile.flags & TILEFLAG_FH) glRotatef(180, 0, 1, 0); // this is only relevant in editor mode and is always 0 otherwise - glTranslatef(tile.beforeScaleOffsetX, tile.beforeScaleOffsetY, 0); + //glTranslatef(tile.beforeScaleOffsetX, tile.beforeScaleOffsetY, 0); - glScalef(tile.scalex, tile.scaley, 1); - //glScalef(tile.scalex * et->w, tile.scaley * et->h, 1); // TODO use this + fixed verts + glScalef(sw, sh, 1); - BlendType blend = BLEND_DEFAULT; float alpha = rs.alpha; - RenderGrid *grid = NULL; const TileEffectData * const eff = tile.eff; - if(eff) + if(eff != prevEff) // effects between tiles are often shared so this works not only for NULL { - grid = eff->grid; - alpha *= eff->alpha.x; - blend = eff->blend; + prevEff = eff; + BlendType blend = BLEND_DEFAULT; + alpha = rs.alpha; + grid = NULL; + + if(eff) + { + grid = eff->grid; + alpha *= eff->alpha.x; + blend = eff->blend; + } + + rs.gpu.setBlend(blend); + glColor4f(rs.color.x, rs.color.y, rs.color.z, alpha); } - rs.gpu.setBlend(blend); - - // TODO: only need to do this when prev. tile had different alpha - glColor4f(rs.color.x, rs.color.y, rs.color.z, alpha); - - const Vector upperLeftTextureCoordinates(et->tu1, et->tv1); - const Vector lowerRightTextureCoordinates(et->tu2, et->tv2); - if(!grid) { - const float _w2 = et->w * 0.5f; - const float _h2 = et->h * 0.5f; - - glBegin(GL_QUADS); + const float *tcbuf = tile.et->texcoordQuadPtr; + assert(tcbuf); + if(lastTexcoordBuf != tcbuf) { - glTexCoord2f(upperLeftTextureCoordinates.x, 1.0f-upperLeftTextureCoordinates.y); - glVertex2f(-_w2, +_h2); - - glTexCoord2f(lowerRightTextureCoordinates.x, 1.0f-upperLeftTextureCoordinates.y); - glVertex2f(+_w2, +_h2); - - glTexCoord2f(lowerRightTextureCoordinates.x, 1.0f-lowerRightTextureCoordinates.y); - glVertex2f(+_w2, -_h2); - - glTexCoord2f(upperLeftTextureCoordinates.x, 1.0f-lowerRightTextureCoordinates.y); - glVertex2f(-_w2, -_h2); + lastTexcoordBuf = tcbuf; + glTexCoordPointer(2, GL_FLOAT, 0, tcbuf); } - glEnd(); + glDrawArrays(GL_QUADS, 0, 4); } else { - glPushMatrix(); - glScalef(et->w, et->h, 1); - - RenderState rx(rs); rx.alpha = alpha; + const Vector upperLeftTextureCoordinates(et->tu1, et->tv1); + const Vector lowerRightTextureCoordinates(et->tu2, et->tv2); grid->render(rx, upperLeftTextureCoordinates, lowerRightTextureCoordinates); - if (RenderObject::renderCollisionShape) + } + + if(renderExtras) + { + glBindTexture(GL_TEXTURE_2D, 0); + lastTexId = 0; + prevEff = ((TileEffectData*)NULL)+1; + + if(grid && RenderObject::renderCollisionShape) { - glBindTexture(GL_TEXTURE_2D, 0); grid->renderDebugPoints(rs); - lastTexId = 0; } - glPopMatrix(); + if(renderBorders) + { + float c = (tile.flags & TILEFLAG_SELECTED) ? 1.0f : 0.5f; + Vector color(c,c,c); + color *= getTagColor(tile.tag); + + glColor4f(color.x, color.y, color.z, 1.0f); + glPointSize(16); + glBegin(GL_POINTS); + glVertex2f(0,0); + glEnd(); + + glLineWidth(2); + glBegin(GL_LINE_STRIP); + glVertex2f(0.5f, 0.5f); + glVertex2f(0.5f, -0.5f); + glVertex2f(-0.5f, -0.5f); + glVertex2f(-0.5f, 0.5f); + glVertex2f(0.5f, 0.5f); + glEnd(); + } } - if(renderBorders) - { - lastTexId = 0; - glBindTexture(GL_TEXTURE_2D, 0); - - float c = (tile.flags & TILEFLAG_SELECTED) ? 1.0f : 0.5f; - Vector color(c,c,c); - color *= getTagColor(tile.tag); - const float _w2 = et->w * 0.5f; - const float _h2 = et->h * 0.5f; - - glColor4f(color.x, color.y, color.z, 1.0f); - glPointSize(16); - glBegin(GL_POINTS); - glVertex2f(0,0); - glEnd(); - - glLineWidth(2); - glBegin(GL_LINE_STRIP); - glVertex2f(_w2, _h2); - glVertex2f(_w2, -_h2); - glVertex2f(-_w2, -_h2); - glVertex2f(-_w2, _h2); - glVertex2f(_w2, _h2); - glEnd(); - } - - glPopMatrix(); } + glPopClientAttrib(); + RenderObject::lastTextureApplied = lastTexId; RenderObject::lastTextureRepeat = !!lastTexRepeat; } diff --git a/BBGE/Tileset.cpp b/BBGE/Tileset.cpp index 26e4a53..aee51fa 100644 --- a/BBGE/Tileset.cpp +++ b/BBGE/Tileset.cpp @@ -16,7 +16,7 @@ Tileset::~Tileset() bool Tileset::loadFile(const char *fn, const unsigned char *usedIdx, size_t usedIdxLen) { - elementTemplates.clear(); + clear(); InStream in(fn); if(!in) @@ -34,12 +34,12 @@ bool Tileset::loadFile(const char *fn, const unsigned char *usedIdx, size_t used { if(idx < 1024) { - ElementTemplate t; - t.idx = idx; - t.gfx = gfx; - t.w = w; - t.h = h; - elementTemplates.push_back(t); + ElementTemplate *et = new ElementTemplate; + et->idx = idx; + et->gfx = gfx; + et->w = w; + et->h = h; + elementTemplates.push_back(et); } else warn = true; @@ -59,9 +59,9 @@ bool Tileset::loadFile(const char *fn, const unsigned char *usedIdx, size_t used for (size_t i = 0; i < elementTemplates.size(); i++) { - size_t idx = elementTemplates[i].idx; + size_t idx = elementTemplates[i]->idx; if (!usedIdx || (idx < usedIdxLen && usedIdx[idx])) - usedTex.push_back(elementTemplates[i].gfx); + usedTex.push_back(elementTemplates[i]->gfx); } std::sort(usedTex.begin(), usedTex.end()); // drop duplicates @@ -90,15 +90,16 @@ bool Tileset::loadFile(const char *fn, const unsigned char *usedIdx, size_t used std::ostringstream failed; for (size_t i = 0; i < elementTemplates.size(); i++) { - ElementTemplate& et = elementTemplates[i]; + ElementTemplate *et = elementTemplates[i]; // only check those that are actualy loaded; otherwise this would load in textures // that we didn't bother to batch-load above - if(!usedIdx || (et.idx < usedIdxLen && usedIdx[et.idx])) + if(!usedIdx || (et->idx < usedIdxLen && usedIdx[et->idx])) { - if(!et.getTexture()) // assigns width/height and caches texture pointer + et->finalize(); // assigns width/height and caches texture pointer + if(!et->tex) { ++nfailed; - failed << et.gfx << " "; + failed << et->gfx << " "; } } } @@ -119,6 +120,9 @@ void Tileset::clear() for(size_t i = 0; i < dummies.size(); ++i) delete dummies[i]; dummies.clear(); + + for(size_t i = 0; i < elementTemplates.size(); ++i) + delete elementTemplates[i]; elementTemplates.clear(); } @@ -126,11 +130,11 @@ const ElementTemplate *Tileset::getByIdx(size_t idx) { for (size_t i = 0; i < elementTemplates.size(); i++) { - ElementTemplate& et = elementTemplates[i]; - if (et.idx == idx) + ElementTemplate *et = elementTemplates[i]; + if (et->idx == idx) { - et.getTexture(); // HACK: make sure the texture is loaded before this gets used - return &et; + et->finalize(); // HACK: make sure the texture is loaded before this gets used + return et; } } @@ -151,6 +155,7 @@ const ElementTemplate *Tileset::getByIdx(size_t idx) ElementTemplate *dummy = new ElementTemplate; dummy->idx = idx; + dummy->finalize(); dummies.push_back(dummy); return dummy; @@ -160,17 +165,22 @@ const ElementTemplate* Tileset::getAdjacent(size_t idx, int direction, bool wrap { ElementTemplate *et = _getAdjacent(idx, direction, wraparound); if(et) - et->getTexture(); // load just in case + et->finalize(); // load just in case return et; } -Texture* ElementTemplate::getTexture() +static const float s_defaultTexcoordBuf[] = { - if(loaded) - return tex.content(); + 0, 1, + 1, 1, + 1, 0, + 0, 0 +}; - loaded = true; - tex = core->getTexture(gfx); // may end up NULL +void ElementTemplate::finalize() +{ + if(!gfx.empty()) + tex = core->getTexture(gfx); // may end up NULL if(tex) { if(!w) @@ -186,8 +196,20 @@ Texture* ElementTemplate::getTexture() h = 64; } - return tex.content(); - + if(tu1 == 0 && tv1 == 0 && tu2 == 1 && tv2 == 1) + texcoordQuadPtr = s_defaultTexcoordBuf; + else + { + texcoordQuadPtr = &texcoordQuadBuffer[0]; + texcoordQuadBuffer[0] = tu1; + texcoordQuadBuffer[1] = 1.0f-tv1; + texcoordQuadBuffer[2] = tu2; + texcoordQuadBuffer[3] = 1.0f-tv1; + texcoordQuadBuffer[4] = tu2; + texcoordQuadBuffer[5] = 1.0f-tv2; + texcoordQuadBuffer[6] = tu1; + texcoordQuadBuffer[7] = 1.0f-tv2; + } } ElementTemplate * Tileset::_getAdjacent(size_t idx, int direction, bool wraparound) @@ -198,21 +220,21 @@ ElementTemplate * Tileset::_getAdjacent(size_t idx, int direction, bool wraparou int mindiff = 0; for (size_t i = 0; i < maxn; i++) { - if (elementTemplates[i].idx == idx) + if (elementTemplates[i]->idx == idx) { if(wraparound) { if(!i && direction < 0) - return &elementTemplates.back(); + return elementTemplates.back(); if(i + direction >= maxn) - return &elementTemplates[0]; + return elementTemplates[0]; } else i += direction; // may underflow - return i < maxn ? &elementTemplates[i] : NULL; + return i < maxn ? elementTemplates[i] : NULL; } - int diff = labs((int)elementTemplates[i].idx - (int)idx); + int diff = labs((int)elementTemplates[i]->idx - (int)idx); if(diff < mindiff || !mindiff) { mindiff = diff; @@ -230,11 +252,11 @@ ElementTemplate * Tileset::_getAdjacent(size_t idx, int direction, bool wraparou else if(wraparound) { if(!closest && direction < 0) - return &elementTemplates.back(); + return elementTemplates.back(); if(closest + direction >= maxn) - return &elementTemplates[0]; + return elementTemplates[0]; } size_t i = closest + direction; - return i < maxn ? &elementTemplates[i] : NULL; + return i < maxn ? elementTemplates[i] : NULL; } diff --git a/BBGE/Tileset.h b/BBGE/Tileset.h index 857a85c..ec919b3 100644 --- a/BBGE/Tileset.h +++ b/BBGE/Tileset.h @@ -8,21 +8,24 @@ class ElementTemplate { public: - ElementTemplate() { w=0; h=0; idx=-1; tu1=tv1=0; tu2=tv2=1; loaded=false; } + ElementTemplate() { w=0; h=0; idx=-1; tu1=tv1=0; tu2=tv2=1; texcoordQuadPtr=NULL; } inline bool operator<(const ElementTemplate& o) const { return idx < o.idx; } - Texture *getTexture(); // loads if not already loaded + void finalize(); // call after settings params // lazily assigned when tex is loaded CountedPtr tex; // NULL if failed to load or not yet loaded float w,h; // custom size if used, otherwise texture size + const float *texcoordQuadPtr; + float texcoordQuadBuffer[8]; // fixed float tu1, tu2, tv1, tv2; // texcoords size_t idx; std::string gfx; - bool loaded; +private: + ElementTemplate(const ElementTemplate&); // no copy }; class Tileset @@ -43,7 +46,7 @@ public: // never returns dummy ET. May return NULL. const ElementTemplate *getAdjacent(size_t idx, int direction, bool wraparound); - std::vector elementTemplates; + std::vector elementTemplates; private: ElementTemplate *_getAdjacent(size_t idx, int direction, bool wraparound);