package tk.amberide.engine.gl.tess; import tk.amberide.engine.data.math.Angles; import tk.amberide.engine.data.map.Tile; import static tk.amberide.engine.data.map.Angle.*; import tk.amberide.engine.data.map.TileModel; import tk.amberide.ide.data.res.Tileset; import tk.amberide.engine.gl.atlas.ITextureAtlas; import tk.amberide.engine.gl.atlas.TextureAtlasFactory; import tk.amberide.engine.gl.model.ModelScene; import tk.amberide.engine.gl.model.obj.WavefrontObject; import java.awt.Dimension; import java.awt.Point; import java.io.IOException; import java.util.WeakHashMap; import static org.lwjgl.opengl.GL11.*; import org.lwjgl.util.vector.Vector2f; /** * Renders tiles in immediate mode. * * @author Tudor */ public class ImmediateTesselator implements ITesselator { protected WeakHashMap<Tileset, ITextureAtlas> textureCache = new WeakHashMap<Tileset, ITextureAtlas>(); protected WeakHashMap<WavefrontObject, ModelScene> modelCache = new WeakHashMap<WavefrontObject, ModelScene>(); protected ITextureAtlas atl; public void drawTile(Tile tile, float x, float y, float z) { atl = getTexture(tile); glPushMatrix(); float tx = x, ty = y, rot = 0; float[] t0 = {0, 1}; float[] t1 = {0, 0}; float[] t2 = {1, 0}; float[] t3 = {1, 1}; switch (tile.getDirection().toCardinal()) { case SOUTH: tx += 1; ty += 1; rot = 180; break; case WEST: ty += 1; rot = 90; break; case EAST: tx += 1; rot = 270; break; } float y1, y2, y3, y4; y1 = y2 = y3 = y4 = 0; Vector2f ix = null; switch (tile.getType()) { case TILE_CORNER: switch (tile.getDirection()) { case NORTH_EAST: case SOUTH_WEST: t2 = new float[]{0, 0}; t3 = new float[]{1, 0}; t0 = new float[]{1, 1}; t1 = new float[]{0, 1}; y3++; break; case NORTH_WEST: case SOUTH_EAST: y2++; break; } ix = Angles.circleIntercept(HORIZONTAL.intValue(), 0, 0, 1); break; case TILE_CORNER_INVERSED: switch (tile.getDirection()) { case NORTH_EAST: case SOUTH_WEST: y4++; y3++; y2++; t3 = new float[]{0, 0}; break; case NORTH_WEST: case SOUTH_EAST: y1++; y2++; y3++; break; } ix = Angles.circleIntercept(HORIZONTAL.intValue(), 0, 0, 1); break; case TILE_NORMAL: ix = Angles.circleIntercept(tile.getAngle().intValue(), 0, 0, 1); break; } glTranslatef(tx, z, ty); Point start = tile.getSprite().getStart(); Dimension size = tile.getSprite().getSize(); atl.bindTextureRegion(start.x, start.y, size.height, size.width); glRotatef(rot, 0, 1, 0); glBegin(GL_TRIANGLES); { //0 atl.atlasCoord(t0[0], t0[1]); glVertex3f(0, y1, 0); //1 atl.atlasCoord(t1[0], t1[1]); glVertex3f(ix.x, ix.y + y2, 0); //2 atl.atlasCoord(t2[0], t2[1]); glVertex3f(ix.x, ix.y + y3, 1); //3 atl.atlasCoord(t3[0], t3[1]); glVertex3f(0, y4, 1); //2 atl.atlasCoord(t2[0], t2[1]); glVertex3f(ix.x, ix.y + y3, 1); //0 atl.atlasCoord(t0[0], t0[1]); glVertex3f(0, y1, 0); } glEnd(); glPopMatrix(); } public void startTileBatch() { glPushMatrix(); } public void endTileBatch() { glPopMatrix(); if (atl != null) { atl.unbind(); } } public void startModelBatch() { glPushMatrix(); } public void drawModel(TileModel model, float x, float y, float z) { ModelScene scene = getModel(model); if (scene != null) { glPushMatrix(); glPushAttrib(GL_CURRENT_BIT | GL_TRANSFORM_BIT); glTranslatef(x, z, y); scene.draw(); glTranslatef(-x, -z, -y); glPopAttrib(); glPopMatrix(); glBindTexture(GL_TEXTURE_2D, 0); } } public void endModelBatch() { glPopMatrix(); } public void invalidate() { textureCache.clear(); modelCache.clear(); } protected ITextureAtlas getTexture(Tile t) { Tileset sheet = t.getSprite().getTileset(); ITextureAtlas atlas; if (textureCache.containsKey(sheet)) { atlas = textureCache.get(sheet); } else { textureCache.put(sheet, atlas = TextureAtlasFactory.createAtlas(sheet.getImage())); } return atlas; } protected ModelScene getModel(TileModel t) { WavefrontObject m = t.getModel(); ModelScene scene = null; if (m != null) { if (modelCache.containsKey(m)) { scene = modelCache.get(m); } else { try { modelCache.put(m, scene = new ModelScene(m)); } catch (IOException ex) { } } } return scene; } }