Skip to content

Commit

Permalink
fix curved path picking
Browse files Browse the repository at this point in the history
  • Loading branch information
Manfred Cheung committed Aug 22, 2023
1 parent 91c2938 commit cf208c2
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 8 deletions.
15 changes: 13 additions & 2 deletions src/graph/edges/path/CurvedPath.data.vs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ layout(location=1) in uint aTargetIndex;
layout(location=2) in uvec3 aControl;
layout(location=3) in uint aSourceColor;
layout(location=4) in uint aTargetColor;
layout(location=5) in uvec4 aPickingColor;

uniform sampler2D uGraphPoints;

Expand All @@ -14,8 +15,16 @@ out vec3 vControl;
flat out uint vSourceColor;
flat out uint vTargetColor;
out vec2 vColorMix;

#pragma glslify: valueForIndex = require(../../../renderer/shaders/valueForIndex.glsl)
flat out uvec4 vPickingColor;

// manual import from ../../../renderer/shaders/valueForIndex.glsl
// to avoid uvec4 pragma error
vec4 valueForIndex(sampler2D tex, int index) {
int texWidth = textureSize(tex, 0).x;
int col = index % texWidth;
int row = index / texWidth;
return texelFetch(tex, ivec2(col, row), 0);
}

void main() {
vec4 source = valueForIndex(uGraphPoints, int(aSourceIndex));
Expand All @@ -41,4 +50,6 @@ void main() {
vTargetColor = aTargetColor;

vColorMix = vec2(float(aControl[1]) / float(aControl[2]), float(aControl[1] + 1u) / float(aControl[2]));

vPickingColor = aPickingColor;
}
10 changes: 10 additions & 0 deletions src/graph/edges/path/CurvedPath.picking.fs.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#version 300 es
precision highp float;

flat in vec4 fPickingColor;

out vec4 fragColor;

void main() {
fragColor = fPickingColor;
}
60 changes: 55 additions & 5 deletions src/graph/edges/path/CurvedPath.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import edgeVS from './CurvedPath.vs.glsl';
import edgeFS from './CurvedPath.fs.glsl';
import pickingFS from './CurvedPath.picking.fs.glsl';
import dataVS from './CurvedPath.data.vs.glsl';

import {App, DrawCall, PicoGL, Program, VertexArray, VertexBuffer} from 'picogl';
import {GraferInputColor} from '../../../renderer/colors/ColorRegistry';
import {DataMappings, DataShader, kDataMappingFlatten} from '../../../data/DataTools';
import {DataMappings, DataShader, kDataMappingFlatten, printDataGL} from '../../../data/DataTools';

Check warning on line 8 in src/graph/edges/path/CurvedPath.ts

View workflow job for this annotation

GitHub Actions / clean-lint-build-test (14.x)

'printDataGL' is defined but never used

Check warning on line 8 in src/graph/edges/path/CurvedPath.ts

View workflow job for this annotation

GitHub Actions / clean-lint-build-test (16.x)

'printDataGL' is defined but never used

Check warning on line 8 in src/graph/edges/path/CurvedPath.ts

View workflow job for this annotation

GitHub Actions / clean-lint-build-test (18.x)

'printDataGL' is defined but never used
import {
GLDataTypes,
RenderableShaders,
Expand All @@ -14,7 +15,8 @@ import {
} from '../../../renderer/Renderable';
import {Edges} from '../Edges';
import {GraphPoints} from '../../../data/GraphPoints';
import {PickingManager} from '../../../UX/picking/PickingManager';
import {PickingColors, PickingEvent, PickingManager} from '../../../UX/picking/PickingManager';
import {MouseCallback} from '../../../UX/mouse/MouseHandler';
import {GraferContext} from '../../../renderer/GraferContext';

export interface CurvedPathEdgeData {
Expand All @@ -24,15 +26,18 @@ export interface CurvedPathEdgeData {
control: number | number[];
sourceColor?: GraferInputColor,
targetColor?: GraferInputColor,
pickingColor?: [number, number, number, number];
}

const pickingColorNoOpMapping = (): null => null;
export const kCurvedPathEdgeMappings: DataMappings<CurvedPathEdgeData> = {
id: (entry: CurvedPathEdgeData, i) => 'id' in entry ? entry.id : i,
source: (entry: CurvedPathEdgeData) => entry.source,
target: (entry: CurvedPathEdgeData) => entry.target,
control: (entry: CurvedPathEdgeData) => entry.control,
sourceColor: (entry: CurvedPathEdgeData) => 'sourceColor' in entry ? entry.sourceColor : 0, // first registered color
targetColor: (entry: CurvedPathEdgeData) => 'targetColor' in entry ? entry.targetColor : 0, // first registered color
pickingColor: pickingColorNoOpMapping,
};

export const kCurvedPathEdgeDataTypes: GLDataTypes<CurvedPathEdgeData> = {
Expand All @@ -41,6 +46,7 @@ export const kCurvedPathEdgeDataTypes: GLDataTypes<CurvedPathEdgeData> = {
control: [PicoGL.UNSIGNED_INT, PicoGL.UNSIGNED_INT, PicoGL.UNSIGNED_INT],
sourceColor: PicoGL.UNSIGNED_INT,
targetColor: PicoGL.UNSIGNED_INT,
pickingColor: [PicoGL.UNSIGNED_INT, PicoGL.UNSIGNED_INT, PicoGL.UNSIGNED_INT, PicoGL.UNSIGNED_INT],
};

export const kGLCurvedPathEdgeTypes = {
Expand All @@ -50,13 +56,19 @@ export const kGLCurvedPathEdgeTypes = {
sourceColor: PicoGL.UNSIGNED_INT,
targetColor: PicoGL.UNSIGNED_INT,
colorMix: [PicoGL.FLOAT, PicoGL.FLOAT],
pickingColor: [PicoGL.UNSIGNED_INT, PicoGL.UNSIGNED_INT, PicoGL.UNSIGNED_INT, PicoGL.UNSIGNED_INT],
} as const;
export type GLCurvedPathEdgeTypes = typeof kGLCurvedPathEdgeTypes;

export class CurvedPath extends Edges<CurvedPathEdgeData, GLCurvedPathEdgeTypes> {
protected program: Program;
protected drawCall: DrawCall;

protected pickingProgram: Program;
protected pickingDrawCall: DrawCall;
protected pickingColors: PickingColors;
protected pickingHandler: MouseCallback;

protected verticesVBO: VertexBuffer;
protected edgesVAO: VertexArray;

Expand Down Expand Up @@ -89,6 +101,8 @@ export class CurvedPath extends Edges<CurvedPathEdgeData, GLCurvedPathEdgeTypes>
);
}

this.pickingHandler = this.handlePickingEvent.bind(this);

this.verticesVBO = context.createVertexBuffer(PicoGL.FLOAT, 2, new Float32Array(segmentVertices));
this.edgesVAO = context.createVertexArray().vertexAttributeBuffer(0, this.verticesVBO);
this.configureTargetVAO(this.edgesVAO);
Expand All @@ -97,11 +111,18 @@ export class CurvedPath extends Edges<CurvedPathEdgeData, GLCurvedPathEdgeTypes>
this.program = context.createProgram(shaders.vs, shaders.fs);
this.drawCall = context.createDrawCall(this.program, this.edgesVAO).primitive(PicoGL.TRIANGLE_STRIP);

const pickingShaders = this.getPickingShaders();
this.pickingProgram = context.createProgram(pickingShaders.vs, pickingShaders.fs);
this.pickingDrawCall = context.createDrawCall(this.pickingProgram, this.edgesVAO).primitive(PicoGL.TRIANGLE_STRIP);

this.compute(context, {
uGraphPoints: this.dataTexture,
});

// printDataGL(context, this.targetVBO, data.length, kGLCurvedPathEdgeTypes);
this.pickingManager.on(PickingManager.events.hoverOn, this.pickingHandler);
this.pickingManager.on(PickingManager.events.hoverOff, this.pickingHandler);
this.pickingManager.on(PickingManager.events.click, this.pickingHandler);

this.localUniforms.uSegments = segments;
}
Expand All @@ -110,6 +131,25 @@ export class CurvedPath extends Edges<CurvedPathEdgeData, GLCurvedPathEdgeTypes>
// TODO: Implement destroy method
}

protected ingestData(context: App, data: unknown[], mappings: Partial<DataMappings<CurvedPathEdgeData>>): void {
this.pickingColors = this.pickingManager.allocatePickingColors(data.length);
super.ingestData(context, data, mappings);
}

protected packDataCB(): any {
return (index, entry): void => {
this.idArray.push(entry.id);

const indexStart = 4 * index;
entry.pickingColor = [
this.pickingColors.colors[indexStart],
this.pickingColors.colors[indexStart + 1],
this.pickingColors.colors[indexStart + 2],
this.pickingColors.colors[indexStart + 3],
];
};
}

public render(context:App, mode: RenderMode, uniforms: RenderUniforms): void {
setDrawCallUniforms(this.drawCall, uniforms);
setDrawCallUniforms(this.drawCall, this.localUniforms);
Expand All @@ -118,7 +158,10 @@ export class CurvedPath extends Edges<CurvedPathEdgeData, GLCurvedPathEdgeTypes>

switch (mode) {
case RenderMode.PICKING:
// this.pickingDrawCall.draw();
setDrawCallUniforms(this.pickingDrawCall, uniforms);
setDrawCallUniforms(this.pickingDrawCall, this.localUniforms);
this.pickingDrawCall.uniform('uPicking', true);
this.pickingDrawCall.draw();
break;

default:
Expand All @@ -137,7 +180,7 @@ export class CurvedPath extends Edges<CurvedPathEdgeData, GLCurvedPathEdgeTypes>
protected getPickingShaders(): RenderableShaders {
return {
vs: edgeVS,
fs: null, // pickingFS,
fs: pickingFS,
};
}

Expand All @@ -152,7 +195,7 @@ export class CurvedPath extends Edges<CurvedPathEdgeData, GLCurvedPathEdgeTypes>
protected getDataShader(): DataShader {
return {
vs: dataVS,
varyings: [ 'vSource', 'vTarget', 'vControl', 'vSourceColor', 'vTargetColor', 'vColorMix' ],
varyings: [ 'vSource', 'vTarget', 'vControl', 'vSourceColor', 'vTargetColor', 'vColorMix', 'vPickingColor' ],
};
}

Expand Down Expand Up @@ -180,4 +223,11 @@ export class CurvedPath extends Edges<CurvedPathEdgeData, GLCurvedPathEdgeTypes>

return edgesMappings;
}

protected handlePickingEvent(event: PickingEvent, colorID: number): void {
if (this.picking && this.pickingColors.map.has(colorID)) {
const id = this.idArray[this.pickingColors.map.get(colorID)];
this.emit(event, id);
}
}
}
8 changes: 7 additions & 1 deletion src/graph/edges/path/CurvedPath.vs.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ layout(location=3) in vec3 iControl;
layout(location=4) in uint iColorA;
layout(location=5) in uint iColorB;
layout(location=6) in vec2 iColorMix;
layout(location=7) in uvec4 iPickingColor;

uniform bool uPicking;

uniform mat4 uViewMatrix;
uniform mat4 uSceneMatrix;
Expand All @@ -19,6 +22,7 @@ uniform float uLineWidth;
uniform float uSegments;

flat out float fLineWidth;
flat out vec4 fPickingColor;
out vec3 vColor;
out vec2 vProjectedPosition;
out float vProjectedW;
Expand All @@ -35,6 +39,8 @@ vec3 bezier(vec3 p0, vec3 p1, vec3 p2, float t) {
}

void main() {
fPickingColor = uPicking ? vec4(iPickingColor) / 255.0 : vec4(0.0);

// bezier works fine with 0 > t > 1
float t0 = aVertex.y / uSegments;
float t1 = (aVertex.y + 1.0) / uSegments;
Expand All @@ -57,7 +63,7 @@ void main() {
vec2 normal = vec2(-direction.y, direction.x);

// calculate the pixel offset
fLineWidth = uLineWidth * uPixelRatio;
fLineWidth = (uPicking ? uLineWidth * 8. : uLineWidth) * uPixelRatio;
float offsetWidth = fLineWidth + 0.5;
vec4 offset = vec4(((aVertex.x * normal * offsetWidth) / uViewportSize) * b0Projected.w, 0.0, 0.0);

Expand Down

0 comments on commit cf208c2

Please sign in to comment.