v0.4.2: lots of performance improvements to fog visuals
This commit is contained in:
committed by
Evan Debenham
parent
b325858644
commit
2bd1962b34
@@ -41,6 +41,14 @@ public class SmartTexture extends Texture {
|
||||
|
||||
public Atlas atlas;
|
||||
|
||||
protected SmartTexture( ) {
|
||||
super();
|
||||
//useful for subclasses which want to manage their own texture data
|
||||
// in cases where android.graphics.bitmap isn't fast enough.
|
||||
|
||||
//subclasses which use this MUST also override reload()
|
||||
}
|
||||
|
||||
public SmartTexture( Bitmap bitmap ) {
|
||||
this( bitmap, NEAREST, CLAMP, false );
|
||||
}
|
||||
@@ -93,7 +101,8 @@ public class SmartTexture extends Texture {
|
||||
|
||||
super.delete();
|
||||
|
||||
bitmap.recycle();
|
||||
if (bitmap != null)
|
||||
bitmap.recycle();
|
||||
bitmap = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ package com.shatteredpixel.shatteredpixeldungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Amok;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Awareness;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Light;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MindVision;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith;
|
||||
@@ -657,7 +659,11 @@ public class Dungeon {
|
||||
Rankings.INSTANCE.submit( true, cause );
|
||||
}
|
||||
|
||||
public static void observe() {
|
||||
public static void observe(){
|
||||
observe( hero.viewDistance+1 );
|
||||
}
|
||||
|
||||
public static void observe( int dist ) {
|
||||
|
||||
if (level == null) {
|
||||
return;
|
||||
@@ -668,12 +674,10 @@ public class Dungeon {
|
||||
int cx = hero.pos % level.width();
|
||||
int cy = hero.pos / level.width();
|
||||
|
||||
//Add one to account for hero's previous position
|
||||
int viewDist = hero.viewDistance+1;
|
||||
int ax = Math.max( 0, cx - viewDist );
|
||||
int bx = Math.min( cx + viewDist, level.width() - 1 );
|
||||
int ay = Math.max( 0, cy - viewDist );
|
||||
int by = Math.min( cy + viewDist, level.height() - 1 );
|
||||
int ax = Math.max( 0, cx - dist );
|
||||
int bx = Math.min( cx + dist, level.width() - 1 );
|
||||
int ay = Math.max( 0, cy - dist );
|
||||
int by = Math.min( cy + dist, level.height() - 1 );
|
||||
|
||||
int len = bx - ax + 1;
|
||||
int pos = ax + ay * level.width();
|
||||
@@ -681,6 +685,11 @@ public class Dungeon {
|
||||
BArray.or( level.visited, visible, pos, len, level.visited );
|
||||
}
|
||||
|
||||
if (hero.buff(MindVision.class) != null || hero.buff(Awareness.class) != null)
|
||||
GameScene.updateFog();
|
||||
else
|
||||
GameScene.updateFog(ax, ay, len, by-ay);
|
||||
|
||||
GameScene.afterObserve();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,14 +20,17 @@
|
||||
*/
|
||||
package com.shatteredpixel.shatteredpixeldungeon;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import android.opengl.GLES20;
|
||||
|
||||
import com.watabou.gltextures.SmartTexture;
|
||||
import com.watabou.gltextures.TextureCache;
|
||||
import com.watabou.glwrap.Texture;
|
||||
import com.watabou.noosa.Image;
|
||||
import com.watabou.utils.Rect;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
public class FogOfWar extends Image {
|
||||
|
||||
@@ -36,14 +39,14 @@ public class FogOfWar extends Image {
|
||||
private static final int MAPPED = 0xcc442211;
|
||||
private static final int INVISIBLE = 0xFF000000;
|
||||
|
||||
private int[] pixels;
|
||||
|
||||
private int pWidth;
|
||||
private int pHeight;
|
||||
|
||||
private int width2;
|
||||
private int height2;
|
||||
|
||||
public Rect updated;
|
||||
|
||||
public FogOfWar( int mapWidth, int mapHeight ) {
|
||||
|
||||
super();
|
||||
@@ -65,59 +68,129 @@ public class FogOfWar extends Image {
|
||||
width = width2 * size;
|
||||
height = height2 * size;
|
||||
|
||||
texture( new FogTexture() );
|
||||
texture( new FogTexture(width2, height2) );
|
||||
|
||||
scale.set(
|
||||
DungeonTilemap.SIZE,
|
||||
DungeonTilemap.SIZE );
|
||||
|
||||
x = y = -size / 2;
|
||||
|
||||
updated = new Rect(0, 0, pWidth, pHeight);
|
||||
}
|
||||
|
||||
public void updateVisibility( boolean[] visible, boolean[] visited, boolean[] mapped ) {
|
||||
|
||||
if (pixels == null) {
|
||||
pixels = new int[width2 * height2];
|
||||
Arrays.fill( pixels, INVISIBLE );
|
||||
}
|
||||
if (updated.isEmpty())
|
||||
return;
|
||||
|
||||
for (int i=1; i < pHeight - 1; i++) {
|
||||
int pos = (pWidth - 1) * i;
|
||||
for (int j=1; j < pWidth - 1; j++) {
|
||||
pos++;
|
||||
int c = INVISIBLE;
|
||||
if (visible[pos] && visible[pos - (pWidth - 1)] &&
|
||||
visible[pos - 1] && visible[pos - (pWidth - 1) - 1]) {
|
||||
c = VISIBLE;
|
||||
FogTexture fog = (FogTexture)texture;
|
||||
|
||||
for (int i=updated.top; i < updated.bottom; i++) {
|
||||
int cell = (pWidth - 1) * i + updated.left;
|
||||
fog.pixels.position((width2) * i + updated.left);
|
||||
for (int j=updated.left; j < updated.right; j++) {
|
||||
if (cell < pWidth || cell >= Dungeon.level.length()) {
|
||||
fog.pixels.put(INVISIBLE);
|
||||
} else
|
||||
if (visited[pos] && visited[pos - (pWidth - 1)] &&
|
||||
visited[pos - 1] && visited[pos - (pWidth - 1) - 1]) {
|
||||
c = VISITED;
|
||||
if (visible[cell] && visible[cell - (pWidth - 1)] &&
|
||||
visible[cell - 1] && visible[cell - (pWidth - 1) - 1]) {
|
||||
fog.pixels.put(VISIBLE);
|
||||
} else
|
||||
if (visited[cell] && visited[cell - (pWidth - 1)] &&
|
||||
visited[cell - 1] && visited[cell - (pWidth - 1) - 1]) {
|
||||
fog.pixels.put(VISITED);
|
||||
}
|
||||
else
|
||||
if (mapped[pos] && mapped[pos - (pWidth - 1)] &&
|
||||
mapped[pos - 1] && mapped[pos - (pWidth - 1) - 1]) {
|
||||
c = MAPPED;
|
||||
if (mapped[cell] && mapped[cell - (pWidth - 1)] &&
|
||||
mapped[cell - 1] && mapped[cell - (pWidth - 1) - 1]) {
|
||||
fog.pixels.put(MAPPED);
|
||||
} else {
|
||||
fog.pixels.put(INVISIBLE);
|
||||
}
|
||||
pixels[i * width2 + j] = c;
|
||||
cell++;
|
||||
}
|
||||
}
|
||||
|
||||
texture.pixels( width2, height2, pixels );
|
||||
if (updated.width() == pWidth && updated.height() == pHeight)
|
||||
fog.update();
|
||||
else
|
||||
fog.update(updated.top, updated.bottom);
|
||||
updated.setEmpty();
|
||||
|
||||
}
|
||||
|
||||
//provides a native intbuffer implementation because android.graphics.bitmap is too slow
|
||||
//TODO perhaps should spin this off into something like FastEditTexture in SPD-classes
|
||||
private class FogTexture extends SmartTexture {
|
||||
|
||||
public FogTexture() {
|
||||
super( Bitmap.createBitmap( width2, height2, Bitmap.Config.ARGB_8888 ) );
|
||||
private IntBuffer pixels;
|
||||
|
||||
public FogTexture(int w, int h) {
|
||||
super();
|
||||
width = w;
|
||||
height = h;
|
||||
pixels = ByteBuffer.
|
||||
allocateDirect( w * h * 4 ).
|
||||
order( ByteOrder.nativeOrder() ).
|
||||
asIntBuffer();
|
||||
|
||||
filter( Texture.LINEAR, Texture.LINEAR );
|
||||
TextureCache.add( FogOfWar.class, this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
GameScene.afterObserve();
|
||||
int[] ids = new int[1];
|
||||
GLES20.glGenTextures( 1, ids, 0 );
|
||||
id = ids[0];
|
||||
filter( Texture.LINEAR, Texture.LINEAR );
|
||||
update();
|
||||
}
|
||||
|
||||
public void update(){
|
||||
bind();
|
||||
pixels.position(0);
|
||||
GLES20.glTexImage2D(
|
||||
GLES20.GL_TEXTURE_2D,
|
||||
0,
|
||||
GLES20.GL_RGBA,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
GLES20.GL_RGBA,
|
||||
GLES20.GL_UNSIGNED_BYTE,
|
||||
pixels );
|
||||
}
|
||||
|
||||
//allows partially updating the texture
|
||||
public void update(int top, int bottom){
|
||||
bind();
|
||||
pixels.position(top*width);
|
||||
GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D,
|
||||
0,
|
||||
0,
|
||||
top,
|
||||
width,
|
||||
bottom - top,
|
||||
GLES20.GL_RGBA,
|
||||
GLES20.GL_UNSIGNED_BYTE,
|
||||
pixels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
super.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw() {
|
||||
|
||||
if (!updated.isEmpty()){
|
||||
updateVisibility(Dungeon.visible, Dungeon.level.visited, Dungeon.level.mapped);
|
||||
}
|
||||
|
||||
super.draw();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
package com.shatteredpixel.shatteredpixeldungeon.actors.buffs;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
|
||||
public class Awareness extends FlavourBuff {
|
||||
|
||||
@@ -30,5 +31,6 @@ public class Awareness extends FlavourBuff {
|
||||
public void detach() {
|
||||
super.detach();
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class Light extends FlavourBuff {
|
||||
@Override
|
||||
public void detach() {
|
||||
target.viewDistance = Dungeon.level.viewDistance;
|
||||
Dungeon.observe();
|
||||
Dungeon.observe(DISTANCE+1);
|
||||
super.detach();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.buffs;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator;
|
||||
|
||||
public class MindVision extends FlavourBuff {
|
||||
@@ -48,6 +49,7 @@ public class MindVision extends FlavourBuff {
|
||||
public void detach() {
|
||||
super.detach();
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfHealing;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.GuardSprite;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Callback;
|
||||
@@ -117,6 +118,7 @@ public class Guard extends Mob {
|
||||
if (enemy == Dungeon.hero) {
|
||||
Dungeon.hero.interrupt();
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
}
|
||||
}
|
||||
}), -1);
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||
import com.watabou.noosa.Game;
|
||||
import com.watabou.noosa.Visual;
|
||||
@@ -92,6 +93,7 @@ public class Swap extends Actor {
|
||||
|
||||
if (ch1 == Dungeon.hero || ch2 == Dungeon.hero) {
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ public class RogueArmor extends ClassArmor {
|
||||
Sample.INSTANCE.play( Assets.SND_PUFF );
|
||||
Dungeon.level.press( target, curUser );
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
|
||||
curUser.spendAndNext( Actor.TICK );
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ public class WarriorArmor extends ClassArmor {
|
||||
curUser.move(dest);
|
||||
Dungeon.level.press(dest, curUser);
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
|
||||
for (int i = 0; i < PathFinder.NEIGHBOURS8.length; i++) {
|
||||
Char mob = Actor.findChar(curUser.pos + PathFinder.NEIGHBOURS8[i]);
|
||||
|
||||
@@ -141,6 +141,7 @@ public class EtherealChains extends Artifact {
|
||||
}));
|
||||
affected.pos = newMobPos;
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
curUser.spendAndNext(1f);
|
||||
}
|
||||
}));
|
||||
@@ -178,6 +179,7 @@ public class EtherealChains extends Artifact {
|
||||
curUser.spendAndNext(1f);
|
||||
curUser.pos = newHeroPos;
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -160,6 +160,7 @@ public class LloydsBeacon extends Artifact {
|
||||
ScrollOfTeleportation.appear( hero, returnPos );
|
||||
Dungeon.level.press( returnPos, hero );
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
} else {
|
||||
|
||||
Buff buff = Dungeon.hero.buff(TimekeepersHourglass.timeFreeze.class);
|
||||
|
||||
@@ -69,7 +69,7 @@ public class ScrollOfMagicMapping extends Scroll {
|
||||
}
|
||||
}
|
||||
}
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
|
||||
GLog.i( Messages.get(this, "layout") );
|
||||
if (noticed) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
import com.watabou.noosa.tweeners.AlphaTweener;
|
||||
@@ -69,6 +70,7 @@ public class ScrollOfTeleportation extends Scroll {
|
||||
appear( hero, pos );
|
||||
Dungeon.level.press( pos, hero );
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
|
||||
GLog.i( Messages.get(ScrollOfTeleportation.class, "tele") );
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ public class WandOfPrismaticLight extends DamageWand {
|
||||
if (noticed)
|
||||
Sample.INSTANCE.play( Assets.SND_SECRET );
|
||||
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.KindOfWeapon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Knuckles;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.TrapSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
@@ -55,7 +56,7 @@ public class DisarmingTrap extends Trap{
|
||||
Dungeon.level.drop( item, cell ).seen = true;
|
||||
for (int i : PathFinder.NEIGHBOURS9)
|
||||
Dungeon.level.visited[cell+i] = true;
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
|
||||
Sample.INSTANCE.play(Assets.SND_TELEPORT);
|
||||
CellEmitter.get(pos).burst(Speck.factory(Speck.LIGHT), 4);
|
||||
@@ -77,7 +78,7 @@ public class DisarmingTrap extends Trap{
|
||||
Dungeon.level.drop(weapon, cell).seen = true;
|
||||
for (int i : PathFinder.NEIGHBOURS9)
|
||||
Dungeon.level.visited[cell+i] = true;
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
|
||||
GLog.w( Messages.get(this, "disarm") );
|
||||
|
||||
|
||||
@@ -665,8 +665,8 @@ public class GameScene extends PixelScene {
|
||||
public static void resetMap() {
|
||||
if (scene != null) {
|
||||
scene.tiles.map(Dungeon.level.map, Dungeon.level.width() );
|
||||
|
||||
}
|
||||
updateFog();
|
||||
}
|
||||
|
||||
public static void updateMap() {
|
||||
@@ -692,10 +692,20 @@ public class GameScene extends PixelScene {
|
||||
scene.addToFront( wnd );
|
||||
}
|
||||
|
||||
public static void updateFog(){
|
||||
if (scene != null)
|
||||
scene.fog.updated.set(0, 0, Dungeon.level.width()+1, Dungeon.level.height()+1);
|
||||
}
|
||||
|
||||
public static void updateFog(int x, int y, int w, int h){
|
||||
if (scene != null) {
|
||||
scene.fog.updated.union(x, y);
|
||||
scene.fog.updated.union(x + w, y + h);
|
||||
}
|
||||
}
|
||||
|
||||
public static void afterObserve() {
|
||||
if (scene != null) {
|
||||
scene.fog.updateVisibility( Dungeon.visible, Dungeon.level.visited, Dungeon.level.mapped );
|
||||
|
||||
for (Mob mob : Dungeon.level.mobs) {
|
||||
mob.sprite.visible = Dungeon.visible[mob.pos];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user