C2Tess2D.pas
上传用户:yj_qiu
上传日期:2022-08-08
资源大小:23636k
文件大小:16k
源码类别:

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(CAST II Engine 2D tesselation unit)
  3.  (C) 2006 George "Mirage" Bakhtadze. <a href="http://www.casteng.com">www.casteng.com</a> <br>
  4.  The source code may be used under either MPL 1.1 or LGPL 2.1 license. See included license.txt file <br>
  5.  The unit contains 2D tesselator classes
  6. *)
  7. // ToFix: Remove unneeded data from vertex formats
  8. {$Include GDefines.inc}
  9. {$Include C2Defines.inc}
  10. unit C2Tess2D;
  11. interface
  12. uses
  13.   {$IFDEF LOGGING}
  14.   TextFile,
  15.   {$ENDIF}
  16.   BaseTypes, C2Types, C2Visual, CAST2, BaseGraph;
  17. const
  18.   MaxColorStack = 15;
  19.   PointsGrowStep = 1; LinesGrowStep = 1;
  20. // Alignment
  21.   amLeft = 0; amCenter = 1; amRight = 2;
  22. type
  23.   TPPoint = packed record X, Y, Z, U, V: Single; Color: BaseTypes.TColor; end;
  24.   TLineMesh = class(TSharedTesselator)
  25.     constructor Create; override;
  26.     procedure AddPoint(const X, Y: Single; const Color: BaseTypes.TColor);
  27.     procedure Clear; override;
  28.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; override;
  29.     destructor Destroy; override;
  30.   protected
  31.     Points: array of TPPoint; TotalPoints: Integer;
  32.   end;
  33.   TTetragonMesh = class(TSharedTesselator)
  34.     constructor Create; override;
  35.     procedure AddPoint(X, Y, U, V: Single; Color: BaseTypes.TColor);
  36.     procedure AddCorner(X, Y, U, V: Single; Color: BaseTypes.TColor);
  37.     procedure Clear; override;
  38.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; override;
  39.     function SetIndices(IBPTR: Pointer): Integer; override;
  40.   protected
  41.     Points: array of TPPoint; TotalPoints: Integer;
  42.   end;
  43.   TTextLine = record
  44.     Text: string;
  45.     Color: BaseTypes.TColor;
  46.     X, Y, Z: Single;
  47.     Font: BaseGraph.TBaseBitmapFont;
  48.     Viewport: BaseGraph.TViewport;
  49.     Transform: BaseGraph.T2DTransform;
  50.   end;
  51.   TTextMesh = class(TSharedTesselator)
  52.     constructor Create; override;
  53.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; override;
  54.     procedure SetFont(const AFont: TFont; ATextSizeX, ATextSizeY: Single);
  55.     procedure AddText(const AX, AY: Single; const Color: BaseTypes.TColor; const NewText: string); virtual;
  56.     procedure Clear; override;
  57.   protected
  58.     Lines: array of TTextLine;
  59.     TotalLines: Integer;
  60. // Current text parameters
  61.     Font: TFont;
  62.     procedure AddLine(const AX, AY: Single; const Color: BaseTypes.TColor; const NewText: string);
  63.   end;
  64. implementation
  65. function ClipBar(var X1, Y1, U1, V1: Single; var X2, Y2, U2, V2: Single): Boolean;
  66. var VPLeft, VPTop, VPRight, VPBottom: Single;
  67.   function GetCode(X, Y: Single): Integer;
  68.   begin
  69.     Result := Ord(X < VPLeft)       or Ord(X > VPRight)  shl 1 or
  70.               Ord(Y < VPTop)  shl 2 or Ord(Y > VPBottom) shl 3;
  71.   end;
  72. var ts: Single;
  73. begin
  74.   VPLeft   := Screen.Viewport.Left;
  75.   VPTop    := Screen.Viewport.Top;
  76.   VPRight  := Screen.Viewport.Right;
  77.   VPBottom := Screen.Viewport.Bottom;
  78.   if X1 > X2 then begin
  79.     ts := X1; X1 := X2; X2 := ts;
  80.     ts := U1; U1 := U2; U2 := ts;
  81.   end;
  82.   if Y1 > Y2 then begin
  83.     ts := Y1; Y1 := Y2; Y2 := ts;
  84.     ts := V1; V1 := V2; V2 := ts;
  85.   end;
  86.   Result := False;                                                // Completely invisible cases
  87.   if (X2 < VPLeft) or (X1 > VPRight) or (Y2 < VPTop) or (Y1 > VPBottom) then Exit;
  88.   Result := True;
  89.   if X1 < VPLeft then begin
  90.     U1 := U1 + (U2-U1)/(X2-X1) * (VPLeft - X1);
  91.     X1 := VPLeft;
  92.   end;
  93.   if X2 > VPRight then begin
  94.     U2 := U2 + (U2-U1)/(X2-X1) * (VPRight - X2);
  95.     X2 := VPRight;
  96.   end;
  97.   if Y1 < VPTop then begin
  98.     V1 := V1 + (V2-V1)/(Y2-Y1) * (VPTop - Y1);
  99.     Y1 := VPTop;
  100.   end;
  101.   if Y2 > VPBottom then begin
  102.     V2 := V2 + (V2-V1)/(Y2-Y1) * (VPBottom - Y2);
  103.     Y2 := VPBottom;
  104.   end;
  105. end;
  106. { TLineMesh }
  107. constructor TLineMesh.Create;
  108. begin
  109.   inherited;
  110.   TotalPoints := 0;
  111.   PrimitiveType := ptLINELIST;
  112.   VertexFormat  := GetVertexFormat(True, False, True, False, False, 0, [2]);
  113.   TesselationStatus[tbVertex].TesselatorType := ttDynamic;
  114.   TesselationStatus[tbIndex].TesselatorType  := ttDynamic;
  115. end;
  116. procedure TLineMesh.AddPoint(const X, Y: Single; const Color: BaseTypes.TColor);
  117. var t: Single;
  118. begin
  119.   if Length(Points) <= TotalPoints then SetLength(Points, Length(Points) + PointsGrowStep);
  120.   Points[TotalPoints].X := X; Points[TotalPoints].Y := Y;
  121.   Points[TotalPoints].Z := Screen.CurrentZ;
  122.   Points[TotalPoints].Color := Color;
  123.   if Odd(TotalPoints) then begin                                 // Line completed
  124.     if ClipLineColorTex(Points[TotalPoints-1].X, Points[TotalPoints-1].Y, t, t, Points[TotalPoints-1].Color,
  125.                         Points[TotalPoints].X,   Points[TotalPoints].Y,   t, t, Points[TotalPoints].Color,
  126.                         Screen.Viewport.Left, Screen.Viewport.Top, Screen.Viewport.Right, Screen.Viewport.Bottom) then begin
  127.       Screen.TransformPoint(Points[TotalPoints-1].X, Points[TotalPoints-1].Y);
  128.       Screen.TransformPoint(Points[TotalPoints].X,   Points[TotalPoints].Y);
  129.       Inc(TotalPoints);
  130.     end else Dec(TotalPoints);
  131.   end else Inc(TotalPoints);
  132.   TotalVertices := TotalPoints;
  133.   Invalidate([tbVertex, tbIndex], True);
  134. end;
  135. function TLineMesh.Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer;
  136. var i: Integer;
  137. begin
  138.   Assert(TotalPoints mod 2 = 0, ClassName + '.Tesselate: TotalPoints should be divisible by 4');
  139.   TotalPrimitives := TotalPoints div 2;
  140.   for i := 0 to TotalPoints-1 do begin
  141.     SetVertexDataCRHW(Points[i].X, Points[i].Y, Points[i].Z, 1/0.1, i, VBPTR);
  142.     SetVertexDataD(Points[i].Color, i, VBPTR);
  143.     SetVertexDataUV(0, 0, i, VBPTR);
  144.   end;
  145.   TesselationStatus[tbVertex].Status := tsTesselated;
  146.   LastTotalVertices := TotalVertices;
  147.   Result            := TotalVertices;
  148. end;
  149. procedure TLineMesh.Clear;
  150. begin
  151.   TotalPoints   := 0;
  152.   TotalVertices := TotalPoints;
  153. end;
  154. destructor TLineMesh.Destroy;
  155. begin
  156.   Clear;
  157.   Points :=nil;
  158.   inherited;
  159. end;
  160. { TTetragonMesh }
  161. constructor TTetragonMesh.Create;
  162. begin
  163.   inherited;
  164.   PrimitiveType := ptTRIANGLELIST;
  165.   VertexFormat  := GetVertexFormat(True, False, True, False, False, 0, [2]);
  166.   TotalVertices := 0; TotalIndices := 0; TotalPrimitives := 0;
  167.   TesselationStatus[tbVertex].TesselatorType := ttDynamic;
  168.   TesselationStatus[tbIndex].TesselatorType  := ttDynamic;
  169. end;
  170. procedure TTetragonMesh.AddPoint(X, Y, U, V: Single; Color: BaseTypes.TColor);
  171. begin
  172.   if Length(Points) <= TotalPoints then SetLength(Points, Length(Points) + PointsGrowStep);
  173.   Points[TotalPoints].X := X;
  174.   Points[TotalPoints].Y := Y;
  175. //  Screen.TransformPoint(Points[TotalPoints].X, Points[TotalPoints].Y);
  176.   Points[TotalPoints].Z := Screen.CurrentZ;
  177.   Points[TotalPoints].U := U;
  178.   Points[TotalPoints].V := V;
  179.   Points[TotalPoints].Color := Color;
  180.   Inc(TotalPoints);
  181.   TotalVertices    := TotalPoints;
  182.   TotalIndices     := (TotalPoints * 6) shr 2;
  183.   IndexingVertices := TotalVertices;
  184.   Invalidate([tbVertex, tbIndex], True);
  185. end;
  186. procedure TTetragonMesh.AddCorner(X, Y, U, V: Single; Color: BaseTypes.TColor);
  187. var CX, CY: Single;
  188. begin
  189.   if Odd(TotalPoints) then begin
  190.     if ClipBar(Points[TotalPoints-1].X, Points[TotalPoints-1].Y,
  191.                Points[TotalPoints-1].U, Points[TotalPoints-1].V, 
  192.                X, Y, U, V) then begin
  193.       CX := X; CY := Points[TotalPoints-1].Y;
  194.       Screen.TransformPoint(CX, CY);
  195.       AddPoint(CX, CY, U, Points[TotalPoints-1].V, Color);
  196.       CX := X; CY := Y;
  197.       Screen.TransformPoint(CX, CY);
  198.       AddPoint(CX, CY, U, V, Color);
  199.       CX := Points[TotalPoints-3].X; CY := Y;
  200.       Screen.TransformPoint(CX, CY);
  201.       AddPoint(CX, CY, Points[TotalPoints-3].U, V, Color);
  202.       Screen.TransformPoint(Points[TotalPoints-4].X, Points[TotalPoints-4].Y);
  203.     end else Dec(TotalPoints);
  204.   end else AddPoint(X, Y, U, V, Color);
  205. end;
  206. procedure TTetragonMesh.Clear;
  207. begin
  208.   TotalPoints := 0;
  209.   TotalVertices    := TotalPoints;
  210.   TotalIndices     := TotalPoints;
  211.   IndexingVertices := TotalVertices;
  212. end;
  213. function TTetragonMesh.Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer;
  214. var i: Integer;
  215. begin
  216.   Assert(TotalPoints mod 4 = 0, ClassName + '.Tesselate: TotalPoints should be divisible by 4');
  217.   TotalPrimitives := TotalPoints div 2;
  218.   for i := 0 to TotalPoints-1 do begin
  219. //  for i := TotalPoints-1 downto 0 do begin
  220.     SetVertexDataCRHW(Points[i].X, Points[i].Y, Points[i].Z, 1/0.1, i, VBPTR);
  221.     SetVertexDataD(Points[i].Color, i, VBPTR);
  222.     SetVertexDataUV(Points[i].U, Points[i].V, i, VBPTR);
  223.   end;
  224.   TesselationStatus[tbVertex].Status := tsTesselated;
  225.   LastTotalVertices := TotalVertices;
  226.   Result            := TotalVertices;
  227. end;
  228. function TTetragonMesh.SetIndices(IBPTR: Pointer): Integer;
  229. var i, Index: Integer;
  230. begin
  231.   Index := 0;
  232.   for i := 0 to TotalPoints shr 2-1 do begin
  233.     TWordBuffer(IBPTR^)[Index]   := i*4;
  234.     TWordBuffer(IBPTR^)[Index+1] := i*4+1;
  235.     TWordBuffer(IBPTR^)[Index+2] := i*4+2;
  236.     TWordBuffer(IBPTR^)[Index+3] := i*4;
  237.     TWordBuffer(IBPTR^)[Index+4] := i*4+2;
  238.     TWordBuffer(IBPTR^)[Index+5] := i*4+3;
  239.     Inc(Index, 6);
  240.   end;
  241.   TesselationStatus[tbIndex].Status := tsTesselated;
  242.   LastTotalIndices := TotalIndices;
  243.   Result           := TotalIndices;
  244. end;
  245. { TTextTesselator }
  246. constructor TTextMesh.Create;
  247. begin
  248.   inherited;
  249. //  PrimitiveType := ptTRIANGLESTRIP;
  250.   VertexFormat  := GetVertexFormat(True, False, True, False, False, 0, [2]);
  251.   TesselationStatus[tbVertex].TesselatorType := ttDynamic;
  252.   TesselationStatus[tbIndex].TesselatorType  := ttDynamic;
  253.   Clear;
  254.   Font := nil;
  255. end;
  256. procedure TTextMesh.SetFont(const AFont: TFont; ATextSizeX, ATextSizeY: Single);
  257. begin
  258.   Font := AFont;
  259. end;
  260. procedure TTextMesh.AddText(const AX, AY: Single; const Color: BaseTypes.TColor; const NewText: string);
  261. var StrLen: Integer;
  262. begin
  263.   if NewText = '' then Exit;
  264.   if not (Font is BaseGraph.TBaseBitmapFont) then begin
  265.     {$IFDEF LOGGING} Log.Log(ClassName + '.AddText: Font is undefined', lkError); {$ENDIF}
  266.     Exit;
  267.   end;
  268.   AddLine(AX, AY, Color, NewText);
  269.   StrLen := Length(NewText);
  270.   Inc(TotalVertices, StrLen * 6);
  271.   Inc(TotalPrimitives, StrLen * 2);
  272.   if (TotalVertices = LastTotalVertices) and (TesselationStatus[tbVertex].Status = tsTesselated) then
  273.     Invalidate([tbVertex, tbIndex], False) else
  274.       Invalidate([tbVertex, tbIndex], True);
  275. end;
  276. function TTextMesh.Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer;
  277. var
  278.   i, j, Index: Integer;
  279.   X, Y, CurX, CurY, CurZ, AddY, UVecX, UVecY, VVecX, VVecY, t: Single;
  280.   Coord: TUV;
  281. //  X1, Y1, X2, Y2, U1, V1, U2, V2: Single;
  282. begin
  283. //  Assert((UVMap <> nil) and (CharMap <> nil), 'TTextMesh.Tesselate: One of the maps is nil');
  284.   TotalVertices   := 0;
  285.   TotalPrimitives := 0;
  286.   Index := 0;
  287.   for j := 0 to TotalLines-1 do begin
  288.     CurZ := Lines[j].Z;
  289.     X := Lines[j].X; Y := Lines[j].Y;
  290.     CurX := X; CurY := Y;
  291.     Screen.TransformPointWith(Lines[j].Transform, CurX, CurY);
  292.     CurX := CurX - 0.5;
  293.     if (Y < Lines[j].Viewport.Bottom) then begin
  294.       UVecX := Lines[j].Font.XScale;
  295.       UVecY := 0;
  296.       Screen.RotateScalePointWith(Lines[j].Transform, UVecX, UVecY);
  297.       VVecX := 0;
  298.       VVecY := Lines[j].Font.YScale;
  299.       Screen.RotateScalePointWith(Lines[j].Transform, VVecX, VVecY);
  300.       for i := 0 to Length(Lines[j].Text)-1 do if (X < Lines[j].Viewport.Right) then begin
  301.         Coord := Lines[j].Font.UVMap^[Lines[j].Font.CharMap^[Ord(Lines[j].Text[i+1])]];
  302.         if X + Coord.W * Lines[j].Font.XScale > Lines[j].Viewport.Right then
  303.           Coord.W := Coord.W * (1 - (X + Coord.W * Lines[j].Font.XScale - (Lines[j].Viewport.Right)) / (Coord.W * Lines[j].Font.XScale));
  304.         if Y + Coord.H * Lines[j].Font.YScale > Lines[j].Viewport.Bottom then
  305.           Coord.H := Coord.H * (1 - (Y + Coord.H * Lines[j].Font.YScale - (Lines[j].Viewport.Bottom)) / (Coord.H * Lines[j].Font.YScale));
  306.         t := 0;
  307.         if X < Lines[j].Viewport.Left then begin
  308.           t := (Lines[j].Viewport.Left - X) / (Coord.W * Lines[j].Font.XScale);
  309.           if t < 1 then begin
  310.             CurX := CurX + UVecX * Coord.W * t;
  311. //            CurX := CurX + (Lines[j].Viewport^.Left - X);
  312. //            X    := X    + (Lines[j].Viewport^.Left - X);
  313.             X := X + Coord.W * Lines[j].Font.XScale * t;
  314.             CurY := CurY + UVecY * Coord.W * t;
  315.             Coord.U := Coord.U + Coord.W * t;
  316.             Coord.W := Coord.W * (1 - t);
  317.           end;
  318.         end;
  319.         AddY := 0;
  320.         if (t < 1) and (Y < Lines[j].Viewport.Top) then begin
  321.           t := (Lines[j].Viewport.Top  - Y) / (Coord.H * Lines[j].Font.YScale);
  322.           if t < 1 then begin
  323.             Coord.V := Coord.V + Coord.H * t;
  324.             Coord.H := Coord.H * (1 - t);
  325.             AddY := Lines[j].Viewport.Top  - Y;
  326.           end;
  327.         end;
  328.         if t < 1 then begin
  329.           Inc(TotalVertices,   6);
  330.           Inc(TotalPrimitives, 2);
  331.           CurY := CurY + AddY;
  332.           // First treangle
  333.           SetVertexDataCRHW(CurX + VVecX * Coord.H, CurY + VVecY * Coord.H - 0.5, CurZ, 1, Index, VBPTR);
  334.           SetVertexDataD(Lines[j].Color, Index, VBPTR);
  335.           SetVertexDataUV(Coord.U, Coord.V + Coord.H, Index, VBPTR);
  336.           Inc(Index);
  337.           SetVertexDataCRHW(CurX, CurY - 0.5, CurZ, 1, Index, VBPTR);
  338.           SetVertexDataD(Lines[j].Color, Index, VBPTR);
  339.           SetVertexDataUV(Coord.U, Coord.V, Index, VBPTR);
  340.           Inc(Index);
  341.           SetVertexDataCRHW(CurX + UVecX * Coord.W + VVecX * Coord.H, CurY + UVecY * Coord.W + VVecY * Coord.H - 0.5, CurZ, 1, Index, VBPTR);
  342.           SetVertexDataD(Lines[j].Color, Index, VBPTR);
  343.           SetVertexDataUV(Coord.U + Coord.W, Coord.V + Coord.H, Index, VBPTR);
  344.           Inc(Index);
  345.           // Second treangle
  346.           SetVertexDataCRHW(CurX, CurY - 0.5, CurZ, 1, Index, VBPTR);
  347.           SetVertexDataD(Lines[j].Color, Index, VBPTR);
  348.           SetVertexDataUV(Coord.U, Coord.V, Index, VBPTR);
  349.           Inc(Index);
  350.           SetVertexDataCRHW(CurX + UVecX * Coord.W, CurY + UVecY * Coord.W - 0.5, CurZ, 1, Index, VBPTR);
  351.           SetVertexDataD(Lines[j].Color, Index, VBPTR);
  352.           SetVertexDataUV(Coord.U + Coord.W, Coord.V, Index, VBPTR);
  353.           Inc(Index);
  354.           SetVertexDataCRHW(CurX + UVecX * Coord.W + VVecX * Coord.H, CurY + UVecY * Coord.W + VVecY * Coord.H - 0.5, CurZ, 1, Index, VBPTR);
  355.           SetVertexDataD(Lines[j].Color, Index, VBPTR);
  356.           SetVertexDataUV(Coord.U + Coord.W, Coord.V + Coord.H, Index, VBPTR);
  357.           Inc(Index);
  358.           CurY := CurY - AddY;
  359.         end;
  360.         CurX := CurX + UVecX * Coord.W;
  361.         CurY := CurY + UVecY * Coord.W;
  362.         X := X + Coord.W * Lines[j].Font.XScale;        
  363.       end;
  364.     end;  
  365.   end;
  366.   Assert(Index <= TotalVertices, ClassName + '.Tesselate: Index out of range');
  367.   TesselationStatus[tbVertex].Status := tsTesselated;
  368.   LastTotalIndices := 0;
  369.   LastTotalVertices := TotalVertices;
  370.   Result := LastTotalVertices;
  371. end;
  372. procedure TTextMesh.Clear;
  373. begin
  374.   TotalVertices   := 0;
  375.   TotalPrimitives := 0;
  376.   TotalLines      := 0;
  377. end;
  378. procedure TTextMesh.AddLine(const AX, AY: Single; const Color: BaseTypes.TColor; const NewText: string);
  379. begin
  380.   if Length(Lines) <= TotalLines then SetLength(Lines, Length(Lines) + LinesGrowStep);
  381.   Lines[TotalLines].Text      := NewText;
  382.   Lines[TotalLines].X         := AX;
  383.   Lines[TotalLines].Y         := AY;
  384.   Lines[TotalLines].Z         := Screen.CurrentZ;
  385.   Lines[TotalLines].Color     := Color;
  386.   Lines[TotalLines].Font      := Font as BaseGraph.TBaseBitmapFont;
  387.   Lines[TotalLines].Viewport  := Screen.Viewport;
  388.   Lines[TotalLines].Transform := Screen.Transform;
  389.   Inc(TotalLines);
  390. end;
  391. end.