/** * Creates a texture with this image's bitmap data using {@code config}. NOTE: this creates a new * texture with every call. This is generally only needed if you plan to create multiple textures * from the same bitmap, with different configurations. Otherwise just use {@link #texture} to * create the image's "default" texture which will be shared by all callers. */ public Texture createTexture (Texture.Config config) { if (!isLoaded()) throw new IllegalStateException( "Cannot create texture from unready image: " + this); int texWidth = config.toTexWidth(pixelWidth()); int texHeight = config.toTexHeight(pixelHeight()); if (texWidth <= 0 || texHeight <= 0) throw new IllegalArgumentException( "Invalid texture size: " + texWidth + "x" + texHeight + " from: " + this); Texture tex = new Texture(gfx, gfx.createTexture(config), config, texWidth, texHeight, scale(), width(), height()); tex.update(this); // this will handle non-POT source image conversion return tex; }
/** Informs this layer that a drawing operation has just completed. The backing canvas image data * is uploaded to the GPU. */ public void end () { Texture tex = (Texture)tile(); Image image = canvas.image; // if our texture is already the right size, just update it if (tex != null && tex.pixelWidth == image.pixelWidth() && tex.pixelHeight == image.pixelHeight()) tex.update(image); // otherwise we need to create a new texture (setTexture will unreference the old texture which // will cause it to be destroyed) else super.setTile(canvas.image.createTexture(Texture.Config.DEFAULT)); }
Image text = new Image(clickToStartRegion); Float fadeTime = 1f; //... text.addAction(Actions.alpha(0)); //make the text transparent. text.act(0); //update the text once text.addAction(Actions.sequence(Actions.fadeIn(fadeTime), Actions.fadeOut(fadeTime)); //... text.act(deltaTime); //... text.draw(batch, 1);
/** * This image's width in display units. If this image is loaded asynchrously, this will return * 0 until loading is complete. See {@link #state}. */ public float width () { return scale().invScaled(pixelWidth()); }
@Override public void init () { game.assets.getImage("images/orange.png").state.onSuccess(orange -> { Texture otex = orange.texture(); float dx = orange.width() + 25; game.rootLayer.addAt(new ImageLayer(otex), 25, 25); rotBatch.eyeY = orange.height()/2; Canvas canvas = game.graphics.createCanvas(orange.width(), orange.height()); canvas.setFillColor(0xFF99CCFF).fillRect(0, 0, canvas.width, canvas.height); canvas.draw(orange, 0, 0); ImageLayer rotlayer = new ImageLayer(canvas.toTexture()); rotlayer.setBatch(rotBatch); game.rootLayer.addAt(rotlayer, 25 + 2*dx + orange.width(), 25); game.rootLayer.addAt(irotlayer, 25 + 3*dx + orange.width(), 25);
@Override public void paint(Canvas canvas, float parentAlpha) { if (!visible() || img == null || !img.isReady()) return; canvas.save(); canvas.setAlpha(parentAlpha * alpha()); transform(canvas); float width = width(), height = height(); boolean repX = img.repeatX(), repY = img.repeatY(); if (repX || repY) { if (pattern == null || repX != patternRepeatX || repY != patternRepeatY) { patternRepeatX = repX; patternRepeatY = repY; pattern = img.toPattern(); } canvas.setFillPattern(pattern); float xScale = repX ? 1 : width / img.width(), yScale = repY ? 1 : height / img.height(); canvas.scale(xScale, yScale); canvas.fillRect(0, 0, width / xScale, height / yScale); } else { canvas.drawImage(img, 0, 0, width, height); } canvas.restore(); } }
Texture otex = orange.texture(); fragment("Image", otex, 250, 10); float pw = orange.width(), ph = orange.height(), phw = pw/2, phh = ph/2; Tile otile = otex.tile(0, phh/2, pw, phh); Canvas split = game.graphics.createCanvas(orange.width(), orange.height()); split.draw(orange.region( 0, 0, phw, phh), phw, phh); split.draw(orange.region(phw, 0, phw, phh), 0, phh); split.draw(orange.region( 0, phh, phw, phh), phw, 0); split.draw(orange.region(phw, phh, phw, phh), 0, 0); addTest(140, 10, new ImageLayer(split.toTexture()), "Canvas draw Image.Region", 80); osci.region = new Rectangle(0, 0, orange.width(), orange.height()); addTest(10, 150, osci, "ImageLayer with changing width", 100);
protected void fragment(String source, Image image, float ox, float oy) { float hw = image.width()/2f, hh = image.height()/2f; Image ul = image.subImage(0, 0, hw, hh); Image ur = image.subImage(hw, 0, hw, hh); Image ll = image.subImage(0, hh, hw, hh); Image lr = image.subImage(hw, hh, hw, hh); Image ctr = image.subImage(hw/2, hh/2, hw, hh); float dx = hw + 10, dy = hh + 10; GroupLayer group = graphics().createGroupLayer(); group.addAt(graphics().createImageLayer(ul), 0, 0); group.addAt(graphics().createImageLayer(ur), dx, 0); group.addAt(graphics().createImageLayer(ll), 0, dy); group.addAt(graphics().createImageLayer(lr), dx, dy); group.addAt(graphics().createImageLayer(ctr), dx/2, 2*dy); float xoff = image.width() + 20; group.addAt(scaleLayer(graphics().createImageLayer(ul), 2), xoff, 0); group.addAt(scaleLayer(graphics().createImageLayer(ur), 2), xoff+2*dx, 0); group.addAt(scaleLayer(graphics().createImageLayer(ll), 2), xoff, 2*dy); group.addAt(scaleLayer(graphics().createImageLayer(lr), 2), xoff+2*dx, 2*dy); graphics().rootLayer().addAt(group, ox, oy); addDescrip(source + " split into subimages, and scaled", ox, oy + image.height()*2 + 25, 3*image.width()+40); }
protected static ByteBuffer getRgba(Image image) { int w = (int) image.width(), h = (int) image.height(), size = w * h; int[] rawPixels = new int[size]; ByteBuffer pixels = ByteBuffer.allocateDirect(size * 4); pixels.order(ByteOrder.nativeOrder()); IntBuffer rgba = pixels.asIntBuffer(); image.getRgb(0, 0, w, h, rawPixels, 0, w); for (int i = 0; i < size; i++) { int argb = rawPixels[i]; // Order is inverted because this is read as a byte array, and we store intel ints. rgba.put(i, ((argb >> 16) & 0x0ff) | (argb & 0x0ff00ff00) | ((argb & 0xff) << 16)); } return pixels; }
float phwidth = princess.width()/2f, phheight = princess.height()/2f; ImageLayer player1 = new ImageLayer(princess); player1.setOrigin(phwidth, phheight); game.rootLayer.addAt(player1, 100, 100); ImageLayer player2 = new ImageLayer(princess.createTexture(MIPMAPPED)); player2.setOrigin(phwidth, phheight); game.rootLayer.addAt(player2, 250, 100); float shwidth = star.width()/2, shheight = star.height()/2; ImageLayer slayer1 = new ImageLayer(star); slayer1.setOrigin(shwidth, shheight); game.rootLayer.addAt(slayer1, 100, 250); ImageLayer slayer2 = new ImageLayer(star.createTexture(MIPMAPPED)); slayer2.setOrigin(shwidth, shheight); game.rootLayer.addAt(slayer2, 250, 250);
// look for all (x,y) positions where target appears in desktop List<Loc> findMatches(Image desktop, Image target, float threshold) { List<Loc> locs; for (int y=0; y<desktop.height()-target.height(); y++) { for (int x=0; x<desktop.width()-target.width(); x++) { if (imageDistance(desktop, x, y, target) < threshold) { locs.append(Loc(x,y)); } } } return locs; } // computes the root mean squared error between a rectangular window in // bigImg and target. float imageDistance(Image bigImg, int bx, int by, Image target) { float dist = 0.0; for (int y=0; y<target.height(); y++) { for (int x=0; x<target.width(); x++) { // assume RGB images... for (int colorChannel=0; colorChannel<3; colorChannel++) { dist += Math.pow(target.getPixel(x,y) - bigImg.getPixel(bx+x,by+y), 2); } } } return Math.sqrt(dist) / target.width() / target.height(); }
/** * This image's height in display units. If this image is loaded asynchrously, this will return * 0 until loading is complete. See {@link #state}. */ public float height () { return scale().invScaled(pixelHeight()); }
/** Uploads {@code image} to this texture's GPU memory. {@code image} must have the exact same * size as this texture and must be fully loaded. This is generally useful for updating a * texture which was created from a canvas when the canvas has been changed. */ public void update (Image image) { // if we're a repeating texture (or we want mipmaps) and this image is non-POT on the relevant // axes, we need to scale it before we upload it; we'll just do this on the CPU since it feels // like creating a second texture, a frame buffer to render into it, sending a GPU batch and // doing all the blah blah blah is going to be more expensive overall if (config.repeatX || config.repeatY || config.mipmaps) { int pixWidth = image.pixelWidth(), pixHeight = image.pixelHeight(); int potWidth = config.toTexWidth(pixWidth), potHeight = config.toTexWidth(pixHeight); if (potWidth != pixWidth || potHeight != pixHeight) { Canvas scaled = gfx.createCanvasImpl(Scale.ONE, potWidth, potHeight); scaled.draw(image, 0, 0, potWidth, potHeight); scaled.image.upload(gfx, this); scaled.close(); } else image.upload(gfx, this); // fast path, woo! } else image.upload(gfx, this); // fast path, woo! if (config.mipmaps) gfx.gl.glGenerateMipmap(GL_TEXTURE_2D); }
@Override public Tile tile () { return texture(); } @Override public RFuture<Tile> tileAsync () {
@Override public Image snapshot() { Bitmap bitmap = ((AndroidImage)this.image).bitmap(); return new AndroidImage(gfx, image.scale(), bitmap.copy(bitmap.getConfig(), false), "<canvas>"); }
@Override public float height() { if (heightSet) return height; assert img != null : "Image has not yet been set"; return img.height(); }
protected Entity createAsteroid (Size sz, float x, float y, float vx, float vy) { Entity ast = create(true); ast.add(type, size, sprite, opos, pos, vel, spin, radius); float side = sz.size; int iidx = rando.getInt(8); float ah = asteroids.height(); ImageLayer layer = new ImageLayer(asteroids.region(iidx*ah, 0, ah, ah)); layer.setOrigin(ah/2, ah/2); layer.setScale(side/ah); layer.setRotation(rando.getFloat(MathUtil.TAU)); int id = ast.id; type.set(id, ASTEROID); size.set(id, sz); sprite.set(id, layer); spin.set(id, rando.getInRange(-MAXSPIN, MAXSPIN)); opos.set(id, x, y); pos.set(id, x, y); vel.set(id, vx, vy); radius.set(id, side*0.425f); return ast; }
/** A helper function for creating a texture from this canvas's image, and then disposing this * canvas. This is useful for situations where you create a canvas, draw something in it, turn * it into a texture and then never use the canvas again. */ public Texture toTexture (Texture.Config config) { try { return image.createTexture(config); } finally { close(); } }
/** * Adds an image resource to be watched. */ public void add(Image image) { assert !start || listener == null; ++total; image.addCallback(callback); }