Commits

Chuck Adams  committed 768015d

added subpixel blit

  • Participants
  • Parent commits 1a0896d

Comments (0)

Files changed (5)

File src/main/java/net/fishbulb/jcod/demo/Demo.java

         add(Offscreen.class);
         add(Lines.class);
         add(Noise.class);
+        add(Image.class);
     }};
 
     Iterator<Class<? extends DemoApplet>> applets = Iterators.cycle(allApplets);

File src/main/java/net/fishbulb/jcod/demo/Image.java

+package net.fishbulb.jcod.demo;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.graphics.Pixmap;
+import net.fishbulb.jcod.Console;
+import net.fishbulb.jcod.util.ImageUtils;
+
+public class Image extends DemoApplet {
+    private long lastUpdate;
+
+    Pixmap star;
+    public Image(Console parent) {
+        super(parent);
+
+        star = new Pixmap(Gdx.files.internal("star.png"));
+    }
+
+    @Override public void update() {
+        long now = System.currentTimeMillis();
+        long updateMillis = 30;
+        if ((now - lastUpdate) < updateMillis) return;
+        lastUpdate = now;
+        console.clear();
+
+        ImageUtils.imageBlit2x(star,console,0,0,0,0,48,48);
+
+    }
+}

File src/main/java/net/fishbulb/jcod/util/ColorUtils.java

     public static Color lerp(Color from, Color to, float coef) {
         return lerp(from, to, coef, new Color());
     }
+
+    /**
+     * Returns a float between [0,1] giving the Euclidian distance between two colors in RGB space (alpha is ignored).
+     * Note that this is really only useful for colors that have similar hues already.  For something closer to what
+     * human vision considers "color similarity", you'll want to look into the (very complex) CIEDE formulas.
+     *
+     * @param c1 first color
+     * @param c2 second color
+     * @return distance between c1 and c2
+     */
+    public static float rgbdist(Color c1, Color c2) {
+        float dr = c1.r - c2.r;
+        float dg = c1.g - c2.g;
+        float db = c1.b - c2.b;
+        return dr * dr + dg * dg + db * db;
+    }
+
 }

File src/main/java/net/fishbulb/jcod/util/ImageUtils.java

 
 import com.badlogic.gdx.graphics.Color;
 import com.badlogic.gdx.graphics.Pixmap;
+import net.fishbulb.jcod.Console;
 
 import java.nio.ByteBuffer;
 import java.nio.IntBuffer;
 
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+import static net.fishbulb.jcod.util.ColorUtils.lerp;
+import static net.fishbulb.jcod.util.ColorUtils.rgbdist;
+
 public final class ImageUtils {
 
     private ImageUtils() {}
         return grayScaleToAlpha(pixmap, false);     // default blend mode in SpriteBatch assumes non-premultiplied
     }
 
+    private static int getPattern(Color[] desired, Color[] palette) {
+        // adapted from Jeff Lait's code posted on r.g.r.d
+        int flag = 0;
 
+        // pixels have following flag values :
+        // X 1
+        // 2 4
+        // flag indicates which pixels uses foreground color (palette[1])
+
+        int[] flagToAscii = {
+                0,
+                CharCodes.OEM.SUBP_NE, CharCodes.OEM.SUBP_SW, -CharCodes.OEM.SUBP_DIAG, CharCodes.OEM.SUBP_SE,
+                CharCodes.OEM.SUBP_E, -CharCodes.OEM.SUBP_N, -CharCodes.OEM.SUBP_NW
+        };
+
+        int[] weight = {0, 0};
+        int i;
+
+        // First colour trivial.
+        palette[0] = desired[0];
+
+        // Ignore all duplicates...
+        for (i = 1; i < 4; i++) {
+            if (desired[i].r != palette[0].r || desired[i].g != palette[0].g || desired[i].b != palette[0].b)
+                break;
+        }
+
+        if (i == 4) {
+            return ' ';
+        }
+
+        weight[0] = i;
+
+        // Found a second colour...
+        palette[1] = desired[i];
+        weight[1] = 1;
+        flag |= 1 << (i - 1);
+
+        // remaining colours
+        i++;
+        while (i < 4) {
+            if (desired[i].r == palette[0].r && desired[i].g == palette[0].g && desired[i].b == palette[0].b) {
+                weight[0]++;
+            } else if (desired[i].r == palette[1].r && desired[i].g == palette[1].g && desired[i].b == palette[1].b) {
+                flag |= 1 << (i - 1);
+                weight[1]++;
+            } else {
+                // Bah, too many colours,
+                // merge the two nearest
+                float dist0i = rgbdist(desired[i], palette[0]);
+                float dist1i = rgbdist(desired[i], palette[1]);
+                float dist01 = rgbdist(palette[0], palette[1]);
+                if (dist0i < dist1i) {
+                    if (dist0i <= dist01) {
+                        // merge 0 and i
+                        palette[0] = lerp(desired[i], palette[0], weight[0] / (1.0f + weight[0]));
+                        weight[0]++;
+                    } else {
+                        // merge 0 and 1
+                        palette[0] = lerp(palette[0], palette[1], (float) (weight[1]) / (weight[0] + weight[1]));
+                        weight[0]++;
+                        palette[1] = desired[i];
+                        flag = 1 << (i - 1);
+                    }
+                } else {
+                    if (dist1i <= dist01) {
+                        // merge 1 and i
+                        palette[1] = lerp(desired[i], palette[1], weight[1] / (1.0f + weight[1]));
+                        weight[1]++;
+                        flag |= 1 << (i - 1);
+                    } else {
+                        // merge 0 and 1
+                        palette[0] = lerp(palette[0], palette[1], (float) (weight[1]) / (weight[0] + weight[1]));
+                        weight[0]++;
+                        palette[1] = desired[i];
+                        flag = 1 << (i - 1);
+                    }
+                }
+            }
+            i++;
+        }
+        return flagToAscii[flag];
+    }
+
+
+    public static void imageBlit2x(Pixmap image, Console con, int dx, int dy, int sx, int sy, int w, int h) {
+        Color[] grid = {new Color(), new Color(), new Color(), new Color()};
+        Color[] cols = {new Color(), new Color()};
+        int ascii, cx, cy;
+
+        int maxx, maxy;
+
+        int width = image.getWidth();
+        int height = image.getHeight();
+
+        sx = max(0, sx);
+        sy = max(0, sy);
+        w = min(w, width - sx);
+        h = min(h, height - sy);
+
+        maxx = dx + w / 2 <= con.getWidth() ? w : (con.getWidth() - dx) * 2;
+        maxy = dy + h / 2 <= con.getHeight() ? h : (con.getHeight() - dy) * 2;
+        // check that the image is not blitted outside the console
+        if (!(dx + maxx / 2 >= 0 && dy + maxy / 2 >= 0 && dx < con.getWidth() && dy < con.getHeight()))
+            return;
+        maxx += sx;
+        maxy += sy;
+
+        int pixel;
+        for (cx = sx; cx < maxx; cx += 2) {
+            for (cy = sy; cy < maxy; cy += 2) {
+            /* get the 2x2 super pixel colors from the image */
+                int conx = dx + (cx - sx) / 2;
+                int cony = dy + (cy - sy) / 2;
+                Color consoleBack = con.getCharBackground(conx, cony);
+                // grid[0]=TCOD_image_get_pixel(image,cx,cy);
+                grid[0].set(consoleBack);
+                grid[1].set(consoleBack);
+                grid[2].set(consoleBack);
+                grid[3].set(consoleBack);
+                if (((pixel = image.getPixel(cx, cy)) & 0xff) != 0)
+                    Color.rgba8888ToColor(grid[0], pixel);
+
+                if (cx < maxx - 1 && (((pixel = image.getPixel(cx + 1, cy)) & 0xff) != 0))
+                    Color.rgba8888ToColor(grid[1], pixel);
+
+                if (cy < maxy - 1 && (((pixel = image.getPixel(cx, cy + 1)) & 0xff) != 0))
+                    Color.rgba8888ToColor(grid[2], pixel);
+
+                if (cy < maxy - 1 && cy < maxy - 1 && (((pixel = image.getPixel(cx + 1, cy + 1)) & 0xff) != 0))
+                    Color.rgba8888ToColor(grid[3], pixel);
+
+                ascii = getPattern(grid, cols);
+                if (ascii == ' ') {
+                    // single color
+                    con.setCharBackground(conx, cony, cols[0], BlendMode.Set);
+                    con.setChar(conx, cony, ' ');
+                } else {
+                    if (ascii >= 0) {
+                        con.setDefaultBackground(cols[0]);
+                        con.setDefaultForeground(cols[1]);
+                        con.putChar(conx, cony, (char) ascii, BlendMode.Set);
+
+                    } else {
+                        // negative ascii code means we need to invert back/fore colors
+                        con.setDefaultBackground(cols[1]);
+                        con.setDefaultForeground(cols[0]);
+                        con.putChar(conx, cony, (char) -ascii, BlendMode.Set);
+                    }
+                }
+            }
+        }
+    }
 }

File src/main/resources/star.png

Added
New image