Package graphics.model.rails

Source Code of graphics.model.rails.Rails$Chunk

package graphics.model.rails;

import graphics.mesh.Mesh;
import engine.Map;
import static engine.Map.mapHeight;
import static engine.Map.mapWidth;
import java.nio.FloatBuffer;
import org.lwjgl.util.vector.Matrix4f;
import org.lwjgl.util.vector.Vector3f;
import org.lwjgl.util.vector.Vector4f;
import static engine.Engine.MeshHandler;
import static graphics.Graphics.pointInFrustum;
import graphics.material.Material;
import graphics.model.Model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Random;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;

/**
*
* @author simokr
*/
public class Rails extends Model{
 
  public Rails(){
    super();
    chunkList = new ArrayList<>();
    chunksDrawn = 0;
  }
   
  public static final int NS_STRAIGHT = 0;
  public static final int EW_STRAIGHT = 1;
  public static final int NSEW_CROSS = 2;
  public static final int SE_CURVE = 3;
  public static final int SW_CURVE = 4;
  public static final int NW_CURVE = 5;
  public static final int NE_CURVE = 6;
  public static final int NES_CROSS = 7;
  public static final int ESW_CROSS = 8;
  public static final int SWN_CROSS = 9;
  public static final int WNE_CROSS = 10;
  public static final int NS_STATION = 11;
  public static final int EW_STATION = 12;
  public static final int NES_STATION = 13;
  public static final int ESW_STATION = 14;
  public static final int SWN_STATION = 15;
  public static final int WNE_STATION = 16;
  public static final int TREE = 17;
  public static final int UNKNOWN = 18;
 
  private static final int cullingRadius = Map.chunkSize/2;
  private ArrayList<Chunk> chunkList;
  private static int chunksDrawn;
 
  public boolean create(Map map){
   
    ArrayList<Material> materialList = new ArrayList<>();
    HashMap<String, Mesh> objMeshes = new HashMap<>();
   
    objMeshes.put("res/mesh/track.obj",    MeshHandler.get("res/mesh/track.obj"));
    objMeshes.put("res/mesh/track_90_corner.obj",  MeshHandler.get("res/mesh/track_90_corner.obj"));
    objMeshes.put("res/mesh/track_x_cross.obj",  MeshHandler.get("res/mesh/track_x_cross.obj"));
    objMeshes.put("res/mesh/track_t_cross.obj",  MeshHandler.get("res/mesh/track_t_cross.obj"));
    objMeshes.put("res/mesh/station2.obj",    MeshHandler.get("res/mesh/station2.obj"));
    objMeshes.put("res/mesh/station2_bin.obj",  MeshHandler.get("res/mesh/station2_bin.obj"));
    objMeshes.put("res/mesh/station2_bench.obj",  MeshHandler.get("res/mesh/station2_bench.obj"));
    objMeshes.put("res/mesh/station2_map.obj",  MeshHandler.get("res/mesh/station2_map.obj"));
    objMeshes.put("res/mesh/cactus_trunk.obj",  MeshHandler.get("res/mesh/cactus_trunk.obj"));
    objMeshes.put("res/mesh/cactus_branch1.obj",  MeshHandler.get("res/mesh/cactus_branch1.obj"));
    objMeshes.put("res/mesh/cactus_branch2.obj",  MeshHandler.get("res/mesh/cactus_branch2.obj"));
    objMeshes.put("res/mesh/cactus_branch3.obj",  MeshHandler.get("res/mesh/cactus_branch3.obj"));
   
    for (Entry<String, Mesh> objMesh : objMeshes.entrySet()) {
      materialList.add(objMesh.getValue().getDefaultMaterial());
    }
   
    /* Build a one compact material from all the meshes */
    Material railMaterials = new Material(materialList);
    this.material = railMaterials;
    materialList = null;
 
    int rowCount = mapHeight/Map.chunkSize;
    int colCount = mapWidth/Map.chunkSize;
    int totalFloatCount = 0;
   
    for(int chunkY = 0; chunkY < rowCount; chunkY++) {
      for(int chunkX = 0; chunkX < colCount; chunkX++) {
        ArrayList<Float> buffer = this.createChunk(map, chunkX*Map.chunkSize, chunkY*Map.chunkSize, railMaterials, objMeshes);
       
        if(buffer == null || buffer.size() < 1)
          continue;
       
        Chunk chunk = new Chunk(buffer);
        if(chunk.isReady()){
          this.chunkList.add(chunk);
          totalFloatCount += buffer.size();
        }
        else{
          System.err.println("Failed to create rail chunk ("+chunkX+","+chunkY+")");
        }
      }
    }
   
    for (Entry<String, Mesh> objMesh : objMeshes.entrySet()) {
      MeshHandler.free(objMesh.getKey());
    }
   
    System.out.println("Created rails from map. "+this.chunkList.size()+" chunks with "+(totalFloatCount/9/3)+" triangles.");
    return true;
  }
 
  private ArrayList<Float> createChunk(Map map, int xStart, int yStart, Material material, HashMap<String, Mesh> objMeshes){
    Random rand = new Random();
    ArrayList<Float> buffer = new ArrayList<>();
    ArrayList<Float> posBuffer = new ArrayList<>();
    ArrayList<Float> uvBuffer = new ArrayList<>();
    ArrayList<Float> norBuffer = new ArrayList<>();
    ArrayList<Float> idBuffer = new ArrayList<>();
 
    Matrix4f transMat = new Matrix4f();
    Matrix4f rotMat = new Matrix4f();
   
    Vector4f translatedVertex = new Vector4f();
    Vector4f rotatedNormal = new Vector4f();
   
    float[] temp = new float[9];
   
    for(int row = 0; row < Map.chunkSize; row++) {
      for(int col = 0; col < Map.chunkSize; col++) {
        int x = xStart+col;
        int y = yStart+row;
       
        if(map.get(y, x) == Map.EMPTY){
          /* Nothing to be added*/
          continue;
        }
       
        ArrayList<Mesh> msh = new ArrayList<>();
        int scan[] = map.scan(y, x);
        float mRotation = 0f;

        /* Set transform matrix for this piece of track */
        transMat.setIdentity();
        rotMat.setIdentity();
        /* Translate by x,z coordinates */
        transMat.translate(new Vector3f(y, 0, x));
       
        int trackType = getTrackType(map.get(y, x), scan, map.scanRideable(y, x));
       
        /* Populate msh list with right .obj meshes */
        switch(trackType){
          case EW_STRAIGHT:
            mRotation -= 90f;
            rotMat.rotate((float) Math.toRadians(mRotation), new Vector3f(0, 1, 0));
          case NS_STRAIGHT:
            //msh.add(trackStraight);
            msh.add(objMeshes.get("res/mesh/track.obj"));
            break;

          case NSEW_CROSS:
            //msh.add(trackXCrossing);
            msh.add(objMeshes.get("res/mesh/track_x_cross.obj"));
            break;

          case NE_CURVE:
            mRotation -= 90f;
          case NW_CURVE:
            mRotation -= 90f;
          case SW_CURVE:
            mRotation -= 90f;
            rotMat.rotate((float) Math.toRadians(mRotation), new Vector3f(0, 1, 0));
          case SE_CURVE:
            //msh.add(track90Corner);
            msh.add(objMeshes.get("res/mesh/track_90_corner.obj"));
            break;

          case WNE_CROSS:
            mRotation -= 90f;
          case SWN_CROSS:
            mRotation -= 90f;
          case ESW_CROSS:
            mRotation -= 90f;
            rotMat.rotate((float) Math.toRadians(mRotation), new Vector3f(0, 1, 0));
          case NES_CROSS:
            //msh.add(trackTCrossing);
            msh.add(objMeshes.get("res/mesh/track_t_cross.obj"));
            break;

          case EW_STATION:
            mRotation -= 90f;
            rotMat.rotate((float) Math.toRadians(mRotation), new Vector3f(0, 1, 0));
          case NS_STATION:
            //msh.add(trackStraight);
            //msh.add(station);
            msh.add(objMeshes.get("res/mesh/track.obj"));
            msh.add(objMeshes.get("res/mesh/station2.obj"));

            if(rand.nextFloat() > 0.5f){
              //msh.add(station_bin);
              msh.add(objMeshes.get("res/mesh/station2_bin.obj"));
            }
            if(rand.nextFloat() > 0.5f){
              //msh.add(station_bench);
              msh.add(objMeshes.get("res/mesh/station2_bench.obj"));
            }
            if(rand.nextFloat() > 0.75f){
              //msh.add(station_map);
              msh.add(objMeshes.get("res/mesh/station2_map.obj"));
            }
            break;

          case WNE_STATION:
            mRotation -= 90f;
          case SWN_STATION:
            mRotation -= 90f;
          case ESW_STATION:
            mRotation -= 90f;
            rotMat.rotate((float) Math.toRadians(mRotation), new Vector3f(0, 1, 0));
          case NES_STATION:
            //msh.add(trackTCrossing);
            //msh.add(station);
            msh.add(objMeshes.get("res/mesh/track_t_cross.obj"));
            msh.add(objMeshes.get("res/mesh/station2.obj"));

            if(rand.nextFloat() > 0.5f){
              //msh.add(station_bin);
              msh.add(objMeshes.get("res/mesh/station2_bin.obj"));
            }
            if(rand.nextFloat() > 0.5f){
              //msh.add(station_bench);
              msh.add(objMeshes.get("res/mesh/station2_bench.obj"));
            }
            if(rand.nextFloat() > 0.75f){
              //msh.add(station_map);
              msh.add(objMeshes.get("res/mesh/station2_map.obj"));
            }
            break;
           
          case TREE:
            transMat.translate(new Vector3f(((float)Math.random()-0.5f)*0.8f, 0, ((float)Math.random()-0.5f)*0.8f));
            rotMat.rotate((float) Math.toRadians(Math.random()*360.0), new Vector3f(0, 1, 0));
            msh.add(objMeshes.get("res/mesh/cactus_trunk.obj"));
            if(rand.nextFloat() > 0.15f){
              msh.add(objMeshes.get("res/mesh/cactus_branch1.obj"));
            }
            if(rand.nextFloat() > 0.15f){
              msh.add(objMeshes.get("res/mesh/cactus_branch2.obj"));
            }
            if(rand.nextFloat() > 0.15f){
              msh.add(objMeshes.get("res/mesh/cactus_branch3.obj"));
            }
           
            break;
          default:
            //msh.add(trackStraight);
            msh.add(objMeshes.get("res/mesh/track.obj"));
        }
       
        /* Stitch together the meshes of current grid */
        for(int i=0; i<msh.size(); i++){
          FloatBuffer data = msh.get(i).getData();
          int indices = msh.get(i).getIndiceCount();
          int keyframes = msh.get(i).getKeyframeCount();
          int[] offsets = new int[4];
         
          offsets[0] = 0// always only the first keyframe
          offsets[1] = 3*indices*keyframes;
          offsets[2] = 2*indices+offsets[1];
          offsets[3] = 3*indices*keyframes+offsets[2];
         
          data.rewind();

          for(int n=0;n<indices;n++){
            data.position(offsets[0]);
            data.get(temp, 0, 3);
            data.position(offsets[1]);
            data.get(temp, 3, 2);
            data.position(offsets[2]);
            data.get(temp, 5, 3);
            data.position(offsets[3]);
            data.get(temp, 8, 1);
           
            offsets[0] += 3;
            offsets[1] += 2;
            offsets[2] += 3;
            offsets[3]++;
           
            /* XYZ */
            Matrix4f.transform(rotMat, new Vector4f(temp[0], temp[1], temp[2], 1), translatedVertex);
            Matrix4f.transform(transMat, translatedVertex, translatedVertex);
            posBuffer.add(translatedVertex.x);
            posBuffer.add(translatedVertex.y);
            posBuffer.add(translatedVertex.z);
           
            /* UV */
            uvBuffer.add(temp[3]);
            uvBuffer.add(temp[4]);
           
            /* Normals */
            Matrix4f.transform(rotMat, new Vector4f(temp[5], temp[6], temp[7], 0), rotatedNormal);
            norBuffer.add(rotatedNormal.x);
            norBuffer.add(rotatedNormal.y);
            norBuffer.add(rotatedNormal.z);
           
           
            Material meshMat = msh.get(i).getDefaultMaterial();

            /* texture index defaults to 0 */
            int texIndex = material.getTextureHandleIndex(meshMat.getTextureHandle((int)temp[8]));
            texIndex = (texIndex > 0)?texIndex:0;

            /* TexID */
            idBuffer.add((float)texIndex);
          }
        }
      }
    }
   
    buffer.addAll(posBuffer);
    buffer.addAll(uvBuffer);
    buffer.addAll(norBuffer);
    buffer.addAll(idBuffer);
    return buffer;
  }
 
  private int getTrackType(int thisTile, int[] scan, boolean[] scanR){
   
    switch (thisTile){
      /* Track tile */ 
      case Map.TRACK:
        if((scanR[0] || scanR[4])
          && (!scanR[2] && !scanR[6])) {
          return EW_STRAIGHT;
        }
        else if((scanR[2] || scanR[6])
          && (!scanR[0] && !scanR[4])) {
          return NS_STRAIGHT;
        }
        else if((scanR[0] || scanR[2])
          && (!scanR[4] && !scanR[6])) {
          return SE_CURVE;
        }
        else if((scanR[2] || scanR[4])
          && (!scanR[6] && !scanR[0])) {
          return SW_CURVE;
        }
        else if((scanR[4] || scanR[6])
          && (!scanR[0] && !scanR[2])) {
          return NW_CURVE;
        }
        else if((scanR[6] || scanR[0])
          && (!scanR[2] && !scanR[4])) {
          return NE_CURVE;
        }
        else if((scanR[2] && scanR[6] && scanR[0])
          && (!scanR[4])) {
          return NES_CROSS;
        }
        else if((scanR[4] && scanR[2] && scanR[0])
          && (!scanR[6])) {
          return ESW_CROSS;
        }
        else if((scanR[2] && scanR[4] && scanR[6])
          && (!scanR[0])) {
          return SWN_CROSS;
        }
        else if((scanR[4] && scanR[6] && scanR[0])
          && (!scanR[2])) {
          return WNE_CROSS;
        }
        else if((scanR[4] && scanR[6] && scanR[0] && scanR[2])) {
          return NSEW_CROSS;
        }
        return UNKNOWN;
       
       
       
      /* Station tile */ 
      case Map.STATION:
        if((scanR[0] || scanR[4])
          && (!scanR[2] && !scanR[6])) {
          return EW_STATION;
        }
        else if((scanR[2] || scanR[6])
          && (!scanR[0] && !scanR[4])) {
          return NS_STATION;
        }
        else if((scanR[0] || scanR[2])
          && (!scanR[4] && !scanR[6])) {
          return SE_CURVE;
        }
        else if((scanR[2] || scanR[4])
          && (!scanR[6] && !scanR[0])) {
          return SW_CURVE;
        }
        else if((scanR[4] || scanR[6])
          && (!scanR[0] && !scanR[2])) {
          return NW_CURVE;
        }
        else if((scanR[6] || scanR[0])
          && (!scanR[2] && !scanR[4])) {
          return NE_CURVE;
        }
        else if((scanR[2] && scanR[6] && scanR[0])
          && (!scanR[4])) {
          return NES_STATION;
        }
        else if((scanR[4] && scanR[2] && scanR[0])
          && (!scanR[6])) {
          return ESW_STATION;
        }
        else if((scanR[2] && scanR[4] && scanR[6])
          && (!scanR[0])) {
          return SWN_STATION;
        }
        else if((scanR[4] && scanR[6] && scanR[0])
          && (!scanR[2])) {
          return WNE_STATION;
        }
        else if((scanR[4] && scanR[6] && scanR[0] && scanR[2])) {
          return NSEW_CROSS;
        }
        return UNKNOWN;
       
      case Map.TREE:
        return TREE;
       
      /* Unkown tile type */ 
      default:
        return UNKNOWN;
       
    }
   
  }
 
  @Override
  protected boolean preRender(){
    if(this.chunkList == null || this.chunkList.isEmpty()|| this.shader == null || !this.shader.isReady())
      return false;
   
    this.updateModelMatrix();
   
    this.shader.setModelMatrix(this.modelMatrix);
    return true;
  }
 
  @Override
  public void render(){
    if(!this.preRender())
      return;
   
    this.shader.enable();

    this.material.bindTextures();
    chunksDrawn = 0;
   
    for (Chunk chunk : this.chunkList) {
      chunk.render();
    }
    //System.out.println("Chunks on screen: "+chunksDrawn);
    this.material.unbindTextures();
    this.shader.disable();
  }
 
  @Override
  public void free(){
    for (Chunk chunk : this.chunkList) {
      chunk.free();
    }
  }
 
  private class Chunk{
    private Mesh mesh;
    Vector3f corner[];
    public Chunk(ArrayList<Float> data){
      mesh = new Mesh();
      mesh.create(data, 9, GL_STATIC_DRAW, false);
      corner = new Vector3f[9];
     
      Vector3f topLeftFrontCorner = new Vector3f();
      Vector3f bottomRightBackCorner = new Vector3f();
     
      topLeftFrontCorner.x = data.get(0);
      bottomRightBackCorner.y = data.get(1);
      bottomRightBackCorner.z = data.get(2);
     
      int indices = mesh.getIndiceCount()*3;
      for (int i = 0; i < indices; i=i+3) {
        topLeftFrontCorner.x = Math.min(data.get(i), topLeftFrontCorner.x);
        topLeftFrontCorner.y = Math.max(data.get(i+1), topLeftFrontCorner.y);
        topLeftFrontCorner.z = Math.max(data.get(i+2), topLeftFrontCorner.z);
       
        bottomRightBackCorner.x = Math.max(data.get(i), bottomRightBackCorner.x);
        bottomRightBackCorner.y = Math.min(data.get(i+1), bottomRightBackCorner.y);
        bottomRightBackCorner.z = Math.min(data.get(i+2), bottomRightBackCorner.z);
      }
      corner[0] = new Vector3f(topLeftFrontCorner);
      corner[1] = new Vector3f(topLeftFrontCorner.x, topLeftFrontCorner.y, bottomRightBackCorner.z);
      corner[2] = new Vector3f(bottomRightBackCorner.x, topLeftFrontCorner.y, bottomRightBackCorner.z);
      corner[3] = new Vector3f(bottomRightBackCorner.x, topLeftFrontCorner.y, topLeftFrontCorner.z);
     
      corner[4] = new Vector3f(bottomRightBackCorner);
      corner[5] = new Vector3f(topLeftFrontCorner.x, bottomRightBackCorner.y, bottomRightBackCorner.z);
      corner[6] = new Vector3f(bottomRightBackCorner.x, bottomRightBackCorner.y, bottomRightBackCorner.z);
      corner[7] = new Vector3f(bottomRightBackCorner.x, bottomRightBackCorner.y, topLeftFrontCorner.z);
     
      corner[8] = new Vector3f((bottomRightBackCorner.x+topLeftFrontCorner.x)/2f,
        (bottomRightBackCorner.y+topLeftFrontCorner.y)/2f,
        (bottomRightBackCorner.z+topLeftFrontCorner.z)/2f
        );
    }
   
    public boolean isReady(){
      return this.mesh.isReady();
    }
   
    public boolean inFrustrum(){
      //return pointInFrustum(this.corner[8]) || pointInFrustum(this.corner[0]) || pointInFrustum(this.corner[1]) || pointInFrustum(this.corner[2]) || pointInFrustum(this.corner[3])
      //   || pointInFrustum(this.corner[4]) || pointInFrustum(this.corner[5]) || pointInFrustum(this.corner[6]) || pointInFrustum(this.corner[7]);
     
      return pointInFrustum(this.corner[8], cullingRadius);
    }
   
    public void free(){
      this.mesh.free();
    }
   
    public void render(){
      if(!this.mesh.isReady() || !this.inFrustrum())
        return;
     
      chunksDrawn++;
     
      this.mesh.render();
    }
  }
}
TOP

Related Classes of graphics.model.rails.Rails$Chunk

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.