/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2013, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.display3d.scene.component; import com.jogamp.common.nio.Buffers; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLException; import com.jogamp.opengl.util.texture.TextureData; import org.geotoolkit.math.XMath; import org.opengis.geometry.Envelope; import javax.vecmath.Point3i; import javax.vecmath.Vector3f; import java.awt.*; import org.geotoolkit.display3d.Map3D; import org.geotoolkit.display3d.utils.TextureManager; /** * @author Thomas Rouby (Geomatys) */ public class Tile3D extends Mesh3D { public static final int INDEX_MNT = 9; public static final int INDEX_IMAGE = 0; private final Envelope envelope; private final Point3i position; private final int axis0Number, axis1Number; private final int axis0Pts, axis1Pts; public static final float borderZTranslate = -2000.0f; public Tile3D(Map3D map, Envelope env, Point3i position, int axis0, int axis1){ super(map); this.envelope = env; this.position = position; this.axis0Number = axis0; this.axis1Number = axis1; this.axis0Pts = axis0+2; this.axis1Pts = axis1+2; final float[] vertices = new float[(axis0Pts*axis1Pts)*3]; final float[] normals = new float[(axis0Pts*axis1Pts)*3]; final int[] indices = new int[((axis0Pts-1)*(axis1Pts-1)) * 3 * 2]; final float[] uvs = new float[(axis0Pts*axis1Pts)*2]; final double axis0Step = envelope.getSpan(0) / (axis0Number-1); final double axis1Step = envelope.getSpan(1) / (axis1Number-1); for (int j=0; j<axis1Pts; j++){ for (int i=0; i<axis0Pts; i++){ final int col = XMath.clamp(i-1, 0, axis0Number-1); final int row = XMath.clamp(j-1, 0, axis1Number-1); final int coord = i + j * axis0Pts; vertices[coord *3 ] = (float)(envelope.getMinimum(0) + col*axis0Step); vertices[coord *3 + 1] = (float)(envelope.getMaximum(1) - row*axis1Step); vertices[coord *3 + 2] = (inBorder(coord))?(borderZTranslate):(0.0f); normals[coord *3 ] = 0.0f; normals[coord *3 + 1] = 0.0f; normals[coord *3 + 2] = 1.0f; uvs[coord *2 ] = (float)col/((float)axis0Number-1.0f); uvs[coord *2 + 1] = (float)row/((float)axis1Number-1.0f); if (j < axis1Pts-1 && i < axis0Pts-1){ final int coordInd = i + j * (axis0Pts - 1); indices[coordInd *6 ] = coord; indices[coordInd *6 + 1] = i+j*axis0Pts + axis0Pts + 1; indices[coordInd *6 + 2] = i+j*axis0Pts + 1; indices[coordInd *6 + 3] = coord; indices[coordInd *6 + 4] = i+j*axis0Pts + axis0Pts; indices[coordInd *6 + 5] = i+j*axis0Pts + axis0Pts + 1; } } } this.verticesb = Buffers.newDirectFloatBuffer(vertices); this.normalb = Buffers.newDirectFloatBuffer(normals); this.indicesb = Buffers.newDirectIntBuffer(indices); this.uvsb = Buffers.newDirectFloatBuffer(uvs); } public double getScale() { TextureManager textImg = getTexture(INDEX_IMAGE); if (textImg != null){ return this.envelope.getSpan(0) / textImg.getTextureData().getWidth(); } else { return this.envelope.getSpan(0) / 256.0; } } public final Point3i getPosition() { return this.position; } public final Envelope getEnvelope() { return this.envelope; } public void setMNT(float[] vertices) { setVertices(vertices); computeNormals(); } public final TextureManager getTextureImg() { return this.getTexture(INDEX_IMAGE); } public void setTextureImg(TextureManager textureImg) { this.setTexture(INDEX_IMAGE, textureImg); } public void setTextureDataImg(TextureData textureImg) { this.setTextureData(INDEX_IMAGE, textureImg); } @Override public void checkTexture(GLAutoDrawable glAutoDrawable, int index){ final Map3D canvas = this.getCanvas(); if (index < 0 || index >= this.textures.length) return; if (canvas.doAction()) { if (this.futurText[index] != null) { if (this.futurText[index].updateTexture(glAutoDrawable)) { computeUVs(); setTexture(index, this.futurText[index]); this.futurText[index] = null; canvas.addAction(); } } else if (this.textures[index] != null) { if (this.textures[index].updateTexture(glAutoDrawable)) { canvas.addAction(); } } } } public void computeUVs() { final float[] uvs = new float[(axis0Pts*axis1Pts)*2]; for (int j=0; j<axis1Pts; j++){ for (int i=0; i<axis0Pts; i++){ int col = XMath.clamp(i - 1, 0, axis0Number - 1); int row = XMath.clamp(j-1, 0, axis1Number-1); uvs[(i+j*axis0Pts)*2 ] = (float)col/((float)axis0Number-1.0f); uvs[(i+j*axis0Pts)*2 + 1] = (float)row/((float)axis1Number-1.0f); } } this.uvsb = Buffers.newDirectFloatBuffer(uvs); minU = minV = 0.0f; maxU = maxV = 1.0f; } private boolean inBorder(int ind){ final int mod = ind%axis0Pts; return ind<axis0Pts || ind >= axis0Pts*(axis1Pts-1) || mod <= 0 || mod >= axis0Pts-1; } public void computeNormals() { final Vector3f[] nls = new Vector3f[axis0Pts*axis1Pts]; final int[] indices = getIndicesAsArray(); final float[] vertices = getVerticesAsArray(); for (int i=0; i<indices.length; i+=3) { if (inBorder(indices[i]) || inBorder(indices[i+1]) || inBorder(indices[i+2])){ continue; } int p1ind = indices[i]*3; final Vector3f p1 = new Vector3f(vertices[p1ind], vertices[p1ind+1],vertices[p1ind+2]); int p2ind = indices[i+1]*3; final Vector3f p2 = new Vector3f(vertices[p2ind], vertices[p2ind+1],vertices[p2ind+2]); int p3ind = indices[i+2]*3; final Vector3f p3 = new Vector3f(vertices[p3ind], vertices[p3ind+1],vertices[p3ind+2]); final Vector3f v1 = new Vector3f(); v1.sub(p2, p1); final Vector3f v2 = new Vector3f(); v2.sub(p3, p1); final Vector3f normal = new Vector3f(); normal.cross(v1, v2); if (nls[indices[i ]] == null){ nls[indices[i ]] = new Vector3f(normal); } else { nls[indices[i ]].add(normal); } if (nls[indices[i+1]] == null){ nls[indices[i+1]] = new Vector3f(normal); } else { nls[indices[i+1]].add(normal); } if (nls[indices[i+2]] == null){ nls[indices[i+2]] = new Vector3f(normal); } else { nls[indices[i+2]].add(normal); } } final float[] nlsa = new float[nls.length*3]; for (int i=0; i<nls.length; i++){ if (nls[i] == null){ nls[i] = new Vector3f(0.0f, 0.0f, 1.0f); } else { nls[i].normalize(); } nlsa[i*3 ] = nls[i].x; nlsa[i*3+1] = nls[i].y; nlsa[i*3+2] = nls[i].z; } this.normalb = Buffers.newDirectFloatBuffer(nlsa); } public Dimension getPtsNumber(){ return new Dimension(this.axis0Pts, this.axis1Pts); } public Dimension getAxisNumber(){ return new Dimension(axis0Number, axis1Number); } public double getZValue(double axis0, double axis1){ final double axis0Pos = axis0Number*XMath.clamp(axis0, 0.0, 1.0) + 1.0; final double axis1Pos = axis1Number*XMath.clamp(axis1, 0.0, 1.0) + 1.0; /** * C -- D * | | * A -- B */ final double zValueA = this.verticesb.get(((int)Math.floor(axis0Pos)+(int)Math.floor(axis1Pos)*axis0Pts)*3 + 2); final double zValueB = this.verticesb.get(((int)Math.ceil(axis0Pos)+(int)Math.floor(axis1Pos)*axis0Pts)*3 + 2); final double zValueC = this.verticesb.get(((int)Math.floor(axis0Pos)+(int)Math.ceil(axis1Pos)*axis0Pts)*3 + 2); final double zValueD = this.verticesb.get(((int)Math.ceil(axis0Pos)+(int)Math.ceil(axis1Pos)*axis0Pts)*3 + 2); final double axis0Coef = axis0Pos - Math.floor(axis0Pos); final double axis1Coef = axis1Pos - Math.floor(axis1Pos); final double AB = axis0Coef*zValueA + (1.0-axis0Coef)*zValueB; final double CD = axis0Coef*zValueC + (1.0-axis0Coef)*zValueD; return axis1Coef*AB + (1.0-axis1Coef)*CD; } @Override protected void drawInternal(GLAutoDrawable glDrawable) throws GLException { final GL gl = glDrawable.getGL(); if (gl.isGL2()) { final GL2 gl2 = gl.getGL2(); if (this.wireframe){ gl2.glDisable(GL.GL_CULL_FACE); gl2.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_LINE); } else { gl2.glEnable(GL.GL_CULL_FACE); gl2.glPolygonMode(GL2.GL_FRONT, GL2.GL_FILL); } this.checkTexture(glDrawable, INDEX_IMAGE); final TextureManager image = getTextureImg(); if(image != null && image.isUpdate()){ gl2.glEnable(GL.GL_TEXTURE_2D); image.bind(gl2); image.enable(gl2); }else{ gl2.glColor4f(0.4f, 0.4f, 0.4f, 0.4f); } if (!gl2.glIsEnabled(GL.GL_TEXTURE_2D)){ gl2.glColor4f(0.4f, 0.4f, 0.4f, 0.4f); } gl2.glEnableClientState(GL2.GL_VERTEX_ARRAY); gl2.glVertexPointer(3, GL.GL_FLOAT, 0, this.verticesb.rewind()); if (this.normalb != null){ gl2.glEnableClientState(GL2.GL_NORMAL_ARRAY); gl2.glNormalPointer(GL.GL_FLOAT, 0, this.normalb.rewind()); } gl2.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY); gl2.glTexCoordPointer(2, GL.GL_FLOAT, 0, this.uvsb.rewind()); gl2.glDrawElements(GL2.GL_TRIANGLES, this.getNumIndices(), GL2.GL_UNSIGNED_INT, this.indicesb.rewind()); if(image != null){ gl2.glDisable(GL.GL_TEXTURE_2D); }else{ gl2.glColor4f(1.0f, 1.0f,1.0f, 1.0f); } if (this.wireframe){ gl2.glEnable(GL.GL_CULL_FACE); } } } @Override public void dispose(GLAutoDrawable glDrawable) { super.dispose(glDrawable); } }