Java tutorial
/* * Copyright (C) 2017 Google Inc. * * 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 com.google.gapid.glviewer; import com.google.gapid.glviewer.camera.Emitter; import com.google.gapid.glviewer.geo.BoundingBox; import com.google.gapid.glviewer.geo.Model; import com.google.gapid.glviewer.gl.IndexBuffer; import com.google.gapid.glviewer.gl.Renderer; import com.google.gapid.glviewer.gl.VertexBuffer; import com.google.gapid.glviewer.vec.MatD; import com.google.gapid.proto.service.api.API; import org.lwjgl.opengl.GL11; /** * Renders a {@link Model}. Can render the geometry using either y-up or z-up and as either a * point cloud, wire mesh, or solid. */ public class Geometry { public static final Geometry NULL = new Geometry(null, false); public final Model model; public final boolean zUp; public final MatD modelMatrix; public Geometry(Model model, boolean zUp) { this.model = model; this.zUp = zUp; this.modelMatrix = getBounds().getCenteringMatrix(Constants.SCENE_SCALE_FACTOR, zUp); } public BoundingBox getBounds() { return (model == null) ? new BoundingBox() : model.getBounds(); } public Renderable asRenderable(DisplayMode displayMode) { if (model == null) { return Renderable.NOOP; } final int polygonMode = displayMode.glPolygonMode; final int modelPrimitive = translatePrimitive(model.getPrimitive()); final float[] positions = model.getPositions(); final float[] normals = model.getNormals(); final int[] indices = isNonPolygonPoints(displayMode) ? null : model.getIndices(); return new Renderable() { private VertexBuffer positionBuffer; private VertexBuffer normalBuffer; private IndexBuffer indexBuffer; @Override public void init(Renderer renderer) { positionBuffer = renderer.newVertexBuffer(positions, 3); if (normals != null) { normalBuffer = renderer.newVertexBuffer(normals, 3); } if (indices != null) { indexBuffer = renderer.newIndexBuffer(indices); } } @Override public void render(Renderer renderer, State state) { state.transform.push(modelMatrix); state.transform.apply(state.shader); GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, polygonMode); state.shader.setAttribute(Constants.POSITION_ATTRIBUTE, positionBuffer); if (normalBuffer != null) { state.shader.setAttribute(Constants.NORMAL_ATTRIBUTE, normalBuffer); } else { state.shader.setAttribute(Constants.NORMAL_ATTRIBUTE, 1, 0, 0); } if (indexBuffer != null) { Renderer.draw(state.shader, modelPrimitive, indexBuffer); } else { Renderer.draw(state.shader, GL11.GL_POINTS, positions.length / 3); } GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL); state.transform.pop(); } @Override public void dispose(Renderer renderer) { if (positionBuffer != null) { positionBuffer.delete(); positionBuffer = null; } if (normalBuffer != null) { normalBuffer.delete(); normalBuffer = null; } if (indexBuffer != null) { indexBuffer.delete(); indexBuffer = null; } } }; } /** * @return an {@link Emitter} based on the bounding box. */ public Emitter getEmitter() { return Emitter.BoxEmitter.fromBoundingBox(getBounds().transform(modelMatrix)); } /** * @return whether the given {@link com.google.gapid.proto.service.api.API.DrawPrimitive} will be * considered a polygon by GL. I.e. not points or lines. */ public static boolean isPolygon(API.DrawPrimitive primitive) { switch (primitive) { case Triangles: case TriangleFan: case TriangleStrip: return true; default: return false; } } /** * @return whether the given {@link DisplayMode} will require special handling when rendering * the geometry. We control the rendering mode (points, wire mesh, solid) using glPolygonMode, * which only works if the underlying geometry is polygon. Since rendering lines as lines is fine, * even if it ignores glPolygonMode, the only case that requires special handling is rendering * non-polygons as points. */ private boolean isNonPolygonPoints(DisplayMode displayMode) { return displayMode == DisplayMode.POINTS && !isPolygon(model.getPrimitive()); } private static int translatePrimitive(API.DrawPrimitive primitive) { switch (primitive) { case Points: return GL11.GL_POINTS; case Lines: return GL11.GL_LINES; case LineStrip: return GL11.GL_LINE_STRIP; case LineLoop: return GL11.GL_LINE_LOOP; case Triangles: return GL11.GL_TRIANGLES; case TriangleStrip: return GL11.GL_TRIANGLE_STRIP; case TriangleFan: return GL11.GL_TRIANGLE_FAN; default: throw new AssertionError(); } } public static enum DisplayMode { POINTS(GL11.GL_POINT), LINES(GL11.GL_LINE), TRIANGLES(GL11.GL_FILL); public final int glPolygonMode; DisplayMode(int glPolygonMode) { this.glPolygonMode = glPolygonMode; } } }