gameWorld.WorldRenderer.java Source code

Java tutorial

Introduction

Here is the source code for gameWorld.WorldRenderer.java

Source

/*******************************************************************************
 * Copyright 2011 See AUTHORS file.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package gameWorld;

import screens.GameScreen;
import android.util.Log;
import box2DLights.PointLight;
import box2DLights.RayHandler;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.maps.Map;
import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.maps.MapObjects;
import com.badlogic.gdx.maps.objects.CircleMapObject;
import com.badlogic.gdx.maps.objects.PolygonMapObject;
import com.badlogic.gdx.maps.objects.PolylineMapObject;
import com.badlogic.gdx.maps.objects.RectangleMapObject;
import com.badlogic.gdx.maps.objects.TextureMapObject;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.math.Circle;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.ChainShape;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.Shape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.Array;
import com.komodo.mygdxgame.Assets;

public class WorldRenderer {

    private BitmapFont bitmapFont;

    static final float FRUSTUM_WIDTH = 17;
    static final float FRUSTUM_HEIGHT = 10;
    GameWorld world;
    OrthographicCamera cam;
    SpriteBatch batch;
    TextureRegion background;
    private OrthogonalTiledMapRenderer renderer;

    ShapeRenderer shapeRender;

    float dampingCounter;
    float followX;
    float followY;
    Vector2 lookAhead;
    Vector2 target;

    private Texture ghostTexture;
    private TextureRegion ghostRegion;
    private float originX;
    private float originY;
    private float textureWidth;
    private float textureHeight;

    Box2DDebugRenderer debugRenderer;
    // TODO attach light as a component of an object.
    RayHandler handler;
    RayHandler handler2;
    public TiledMap map; // this is what the worldRenderer uses.
    MapBodyBuilder mapBuilder;

    PointLight pointLight;
    PointLight pointLight2;

    private int lightSize = 64;
    // private int lightSize = 160;
    Vector2 velocity;

    private float upScale = 1.5f; // for example; try lightSize=128,
    // upScale=1.5f

    BitmapFont font;

    TextureRegion shadowMap1D; // 1 dimensional shadow map
    TextureRegion occluders; // occluder map

    FrameBuffer shadowMapFBO;
    FrameBuffer occludersFBO;

    Texture casterSprites;
    TextureRegion casterRegion;
    // Texture light;

    ShaderProgram shadowMapShader, shadowRenderShader;

    boolean additive = true;
    boolean softShadows = true;

    // allconstant = world doesnt react to rotations. ghost just follows finger.
    GameScreen.rotationMode rotation;

    public final static short FILTER_CATEGORY_SCENERY = 0x0001;
    public final static short FILTER_CATEGORY_LIGHT = 0x0002; // LIGHT PASS
    // THROUGH
    public static final short FILTER_CATEGORY_DONT_ABSORB_LIGHT = 0x0004;
    public static final short FILTER_CATEGORY_LIGHT_PASS = 0x0008;
    public final static short FILTER_MASK_SCENERY = -1;
    public final static short FILTER_MASK_DONT_ABSORB_LIGHT = FILTER_CATEGORY_SCENERY | FILTER_CATEGORY_LIGHT;
    public final static short FILTER_MASK_ABSORB_LIGHT = FILTER_CATEGORY_SCENERY;

    public WorldRenderer(SpriteBatch batch, GameWorld world) {
        this.rotation = GameScreen.rotation;
        this.world = world;
        this.cam = new OrthographicCamera(FRUSTUM_WIDTH, FRUSTUM_HEIGHT);
        this.cam.position.set(FRUSTUM_WIDTH / 2, FRUSTUM_HEIGHT / 2, 0);
        this.batch = batch;
        renderer = new OrthogonalTiledMapRenderer(world.map, 1 / 70f); // the 70
        // is
        // because
        // each
        // tile
        // is
        // 70px
        followX = 0f;
        followY = 0f;
        shapeRender = new ShapeRenderer();

        ghostTexture = new Texture("data/ghost_fixed.png");
        ghostRegion = new TextureRegion(ghostTexture, 0, 0, 64, 64);
        originX = 1 / 48f * ghostTexture.getWidth() / 2f;
        originY = 1 / 48f * ghostTexture.getHeight() / 2f;
        textureWidth = 1 / 48f * 64; // texture is 64 pixels big.
        textureHeight = 1 / 48f * 64;

        dampingCounter = 0;
        velocity = new Vector2();

        // Light setup ---------------------------
        RayHandler.useDiffuseLight(true);
        handler = new RayHandler(world.world2);
        handler.setAmbientLight(.1f, .1f, .1f, 1f);
        // handler.setAmbientLight(.06f, .06f, .06f, .05f);
        handler.setShadows(true);
        handler.setCulling(true);
        // handler.setBlur(true);

        // Renders shadows
        pointLight = new PointLight(handler, 290, new Color(1, 1, .8f, .6f), 15, 10, 110);
        pointLight.setSoft(true);
        pointLight.setSoftnessLenght(.3f);

        // lights up the tiles around the player (no shadows)
        pointLight2 = new PointLight(handler, 200, new Color(1, 1, .8f, .6f), 6, 10, 110);
        pointLight2.setSoftnessLenght(1.5f);
        pointLight2.setXray(true);

        // for debugging---------
        // Box2D debug renderer. renders wireframes of the objects we create.
        debugRenderer = new Box2DDebugRenderer();
        bitmapFont = new BitmapFont();
        bitmapFont.setUseIntegerPositions(false);
        bitmapFont.getRegion().getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
        bitmapFont.setColor(Color.WHITE);
        bitmapFont.setScale(1.0f / 48.0f);
    }

    public void render() {
        // Set lights
        pointLight.setPosition(world.bob.position.x, world.bob.position.y);
        pointLight2.setPosition(world.bob.position.x, world.bob.position.y);
        handler.setCombinedMatrix(cam.combined, cam.position.x, cam.position.y, cam.viewportWidth * cam.zoom,
                cam.viewportHeight * cam.zoom);

        // Set camera
        float lerp = 0.95f;
        Vector3 position = cam.position;
        world.bob.directionVector.nor();
        position.x += (world.bob.position.x + world.bob.directionVector.x * 1.8 - position.x) * lerp;
        position.y += (world.bob.position.y + world.bob.directionVector.y * 1.8 - position.y) * lerp;

        // cam.position.x = world.bob.position.x;
        // cam.position.y = world.bob.position.y;
        float camAngle = -getCameraCurrentXYAngle(cam); // + 180;
        if (rotation == GameScreen.rotationMode.WORLD) {
            cam.rotate((camAngle + world.sensor.getAzimuth() + 90)); // switch
        }
        // angle to positive for reverse spin.
        cam.update();

        renderBackground();
        renderObjects();

    }

    public float getCameraCurrentXYAngle(OrthographicCamera cam) {
        return (float) Math.atan2(cam.up.x, cam.up.y) * MathUtils.radiansToDegrees;
    }

    public void renderBackground() {
    }

    public void renderObjects() {

        // Draw all tiles now and black background
        shapeRender.begin(ShapeType.Filled);
        shapeRender.setColor(new Color(.1f, .1f, .1f, 1f));
        shapeRender.rect(cam.position.x - 200, cam.position.y - 200, 2580, 1680);
        shapeRender.end();
        batch = (SpriteBatch) renderer.getSpriteBatch();
        renderer.setView(cam.combined, cam.position.x - 20, cam.position.y - 20, cam.viewportWidth + 40,
                cam.viewportWidth + 40);
        renderer.render();

        // render game objects
        batch.begin();
        renderBob();
        renderPlatforms();
        renderItems();
        renderCastle();
        batch.end();

        // Debug rendering
        // draw fonts
        debugRender();
        // draw box2d world.
        debugRenderer.render(world.world2, cam.combined);

        // light rendering
        handler.updateAndRender();

        // world2.step(1 / 60f, 6, 2);

    }

    public void debugRender() {
        batch.begin();
        float x = cam.position.x;
        /*bitmapFont.setColor(shaderSelection==ShaderSelection.Default?Color.YELLOW:Color.WHITE);
        x += bitmapFont.draw(batch, "1=Default Shader", x, cam.position.y).width;
        bitmapFont.setColor(shaderSelection==ShaderSelection.Ambiant?Color.YELLOW:Color.WHITE);
        x += bitmapFont.draw(batch, " 2=Ambient Light", x, cam.position.y).width;
        bitmapFont.setColor(shaderSelection==ShaderSelection.Light?Color.YELLOW:Color.WHITE);
        x += bitmapFont.draw(batch, " 3=Light Shader", x, cam.position.y).width;
        bitmapFont.setColor(shaderSelection==ShaderSelection.Final?Color.YELLOW:Color.WHITE);
        x += bitmapFont.draw(batch, " 4=Final Shader", x, cam.position.y).width;
        x = cam.position.x;
        bitmapFont.setColor(lightMove?Color.YELLOW:Color.WHITE);
        x += bitmapFont.draw(batch, "click=light control (" +lightMove+ ")", x, cam.position.y-bitmapFont.getLineHeight()).width;
        bitmapFont.setColor(lightOscillate?Color.YELLOW:Color.WHITE);
        x += bitmapFont.draw(batch, " space=light flicker (" +lightOscillate+ ")", x, cam.position.y-bitmapFont.getLineHeight()).width;
        x = cam.position.x;
        bitmapFont.setColor(Color.WHITE);*/
        x += bitmapFont.draw(batch, Gdx.graphics.getFramesPerSecond() + " fps", x,
                cam.position.y - bitmapFont.getLineHeight() * 2.0f).width;
        batch.end();
    }

    private void renderBob() {
        TextureRegion keyFrame;
        switch (world.bob.state) {
        case Bob.BOB_STATE_FALL:
            keyFrame = Assets.bobFall.getKeyFrame(world.bob.stateTime);
            break;
        case Bob.BOB_STATE_JUMP:
            keyFrame = Assets.bobJump.getKeyFrame(world.bob.stateTime);
            break;
        case Bob.BOB_STATE_HIT:
        default:
            keyFrame = Assets.bobHit;
        }

        if (rotation == GameScreen.rotationMode.PLAYER) {
            batch.draw(ghostRegion, world.bob.position.x - .7f, world.bob.position.y - .64f, originX, originY,
                    textureWidth, textureHeight, 1, 1, world.sensor.getAzimuth(), false);
            batch.draw(ghostRegion, world.bob.position2.x - .2f, world.bob.position2.y - .84f, originX, originY,
                    textureWidth * .5f, textureHeight * .5f, 1, 1, world.bob.angleBaby, false);

        } else if (rotation == GameScreen.rotationMode.WORLD) {
            batch.draw(ghostRegion, world.bob.position.x - .7f, world.bob.position.y - .64f, originX, originY,
                    textureWidth, textureHeight, 1, 1, -world.sensor.getAzimuth() + 180, false);

            batch.draw(ghostRegion, world.bob.position2.x - .2f, world.bob.position2.y - 1.5f, originX, originY,
                    textureWidth * .5f, textureHeight * .5f, 1, 1, -world.bob.angleBaby + 180, false);
        }

        // batch.draw(ghostRegion, world.bob.position.x - .2f,
        // world.bob.position.y - .2f, originX, originY, textureWidth,
        // textureHeight, 1, 1, world.sensor.getAzimuth(), false);

        /*   float side = world.bob.velocity.x < 0 ? -1 : 1;
           if (side < 0) { // the -1 is to render a bit higher than usual {
        // batch.draw(keyFrame, world.bob.position.x + 0.5f + .4f,
        // world.bob.position.y - 0.5f + .5f, side * 1, 1);
            
        batch.draw(keyFrame, world.bob.position.x, world.bob.position.y,
              .5f, .5f, (float) keyFrame.getTexture().getWidth(),
              (float) keyFrame.getTexture().getWidth(), 1f, 1f,
              world.sensor.getAzimuth(), false);
           }
            
           else {
        // batch.draw(keyFrame, world.bob.position.x - 0.5f +.4f,
        // world.bob.position.y - 0.5f + .5f, side * 1, 1);
        batch.draw(keyFrame, world.bob.position.x, world.bob.position.y,
              .5f, .5f, (float) keyFrame.getTexture().getWidth(),
              (float) keyFrame.getTexture().getWidth(), 1f, 1f,
              world.sensor.getAzimuth(), false);
           }*/
    }

    private void renderPlatforms() {
        // int len = world.platforms.size();
        // for (int i = 0; i < len; i++) {
        // Platform platform = world.platforms.get(i);
        // TextureRegion keyFrame = Assets.platform;
        // if (platform.state == Platform.PLATFORM_STATE_PULVERIZING) {
        // keyFrame = Assets.brakingPlatform.getKeyFrame(platform.stateTime,
        // Animation.ANIMATION_NONLOOPING);
        // }
        //
        // batch.draw(keyFrame, platform.position.x - 1, platform.position.y -
        // 0.25f, 2, 0.5f);
        // }
    }

    private void renderItems() {
        if (world.collision) {
            Coin coin = new Coin(world.bob.position.x, world.bob.position.y);
            TextureRegion keyFrame = Assets.coinAnim.getKeyFrame(coin.stateTime, true);
            batch.draw(keyFrame, coin.position.x - 0.5f, coin.position.y - 0.5f, 1, 1);
        }
        // int len = world.springs.size();
        // for (int i = 0; i < len; i++) {
        // Spring spring = world.springs.get(i);
        // batch.draw(Assets.spring, spring.position.x - 0.5f, spring.position.y
        // - 0.5f, 1, 1);
        // }
        //
        // len = world.coins.size();
        // for (int i = 0; i < len; i++) {
        // Coin coin = world.coins.get(i);
        // TextureRegion keyFrame = Assets.coinAnim.getKeyFrame(coin.stateTime,
        // Animation.ANIMATION_LOOPING);
        // batch.draw(keyFrame, coin.position.x - 0.5f, coin.position.y - 0.5f,
        // 1, 1);
        // }
    }

    private void renderCastle() {
        // Castle castle = world.castle;
        // batch.draw(Assets.castle, castle.position.x - 1, castle.position.y -
        // 1, 2, 2);
    }

    private class MapBodyBuilder {

        // The pixels per tile. If your tiles are 16x16, this is set to 16f
        private float ppt = 0;

        public Array<Body> buildShapes(Map map, float pixels, World world) {
            ppt = pixels;
            MapObjects objects = map.getLayers().get("Obstacles").getObjects();

            Array<Body> bodies = new Array<Body>();

            for (MapObject object : objects) {

                if (object instanceof TextureMapObject) {
                    continue;
                }

                Shape shape;

                if (object instanceof RectangleMapObject) {
                    shape = getRectangle((RectangleMapObject) object);
                } else if (object instanceof PolygonMapObject) {
                    shape = getPolygon((PolygonMapObject) object);
                } else if (object instanceof PolylineMapObject) {
                    shape = getPolyline((PolylineMapObject) object);
                } else if (object instanceof CircleMapObject) {
                    shape = getCircle((CircleMapObject) object);
                } else {
                    continue;
                }

                BodyDef bd = new BodyDef();

                //
                // groundBodyDef.position.set(5,84);

                bd.type = BodyType.KinematicBody;
                // bd.type = BodyType.DynamicBody;
                Body body = world.createBody(bd);
                body.createFixture(shape, 1);

                bodies.add(body);

                shape.dispose();
            }
            return bodies;
        }

        public PolygonShape getRectangle(RectangleMapObject rectangleObject) {
            Rectangle rectangle = rectangleObject.getRectangle();
            PolygonShape polygon = new PolygonShape();
            Vector2 size = new Vector2((rectangle.x + rectangle.width * 0.5f) / ppt,
                    (rectangle.y + rectangle.height * 0.5f) / ppt);
            polygon.setAsBox(rectangle.width * 0.5f / ppt, rectangle.height * 0.5f / ppt, size, 0.0f);
            return polygon;
        }

        private CircleShape getCircle(CircleMapObject circleObject) {
            Circle circle = circleObject.getCircle();
            CircleShape circleShape = new CircleShape();
            circleShape.setRadius(circle.radius / ppt);
            circleShape.setPosition(new Vector2(circle.x / ppt, circle.y / ppt));
            return circleShape;
        }

        private PolygonShape getPolygon(PolygonMapObject polygonObject) {
            PolygonShape polygon = new PolygonShape();
            float[] vertices = polygonObject.getPolygon().getTransformedVertices();

            float[] worldVertices = new float[vertices.length];

            for (int i = 0; i < vertices.length; ++i) {
                System.out.println(vertices[i]);
                worldVertices[i] = vertices[i] / ppt;
            }

            polygon.set(worldVertices);
            return polygon;
        }

        private ChainShape getPolyline(PolylineMapObject polylineObject) {
            float[] vertices = polylineObject.getPolyline().getTransformedVertices();
            Vector2[] worldVertices = new Vector2[vertices.length / 2];

            for (int i = 0; i < vertices.length / 2; ++i) {
                worldVertices[i] = new Vector2();
                worldVertices[i].x = vertices[i * 2] / ppt;
                worldVertices[i].y = vertices[i * 2 + 1] / ppt;
            }

            ChainShape chain = new ChainShape();
            chain.createChain(worldVertices);
            return chain;
        }
    }

}