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.tests; 18 19 import com.badlogic.gdx.Gdx; 20 import com.badlogic.gdx.graphics.Color; 21 import com.badlogic.gdx.graphics.GL20; 22 import com.badlogic.gdx.graphics.OrthographicCamera; 23 import com.badlogic.gdx.graphics.Texture; 24 import com.badlogic.gdx.graphics.g2d.PolygonRegion; 25 import com.badlogic.gdx.graphics.g2d.PolygonRegionLoader; 26 import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; 27 import com.badlogic.gdx.graphics.g2d.TextureRegion; 28 import com.badlogic.gdx.graphics.glutils.ShapeRenderer; 29 import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; 30 import com.badlogic.gdx.math.MathUtils; 31 import com.badlogic.gdx.math.Matrix4; 32 import com.badlogic.gdx.tests.utils.GdxTest; 33 import com.badlogic.gdx.utils.Disposable; 34 35 public class PolygonRegionTest extends GdxTest { 36 37 PolygonSpriteBatch batch; 38 PolygonRegionDebugRenderer debugRenderer; 39 40 Texture texture; 41 OrthographicCamera camera; 42 PolygonRegion region; 43 PolygonRegion region2; 44 45 boolean usePolygonBatch = true; 46 47 @Override create()48 public void create () { 49 texture = new Texture(Gdx.files.internal("data/tree.png")); 50 51 PolygonRegionLoader loader = new PolygonRegionLoader(); 52 region = loader.load(new TextureRegion(texture), Gdx.files.internal("data/tree.psh")); 53 54 // create a region from an arbitrary set of vertices (a triangle in this case) 55 region2 = new PolygonRegion(new TextureRegion(texture), new float[] {0, 0, 100, 100, 0, 100}, new short[] {0, 1, 2}); 56 57 camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); 58 camera.position.x = 0; 59 camera.position.y = 0; 60 61 batch = new PolygonSpriteBatch(); 62 debugRenderer = new PolygonRegionDebugRenderer(); 63 64 Gdx.input.setInputProcessor(this); 65 } 66 67 @Override resize(int width, int height)68 public void resize (int width, int height) { 69 camera.viewportWidth = width; 70 camera.viewportHeight = height; 71 camera.update(); 72 } 73 74 @Override render()75 public void render () { 76 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 77 Gdx.gl.glClearColor(0.25f, 0.25f, 0.25f, 1.0f); 78 79 camera.update(); 80 batch.setProjectionMatrix(camera.combined); 81 82 batch.begin(); 83 84 // draw bot regions side-by-side 85 float width = 256; 86 float x = -width; 87 batch.draw(region, x, -128, 256, 256); 88 batch.draw(region2, x + width + 10, -128, 256, 256); 89 90 batch.end(); 91 92 debugRenderer.setProjectionMatrix(camera.combined); 93 debugRenderer.draw(region, x, -128, 0, 0, 256, 256, 1, 1, 0); 94 debugRenderer.draw(region2, x + width + 10, -128, 0, 0, 256, 256, 1, 1, 0); 95 } 96 97 @Override dispose()98 public void dispose () { 99 debugRenderer.dispose(); 100 texture.dispose(); 101 batch.dispose(); 102 } 103 104 public class PolygonRegionDebugRenderer implements Disposable { 105 ShapeRenderer renderer; 106 PolygonRegionDebugRenderer()107 public PolygonRegionDebugRenderer () { 108 renderer = new ShapeRenderer(); 109 } 110 draw(PolygonRegion region, float x, float y, float originX, float originY, float width, float height, float scaleX, float scaleY, float rotation)111 public void draw (PolygonRegion region, float x, float y, float originX, float originY, float width, float height, 112 float scaleX, float scaleY, float rotation) { 113 114 float[] vertices = region.getVertices(); 115 short[] triangles = region.getTriangles(); 116 float[] textureCoords = region.getTextureCoords(); 117 118 // bottom left and top right corner points relative to origin 119 final float worldOriginX = x + originX; 120 final float worldOriginY = y + originY; 121 float sX = width / region.getRegion().getRegionWidth(); 122 float sY = height / region.getRegion().getRegionHeight(); 123 float fx1, fx2, fx3, px1, px2, px3; 124 float fy1, fy2, fy3, py1, py2, py3; 125 126 final float cos = MathUtils.cosDeg(rotation); 127 final float sin = MathUtils.sinDeg(rotation); 128 129 renderer.setColor(Color.RED); 130 renderer.begin(ShapeType.Line); 131 132 for (int i = 0, n = triangles.length; i < n; i += 3) { 133 int p1 = triangles[i] * 2; 134 int p2 = triangles[i + 1] * 2; 135 int p3 = triangles[i + 2] * 2; 136 fx1 = vertices[p1] * sX; 137 fy1 = vertices[p1 + 1] * sY; 138 fx2 = vertices[p2] * sX; 139 fy2 = vertices[p2 + 1] * sY; 140 fx3 = vertices[p3] * sX; 141 fy3 = vertices[p3 + 1] * sY; 142 143 fx1 -= originX; 144 fy1 -= originY; 145 fx2 -= originX; 146 fy2 -= originY; 147 fx3 -= originX; 148 fy3 -= originY; 149 150 if (scaleX != 1 || scaleY != 1) { 151 fx1 *= scaleX; 152 fy1 *= scaleY; 153 fx2 *= scaleX; 154 fy2 *= scaleY; 155 fx3 *= scaleX; 156 fy3 *= scaleY; 157 } 158 159 px1 = cos * fx1 - sin * fy1; 160 py1 = sin * fx1 + cos * fy1; 161 px2 = cos * fx2 - sin * fy2; 162 py2 = sin * fx2 + cos * fy2; 163 px3 = cos * fx3 - sin * fy3; 164 py3 = sin * fx3 + cos * fy3; 165 166 px1 += worldOriginX; 167 py1 += worldOriginY; 168 px2 += worldOriginX; 169 py2 += worldOriginY; 170 px3 += worldOriginX; 171 py3 += worldOriginY; 172 173 renderer.line(px1, py1, px2, py2); 174 renderer.line(px2, py2, px3, py3); 175 renderer.line(px3, py3, px1, py1); 176 } 177 178 renderer.end(); 179 180 renderer.setColor(Color.BLUE); 181 renderer.begin(ShapeType.Filled); 182 183 renderer.circle(worldOriginX, worldOriginY, 4); 184 185 renderer.end(); 186 187 // Calculate the bounding rect, is there a better way?! 188 // bottom left and top right corner points relative to origin 189 fx1 = -originX; 190 fy1 = -originY; 191 fx2 = width - originX; 192 fy2 = height - originY; 193 194 // scale 195 if (scaleX != 1 || scaleY != 1) { 196 fx1 *= scaleX; 197 fy1 *= scaleY; 198 fx2 *= scaleX; 199 fy2 *= scaleY; 200 } 201 202 // construct corner points, start from top left and go counter clockwise 203 final float p1x = fx1; 204 final float p1y = fy1; 205 final float p2x = fx1; 206 final float p2y = fy2; 207 final float p3x = fx2; 208 final float p3y = fy2; 209 final float p4x = fx2; 210 final float p4y = fy1; 211 212 float x1; 213 float y1; 214 float x2; 215 float y2; 216 float x3; 217 float y3; 218 float x4; 219 float y4; 220 221 // rotate 222 if (rotation != 0) { 223 x1 = cos * p1x - sin * p1y; 224 y1 = sin * p1x + cos * p1y; 225 226 x2 = cos * p2x - sin * p2y; 227 y2 = sin * p2x + cos * p2y; 228 229 x3 = cos * p3x - sin * p3y; 230 y3 = sin * p3x + cos * p3y; 231 232 x4 = x1 + (x3 - x2); 233 y4 = y3 - (y2 - y1); 234 } else { 235 x1 = p1x; 236 y1 = p1y; 237 238 x2 = p2x; 239 y2 = p2y; 240 241 x3 = p3x; 242 y3 = p3y; 243 244 x4 = p4x; 245 y4 = p4y; 246 } 247 248 x1 += worldOriginX; 249 y1 += worldOriginY; 250 x2 += worldOriginX; 251 y2 += worldOriginY; 252 x3 += worldOriginX; 253 y3 += worldOriginY; 254 x4 += worldOriginX; 255 y4 += worldOriginY; 256 257 // Draw the bounding rectangle 258 renderer.setColor(Color.GREEN); 259 renderer.begin(ShapeType.Line); 260 261 renderer.line(x1, y1, x2, y2); 262 renderer.line(x2, y2, x3, y3); 263 renderer.line(x3, y3, x4, y4); 264 renderer.line(x4, y4, x1, y1); 265 266 renderer.end(); 267 } 268 setProjectionMatrix(Matrix4 matrix)269 public void setProjectionMatrix (Matrix4 matrix) { 270 this.renderer.setProjectionMatrix(matrix); 271 } 272 273 @Override dispose()274 public void dispose () { 275 renderer.dispose(); 276 } 277 } 278 } 279