com.google.gapid.glviewer.Geometry.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gapid.glviewer.Geometry.java

Source

/*
 * 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;
        }
    }
}