Hosted by
|
with Messages; use Messages;
with Integer_Strings; use Integer_Strings;
with Real_Strings; use Real_Strings;
with Real_Vectors; use Real_Vectors;
with Gray_Images; use Gray_Images;
with Lines; use Lines;
with Glyphs; use Glyphs;
with Outlines; use Outlines;
with Intersections; use Intersections;
with Intersection_Heaps; use Intersection_Heaps;
package body Render_Glyphs is
type Heap_Array is array(Positive range <>) of Heap;
type Natural_Array is array(Positive range <>) of Natural;
function To_Pixel
(Y : in Real;
Zoom_Y : in Real;
Center_Y : in Positive;
Offset : in Real)
return Real is
begin
return Real(Center_Y) + Y * Zoom_Y + Offset;
end To_Pixel;
function To_Glyph
(Y : in Positive;
Zoom_Y : in Real;
Center_Y : in Positive;
Offset : in Real)
return Real is
begin
return (Real(Y - Center_Y) - Offset) / Zoom_Y;
end To_Glyph;
procedure Intersect
(This : access Glyph;
Zoom_X : in Real;
Zoom_Y : in Real;
Center_X : in Positive;
Center_Y : in Positive;
Offset : in Real;
Heaps : in out Heap_Array)
is
use Glyphs.Outline_Lists;
use Outlines.Line_Lists;
Outlines : Outline_List_Access;
Outline : Outline_Access;
Line : Line_Access;
P1, P2 : Vector;
Y1, Y2 : Integer;
Slope : Real;
Pixel_X : Real;
Real_X : Real;
Real_Y : Real;
White_To_Black : Boolean;
begin
Outlines := Get_Outlines(This);
Reset(Outlines);
while Next(Outlines) loop
Outline := Current(Outlines);
P2 := Last(Outline).To;
Reset(Outline);
while Next(Outline) loop
Line := Current(Outline);
P1 := P2;
P2 := Line.To;
if P1.Y /= P2.Y then
White_To_Black := P1.Y < P2.Y;
if White_To_Black then
Y1 := Greater(To_Pixel(P1.Y, Zoom_Y, Center_Y, Offset));
Y2 := Smaller_Or_Equal(To_Pixel(P2.Y, Zoom_Y, Center_Y, Offset));
else
Y1 := Greater(To_Pixel(P2.Y, Zoom_Y, Center_Y, Offset));
Y2 := Smaller_Or_Equal(To_Pixel(P1.Y, Zoom_Y, Center_Y, Offset));
end if;
if (P1.X = P2.X) then
Pixel_X := To_Pixel(P1.X, Zoom_X, Center_X, 0.0);
if Y1 < Heaps'First then Y1 := Heaps'First; end if;
if Y2 > Heaps'Last then Y2 := Heaps'Last; end if;
for Y in Y1 .. Y2 loop
Insert(Heaps(Y), (Pixel_X, White_To_Black));
end loop;
else
Slope := (P1.Y - P2.Y) / (P1.X - P2.X);
if Y1 < 1 then Y1 := 1; end if;
for Y in Y1 .. Y2 loop
Real_Y := To_Glyph(Y, Zoom_Y, Center_Y, Offset);
Real_X := Real(P1.X) + (Real_Y - P1.Y) / Slope;
Pixel_X := To_Pixel(Real_X, Zoom_X, Center_X, 0.0);
Insert(Heaps(Y), (Pixel_X, White_To_Black));
end loop;
end if;
end if;
end loop;
end loop;
end Intersect;
procedure Collect
(Anti_Alias : in Positive;
Heaps : in out Heap_Array;
Pixels : out Gray_Pixel_Array_2)
is
Black_Count : Integer;
Black_Start : Real;
Pixel_Black : Real;
use type Gray_Pixel;
Width : Positive := Pixels'Length(2);
Collected : Natural_Array(1 .. Width) := (others => 0);
procedure Fill_White
(L : in Real;
X : in out Positive) is
begin
if X <= Smaller_Or_Equal(L - 0.5) and X <= Pixels'Last(2) then
Collected(X) := Collected(X) +
Natural(255.0 * (1.0 - Pixel_Black));
Pixel_Black := 0.0;
X := X + 1;
end if;
while X <= Smaller_Or_Equal(L - 0.5) and X <= Pixels'Last(2) loop
Collected(X) := Collected(X) + 255;
X := X + 1;
end loop;
Black_Start := L;
end Fill_White;
procedure Fill_Black
(L : in Real;
X : in out Positive)
is
Black_Stop : Real;
begin
if L <= Real(X) + 0.5 then
Black_Stop := L;
Pixel_Black := Pixel_Black + Black_Stop - Black_Start;
else
Black_Stop := Real(X) + 0.5;
Pixel_Black := Pixel_Black + Black_Stop - Black_Start;
if X <= Smaller_Or_Equal(L - 0.5) and X <= Pixels'Last(2) then
if Pixel_Black < 1.0 then
Collected(X) := Collected(X) +
Natural(255.0 * (1.0 - Pixel_Black));
end if;
Pixel_Black := 0.0;
X := X + 1;
end if;
while X <= Smaller_Or_Equal(L - 0.5) and X <= Pixels'Last(2) loop
X := X + 1;
end loop;
Black_Start := Real(X) - 0.5;
Black_Stop := L;
Pixel_Black := Pixel_Black + Black_Stop - Black_Start;
end if;
end Fill_Black;
X : Positive;
Y : Positive;
I : Intersection;
begin
for Heaps_Y in Heaps'Range loop
Black_Count := 0;
Pixel_Black := 0.0;
X := Collected'First;
while Count(Heaps(Heaps_Y)) /= 0 loop
I := Extract(Heaps(Heaps_Y));
if not I.White_To_Black then
Black_Count := Black_Count + 1;
if Black_Count = 1 then Fill_White(I.X, X); end if;
else
if Black_Count = 1 then Fill_Black(I.X, X); end if;
Black_Count := Black_Count - 1;
end if;
exit when X > Pixels'Last(2);
end loop;
if X <= Pixels'Last(2) then
Fill_White(Real(Pixels'Last(2) + 2), X);
end if;
if Heaps_Y mod Anti_Alias = 0 then
Y := Heaps_Y / Anti_Alias;
for X in Collected'Range loop
Pixels(Y, X) := Gray_Pixel(Collected(X) / Anti_Alias);
Collected(X) := 0;
end loop;
end if;
end loop;
end Collect;
function Render
(This : access Glyph;
Staff_Height : in Real := 1.0;
Aspect_Ratio : in Real := 1.0;
Anti_Alias : in Positive := 1)
return Glyph_Image_Access
is
Result : Glyph_Image_Access :=
Bounds_To_Image(Get_Bounds(This), Staff_Height, Aspect_Ratio);
Heaps : Heap_Array(1 .. Result.Height * Anti_Alias);
begin
Intersect(This,
Staff_Height / 400.0 * Aspect_Ratio,
Staff_Height / 400.0 * Real(Anti_Alias),
Integer(Result.Center.X), Integer(Result.Center.Y) * Anti_Alias,
-Real(Anti_Alias - 1) / 2.0,
Heaps);
Collect(Anti_Alias, Heaps, Result.Pixels);
return Result;
end Render;
end Render_Glyphs;
|