Home | History | Annotate | Download | only in g2d
      1 /*******************************************************************************
      2  * Copyright 2011 See AUTHORS file.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *   http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  ******************************************************************************/
     16 
     17 package com.badlogic.gdx.graphics.g2d;
     18 
     19 import com.badlogic.gdx.graphics.Texture;
     20 
     21 /** Defines a rectangular area of a texture. The coordinate system used has its origin in the upper left corner with the x-axis
     22  * pointing to the right and the y axis pointing downwards.
     23  * @author mzechner
     24  * @author Nathan Sweet */
     25 public class TextureRegion {
     26 	Texture texture;
     27 	float u, v;
     28 	float u2, v2;
     29 	int regionWidth, regionHeight;
     30 
     31 	/** Constructs a region with no texture and no coordinates defined. */
     32 	public TextureRegion () {
     33 	}
     34 
     35 	/** Constructs a region the size of the specified texture. */
     36 	public TextureRegion (Texture texture) {
     37 		if (texture == null) throw new IllegalArgumentException("texture cannot be null.");
     38 		this.texture = texture;
     39 		setRegion(0, 0, texture.getWidth(), texture.getHeight());
     40 	}
     41 
     42 	/** @param width The width of the texture region. May be negative to flip the sprite when drawn.
     43 	 * @param height The height of the texture region. May be negative to flip the sprite when drawn. */
     44 	public TextureRegion (Texture texture, int width, int height) {
     45 		this.texture = texture;
     46 		setRegion(0, 0, width, height);
     47 	}
     48 
     49 	/** @param width The width of the texture region. May be negative to flip the sprite when drawn.
     50 	 * @param height The height of the texture region. May be negative to flip the sprite when drawn. */
     51 	public TextureRegion (Texture texture, int x, int y, int width, int height) {
     52 		this.texture = texture;
     53 		setRegion(x, y, width, height);
     54 	}
     55 
     56 	public TextureRegion (Texture texture, float u, float v, float u2, float v2) {
     57 		this.texture = texture;
     58 		setRegion(u, v, u2, v2);
     59 	}
     60 
     61 	/** Constructs a region with the same texture and coordinates of the specified region. */
     62 	public TextureRegion (TextureRegion region) {
     63 		setRegion(region);
     64 	}
     65 
     66 	/** Constructs a region with the same texture as the specified region and sets the coordinates relative to the specified region.
     67 	 * @param width The width of the texture region. May be negative to flip the sprite when drawn.
     68 	 * @param height The height of the texture region. May be negative to flip the sprite when drawn. */
     69 	public TextureRegion (TextureRegion region, int x, int y, int width, int height) {
     70 		setRegion(region, x, y, width, height);
     71 	}
     72 
     73 	/** Sets the texture and sets the coordinates to the size of the specified texture. */
     74 	public void setRegion (Texture texture) {
     75 		this.texture = texture;
     76 		setRegion(0, 0, texture.getWidth(), texture.getHeight());
     77 	}
     78 
     79 	/** @param width The width of the texture region. May be negative to flip the sprite when drawn.
     80 	 * @param height The height of the texture region. May be negative to flip the sprite when drawn. */
     81 	public void setRegion (int x, int y, int width, int height) {
     82 		float invTexWidth = 1f / texture.getWidth();
     83 		float invTexHeight = 1f / texture.getHeight();
     84 		setRegion(x * invTexWidth, y * invTexHeight, (x + width) * invTexWidth, (y + height) * invTexHeight);
     85 		regionWidth = Math.abs(width);
     86 		regionHeight = Math.abs(height);
     87 	}
     88 
     89 	public void setRegion (float u, float v, float u2, float v2) {
     90 		int texWidth = texture.getWidth(), texHeight = texture.getHeight();
     91 		regionWidth = Math.round(Math.abs(u2 - u) * texWidth);
     92 		regionHeight = Math.round(Math.abs(v2 - v) * texHeight);
     93 
     94 		// For a 1x1 region, adjust UVs toward pixel center to avoid filtering artifacts on AMD GPUs when drawing very stretched.
     95 		if (regionWidth == 1 && regionHeight == 1) {
     96 			float adjustX = 0.25f / texWidth;
     97 			u += adjustX;
     98 			u2 -= adjustX;
     99 			float adjustY = 0.25f / texHeight;
    100 			v += adjustY;
    101 			v2 -= adjustY;
    102 		}
    103 
    104 		this.u = u;
    105 		this.v = v;
    106 		this.u2 = u2;
    107 		this.v2 = v2;
    108 	}
    109 
    110 	/** Sets the texture and coordinates to the specified region. */
    111 	public void setRegion (TextureRegion region) {
    112 		texture = region.texture;
    113 		setRegion(region.u, region.v, region.u2, region.v2);
    114 	}
    115 
    116 	/** Sets the texture to that of the specified region and sets the coordinates relative to the specified region. */
    117 	public void setRegion (TextureRegion region, int x, int y, int width, int height) {
    118 		texture = region.texture;
    119 		setRegion(region.getRegionX() + x, region.getRegionY() + y, width, height);
    120 	}
    121 
    122 	public Texture getTexture () {
    123 		return texture;
    124 	}
    125 
    126 	public void setTexture (Texture texture) {
    127 		this.texture = texture;
    128 	}
    129 
    130 	public float getU () {
    131 		return u;
    132 	}
    133 
    134 	public void setU (float u) {
    135 		this.u = u;
    136 		regionWidth = Math.round(Math.abs(u2 - u) * texture.getWidth());
    137 	}
    138 
    139 	public float getV () {
    140 		return v;
    141 	}
    142 
    143 	public void setV (float v) {
    144 		this.v = v;
    145 		regionHeight = Math.round(Math.abs(v2 - v) * texture.getHeight());
    146 	}
    147 
    148 	public float getU2 () {
    149 		return u2;
    150 	}
    151 
    152 	public void setU2 (float u2) {
    153 		this.u2 = u2;
    154 		regionWidth = Math.round(Math.abs(u2 - u) * texture.getWidth());
    155 	}
    156 
    157 	public float getV2 () {
    158 		return v2;
    159 	}
    160 
    161 	public void setV2 (float v2) {
    162 		this.v2 = v2;
    163 		regionHeight = Math.round(Math.abs(v2 - v) * texture.getHeight());
    164 	}
    165 
    166 	public int getRegionX () {
    167 		return Math.round(u * texture.getWidth());
    168 	}
    169 
    170 	public void setRegionX (int x) {
    171 		setU(x / (float)texture.getWidth());
    172 	}
    173 
    174 	public int getRegionY () {
    175 		return Math.round(v * texture.getHeight());
    176 	}
    177 
    178 	public void setRegionY (int y) {
    179 		setV(y / (float)texture.getHeight());
    180 	}
    181 
    182 	/** Returns the region's width. */
    183 	public int getRegionWidth () {
    184 		return regionWidth;
    185 	}
    186 
    187 	public void setRegionWidth (int width) {
    188 		if (isFlipX()) {
    189 			setU(u2 + width / (float)texture.getWidth());
    190 		} else {
    191 			setU2(u + width / (float)texture.getWidth());
    192 		}
    193 	}
    194 
    195 	/** Returns the region's height. */
    196 	public int getRegionHeight () {
    197 		return regionHeight;
    198 	}
    199 
    200 	public void setRegionHeight (int height) {
    201 		if (isFlipY()) {
    202 			setV(v2 + height / (float)texture.getHeight());
    203 		} else {
    204 			setV2(v + height / (float)texture.getHeight());
    205 		}
    206 	}
    207 
    208 	public void flip (boolean x, boolean y) {
    209 		if (x) {
    210 			float temp = u;
    211 			u = u2;
    212 			u2 = temp;
    213 		}
    214 		if (y) {
    215 			float temp = v;
    216 			v = v2;
    217 			v2 = temp;
    218 		}
    219 	}
    220 
    221 	public boolean isFlipX () {
    222 		return u > u2;
    223 	}
    224 
    225 	public boolean isFlipY () {
    226 		return v > v2;
    227 	}
    228 
    229 	/** Offsets the region relative to the current region. Generally the region's size should be the entire size of the texture in
    230 	 * the direction(s) it is scrolled.
    231 	 * @param xAmount The percentage to offset horizontally.
    232 	 * @param yAmount The percentage to offset vertically. This is done in texture space, so up is negative. */
    233 	public void scroll (float xAmount, float yAmount) {
    234 		if (xAmount != 0) {
    235 			float width = (u2 - u) * texture.getWidth();
    236 			u = (u + xAmount) % 1;
    237 			u2 = u + width / texture.getWidth();
    238 		}
    239 		if (yAmount != 0) {
    240 			float height = (v2 - v) * texture.getHeight();
    241 			v = (v + yAmount) % 1;
    242 			v2 = v + height / texture.getHeight();
    243 		}
    244 	}
    245 
    246 	/** Helper function to create tiles out of this TextureRegion starting from the top left corner going to the right and ending at
    247 	 * the bottom right corner. Only complete tiles will be returned so if the region's width or height are not a multiple of the
    248 	 * tile width and height not all of the region will be used. This will not work on texture regions returned form a TextureAtlas
    249 	 * that either have whitespace removed or where flipped before the region is split.
    250 	 *
    251 	 * @param tileWidth a tile's width in pixels
    252 	 * @param tileHeight a tile's height in pixels
    253 	 * @return a 2D array of TextureRegions indexed by [row][column]. */
    254 	public TextureRegion[][] split (int tileWidth, int tileHeight) {
    255 		int x = getRegionX();
    256 		int y = getRegionY();
    257 		int width = regionWidth;
    258 		int height = regionHeight;
    259 
    260 		int rows = height / tileHeight;
    261 		int cols = width / tileWidth;
    262 
    263 		int startX = x;
    264 		TextureRegion[][] tiles = new TextureRegion[rows][cols];
    265 		for (int row = 0; row < rows; row++, y += tileHeight) {
    266 			x = startX;
    267 			for (int col = 0; col < cols; col++, x += tileWidth) {
    268 				tiles[row][col] = new TextureRegion(texture, x, y, tileWidth, tileHeight);
    269 			}
    270 		}
    271 
    272 		return tiles;
    273 	}
    274 
    275 	/** Helper function to create tiles out of the given {@link Texture} starting from the top left corner going to the right and
    276 	 * ending at the bottom right corner. Only complete tiles will be returned so if the texture's width or height are not a
    277 	 * multiple of the tile width and height not all of the texture will be used.
    278 	 *
    279 	 * @param texture the Texture
    280 	 * @param tileWidth a tile's width in pixels
    281 	 * @param tileHeight a tile's height in pixels
    282 	 * @return a 2D array of TextureRegions indexed by [row][column]. */
    283 	public static TextureRegion[][] split (Texture texture, int tileWidth, int tileHeight) {
    284 		TextureRegion region = new TextureRegion(texture);
    285 		return region.split(tileWidth, tileHeight);
    286 	}
    287 }
    288