void drawGround() { if (groundQuads == 0) return; ShaderBase *shader; if (!nullOrDisposed(bitmaps[BM_A1])) { /* Animated tileset */ TilemapVXShader &tmShader = shState->shaders().tilemapVX; tmShader.bind(); tmShader.setAniOffset(aniOffset); shader = &tmShader; } else { /* Static tileset */ shader = &shState->shaders().simple; shader->bind(); } shader->setTexSize(Vec2i(atlas.width, atlas.height)); shader->applyViewportProj(); shader->setTranslation(dispPos); TEX::bind(atlas.tex); GLMeta::vaoBind(vao); gl.DrawElements(GL_TRIANGLES, groundQuads*6, _GL_INDEX_TYPE, 0); GLMeta::vaoUnbind(vao); }
void recomputeBushDepth() { if (nullOrDisposed(bitmap)) return; /* Calculate effective (normalized) bush depth */ float texBushDepth = (bushDepth / trans.getScale().y) - (srcRect->y + srcRect->height) + bitmap->height(); efBushDepth = 1.0f - texBushDepth / bitmap->height(); }
void updateQuadSource() { if (gl.npot_repeat) { FloatRect srcRect; srcRect.x = (sceneGeo.orig.x + ox) / zoomX; srcRect.y = (sceneGeo.orig.y + oy) / zoomY; srcRect.w = sceneGeo.rect.w / zoomX; srcRect.h = sceneGeo.rect.h / zoomY; Quad::setTexRect(&qArray.vertices[0], srcRect); qArray.commit(); return; } if (nullOrDisposed(bitmap)) return; /* Scaled (zoomed) bitmap dimensions */ double sw = bitmap->width() * zoomX; double sh = bitmap->height() * zoomY; /* Plane offset wrapped by scaled bitmap dims */ float wox = fwrap(ox, sw); float woy = fwrap(oy, sh); /* Viewport dimensions */ int vpw = sceneGeo.rect.w; int vph = sceneGeo.rect.h; /* Amount the scaled bitmap is tiled (repeated) */ size_t tilesX = ceil((vpw - sw + wox) / sw) + 1; size_t tilesY = ceil((vph - sh + woy) / sh) + 1; FloatRect tex = bitmap->rect(); qArray.resize(tilesX * tilesY); for (size_t y = 0; y < tilesY; ++y) for (size_t x = 0; x < tilesX; ++x) { SVertex *vert = &qArray.vertices[(y*tilesX + x) * 4]; FloatRect pos(x*sw - wox, y*sh - woy, sw, sh); Quad::setTexPosRect(vert, tex, pos); } qArray.commit(); }
void Plane::draw() { if (nullOrDisposed(p->bitmap)) return; if (!p->opacity) return; ShaderBase *base; if (p->color->hasEffect() || p->tone->hasEffect() || p->opacity != 255) { PlaneShader &shader = shState->shaders().plane; shader.bind(); shader.applyViewportProj(); shader.setTone(p->tone->norm); shader.setColor(p->color->norm); shader.setFlash(Vec4()); shader.setOpacity(p->opacity.norm); base = &shader; } else { SimpleShader &shader = shState->shaders().simple; shader.bind(); shader.applyViewportProj(); shader.setTranslation(Vec2i()); base = &shader; } glState.blendMode.pushSet(p->blendType); p->bitmap->bindTex(*base); if (gl.npot_repeat) TEX::setRepeat(true); p->qArray.draw(); if (gl.npot_repeat) TEX::setRepeat(false); glState.blendMode.pop(); }
void WindowVX::setContents(Bitmap *value) { guardDisposed(); if (p->contents == value) return; p->contents = value; if (nullOrDisposed(value)) return; FloatRect rect = p->contents->rect(); p->contentsQuad.setTexPosRect(rect, rect); p->ctrlVertDirty = true; }
void rebuildCtrlVert() { /* Scroll arrow position: Top Bottom X, Left Right Y */ const Vec2i arrow = (geo.size() - Vec2i(16)) / 2; const Sides<FloatRect> arrowPos = { FloatRect( 4, arrow.y, 8, 16 ), /* Left */ FloatRect( geo.w - 12, arrow.y, 8, 16 ), /* Right */ FloatRect( arrow.x, 4, 16, 8 ), /* Top */ FloatRect( arrow.x, geo.h - 12, 16, 8 ) /* Bottom */ }; size_t i = 0; Vertex *vert = dataPtr(ctrlVert.vertices); if (!nullOrDisposed(contents) && arrowsVisible) { if (contentsOff.x > 0) i += Quad::setTexPosRect(&vert[i*4], scrollArrowSrc.l, arrowPos.l); if (contentsOff.y > 0) i += Quad::setTexPosRect(&vert[i*4], scrollArrowSrc.t, arrowPos.t); if (padRect.w < (contents->width() - contentsOff.x)) i += Quad::setTexPosRect(&vert[i*4], scrollArrowSrc.r, arrowPos.r); if (padRect.h < (contents->height() - contentsOff.y)) i += Quad::setTexPosRect(&vert[i*4], scrollArrowSrc.b, arrowPos.b); } pauseVert = 0; if (pause) { const FloatRect pausePos(arrow.x, geo.h - 16, 16, 16); pauseVert = &vert[i*4]; i += Quad::setTexPosRect(&vert[i*4], pauseSrc[0], pausePos); } ctrlQuads = i; ctrlVertArrayDirty = true; }
void Sprite::setBitmap(Bitmap *bitmap) { guardDisposed(); if (p->bitmap == bitmap) return; p->bitmap = bitmap; if (nullOrDisposed(bitmap)) return; bitmap->ensureNonMega(); *p->srcRect = bitmap->rect(); p->onSrcRectChange(); p->quad.setPosRect(p->srcRect->toFloatRect()); p->wave.dirty = true; }
void onSrcRectChange() { FloatRect rect = srcRect->toFloatRect(); Vec2i bmSize; if (!nullOrDisposed(bitmap)) bmSize = Vec2i(bitmap->width(), bitmap->height()); /* Clamp the rectangle so it doesn't reach outside * the bitmap bounds */ rect.w = clamp<int>(rect.w, 0, bmSize.x-rect.x); rect.h = clamp<int>(rect.h, 0, bmSize.y-rect.y); quad.setTexRect(mirrored ? rect.hFlipped() : rect); quad.setPosRect(FloatRect(0, 0, rect.w, rect.h)); recomputeBushDepth(); wave.dirty = true; }
void updateVisibility() { isVisible = false; if (nullOrDisposed(bitmap)) return; if (!opacity) return; if (wave.active) { /* Don't do expensive wave bounding box * calculations */ isVisible = true; return; } /* Compare sprite bounding box against the scene */ /* If sprite is zoomed/rotated, just opt out for now * for simplicity's sake */ const Vec2 &scale = trans.getScale(); if (scale.x != 1 || scale.y != 1 || trans.getRotation() != 0) { isVisible = true; return; } SDL_Rect self; self.x = trans.getPosition().x - trans.getOrigin().x; self.y = trans.getPosition().y - trans.getOrigin().y; self.w = bitmap->width(); self.h = bitmap->height(); isVisible = SDL_HasIntersection(&self, &sceneRect); }
void updateWave() { if (nullOrDisposed(bitmap)) return; if (wave.amp == 0) { wave.active = false; return; } wave.active = true; int width = srcRect->width; int height = srcRect->height; float zoomY = trans.getScale().y; if (wave.amp < -(width / 2)) { wave.qArray.resize(0); wave.qArray.commit(); return; } /* RMVX does this, and I have no f*****g clue why */ if (wave.amp < 0) { wave.qArray.resize(1); int x = -wave.amp; int w = width - x * 2; FloatRect tex(x, srcRect->y, w, srcRect->height); Quad::setTexPosRect(&wave.qArray.vertices[0], tex, tex); wave.qArray.commit(); return; } /* The length of the sprite as it appears on screen */ int visibleLength = height * zoomY; /* First chunk length (aligned to 8 pixel boundary */ int firstLength = ((int) trans.getPosition().y) % 8; /* Amount of full 8 pixel chunks in the middle */ int chunks = (visibleLength - firstLength) / 8; /* Final chunk length */ int lastLength = (visibleLength - firstLength) % 8; wave.qArray.resize(!!firstLength + chunks + !!lastLength); SVertex *vert = &wave.qArray.vertices[0]; float phase = (wave.phase * M_PI) / 180.f; if (firstLength > 0) emitWaveChunk(vert, phase, width, zoomY, 0, firstLength); for (int i = 0; i < chunks; ++i) emitWaveChunk(vert, phase, width, zoomY, firstLength + i * 8, 8); if (lastLength > 0) emitWaveChunk(vert, phase, width, zoomY, firstLength + chunks * 8, lastLength); wave.qArray.commit(); }
void draw() { if (base.tex.tex == TEX::ID(0)) return; bool windowskinValid = !nullOrDisposed(windowskin); bool contentsValid = !nullOrDisposed(contents); Vec2i trans = geo.pos() + sceneOffset; SimpleAlphaShader &shader = shState->shaders().simpleAlpha; shader.bind(); shader.applyViewportProj(); if (windowskinValid) { shader.setTranslation(trans); shader.setTexSize(Vec2i(base.tex.width, base.tex.height)); TEX::bind(base.tex.tex); base.quad.draw(); if (openness < 255) return; windowskin->bindTex(shader); TEX::setSmooth(true); ctrlVert.draw(0, ctrlQuads); TEX::setSmooth(false); } if (openness < 255) return; bool drawCursor = cursorVert.count() > 0 && windowskinValid; if (drawCursor || contentsValid) { /* Translate cliprect from local into screen space */ IntRect clip = clipRect; clip.setPos(clip.pos() + trans); glState.scissorBox.push(); glState.scissorTest.pushSet(true); if (rgssVer >= 3) glState.scissorBox.setIntersect(clip); else glState.scissorBox.setIntersect(IntRect(trans, geo.size())); IntRect pad = padRect; pad.setPos(pad.pos() + trans); if (drawCursor) { Vec2i contTrans = pad.pos(); contTrans.x += cursorRect->x; contTrans.y += cursorRect->y; if (rgssVer >= 3) contTrans -= contentsOff; shader.setTranslation(contTrans); TEX::setSmooth(true); cursorVert.draw(); TEX::setSmooth(false); } if (contentsValid) { if (rgssVer <= 2) glState.scissorBox.setIntersect(clip); Vec2i contTrans = pad.pos(); contTrans -= contentsOff; shader.setTranslation(contTrans); TEX::setSmooth(false); // XXX contents->bindTex(shader); contentsQuad.draw(); } glState.scissorBox.pop(); glState.scissorTest.pop(); } TEX::setSmooth(false); // XXX FIND out a way to eliminate }
void redrawBaseTex() { if (nullOrDisposed(windowskin)) return; if (base.tex.tex == TEX::ID(0)) return; FBO::bind(base.tex.fbo); /* Clear texture */ glState.clearColor.pushSet(Vec4()); FBO::clear(); glState.clearColor.pop(); glState.viewport.pushSet(IntRect(0, 0, base.tex.width, base.tex.height)); glState.blend.pushSet(false); ShaderBase *shader; if (backOpacity < 255 || tone->hasEffect()) { PlaneShader &planeShader = shState->shaders().plane; planeShader.bind(); planeShader.setColor(Vec4()); planeShader.setFlash(Vec4()); planeShader.setTone(tone->norm); planeShader.setOpacity(backOpacity.norm); shader = &planeShader; } else { shader = &shState->shaders().simple; shader->bind(); } windowskin->bindTex(*shader); TEX::setSmooth(true); shader->setTranslation(Vec2i()); shader->applyViewportProj(); /* Draw stretched layer */ base.vert.draw(0, 1); glState.blend.set(true); glState.blendMode.pushSet(BlendKeepDestAlpha); /* Draw tiled layer */ base.vert.draw(1, base.bgTileQuads); glState.blendMode.set(BlendNormal); /* If we used plane shader before, switch to simple */ if (shader != &shState->shaders().simple) { shader = &shState->shaders().simple; shader->bind(); shader->setTranslation(Vec2i()); shader->applyViewportProj(); windowskin->bindTex(*shader); } base.vert.draw(1+base.bgTileQuads, base.borderQuads); TEX::setSmooth(false); glState.blendMode.pop(); glState.blend.pop(); glState.viewport.pop(); }