(too long; didn't fit)
Code:
//replacement for GL_LINE_STRIP used in GUI everywhere
procedure TDumbUniMesh.AddLine(c: array of const; width: float);
begin
GenerateLineMesh(ParseAOCToVector2f(c), width, false);
end;
procedure TDumbUniMesh.AddLineLoop(c: array of const; width: float);
begin
GenerateLineMesh(ParseAOCToVector2f(c), width, true);
end;
procedure TDumbUniMesh.AddLine(points: array of TVector2f; width: float);
begin
GenerateLineMesh(points, width, false);
end;
procedure TDumbUniMesh.AddLineLoop(points: array of TVector2f; width: float);
begin
GenerateLineMesh(points, width, true);
end;
function TDumbUniMesh.ParseAOCToVector2f(var c: array of const): TVector2fArray;
var
i, k, n: integer;
v: float;
begin
if (Length(c) mod 2) <> 0 then Die(MI_ERROR_PROGRAMMER_NO_BAKA, [
'Odd number of parameters passed to TDumbLineMesh.AddLine']);
SetLength(Result, Length(c) div 2);
n:= 0;
k:= 0;
for i:= 0 to High(c) do begin
case c[i].Vtype of
vtInteger: v:= c[i].VInteger;
vtExtended: v:= c[i].VExtended^;
else
Die(MI_ERROR_PROGRAMMER_NO_BAKA,
['Wrong parameter type passed to TDumbUniMesh.AddLine, Vtype='
+ IntToStr(c[i].Vtype)]);
end;
Result[n][k]:= v;
k:= 1 - k;
if k = 0 then Inc(n);
end;
end;
procedure TDumbUniMesh.SetLineTexCoords(a, b: TVector2f; _repeat: boolean); overload;
begin
lineTC[0]:= a;
lineTC[1]:= b - a;
lineTCrepeat:= _repeat;
end;
procedure TDumbUniMesh.SetLineTexCoords; // default glyph from | character in the font
var pv4: PVector4f;
begin
pv4:= @Mother^.Text.BuiltinFont[Mother^.Text.FixedFontQuality].GlyphTexCoords^[bifgglyph_Pipe];
lineTC[0][0]:= pv4^[0];
lineTC[0][1]:= pv4^[1];
lineTC[1][0]:= pv4^[2] - pv4^[0];
lineTC[1][1]:= pv4^[3] - pv4^[1];
lineTCrepeat:= true;
end;
procedure TDumbUniMesh.GenerateLineMesh(points: array of TVector2f;
width: float; loop: boolean);
var
vectors, //vector goes from i to point i + 1
rightnormals, conormals, // normal goes clockwise in my GUI
// coordinate system (X axis goes right, Y axis goes down from the top left
// screen corner, which is NOT how GL usually is set up)
v, //vertex buffer. Calculate in 2df before copying to real vertices field
tc //texcoords.
: array of TVector2f;
idx: array of integer; //index buffer. To be copied to the real indices.
connect, degenerate: array of boolean;//the segment i connects smoothly with segment i - 1
i, j, a, b, c, numConnections, startInd, startVert, curV, curI: integer;
anglecosine, veclen, confrac, ffrac: float;
begin
if Length(points) < 2 then Die(MI_ERROR_PROGRAMMER_NO_BAKA,
['Not enough points passed to TDumbUniMesh.GenerateLineMesh']);
if loop then j:= length(points) else j:= length(points) - 1;
SetLength(vectors, j);
SetLength(rightnormals, j);
SetLength(conormals, j);
SetLength(connect, j);
SetLength(degenerate, j);
for i:= 0 to length(points) - 2 do
vectors[i]:= points[i + 1] - points[i];
if loop then
vectors[j - 1]:= points[0] - points[High(points)];
for i:= 0 to High(vectors) do begin
rightnormals[i][0]:= - vectors[i][1]; // points clockwise 90 deg from the vector
rightnormals[i][1]:= vectors[i][0];
QuickNormalize(rightnormals[i]);
ffrac:= FastInverseSquareRoot(sqr(vectors[i][0]) + sqr(vectors[i][1]));
conormals[i]:= vectors[i] * ffrac;
degenerate[i]:= ffrac > (1 / width);
end;
numConnections:= 0;
if loop then a:= 0
else begin
a:= 1;
connect[0]:= false;
end;
for i:= a to j - 1 do begin
if i = 0 then b:= j - 1 else b:= i - 1;
//connect *only* if angle is less that 90 degrees !
//otherwise render as separate (overlapping) segments
anglecosine:= DotProduct(rightnormals[b], rightnormals[i]);
connect[i]:= (anglecosine >= 0) and not degenerate[i] and not degenerate[b];
if connect[i] then inc(numConnections);
end;
width*= 0.5;
//finally generate the mesh
startInd:= MaxIndex + 1;
curI:= 0;
SetLength(idx, (2 * 3 * j) + (4 * 3 * numConnections));
//addlog('i/i %0/%1 %2 %3 %4 ',[curI, length(idx), j, numConnections, connect[0]]);
startVert:= MaxVertex + 1;
curV:= 0;
SetLength(v, (4 * j) + (1 * numConnections));
if renc_Texcoord in components then begin
SetLength(tc, Length(v));
end;
for i:= 0 to j - 1 do begin
if i = (j - 1)
then a:= 0 //next point index
else a:= i + 1;
if connect[i] or connect[a]
then confrac:= 0.5 * ( 2 * width / QuickLength(vectors[i]));
if connect[i] then begin
//adding the 4 triangles of the connection
if i > 0
then c:= curV //vertices added by the previous segment
else c:= length(v); //vertices that *will* be added by the last segment
// It's a good thing our algorithm is 100% predictable, isn't it?
idx[curI + 0]:= (* CurV - 1;
Так вот где таилась погибель моя!
Мне смертию кость угрожала!
Из мёртвой главы Access Violation in ig4icd32.dll,
Шипя, между тем, выползало *) c - 1;
idx[curI + 1]:= c - 3;
idx[curI + 2]:= CurV + 0 ;
idx[curI + 3]:= CurV + 1;
idx[curI + 4]:= c - 2;
idx[curI + 5]:= c - 1;
idx[curI + 6]:= CurV + 0;
idx[curI + 7]:= CurV + 1;
idx[curI + 8]:= c - 1;
idx[curI + 9]:= c - 1;
idx[curI +10]:= c - 2;
idx[curI +11]:= c - 3;
inc(curI, 12);
v[curV + 0]:= points[i] + ((conormals[i] - rightnormals[i]) * width);
v[curV + 1]:= points[i] + ((conormals[i] + rightnormals[i]) * width);
if renc_Texcoord in components then begin
tc[curV + 0]:= lineTC[0] + lineTC[1] * ToVector2f(0, confrac);
tc[curV + 1]:= lineTC[0] + lineTC[1] * ToVector2f(1, confrac);
end;
end
else begin
v[curV + 0]:= points[i] - (rightnormals[i] * width);
v[curV + 1]:= points[i] + (rightnormals[i] * width);
if renc_Texcoord in components then begin
tc[curV + 0]:= lineTC[0];
tc[curV + 1]:= lineTC[0]+ lineTC[1] * ToVector2f(1, 0);
end;
end;
idx[curI + 0]:= curV + 1; //1st body triangle
idx[curI + 1]:= curV + 0;
idx[curI + 2]:= curV + 2;
idx[curI + 3]:= curV + 2; //2nd body triangle
idx[curI + 4]:= curV + 3;
idx[curI + 5]:= curV + 1;
inc(curI, 6);
if connect[a] then begin
v[curV + 2]:= points[a] - ((conormals[i] + rightnormals[i]) * width);
v[curV + 3]:= points[a] - ((conormals[i] - rightnormals[i]) * width);
if renc_Texcoord in components then begin
tc[curV + 2]:= lineTC[0] + lineTC[1] * ToVector2f(0, 1 - confrac);
tc[curV + 3]:= lineTC[0] + lineTC[1] * ToVector2f(1, 1 - confrac);
end;
//middle vertex
v[curV + 4]:= points[a] + (conormals[a] - conormals[i]) * width * 0.5;
if renc_Texcoord in components then begin
tc[curV + 4]:= lineTC[0] + lineTC[1] * ToVector2f(0.5, 1);
end;
inc(curV, 5);
end
else begin
v[curV + 2]:= points[a] - (rightnormals[i] * width);
v[curV + 3]:= points[a] + (rightnormals[i] * width);
if renc_Texcoord in components then begin
tc[curV + 2]:= lineTC[0] + lineTC[1] * ToVector2f(0, 1);
tc[curV + 3]:= lineTC[0] + lineTC[1] * ToVector2f(1, 1);
end;
inc(curV, 4);
end;
end;
inc (MaxIndex, Length(idx));
inc (MaxVertex, Length(v));
EnlargeBuffersIfNecessary;
for i:= 0 to High(idx) do begin
indices[startInd + i]:= startVert + idx[i];
end;
ffrac:= 1 / High(v);
for i:= 0 to High(v) do begin
vertices[startVert + i]:= v[i];
if renc_Texcoord in components
then texcoords[startVert + i]:= tc[i];
if renc_Normal in components
then normals[startVert + i]:= currentNormal;
if renc_Texcoord in components
then colors[startVert + i]:= currentColor + lineGrad * (i * ffrac);
end;
end;
procedure TDumbUniMesh.SetLineGradientTo(c: TVector4f);
begin
lineGrad:= c - currentColor;
end;
.. and usage (converted my old uber-crappy code to this less-crappy abstraction layer):
Code:
Mesh:= TDumbUniMesh.Create;
Mesh.Color4f(
f * Mother^.Display.FadeIn, f * Mother^.Display.FadeIn, f * Mother^.Display.FadeIn, 1);
Mesh.AddQuad2d(
0, 0, Mother^.Display.ClientRect.Width, Mother^.Display.ClientRect.Height,
0, 0, 1, 1);
TGAPI.SetGLStatesForGUI;
case Mother^.GAPI.Mode of
{$ifndef glesonly}
gapi_GL21 : begin
glDisable(GL_ALPHA_TEST);
end;
{$endif glesonly}
gapi_GLES2: begin
end;
else
DieUnsupportedGLMode;
end;
//f_current_bgtex
//f_current_bgw
//f_current_bgh
glDisable(GL_BLEND);
//glEnable(GL_TEXTURE_2D);
if Mother^.Display.Background.custom = 0
then glBindTexture(GL_TEXTURE_2D, f_bgtex[Mother^.Display.Background._default])
else glBindTexture(GL_TEXTURE_2D, Mother^.Display.Background.custom);
Mesh.Render;
Mesh.Free;
{
glColor4f(f * Mother^.Display.FadeIn, f * Mother^.Display.FadeIn, f * Mother^.Display.FadeIn, 1);
glBindTexture(GL_TEXTURE_2D, f_bgtex);
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(0, 0); //bottom left corner
glTexCoord2f(0, 1);
glVertex2f(0, Mother^.Display.WindowClientRect.Height);
glTexCoord2f(1, 1);
glVertex2f(Mother^.Display.WindowClientRect.Width, Mother^.Display.WindowClientRect.Height);
glTexCoord2f(1, 0);
glVertex2f(Mother^.Display.WindowClientRect.Width, 0);
glEnd;
glEnable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
}
Bookmarks