Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Extrude edges of a Texture instead of surrounding it with transparent padding #97

Closed
wants to merge 1 commit into from

3 participants

@nazgee

Padding texture region with transparent region in some cases results
in appearance of display artifacts. This patch changes transparent padding
into borders extruded from a bitmap texture region.

I believe, that this change will automagically fix most of: "there is a gap between two sprites when camera moves" complaints.

DISCLAIMER: This is not very thoroughly tested. I can only see that this commit fixed most (all?) of the glitches I've seen when moving/scaling two adjacent Sprites.

@nazgee nazgee Extrude edges of a Texture, instead of surrounding it with transparen…
…t padding

Padding texture region with transparent region in some cases results
in appearance of display artifacts. This patch changes transparent padding
into borders extruded from a bitmap texture region.
5f052a2
@larku

I've been using this patch to fix the dreaded gaps/lines glitches that can be seen around sprites in some situations - this has totally fixed it for me.

I understand there are other workarounds such as using texture packer to extrude sprites etc, but this fix is far more elegant and does not require any additional work by the developer.

What's more is this fix will also work for runtime rendered SVG images - this can't really be done using texture packer.

I add a vote for this to be merged into GLES2.

@Niffy

Sorry to be a pain but how do you use this? Looking at the code

@Niffy

Hellos. Coming back to this, as I've got a TMX map with lots of artifacts so would like to try this out.
So how do I go about using it, can't seem to fathom it out.

@nazgee

Here is a description:
http://www.andengine.org/forums/post38274.html?hilit=extrude#p38274

There are some crashes (that can be workarounded somehow) when this patch is used. I've never get the nerves to fix it properly, unfortunately...

@nazgee nazgee closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 3, 2012
  1. @nazgee

    Extrude edges of a Texture, instead of surrounding it with transparen…

    nazgee authored
    …t padding
    
    Padding texture region with transparent region in some cases results
    in appearance of display artifacts. This patch changes transparent padding
    into borders extruded from a bitmap texture region.
This page is out of date. Refresh to see the latest.
View
3  src/org/andengine/opengl/texture/atlas/ITextureAtlas.java
@@ -3,6 +3,7 @@
import org.andengine.BuildConfig;
import org.andengine.opengl.texture.ITexture;
import org.andengine.opengl.texture.ITextureStateListener;
+import org.andengine.opengl.texture.atlas.bitmap.source.ExtrudingBitmapTextureAtlasSource.ExtrusionDirection;
import org.andengine.opengl.texture.atlas.source.ITextureAtlasSource;
import org.andengine.util.debug.Debug;
@@ -24,7 +25,7 @@
public void addTextureAtlasSource(final T pTextureAtlasSource, final int pTextureX, final int pTextureY) throws IllegalArgumentException;
public void addTextureAtlasSource(final T pTextureAtlasSource, final int pTextureX, final int pTextureY, final int pTextureAtlasSourcePadding) throws IllegalArgumentException;
- public void addEmptyTextureAtlasSource(final int pTextureX, final int pTextureY, final int pWidth, final int pHeight);
+ public void addExtrudingTextureAtlasSource(final int pTextureX, final int pTextureY, final int pWidth, final int pHeight, final ITextureAtlasSource pExtrusionSource, final ExtrusionDirection pExtrusionDirection, final int pExtrusionSize);
public void removeTextureAtlasSource(final T pTextureAtlasSource, final int pTextureX, final int pTextureY);
public void clearTextureAtlasSources();
View
9 src/org/andengine/opengl/texture/atlas/TextureAtlas.java
@@ -7,6 +7,7 @@
import org.andengine.opengl.texture.Texture;
import org.andengine.opengl.texture.TextureManager;
import org.andengine.opengl.texture.TextureOptions;
+import org.andengine.opengl.texture.atlas.bitmap.source.ExtrudingBitmapTextureAtlasSource.ExtrusionDirection;
import org.andengine.opengl.texture.atlas.source.ITextureAtlasSource;
/**
@@ -116,22 +117,22 @@ public void addTextureAtlasSource(final T pTextureAtlasSource, final int pTextur
if(pTextureAtlasSourcePadding > 0) {
/* Left padding. */
if(pTextureX >= pTextureAtlasSourcePadding) {
- this.addEmptyTextureAtlasSource(pTextureX - pTextureAtlasSourcePadding, pTextureY, pTextureAtlasSourcePadding, pTextureAtlasSource.getTextureHeight());
+ this.addExtrudingTextureAtlasSource(pTextureX - pTextureAtlasSourcePadding, pTextureY, pTextureAtlasSourcePadding, pTextureAtlasSource.getTextureHeight(), pTextureAtlasSource, ExtrusionDirection.LEFT, pTextureAtlasSourcePadding);
}
/* Top padding. */
if(pTextureY >= pTextureAtlasSourcePadding) {
- this.addEmptyTextureAtlasSource(pTextureX, pTextureY - pTextureAtlasSourcePadding, pTextureAtlasSource.getTextureWidth(), pTextureAtlasSourcePadding);
+ this.addExtrudingTextureAtlasSource(pTextureX, pTextureY - pTextureAtlasSourcePadding, pTextureAtlasSource.getTextureWidth(), pTextureAtlasSourcePadding, pTextureAtlasSource, ExtrusionDirection.TOP, pTextureAtlasSourcePadding);
}
/* Right padding. */
if(pTextureX + pTextureAtlasSource.getTextureWidth() - 1 + pTextureAtlasSourcePadding <= this.getWidth()) {
- this.addEmptyTextureAtlasSource(pTextureX + pTextureAtlasSource.getTextureWidth(), pTextureY, pTextureAtlasSourcePadding, pTextureAtlasSource.getTextureHeight());
+ this.addExtrudingTextureAtlasSource(pTextureX + pTextureAtlasSource.getTextureWidth(), pTextureY, pTextureAtlasSourcePadding, pTextureAtlasSource.getTextureHeight(), pTextureAtlasSource, ExtrusionDirection.RIGHT, pTextureAtlasSourcePadding);
}
/* Bottom padding. */
if(pTextureY + pTextureAtlasSource.getTextureHeight() - 1 + pTextureAtlasSourcePadding <= this.getHeight()) {
- this.addEmptyTextureAtlasSource(pTextureX, pTextureY + pTextureAtlasSource.getTextureHeight(), pTextureAtlasSource.getTextureWidth(), pTextureAtlasSourcePadding);
+ this.addExtrudingTextureAtlasSource(pTextureX, pTextureY + pTextureAtlasSource.getTextureHeight(), pTextureAtlasSource.getTextureWidth(), pTextureAtlasSourcePadding, pTextureAtlasSource, ExtrusionDirection.BOTTOM, pTextureAtlasSourcePadding);
}
}
}
View
24 src/org/andengine/opengl/texture/atlas/bitmap/BitmapTextureAtlas.java
@@ -6,7 +6,8 @@
import org.andengine.opengl.texture.TextureManager;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.TextureAtlas;
-import org.andengine.opengl.texture.atlas.bitmap.source.EmptyBitmapTextureAtlasSource;
+import org.andengine.opengl.texture.atlas.bitmap.source.ExtrudingBitmapTextureAtlasSource;
+import org.andengine.opengl.texture.atlas.bitmap.source.ExtrudingBitmapTextureAtlasSource.ExtrusionDirection;
import org.andengine.opengl.texture.atlas.bitmap.source.IBitmapTextureAtlasSource;
import org.andengine.opengl.texture.atlas.source.ITextureAtlasSource;
import org.andengine.opengl.texture.bitmap.BitmapTextureFormat;
@@ -123,8 +124,8 @@ public BitmapTextureFormat getBitmapTextureFormat() {
// ===========================================================
@Override
- public void addEmptyTextureAtlasSource(final int pTextureX, final int pTextureY, final int pWidth, final int pHeight) {
- this.addTextureAtlasSource(new EmptyBitmapTextureAtlasSource(pWidth, pHeight), pTextureX, pTextureY);
+ public void addExtrudingTextureAtlasSource(final int pTextureX, final int pTextureY, final int pWidth, final int pHeight, final ITextureAtlasSource pExtrusionSource, final ExtrusionDirection pExtrusionDirection, final int pExtrusionSize) {
+ this.addTextureAtlasSource(new ExtrudingBitmapTextureAtlasSource(pWidth, pHeight, pExtrusionSource, pExtrusionDirection, pExtrusionSize), pTextureX, pTextureY);
}
// ===========================================================
@@ -156,6 +157,23 @@ protected void writeTextureToHardware(final GLState pGLState) {
throw new NullBitmapException("Caused by: " + bitmapTextureAtlasSource.getClass().toString() + " --> " + bitmapTextureAtlasSource.toString() + " returned a null Bitmap.");
}
+ /*
+ * Handle special case of extruding edges of a Bitmap.
+ * ExtrudingBitmapTextureAtlasSource expects to be fed with a
+ * Bitmap before it can return correct bitmap via onLoadBitmap()
+ */
+ if (false == (bitmapTextureAtlasSource instanceof ExtrudingBitmapTextureAtlasSource)) {
+ // There can be 4 extrusions made for a single texture region
+ for(int j = (i + 1); j <= (i + 4); j++) {
+ if ((j < textureSources.size()) && textureSources.get(j) instanceof ExtrudingBitmapTextureAtlasSource) {
+ ExtrudingBitmapTextureAtlasSource extruder = (ExtrudingBitmapTextureAtlasSource) textureSources.get(j);
+ if (extruder.getExtrusionSource() == bitmapTextureAtlasSource) {
+ extruder.createExtrusionBitmap(bitmap);
+ }
+ }
+ }
+ }
+
final boolean useDefaultAlignment = MathUtils.isPowerOfTwo(bitmap.getWidth()) && MathUtils.isPowerOfTwo(bitmap.getHeight()) && pixelFormat == PixelFormat.RGBA_8888;
if(!useDefaultAlignment) {
/* Adjust unpack alignment. */
View
130 src/org/andengine/opengl/texture/atlas/bitmap/source/ExtrudingBitmapTextureAtlasSource.java
@@ -0,0 +1,130 @@
+package org.andengine.opengl.texture.atlas.bitmap.source;
+
+
+import org.andengine.opengl.texture.atlas.source.BaseTextureAtlasSource;
+import org.andengine.opengl.texture.atlas.source.ITextureAtlasSource;
+import org.andengine.util.debug.Debug;
+import org.andengine.util.exception.NullBitmapException;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Matrix;
+
+/**
+ * (c) 2010 Nicolas Gramlich
+ * (c) 2011 Zynga Inc.
+ *
+ * @author Michal Stawinski
+ * @since 02:20:33 - 03.05.2012
+ */
+public class ExtrudingBitmapTextureAtlasSource extends BaseTextureAtlasSource implements IBitmapTextureAtlasSource {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+ private final ExtrusionDirection mExtrusionDirection;
+ private final ITextureAtlasSource mExtrusionSource;
+ private final int mExtrusionSize;
+ private Bitmap mExtrusionBitmap;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+
+ public ExtrudingBitmapTextureAtlasSource(final int pTextureWidth, final int pTextureHeight,
+ final ITextureAtlasSource pExtrusionSource, final ExtrusionDirection pExtrusionDirection, final int pExtrusionSize) {
+ this(0, 0, pTextureWidth, pTextureHeight, pExtrusionSource, pExtrusionDirection, pExtrusionSize);
+ }
+
+ public ExtrudingBitmapTextureAtlasSource(final int pTextureX, final int pTextureY, final int pTextureWidth, final int pTextureHeight,
+ ITextureAtlasSource pExtrusionSource, ExtrusionDirection pExtrusionDirection, final int pExtrusionSize) {
+ super(pTextureX, pTextureY, pTextureWidth, pTextureHeight);
+ mExtrusionDirection = pExtrusionDirection;
+ mExtrusionSource = pExtrusionSource;
+ mExtrusionSize = pExtrusionSize;
+ }
+
+ @Override
+ public ExtrudingBitmapTextureAtlasSource deepCopy() {
+ return new ExtrudingBitmapTextureAtlasSource(this.mTextureX, this.mTextureY, this.mTextureWidth, this.mTextureHeight, mExtrusionSource, mExtrusionDirection, mExtrusionSize);
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+ public ITextureAtlasSource getExtrusionSource() {
+ return mExtrusionSource;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public Bitmap onLoadBitmap(final Config pBitmapConfig) {
+ if (mExtrusionBitmap != null && !mExtrusionBitmap.isRecycled()) {
+ return mExtrusionBitmap;
+ }
+
+ return Bitmap.createBitmap(this.mTextureWidth, this.mTextureHeight, pBitmapConfig);
+ }
+
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName() + "(" + this.mTextureWidth + " x " + this.mTextureHeight + ")";
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ public void createExtrusionBitmap(final Bitmap pBitmapToExtrude) {
+ if (mExtrusionBitmap != null && !mExtrusionBitmap.isRecycled()) {
+ Debug.w("Someone did not clean up mExtrusionBitmap! Doing it now.");
+ mExtrusionBitmap.recycle();
+ }
+
+ if (getTextureHeight() == pBitmapToExtrude.getHeight() && pBitmapToExtrude.getWidth() < mExtrusionSize) {
+ throw new NullBitmapException("BitmapToExtrude is only " + pBitmapToExtrude.getWidth() + " pixels wide, but ExtrusionSize was set to " + mExtrusionSize);
+ } else if (getTextureWidth() == pBitmapToExtrude.getWidth() && pBitmapToExtrude.getHeight() < mExtrusionSize) {
+ throw new NullBitmapException("BitmapToExtrude is only " + pBitmapToExtrude.getWidth() + " pixels high, but ExtrusionSize was set to " + mExtrusionSize);
+ } else if (getTextureWidth() != pBitmapToExtrude.getWidth() && getTextureHeight() != pBitmapToExtrude.getHeight()) {
+ throw new NullBitmapException("BitmapToExtrude does not match" + getClass().getSimpleName());
+ }
+
+ final Matrix flippingMatrix = new Matrix();
+
+ switch (mExtrusionDirection) {
+ case LEFT:
+ flippingMatrix.preScale(-1, 1);
+ mExtrusionBitmap = Bitmap.createBitmap(pBitmapToExtrude, 0, 0, mExtrusionSize, pBitmapToExtrude.getHeight(), flippingMatrix, false);
+ break;
+ case TOP:
+ flippingMatrix.preScale(1, -1);
+ mExtrusionBitmap = Bitmap.createBitmap(pBitmapToExtrude, 0, 0, pBitmapToExtrude.getWidth(), mExtrusionSize, flippingMatrix, false);
+ break;
+ case RIGHT:
+ flippingMatrix.preScale(-1, 1);
+ mExtrusionBitmap = Bitmap.createBitmap(pBitmapToExtrude, pBitmapToExtrude.getWidth() - mExtrusionSize - 1, 0, mExtrusionSize, pBitmapToExtrude.getHeight(), flippingMatrix, false);
+ break;
+ case BOTTOM:
+ flippingMatrix.preScale(1, -1);
+ mExtrusionBitmap = Bitmap.createBitmap(pBitmapToExtrude, 0, pBitmapToExtrude.getHeight() - mExtrusionSize - 1, pBitmapToExtrude.getWidth(), mExtrusionSize, flippingMatrix, false);
+ break;
+ }
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+ public static enum ExtrusionDirection {
+ TOP,
+ BOTTOM,
+ LEFT,
+ RIGHT
+ }
+}
View
5 src/org/andengine/opengl/texture/atlas/buildable/BuildableTextureAtlas.java
@@ -8,6 +8,7 @@
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.ITextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BuildableBitmapTextureAtlas;
+import org.andengine.opengl.texture.atlas.bitmap.source.ExtrudingBitmapTextureAtlasSource.ExtrusionDirection;
import org.andengine.opengl.texture.atlas.buildable.builder.ITextureAtlasBuilder;
import org.andengine.opengl.texture.atlas.buildable.builder.ITextureAtlasBuilder.TextureAtlasBuilderException;
import org.andengine.opengl.texture.atlas.source.ITextureAtlasSource;
@@ -209,8 +210,8 @@ public void setTextureAtlasStateListener(final ITextureAtlasStateListener<S> pTe
// ===========================================================
@Override
- public void addEmptyTextureAtlasSource(final int pTextureX, final int pTextureY, final int pWidth, final int pHeight) {
- this.mTextureAtlas.addEmptyTextureAtlasSource(pTextureX, pTextureY, pWidth, pHeight);
+ public void addExtrudingTextureAtlasSource(final int pTextureX, final int pTextureY, final int pWidth, final int pHeight, final ITextureAtlasSource pExtrusionSource, final ExtrusionDirection pExtrusionDirection, final int pExtrusionSize) {
+ this.mTextureAtlas.addExtrudingTextureAtlasSource(pTextureX, pTextureY, pWidth, pHeight, pExtrusionSource, pExtrusionDirection, pExtrusionSize);
}
@Override
Something went wrong with that request. Please try again.