#include webgl_header.vs


/* computeConnectorOffset : this function takes the drawVector and returns the offset of the
 * endpoint for the connector in the label's bbx coordinates
 */
//computeFinalCornerOrCenterOffset
vec2 computeConnectorOffset_0(vec2 drawVector){
//  this puts the endpoint at either the corners of the label, or in the center, based on the target relative to the label.

  // if target is closer than half label size, set to midpoint (in both directions)
  float hmid = step(abs(drawVector.x), .5); 
  float vmid = step(abs(drawVector.y), .5);

  // if not midpoint (hmid=0., vmid=0.), 
  //    set these variables to which side to draw based on the draw vector (in both directions)
  float right = (1.-hmid) * step(0., drawVector.x) + hmid * .5;
  float top = (1.-vmid) * step(0., drawVector.y) + vmid * .5;

  // normalize the offsets (either -1 or 1)
  float xoff = 2. * (right - .5), yoff = 2. * (top - .5);
  return vec2(xoff, yoff);
}

//computeFinalBBXOffset
vec2 computeConnectorOffset_1(vec2 drawVector){

  vec2 drawVectorN = normalize(drawVector);

  //   \ notabsyx /
  //     \      /
  //       \  /
  // absyx   \   absyx
  //      /     \
  //    / notabsyx \
  // absyx/notabsyx - specifies which area above in label coordinates
  float absyx = step(abs(drawVectorN.y), abs(drawVectorN.x));
  float notabsyx = 1. - absyx;

  // hdir/vdir : specifies which direction (in both axes), (-.5 or .5)
  float hdir = 2. * (step(0., drawVectorN.x) - .5);
  float vdir = 2. * (step(0., drawVectorN.y) - .5);

  float dvxy = drawVector.x / drawVector.y;
  float dvyx = drawVector.y / drawVector.x;
  // depending on which quadrant, the connector point is calculated
  return vec2(((absyx * hdir) + (notabsyx * vdir * dvxy)),
  	      ((notabsyx * vdir) + (absyx * hdir * dvyx)));
}

vec2 computeConnectorOffset_2(vec2 drawVector, out vec2 eoff, vec2 textSize, float extLength){
//  this puts the endpoint at either the corners of the label, or in the center, based on the target relative to the label.
  //    set these variables to which side to draw based on the draw vector (in both directions)
  float rightorig = step(0., drawVector.x);
  float ratio = abs(textSize.y/textSize.x);
  float right = rightorig + (rightorig - .5) * clamp(abs(drawVector.x)-1., 0., 2. * min(1., extLength * ratio));
  float top = step(0., drawVector.y);

  // normalize the offsets (either -1 or 1)
  float xofforig = 2. * (rightorig - .5), xoff = 2. * (right - .5), yoff = 2. * (top - .5);
  eoff = vec2(xoff, yoff);
  return vec2(xofforig, yoff);
}

vec2 computeConnectorOffset_3(vec2 drawVector){
//  this puts the endpoint at either the corners of the label, or in the center, based on the target relative to the label.

  // if target is inside label size, then set to drawVector value
  float hmid = step(abs(drawVector.x), 1.); 
  float vmid = step(abs(drawVector.y), 1.);

  // if not midpoint (hmid=0., vmid=0.), 
  //    set these variables to which side to draw based on the draw vector (in both directions)
  float right = (1.-hmid) * step(0., drawVector.x) + hmid * ((1. + drawVector.x) / 2.);
  float top = (1.-vmid) * step(0., drawVector.y) + vmid * ((1. + drawVector.y) / 2.);

  // normalize the offsets (either -1 or 1)
  float xoff = 2. * (right - .5), yoff = 2. * (top - .5);
  return vec2(xoff, yoff);
}

vec2 computeConnectorOffset_4(vec2 drawVector, out vec2 eoff, vec2 textSize, float extLength){
//  this puts the endpoint at either the corners of the label, or in the center, based on the target relative to the label.
  //    set these variables to which side to draw based on the draw vector (in both directions)
  float hmid = step(abs(drawVector.x), 1.); 
  float vmid = step(abs(drawVector.y), 1.);
  float rightorig = (1.-hmid) * step(0., drawVector.x) + hmid * ((1. + drawVector.x) / 2.);
  float ratio = abs(textSize.y/textSize.x);
  float right = rightorig + (1.-hmid) * (rightorig - .5) * clamp(abs(drawVector.x)-1., 0., 2. * min(1., extLength * ratio));
  float top = (1.-vmid) * step(0., drawVector.y) +
                vmid * ((1. + drawVector.y) / 2.);

  // normalize the offsets (either -1 or 1)
  float xofforig = 2. * (rightorig - .5), xoff = 2. * (right - .5), yoff = 2. * (top - .5);
  eoff = vec2(xoff, yoff);
  return vec2(xofforig, yoff);
}

vec2 computeCenterOffsetFromProjectedPoint(vec2 indentFactor, vec2 textSizeInScreen, vec2 screenWorldOffset){
     return (indentFactor * textSizeInScreen + screenWorldOffset/(screenSize*screenOriginVertexScale));
}

vec4 normalizeVec4(vec4 point){
   vec4 retPt = vec4(point.xyz/point.w, 1.);
   retPt.xy = ( floor(retPt.xy * screenSize + .5 ) + .5 ) / screenSize; // to match label rounding to middle of pixel
   return retPt;
}

float convertNormalZToScreenZ(float normalz){
   float a_centerN = (normalz + 1.) / 2.;
   float ptInPreProjectionZ = -(front + clipRange * a_centerN);
   vec4 ptInPreProjection = vec4(0., 0., ptInPreProjectionZ, 1.);
   vec4 projVect = g_ProjectionMatrix * ptInPreProjection;
   return projVect.z / projVect.w;
}

void calculatePreConnectorInfo(vec4 a_center, vec4 a_target, vec2 textSize, vec2 indentFactor, vec3 screenWorldOffset, out vec4 tCenter, out vec4 tTarget, out vec2 tsScreen, out vec2 offset, out vec2 dVector, out float doNotDraw, float a_relative_mode, out float isProjected, out float zValue, in float lineWidth, out float zTarget){
   vec3 viewVector = vec3(vec4(0., 0., -1., 0.) * g_ModelViewMatrix);
   tCenter = normalizeVec4(g_ProjectionMatrix * g_ModelViewMatrix * a_center);
   tTarget = normalizeVec4(g_ProjectionMatrix * g_ModelViewMatrix * a_target);
   vec4 a_centerp = (a_center + screenWorldOffset.z * vec4(viewVector, 0.));
   vec4 transformedPositionZ = normalizeVec4(g_ProjectionMatrix * g_ModelViewMatrix * a_centerp);  // use projected center point for z

   float isScreenCoord = step(2., mod(a_relative_mode, 4.));
   float isPixelCoord = step(4., mod(a_relative_mode, 8.));
   isProjected = step(isPixelCoord + isScreenCoord, 0.5);
   zTarget = step(8., mod(a_relative_mode, 16.));

   zValue = (1.-zTarget) * ((isProjected * transformedPositionZ.z) + (1.-isProjected) * convertNormalZToScreenZ(a_center.z) ) + zTarget * tTarget.z;

   // workaround for label and label_bg being at same z
   zValue += 1e-4;

   vec2 pixOffset = ((2. * a_center.xy / screenSize) - 1.);
   tCenter = isProjected * tCenter + isScreenCoord * a_center + isPixelCoord * vec4(pixOffset.x, pixOffset.y, -0.5, 0.); // only xy are used from tCenter
   tCenter.w = 1.;

   tsScreen = textSize / screenSize;
   offset = computeCenterOffsetFromProjectedPoint(indentFactor, tsScreen, screenWorldOffset.xy);
   dVector = (tTarget.xy - tCenter.xy - offset) / tsScreen;
   vec2 limit = 1.0 + .5 * lineWidth/textSize;
   doNotDraw = (1.-step(limit.x, abs(dVector.x)))  * (1.-step(limit.y, abs(dVector.y)));
}

void getDrawFlags(float drawFlags, out float connector_mode_0, out float connector_mode_1, out float connector_mode_2, out float connector_mode_3, out float connector_mode_4, out float drawBackgroundOutline, out float drawBackground, out float drawConnector){
	connector_mode_4 = step(64., mod(drawFlags, 128.));
	connector_mode_3 = step(32., mod(drawFlags, 64.));
	connector_mode_2 = step(16., mod(drawFlags, 32.));
	connector_mode_1 = step(8., mod(drawFlags, 16.));
	drawBackgroundOutline = step(4., mod(drawFlags, 8.));
	drawBackground = step(2., mod(drawFlags, 4.));
	drawConnector = step(1., mod(drawFlags, 2.));
	connector_mode_0 = 1. - step(0.5, connector_mode_1 + connector_mode_2 + connector_mode_3 + connector_mode_4);
}


void calculateConnectorInfo(vec4 a_center, vec2 tsScreen, vec2 textSize, vec2 dVector, vec2 offset, out float fog, in vec4 tCenter, in vec4 tTarget, out vec4 endpointOnBBX, out vec4 endpointExtendedOffBBX, float connector_mode_0, float connector_mode_1, float connector_mode_2, float connector_mode_3, float connector_mode_4, float extLength, float isProjected, float zValue){
  vec3 eye_pos = vec3(isProjected * (g_ModelViewMatrix * a_center) + ((1.-isProjected) * a_center));
  fog = (g_Fog_end - abs(eye_pos.z)) * g_Fog_scale;
  vec2 eoff;
  vec2 conOff;
  if (connector_mode_0 > 0.)
     conOff = computeConnectorOffset_0(dVector);
  else if (connector_mode_1 > 0.)
     conOff = computeConnectorOffset_1(dVector);
  else if (connector_mode_2 > 0.)
     conOff = computeConnectorOffset_2(dVector, eoff, textSize, extLength);
  else if (connector_mode_3 > 0.)
     conOff = computeConnectorOffset_3(dVector);
  else if (connector_mode_4 > 0.)
     conOff = computeConnectorOffset_4(dVector, eoff, textSize, extLength);

  vec2 addXY = offset + tsScreen * conOff;
  endpointOnBBX = tCenter;
  endpointOnBBX.xy = endpointOnBBX.xy + addXY;
  endpointOnBBX.z = zValue;
  endpointExtendedOffBBX = tCenter;
  endpointExtendedOffBBX.xy = endpointExtendedOffBBX.xy + offset + tsScreen * eoff;
  endpointExtendedOffBBX.z = zValue;
}
