388 lines
15 KiB
GLSL
388 lines
15 KiB
GLSL
#version 120
|
|
#extension GL_EXT_geometry_shader4 : require
|
|
#extension GL_EXT_gpu_shader4 : require
|
|
|
|
varying out vec3 NORMAL ;
|
|
varying out vec4 COLOR ;
|
|
varying out float fog;
|
|
varying out vec2 bgTextureLookup;
|
|
varying out float lineEdge;
|
|
varying out float aaCutoff;
|
|
|
|
varying in vec4 a_center[];
|
|
varying in vec4 a_target[];
|
|
varying in vec4 COLORIn[];
|
|
varying in vec2 a_textSizeIn[];
|
|
varying in vec3 a_screenWorldOffsetIn[];
|
|
varying in vec2 a_indentFactorIn[];
|
|
varying in float a_relative_modeIn[];
|
|
varying in float a_draw_flagsIn[];
|
|
varying in vec4 a_bkgrd_colorIn[];
|
|
varying in float a_rel_ext_lengthIn[];
|
|
varying in float a_con_widthIn[];
|
|
|
|
uniform vec2 screenSize;
|
|
uniform float screenOriginVertexScale;
|
|
uniform float antialiasedLines;
|
|
uniform float textureToLabelSize;
|
|
uniform float front;
|
|
uniform float clipRange;
|
|
|
|
float PI = 3.14159265358979323846264;
|
|
|
|
float mysmoothstep(float edge0, float edge1, float x){
|
|
float rets = step(edge0, edge1) * step(edge1, edge0);
|
|
return rets * step(edge0, x) + (1.-rets) * smoothstep(edge0, edge1, x);
|
|
}
|
|
|
|
#include connector.shared
|
|
|
|
struct lineSeg_t {
|
|
vec2 p1;
|
|
vec2 p2;
|
|
};
|
|
bool lineSegIntersection(vec2 p1, vec2 p2, vec2 p3, vec2 p4, out vec2 po) {
|
|
float distAB, theCos, theSin, newX, abpos;
|
|
vec2 p2i, p3i, p4i;
|
|
if ((p1.x==p2.x && p1.y==p2.y) || (p3.x==p4.x && p3.y==p4.y)) return false;
|
|
if ((p1.x==p3.x && p1.y==p3.y) || (p2.x==p3.x && p2.y==p3.y)
|
|
|| (p1.x==p4.x && p1.y==p4.y) || (p2.x==p4.x && p2.y==p4.y)) {
|
|
return false; }
|
|
p2i.x = p2.x; p2i.y = p2.y;
|
|
p3i.x = p3.x; p3i.y = p3.y;
|
|
p4i.x = p4.x; p4i.y = p4.y;
|
|
p2i.x -= p1.x; p2i.y -= p1.y;
|
|
p3i.x -= p1.x; p3i.y -= p1.y;
|
|
p4i.x -= p1.x; p4i.y -= p1.y;
|
|
distAB = sqrt(p2i.x * p2i.x + p2i.y * p2i.y);
|
|
theCos = p2i.x / distAB;
|
|
theSin = p2i.y / distAB;
|
|
newX = p3i.x * theCos + p3i.y * theSin;
|
|
p3i.y = p3i.y * theCos - p3i.x * theSin;
|
|
p3i.x = newX;
|
|
newX = p4i.x * theCos + p4i.y * theSin;
|
|
p4i.y = p4i.y * theCos - p4i.x * theSin;
|
|
p4i.x = newX;
|
|
if ((p3i.y < 0. && p4i.y<0.) || (p3i.y >= 0. && p4i.y >= 0.)) return false;
|
|
abpos = p4i.x + (p3i.x - p4i.x) * p4i.y / (p4i.y - p3i.y);
|
|
if (abpos<0. || abpos>distAB) return false;
|
|
po.x = p1.x + abpos * theCos;
|
|
po.y = p1.y + abpos * theSin;
|
|
return true;
|
|
}
|
|
|
|
void setBG(){
|
|
bgTextureLookup = (gl_Position.xy/gl_Position.w) / 2.0 + 0.5;
|
|
}
|
|
|
|
void drawLineAsGeometryClipped(vec4 pt1, vec4 pt2, lineSeg_t labelTop, lineSeg_t labelBottom, lineSeg_t labelLeft, lineSeg_t labelRight, out vec2 dirv, float lineWidth, float aa){
|
|
vec4 pt1E = pt1;
|
|
vec4 pt2E = pt2;
|
|
pt1E.xy = floor(pt1.xy * screenSize) / screenSize;
|
|
pt2E.xy = floor(pt2.xy * screenSize) / screenSize;
|
|
vec3 diffV = pt1E.xyz - pt2E.xyz;
|
|
vec2 dirvPnorm = vec2(normalize(cross(diffV, vec3(0.,0.,1.))).xy);
|
|
vec2 dirvP = lineWidth*dirvPnorm;
|
|
dirv = dirvP/screenSize;
|
|
int l1V = 0 , l2V = 0;
|
|
lineSeg_t l1, l2;
|
|
vec2 isec1, isec2;
|
|
l1.p1 = pt1.xy + dirv;
|
|
l1.p2 = pt2.xy + dirv;
|
|
l2.p1 = pt1.xy - dirv;
|
|
l2.p2 = pt2.xy - dirv;
|
|
|
|
if (lineSegIntersection(labelTop.p1, labelTop.p2, l1.p1, l1.p2, isec1)) {
|
|
l1V = 1;
|
|
} else if (lineSegIntersection(labelRight.p1, labelRight.p2, l1.p1, l1.p2, isec1)) {
|
|
l1V = 2;
|
|
} else if (lineSegIntersection(labelBottom.p1, labelBottom.p2, l1.p1, l1.p2, isec1)) {
|
|
l1V = 3;
|
|
} else if (lineSegIntersection(labelLeft.p1, labelLeft.p2, l1.p1, l1.p2, isec1)) {
|
|
l1V = 4;
|
|
}
|
|
|
|
if (lineSegIntersection(labelTop.p1, labelTop.p2, l2.p1, l2.p2, isec2)) {
|
|
l2V = 1;
|
|
} else if (lineSegIntersection(labelRight.p1, labelRight.p2, l2.p1, l2.p2, isec2)) {
|
|
l2V = 2;
|
|
} else if (lineSegIntersection(labelBottom.p1, labelBottom.p2, l2.p1, l2.p2, isec2)) {
|
|
l2V = 3;
|
|
} else if (lineSegIntersection(labelLeft.p1, labelLeft.p2, l2.p1, l2.p2, isec2)) {
|
|
l2V = 4;
|
|
}
|
|
|
|
// Both lines run through one side
|
|
if ( (l1V > 0 && l2V > 0) && (l1V == l2V) ) {
|
|
pt1E.xy = pt1.xy + dirv; pt1E.z = pt1.z;
|
|
gl_Position = pt1E;
|
|
lineEdge = 1.; aaCutoff = aa;
|
|
setBG(); EmitVertex();
|
|
|
|
pt1E.xy = pt1.xy - dirv; pt1E.z = pt1.z;
|
|
gl_Position = pt1E;
|
|
lineEdge = -1.;
|
|
setBG(); EmitVertex();
|
|
|
|
pt2E.xy = isec1; pt2E.z = pt2.z;
|
|
gl_Position = pt2E;
|
|
lineEdge = 1.;
|
|
setBG(); EmitVertex();
|
|
|
|
pt2E.xy = isec2; pt2E.z = pt2.z;
|
|
gl_Position = pt2E;
|
|
lineEdge = -1.;
|
|
setBG(); EmitVertex();
|
|
EndPrimitive();
|
|
lineEdge = 0.;
|
|
aaCutoff = 0.;
|
|
|
|
} else if ( (l1V > 0 && l2V > 0) && (l1V != l2V) ) { // Find the corner
|
|
vec2 isecc;
|
|
if ( (l1V == 1 && l2V == 2) || (l1V == 2 && l2V == 1) ) { // UR
|
|
isecc = labelTop.p1;
|
|
} else if ( (l1V == 2 && l2V == 3) || (l1V == 3 && l2V == 2) ) { // LR
|
|
isecc = labelBottom.p2;
|
|
} else if ( (l1V == 3 && l2V == 4) || (l1V == 4 && l2V == 3) ) { // LL
|
|
isecc = labelBottom.p1;
|
|
} else if ( (l1V == 4 && l2V == 1) || (l1V == 1 && l2V == 4) ) { // UL
|
|
isecc = labelTop.p2;
|
|
}
|
|
|
|
pt2E.xy = isec1.xy; pt2E.z = pt2.z;
|
|
gl_Position = pt2E;
|
|
lineEdge = 1.; aaCutoff = aa;
|
|
setBG(); EmitVertex();
|
|
|
|
pt1E.xy = pt1.xy + dirv; pt1E.z = pt1.z;
|
|
gl_Position = pt1E;
|
|
lineEdge = 1.;
|
|
setBG(); EmitVertex();
|
|
|
|
pt2E.xy = isecc.xy; pt2E.z = pt2.z;
|
|
gl_Position = pt2E;
|
|
|
|
|
|
/* since we are adding a corner vertex, we also need to
|
|
account for anti-aliasing by setting lineEdge for that
|
|
vertex. */
|
|
float len1 = length(screenSize* (isecc.xy - isec1.xy)); // length between corner and first intersection
|
|
float len2 = length(screenSize* (isecc.xy - isec2.xy)); // length between corner and second intersection
|
|
float lenc = length(screenSize* (isec2.xy - isec1.xy)); // length between intersections, i.e., line width
|
|
float ang = atan(len2 / len1); // angle between perpendicular vector and first edge
|
|
float n2 = sin(ang) * len2; // second edge projected onto perpendicular vector
|
|
float lenr = (n2 / lenc) * 2. - 1.; // figure out ratio and normalize it between -1 and 1
|
|
float lenrsign = 2. * (step(0., lenr) - .5); // sign for lenr used below
|
|
lineEdge = lenrsign * (1. - mysmoothstep(0., aa, 1 - abs(lenr))); // take into account aa for corner vertex lineEdge
|
|
|
|
setBG(); EmitVertex();
|
|
|
|
pt1E.xy = pt1.xy - dirv; pt1E.z = pt1.z;
|
|
gl_Position = pt1E;
|
|
lineEdge = -1.;
|
|
setBG(); EmitVertex();
|
|
|
|
pt2E.xy = isec2.xy; pt2E.z = pt2.z;
|
|
gl_Position = pt2E;
|
|
lineEdge = -1.;
|
|
setBG(); EmitVertex();
|
|
EndPrimitive();
|
|
|
|
|
|
}
|
|
}
|
|
|
|
void drawLineAsGeometry(vec4 pt1, vec4 pt2, out vec2 dirv, float lineWidth, float aa){
|
|
vec4 pt1E = pt1;
|
|
vec4 pt2E = pt2;
|
|
pt1E.xy = floor(pt1.xy * screenSize) / screenSize;
|
|
pt2E.xy = floor(pt2.xy * screenSize) / screenSize;
|
|
vec3 diffV = pt1E.xyz - pt2E.xyz;
|
|
vec2 dirvPnorm = vec2(normalize(cross(diffV, vec3(0.,0.,1.))).xy);
|
|
vec2 dirvP = lineWidth*dirvPnorm;
|
|
dirv = dirvP/screenSize;
|
|
|
|
pt1E.xy = pt1.xy + dirv;
|
|
gl_Position = pt1E;
|
|
lineEdge = -1.; aaCutoff = aa;
|
|
setBG(); EmitVertex();
|
|
|
|
pt2E.xy = pt2.xy + dirv;
|
|
gl_Position = pt2E;
|
|
lineEdge = -1.;
|
|
setBG(); EmitVertex();
|
|
|
|
pt1E.xy = pt1.xy - dirv;
|
|
gl_Position = pt1E;
|
|
lineEdge = 1.;
|
|
setBG(); EmitVertex();
|
|
|
|
pt2E.xy = pt2.xy - dirv;
|
|
gl_Position = pt2E;
|
|
lineEdge = 1.;
|
|
setBG(); EmitVertex();
|
|
EndPrimitive();
|
|
lineEdge = 0.;
|
|
aaCutoff = 0.;
|
|
}
|
|
|
|
void drawLineAsGeometryWithOffsets(vec4 pt1, vec4 pt2, float topext, float bottomext){
|
|
vec4 pt1E = pt1;
|
|
vec4 pt2E = pt2;
|
|
vec3 diffV = pt1E.xyz - pt2E.xyz;
|
|
vec2 linev = vec2(a_con_widthIn[0] * normalize(diffV).xy) / screenSize;
|
|
vec2 dirv = vec2((a_con_widthIn[0]*normalize(cross(diffV, vec3(0.,0.,1.)).xy)))/screenSize;
|
|
pt1E.xy = pt1.xy + dirv + topext * linev;
|
|
gl_Position = pt1E;
|
|
setBG(); EmitVertex();
|
|
|
|
pt2E.xy = pt2.xy + dirv - topext * linev;
|
|
gl_Position = pt2E;
|
|
setBG(); EmitVertex();
|
|
|
|
pt1E.xy = pt1.xy - dirv + bottomext * linev;
|
|
gl_Position = pt1E;
|
|
setBG(); EmitVertex();
|
|
|
|
pt2E.xy = pt2.xy - dirv - bottomext * linev;
|
|
gl_Position = pt2E;
|
|
setBG(); EmitVertex();
|
|
EndPrimitive();
|
|
}
|
|
|
|
void main()
|
|
{
|
|
vec4 transformedCenter, transformedTarget;
|
|
vec2 textSizeInScreen, offset, drawVector;
|
|
float doNotDraw;
|
|
float connector_mode_0, connector_mode_1, connector_mode_2, connector_mode_3, connector_mode_4, connector_mode_2_4, drawBackgroundOutline, drawBackground, drawConnector, isProjected, zValue, zTarget;
|
|
lineEdge = 0.;
|
|
aaCutoff = 0.;
|
|
getDrawFlags(a_draw_flagsIn[0], connector_mode_0, connector_mode_1, connector_mode_2, connector_mode_3, connector_mode_4, drawBackgroundOutline, drawBackground, drawConnector);
|
|
|
|
float negLabelSize = step(textureToLabelSize, 0.);
|
|
float textureToLabelSizeA = abs(textureToLabelSize);
|
|
float extLength = (1.-negLabelSize) * a_rel_ext_lengthIn[0] + negLabelSize * (-a_rel_ext_lengthIn[0]/(screenOriginVertexScale*2.) );
|
|
vec2 textSize = a_textSizeIn[0] / textureToLabelSizeA;
|
|
connector_mode_2_4 = connector_mode_2 + connector_mode_4;
|
|
calculatePreConnectorInfo(a_center[0], a_target[0], textSize, a_indentFactorIn[0], a_screenWorldOffsetIn[0], transformedCenter, transformedTarget, textSizeInScreen, offset, drawVector, doNotDraw, a_relative_modeIn[0], isProjected, zValue, a_con_widthIn[0], zTarget);
|
|
vec4 endpointOnBBX, endpointExtendedOffBBX;
|
|
calculateConnectorInfo(a_center[0], textSizeInScreen, textSize, drawVector, offset, fog, transformedCenter, transformedTarget, endpointOnBBX, endpointExtendedOffBBX, connector_mode_0, connector_mode_1, connector_mode_2, connector_mode_3, connector_mode_4, extLength, isProjected, zValue);
|
|
NORMAL = vec3(0.,0.,1.);
|
|
|
|
// if the zValue is not within the clipping planes, then set the transformedTarget z
|
|
// to the zValue as well, to make sure that the connector doesn't get drawn
|
|
float withinView = step(zValue, 1.) * step(-1., zValue);
|
|
float ttz = (1.-zTarget) * (1.-isProjected); // not zTarget and not projected, then keep same, otherwise zValue
|
|
transformedTarget.z = ttz * transformedTarget.z + (1.-ttz) * zValue;
|
|
|
|
vec4 transformedPosition3 = transformedCenter;
|
|
transformedPosition3.xy += offset;
|
|
transformedPosition3.z = zValue;
|
|
// bbx of the label
|
|
vec4 upperLeft = transformedPosition3;
|
|
upperLeft.xy += textSizeInScreen * vec2(-1.,1.);
|
|
vec4 upperRight = transformedPosition3;
|
|
upperRight.xy += textSizeInScreen * vec2(1.,1.);
|
|
vec4 lowerLeft = transformedPosition3;
|
|
lowerLeft.xy += textSizeInScreen * vec2(-1.,-1.);
|
|
vec4 lowerRight = transformedPosition3;
|
|
lowerRight.xy += textSizeInScreen * vec2(1.,-1.);
|
|
|
|
lineSeg_t labelTop, labelBottom, labelLeft, labelRight;
|
|
|
|
labelTop.p1 = upperRight.xy;
|
|
labelTop.p2 = upperLeft.xy;
|
|
labelBottom.p1 = lowerLeft.xy;
|
|
labelBottom.p2 = lowerRight.xy;
|
|
labelRight.p1 = upperRight.xy;
|
|
labelRight.p2 = lowerRight.xy;
|
|
labelLeft.p1 = upperLeft.xy;
|
|
labelLeft.p2 = lowerLeft.xy;
|
|
|
|
if (drawBackgroundOutline + drawBackground > 0.){
|
|
if (drawBackground > 0.){
|
|
if (drawBackgroundOutline > 0.){
|
|
vec2 lineWidth = a_con_widthIn[0] / (screenSize);
|
|
vec4 upperLeftM = upperLeft + vec4(lineWidth.x, -lineWidth.y, 0., 0.),
|
|
upperRightM = upperRight + vec4(-lineWidth.x, -lineWidth.y, 0., 0.),
|
|
lowerLeftM = lowerLeft + vec4(lineWidth.x, lineWidth.y, 0., 0.),
|
|
lowerRightM = lowerRight + vec4(-lineWidth.x, lineWidth.y, 0., 0.);
|
|
|
|
COLOR = a_bkgrd_colorIn[0];
|
|
gl_Position = upperLeftM; setBG(); EmitVertex();
|
|
gl_Position = upperRightM; setBG(); EmitVertex();
|
|
gl_Position = lowerLeftM; setBG(); EmitVertex();
|
|
gl_Position = lowerRightM; setBG(); EmitVertex();
|
|
EndPrimitive();
|
|
} else {
|
|
COLOR = a_bkgrd_colorIn[0];
|
|
gl_Position = upperLeft; setBG(); EmitVertex();
|
|
gl_Position = upperRight; setBG(); EmitVertex();
|
|
gl_Position = lowerLeft; setBG(); EmitVertex();
|
|
gl_Position = lowerRight; setBG(); EmitVertex();
|
|
EndPrimitive();
|
|
}
|
|
}
|
|
if (drawBackgroundOutline > 0.){
|
|
COLOR = COLORIn[0];
|
|
drawLineAsGeometryWithOffsets(upperLeft, upperRight, 1., 0.);
|
|
drawLineAsGeometryWithOffsets(lowerRight, upperRight, 0., 1.);
|
|
drawLineAsGeometryWithOffsets(lowerLeft, lowerRight, 0., 1.);
|
|
drawLineAsGeometryWithOffsets(lowerLeft, upperLeft, 1., 0.);
|
|
}
|
|
}
|
|
if (drawConnector > 0 && doNotDraw == 0.){
|
|
COLOR = COLORIn[0];
|
|
float aa = min(1., 2./a_con_widthIn[0]);
|
|
float widthAdjustment = aa * a_con_widthIn[0];
|
|
float adjLineWidth = antialiasedLines * widthAdjustment + a_con_widthIn[0];
|
|
if (connector_mode_2_4 > 0.){
|
|
// create 2 lines, between transformedTarget -> endpointExtendedOffBBX, and endpointExtendedOffBBX -> endpointOnBBX
|
|
vec2 dirv1, dirv2;
|
|
drawLineAsGeometry(endpointExtendedOffBBX, endpointOnBBX, dirv2, a_con_widthIn[0], 0);
|
|
drawLineAsGeometry(transformedTarget, endpointExtendedOffBBX, dirv1, adjLineWidth, aa);
|
|
float norder = step(0., cross(vec3(dirv1.x, dirv1.y, 0.), vec3(dirv2.x, dirv2.y, 0.)).z);
|
|
// need to draw 'fan' that creates a curved elbow between the lines
|
|
|
|
lineEdge = 0.; aaCutoff = 0.;
|
|
gl_Position = endpointExtendedOffBBX;
|
|
setBG(); EmitVertex();
|
|
lineEdge = -1.; aaCutoff = aa;
|
|
if (norder < .5){
|
|
vec4 pt = endpointExtendedOffBBX;
|
|
pt.xy = endpointExtendedOffBBX.xy + dirv1;
|
|
gl_Position = pt;
|
|
setBG(); EmitVertex();
|
|
pt.xy = endpointExtendedOffBBX.xy + dirv2;
|
|
gl_Position = pt;
|
|
aaCutoff = 0.;
|
|
setBG(); EmitVertex();
|
|
} else {
|
|
vec4 pt = endpointExtendedOffBBX;
|
|
pt.xy = endpointExtendedOffBBX.xy - dirv2;
|
|
gl_Position = pt;
|
|
aaCutoff = 0.;
|
|
setBG(); EmitVertex();
|
|
pt.xy = endpointExtendedOffBBX.xy - dirv1;
|
|
gl_Position = pt;
|
|
aaCutoff = aa;
|
|
setBG(); EmitVertex();
|
|
}
|
|
EndPrimitive();
|
|
lineEdge = 0.; aaCutoff = 0.;
|
|
} else if (connector_mode_1 > 0. && drawBackground > 0.){
|
|
// create 1 lines, between transformedTarget -> endpointOnBBX
|
|
// replace endpointOnBBX with midpoint of midpoints
|
|
vec4 midULUR = (upperLeft + upperRight) / 2.0;
|
|
vec4 midLLLR = (lowerLeft + lowerRight) / 2.0;
|
|
vec4 midMid = (midULUR + midLLLR) / 2.0;
|
|
vec2 dirv;
|
|
drawLineAsGeometryClipped(transformedTarget, midMid, labelTop, labelBottom, labelLeft, labelRight, dirv, adjLineWidth, aa);
|
|
} else { //connector_mode 0 or 3, or connector_mode 1 without the background
|
|
vec2 dirv;
|
|
drawLineAsGeometry(transformedTarget, endpointOnBBX, dirv, adjLineWidth, aa);
|
|
}
|
|
}
|
|
}
|