Reputation: 26361
I've adapted Cinder library signed distance fonthandling to Delphi, and am now implementing a twist to upload all data for multiple texts in a single call, and to and to have some control over relative size when zooming (using an uniform instead of the 1.0001 factor in the geometry shader, not yet working in this code)
The basic signed distance handling is not altered, I only tried to calculate the needed rectangles using the geometry shader. I understand how to create the destination rectangle (where the character must appear) using triangle_strip, but are having problems passing the texcoord to the fragment shader.
destination rectangle : the input topleft.xy + widthheight (dimensions) is used to calculate the destination rectangle of each character on the screen. Using gl_position.
texture source rectangle 2: texcoordtl+texdimens, topleft point + dimensions for the character in the font texture. This is the main point where I'm unsure. Passed to fragment using texcoord in/out param.
I'd be grateful for any pointers or avenues to research and specially wonder about the way I calculate the texcoord coordinates and pass them on to the fragment shader.
An array of the below record is bound with GL_ARRAY_BUFFER and described using a series of glGetAttribLocation/glEnableVertexAttribArray/glVertexAttribPointer calls)
Drawing is done using
glDrawArrays(GL_POINTS, 0, numberofelements_in_array );
The record:
TGLCharacter = packed record // 5*2* single + 1*4 byte color + 1*4 byte detail. = 48 bytes per character drawn
origin : TGLVectorf2; // origin of text ( = glfloat[2])
topleft : TGLVectorf2; // origin of this character
widthheight: TGLVectorf2; // width and heght this chracter
texcoordtl : TGLVectorf2; // coordinates topleft in texture.
texdimens : TGLVectorf2; // sizes in texture
col : TGLVectorub4; // 4 colors, 1 per rect vertex
detail : integer; // layer. Not used in this example.
end;
geometry code first because I expect the problems here:
#version 150 compatibility
layout(points) in;
layout(triangle_strip, max_vertices = 4) out;
in vec2 gorigin[];
in vec2 gtopleft[];
in vec2 gwidthheight[];
in vec2 gtexcoordtl[];
in vec2 gtexdimens[];
in vec4 gcolor[];
out vec3 fColor;
out vec2 texcoord;
void main() {
// calculate distance cur char - first char of this text
vec2 dxcoordinate = (gtopleft[0]-gorigin[0]);
// now multiply with uniform here and calc new coordinate:
// for now we use uniform slightly close to 1 to make debugging easier and avoid
// nvidia's shadercompiler to optimize gorigin out.
// equal to 1, and the nvidia shader optimizes it out.
vec2 x1y1 = 1.0001*gorigin[0]+dxcoordinate;
vec2 x2y2 = x1y1+gwidthheight[0]*1.0001;
vec2 texx1y1 = gtexcoordtl[0];
vec2 texx2y2 = gtexcoordtl[0]+gtexdimens[0];
fColor = vec3(gcolor[0].rgb);
gl_Position = gl_ModelViewProjectionMatrix * vec4(x1y1,0,1.0);
texcoord = texx1y1.xy;
EmitVertex();
gl_Position = gl_ModelViewProjectionMatrix * vec4(x2y2.x,x1y1.y,0,1.0);
texcoord = vec2(texx2y2.x,texx1y1.y);
EmitVertex();
gl_Position= gl_ModelViewProjectionMatrix * vec4(x1y1.x,x2y2.y,0,1.0);
texcoord = vec2(texx1y1.x,texx2y2.y);
EmitVertex();
gl_Position = gl_ModelViewProjectionMatrix * vec4(x2y2,0,1.0);
texcoord = texx2y2.xy;
EmitVertex();
EndPrimitive();
}
frag code:
#version 150 compatibility
uniform sampler2D font_map;
uniform float smoothness;
const float gamma = 2.2;
in vec3 fColor;
in vec2 texcoord;
void main()
{
// retrieve signed distance
float sdf = texture2D( font_map, texcoord.xy ).r;
// perform adaptive anti-aliasing of the edges
float w = clamp( smoothness * (abs(dFdx(texcoord.x)) + abs(dFdy(texcoord.y))), 0.0, 0.5);
float a = smoothstep(0.5-w, 0.5+w, sdf);
// gamma correction for linear attenuation
a = pow(a, 1.0/gamma);
if (a<0.1)
discard;
// final color
gl_FragColor.rgb = fColor.rgb;
gl_FragColor.a = gl_Color.a * a;
}
vertex code is probably ok I guess.
#version 150 compatibility
in vec2 anorigin;
in vec2 topleft;
in vec2 widthheight;
in vec2 texcoordtl;
in vec2 texdimens;
in vec4 color;
out vec2 gorigin;
out vec2 gtopleft;
out vec2 gwidthheight;
out vec2 gtexcoordtl;
out vec2 gtexdimens;
out vec4 gcolor;
void main()
{
gorigin=anorigin;
gtopleft=topleft;
gwidthheight=widthheight;
gtexcoordtl=texcoordtl;
gtexdimens=texdimens;
gcolor=color;
gl_Position = gl_ModelViewProjectionMatrix * vec4(anorigin.xy,0,1.0);;
}
Upvotes: 3
Views: 266
Reputation: 26361
The above code works. The problem was in the uploading code, so wrong vertex data was uploaded. I did some minor fixes to the above code while debugging and added it to the question, so that the question now shows working code.
Here is some possible code that changes the last 2 lines of the frag shader to create outline fonts. I'm not really happy yet with it though. When zooming out the color of the font seems to change
vec3 othercol; // to be added to declarations
.. rest shader below the discard statement becomes:
othercol=vec3(1.0,1.0,1.0);
if (sqrt(0.299 * fColor.r*fColor.r + 0.587 * fColor.g*fColor.g + 0.114 * fColor.b*fColor.b)>0.5)
{ othercol=vec3(0,0,0);}
// final color
if (sdf>0.25 && sdf<0.75)
{gl_FragColor.rgb = othercol.rgb;}
else
{gl_FragColor.rgb = fColor.rgb;}
gl_FragColor.a = gl_Color.a * a;
}
Upvotes: 1