From 24c514a8eda21b6e417a27dbfe45212203dd4b48 Mon Sep 17 00:00:00 2001 From: Eduardo Ramos Date: Fri, 28 Jul 2023 17:45:47 +0200 Subject: [PATCH] WIP: Adding back JOGL implementation based on current LWJGL code --- .../jogl/availability/InstancedDraw.java | 4 +- .../jogl/models/EdgeLineModelDirected.java | 161 ++++-- .../jogl/models/EdgeLineModelUndirected.java | 164 ++++-- .../viz/engine/jogl/models/NodeDiskModel.java | 194 ++++--- .../models/NodeDiskVertexDataGenerator.java | 58 ++ .../pipeline/arrays/ArrayDrawEdgeData.java | 246 ++++----- .../pipeline/arrays/ArrayDrawNodeData.java | 325 +++-------- .../renderers/EdgeRendererArrayDraw.java | 24 +- .../renderers/NodeRendererArrayDraw.java | 24 +- .../RectangleSelectionArrayDraw.java | 231 ++++++++ .../pipeline/common/AbstractEdgeData.java | 428 +++++++++++---- .../pipeline/common/AbstractEdgeRenderer.java | 32 ++ .../pipeline/common/AbstractNodeData.java | 504 +++++++++++++++--- .../pipeline/common/AbstractNodeRenderer.java | 31 ++ .../capabilities/GLCapabilitiesSummary.java | 5 +- 15 files changed, 1618 insertions(+), 813 deletions(-) create mode 100644 modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/NodeDiskVertexDataGenerator.java create mode 100644 modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/renderers/RectangleSelectionArrayDraw.java create mode 100644 modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractEdgeRenderer.java create mode 100644 modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractNodeRenderer.java diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/availability/InstancedDraw.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/availability/InstancedDraw.java index 891daaf..76ade55 100644 --- a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/availability/InstancedDraw.java +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/availability/InstancedDraw.java @@ -23,8 +23,6 @@ public static boolean isAvailable(VizEngine engine, GLAutoDrawable drawable) { final GLCapabilitiesSummary caps = engine.getLookup().lookup(GLCapabilitiesSummary.class); return drawable.getGLProfile().isGL2ES3() - && caps.isInstancingSupported() - && caps.getExtensions().ARB_base_instance//Maybe we can avoid this extension with separated gl buffers... - ; + && caps.isInstancingSupported(); } } diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/EdgeLineModelDirected.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/EdgeLineModelDirected.java index 44e211d..b994aa0 100644 --- a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/EdgeLineModelDirected.java +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/EdgeLineModelDirected.java @@ -1,9 +1,10 @@ package org.gephi.viz.engine.jogl.models; -import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2ES2; -import com.jogamp.opengl.GL2ES3; +import com.jogamp.opengl.GL3ES3; import org.gephi.viz.engine.util.gl.Constants; + +import static com.jogamp.opengl.GL.GL_TRIANGLES; import static org.gephi.viz.engine.util.gl.Constants.*; import org.gephi.viz.engine.util.NumberUtils; import org.gephi.viz.engine.jogl.util.gl.GLShaderProgram; @@ -19,28 +20,25 @@ public class EdgeLineModelDirected { public static final int POSITION_TARGET_FLOATS = 2; public static final int SOURCE_COLOR_FLOATS = 1; public static final int COLOR_FLOATS = 1; - public static final int COLOR_BIAS_FLOATS = 1; - public static final int COLOR_MULTIPLIER_FLOATS = 1; public static final int TARGET_SIZE_FLOATS = 1; public static final int SIZE_FLOATS = 1; public static final int TOTAL_ATTRIBUTES_FLOATS - = POSITION_SOURCE_FLOATS - + POSITION_TARGET_FLOATS - + SOURCE_COLOR_FLOATS - + COLOR_FLOATS - + COLOR_BIAS_FLOATS - + COLOR_MULTIPLIER_FLOATS - + TARGET_SIZE_FLOATS - + SIZE_FLOATS; + = POSITION_SOURCE_FLOATS + + POSITION_TARGET_FLOATS + + SOURCE_COLOR_FLOATS + + COLOR_FLOATS + + TARGET_SIZE_FLOATS + + SIZE_FLOATS; private static final int VERTEX_PER_TRIANGLE = 3; public static final int TRIANGLE_COUNT = 3; public static final int VERTEX_COUNT = TRIANGLE_COUNT * VERTEX_PER_TRIANGLE; - public static final int FLOATS_COUNT = VERTEX_COUNT * VERTEX_FLOATS; private GLShaderProgram program; + private GLShaderProgram programWithSelectionSelected; + private GLShaderProgram programWithSelectionUnselected; public int getVertexCount() { return VERTEX_COUNT; @@ -53,60 +51,93 @@ public void initGLPrograms(GL2ES2 gl) { private static final String SHADERS_ROOT = Constants.SHADERS_ROOT + "edge"; private static final String SHADERS_EDGE_LINE_SOURCE = "edge-line-directed"; + private static final String SHADERS_EDGE_LINE_SOURCE_WITH_SELECTION_SELECTED = "edge-line-directed_with_selection_selected"; + private static final String SHADERS_EDGE_LINE_SOURCE_WITH_SELECTION_UNSELECTED = "edge-line-directed_with_selection_unselected"; private void initProgram(GL2ES2 gl) { program = new GLShaderProgram(SHADERS_ROOT, SHADERS_EDGE_LINE_SOURCE, SHADERS_EDGE_LINE_SOURCE) - .addUniformName(UNIFORM_NAME_MODEL_VIEW_PROJECTION) - .addUniformName(UNIFORM_NAME_BACKGROUND_COLOR) - .addUniformName(UNIFORM_NAME_COLOR_LIGHTEN_FACTOR) - .addUniformName(UNIFORM_NAME_EDGE_SCALE_MIN) - .addUniformName(UNIFORM_NAME_EDGE_SCALE_MAX) - .addUniformName(UNIFORM_NAME_MIN_WEIGHT) - .addUniformName(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR) - .addAttribLocation(ATTRIB_NAME_VERT, SHADER_VERT_LOCATION) - .addAttribLocation(ATTRIB_NAME_POSITION, SHADER_POSITION_LOCATION) - .addAttribLocation(ATTRIB_NAME_POSITION_TARGET, SHADER_POSITION_TARGET_LOCATION) - .addAttribLocation(ATTRIB_NAME_SIZE, SHADER_SIZE_LOCATION) - .addAttribLocation(ATTRIB_NAME_SOURCE_COLOR, SHADER_SOURCE_COLOR_LOCATION) - .addAttribLocation(ATTRIB_NAME_COLOR, SHADER_COLOR_LOCATION) - .addAttribLocation(ATTRIB_NAME_COLOR_BIAS, SHADER_COLOR_BIAS_LOCATION) - .addAttribLocation(ATTRIB_NAME_COLOR_MULTIPLIER, SHADER_COLOR_MULTIPLIER_LOCATION) - .addAttribLocation(ATTRIB_NAME_TARGET_SIZE, SHADER_TARGET_SIZE_LOCATION) - .init(gl); + .addUniformName(UNIFORM_NAME_MODEL_VIEW_PROJECTION) + .addUniformName(UNIFORM_NAME_EDGE_SCALE_MIN) + .addUniformName(UNIFORM_NAME_EDGE_SCALE_MAX) + .addUniformName(UNIFORM_NAME_MIN_WEIGHT) + .addUniformName(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR) + .addAttribLocation(ATTRIB_NAME_VERT, SHADER_VERT_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION, SHADER_POSITION_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION_TARGET, SHADER_POSITION_TARGET_LOCATION) + .addAttribLocation(ATTRIB_NAME_SIZE, SHADER_SIZE_LOCATION) + .addAttribLocation(ATTRIB_NAME_SOURCE_COLOR, SHADER_SOURCE_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_COLOR, SHADER_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_TARGET_SIZE, SHADER_TARGET_SIZE_LOCATION) + .init(gl); + + programWithSelectionSelected = new GLShaderProgram(SHADERS_ROOT, SHADERS_EDGE_LINE_SOURCE_WITH_SELECTION_SELECTED, SHADERS_EDGE_LINE_SOURCE) + .addUniformName(UNIFORM_NAME_MODEL_VIEW_PROJECTION) + .addUniformName(UNIFORM_NAME_COLOR_BIAS) + .addUniformName(UNIFORM_NAME_COLOR_MULTIPLIER) + .addUniformName(UNIFORM_NAME_EDGE_SCALE_MIN) + .addUniformName(UNIFORM_NAME_EDGE_SCALE_MAX) + .addUniformName(UNIFORM_NAME_MIN_WEIGHT) + .addUniformName(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR) + .addAttribLocation(ATTRIB_NAME_VERT, SHADER_VERT_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION, SHADER_POSITION_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION_TARGET, SHADER_POSITION_TARGET_LOCATION) + .addAttribLocation(ATTRIB_NAME_SIZE, SHADER_SIZE_LOCATION) + .addAttribLocation(ATTRIB_NAME_SOURCE_COLOR, SHADER_SOURCE_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_COLOR, SHADER_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_TARGET_SIZE, SHADER_TARGET_SIZE_LOCATION) + .init(gl); + + programWithSelectionUnselected = new GLShaderProgram(SHADERS_ROOT, SHADERS_EDGE_LINE_SOURCE_WITH_SELECTION_UNSELECTED, SHADERS_EDGE_LINE_SOURCE) + .addUniformName(UNIFORM_NAME_MODEL_VIEW_PROJECTION) + .addUniformName(UNIFORM_NAME_BACKGROUND_COLOR) + .addUniformName(UNIFORM_NAME_COLOR_LIGHTEN_FACTOR) + .addUniformName(UNIFORM_NAME_EDGE_SCALE_MIN) + .addUniformName(UNIFORM_NAME_EDGE_SCALE_MAX) + .addUniformName(UNIFORM_NAME_MIN_WEIGHT) + .addUniformName(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR) + .addAttribLocation(ATTRIB_NAME_VERT, SHADER_VERT_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION, SHADER_POSITION_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION_TARGET, SHADER_POSITION_TARGET_LOCATION) + .addAttribLocation(ATTRIB_NAME_SIZE, SHADER_SIZE_LOCATION) + .addAttribLocation(ATTRIB_NAME_SOURCE_COLOR, SHADER_SOURCE_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_COLOR, SHADER_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_TARGET_SIZE, SHADER_TARGET_SIZE_LOCATION) + .init(gl); } - public void drawArraysSingleInstance(GL2ES2 gl) { - gl.glDrawArrays(GL.GL_TRIANGLES, 0, VERTEX_COUNT); + public void drawArraysMultipleInstance(GL2ES2 gl, final int drawBatchCount) { + if (drawBatchCount <= 0){ + return; + } + //Multiple lines, attributes must be in the buffer once per vertex count: + gl.glDrawArrays(GL_TRIANGLES, 0, VERTEX_COUNT * drawBatchCount); } - public void drawArraysMultipleInstance(GL2ES2 gl, int drawBatchCount) { - //Multiple lines, attributes must be in the buffer once per vertex count: - gl.glDrawArrays(GL.GL_TRIANGLES, 0, VERTEX_COUNT * drawBatchCount); + public void drawInstanced(GL3ES3 gl, int instanceCount) { + gl.glDrawArraysInstanced(GL_TRIANGLES, 0, VERTEX_COUNT, instanceCount); } - public void drawInstanced(GL2ES3 gl, float[] mvpFloats, float[] backgroundColorFloats, float colorLightenFactor, int instanceCount, int instancesOffset, float scale, float minWeight, float maxWeight) { - useProgram(gl, mvpFloats, backgroundColorFloats, colorLightenFactor, scale, minWeight, maxWeight); - if (instancesOffset > 0) { - gl.glDrawArraysInstancedBaseInstance(GL.GL_TRIANGLES, 0, VERTEX_COUNT, instanceCount, instancesOffset); - } else { - gl.glDrawArraysInstanced(GL.GL_TRIANGLES, 0, VERTEX_COUNT, instanceCount); - } - stopUsingProgram(gl); + public void stopUsingProgram(GL2ES2 gl) { + gl.glUseProgram(0); } - public void useProgram(GL2ES2 gl, float[] mvpFloats, float[] backgroundColorFloats, float colorLightenFactor, float scale, float minWeight, float maxWeight) { + public void useProgram(GL2ES2 gl, float[] mvpFloats, float scale, float minWeight, float maxWeight) { program.use(gl); - prepareProgramData(gl, mvpFloats, backgroundColorFloats, colorLightenFactor, scale, minWeight, maxWeight); + prepareProgramData(gl, mvpFloats, scale, minWeight, maxWeight); } - public void stopUsingProgram(GL2ES2 gl) { - program.stopUsing(gl); + public void useProgramWithSelectionSelected(GL2ES2 gl, float[] mvpFloats, float scale, float minWeight, float maxWeight, float colorBias, float colorMultiplier) { + programWithSelectionSelected.use(gl); + prepareProgramDataWithSelectionSelected(gl, mvpFloats, scale, minWeight, maxWeight, colorBias, colorMultiplier); } - private void prepareProgramData(GL2ES2 gl, float[] mvpFloats, float[] backgroundColorFloats, float colorLightenFactor, float scale, float minWeight, float maxWeight) { + public void useProgramWithSelectionUnselected(GL2ES2 gl, float[] mvpFloats, float scale, float minWeight, float maxWeight, float[] backgroundColorFloats, float colorLightenFactor) { + programWithSelectionUnselected.use(gl); + prepareProgramDataWithSelectionUnselected(gl, mvpFloats, scale, minWeight, maxWeight, backgroundColorFloats, colorLightenFactor); + } + + private void prepareProgramData(GL2ES2 gl, float[] mvpFloats, float scale, float minWeight, float maxWeight) { gl.glUniformMatrix4fv(program.getUniformLocation(UNIFORM_NAME_MODEL_VIEW_PROJECTION), 1, false, mvpFloats, 0); - gl.glUniform4fv(program.getUniformLocation(UNIFORM_NAME_BACKGROUND_COLOR), 1, backgroundColorFloats, 0); - gl.glUniform1f(program.getUniformLocation(UNIFORM_NAME_COLOR_LIGHTEN_FACTOR), colorLightenFactor); gl.glUniform1f(program.getUniformLocation(UNIFORM_NAME_EDGE_SCALE_MIN), EDGE_SCALE_MIN * scale); gl.glUniform1f(program.getUniformLocation(UNIFORM_NAME_EDGE_SCALE_MAX), EDGE_SCALE_MAX * scale); gl.glUniform1f(program.getUniformLocation(UNIFORM_NAME_MIN_WEIGHT), minWeight); @@ -118,6 +149,36 @@ private void prepareProgramData(GL2ES2 gl, float[] mvpFloats, float[] background } } + private void prepareProgramDataWithSelectionSelected(GL2ES2 gl, float[] mvpFloats, float scale, float minWeight, float maxWeight, float colorBias, float colorMultiplier) { + gl.glUniformMatrix4fv(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_MODEL_VIEW_PROJECTION), 1, false, mvpFloats, 0); + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_COLOR_BIAS), colorBias); + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_COLOR_MULTIPLIER), colorMultiplier); + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_EDGE_SCALE_MIN), EDGE_SCALE_MIN * scale); + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_EDGE_SCALE_MAX), EDGE_SCALE_MAX * scale); + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_MIN_WEIGHT), minWeight); + + if (NumberUtils.equalsEpsilon(minWeight, maxWeight, 1e-3f)) { + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR), 1); + } else { + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR), maxWeight - minWeight); + } + } + + private void prepareProgramDataWithSelectionUnselected(GL2ES2 gl, float[] mvpFloats, float scale, float minWeight, float maxWeight, float[] backgroundColorFloats, float colorLightenFactor) { + gl.glUniformMatrix4fv(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_MODEL_VIEW_PROJECTION), 1, false, mvpFloats, 0); + gl.glUniform4fv(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_BACKGROUND_COLOR), 1, backgroundColorFloats, 0); + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_COLOR_LIGHTEN_FACTOR), colorLightenFactor); + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_EDGE_SCALE_MIN), EDGE_SCALE_MIN * scale); + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_EDGE_SCALE_MAX), EDGE_SCALE_MAX * scale); + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_MIN_WEIGHT), minWeight); + + if (NumberUtils.equalsEpsilon(minWeight, maxWeight, 1e-3f)) { + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR), 1); + } else { + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR), maxWeight - minWeight); + } + } + public static float[] getVertexData() { //lineEnd, sideVector, arrowHeight return new float[]{ diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/EdgeLineModelUndirected.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/EdgeLineModelUndirected.java index 23c9e9b..f2d0013 100644 --- a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/EdgeLineModelUndirected.java +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/EdgeLineModelUndirected.java @@ -1,9 +1,10 @@ package org.gephi.viz.engine.jogl.models; -import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2ES2; -import com.jogamp.opengl.GL2ES3; +import com.jogamp.opengl.GL3ES3; import org.gephi.viz.engine.util.gl.Constants; + +import static com.jogamp.opengl.GL.GL_TRIANGLES; import static org.gephi.viz.engine.util.gl.Constants.*; import org.gephi.viz.engine.util.NumberUtils; import org.gephi.viz.engine.jogl.util.gl.GLShaderProgram; @@ -20,27 +21,24 @@ public class EdgeLineModelUndirected { public static final int SOURCE_COLOR_FLOATS = 1; public static final int TARGET_COLOR_FLOATS = SOURCE_COLOR_FLOATS; public static final int COLOR_FLOATS = 1; - public static final int COLOR_BIAS_FLOATS = 1; - public static final int COLOR_MULTIPLIER_FLOATS = 1; public static final int SIZE_FLOATS = 1; public static final int TOTAL_ATTRIBUTES_FLOATS - = POSITION_SOURCE_FLOATS - + POSITION_TARGET_LOCATION - + SOURCE_COLOR_FLOATS - + TARGET_COLOR_FLOATS - + COLOR_FLOATS - + COLOR_BIAS_FLOATS - + COLOR_MULTIPLIER_FLOATS - + SIZE_FLOATS; + = POSITION_SOURCE_FLOATS + + POSITION_TARGET_LOCATION + + SOURCE_COLOR_FLOATS + + TARGET_COLOR_FLOATS + + COLOR_FLOATS + + SIZE_FLOATS; private static final int VERTEX_PER_TRIANGLE = 3; public static final int TRIANGLE_COUNT = 2; public static final int VERTEX_COUNT = TRIANGLE_COUNT * VERTEX_PER_TRIANGLE; - public static final int FLOATS_COUNT = VERTEX_COUNT * VERTEX_FLOATS; private GLShaderProgram program; + private GLShaderProgram programWithSelectionSelected; + private GLShaderProgram programWithSelectionUnselected; public int getVertexCount() { return VERTEX_COUNT; @@ -53,62 +51,98 @@ public void initGLPrograms(GL2ES2 gl) { private static final String SHADERS_ROOT = Constants.SHADERS_ROOT + "edge"; private static final String SHADERS_EDGE_LINE_SOURCE = "edge-line-undirected"; + private static final String SHADERS_EDGE_LINE_SOURCE_WITH_SELECTION_SELECTED = "edge-line-undirected_with_selection_selected"; + private static final String SHADERS_EDGE_LINE_SOURCE_WITH_SELECTION_UNSELECTED = "edge-line-undirected_with_selection_unselected"; private void initProgram(GL2ES2 gl) { program = new GLShaderProgram(SHADERS_ROOT, SHADERS_EDGE_LINE_SOURCE, SHADERS_EDGE_LINE_SOURCE) - .addUniformName(UNIFORM_NAME_MODEL_VIEW_PROJECTION) - .addUniformName(UNIFORM_NAME_BACKGROUND_COLOR) - .addUniformName(UNIFORM_NAME_COLOR_LIGHTEN_FACTOR) - .addUniformName(UNIFORM_NAME_EDGE_SCALE_MIN) - .addUniformName(UNIFORM_NAME_EDGE_SCALE_MAX) - .addUniformName(UNIFORM_NAME_MIN_WEIGHT) - .addUniformName(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR) - .addAttribLocation(ATTRIB_NAME_VERT, SHADER_VERT_LOCATION) - .addAttribLocation(ATTRIB_NAME_POSITION, SHADER_POSITION_LOCATION) - .addAttribLocation(ATTRIB_NAME_POSITION_TARGET, SHADER_POSITION_TARGET_LOCATION) - .addAttribLocation(ATTRIB_NAME_SIZE, SHADER_SIZE_LOCATION) - .addAttribLocation(ATTRIB_NAME_SOURCE_COLOR, SHADER_SOURCE_COLOR_LOCATION) - .addAttribLocation(ATTRIB_NAME_TARGET_COLOR, SHADER_TARGET_COLOR_LOCATION) - .addAttribLocation(ATTRIB_NAME_COLOR, SHADER_COLOR_LOCATION) - .addAttribLocation(ATTRIB_NAME_COLOR_BIAS, SHADER_COLOR_BIAS_LOCATION) - .addAttribLocation(ATTRIB_NAME_COLOR_MULTIPLIER, SHADER_COLOR_MULTIPLIER_LOCATION) - .init(gl); - } - - public void drawArraysSingleInstance(GL2ES2 gl) { - //Line: - gl.glDrawArrays(GL.GL_TRIANGLES, 0, VERTEX_COUNT); + .addUniformName(UNIFORM_NAME_MODEL_VIEW_PROJECTION) + .addUniformName(UNIFORM_NAME_COLOR_LIGHTEN_FACTOR) + .addUniformName(UNIFORM_NAME_EDGE_SCALE_MIN) + .addUniformName(UNIFORM_NAME_EDGE_SCALE_MAX) + .addUniformName(UNIFORM_NAME_MIN_WEIGHT) + .addUniformName(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR) + .addAttribLocation(ATTRIB_NAME_VERT, SHADER_VERT_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION, SHADER_POSITION_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION_TARGET, SHADER_POSITION_TARGET_LOCATION) + .addAttribLocation(ATTRIB_NAME_SIZE, SHADER_SIZE_LOCATION) + .addAttribLocation(ATTRIB_NAME_SOURCE_COLOR, SHADER_SOURCE_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_TARGET_COLOR, SHADER_TARGET_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_COLOR, SHADER_COLOR_LOCATION) + .init(gl); + + programWithSelectionSelected = new GLShaderProgram(SHADERS_ROOT, SHADERS_EDGE_LINE_SOURCE_WITH_SELECTION_SELECTED, SHADERS_EDGE_LINE_SOURCE) + .addUniformName(UNIFORM_NAME_MODEL_VIEW_PROJECTION) + .addUniformName(UNIFORM_NAME_COLOR_BIAS) + .addUniformName(UNIFORM_NAME_COLOR_MULTIPLIER) + .addUniformName(UNIFORM_NAME_EDGE_SCALE_MIN) + .addUniformName(UNIFORM_NAME_EDGE_SCALE_MAX) + .addUniformName(UNIFORM_NAME_MIN_WEIGHT) + .addUniformName(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR) + .addAttribLocation(ATTRIB_NAME_VERT, SHADER_VERT_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION, SHADER_POSITION_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION_TARGET, SHADER_POSITION_TARGET_LOCATION) + .addAttribLocation(ATTRIB_NAME_SIZE, SHADER_SIZE_LOCATION) + .addAttribLocation(ATTRIB_NAME_SOURCE_COLOR, SHADER_SOURCE_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_TARGET_COLOR, SHADER_TARGET_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_COLOR, SHADER_COLOR_LOCATION) + .init(gl); + + programWithSelectionUnselected = new GLShaderProgram(SHADERS_ROOT, SHADERS_EDGE_LINE_SOURCE_WITH_SELECTION_UNSELECTED, SHADERS_EDGE_LINE_SOURCE) + .addUniformName(UNIFORM_NAME_MODEL_VIEW_PROJECTION) + .addUniformName(UNIFORM_NAME_BACKGROUND_COLOR) + .addUniformName(UNIFORM_NAME_COLOR_LIGHTEN_FACTOR) + .addUniformName(UNIFORM_NAME_EDGE_SCALE_MIN) + .addUniformName(UNIFORM_NAME_EDGE_SCALE_MAX) + .addUniformName(UNIFORM_NAME_MIN_WEIGHT) + .addUniformName(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR) + .addAttribLocation(ATTRIB_NAME_VERT, SHADER_VERT_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION, SHADER_POSITION_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION_TARGET, SHADER_POSITION_TARGET_LOCATION) + .addAttribLocation(ATTRIB_NAME_SIZE, SHADER_SIZE_LOCATION) + .addAttribLocation(ATTRIB_NAME_SOURCE_COLOR, SHADER_SOURCE_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_TARGET_COLOR, SHADER_TARGET_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_COLOR, SHADER_COLOR_LOCATION) + .init(gl); } - public void drawArraysMultipleInstance(GL2ES2 gl, int drawBatchCount) { + public void drawArraysMultipleInstance(GL2ES2 gl, final int drawBatchCount) { + if (drawBatchCount <= 0) { + return; + } //Multiple lines, attributes must be in the buffer once per vertex count: - gl.glDrawArrays(GL.GL_TRIANGLES, 0, VERTEX_COUNT * drawBatchCount); + gl.glDrawArrays(GL_TRIANGLES, 0, VERTEX_COUNT * drawBatchCount); } - public void drawInstanced(GL2ES3 gl, float[] mvpFloats, float[] backgroundColorFloats, float colorLightenFactor, int instanceCount, int instancesOffset, float scale, float minWeight, float maxWeight) { - useProgram(gl, mvpFloats, backgroundColorFloats, colorLightenFactor, scale, minWeight, maxWeight); - if (instancesOffset > 0) { - gl.glDrawArraysInstancedBaseInstance(GL.GL_TRIANGLES, 0, VERTEX_COUNT, instanceCount, instancesOffset); - } else { - gl.glDrawArraysInstanced(GL.GL_TRIANGLES, 0, VERTEX_COUNT, instanceCount); + public void drawInstanced(GL3ES3 gl, int instanceCount) { + if (instanceCount <= 0) { + return; } - stopUsingProgram(gl); + gl.glDrawArraysInstanced(GL_TRIANGLES, 0, VERTEX_COUNT, instanceCount); } - public void useProgram(GL2ES2 gl, float[] mvpFloats, float[] backgroundColorFloats, float colorLightenFactor, float scale, float minWeight, float maxWeight) { + public void useProgram(GL2ES2 gl, float[] mvpFloats, float scale, float minWeight, float maxWeight) { //Line: program.use(gl); - prepareProgramData(gl, mvpFloats, backgroundColorFloats, colorLightenFactor, scale, minWeight, maxWeight); + prepareProgramData(gl, mvpFloats, scale, minWeight, maxWeight); + } + + public void useProgramWithSelectionSelected(GL2ES2 gl, float[] mvpFloats, float scale, float minWeight, float maxWeight, float colorBias, float colorMultiplier) { + programWithSelectionSelected.use(gl); + prepareProgramDataWithSelectionSelected(gl, mvpFloats, scale, minWeight, maxWeight, colorBias, colorMultiplier); + } + + public void useProgramWithSelectionUnselected(GL2ES2 gl, float[] mvpFloats, float scale, float minWeight, float maxWeight, float[] backgroundColorFloats, float colorLightenFactor) { + programWithSelectionUnselected.use(gl); + prepareProgramDataWithSelectionUnselected(gl, mvpFloats, scale, minWeight, maxWeight, backgroundColorFloats, colorLightenFactor); } public void stopUsingProgram(GL2ES2 gl) { - program.stopUsing(gl); + gl.glUseProgram(0); } - private void prepareProgramData(GL2ES2 gl, float[] mvpFloats, float[] backgroundColorFloats, float colorLightenFactor, float scale, float minWeight, float maxWeight) { + private void prepareProgramData(GL2ES2 gl, float[] mvpFloats, float scale, float minWeight, float maxWeight) { gl.glUniformMatrix4fv(program.getUniformLocation(UNIFORM_NAME_MODEL_VIEW_PROJECTION), 1, false, mvpFloats, 0); - gl.glUniform4fv(program.getUniformLocation(UNIFORM_NAME_BACKGROUND_COLOR), 1, backgroundColorFloats, 0); - gl.glUniform1f(program.getUniformLocation(UNIFORM_NAME_COLOR_LIGHTEN_FACTOR), colorLightenFactor); gl.glUniform1f(program.getUniformLocation(UNIFORM_NAME_EDGE_SCALE_MIN), EDGE_SCALE_MIN * scale); gl.glUniform1f(program.getUniformLocation(UNIFORM_NAME_EDGE_SCALE_MAX), EDGE_SCALE_MAX * scale); gl.glUniform1f(program.getUniformLocation(UNIFORM_NAME_MIN_WEIGHT), minWeight); @@ -120,6 +154,36 @@ private void prepareProgramData(GL2ES2 gl, float[] mvpFloats, float[] background } } + private void prepareProgramDataWithSelectionSelected(GL2ES2 gl, float[] mvpFloats, float scale, float minWeight, float maxWeight, float colorBias, float colorMultiplier) { + gl.glUniformMatrix4fv(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_MODEL_VIEW_PROJECTION), 1, false, mvpFloats, 0); + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_COLOR_BIAS), colorBias); + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_COLOR_MULTIPLIER), colorMultiplier); + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_EDGE_SCALE_MIN), EDGE_SCALE_MIN * scale); + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_EDGE_SCALE_MAX), EDGE_SCALE_MAX * scale); + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_MIN_WEIGHT), minWeight); + + if (NumberUtils.equalsEpsilon(minWeight, maxWeight, 1e-3f)) { + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR), 1); + } else { + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR), maxWeight - minWeight); + } + } + + private void prepareProgramDataWithSelectionUnselected(GL2ES2 gl, float[] mvpFloats, float scale, float minWeight, float maxWeight, float[] backgroundColorFloats, float colorLightenFactor) { + gl.glUniformMatrix4fv(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_MODEL_VIEW_PROJECTION), 1, false, mvpFloats, 0); + gl.glUniform4fv(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_BACKGROUND_COLOR), 1, backgroundColorFloats, 0); + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_COLOR_LIGHTEN_FACTOR), colorLightenFactor); + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_EDGE_SCALE_MIN), EDGE_SCALE_MIN * scale); + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_EDGE_SCALE_MAX), EDGE_SCALE_MAX * scale); + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_MIN_WEIGHT), minWeight); + + if (NumberUtils.equalsEpsilon(minWeight, maxWeight, 1e-3f)) { + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR), 1); + } else { + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_WEIGHT_DIFFERENCE_DIVISOR), maxWeight - minWeight); + } + } + public static float[] getVertexData() { //lineEnd, sideVector return new float[]{ diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/NodeDiskModel.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/NodeDiskModel.java index 90b9dbf..350fb82 100644 --- a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/NodeDiskModel.java +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/NodeDiskModel.java @@ -1,13 +1,28 @@ package org.gephi.viz.engine.jogl.models; -import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GL2ES3; +import com.jogamp.opengl.GL3; import com.jogamp.opengl.GL4; -import org.gephi.viz.engine.util.gl.Constants; -import static org.gephi.viz.engine.util.gl.Constants.*; import org.gephi.viz.engine.jogl.util.gl.GLShaderProgram; -import org.gephi.viz.engine.util.gl.GLConstants; +import org.gephi.viz.engine.util.gl.Constants; + +import static com.jogamp.opengl.GL.GL_TRIANGLES; +import static org.gephi.viz.engine.util.gl.Constants.ATTRIB_NAME_COLOR; +import static org.gephi.viz.engine.util.gl.Constants.ATTRIB_NAME_POSITION; +import static org.gephi.viz.engine.util.gl.Constants.ATTRIB_NAME_SIZE; +import static org.gephi.viz.engine.util.gl.Constants.ATTRIB_NAME_VERT; +import static org.gephi.viz.engine.util.gl.Constants.SHADER_COLOR_LOCATION; +import static org.gephi.viz.engine.util.gl.Constants.SHADER_POSITION_LOCATION; +import static org.gephi.viz.engine.util.gl.Constants.SHADER_SIZE_LOCATION; +import static org.gephi.viz.engine.util.gl.Constants.SHADER_VERT_LOCATION; +import static org.gephi.viz.engine.util.gl.Constants.UNIFORM_NAME_BACKGROUND_COLOR; +import static org.gephi.viz.engine.util.gl.Constants.UNIFORM_NAME_COLOR_BIAS; +import static org.gephi.viz.engine.util.gl.Constants.UNIFORM_NAME_COLOR_LIGHTEN_FACTOR; +import static org.gephi.viz.engine.util.gl.Constants.UNIFORM_NAME_COLOR_MULTIPLIER; +import static org.gephi.viz.engine.util.gl.Constants.UNIFORM_NAME_MODEL_VIEW_PROJECTION; +import static org.gephi.viz.engine.util.gl.Constants.UNIFORM_NAME_SIZE_MULTIPLIER; +import static org.gephi.viz.engine.util.gl.GLConstants.INDIRECT_DRAW_COMMAND_BYTES; /** * @author Eduardo Ramos @@ -17,132 +32,107 @@ public class NodeDiskModel { public static final int VERTEX_FLOATS = 2; public static final int POSITION_FLOATS = 2; public static final int COLOR_FLOATS = 1; - public static final int COLOR_BIAS_FLOATS = 1; - public static final int COLOR_MULTIPLIER_FLOATS = 1; public static final int SIZE_FLOATS = 1; public static final int TOTAL_ATTRIBUTES_FLOATS - = POSITION_FLOATS - + COLOR_FLOATS - + COLOR_BIAS_FLOATS - + COLOR_MULTIPLIER_FLOATS - + SIZE_FLOATS; - - private final int triangleAmount; - private final float[] vertexData; - private final int vertexCount; + = POSITION_FLOATS + + COLOR_FLOATS + + SIZE_FLOATS; private GLShaderProgram program; - - public NodeDiskModel(int triangleAmount) { - this.triangleAmount = triangleAmount; - this.vertexData = generateFilledCircle(triangleAmount); - - this.vertexCount = triangleAmount * 3; - } - - public int getTriangleAmount() { - return triangleAmount; - } - - public int getVertexCount() { - return vertexCount; - } - - public float[] getVertexData() { - return vertexData; - } - - public void initGLPrograms(GL2ES2 gl) { - initProgram(gl); - } + private GLShaderProgram programWithSelectionSelected; + private GLShaderProgram programWithSelectionUnselected; private static final String SHADERS_ROOT = Constants.SHADERS_ROOT + "node"; private static final String SHADERS_NODE_CIRCLE_SOURCE = "node"; + private static final String SHADERS_NODE_CIRCLE_SOURCE_WITH_SELECTION_SELECTED = "node_with_selection_selected"; + private static final String SHADERS_NODE_CIRCLE_SOURCE_WITH_SELECTION_UNSELECTED = "node_with_selection_unselected"; - private void initProgram(GL2ES2 gl) { + public void initGLPrograms(GL2ES2 gl) { program = new GLShaderProgram(SHADERS_ROOT, SHADERS_NODE_CIRCLE_SOURCE, SHADERS_NODE_CIRCLE_SOURCE) - .addUniformName(UNIFORM_NAME_MODEL_VIEW_PROJECTION) - .addUniformName(UNIFORM_NAME_BACKGROUND_COLOR) - .addUniformName(UNIFORM_NAME_COLOR_LIGHTEN_FACTOR) - .addAttribLocation(ATTRIB_NAME_VERT, SHADER_VERT_LOCATION) - .addAttribLocation(ATTRIB_NAME_POSITION, SHADER_POSITION_LOCATION) - .addAttribLocation(ATTRIB_NAME_COLOR, SHADER_COLOR_LOCATION) - .addAttribLocation(ATTRIB_NAME_COLOR_BIAS, SHADER_COLOR_BIAS_LOCATION) - .addAttribLocation(ATTRIB_NAME_COLOR_MULTIPLIER, SHADER_COLOR_MULTIPLIER_LOCATION) - .addAttribLocation(ATTRIB_NAME_SIZE, SHADER_SIZE_LOCATION) - .init(gl); + .addUniformName(UNIFORM_NAME_MODEL_VIEW_PROJECTION) + .addUniformName(UNIFORM_NAME_SIZE_MULTIPLIER) + .addUniformName(UNIFORM_NAME_COLOR_MULTIPLIER) + .addAttribLocation(ATTRIB_NAME_VERT, SHADER_VERT_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION, SHADER_POSITION_LOCATION) + .addAttribLocation(ATTRIB_NAME_COLOR, SHADER_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_SIZE, SHADER_SIZE_LOCATION) + .init(gl); + + programWithSelectionSelected = new GLShaderProgram(SHADERS_ROOT, SHADERS_NODE_CIRCLE_SOURCE_WITH_SELECTION_SELECTED, SHADERS_NODE_CIRCLE_SOURCE) + .addUniformName(UNIFORM_NAME_MODEL_VIEW_PROJECTION) + .addUniformName(UNIFORM_NAME_SIZE_MULTIPLIER) + .addUniformName(UNIFORM_NAME_COLOR_BIAS) + .addUniformName(UNIFORM_NAME_COLOR_MULTIPLIER) + .addAttribLocation(ATTRIB_NAME_VERT, SHADER_VERT_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION, SHADER_POSITION_LOCATION) + .addAttribLocation(ATTRIB_NAME_COLOR, SHADER_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_SIZE, SHADER_SIZE_LOCATION) + .init(gl); + + programWithSelectionUnselected = new GLShaderProgram(SHADERS_ROOT, SHADERS_NODE_CIRCLE_SOURCE_WITH_SELECTION_UNSELECTED, SHADERS_NODE_CIRCLE_SOURCE) + .addUniformName(UNIFORM_NAME_MODEL_VIEW_PROJECTION) + .addUniformName(UNIFORM_NAME_COLOR_MULTIPLIER) + .addUniformName(UNIFORM_NAME_BACKGROUND_COLOR) + .addUniformName(UNIFORM_NAME_COLOR_LIGHTEN_FACTOR) + .addUniformName(UNIFORM_NAME_SIZE_MULTIPLIER) + .addAttribLocation(ATTRIB_NAME_VERT, SHADER_VERT_LOCATION) + .addAttribLocation(ATTRIB_NAME_POSITION, SHADER_POSITION_LOCATION) + .addAttribLocation(ATTRIB_NAME_COLOR, SHADER_COLOR_LOCATION) + .addAttribLocation(ATTRIB_NAME_SIZE, SHADER_SIZE_LOCATION) + .init(gl); } public void drawArraysSingleInstance(GL2ES2 gl, int firstVertexIndex, int vertexCount) { - gl.glDrawArrays(GL.GL_TRIANGLES, firstVertexIndex, vertexCount); + gl.glDrawArrays(GL_TRIANGLES, firstVertexIndex, vertexCount); } - public void drawInstanced(GL2ES3 gl, int vertexOffset, float[] mvpFloats, float[] backgroundColorFloats, float colorLightenFactor, int instanceCount, int instancesOffset) { - useProgram(gl, mvpFloats, backgroundColorFloats, colorLightenFactor); - if (instancesOffset > 0) { - gl.glDrawArraysInstancedBaseInstance(GL.GL_TRIANGLES, vertexOffset, vertexCount, instanceCount, instancesOffset); - } else { - gl.glDrawArraysInstanced(GL.GL_TRIANGLES, vertexOffset, vertexCount, instanceCount); + public void drawInstanced(GL2ES3 gl, int vertexOffset, int vertexCount, int instanceCount) { + if (instanceCount <= 0) { + return; } - stopUsingProgram(gl); + gl.glDrawArraysInstanced(GL_TRIANGLES, vertexOffset, vertexCount, instanceCount); } - public void drawInstanced(GL2ES3 gl, float[] mvpFloats, float[] backgroundColorFloats, float colorLightenFactor, int instanceCount, int instancesOffset) { - drawInstanced(gl, 0, mvpFloats, backgroundColorFloats, colorLightenFactor, instanceCount, instancesOffset); - } - - public void drawIndirect(GL4 gl, float[] mvpFloats, float[] backgroundColorFloats, float colorLightenFactor, int instanceCount, int instancesOffset) { - useProgram(gl, mvpFloats, backgroundColorFloats, colorLightenFactor); - gl.glMultiDrawArraysIndirect(GL.GL_TRIANGLES, instancesOffset * GLConstants.INDIRECT_DRAW_COMMAND_BYTES, instanceCount, GLConstants.INDIRECT_DRAW_COMMAND_BYTES); - stopUsingProgram(gl); + public void drawIndirect(GL3 gl, int instanceCount, int instancesOffset) { + if (instanceCount <= 0) { + return; + } + gl.glMultiDrawArraysIndirect(GL_TRIANGLES, (long) instancesOffset * INDIRECT_DRAW_COMMAND_BYTES, instanceCount, 0); } - public void useProgram(GL2ES2 gl, float[] mvpFloats, float[] backgroundColorFloats, float colorLightenFactor) { + public void useProgramWithSelectionSelected(GL2ES2 gl, float[] mvpFloats, float sizeMultiplier, float colorBias, float colorMultiplier) { //Circle: - program.use(gl); - gl.glUniformMatrix4fv(program.getUniformLocation(UNIFORM_NAME_MODEL_VIEW_PROJECTION), 1, false, mvpFloats, 0); - gl.glUniform4fv(program.getUniformLocation(UNIFORM_NAME_BACKGROUND_COLOR), 1, backgroundColorFloats, 0); - gl.glUniform1f(program.getUniformLocation(UNIFORM_NAME_COLOR_LIGHTEN_FACTOR), colorLightenFactor); - } - - public void stopUsingProgram(GL2ES2 gl) { - program.stopUsing(gl); - } + programWithSelectionSelected.use(gl); - public GLShaderProgram getCircleProgram() { - return program; + gl.glUniformMatrix4fv(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_MODEL_VIEW_PROJECTION), 1, false, mvpFloats, 0); + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_SIZE_MULTIPLIER), sizeMultiplier); + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_COLOR_BIAS), colorBias); + gl.glUniform1f(programWithSelectionSelected.getUniformLocation(UNIFORM_NAME_COLOR_MULTIPLIER), colorMultiplier); } - private static float[] generateFilledCircle(int triangleAmount) { - final double twicePi = 2.0 * Math.PI; + public void useProgramWithSelectionUnselected(GL2ES2 gl, float[] mvpFloats, float sizeMultiplier, float[] backgroundColorFloats, float colorLightenFactor, float colorMultiplier) { + //Circle: + programWithSelectionUnselected.use(gl); - final int circleFloatsCount = (triangleAmount * 3) * VERTEX_FLOATS; - final float[] data = new float[circleFloatsCount]; - final int triangleFloats = 3 * VERTEX_FLOATS; + gl.glUniformMatrix4fv(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_MODEL_VIEW_PROJECTION), 1, false, mvpFloats, 0); + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_COLOR_MULTIPLIER), colorMultiplier); + gl.glUniform4fv(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_BACKGROUND_COLOR), 1, backgroundColorFloats, 0); + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_COLOR_LIGHTEN_FACTOR), colorLightenFactor); + gl.glUniform1f(programWithSelectionUnselected.getUniformLocation(UNIFORM_NAME_SIZE_MULTIPLIER), sizeMultiplier); + } + public void useProgram(GL2ES2 gl, float[] mvpFloats, float sizeMultiplier, float colorMultiplier) { //Circle: - for (int i = 1, j = 0; i <= triangleAmount; i++, j += triangleFloats) { - //Center - data[j + 0] = 0;//X - data[j + 1] = 0;//Y - - //Triangle start: - data[j + 2] = (float) Math.cos((i - 1) * twicePi / triangleAmount);//X - data[j + 3] = (float) Math.sin((i - 1) * twicePi / triangleAmount);//Y - - //Triangle end: - if (i == triangleAmount) { - //Last point - data[j + 4] = 1;//X - data[j + 5] = 0;//Y - } else { - data[j + 4] = (float) Math.cos(i * twicePi / triangleAmount);//X - data[j + 5] = (float) Math.sin(i * twicePi / triangleAmount);//Y - } - } + program.use(gl); - return data; + gl.glUniformMatrix4fv(program.getUniformLocation(UNIFORM_NAME_MODEL_VIEW_PROJECTION), 1, false, mvpFloats, 0); + gl.glUniform1f(program.getUniformLocation(UNIFORM_NAME_SIZE_MULTIPLIER), sizeMultiplier); + gl.glUniform1f(program.getUniformLocation(UNIFORM_NAME_COLOR_MULTIPLIER), colorMultiplier); + } + + public void stopUsingProgram(GL2ES2 gl) { + gl.glUseProgram(0); } } diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/NodeDiskVertexDataGenerator.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/NodeDiskVertexDataGenerator.java new file mode 100644 index 0000000..2f02078 --- /dev/null +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/models/NodeDiskVertexDataGenerator.java @@ -0,0 +1,58 @@ +package org.gephi.viz.engine.jogl.models; + +public class NodeDiskVertexDataGenerator { + public static final int VERTEX_FLOATS = 2; + private final int triangleAmount; + private final float[] vertexData; + private final int vertexCount; + + public NodeDiskVertexDataGenerator(int triangleAmount) { + this.triangleAmount = triangleAmount; + this.vertexData = generateFilledCircle(triangleAmount); + + this.vertexCount = triangleAmount * 3; + } + + public int getTriangleAmount() { + return triangleAmount; + } + + public int getVertexCount() { + return vertexCount; + } + + public float[] getVertexData() { + return vertexData; + } + + private static float[] generateFilledCircle(int triangleAmount) { + final double twicePi = 2.0 * Math.PI; + + final int circleFloatsCount = (triangleAmount * 3) * VERTEX_FLOATS; + final float[] data = new float[circleFloatsCount]; + final int triangleFloats = 3 * VERTEX_FLOATS; + + //Circle: + for (int i = 1, j = 0; i <= triangleAmount; i++, j += triangleFloats) { + //Center + data[j + 0] = 0;//X + data[j + 1] = 0;//Y + + //Triangle start: + data[j + 2] = (float) Math.cos((i - 1) * twicePi / triangleAmount);//X + data[j + 3] = (float) Math.sin((i - 1) * twicePi / triangleAmount);//Y + + //Triangle end: + if (i == triangleAmount) { + //Last point + data[j + 4] = 1;//X + data[j + 5] = 0;//Y + } else { + data[j + 4] = (float) Math.cos(i * twicePi / triangleAmount);//X + data[j + 5] = (float) Math.sin(i * twicePi / triangleAmount);//Y + } + } + + return data; + } +} diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/ArrayDrawEdgeData.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/ArrayDrawEdgeData.java index 309184a..ac6f456 100644 --- a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/ArrayDrawEdgeData.java +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/ArrayDrawEdgeData.java @@ -2,6 +2,8 @@ import com.jogamp.opengl.GL; import static com.jogamp.opengl.GL.GL_FLOAT; +import static org.gephi.viz.engine.pipeline.RenderingLayer.BACK1; + import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.util.GLBuffers; import java.nio.FloatBuffer; @@ -28,158 +30,118 @@ */ public class ArrayDrawEdgeData extends AbstractEdgeData { - private IntBuffer bufferName; + private final int[] bufferName = new int[4]; private static final int VERT_BUFFER_UNDIRECTED = 0; private static final int VERT_BUFFER_DIRECTED = 1; - private static final int ATTRIBS_BUFFER = 2; + private static final int ATTRIBS_BUFFER_DIRECTED = 2; + private static final int ATTRIBS_BUFFER_UNDIRECTED = 3; public ArrayDrawEdgeData() { - super(false); - } - - @Override - public void init(GL2ES2 gl) { - super.init(gl); - initBuffers(gl); + super(false, false); } public void update(VizEngine engine, GraphIndexImpl graphIndex) { updateData( - graphIndex, - engine.getLookup().lookup(GraphRenderingOptions.class), - engine.getLookup().lookup(GraphSelection.class) + graphIndex, + engine.getLookup().lookup(GraphRenderingOptions.class), + engine.getLookup().lookup(GraphSelection.class) ); } public void drawArrays(GL2ES2 gl, RenderingLayer layer, VizEngine engine, float[] mvpFloats) { - GraphRenderingOptions renderingOptions = engine.getLookup().lookup(GraphRenderingOptions.class); - - final float[] backgroundColorFloats = engine.getBackgroundColor(); - final float edgeScale = renderingOptions.getEdgeScale(); - float lightenNonSelectedFactor = renderingOptions.getLightenNonSelectedFactor(); + drawUndirected(gl, engine, layer, mvpFloats); + drawDirected(gl, engine, layer, mvpFloats); + } - final GraphIndex graphIndex = engine.getLookup().lookup(GraphIndex.class); + private void drawUndirected(GL2ES2 gl, VizEngine engine, RenderingLayer layer, float[] mvpFloats) { + final int instanceCount = setupShaderProgramForRenderingLayerUndirected(gl, layer, engine, mvpFloats); - final float minWeight = graphIndex.getEdgesMinWeight(); - final float maxWeight = graphIndex.getEdgesMaxWeight(); + final boolean renderingUnselectedEdges = layer == BACK1; + final int instancesOffset = renderingUnselectedEdges ? 0 : undirectedInstanceCounter.unselectedCountToDraw; - drawUndirected(engine, layer, gl, mvpFloats, backgroundColorFloats, lightenNonSelectedFactor, edgeScale, minWeight, maxWeight); - drawDirected(engine, layer, gl, mvpFloats, backgroundColorFloats, lightenNonSelectedFactor, edgeScale, minWeight, maxWeight); - } + final FloatBuffer batchUpdateBuffer = attributesDrawBufferBatchOneCopyPerVertexManagedDirectBuffer.floatBuffer(); - private void drawUndirected(VizEngine engine, RenderingLayer layer, GL2ES2 gl, float[] mvpFloats, float[] backgroundColorFloats, float lightenNonSelectedFactor, float edgeScale, float minWeight, float maxWeight) { - final int instanceCount; - final int instancesOffset; - final float colorLightenFactor; + final int maxIndex = (instancesOffset + instanceCount); + for (int edgeBase = instancesOffset; edgeBase < maxIndex; edgeBase += BATCH_EDGES_SIZE) { + final int drawBatchCount = Math.min(maxIndex - edgeBase, BATCH_EDGES_SIZE); - if (layer == RenderingLayer.BACK) { - instanceCount = undirectedInstanceCounter.unselectedCountToDraw; - instancesOffset = 0; - colorLightenFactor = lightenNonSelectedFactor; - } else { - instanceCount = undirectedInstanceCounter.selectedCountToDraw; - instancesOffset = undirectedInstanceCounter.unselectedCountToDraw; - colorLightenFactor = 0; - } + //Need to copy attributes as many times as vertex per model: + for (int edgeIndex = 0; edgeIndex < drawBatchCount; edgeIndex++) { + System.arraycopy( + attributesBuffer, (edgeBase + edgeIndex) * ATTRIBS_STRIDE, + attributesDrawBufferBatchOneCopyPerVertex, edgeIndex * ATTRIBS_STRIDE * VERTEX_COUNT_UNDIRECTED, + ATTRIBS_STRIDE + ); - if (instanceCount > 0) { - setupUndirectedVertexArrayAttributes(engine, gl); - lineModelUndirected.useProgram(gl, mvpFloats, backgroundColorFloats, colorLightenFactor, edgeScale, minWeight, maxWeight); - - final FloatBuffer batchUpdateBuffer = attributesDrawBufferBatchOneCopyPerVertexManagedDirectBuffer.floatBuffer(); - - final int maxIndex = (instancesOffset + instanceCount); - for (int edgeBase = instancesOffset; edgeBase < maxIndex; edgeBase += BATCH_EDGES_SIZE) { - final int drawBatchCount = Math.min(maxIndex - edgeBase, BATCH_EDGES_SIZE); - - //Need to copy attributes as many times as vertex per model: - for (int edgeIndex = 0; edgeIndex < drawBatchCount; edgeIndex++) { - System.arraycopy( - attributesBuffer, (edgeBase + edgeIndex) * ATTRIBS_STRIDE, - attributesDrawBufferBatchOneCopyPerVertex, edgeIndex * ATTRIBS_STRIDE * VERTEX_COUNT_UNDIRECTED, - ATTRIBS_STRIDE - ); - - ArrayUtils.repeat( - attributesDrawBufferBatchOneCopyPerVertex, - edgeIndex * ATTRIBS_STRIDE * VERTEX_COUNT_UNDIRECTED, - ATTRIBS_STRIDE, - VERTEX_COUNT_UNDIRECTED - ); - } - - batchUpdateBuffer.clear(); - batchUpdateBuffer.put(attributesDrawBufferBatchOneCopyPerVertex, 0, drawBatchCount * ATTRIBS_STRIDE * VERTEX_COUNT_UNDIRECTED); - batchUpdateBuffer.flip(); - - attributesGLBuffer.bind(gl); - attributesGLBuffer.updateWithOrphaning(gl, batchUpdateBuffer); - attributesGLBuffer.unbind(gl); - - lineModelUndirected.drawArraysMultipleInstance(gl, drawBatchCount); + ArrayUtils.repeat( + attributesDrawBufferBatchOneCopyPerVertex, + edgeIndex * ATTRIBS_STRIDE * VERTEX_COUNT_UNDIRECTED, + ATTRIBS_STRIDE, + VERTEX_COUNT_UNDIRECTED + ); } - lineModelUndirected.stopUsingProgram(gl); - unsetupUndirectedVertexArrayAttributes(gl); + batchUpdateBuffer.clear(); + batchUpdateBuffer.put(attributesDrawBufferBatchOneCopyPerVertex, 0, drawBatchCount * ATTRIBS_STRIDE * VERTEX_COUNT_UNDIRECTED); + batchUpdateBuffer.flip(); + + attributesGLBufferUndirected.bind(gl); + attributesGLBufferUndirected.updateWithOrphaning(gl, batchUpdateBuffer); + attributesGLBufferUndirected.unbind(gl); + lineModelUndirected.drawArraysMultipleInstance(gl, drawBatchCount); } + + lineModelUndirected.stopUsingProgram(gl); + unsetupUndirectedVertexArrayAttributes(gl); } - private void drawDirected(VizEngine engine, RenderingLayer layer, GL2ES2 gl, float[] mvpFloats, float[] backgroundColorFloats, float lightenNonSelectedFactor, float edgeScale, float minWeight, float maxWeight) { - final int instanceCount; - final int instancesOffset; - final float colorLightenFactor; + private void drawDirected(GL2ES2 gl, VizEngine engine, RenderingLayer layer, float[] mvpFloats) { + final int instanceCount = setupShaderProgramForRenderingLayerDirected(gl, layer, engine, mvpFloats); - if (layer == RenderingLayer.BACK) { - instanceCount = directedInstanceCounter.unselectedCountToDraw; + final boolean renderingUnselectedEdges = layer == BACK1; + final int instancesOffset; + if (renderingUnselectedEdges) { instancesOffset = undirectedInstanceCounter.totalToDraw(); - colorLightenFactor = lightenNonSelectedFactor; } else { - instanceCount = directedInstanceCounter.selectedCountToDraw; instancesOffset = undirectedInstanceCounter.totalToDraw() + directedInstanceCounter.unselectedCountToDraw; - colorLightenFactor = 0; } - if (instanceCount > 0) { - setupDirectedVertexArrayAttributes(engine, gl); - lineModelDirected.useProgram(gl, mvpFloats, backgroundColorFloats, colorLightenFactor, edgeScale, minWeight, maxWeight); - - final FloatBuffer batchUpdateBuffer = attributesDrawBufferBatchOneCopyPerVertexManagedDirectBuffer.floatBuffer(); - - final int maxIndex = (instancesOffset + instanceCount); - for (int edgeBase = instancesOffset; edgeBase < maxIndex; edgeBase += BATCH_EDGES_SIZE) { - final int drawBatchCount = Math.min(maxIndex - edgeBase, BATCH_EDGES_SIZE); - - //Need to copy attributes as many times as vertex per model: - for (int edgeIndex = 0; edgeIndex < drawBatchCount; edgeIndex++) { - System.arraycopy( - attributesBuffer, (edgeBase + edgeIndex) * ATTRIBS_STRIDE, - attributesDrawBufferBatchOneCopyPerVertex, edgeIndex * ATTRIBS_STRIDE * VERTEX_COUNT_DIRECTED, - ATTRIBS_STRIDE - ); - - ArrayUtils.repeat( - attributesDrawBufferBatchOneCopyPerVertex, - edgeIndex * ATTRIBS_STRIDE * VERTEX_COUNT_DIRECTED, - ATTRIBS_STRIDE, - VERTEX_COUNT_DIRECTED - ); - } - - batchUpdateBuffer.clear(); - batchUpdateBuffer.put(attributesDrawBufferBatchOneCopyPerVertex, 0, drawBatchCount * ATTRIBS_STRIDE * VERTEX_COUNT_DIRECTED); - batchUpdateBuffer.flip(); - - attributesGLBuffer.bind(gl); - attributesGLBuffer.updateWithOrphaning(gl, batchUpdateBuffer); - attributesGLBuffer.unbind(gl); - - lineModelDirected.drawArraysMultipleInstance(gl, drawBatchCount); + final FloatBuffer batchUpdateBuffer = attributesDrawBufferBatchOneCopyPerVertexManagedDirectBuffer.floatBuffer(); + + final int maxIndex = (instancesOffset + instanceCount); + for (int edgeBase = instancesOffset; edgeBase < maxIndex; edgeBase += BATCH_EDGES_SIZE) { + final int drawBatchCount = Math.min(maxIndex - edgeBase, BATCH_EDGES_SIZE); + + //Need to copy attributes as many times as vertex per model: + for (int edgeIndex = 0; edgeIndex < drawBatchCount; edgeIndex++) { + System.arraycopy( + attributesBuffer, (edgeBase + edgeIndex) * ATTRIBS_STRIDE, + attributesDrawBufferBatchOneCopyPerVertex, edgeIndex * ATTRIBS_STRIDE * VERTEX_COUNT_DIRECTED, + ATTRIBS_STRIDE + ); + + ArrayUtils.repeat( + attributesDrawBufferBatchOneCopyPerVertex, + edgeIndex * ATTRIBS_STRIDE * VERTEX_COUNT_DIRECTED, + ATTRIBS_STRIDE, + VERTEX_COUNT_DIRECTED + ); } - lineModelDirected.stopUsingProgram(gl); - unsetupDirectedVertexArrayAttributes(gl); + batchUpdateBuffer.clear(); + batchUpdateBuffer.put(attributesDrawBufferBatchOneCopyPerVertex, 0, drawBatchCount * ATTRIBS_STRIDE * VERTEX_COUNT_DIRECTED); + batchUpdateBuffer.flip(); + + attributesGLBufferDirected.bind(gl); + attributesGLBufferDirected.updateWithOrphaning(gl, batchUpdateBuffer); + attributesGLBufferDirected.unbind(gl); + + lineModelDirected.drawArraysMultipleInstance(gl, drawBatchCount); } + + lineModelDirected.stopUsingProgram(gl); + unsetupDirectedVertexArrayAttributes(gl); } private float[] attributesBuffer; @@ -190,13 +152,13 @@ private void drawDirected(VizEngine engine, RenderingLayer layer, GL2ES2 gl, flo private float[] attributesDrawBufferBatchOneCopyPerVertex; private ManagedDirectBuffer attributesDrawBufferBatchOneCopyPerVertexManagedDirectBuffer; - private void initBuffers(GL2ES2 gl) { + protected void initBuffers(GL2ES2 gl) { + super.initBuffers(); attributesDrawBufferBatchOneCopyPerVertex = new float[ATTRIBS_STRIDE * VERTEX_COUNT_MAX * BATCH_EDGES_SIZE];//Need to copy attributes as many times as vertex per model attributesDrawBufferBatchOneCopyPerVertexManagedDirectBuffer = new ManagedDirectBuffer(GL_FLOAT, ATTRIBS_STRIDE * VERTEX_COUNT_MAX * BATCH_EDGES_SIZE); - bufferName = GLBuffers.newDirectIntBuffer(3); + gl.glGenBuffers(bufferName.length, bufferName, 0); - gl.glGenBuffers(bufferName.capacity(), bufferName); { float[] singleElementData = EdgeLineModelUndirected.getVertexData(); float[] undirectedVertexDataArray = new float[singleElementData.length * BATCH_EDGES_SIZE]; @@ -204,10 +166,12 @@ private void initBuffers(GL2ES2 gl) { ArrayUtils.repeat(undirectedVertexDataArray, 0, singleElementData.length, BATCH_EDGES_SIZE); final FloatBuffer undirectedVertexData = GLBuffers.newDirectFloatBuffer(undirectedVertexDataArray); - vertexGLBufferUndirected = new GLBufferMutable(bufferName.get(VERT_BUFFER_UNDIRECTED), GLBufferMutable.GL_BUFFER_TYPE_ARRAY); + + vertexGLBufferUndirected = new GLBufferMutable(bufferName[VERT_BUFFER_UNDIRECTED], GLBufferMutable.GL_BUFFER_TYPE_ARRAY); vertexGLBufferUndirected.bind(gl); vertexGLBufferUndirected.init(gl, undirectedVertexData, GLBufferMutable.GL_BUFFER_USAGE_STATIC_DRAW); vertexGLBufferUndirected.unbind(gl); + BufferUtils.destroyDirectBuffer(undirectedVertexData); } @@ -218,18 +182,25 @@ private void initBuffers(GL2ES2 gl) { ArrayUtils.repeat(directedVertexDataArray, 0, singleElementData.length, BATCH_EDGES_SIZE); final FloatBuffer directedVertexData = GLBuffers.newDirectFloatBuffer(directedVertexDataArray); - vertexGLBufferDirected = new GLBufferMutable(bufferName.get(VERT_BUFFER_DIRECTED), GLBufferMutable.GL_BUFFER_TYPE_ARRAY); + + vertexGLBufferDirected = new GLBufferMutable(bufferName[VERT_BUFFER_DIRECTED], GLBufferMutable.GL_BUFFER_TYPE_ARRAY); vertexGLBufferDirected.bind(gl); vertexGLBufferDirected.init(gl, directedVertexData, GLBufferMutable.GL_BUFFER_USAGE_STATIC_DRAW); vertexGLBufferDirected.unbind(gl); + BufferUtils.destroyDirectBuffer(directedVertexData); } //Initialize for batch edges size: - attributesGLBuffer = new GLBufferMutable(bufferName.get(ATTRIBS_BUFFER), GLBufferMutable.GL_BUFFER_TYPE_ARRAY); - attributesGLBuffer.bind(gl); - attributesGLBuffer.init(gl, VERTEX_COUNT_MAX * ATTRIBS_STRIDE * Float.BYTES * BATCH_EDGES_SIZE, GLBufferMutable.GL_BUFFER_USAGE_DYNAMIC_DRAW); - attributesGLBuffer.unbind(gl); + attributesGLBufferDirected = new GLBufferMutable(bufferName[ATTRIBS_BUFFER_DIRECTED], GLBufferMutable.GL_BUFFER_TYPE_ARRAY); + attributesGLBufferDirected.bind(gl); + attributesGLBufferDirected.init(gl, VERTEX_COUNT_MAX * ATTRIBS_STRIDE * Float.BYTES * BATCH_EDGES_SIZE, GLBufferMutable.GL_BUFFER_USAGE_DYNAMIC_DRAW); + attributesGLBufferDirected.unbind(gl); + + attributesGLBufferUndirected = new GLBufferMutable(bufferName[ATTRIBS_BUFFER_UNDIRECTED], GLBufferMutable.GL_BUFFER_TYPE_ARRAY); + attributesGLBufferUndirected.bind(gl); + attributesGLBufferUndirected.init(gl, VERTEX_COUNT_MAX * ATTRIBS_STRIDE * Float.BYTES * BATCH_EDGES_SIZE, GLBufferMutable.GL_BUFFER_USAGE_DYNAMIC_DRAW); + attributesGLBufferUndirected.unbind(gl); attributesBuffer = new float[ATTRIBS_STRIDE * BATCH_EDGES_SIZE]; } @@ -260,10 +231,9 @@ private void updateData(final GraphIndexImpl graphIndex, final GraphRenderingOpt final int totalEdges = graphIndex.getEdgeCount(); - final float[] attribs - = attributesBuffer - = ArrayUtils.ensureCapacityNoCopy(attributesBuffer, totalEdges * ATTRIBS_STRIDE); + = attributesBuffer + = ArrayUtils.ensureCapacityNoCopy(attributesBuffer, totalEdges * ATTRIBS_STRIDE); graphIndex.getVisibleEdges(edgesCallback); @@ -274,15 +244,15 @@ private void updateData(final GraphIndexImpl graphIndex, final GraphRenderingOpt int attribsIndex = 0; attribsIndex = updateUndirectedData( - graph, - someEdgesSelection, hideNonSelected, visibleEdgesCount, visibleEdgesArray, - graphSelection, someNodesSelection, edgeSelectionColor, edgeBothSelectionColor, edgeOutSelectionColor, edgeInSelectionColor, - attribs, attribsIndex + graph, + someEdgesSelection, hideNonSelected, visibleEdgesCount, visibleEdgesArray, + graphSelection, someNodesSelection, edgeSelectionColor, edgeBothSelectionColor, edgeOutSelectionColor, edgeInSelectionColor, + attribs, attribsIndex ); updateDirectedData( - graph, someEdgesSelection, hideNonSelected, visibleEdgesCount, visibleEdgesArray, - graphSelection, someNodesSelection, edgeSelectionColor, edgeBothSelectionColor, edgeOutSelectionColor, edgeInSelectionColor, - attribs, attribsIndex + graph, someEdgesSelection, hideNonSelected, visibleEdgesCount, visibleEdgesArray, + graphSelection, someNodesSelection, edgeSelectionColor, edgeBothSelectionColor, edgeOutSelectionColor, edgeInSelectionColor, + attribs, attribsIndex ); } diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/ArrayDrawNodeData.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/ArrayDrawNodeData.java index fed1710..e86fc21 100644 --- a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/ArrayDrawNodeData.java +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/ArrayDrawNodeData.java @@ -26,292 +26,111 @@ */ public class ArrayDrawNodeData extends AbstractNodeData { - private final NodeDiskModel diskModel64 = new NodeDiskModel(64); - private final NodeDiskModel diskModel32 = new NodeDiskModel(32); - private final NodeDiskModel diskModel16 = new NodeDiskModel(16); - private final NodeDiskModel diskModel8 = new NodeDiskModel(8); - - private final int circleVertexCount64; - private final int circleVertexCount32; - private final int circleVertexCount16; - private final int circleVertexCount8; - private final int firstVertex64; - private final int firstVertex32; - private final int firstVertex16; - private final int firstVertex8; - - private final InstanceCounter instanceCounter = new InstanceCounter(); - - private IntBuffer bufferName; + private final int[] bufferName = new int[1]; private static final int VERT_BUFFER = 0; public ArrayDrawNodeData() { - super(false); - circleVertexCount64 = diskModel64.getVertexCount(); - circleVertexCount32 = diskModel32.getVertexCount(); - circleVertexCount16 = diskModel16.getVertexCount(); - circleVertexCount8 = diskModel8.getVertexCount(); - - firstVertex64 = 0; - firstVertex32 = circleVertexCount64; - firstVertex16 = firstVertex32 + circleVertexCount32; - firstVertex8 = firstVertex16 + circleVertexCount16; - } - - public void init(GL2ES2 gl) { - initBuffers(gl); - diskModel64.initGLPrograms(gl); + super(false, false); } public void update(VizEngine engine, GraphIndexImpl spatialIndex) { - updateData(spatialIndex, - engine.getLookup().lookup(GraphRenderingOptions.class), - engine.getLookup().lookup(GraphSelection.class), - engine.getZoom() + updateData( + engine.getZoom(), + spatialIndex, + engine.getLookup().lookup(GraphRenderingOptions.class), + engine.getLookup().lookup(GraphSelection.class) ); } public void drawArrays(GL2ES2 gl, RenderingLayer layer, VizEngine engine, float[] mvpFloats) { - final float[] backgroundColorFloats = engine.getBackgroundColor(); - final float zoom = engine.getZoom(); - - final int instanceCount; - final int instancesOffset; - final float colorLightenFactor; - - if (layer == RenderingLayer.BACK) { - instanceCount = instanceCounter.unselectedCountToDraw * 2; - instancesOffset = 0; - colorLightenFactor = engine.getLookup().lookup(GraphRenderingOptions.class).getLightenNonSelectedFactor(); - } else { - instanceCount = instanceCounter.selectedCountToDraw * 2; - instancesOffset = instanceCounter.unselectedCountToDraw * 2; - colorLightenFactor = 0; - } - - if (instanceCount > 0) { - setupVertexArrayAttributes(engine, gl); - diskModel64.useProgram(gl, mvpFloats, backgroundColorFloats, colorLightenFactor); - - final float[] attrs = new float[ATTRIBS_STRIDE]; - int index = instancesOffset * ATTRIBS_STRIDE; - - //We have to perform one draw call per intance because repeating the attributes without instancing per each vertex would use too much memory: - //TODO: Maybe we can batch a few nodes at once though - final FloatBuffer attribs = attributesBuffer.floatBuffer(); - - attribs.position(index); - for (int i = 0; i < instanceCount; i++) { - attribs.get(attrs); - - //Choose LOD: - final float size = attrs[5]; - final float observedSize = size * zoom; - - final int circleVertexCount; - final int firstVertex; - if (observedSize > OBSERVED_SIZE_LOD_THRESHOLD_64) { - circleVertexCount = circleVertexCount64; - firstVertex = firstVertex64; - } else if (observedSize > OBSERVED_SIZE_LOD_THRESHOLD_32) { - circleVertexCount = circleVertexCount32; - firstVertex = firstVertex32; - } else if (observedSize > OBSERVED_SIZE_LOD_THRESHOLD_16) { - circleVertexCount = circleVertexCount16; - firstVertex = firstVertex16; - } else { - circleVertexCount = circleVertexCount8; - firstVertex = firstVertex8; - } - - //Define instance attributes: - gl.glVertexAttrib2fv(SHADER_POSITION_LOCATION, attrs, 0); - - //No vertexAttribArray, we have to unpack rgba manually: - final int argb = Float.floatToRawIntBits(attrs[2]); - - final int a = ((argb >> 24) & 0xFF); - final int r = ((argb >> 16) & 0xFF); - final int g = ((argb >> 8) & 0xFF); - final int b = (argb & 0xFF); - - gl.glVertexAttrib4f(SHADER_COLOR_LOCATION, b, g, r, a); - - gl.glVertexAttrib1fv(SHADER_COLOR_BIAS_LOCATION, attrs, 3); - gl.glVertexAttrib1fv(SHADER_COLOR_MULTIPLIER_LOCATION, attrs, 4); - gl.glVertexAttrib1f(SHADER_SIZE_LOCATION, size); - - //Draw the instance: - diskModel64.drawArraysSingleInstance(gl, firstVertex, circleVertexCount); - } - - diskModel64.stopUsingProgram(gl); - unsetupVertexArrayAttributes(gl); - } + //First we draw outside circle (for border) and then inside circle: + drawArraysInternal(gl, layer, engine, mvpFloats, true); + drawArraysInternal(gl, layer, engine, mvpFloats, false); } - public void updateBuffers() { - instanceCounter.promoteCountToDraw(); - } - - private ManagedDirectBuffer attributesBuffer; - - private float[] attributesBufferBatch; - private static final int BATCH_NODES_SIZE = 32768; - - private void initBuffers(GL2ES2 gl) { - attributesBufferBatch = new float[ATTRIBS_STRIDE * BATCH_NODES_SIZE * 2]; - - bufferName = GLBuffers.newDirectIntBuffer(3); - - final float[] circleVertexData = new float[diskModel64.getVertexData().length + diskModel32.getVertexData().length + diskModel16.getVertexData().length + diskModel8.getVertexData().length]; - int offset = 0; - System.arraycopy(diskModel64.getVertexData(), 0, circleVertexData, offset, diskModel64.getVertexData().length); - offset += diskModel64.getVertexData().length; - System.arraycopy(diskModel32.getVertexData(), 0, circleVertexData, offset, diskModel32.getVertexData().length); - offset += diskModel32.getVertexData().length; - System.arraycopy(diskModel16.getVertexData(), 0, circleVertexData, offset, diskModel16.getVertexData().length); - offset += diskModel16.getVertexData().length; - System.arraycopy(diskModel8.getVertexData(), 0, circleVertexData, offset, diskModel8.getVertexData().length); - final FloatBuffer circleVertexBuffer = GLBuffers.newDirectFloatBuffer(circleVertexData); + public void drawArraysInternal(final GL2ES2 gl, + final RenderingLayer layer, + final VizEngine engine, + final float[] mvpFloats, + final boolean isRenderingOutsideCircle) { + final int instanceCount = setupShaderProgramForRenderingLayer(gl, layer, engine, mvpFloats, isRenderingOutsideCircle); - gl.glGenBuffers(bufferName.capacity(), bufferName); - - vertexGLBuffer = new GLBufferMutable(bufferName.get(VERT_BUFFER), GLBufferMutable.GL_BUFFER_TYPE_ARRAY); - vertexGLBuffer.bind(gl); - vertexGLBuffer.init(gl, circleVertexBuffer, GLBufferMutable.GL_BUFFER_USAGE_STATIC_DRAW); - vertexGLBuffer.unbind(gl); - - BufferUtils.destroyDirectBuffer(circleVertexBuffer); - - attributesBuffer = new ManagedDirectBuffer(GL_FLOAT, ATTRIBS_STRIDE * BATCH_NODES_SIZE * 2); - } - - private void updateData(final GraphIndexImpl spatialIndex, final GraphRenderingOptions renderingOptions, final GraphSelection selection, final float zoom) { - if (!renderingOptions.isShowNodes()) { - instanceCounter.clearCount(); + if (instanceCount <= 0) { + diskModel.stopUsingProgram(gl); + unsetupVertexArrayAttributes(gl); return; } - spatialIndex.indexNodes(); - - //Selection: - final boolean someSelection = selection.getSelectedNodesCount() > 0; - final float lightenNonSelectedFactor = renderingOptions.getLightenNonSelectedFactor(); - final boolean hideNonSelected = someSelection && (renderingOptions.isHideNonSelected() || lightenNonSelectedFactor >= 1); + final boolean renderingUnselectedNodes = layer.isBack(); + final int instancesOffset = renderingUnselectedNodes ? 0 : instanceCounter.unselectedCountToDraw; - final int totalNodes = spatialIndex.getNodeCount(); - attributesBuffer.ensureCapacity(totalNodes * ATTRIBS_STRIDE * 2); + final float zoom = engine.getZoom(); + final float[] attrs = new float[ATTRIBS_STRIDE]; + int index = instancesOffset * ATTRIBS_STRIDE; + //We have to perform one draw call per instance because repeating the attributes without instancing per each vertex would use too much memory: + //TODO: Maybe we can batch a few nodes at once though final FloatBuffer attribs = attributesBuffer.floatBuffer(); - spatialIndex.getVisibleNodes(nodesCallback); - - final Node[] visibleNodesArray = nodesCallback.getNodesArray(); - final int visibleNodesCount = nodesCallback.getCount(); - - int newNodesCountUnselected = 0; - int newNodesCountSelected = 0; - - float maxNodeSize = 0; - for (int j = 0; j < visibleNodesCount; j++) { - final float size = visibleNodesArray[j].size(); - maxNodeSize = size >= maxNodeSize ? size : maxNodeSize; - } - - int index = 0; - if (someSelection) { - if (hideNonSelected) { - for (int j = 0; j < visibleNodesCount; j++) { - final Node node = visibleNodesArray[j]; - - final boolean selected = selection.isNodeSelected(node); - if (!selected) { - continue; - } - - newNodesCountSelected++; - - index = fillNodeAttributesData(attributesBufferBatch, node, index, someSelection, true); - - if (index == attributesBufferBatch.length) { - attribs.put(attributesBufferBatch, 0, attributesBufferBatch.length); - index = 0; - } - } + attribs.position(index); + for (int i = 0; i < instanceCount; i++) { + attribs.get(attrs); + + //Choose LOD: + final float size = attrs[3]; + final float observedSize = size * zoom; + + final int circleVertexCount; + final int firstVertex; + if (observedSize > OBSERVED_SIZE_LOD_THRESHOLD_64) { + circleVertexCount = circleVertexCount64; + firstVertex = firstVertex64; + } else if (observedSize > OBSERVED_SIZE_LOD_THRESHOLD_32) { + circleVertexCount = circleVertexCount32; + firstVertex = firstVertex32; + } else if (observedSize > OBSERVED_SIZE_LOD_THRESHOLD_16) { + circleVertexCount = circleVertexCount16; + firstVertex = firstVertex16; } else { - //First non-selected (bottom): - for (int j = 0; j < visibleNodesCount; j++) { - final Node node = visibleNodesArray[j]; - - final boolean selected = selection.isNodeSelected(node); - if (selected) { - continue; - } - - newNodesCountUnselected++; - - index = fillNodeAttributesData(attributesBufferBatch, node, index, someSelection, false); - - if (index == attributesBufferBatch.length) { - attribs.put(attributesBufferBatch, 0, attributesBufferBatch.length); - index = 0; - } - } - - //Then selected ones (up): - for (int j = 0; j < visibleNodesCount; j++) { - final Node node = visibleNodesArray[j]; - - final boolean selected = selection.isNodeSelected(node); - if (!selected) { - continue; - } + circleVertexCount = circleVertexCount8; + firstVertex = firstVertex8; + } - newNodesCountSelected++; + //Define instance attributes: + gl.glVertexAttrib2fv(SHADER_POSITION_LOCATION, attrs, 0); - index = fillNodeAttributesData(attributesBufferBatch, node, index, someSelection, true); + //No vertexAttribArray, we have to unpack rgba manually: + final int argb = Float.floatToRawIntBits(attrs[2]); - if (index == attributesBufferBatch.length) { - attribs.put(attributesBufferBatch, 0, attributesBufferBatch.length); - index = 0; - } - } - } - } else { - //Just all nodes, no selection active: - for (int j = 0; j < visibleNodesCount; j++) { - final Node node = visibleNodesArray[j]; + final int a = ((argb >> 24) & 0xFF); + final int r = ((argb >> 16) & 0xFF); + final int g = ((argb >> 8) & 0xFF); + final int b = (argb & 0xFF); - newNodesCountSelected++; + gl.glVertexAttrib4f(SHADER_COLOR_LOCATION, b, g, r, a); - index = fillNodeAttributesData(attributesBufferBatch, node, index, someSelection, true); + gl.glVertexAttrib1f(SHADER_SIZE_LOCATION, size); - if (index == attributesBufferBatch.length) { - attribs.put(attributesBufferBatch, 0, attributesBufferBatch.length); - index = 0; - } - } + //Draw the instance: + diskModel.drawArraysSingleInstance(gl, firstVertex, circleVertexCount); } - //Remaining: - if (index > 0) { - attribs.put(attributesBufferBatch, 0, index); - } + diskModel.stopUsingProgram(gl); + unsetupVertexArrayAttributes(gl); + } - instanceCounter.unselectedCount = newNodesCountUnselected; - instanceCounter.selectedCount = newNodesCountSelected; + public void updateBuffers() { + instanceCounter.promoteCountToDraw(); + maxNodeSizeToDraw = maxNodeSize; } - @Override - public void dispose(GL gl) { - super.dispose(gl); - attributesBufferBatch = null; - if (attributesBuffer != null) { - attributesBuffer.destroy(); - attributesBuffer = null; - } + protected void initBuffers(final GL2ES2 gl) { + super.initBuffers(); + + gl.glGenBuffers(bufferName.length, bufferName, 0); + + initCirclesGLVertexBuffer(gl, bufferName[VERT_BUFFER]); } } diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/renderers/EdgeRendererArrayDraw.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/renderers/EdgeRendererArrayDraw.java index ebe34bb..86faaf3 100644 --- a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/renderers/EdgeRendererArrayDraw.java +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/renderers/EdgeRendererArrayDraw.java @@ -5,6 +5,7 @@ import org.gephi.viz.engine.VizEngine; import org.gephi.viz.engine.jogl.availability.ArrayDraw; import org.gephi.viz.engine.jogl.JOGLRenderingTarget; +import org.gephi.viz.engine.jogl.pipeline.common.AbstractEdgeRenderer; import org.gephi.viz.engine.pipeline.PipelineCategory; import org.gephi.viz.engine.pipeline.RenderingLayer; import org.gephi.viz.engine.jogl.pipeline.arrays.ArrayDrawEdgeData; @@ -15,7 +16,7 @@ * * @author Eduardo Ramos */ -public class EdgeRendererArrayDraw implements Renderer { +public class EdgeRendererArrayDraw extends AbstractEdgeRenderer { private final VizEngine engine; private final ArrayDrawEdgeData edgeData; @@ -39,28 +40,9 @@ public void worldUpdated(JOGLRenderingTarget target) { @Override public void render(JOGLRenderingTarget target, RenderingLayer layer) { - final GL2ES2 gl = target.getDrawable().getGL().getGL2ES2(); - engine.getModelViewProjectionMatrixFloats(mvpFloats); - edgeData.drawArrays(gl, layer, engine, mvpFloats); - } - - private static final EnumSet LAYERS = EnumSet.of(RenderingLayer.BACK, RenderingLayer.MIDDLE); - - @Override - public EnumSet getLayers() { - return LAYERS; - } - - @Override - public int getOrder() { - return Constants.RENDERING_ORDER_EDGES; - } - - @Override - public String getCategory() { - return PipelineCategory.EDGE; + edgeData.drawArrays(target.getDrawable().getGL().getGL2ES2(), layer, engine, mvpFloats); } @Override diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/renderers/NodeRendererArrayDraw.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/renderers/NodeRendererArrayDraw.java index d770bdc..a8a6b42 100644 --- a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/renderers/NodeRendererArrayDraw.java +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/renderers/NodeRendererArrayDraw.java @@ -5,6 +5,7 @@ import org.gephi.viz.engine.VizEngine; import org.gephi.viz.engine.jogl.availability.ArrayDraw; import org.gephi.viz.engine.jogl.JOGLRenderingTarget; +import org.gephi.viz.engine.jogl.pipeline.common.AbstractNodeRenderer; import org.gephi.viz.engine.pipeline.PipelineCategory; import org.gephi.viz.engine.pipeline.RenderingLayer; import org.gephi.viz.engine.jogl.pipeline.arrays.ArrayDrawNodeData; @@ -15,7 +16,7 @@ * * @author Eduardo Ramos */ -public class NodeRendererArrayDraw implements Renderer { +public class NodeRendererArrayDraw extends AbstractNodeRenderer { private final VizEngine engine; private final ArrayDrawNodeData nodeData; @@ -39,28 +40,9 @@ public void worldUpdated(JOGLRenderingTarget target) { @Override public void render(JOGLRenderingTarget target, RenderingLayer layer) { - final GL2ES2 gl = target.getDrawable().getGL().getGL2ES2(); - engine.getModelViewProjectionMatrixFloats(mvpFloats); - nodeData.drawArrays(gl, layer, engine, mvpFloats); - } - - private static final EnumSet LAYERS = EnumSet.of(RenderingLayer.BACK, RenderingLayer.MIDDLE); - - @Override - public EnumSet getLayers() { - return LAYERS; - } - - @Override - public int getOrder() { - return Constants.RENDERING_ORDER_NODES; - } - - @Override - public String getCategory() { - return PipelineCategory.NODE; + nodeData.drawArrays(target.getDrawable().getGL().getGL2ES2(), layer, engine, mvpFloats); } @Override diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/renderers/RectangleSelectionArrayDraw.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/renderers/RectangleSelectionArrayDraw.java new file mode 100644 index 0000000..95e0a87 --- /dev/null +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/arrays/renderers/RectangleSelectionArrayDraw.java @@ -0,0 +1,231 @@ +package org.gephi.viz.engine.jogl.pipeline.arrays.renderers; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.EnumSet; + +import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.util.GLBuffers; +import org.gephi.viz.engine.VizEngine; +import org.gephi.viz.engine.jogl.JOGLRenderingTarget; +import org.gephi.viz.engine.jogl.util.ManagedDirectBuffer; +import org.gephi.viz.engine.jogl.util.gl.GLBufferMutable; +import org.gephi.viz.engine.jogl.util.gl.GLShaderProgram; +import org.gephi.viz.engine.jogl.util.gl.GLVertexArrayObject; +import org.gephi.viz.engine.jogl.util.gl.capabilities.GLCapabilitiesSummary; +import org.gephi.viz.engine.pipeline.PipelineCategory; +import org.gephi.viz.engine.pipeline.RenderingLayer; +import org.gephi.viz.engine.spi.Renderer; +import org.gephi.viz.engine.status.GraphSelection; +import org.gephi.viz.engine.util.gl.Constants; +import org.gephi.viz.engine.util.gl.OpenGLOptions; +import org.joml.Vector2f; + +import static com.jogamp.opengl.GL.GL_BLEND; +import static com.jogamp.opengl.GL.GL_BLEND_DST_ALPHA; +import static com.jogamp.opengl.GL.GL_FLOAT; +import static com.jogamp.opengl.GL.GL_ONE_MINUS_SRC_ALPHA; +import static com.jogamp.opengl.GL.GL_SRC_ALPHA; +import static com.jogamp.opengl.GL.GL_TRIANGLES; +import static org.gephi.viz.engine.util.gl.Constants.ATTRIB_NAME_VERT; +import static org.gephi.viz.engine.util.gl.Constants.SHADER_VERT_LOCATION; +import static org.gephi.viz.engine.util.gl.Constants.UNIFORM_NAME_MODEL_VIEW_PROJECTION; +public class RectangleSelectionArrayDraw implements Renderer { + private final VizEngine engine; + + final float[] mvpFloats = new float[16]; + + private static final int VERT_BUFFER = 0; + + public static final int VERTEX_COUNT = 6; // 2 triangles + public static final int VERTEX_FLOATS = 2; + + private final int[] bufferName = new int[1]; + private ManagedDirectBuffer rectangleVertexDataBuffer; + private GLBufferMutable vertexGLBuffer; + private SelectionRectangleVAO vao; + + public RectangleSelectionArrayDraw(VizEngine engine) { + this.engine = engine; + } + + @Override + public String getCategory() { + return PipelineCategory.RECTANGLE_SELECTION; + } + + @Override + public int getPreferenceInCategory() { + return 0; + } + + @Override + public String getName() { + return "Rectangle Selection"; + } + + @Override + public void init(JOGLRenderingTarget target) { + final GL2ES2 gl = target.getDrawable().getGL().getGL2ES2(); + + shaderProgram = new GLShaderProgram(SHADERS_ROOT, "rectangleSelection", "rectangleSelection") + .addUniformName(UNIFORM_NAME_MODEL_VIEW_PROJECTION) + .addAttribLocation(ATTRIB_NAME_VERT, SHADER_VERT_LOCATION) + .init(gl); + + gl.glGenBuffers(bufferName.length, bufferName, 0); + + rectangleVertexDataBuffer = new ManagedDirectBuffer(GL_FLOAT, Float.BYTES * VERTEX_COUNT * VERTEX_FLOATS); + + vertexGLBuffer = new GLBufferMutable(bufferName[VERT_BUFFER], GLBufferMutable.GL_BUFFER_TYPE_ARRAY); + vertexGLBuffer.bind(gl); + vertexGLBuffer.init(gl, Float.BYTES * VERTEX_COUNT * VERTEX_FLOATS, GLBufferMutable.GL_BUFFER_USAGE_DYNAMIC_DRAW); + vertexGLBuffer.unbind(gl); + + vao = new SelectionRectangleVAO( + engine.getLookup().lookup(GLCapabilitiesSummary.class), + engine.getLookup().lookup(OpenGLOptions.class) + ); + } + + @Override + public int getOrder() { + return 0; + } + + private boolean render = false; + + @Override + public void worldUpdated(JOGLRenderingTarget target) { + final GL2ES2 gl = target.getDrawable().getGL().getGL2ES2(); + + final GraphSelection graphSelection = engine.getLookup().lookup(GraphSelection.class); + + if (graphSelection.getMode() != GraphSelection.GraphSelectionMode.RECTANGLE_SELECTION) { + return; + } + + final Vector2f initialPosition = graphSelection.getRectangleInitialPosition(); + final Vector2f currentPosition = graphSelection.getRectangleCurrentPosition(); + + if (initialPosition != null && currentPosition != null) { + + final float minX = Math.min(initialPosition.x, currentPosition.x); + final float minY = Math.min(initialPosition.y, currentPosition.y); + final float maxX = Math.max(initialPosition.x, currentPosition.x); + final float maxY = Math.max(initialPosition.y, currentPosition.y); + + final FloatBuffer floatBuffer = rectangleVertexDataBuffer.floatBuffer(); + + final float[] rectangleVertexData = { + //Triangle 1: + minX, + minY, + minX, + maxY, + maxX, + minY, + //Triangle 2: + minX, + maxY, + maxX, + maxY, + maxX, + minY + }; + + floatBuffer.put(rectangleVertexData); + floatBuffer.position(0); + + vertexGLBuffer.bind(gl); + vertexGLBuffer.update(gl, floatBuffer); + vertexGLBuffer.unbind(gl); + + render = true; + } else { + render = false; + } + } + + private static final String SHADERS_ROOT = Constants.SHADERS_ROOT + "rectangleSelection"; + private GLShaderProgram shaderProgram; + + private final int[] intData = new int[1]; + private final byte[] booleanData = new byte[1]; + + @Override + public void render(JOGLRenderingTarget target, RenderingLayer layer) { + final GL2ES2 gl = target.getDrawable().getGL().getGL2ES2(); + + if (render) { + shaderProgram.use(gl); + engine.getModelViewProjectionMatrixFloats(mvpFloats); + + gl.glUniformMatrix4fv(shaderProgram.getUniformLocation(UNIFORM_NAME_MODEL_VIEW_PROJECTION), 1, false, mvpFloats, 0); + + vao.use(gl); + + + gl.glGetBooleanv(GL_BLEND, booleanData, 0); + gl.glGetIntegerv(GL_BLEND_DST_ALPHA, intData, 0); + + final boolean blendEnabled = booleanData[0] > 0; + final int blendFunc = intData[1]; + + if (!blendEnabled) { + gl.glEnable(GL_BLEND); + } + + if (blendFunc != GL_ONE_MINUS_SRC_ALPHA) { + gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + gl.glDrawArrays(GL_TRIANGLES, 0, VERTEX_COUNT); + + //Restore state: + if (!blendEnabled) { + gl.glDisable(GL_BLEND); + } + if (blendFunc != GL_ONE_MINUS_SRC_ALPHA) { + gl.glBlendFunc(GL_SRC_ALPHA, blendFunc); + } + + vao.stopUsing(gl); + + shaderProgram.stopUsing(gl); + } + } + + @Override + public EnumSet getLayers() { + return EnumSet.of(RenderingLayer.FRONT4); + } + + private class SelectionRectangleVAO extends GLVertexArrayObject { + + public SelectionRectangleVAO(GLCapabilitiesSummary capabilities, OpenGLOptions openGLOptions) { + super(capabilities, openGLOptions); + } + + @Override + protected void configure(GL2ES2 gl) { + vertexGLBuffer.bind(gl); + { + gl.glVertexAttribPointer(SHADER_VERT_LOCATION, VERTEX_FLOATS, GL_FLOAT, false, 0, 0); + } + vertexGLBuffer.unbind(gl); + } + + @Override + protected int[] getUsedAttributeLocations() { + return new int[]{ + SHADER_VERT_LOCATION + }; + } + + @Override + protected int[] getInstancedAttributeLocations() { + return null; + } + } +} diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractEdgeData.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractEdgeData.java index 134b3d7..45fe88f 100644 --- a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractEdgeData.java +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractEdgeData.java @@ -11,12 +11,16 @@ import org.gephi.viz.engine.VizEngine; import org.gephi.viz.engine.jogl.models.EdgeLineModelDirected; import org.gephi.viz.engine.jogl.models.EdgeLineModelUndirected; +import org.gephi.viz.engine.jogl.util.ManagedDirectBuffer; +import org.gephi.viz.engine.pipeline.RenderingLayer; import org.gephi.viz.engine.pipeline.common.InstanceCounter; +import org.gephi.viz.engine.status.GraphRenderingOptions; import org.gephi.viz.engine.status.GraphSelection; import static org.gephi.viz.engine.util.gl.Constants.*; import org.gephi.viz.engine.jogl.util.gl.GLBuffer; import org.gephi.viz.engine.jogl.util.gl.GLVertexArrayObject; import org.gephi.viz.engine.jogl.util.gl.capabilities.GLCapabilitiesSummary; +import org.gephi.viz.engine.structure.GraphIndex; import org.gephi.viz.engine.util.gl.OpenGLOptions; import org.gephi.viz.engine.util.structure.EdgesCallback; @@ -32,45 +36,242 @@ public class AbstractEdgeData { protected final InstanceCounter undirectedInstanceCounter = new InstanceCounter(); protected final InstanceCounter directedInstanceCounter = new InstanceCounter(); + // NOTE: Why secondary buffers and VAOs? + // Sadly, we cannot use glDrawArraysInstancedBaseInstance in MacOS and it will be never available + protected GLBuffer vertexGLBufferUndirected; protected GLBuffer vertexGLBufferDirected; - protected GLBuffer attributesGLBuffer; + protected GLBuffer attributesGLBufferDirected; + protected GLBuffer attributesGLBufferDirectedSecondary; + protected GLBuffer attributesGLBufferUndirected; + protected GLBuffer attributesGLBufferUndirectedSecondary; protected final EdgesCallback edgesCallback = new EdgesCallback(); - protected static final int ATTRIBS_STRIDE - = Math.max( - EdgeLineModelUndirected.TOTAL_ATTRIBUTES_FLOATS, - EdgeLineModelDirected.TOTAL_ATTRIBUTES_FLOATS - ); + protected static final int ATTRIBS_STRIDE = Math.max( + EdgeLineModelUndirected.TOTAL_ATTRIBUTES_FLOATS, + EdgeLineModelDirected.TOTAL_ATTRIBUTES_FLOATS + ); protected static final int VERTEX_COUNT_UNDIRECTED = EdgeLineModelUndirected.VERTEX_COUNT; protected static final int VERTEX_COUNT_DIRECTED = EdgeLineModelDirected.VERTEX_COUNT; protected static final int VERTEX_COUNT_MAX = Math.max(VERTEX_COUNT_DIRECTED, VERTEX_COUNT_UNDIRECTED); protected final boolean instanced; + protected final boolean usesSecondaryBuffer; + + protected ManagedDirectBuffer attributesBuffer; - public AbstractEdgeData(boolean instanced) { + protected float[] attributesBufferBatch; + protected static final int BATCH_EDGES_SIZE = 32768; + + public AbstractEdgeData(boolean instanced, boolean usesSecondaryBuffer) { this.instanced = instanced; + this.usesSecondaryBuffer = usesSecondaryBuffer; } public void init(GL2ES2 gl) { lineModelDirected.initGLPrograms(gl); lineModelUndirected.initGLPrograms(gl); + initBuffers(); + } + + protected void initBuffers() { + attributesBufferBatch = new float[ATTRIBS_STRIDE * BATCH_EDGES_SIZE]; + attributesBuffer = new ManagedDirectBuffer(GL_FLOAT, ATTRIBS_STRIDE * BATCH_EDGES_SIZE); + } + + protected int setupShaderProgramForRenderingLayerUndirected(final GL2ES2 gl, + final RenderingLayer layer, + final VizEngine engine, + final float[] mvpFloats) { + final boolean someSelection = engine.getLookup().lookup(GraphSelection.class).getSelectedEdgesCount() > 0; + final boolean renderingUnselectedEdges = layer.isBack(); + if (!someSelection && renderingUnselectedEdges) { + return 0; + } + + final float[] backgroundColorFloats = engine.getBackgroundColor(); + + final GraphRenderingOptions renderingOptions = engine.getLookup().lookup(GraphRenderingOptions.class); + + final float edgeScale = renderingOptions.getEdgeScale(); + float lightenNonSelectedFactor = renderingOptions.getLightenNonSelectedFactor(); + + final GraphIndex graphIndex = engine.getLookup().lookup(GraphIndex.class); + + final float minWeight = graphIndex.getEdgesMinWeight(); + final float maxWeight = graphIndex.getEdgesMaxWeight(); + + final int instanceCount; + if (renderingUnselectedEdges) { + instanceCount = undirectedInstanceCounter.unselectedCountToDraw; + + lineModelUndirected.useProgramWithSelectionUnselected( + gl, + mvpFloats, + edgeScale, + minWeight, + maxWeight, + backgroundColorFloats, + lightenNonSelectedFactor + ); + + if (usesSecondaryBuffer) { + setupUndirectedVertexArrayAttributesSecondary(gl, engine); + } else { + setupUndirectedVertexArrayAttributes(gl, engine); + } + } else { + instanceCount = undirectedInstanceCounter.selectedCountToDraw; + lineModelUndirected.useProgram( + gl, + mvpFloats, + edgeScale, + minWeight, + maxWeight + ); + + if (someSelection) { + if (someNodesSelection && edgeSelectionColor) { + lineModelUndirected.useProgram( + gl, + mvpFloats, + edgeScale, + minWeight, + maxWeight + ); + } else { + final float colorBias = 0.5f; + final float colorMultiplier = 0.5f; + + lineModelUndirected.useProgramWithSelectionSelected( + gl, + mvpFloats, + edgeScale, + minWeight, + maxWeight, + colorBias, + colorMultiplier + ); + } + } else { + lineModelUndirected.useProgram( + gl, + mvpFloats, + edgeScale, + minWeight, + maxWeight + ); + } + + setupUndirectedVertexArrayAttributes(gl, engine); + } + + return instanceCount; + } + + protected int setupShaderProgramForRenderingLayerDirected(final GL2ES2 gl, + final RenderingLayer layer, + final VizEngine engine, + final float[] mvpFloats) { + final boolean someSelection = engine.getLookup().lookup(GraphSelection.class).getSelectedEdgesCount() > 0; + final boolean renderingUnselectedEdges = layer.isBack(); + if (!someSelection && renderingUnselectedEdges) { + return 0; + } + + final float[] backgroundColorFloats = engine.getBackgroundColor(); + + final GraphRenderingOptions renderingOptions = engine.getLookup().lookup(GraphRenderingOptions.class); + + final float edgeScale = renderingOptions.getEdgeScale(); + float lightenNonSelectedFactor = renderingOptions.getLightenNonSelectedFactor(); + + final GraphIndex graphIndex = engine.getLookup().lookup(GraphIndex.class); + + final float minWeight = graphIndex.getEdgesMinWeight(); + final float maxWeight = graphIndex.getEdgesMaxWeight(); + + final int instanceCount; + if (renderingUnselectedEdges) { + instanceCount = directedInstanceCounter.unselectedCountToDraw; + lineModelDirected.useProgramWithSelectionUnselected( + gl, + mvpFloats, + edgeScale, + minWeight, + maxWeight, + backgroundColorFloats, + lightenNonSelectedFactor + ); + + if (usesSecondaryBuffer) { + setupDirectedVertexArrayAttributesSecondary(gl, engine); + } else { + setupDirectedVertexArrayAttributes(gl, engine); + } + } else { + instanceCount = directedInstanceCounter.selectedCountToDraw; + lineModelDirected.useProgram( + gl, + mvpFloats, + edgeScale, + minWeight, + maxWeight + ); + + if (someSelection) { + if (someNodesSelection && edgeSelectionColor) { + lineModelDirected.useProgram( + gl, + mvpFloats, + edgeScale, + minWeight, + maxWeight + ); + } else { + final float colorBias = 0.5f; + final float colorMultiplier = 0.5f; + + lineModelDirected.useProgramWithSelectionSelected( + gl, + mvpFloats, + edgeScale, + minWeight, + maxWeight, + colorBias, + colorMultiplier + ); + } + } else { + lineModelDirected.useProgram( + gl, + mvpFloats, + edgeScale, + minWeight, + maxWeight + ); + } + + setupDirectedVertexArrayAttributes(gl, engine); + } + + return instanceCount; } protected int updateDirectedData( - final Graph graph, - final boolean someEdgesSelection, final boolean hideNonSelected, final int visibleEdgesCount, final Edge[] visibleEdgesArray, final GraphSelection graphSelection, final boolean someNodesSelection, final boolean edgeSelectionColor, final float edgeBothSelectionColor, final float edgeOutSelectionColor, final float edgeInSelectionColor, - final float[] attribs, int index + final Graph graph, + final boolean someEdgesSelection, final boolean hideNonSelected, final int visibleEdgesCount, final Edge[] visibleEdgesArray, final GraphSelection graphSelection, final boolean someNodesSelection, final boolean edgeSelectionColor, final float edgeBothSelectionColor, final float edgeOutSelectionColor, final float edgeInSelectionColor, + final float[] attribs, int index ) { return updateDirectedData(graph, someEdgesSelection, hideNonSelected, visibleEdgesCount, visibleEdgesArray, graphSelection, someNodesSelection, edgeSelectionColor, edgeBothSelectionColor, edgeOutSelectionColor, edgeInSelectionColor, attribs, index, null); } protected int updateDirectedData( - final Graph graph, - final boolean someEdgesSelection, final boolean hideNonSelected, final int visibleEdgesCount, final Edge[] visibleEdgesArray, final GraphSelection graphSelection, final boolean someNodesSelection, final boolean edgeSelectionColor, final float edgeBothSelectionColor, final float edgeOutSelectionColor, final float edgeInSelectionColor, - final float[] attribs, int index, final FloatBuffer directBuffer + final Graph graph, + final boolean someEdgesSelection, final boolean hideNonSelected, final int visibleEdgesCount, final Edge[] visibleEdgesArray, final GraphSelection graphSelection, final boolean someNodesSelection, final boolean edgeSelectionColor, final float edgeBothSelectionColor, final float edgeOutSelectionColor, final float edgeInSelectionColor, + final float[] attribs, int index, final FloatBuffer directBuffer ) { checkBufferIndexing(directBuffer, attribs, index); @@ -99,7 +300,8 @@ protected int updateDirectedData( newEdgesCountSelected++; - index = fillDirectedEdgeAttributesDataWithSelection(attribs, edge, index, selected); + fillDirectedEdgeAttributesDataWithSelection(attribs, edge, index, selected); + index += ATTRIBS_STRIDE; if (directBuffer != null && index == attribs.length) { directBuffer.put(attribs, 0, attribs.length); @@ -120,7 +322,8 @@ protected int updateDirectedData( newEdgesCountUnselected++; - index = fillDirectedEdgeAttributesDataWithSelection(attribs, edge, index, false); + fillDirectedEdgeAttributesDataWithSelection(attribs, edge, index, false); + index += ATTRIBS_STRIDE; if (directBuffer != null && index == attribs.length) { directBuffer.put(attribs, 0, attribs.length); @@ -141,7 +344,8 @@ protected int updateDirectedData( newEdgesCountSelected++; - index = fillDirectedEdgeAttributesDataWithSelection(attribs, edge, index, true); + fillDirectedEdgeAttributesDataWithSelection(attribs, edge, index, true); + index += ATTRIBS_STRIDE; if (directBuffer != null && index == attribs.length) { directBuffer.put(attribs, 0, attribs.length); @@ -159,7 +363,8 @@ protected int updateDirectedData( newEdgesCountSelected++; - index = fillDirectedEdgeAttributesDataWithoutSelection(attribs, edge, index); + fillDirectedEdgeAttributesDataWithoutSelection(attribs, edge, index); + index += ATTRIBS_STRIDE; if (directBuffer != null && index == attribs.length) { directBuffer.put(attribs, 0, attribs.length); @@ -181,17 +386,17 @@ protected int updateDirectedData( } protected int updateUndirectedData( - final Graph graph, - final boolean someEdgesSelection, final boolean hideNonSelected, final int visibleEdgesCount, final Edge[] visibleEdgesArray, final GraphSelection graphSelection, final boolean someNodesSelection, final boolean edgeSelectionColor, final float edgeBothSelectionColor, final float edgeOutSelectionColor, final float edgeInSelectionColor, - final float[] attribs, int index + final Graph graph, + final boolean someEdgesSelection, final boolean hideNonSelected, final int visibleEdgesCount, final Edge[] visibleEdgesArray, final GraphSelection graphSelection, final boolean someNodesSelection, final boolean edgeSelectionColor, final float edgeBothSelectionColor, final float edgeOutSelectionColor, final float edgeInSelectionColor, + final float[] attribs, int index ) { return updateUndirectedData(graph, someEdgesSelection, hideNonSelected, visibleEdgesCount, visibleEdgesArray, graphSelection, someNodesSelection, edgeSelectionColor, edgeBothSelectionColor, edgeOutSelectionColor, edgeInSelectionColor, attribs, index, null); } protected int updateUndirectedData( - final Graph graph, - final boolean someEdgesSelection, final boolean hideNonSelected, final int visibleEdgesCount, final Edge[] visibleEdgesArray, final GraphSelection graphSelection, final boolean someNodesSelection, final boolean edgeSelectionColor, final float edgeBothSelectionColor, final float edgeOutSelectionColor, final float edgeInSelectionColor, - final float[] attribs, int index, final FloatBuffer directBuffer + final Graph graph, + final boolean someEdgesSelection, final boolean hideNonSelected, final int visibleEdgesCount, final Edge[] visibleEdgesArray, final GraphSelection graphSelection, final boolean someNodesSelection, final boolean edgeSelectionColor, final float edgeBothSelectionColor, final float edgeOutSelectionColor, final float edgeInSelectionColor, + final float[] attribs, int index, final FloatBuffer directBuffer ) { checkBufferIndexing(directBuffer, attribs, index); @@ -220,7 +425,8 @@ protected int updateUndirectedData( newEdgesCountSelected++; - index = fillUndirectedEdgeAttributesDataWithSelection(attribs, edge, index, true); + fillUndirectedEdgeAttributesDataWithSelection(attribs, edge, index, true); + index += ATTRIBS_STRIDE; if (directBuffer != null && index == attribs.length) { directBuffer.put(attribs, 0, attribs.length); @@ -241,7 +447,8 @@ protected int updateUndirectedData( newEdgesCountUnselected++; - index = fillUndirectedEdgeAttributesDataWithSelection(attribs, edge, index, false); + fillUndirectedEdgeAttributesDataWithSelection(attribs, edge, index, false); + index += ATTRIBS_STRIDE; if (directBuffer != null && index == attribs.length) { directBuffer.put(attribs, 0, attribs.length); @@ -262,7 +469,8 @@ protected int updateUndirectedData( newEdgesCountSelected++; - index = fillUndirectedEdgeAttributesDataWithSelection(attribs, edge, index, true); + fillUndirectedEdgeAttributesDataWithSelection(attribs, edge, index, true); + index += ATTRIBS_STRIDE; if (directBuffer != null && index == attribs.length) { directBuffer.put(attribs, 0, attribs.length); @@ -280,7 +488,8 @@ protected int updateUndirectedData( newEdgesCountSelected++; - index = fillUndirectedEdgeAttributesDataWithoutSelection(attribs, edge, index); + fillUndirectedEdgeAttributesDataWithoutSelection(attribs, edge, index); + index += ATTRIBS_STRIDE; if (directBuffer != null && index == attribs.length) { directBuffer.put(attribs, 0, attribs.length); @@ -339,7 +548,7 @@ protected void fillUndirectedEdgeAttributesDataBase(final float[] buffer, final final float targetY = target.y(); //Position: - buffer[index + 0] = sourceX; + buffer[index] = sourceX; buffer[index + 1] = sourceY; //Target position: @@ -356,24 +565,19 @@ protected void fillUndirectedEdgeAttributesDataBase(final float[] buffer, final buffer[index + 6] = Float.intBitsToFloat(target.getRGBA()); } - protected int fillUndirectedEdgeAttributesDataWithoutSelection(final float[] buffer, final Edge edge, final int index) { + protected void fillUndirectedEdgeAttributesDataWithoutSelection(final float[] buffer, final Edge edge, final int index) { fillUndirectedEdgeAttributesDataBase(buffer, edge, index); - //Color, color bias and color multiplier: buffer[index + 7] = Float.intBitsToFloat(edge.getRGBA());//Color - buffer[index + 8] = 0;//Bias - buffer[index + 9] = 1;//Multiplier - - return index + ATTRIBS_STRIDE; } - protected int fillUndirectedEdgeAttributesDataWithSelection(final float[] buffer, final Edge edge, final int index, final boolean selected) { + protected void fillUndirectedEdgeAttributesDataWithSelection(final float[] buffer, final Edge edge, final int index, final boolean selected) { final Node source = edge.getSource(); final Node target = edge.getTarget(); fillUndirectedEdgeAttributesDataBase(buffer, edge, index); - //Color, color bias and color multiplier: + //Color: if (selected) { if (someNodesSelection && edgeSelectionColor) { boolean sourceSelected = graphSelection.isNodeSelected(source); @@ -388,9 +592,6 @@ protected int fillUndirectedEdgeAttributesDataWithSelection(final float[] buffer } else { buffer[index + 7] = Float.intBitsToFloat(edge.getRGBA());//Color } - - buffer[index + 8] = 0;//Bias - buffer[index + 9] = 1;//Multiplier } else { if (someNodesSelection && edge.alpha() <= 0) { if (graphSelection.isNodeSelected(source)) { @@ -401,17 +602,10 @@ protected int fillUndirectedEdgeAttributesDataWithSelection(final float[] buffer } else { buffer[index + 7] = Float.intBitsToFloat(edge.getRGBA());//Color } - - buffer[index + 8] = 0.5f;//Bias - buffer[index + 9] = 0.5f;//Multiplier } } else { buffer[index + 7] = Float.intBitsToFloat(edge.getRGBA());//Color - buffer[index + 8] = 0;//Bias - buffer[index + 9] = 1;//Multiplier } - - return index + ATTRIBS_STRIDE; } protected void fillDirectedEdgeAttributesDataBase(final float[] buffer, final Edge edge, final int index) { @@ -424,7 +618,7 @@ protected void fillDirectedEdgeAttributesDataBase(final float[] buffer, final Ed final float targetY = target.y(); //Position: - buffer[index + 0] = sourceX; + buffer[index] = sourceX; buffer[index + 1] = sourceY; //Target position: @@ -438,27 +632,23 @@ protected void fillDirectedEdgeAttributesDataBase(final float[] buffer, final Ed buffer[index + 5] = Float.intBitsToFloat(source.getRGBA()); } - protected int fillDirectedEdgeAttributesDataWithoutSelection(final float[] buffer, final Edge edge, final int index) { + protected void fillDirectedEdgeAttributesDataWithoutSelection(final float[] buffer, final Edge edge, final int index) { fillDirectedEdgeAttributesDataBase(buffer, edge, index); - //Color, color bias and color multiplier: + //Color: buffer[index + 6] = Float.intBitsToFloat(edge.getRGBA());//Color - buffer[index + 7] = 0;//Bias - buffer[index + 8] = 1;//Multiplier //Target size: - buffer[index + 9] = edge.getTarget().size(); - - return index + ATTRIBS_STRIDE; + buffer[index + 7] = edge.getTarget().size(); } - protected int fillDirectedEdgeAttributesDataWithSelection(final float[] buffer, final Edge edge, final int index, final boolean selected) { + protected void fillDirectedEdgeAttributesDataWithSelection(final float[] buffer, final Edge edge, final int index, final boolean selected) { final Node source = edge.getSource(); final Node target = edge.getTarget(); fillDirectedEdgeAttributesDataBase(buffer, edge, index); - //Color, color bias and color multiplier: + //Color: if (selected) { if (someNodesSelection && edgeSelectionColor) { boolean sourceSelected = graphSelection.isNodeSelected(source); @@ -473,9 +663,6 @@ protected int fillDirectedEdgeAttributesDataWithSelection(final float[] buffer, } else { buffer[index + 6] = Float.intBitsToFloat(edge.getRGBA());//Color } - - buffer[index + 7] = 0;//Bias - buffer[index + 8] = 1;//Multiplier } else { if (someNodesSelection && edge.alpha() <= 0) { if (graphSelection.isNodeSelected(source)) { @@ -486,53 +673,86 @@ protected int fillDirectedEdgeAttributesDataWithSelection(final float[] buffer, } else { buffer[index + 6] = Float.intBitsToFloat(edge.getRGBA());//Color } - - buffer[index + 7] = 0.5f;//Bias - buffer[index + 8] = 0.5f;//Multiplier } } else { buffer[index + 6] = Float.intBitsToFloat(edge.getRGBA());//Color - buffer[index + 7] = 0;//Bias - buffer[index + 8] = 1;//Multiplier } //Target size: - buffer[index + 9] = target.size(); - - return index + ATTRIBS_STRIDE; + buffer[index + 7] = target.size(); } private UndirectedEdgesVAO undirectedEdgesVAO; + private UndirectedEdgesVAO undirectedEdgesVAOSecondary; private DirectedEdgesVAO directedEdgesVAO; + private DirectedEdgesVAO directedEdgesVAOSecondary; - public void setupUndirectedVertexArrayAttributes(VizEngine engine, GL2ES2 gl) { + public void setupUndirectedVertexArrayAttributes(GL2ES2 gl, VizEngine engine) { if (undirectedEdgesVAO == null) { undirectedEdgesVAO = new UndirectedEdgesVAO( - engine.getLookup().lookup(GLCapabilitiesSummary.class), - engine.getLookup().lookup(OpenGLOptions.class) + engine.getLookup().lookup(GLCapabilitiesSummary.class), + engine.getLookup().lookup(OpenGLOptions.class), + attributesGLBufferUndirected ); } undirectedEdgesVAO.use(gl); } + public void setupUndirectedVertexArrayAttributesSecondary(GL2ES2 gl, VizEngine engine) { + if (undirectedEdgesVAOSecondary == null) { + undirectedEdgesVAOSecondary = new UndirectedEdgesVAO( + engine.getLookup().lookup(GLCapabilitiesSummary.class), + engine.getLookup().lookup(OpenGLOptions.class), + attributesGLBufferUndirectedSecondary + ); + } + + undirectedEdgesVAOSecondary.use(gl); + } + public void unsetupUndirectedVertexArrayAttributes(GL2ES2 gl) { - undirectedEdgesVAO.stopUsing(gl); + if (undirectedEdgesVAO != null) { + undirectedEdgesVAO.stopUsing(gl); + } + + if (undirectedEdgesVAOSecondary != null) { + undirectedEdgesVAOSecondary.stopUsing(gl); + } } - public void setupDirectedVertexArrayAttributes(VizEngine engine, GL2ES2 gl) { + public void setupDirectedVertexArrayAttributes(GL2ES2 gl, VizEngine engine) { if (directedEdgesVAO == null) { directedEdgesVAO = new DirectedEdgesVAO( - engine.getLookup().lookup(GLCapabilitiesSummary.class), - engine.getLookup().lookup(OpenGLOptions.class) + engine.getLookup().lookup(GLCapabilitiesSummary.class), + engine.getLookup().lookup(OpenGLOptions.class), + attributesGLBufferDirected ); } directedEdgesVAO.use(gl); } + public void setupDirectedVertexArrayAttributesSecondary(GL2ES2 gl, VizEngine engine) { + if (directedEdgesVAOSecondary == null) { + directedEdgesVAOSecondary = new DirectedEdgesVAO( + engine.getLookup().lookup(GLCapabilitiesSummary.class), + engine.getLookup().lookup(OpenGLOptions.class), + attributesGLBufferDirectedSecondary + ); + } + + directedEdgesVAOSecondary.use(gl); + } + public void unsetupDirectedVertexArrayAttributes(GL2ES2 gl) { - directedEdgesVAO.stopUsing(gl); + if (directedEdgesVAO != null) { + directedEdgesVAO.stopUsing(gl); + } + + if (directedEdgesVAOSecondary != null) { + directedEdgesVAOSecondary.stopUsing(gl); + } } public void dispose(GL gl) { @@ -544,8 +764,20 @@ public void dispose(GL gl) { vertexGLBufferDirected.destroy(gl); } - if (attributesGLBuffer != null) { - attributesGLBuffer.destroy(gl); + if (attributesGLBufferDirected != null) { + attributesGLBufferDirected.destroy(gl); + } + + if (attributesGLBufferDirectedSecondary != null) { + attributesGLBufferDirectedSecondary.destroy(gl); + } + + if (attributesGLBufferUndirected != null) { + attributesGLBufferUndirected.destroy(gl); + } + + if (attributesGLBufferUndirectedSecondary != null) { + attributesGLBufferUndirectedSecondary.destroy(gl); } edgesCallback.reset(); @@ -553,8 +785,11 @@ public void dispose(GL gl) { private class UndirectedEdgesVAO extends GLVertexArrayObject { - public UndirectedEdgesVAO(GLCapabilitiesSummary capabilities, OpenGLOptions openGLOptions) { + private final GLBuffer attributesBuffer; + + public UndirectedEdgesVAO(GLCapabilitiesSummary capabilities, OpenGLOptions openGLOptions, GLBuffer attributesBuffer) { super(capabilities, openGLOptions); + this.attributesBuffer = attributesBuffer; } @Override @@ -565,7 +800,7 @@ protected void configure(GL2ES2 gl) { } vertexGLBufferUndirected.unbind(gl); - attributesGLBuffer.bind(gl); + attributesBuffer.bind(gl); { int stride = ATTRIBS_STRIDE * Float.BYTES; int offset = 0; @@ -585,14 +820,8 @@ protected void configure(GL2ES2 gl) { offset += EdgeLineModelUndirected.TARGET_COLOR_FLOATS * Float.BYTES; gl.glVertexAttribPointer(SHADER_COLOR_LOCATION, EdgeLineModelUndirected.COLOR_FLOATS * Float.BYTES, GL_UNSIGNED_BYTE, false, stride, offset); - offset += EdgeLineModelUndirected.COLOR_FLOATS * Float.BYTES; - - gl.glVertexAttribPointer(SHADER_COLOR_BIAS_LOCATION, EdgeLineModelUndirected.COLOR_BIAS_FLOATS, GL_FLOAT, false, stride, offset); - offset += EdgeLineModelUndirected.COLOR_BIAS_FLOATS * Float.BYTES; - - gl.glVertexAttribPointer(SHADER_COLOR_MULTIPLIER_LOCATION, EdgeLineModelUndirected.COLOR_MULTIPLIER_FLOATS, GL_FLOAT, false, stride, offset); } - attributesGLBuffer.unbind(gl); + attributesBuffer.unbind(gl); } @Override @@ -604,9 +833,7 @@ protected int[] getUsedAttributeLocations() { SHADER_SIZE_LOCATION, SHADER_SOURCE_COLOR_LOCATION, SHADER_TARGET_COLOR_LOCATION, - SHADER_COLOR_LOCATION, - SHADER_COLOR_BIAS_LOCATION, - SHADER_COLOR_MULTIPLIER_LOCATION + SHADER_COLOR_LOCATION }; } @@ -619,9 +846,7 @@ protected int[] getInstancedAttributeLocations() { SHADER_SIZE_LOCATION, SHADER_SOURCE_COLOR_LOCATION, SHADER_TARGET_COLOR_LOCATION, - SHADER_COLOR_LOCATION, - SHADER_COLOR_BIAS_LOCATION, - SHADER_COLOR_MULTIPLIER_LOCATION + SHADER_COLOR_LOCATION }; } else { return null; @@ -632,8 +857,11 @@ protected int[] getInstancedAttributeLocations() { private class DirectedEdgesVAO extends GLVertexArrayObject { - public DirectedEdgesVAO(GLCapabilitiesSummary capabilities, OpenGLOptions openGLOptions) { + private final GLBuffer attributesBuffer; + + public DirectedEdgesVAO(GLCapabilitiesSummary capabilities, OpenGLOptions openGLOptions, GLBuffer attributesBuffer) { super(capabilities, openGLOptions); + this.attributesBuffer = attributesBuffer; } @Override @@ -644,7 +872,7 @@ protected void configure(GL2ES2 gl) { } vertexGLBufferDirected.unbind(gl); - attributesGLBuffer.bind(gl); + attributesBuffer.bind(gl); { int stride = ATTRIBS_STRIDE * Float.BYTES; int offset = 0; @@ -663,15 +891,9 @@ protected void configure(GL2ES2 gl) { gl.glVertexAttribPointer(SHADER_COLOR_LOCATION, EdgeLineModelDirected.COLOR_FLOATS * Float.BYTES, GL_UNSIGNED_BYTE, false, stride, offset); offset += EdgeLineModelDirected.COLOR_FLOATS * Float.BYTES; - gl.glVertexAttribPointer(SHADER_COLOR_BIAS_LOCATION, EdgeLineModelDirected.COLOR_BIAS_FLOATS, GL_FLOAT, false, stride, offset); - offset += EdgeLineModelDirected.COLOR_BIAS_FLOATS * Float.BYTES; - - gl.glVertexAttribPointer(SHADER_COLOR_MULTIPLIER_LOCATION, EdgeLineModelDirected.COLOR_MULTIPLIER_FLOATS, GL_FLOAT, false, stride, offset); - offset += EdgeLineModelDirected.COLOR_MULTIPLIER_FLOATS * Float.BYTES; - gl.glVertexAttribPointer(SHADER_TARGET_SIZE_LOCATION, EdgeLineModelDirected.TARGET_SIZE_FLOATS, GL_FLOAT, false, stride, offset); } - attributesGLBuffer.unbind(gl); + attributesBuffer.unbind(gl); } @Override @@ -683,8 +905,6 @@ protected int[] getUsedAttributeLocations() { SHADER_SIZE_LOCATION, SHADER_SOURCE_COLOR_LOCATION, SHADER_COLOR_LOCATION, - SHADER_COLOR_BIAS_LOCATION, - SHADER_COLOR_MULTIPLIER_LOCATION, SHADER_TARGET_SIZE_LOCATION }; } @@ -698,8 +918,6 @@ protected int[] getInstancedAttributeLocations() { SHADER_SIZE_LOCATION, SHADER_SOURCE_COLOR_LOCATION, SHADER_COLOR_LOCATION, - SHADER_COLOR_BIAS_LOCATION, - SHADER_COLOR_MULTIPLIER_LOCATION, SHADER_TARGET_SIZE_LOCATION }; } else { diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractEdgeRenderer.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractEdgeRenderer.java new file mode 100644 index 0000000..0bc8fea --- /dev/null +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractEdgeRenderer.java @@ -0,0 +1,32 @@ +package org.gephi.viz.engine.jogl.pipeline.common; + +import java.util.EnumSet; + +import org.gephi.viz.engine.jogl.JOGLRenderingTarget; +import org.gephi.viz.engine.pipeline.PipelineCategory; +import org.gephi.viz.engine.pipeline.RenderingLayer; +import org.gephi.viz.engine.spi.Renderer; +import org.gephi.viz.engine.util.gl.Constants; + +public abstract class AbstractEdgeRenderer implements Renderer { + private static final EnumSet LAYERS = EnumSet.of( + RenderingLayer.BACK1, + RenderingLayer.MIDDLE1 + ); + + @Override + public EnumSet getLayers() { + return LAYERS; + } + + @Override + public int getOrder() { + return Constants.RENDERING_ORDER_EDGES; + } + + @Override + public String getCategory() { + return PipelineCategory.EDGE; + } + +} diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractNodeData.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractNodeData.java index 7890c87..953cae0 100644 --- a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractNodeData.java +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractNodeData.java @@ -1,14 +1,33 @@ package org.gephi.viz.engine.jogl.pipeline.common; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; + import com.jogamp.opengl.GL; import static com.jogamp.opengl.GL.GL_FLOAT; import static com.jogamp.opengl.GL.GL_UNSIGNED_BYTE; import com.jogamp.opengl.GL2ES2; +import com.jogamp.opengl.util.GLBuffers; import org.gephi.graph.api.Node; import org.gephi.viz.engine.VizEngine; import org.gephi.viz.engine.jogl.models.NodeDiskModel; +import org.gephi.viz.engine.jogl.models.NodeDiskVertexDataGenerator; +import org.gephi.viz.engine.jogl.util.ManagedDirectBuffer; +import org.gephi.viz.engine.jogl.util.gl.BufferUtils; +import org.gephi.viz.engine.jogl.util.gl.GLBufferMutable; +import org.gephi.viz.engine.pipeline.RenderingLayer; +import org.gephi.viz.engine.pipeline.common.InstanceCounter; +import org.gephi.viz.engine.status.GraphRenderingOptions; +import org.gephi.viz.engine.status.GraphSelection; +import org.gephi.viz.engine.structure.GraphIndexImpl; import org.gephi.viz.engine.util.gl.Constants; + +import static com.jogamp.opengl.GL.GL_UNSIGNED_INT; +import static org.gephi.viz.engine.jogl.util.gl.GLBufferMutable.GL_BUFFER_TYPE_ARRAY; +import static org.gephi.viz.engine.jogl.util.gl.GLBufferMutable.GL_BUFFER_USAGE_STATIC_DRAW; import static org.gephi.viz.engine.util.gl.Constants.*; +import static org.gephi.viz.engine.util.gl.GLConstants.INDIRECT_DRAW_COMMAND_INTS_COUNT; + import org.gephi.viz.engine.jogl.util.gl.GLBuffer; import org.gephi.viz.engine.jogl.util.gl.GLVertexArrayObject; import org.gephi.viz.engine.jogl.util.gl.capabilities.GLCapabilitiesSummary; @@ -28,103 +47,455 @@ public abstract class AbstractNodeData { protected static final int OBSERVED_SIZE_LOD_THRESHOLD_32 = 16; protected static final int OBSERVED_SIZE_LOD_THRESHOLD_16 = 2; + // NOTE: Why secondary buffers and VAOs? + // Sadly, we cannot use glDrawArraysInstancedBaseInstance in MacOS and it will be never available + protected GLBuffer vertexGLBuffer; protected GLBuffer attributesGLBuffer; + protected GLBuffer attributesGLBufferSecondary; + protected GLBuffer commandsGLBuffer; protected final NodesCallback nodesCallback = new NodesCallback(); protected static final int ATTRIBS_STRIDE = NodeDiskModel.TOTAL_ATTRIBUTES_FLOATS; - protected final boolean instanced; + protected final NodeDiskModel diskModel; + + private final NodeDiskVertexDataGenerator generator64; + private final NodeDiskVertexDataGenerator generator32; + private final NodeDiskVertexDataGenerator generator16; + private final NodeDiskVertexDataGenerator generator8; + + protected final int circleVertexCount64; + protected final int circleVertexCount32; + protected final int circleVertexCount16; + protected final int circleVertexCount8; + protected final int firstVertex64; + protected final int firstVertex32; + protected final int firstVertex16; + protected final int firstVertex8; + protected final boolean instancedRendering; + protected final boolean indirectCommands; + + // State: + protected final InstanceCounter instanceCounter = new InstanceCounter(); + protected float maxNodeSize = 0; + protected float maxNodeSizeToDraw = 0; + + // Buffers for vertex attributes: + protected static final int BATCH_NODES_SIZE = 32768; + protected ManagedDirectBuffer attributesBuffer; + protected float[] attributesBufferBatch; + protected ManagedDirectBuffer commandsBuffer; + private int[] commandsBufferBatch; + + public AbstractNodeData(final boolean instancedRendering, final boolean indirectCommands) { + this.instancedRendering = instancedRendering; + this.indirectCommands = indirectCommands; + + diskModel = new NodeDiskModel(); + + generator64 = new NodeDiskVertexDataGenerator(64); + generator32 = new NodeDiskVertexDataGenerator(32); + generator16 = new NodeDiskVertexDataGenerator(16); + generator8 = new NodeDiskVertexDataGenerator(8); + + circleVertexCount64 = generator64.getVertexCount(); + circleVertexCount32 = generator32.getVertexCount(); + circleVertexCount16 = generator16.getVertexCount(); + circleVertexCount8 = generator8.getVertexCount(); + + firstVertex64 = 0; + firstVertex32 = generator64.getVertexCount(); + firstVertex16 = firstVertex32 + generator32.getVertexCount(); + firstVertex8 = firstVertex16 + generator16.getVertexCount(); + } - public AbstractNodeData(boolean instanced) { - this.instanced = instanced; + public void init(GL2ES2 gl) { + diskModel.initGLPrograms(gl); + initBuffers(); } - protected int fillNodeAttributesData(final float[] buffer, final Node node, final int index, final boolean someSelection, final boolean selected) { - final float x = node.x(); - final float y = node.y(); - final float size = node.size(); - final int rgba = node.getRGBA(); + protected void initBuffers() { + attributesBufferBatch = new float[ATTRIBS_STRIDE * BATCH_NODES_SIZE]; + attributesBuffer = new ManagedDirectBuffer(GL_FLOAT, ATTRIBS_STRIDE * BATCH_NODES_SIZE); - //Outside circle: - { - //Position: - buffer[index + 0] = x; - buffer[index + 1] = y; + if (indirectCommands) { + commandsBufferBatch = new int[INDIRECT_DRAW_COMMAND_INTS_COUNT * BATCH_NODES_SIZE]; + commandsBuffer = new ManagedDirectBuffer(GL_UNSIGNED_INT, INDIRECT_DRAW_COMMAND_INTS_COUNT * BATCH_NODES_SIZE); + } + } + + protected void initCirclesGLVertexBuffer(GL2ES2 gl, final int bufferName) { + final NodeDiskVertexDataGenerator generator64 = new NodeDiskVertexDataGenerator(64); + final NodeDiskVertexDataGenerator generator32 = new NodeDiskVertexDataGenerator(32); + final NodeDiskVertexDataGenerator generator16 = new NodeDiskVertexDataGenerator(16); + final NodeDiskVertexDataGenerator generator8 = new NodeDiskVertexDataGenerator(8); + + final float[] circleVertexData = new float[ + generator64.getVertexData().length + + generator32.getVertexData().length + + generator16.getVertexData().length + + generator8.getVertexData().length + ]; + + int offset = 0; + System.arraycopy(generator64.getVertexData(), 0, circleVertexData, offset, generator64.getVertexData().length); + offset += generator64.getVertexData().length; + System.arraycopy(generator32.getVertexData(), 0, circleVertexData, offset, generator32.getVertexData().length); + offset += generator32.getVertexData().length; + System.arraycopy(generator16.getVertexData(), 0, circleVertexData, offset, generator16.getVertexData().length); + offset += generator16.getVertexData().length; + System.arraycopy(generator8.getVertexData(), 0, circleVertexData, offset, generator8.getVertexData().length); + + + final FloatBuffer circleVertexBuffer = GLBuffers.newDirectFloatBuffer(circleVertexData); + vertexGLBuffer = new GLBufferMutable(bufferName, GL_BUFFER_TYPE_ARRAY); + vertexGLBuffer.bind(gl); + vertexGLBuffer.init(gl, circleVertexBuffer, GL_BUFFER_USAGE_STATIC_DRAW); + vertexGLBuffer.unbind(gl); + + BufferUtils.destroyDirectBuffer(circleVertexBuffer); + } + + protected int setupShaderProgramForRenderingLayer(final GL2ES2 gl, + final RenderingLayer layer, + final VizEngine engine, + final float[] mvpFloats, + final boolean isRenderingOutsideCircle) { + final boolean someSelection = engine.getLookup().lookup(GraphSelection.class).getSelectedNodesCount() > 0; + final boolean renderingUnselectedNodes = layer.isBack(); + if (!someSelection && renderingUnselectedNodes) { + return 0; + } + + final float[] backgroundColorFloats = engine.getBackgroundColor(); + + final int instanceCount; + final float sizeMultiplier = isRenderingOutsideCircle ? 1f : INSIDE_CIRCLE_SIZE; + + if (renderingUnselectedNodes) { + instanceCount = instanceCounter.unselectedCountToDraw; + final float colorLightenFactor = engine.getLookup().lookup(GraphRenderingOptions.class).getLightenNonSelectedFactor(); + final float colorMultiplier = isRenderingOutsideCircle ? NODER_BORDER_DARKEN_FACTOR : 1f; + diskModel.useProgramWithSelectionUnselected( + gl, + mvpFloats, + sizeMultiplier, + backgroundColorFloats, + colorLightenFactor, + colorMultiplier + ); + + setupSecondaryVertexArrayAttributes(gl, engine); + } else { + instanceCount = instanceCounter.selectedCountToDraw; - //Color: - buffer[index + 2] = Float.intBitsToFloat(rgba); - //Bias, multiplier and lighten factor: - buffer[index + 3] = 0; if (someSelection) { - if (selected) { - buffer[index + 4] = 1; - } else { - buffer[index + 4] = Constants.NODER_BORDER_DARKEN_FACTOR;//Darken the color - } + final float colorBias = isRenderingOutsideCircle ? 0f : 0.5f; + final float colorMultiplier = isRenderingOutsideCircle ? 1f : 0.5f; + diskModel.useProgramWithSelectionSelected( + gl, + mvpFloats, + sizeMultiplier, + colorBias, + colorMultiplier + ); } else { - buffer[index + 4] = Constants.NODER_BORDER_DARKEN_FACTOR;//Darken the color + final float colorMultiplier = isRenderingOutsideCircle ? NODER_BORDER_DARKEN_FACTOR : 1f; + diskModel.useProgram(gl, mvpFloats, sizeMultiplier, colorMultiplier); } - //Size: - buffer[index + 5] = size; + setupVertexArrayAttributes(gl, engine); } - final int nextIndex = index + ATTRIBS_STRIDE; + return instanceCount; + } - //Inside circle: - { - //Position: - buffer[nextIndex + 0] = x; - buffer[nextIndex + 1] = y; + protected void updateData(final float zoom, + final GraphIndexImpl spatialIndex, + final GraphRenderingOptions renderingOptions, + final GraphSelection selection) { + if (!renderingOptions.isShowNodes()) { + instanceCounter.clearCount(); + return; + } - //Color: - buffer[nextIndex + 2] = Float.intBitsToFloat(rgba); - //Bias and multiplier: - if (someSelection) { - if (selected) { - buffer[nextIndex + 3] = 0.5f; - buffer[nextIndex + 4] = 0.5f; - } else { - buffer[nextIndex + 3] = 0; - buffer[nextIndex + 4] = 1; + spatialIndex.indexNodes(); + + //Selection: + final boolean someSelection = selection.getSelectedNodesCount() > 0; + final float lightenNonSelectedFactor = renderingOptions.getLightenNonSelectedFactor(); + final boolean hideNonSelected = someSelection && (renderingOptions.isHideNonSelected() || lightenNonSelectedFactor >= 1); + + final int totalNodes = spatialIndex.getNodeCount(); + + attributesBuffer.ensureCapacity(totalNodes * ATTRIBS_STRIDE); + if (indirectCommands) { + commandsBuffer.ensureCapacity(totalNodes * INDIRECT_DRAW_COMMAND_INTS_COUNT); + } + + final FloatBuffer attribs = attributesBuffer.floatBuffer(); + final IntBuffer commands = indirectCommands ? commandsBuffer.intBuffer() : null; + + spatialIndex.getVisibleNodes(nodesCallback); + + final Node[] visibleNodesArray = nodesCallback.getNodesArray(); + final int visibleNodesCount = nodesCallback.getCount(); + + int newNodesCountUnselected = 0; + int newNodesCountSelected = 0; + + float newMaxNodeSize = 0; + for (int j = 0; j < visibleNodesCount; j++) { + final float size = visibleNodesArray[j].size(); + newMaxNodeSize = Math.max(size, newMaxNodeSize); + } + + int attributesIndex = 0; + int commandIndex = 0; + int instanceId = 0; + if (someSelection) { + if (hideNonSelected) { + for (int j = 0; j < visibleNodesCount; j++) { + final Node node = visibleNodesArray[j]; + + final boolean selected = selection.isNodeSelected(node); + if (!selected) { + continue; + } + + newNodesCountSelected++; + fillNodeAttributesData(node, attributesIndex); + attributesIndex += ATTRIBS_STRIDE; + + if (attributesIndex == attributesBufferBatch.length) { + attribs.put(attributesBufferBatch); + attributesIndex = 0; + } + + if (indirectCommands) { + fillNodeCommandData(node, zoom, commandIndex, instanceId); + instanceId++; + commandIndex += INDIRECT_DRAW_COMMAND_INTS_COUNT; + + if (commandIndex == commandsBufferBatch.length) { + commands.put(commandsBufferBatch); + commandIndex = 0; + } + } } } else { - buffer[nextIndex + 3] = 0; - buffer[nextIndex + 4] = 1; + //First non-selected (bottom): + for (int j = 0; j < visibleNodesCount; j++) { + final Node node = visibleNodesArray[j]; + + final boolean selected = selection.isNodeSelected(node); + if (selected) { + continue; + } + + newNodesCountUnselected++; + + fillNodeAttributesData(node, attributesIndex); + attributesIndex += ATTRIBS_STRIDE; + + if (attributesIndex == attributesBufferBatch.length) { + attribs.put(attributesBufferBatch); + attributesIndex = 0; + } + + if (indirectCommands) { + fillNodeCommandData(node, zoom, commandIndex, instanceId); + instanceId++; + commandIndex += INDIRECT_DRAW_COMMAND_INTS_COUNT; + + if (commandIndex == commandsBufferBatch.length) { + commands.put(commandsBufferBatch); + commandIndex = 0; + } + } + } + + instanceId = 0;//Reset instance id, since we draw elements in 2 separate attribute buffers (main/selected and secondary/unselected) + //Then selected ones (up): + for (int j = 0; j < visibleNodesCount; j++) { + final Node node = visibleNodesArray[j]; + + final boolean selected = selection.isNodeSelected(node); + if (!selected) { + continue; + } + + newNodesCountSelected++; + + fillNodeAttributesData(node, attributesIndex); + attributesIndex += ATTRIBS_STRIDE; + + if (attributesIndex == attributesBufferBatch.length) { + attribs.put(attributesBufferBatch); + attributesIndex = 0; + } + + if (indirectCommands) { + fillNodeCommandData(node, zoom, commandIndex, instanceId); + instanceId++; + commandIndex += INDIRECT_DRAW_COMMAND_INTS_COUNT; + + if (commandIndex == commandsBufferBatch.length) { + commands.put(commandsBufferBatch); + commandIndex = 0; + } + } + } } + } else { + //Just all nodes, no selection active: + for (int j = 0; j < visibleNodesCount; j++) { + final Node node = visibleNodesArray[j]; + + newNodesCountSelected++; + + fillNodeAttributesData(node, attributesIndex); + attributesIndex += ATTRIBS_STRIDE; + + if (attributesIndex == attributesBufferBatch.length) { + attribs.put(attributesBufferBatch); + attributesIndex = 0; + } + + if (indirectCommands) { + fillNodeCommandData(node, zoom, commandIndex, instanceId); + instanceId++; + commandIndex += INDIRECT_DRAW_COMMAND_INTS_COUNT; - //Size: - buffer[nextIndex + 5] = size * INSIDE_CIRCLE_SIZE; + if (commandIndex == commandsBufferBatch.length) { + commands.put(commandsBufferBatch); + commandIndex = 0; + } + } + } } - return nextIndex + ATTRIBS_STRIDE; + //Remaining: + if (attributesIndex > 0) { + attribs.put(attributesBufferBatch, 0, attributesIndex); + } + + if (indirectCommands && commandIndex > 0) { + commands.put(commandsBufferBatch, 0, commandIndex); + } + + instanceCounter.unselectedCount = newNodesCountUnselected; + instanceCounter.selectedCount = newNodesCountSelected; + maxNodeSize = newMaxNodeSize; + } + + protected void fillNodeAttributesData(final Node node, final int index) { + final float x = node.x(); + final float y = node.y(); + final float size = node.size(); + final int rgba = node.getRGBA(); + + //Position: + attributesBufferBatch[index] = x; + attributesBufferBatch[index + 1] = y; + + //Color: + attributesBufferBatch[index + 2] = Float.intBitsToFloat(rgba); + + //Size: + attributesBufferBatch[index + 3] = size; + } + + protected void fillNodeCommandData(final Node node, final float zoom, final int index, final int instanceId) { + //Indirect Draw: + //Choose LOD: + final float observedSize = node.size() * zoom; + + final int circleVertexCount; + final int firstVertex; + if (observedSize > OBSERVED_SIZE_LOD_THRESHOLD_64) { + circleVertexCount = circleVertexCount64; + firstVertex = firstVertex64; + } else if (observedSize > OBSERVED_SIZE_LOD_THRESHOLD_32) { + circleVertexCount = circleVertexCount32; + firstVertex = firstVertex32; + } else if (observedSize > OBSERVED_SIZE_LOD_THRESHOLD_16) { + circleVertexCount = circleVertexCount16; + firstVertex = firstVertex16; + } else { + circleVertexCount = circleVertexCount8; + firstVertex = firstVertex8; + } + + commandsBufferBatch[index] = circleVertexCount;//vertex count + commandsBufferBatch[index + 1] = 1;//instance count + commandsBufferBatch[index + 2] = firstVertex;//first vertex + commandsBufferBatch[index + 3] = instanceId;//base instance } private NodesVAO nodesVAO; + private NodesVAO nodesVAOSecondary; - public void setupVertexArrayAttributes(VizEngine engine, GL2ES2 gl) { + public void setupVertexArrayAttributes(GL2ES2 gl, VizEngine engine) { if (nodesVAO == null) { nodesVAO = new NodesVAO( - engine.getLookup().lookup(GLCapabilitiesSummary.class), - engine.getLookup().lookup(OpenGLOptions.class) + engine.getLookup().lookup(GLCapabilitiesSummary.class), + engine.getLookup().lookup(OpenGLOptions.class), + vertexGLBuffer, attributesGLBuffer ); } nodesVAO.use(gl); } + public void setupSecondaryVertexArrayAttributes(GL2ES2 gl, VizEngine engine) { + if (nodesVAOSecondary == null) { + nodesVAOSecondary = new NodesVAO( + engine.getLookup().lookup(GLCapabilitiesSummary.class), + engine.getLookup().lookup(OpenGLOptions.class), + vertexGLBuffer, attributesGLBufferSecondary + ); + } + + nodesVAOSecondary.use(gl); + } + public void unsetupVertexArrayAttributes(GL2ES2 gl) { - nodesVAO.stopUsing(gl); + if (nodesVAO != null) { + nodesVAO.stopUsing(gl); + } + + if (nodesVAOSecondary != null) { + nodesVAOSecondary.stopUsing(gl); + } } - public void dispose(GL gl) { + public void dispose(GL2ES2 gl) { + attributesBufferBatch = null; + commandsBufferBatch = null; + if (attributesBuffer != null) { + attributesBuffer.destroy(); + attributesBuffer = null; + } + if (vertexGLBuffer != null) { vertexGLBuffer.destroy(gl); + vertexGLBuffer = null; } if (attributesGLBuffer != null) { attributesGLBuffer.destroy(gl); + attributesGLBuffer = null; + } + + if (attributesGLBufferSecondary != null) { + attributesGLBufferSecondary.destroy(gl); + attributesGLBufferSecondary = null; + } + if (commandsBuffer != null) { + commandsBuffer.destroy(); + commandsBuffer = null; } nodesCallback.reset(); @@ -132,20 +503,25 @@ public void dispose(GL gl) { private class NodesVAO extends GLVertexArrayObject { - public NodesVAO(GLCapabilitiesSummary capabilities, OpenGLOptions openGLOptions) { + private final GLBuffer vertexBuffer; + private final GLBuffer attributesBuffer; + + public NodesVAO(GLCapabilitiesSummary capabilities, OpenGLOptions openGLOptions, final GLBuffer vertexBuffer, final GLBuffer attributesBuffer) { super(capabilities, openGLOptions); + this.vertexBuffer = vertexBuffer; + this.attributesBuffer = attributesBuffer; } @Override protected void configure(GL2ES2 gl) { - vertexGLBuffer.bind(gl); + vertexBuffer.bind(gl); { gl.glVertexAttribPointer(SHADER_VERT_LOCATION, NodeDiskModel.VERTEX_FLOATS, GL_FLOAT, false, 0, 0); } - vertexGLBuffer.unbind(gl); + vertexBuffer.unbind(gl); - if (instanced) { - attributesGLBuffer.bind(gl); + if (instancedRendering) { + attributesBuffer.bind(gl); { final int stride = ATTRIBS_STRIDE * Float.BYTES; int offset = 0; @@ -156,27 +532,19 @@ protected void configure(GL2ES2 gl) { gl.glVertexAttribPointer(SHADER_COLOR_LOCATION, NodeDiskModel.COLOR_FLOATS * Float.BYTES, GL_UNSIGNED_BYTE, false, stride, offset); offset += NodeDiskModel.COLOR_FLOATS * Float.BYTES; - gl.glVertexAttribPointer(SHADER_COLOR_BIAS_LOCATION, NodeDiskModel.COLOR_BIAS_FLOATS, GL_FLOAT, false, stride, offset); - offset += NodeDiskModel.COLOR_BIAS_FLOATS * Float.BYTES; - - gl.glVertexAttribPointer(SHADER_COLOR_MULTIPLIER_LOCATION, NodeDiskModel.COLOR_MULTIPLIER_FLOATS, GL_FLOAT, false, stride, offset); - offset += NodeDiskModel.COLOR_MULTIPLIER_FLOATS * Float.BYTES; - gl.glVertexAttribPointer(SHADER_SIZE_LOCATION, NodeDiskModel.SIZE_FLOATS, GL_FLOAT, false, stride, offset); } - attributesGLBuffer.unbind(gl); + attributesBuffer.unbind(gl); } } @Override protected int[] getUsedAttributeLocations() { - if (instanced) { + if (instancedRendering) { return new int[]{ SHADER_VERT_LOCATION, SHADER_POSITION_LOCATION, SHADER_COLOR_LOCATION, - SHADER_COLOR_BIAS_LOCATION, - SHADER_COLOR_MULTIPLIER_LOCATION, SHADER_SIZE_LOCATION }; } else { @@ -188,12 +556,10 @@ protected int[] getUsedAttributeLocations() { @Override protected int[] getInstancedAttributeLocations() { - if (instanced) { + if (instancedRendering) { return new int[]{ SHADER_POSITION_LOCATION, SHADER_COLOR_LOCATION, - SHADER_COLOR_BIAS_LOCATION, - SHADER_COLOR_MULTIPLIER_LOCATION, SHADER_SIZE_LOCATION }; } else { diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractNodeRenderer.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractNodeRenderer.java new file mode 100644 index 0000000..3acbba9 --- /dev/null +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/pipeline/common/AbstractNodeRenderer.java @@ -0,0 +1,31 @@ +package org.gephi.viz.engine.jogl.pipeline.common; + +import java.util.EnumSet; + +import org.gephi.viz.engine.jogl.JOGLRenderingTarget; +import org.gephi.viz.engine.pipeline.PipelineCategory; +import org.gephi.viz.engine.pipeline.RenderingLayer; +import org.gephi.viz.engine.spi.Renderer; +import org.gephi.viz.engine.util.gl.Constants; + +public abstract class AbstractNodeRenderer implements Renderer { + public static final EnumSet LAYERS = EnumSet.of( + RenderingLayer.BACK2, + RenderingLayer.MIDDLE2 + ); + + @Override + public EnumSet getLayers() { + return LAYERS; + } + + @Override + public int getOrder() { + return Constants.RENDERING_ORDER_NODES; + } + + @Override + public String getCategory() { + return PipelineCategory.NODE; + } +} diff --git a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/util/gl/capabilities/GLCapabilitiesSummary.java b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/util/gl/capabilities/GLCapabilitiesSummary.java index 7cbe68f..9330fec 100644 --- a/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/util/gl/capabilities/GLCapabilitiesSummary.java +++ b/modules/opengl-jogl/src/main/java/org/gephi/viz/engine/jogl/util/gl/capabilities/GLCapabilitiesSummary.java @@ -695,6 +695,9 @@ public boolean isInstancingSupported() { } public boolean isIndirectDrawSupported() { - return extensions.ARB_multi_draw_indirect; + return + extensions.ARB_draw_indirect && + extensions.ARB_multi_draw_indirect && + extensions.ARB_buffer_storage; } }