UMain.pas
上传用户:zkjn0718
上传日期:2021-01-01
资源大小:776k
文件大小:27k
源码类别:

Delphi/CppBuilder

开发平台:

Delphi

  1. unit UMain;
  2. interface
  3. {$I ....SourcePhysics2D.inc}
  4. uses
  5.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  6.   Dialogs, StdCtrls, CheckLst, ExtCtrls, UOpenGLCanvas, MSTimer, UPhysics2D,
  7.   UPhysics2DTypes, Math, OpenGL;
  8. const
  9.    k_maxContactPoints = 2048;
  10. type
  11.   TDrawPanel = class(TWinControl)
  12.   published
  13.      property OnResize;
  14.      property OnMouseDown;
  15.      property OnMouseMove;
  16.      property OnMouseUp;
  17.   end;
  18.   TfrmMain = class(TForm)
  19.     Panel1: TPanel;
  20.     cboTests: TComboBox;
  21.     Label1: TLabel;
  22.     chkPositionCorrection: TCheckBox;
  23.     chkWarmStarting: TCheckBox;
  24.     chkTimeOfImpact: TCheckBox;
  25.     Label2: TLabel;
  26.     chklstVisibility: TCheckListBox;
  27.     btnPause: TButton;
  28.     btnSingleStep: TButton;
  29.     GroupBox1: TGroupBox;
  30.     editGravityX: TEdit;
  31.     editGravityY: TEdit;
  32.     btnConfirmGravity: TButton;
  33.     Label3: TLabel;
  34.     Label4: TLabel;
  35.     btnReset: TButton;
  36.     GroupBox2: TGroupBox;
  37.     rdoRealTime: TRadioButton;
  38.     rdoFixedStep: TRadioButton;
  39.     procedure FormCreate(Sender: TObject);
  40.     procedure FormDestroy(Sender: TObject);
  41.     procedure chklstVisibilityClickCheck(Sender: TObject);
  42.     procedure SimulationOptionsChanged(Sender: TObject);
  43.     procedure btnSingleStepClick(Sender: TObject);
  44.     procedure btnPauseClick(Sender: TObject);
  45.     procedure cboTestsChange(Sender: TObject);
  46.     procedure FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
  47.       MousePos: TPoint; var Handled: Boolean);
  48.     procedure FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
  49.       MousePos: TPoint; var Handled: Boolean);
  50.     procedure btnConfirmGravityClick(Sender: TObject);
  51.     procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  52.     procedure btnResetClick(Sender: TObject);
  53.     procedure cboTestsCloseUp(Sender: TObject);
  54.     procedure rdoRealTimeClick(Sender: TObject);
  55.     procedure rdoFixedStepClick(Sender: TObject);
  56.   private
  57.     { Private declarations }
  58.    lastp: TGLPointF;
  59.      DrawPanel: TDrawPanel;
  60.      procedure DrawPanelResize(Sender: TObject);
  61.      procedure DrawPanelMouseDown(Sender: TObject; Button: TMouseButton;
  62.        Shift: TShiftState; X, Y: Integer);
  63.      procedure DrawPanelMouseUp(Sender: TObject; Button: TMouseButton;
  64.        Shift: TShiftState; X, Y: Integer);
  65.      procedure DrawPanelMouseMove(Sender: TObject; Shift: TShiftState; X,
  66.        Y: Integer);
  67.   public
  68.     { Public declarations }
  69.      procedure TimerProgress(const deltaTime, newTime: Double);
  70.      procedure ResetView;
  71.   end;
  72.   TTester = class;
  73.   TDrawer = class(Tb2DebugDraw)
  74.   public
  75.       Canvas: TGLCanvas;
  76.       procedure DrawPolygon(const vertices: Tb2PolyVertices; vertexCount: Int32; const color: RGBA); override;
  77.       procedure DrawPolygon4(const vertices: TVectorArray4; vertexCount: Int32; const color: RGBA); override;
  78.       procedure DrawSolidPolygon(const vertices: Tb2PolyVertices; vertexCount: Int32; const color: RGBA); override;
  79.       procedure DrawCircle(const center: TVector2; radius: Float; const color: RGBA); override;
  80.       procedure DrawSolidCircle(const center, axis: TVector2; radius: Float; const color: RGBA); override;
  81.       procedure DrawSegment(const p1, p2: TVector2; const color: RGBA); override;
  82.       procedure DrawXForm(const xf: Tb2XForm); override;
  83.       procedure DrawPoint(const p: TVector2; size: Float; const color: RGBA);
  84.   end;
  85.   TDestructionListener = class(Tb2DestructionListener)
  86.   public
  87.      test: TTester;
  88.      procedure SayGoodbye(shape:Tb2Shape); overload; override;
  89.      procedure SayGoodbye(joint: Tb2Joint); overload; override;
  90.   end;
  91.   TBoundaryListener = class(Tb2BoundaryListener)
  92.   public
  93.      test: TTester;
  94.      procedure Violation(body: Tb2Body); override;
  95.   end;
  96.   TContactListener = class(Tb2ContactListener)
  97.   public
  98.      test: TTester;
  99.      procedure Add(var point: Tb2ContactPoint); override;
  100.      procedure Persist(var point: Tb2ContactPoint); override;
  101.    procedure Remove(var point: Tb2ContactPoint); override;
  102.   end;
  103.   TContactState = (e_contactAdded, e_contactPersisted, e_contactRemoved);
  104.   TContactPoint = record
  105.      shape1, shape2: Tb2Shape;
  106.      normal, position, velocity: TVector2;
  107.      id: Tb2ContactID;
  108.      state: TContactState;
  109.   end;
  110.   TSettings = record
  111.      drawShapes, drawJoints, drawCoreShapes, drawAABBs,
  112.      drawOBBs, drawPairs, drawContactPoints, drawContactNormals,
  113.      drawContactForces, drawFrictionForces, drawCOMs, drawStats, drawKeyInfo,
  114.      enableWarmStarting, enablePositionCorrection, enableTOI,
  115.      pause, singleStep, realTime, customedStep: Boolean;
  116.   end;
  117.   TTestClass = class of TTester;
  118.   TTester = class
  119.   protected
  120.      m_RemainTime: Float;
  121.   public
  122.      m_frameCount: Integer;
  123.      m_worldAABB: Tb2AABB;
  124.      m_points: array[0..k_maxContactPoints - 1] of TContactPoint;
  125.      m_pointCount: Int32;
  126.      m_destructionListener: TDestructionListener;
  127.      m_boundaryListener: TBoundaryListener;
  128.      m_contactListener: TContactListener;
  129.      m_world: Tb2World;
  130.      m_bomb: Tb2Body;
  131.      m_mouseJoint: Tb2MouseJoint;
  132.      m_debugDrawer: TDrawer;
  133.      m_textLine: Int32;
  134.      constructor Create; virtual;
  135.      destructor Destroy; override;
  136.      procedure NextLine;
  137.      procedure Step(var settings: TSettings; timeStep: Float); virtual;
  138.      procedure Keyboard(key: Byte); virtual;
  139.      procedure MouseDown(const p: TVector2);
  140.      procedure MouseUp;
  141.      procedure MouseMove(const p: TVector2);
  142.      procedure LaunchBomb(velocity_factor: Float = 1.0); virtual;
  143.      procedure DrawText(const text: string);
  144.      // Let derived tests know that a joint was destroyed.
  145.      procedure JointDestroyed(joint: Tb2Joint); virtual;
  146.      procedure BoundaryViolated(body: Tb2Body); virtual;
  147.   end;
  148. const
  149.    DefaultStep = 1 / 60;
  150. var
  151.   frmMain: TfrmMain;
  152. procedure RegisterTestEntry(name: ShortString; ClassType: TTestClass);
  153. implementation
  154. {$R *.dfm}
  155. type
  156.    PTestEntry = ^TTestEntry;
  157.    TTestEntry = record
  158.       Name: ShortString;
  159.       ClassType: TTestClass;
  160.    end;
  161. var
  162.    Settings: TSettings;
  163.    Drawer: TDrawer;
  164.    GLCanvas: TGLCanvas;
  165.    Test: TTester;
  166.    TestEntries: array of TTestEntry;
  167.    TestCount: Integer;
  168.    ActiveEntry: PTestEntry;
  169. procedure RegisterTestEntry(name: ShortString; ClassType: TTestClass);
  170. begin
  171.    SetLength(TestEntries, TestCount + 1);
  172.    TestEntries[TestCount].Name := name;
  173.    TestEntries[TestCount].ClassType := ClassType;
  174.    Inc(TestCount);
  175. end;   
  176. procedure TfrmMain.btnConfirmGravityClick(Sender: TObject);
  177. var
  178.    v: TVector2;
  179. begin
  180.    if Assigned(Test) then
  181.    begin
  182.       v.x := StrToFloatDef(editGravityX.Text, 0.0);
  183.       v.y := StrToFloatDef(editGravityY.Text, -10.0);
  184.       editGravityX.Text := FloatToStr(v.x);
  185.       editGravityY.Text := FloatToStr(v.y);
  186.       Test.m_world.SetGravity(v);
  187.       Test.m_world.WakeAllSleepingBodies;
  188.    end;
  189. end;
  190. procedure TfrmMain.btnPauseClick(Sender: TObject);
  191. begin
  192.    Settings.pause := not Settings.pause;
  193. end;
  194. procedure TfrmMain.btnResetClick(Sender: TObject);
  195. begin
  196.    if Assigned(Test) then
  197.    begin
  198.       FreeAndNil(Test);
  199.       if Assigned(ActiveEntry) then
  200.       begin
  201.          Test := ActiveEntry^.ClassType.Create;
  202.          MSCadencer.Reset;
  203.       end;
  204.    end;
  205. end;
  206. procedure TfrmMain.btnSingleStepClick(Sender: TObject);
  207. begin
  208.  Settings.pause := True;
  209.  Settings.singleStep := True;
  210. end;
  211. procedure TfrmMain.cboTestsChange(Sender: TObject);
  212. begin
  213.    if cboTests.ItemIndex = -1 then
  214.       ActiveEntry := nil
  215.    else
  216.       ActiveEntry := @TestEntries[cboTests.ItemIndex];   
  217.    if Assigned(ActiveEntry) then
  218.    begin
  219.       if Assigned(Test) then
  220.          Test.Free;
  221.       Test := ActiveEntry^.ClassType.Create;
  222.       MSCadencer.Reset;
  223.       MSCadencer.Enabled := True;
  224.    end;
  225. end;
  226. procedure TfrmMain.cboTestsCloseUp(Sender: TObject);
  227. begin
  228.    if frmMain.ActiveControl = cboTests then
  229.       frmMain.ActiveControl := nil;
  230. end;
  231. procedure TfrmMain.chklstVisibilityClickCheck(Sender: TObject);
  232. type
  233.    TSettingArray = array[0..SizeOf(TSettings) div SizeOf(Boolean) - 1] of Boolean;
  234. var
  235.    flag: Tb2DebugDrawBitsSet;
  236.    i: Integer;
  237.    SettingArray: TSettingArray;
  238. begin
  239.    for i := 0 to High(SettingArray) - 7 do
  240.       TSettingArray(Settings)[i] := chklstVisibility.Checked[i];
  241.    flag := [];
  242.    with Settings do
  243.    begin
  244.       if drawShapes then
  245.          Include(flag, e_shapeBit);
  246.       if drawJoints then
  247.          Include(flag, e_jointBit);
  248.       if drawCoreShapes then
  249.          Include(flag, e_coreShapeBit);
  250.       if drawAABBs then
  251.          Include(flag, e_aabbBit);
  252.       if drawOBBs then
  253.          Include(flag, e_obbBit);
  254.       if drawPairs then
  255.          Include(flag, e_pairBit);
  256.       if drawCOMs then
  257.          Include(flag, e_centerOfMassBit);
  258.    end;
  259.    Drawer.m_drawFlags := flag;
  260. end;
  261. procedure TfrmMain.FormCreate(Sender: TObject);
  262. var
  263.    i: Integer;
  264. begin
  265.    DrawPanel := TDrawPanel.Create(Self);
  266.    DrawPanel.Parent := Self;
  267.    DrawPanel.Align := alClient;
  268.    DrawPanel.OnMouseDown := DrawPanelMouseDown;
  269.    DrawPanel.OnMouseMove := DrawPanelMouseMove;
  270.    DrawPanel.OnMouseUp := DrawPanelMouseUp;
  271.    DrawPanel.OnResize := DrawPanelResize;
  272.    // Add test entries
  273.    for i := 0 to TestCount - 1 do
  274.       cboTests.Items.Add(TestEntries[i].Name);
  275.    FillChar(Settings, SizeOf(Settings), 0);
  276.    with Settings do
  277.    begin
  278.     drawShapes := True;
  279.     drawJoints := True;
  280.       drawStats := True;
  281.       drawKeyInfo := True;
  282.   enableWarmStarting := True;
  283.   enablePositionCorrection := True;
  284.   enableTOI := True;
  285.       realTime := True;
  286.    end;
  287.    chklstVisibility.Checked[0] := True;
  288.    chklstVisibility.Checked[1] := True;
  289.    chklstVisibility.Checked[11] := True;
  290.    chklstVisibility.Checked[12] := True;
  291.    chkPositionCorrection.Checked := True;
  292.    chkWarmStarting.Checked := True;
  293.    chkTimeOfImpact.Checked := True;
  294.    rdoRealTime.Checked := True;
  295.    MSCadencer := TMSTimer.Create;
  296.    MSCadencer.OnProgress := TimerProgress;
  297.    GLCanvas := TGLCanvas.Create(DrawPanel, False, True, False, True);
  298.    GLCanvas.DefaultFont.WinColor := clWhite;
  299.    Drawer := TDrawer.Create;
  300.    Drawer.Canvas := GLCanvas;
  301.    ResetView;
  302.    chklstVisibilityClickCheck(nil);
  303.    cboTests.ItemIndex := 0;
  304.    cboTestsChange(nil);
  305.    SimulationOptionsChanged(nil);
  306. end;
  307. procedure TfrmMain.FormDestroy(Sender: TObject);
  308. begin
  309.    MSCadencer.Enabled := False;
  310.    if Assigned(Test) then
  311.       Test.Free;
  312.    MSCadencer.Free;
  313.    GLCanvas.Free;
  314.    Drawer.Free;
  315. end;
  316. procedure TfrmMain.FormKeyDown(Sender: TObject; var Key: Word;
  317.   Shift: TShiftState);
  318. begin
  319.    case Key of
  320.       VK_ESCAPE: Close;
  321.       90{'Z'}: GLCanvas.SetEqualScale(b2Min(GLCanvas.ScaleX * 1.1, 60.0));
  322.       88{'X'}: GLCanvas.SetEqualScale(b2Min(GLCanvas.ScaleX * 0.9, 0.5));
  323.       VK_SPACE:
  324.          if Assigned(Test) then
  325.             Test.LaunchBomb;
  326.       VK_LEFT: GLCanvas.SetTranslateX(GLCanvas.TranslateX - 1.0);
  327.       VK_RIGHT: GLCanvas.SetTranslateX(GLCanvas.TranslateX + 1.0);
  328.       VK_UP: GLCanvas.SetTranslateY(GLCanvas.TranslateY + 1.0);
  329.       VK_DOWN: GLCanvas.SetTranslateY(GLCanvas.TranslateY - 1.0);
  330.       VK_HOME: ResetView;
  331.    else
  332.       if Assigned(Test) then
  333.          Test.Keyboard(Key);
  334.    end;
  335. end;
  336. procedure TfrmMain.FormMouseWheelDown(Sender: TObject; Shift: TShiftState;
  337.   MousePos: TPoint; var Handled: Boolean);
  338. begin
  339.    GLCanvas.SetEqualScale(b2Max(GLCanvas.ScaleX * 0.9, 0.5));
  340. end;
  341. procedure TfrmMain.FormMouseWheelUp(Sender: TObject; Shift: TShiftState;
  342.   MousePos: TPoint; var Handled: Boolean);
  343. begin
  344.    GLCanvas.SetEqualScale(b2Min(GLCanvas.ScaleX * 1.1, 60.0));
  345. end;
  346. procedure TfrmMain.rdoFixedStepClick(Sender: TObject);
  347. begin
  348.    Settings.realTime := False;
  349. end;
  350. procedure TfrmMain.rdoRealTimeClick(Sender: TObject);
  351. begin
  352.    Settings.realTime := True;
  353. end;
  354. procedure TfrmMain.DrawPanelResize(Sender: TObject);
  355. begin
  356.    if Assigned(GLCanvas) then
  357.       ResetView;
  358. end;
  359. procedure TfrmMain.DrawPanelMouseDown(Sender: TObject; Button: TMouseButton;
  360.   Shift: TShiftState; X, Y: Integer);
  361. var
  362.    p: TGLPointF;
  363.    pv: TVector2;
  364. begin
  365.    ActiveControl := nil;
  366.    if Button = mbLeft then
  367.    begin            
  368.       if Assigned(Test) then
  369.       begin
  370.          p := GLCanvas.ConvertScreenToWorld(X, Y);
  371.          pv.x := p.X;
  372.          pv.y := p.Y;
  373.          Test.MouseDown(pv);
  374.       end;
  375.    end
  376.    else if Button = mbRight then
  377.    begin
  378.       lastp.X := X;
  379.       lastp.Y := Y;
  380.    end;
  381. end;
  382. procedure TfrmMain.DrawPanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  383. var
  384.    p: TGLPointF;
  385.    pv, diff: TVector2;
  386. begin
  387.    p := GLCanvas.ConvertScreenToWorld(X, Y);
  388.    pv.x := p.X;
  389.    pv.y := p.Y;
  390.    if Assigned(Test) then
  391.       Test.MouseMove(pv);
  392.    if ssRight in Shift then
  393.    begin
  394.       diff.x := lastp.X - X;
  395.       diff.y := lastp.Y - Y;
  396.       GLCanvas.BeginUpdateTransformation;
  397.       GLCanvas.TranslateX := GLCanvas.TranslateX - diff.x;
  398.       GLCanvas.TranslateY := GLCanvas.TranslateY + diff.y;
  399.       GLCanvas.EndUpdateTransformation;
  400.       lastp.X := X;
  401.       lastp.Y := Y;
  402.    end;
  403. end;
  404. procedure TfrmMain.DrawPanelMouseUp(Sender: TObject; Button: TMouseButton;
  405.   Shift: TShiftState; X, Y: Integer);
  406. begin
  407.    if Button = mbLeft then
  408.       test.MouseUp;
  409. end;
  410. procedure TfrmMain.ResetView;
  411. begin
  412.    GLCanvas.BeginUpdateTransformation.ResetTransformation.
  413.       SetTranslateX(DrawPanel.Width div 2).SetTranslateY(DrawPanel.Height div 2 - 20).SetEqualScale(10).
  414.    EndUpdateTransformation;
  415. end;
  416. procedure TfrmMain.SimulationOptionsChanged(Sender: TObject);
  417. begin
  418.    with Settings do
  419.    begin
  420.       enableWarmStarting := chkWarmStarting.Checked;
  421.       enablePositionCorrection := chkPositionCorrection.Checked;
  422.       enableTOI := chkTimeOfImpact.Checked;
  423.       if Assigned(Test) then
  424.       begin
  425.          Test.m_world.m_warmStarting := enableWarmStarting;
  426.          Test.m_world.m_positionCorrection := enablePositionCorrection;
  427.          Test.m_world.m_continuousPhysics := enableTOI;
  428.       end;
  429.    end;
  430. end;
  431. procedure TfrmMain.TimerProgress(const deltaTime, newTime: Double);
  432. begin
  433.    if Assigned(Test) then
  434.    begin
  435.       GLCanvas.RenderingBegin(clBlack);
  436.       Test.m_textLine := DrawPanel.ClientHeight - 15;
  437.       Test.DrawText(ActiveEntry^.Name);
  438.       Test.NextLine;
  439.       Test.DrawText(Format('Delta Time: %.3fs', [deltaTime]));
  440.       Test.Step(settings, deltaTime);
  441.       GLCanvas.RenderingEnd;
  442.    end
  443.    else
  444.       MSCadencer.Enabled := False;
  445. end;
  446. { TDrawer }
  447. procedure TDrawer.DrawPolygon(const vertices: Tb2PolyVertices;
  448.   vertexCount: Int32; const color: RGBA);
  449. {$IFNDEF SINGLE_PRECISION}
  450. var
  451.    i: Integer;
  452. {$ENDIF}
  453. begin
  454.    {$IFDEF SINGLE_PRECISION}
  455.    Canvas.SetPenColor(TColorVector(color)).Polygon(TGLPointsF(@vertices[0]), vertexCount);
  456.    {$ELSE}
  457.    Canvas.SetPenColor(TColorVector(color));
  458.    glBegin(GL_LINE_LOOP);
  459.    for i := 0 to vertexCount - 1 do
  460.       glVertex2d(vertices[i].X, vertices[i].Y);
  461.    glEnd;
  462.    {$ENDIF}
  463. end;
  464. procedure TDrawer.DrawPolygon4(const vertices: TVectorArray4;
  465.    vertexCount: Int32; const color: RGBA);
  466. {$IFNDEF SINGLE_PRECISION}
  467. var
  468.    i: Integer;
  469. {$ENDIF}
  470. begin
  471.    {$IFDEF SINGLE_PRECISION}
  472.    Canvas.SetPenColor(TColorVector(color)).Polygon(TGLPointsF(@vertices[0]), 4);
  473.    {$ELSE}
  474.    Canvas.SetPenColor(TColorVector(color));
  475.    glBegin(GL_LINE_LOOP);
  476.    for i := 0 to 3 do
  477.       glVertex2d(vertices[i].X, vertices[i].Y);
  478.    glEnd;
  479.    {$ENDIF}
  480. end;
  481. procedure TDrawer.DrawSolidPolygon(const vertices: Tb2PolyVertices;
  482.    vertexCount: Int32; const color: RGBA);
  483. var
  484.    tmp: TColorVector;
  485. {$IFNDEF SINGLE_PRECISION}
  486.    i: Integer;
  487. {$ENDIF}
  488. begin
  489.    with TRGBA(color) do
  490.    begin
  491.       tmp[0] := red / 2;
  492.       tmp[1] := green / 2;
  493.       tmp[2] := blue / 2;
  494.       tmp[3] := 0.5;
  495.    end;
  496.    {$IFDEF SINGLE_PRECISION}
  497.    Canvas.SetPenColor(TColorVector(color)).SetBrushColor(tmp).
  498.       FillPolygon(TGLPointsF(@vertices[0]), vertexCount, True);
  499.    {$ELSE}
  500.    Canvas.SetPenColor(tmp);
  501.    glBegin(GL_POLYGON);
  502.    for i := 0 to vertexCount - 1 do
  503.       glVertex2d(vertices[i].X, vertices[i].Y);
  504.    glEnd;
  505.    Canvas.SetPenColor(TColorVector(color));
  506.    glBegin(GL_LINE_LOOP);
  507.    for i := 0 to vertexCount - 1 do
  508.       glVertex2d(vertices[i].X, vertices[i].Y);
  509.    glEnd;
  510.    {$ENDIF}
  511. end;
  512. procedure TDrawer.DrawCircle(const center: TVector2; radius: Float; const color: RGBA);
  513. begin
  514.    Canvas.SetPenColor(TColorVector(color)).Ellipse(center.x, center.y, radius, radius);
  515. end;
  516. procedure TDrawer.DrawSolidCircle(const center, axis: TVector2; radius: Float; const color: RGBA);
  517. var
  518.    tmp: TColorVector;
  519.    p: TVector2;
  520. begin
  521.    Canvas.SetPenColor(TColorVector(color));
  522.    with TRGBA(color) do
  523.    begin
  524.       tmp[0] := red / 2;
  525.       tmp[1] := green / 2;
  526.       tmp[2] := blue / 2;
  527.       tmp[3] := 0.5;
  528.    end;
  529.    Canvas.SetBrushColor(tmp).FillEllipse(center.x, center.y, radius, radius, True);
  530.   {$IFDEF OP_OVERLOAD}
  531. p := center + radius * axis;
  532.   {$ELSE}
  533.   p := Add(center, Multiply(axis, radius));
  534.   {$ENDIF}
  535.   Canvas.Line(center.x, center.y, p.x, p.y);
  536. end;
  537. procedure TDrawer.DrawSegment(const p1, p2: TVector2; const color: RGBA);
  538. begin
  539.    Canvas.SetPenColor(TColorVector(color)).Line(p1.x, p1.y, p2.x, p2.y);
  540. end;
  541. procedure TDrawer.DrawXForm(const xf: Tb2XForm);
  542. const
  543.    k_axisScale = 0.4;
  544.    clRed: TColorVector = (1.0, 0.0, 0.0, 1.0);
  545.    clGreen: TColorVector = (0.0, 1.0, 0.0, 1.0);
  546. var
  547.    p2: TVector2;
  548. begin
  549.    with xf do
  550.    begin
  551.       p2.x := position.x + k_axisScale * R.col1.x;
  552.       p2.y := position.y + k_axisScale * R.col1.y;
  553.       Canvas.SetPenColor(clRed).Line(position.x, position.y, p2.x, p2.y);
  554.       p2.x := position.x + k_axisScale * R.col2.x;
  555.       p2.y := position.y + k_axisScale * R.col2.y;
  556.       Canvas.SetPenColor(clGreen).Line(position.x, position.y, p2.x, p2.y);
  557.    end;
  558. end;
  559. procedure TDrawer.DrawPoint(const p: TVector2; size: Float; const color: RGBA);
  560. begin
  561.    glPointSize(size);
  562.    glColor3f(color[0], color[1], color[2]);
  563.    glBegin(GL_POINTS);
  564.    glVertex2f(p.x, p.y);
  565.    glEnd;
  566.    glPointSize(1.0);
  567. end;
  568. { TDestructionListener }
  569. procedure TDestructionListener.SayGoodbye(shape: Tb2Shape);
  570. begin
  571. end;
  572. procedure TDestructionListener.SayGoodbye(joint: Tb2Joint);
  573. begin
  574.    if test.m_mouseJoint = joint then
  575.       test.m_mouseJoint := nil
  576.    else
  577.       test.JointDestroyed(joint);
  578. end;
  579. { TBoundaryListener }
  580. procedure TBoundaryListener.Violation(body: Tb2Body);
  581. begin
  582. if test.m_bomb <> body then
  583.    test.BoundaryViolated(body);
  584. end;
  585. { TContactListener }
  586. procedure TContactListener.Add(var point: Tb2ContactPoint);
  587. begin
  588.    if test.m_pointCount = k_maxContactPoints then
  589.       Exit;
  590.    with test.m_points[test.m_pointCount] do
  591.    begin
  592.       shape1 := point.shape1;
  593.       shape2 := point.shape2;
  594.       position := point.position;
  595.       normal := point.normal;
  596.       id := point.id;
  597.       state := e_contactAdded;
  598.    end;
  599.    Inc(test.m_pointCount);
  600. end;
  601. procedure TContactListener.Persist(var point: Tb2ContactPoint);
  602. begin
  603.    if test.m_pointCount = k_maxContactPoints then
  604.       Exit;
  605.    with test.m_points[test.m_pointCount] do
  606.    begin
  607.       shape1 := point.shape1;
  608.       shape2 := point.shape2;
  609.       position := point.position;
  610.       normal := point.normal;
  611.       id := point.id;
  612.       state := e_contactPersisted;
  613.    end;
  614.    Inc(test.m_pointCount);
  615. end;
  616. procedure TContactListener.Remove(var point: Tb2ContactPoint);
  617. begin
  618.    if test.m_pointCount = k_maxContactPoints then
  619.       Exit;
  620.    with test.m_points[test.m_pointCount] do
  621.    begin
  622.       shape1 := point.shape1;
  623.       shape2 := point.shape2;
  624.       position := point.position;
  625.       normal := point.normal;
  626.       id := point.id;
  627.       state := e_contactRemoved;
  628.    end;
  629.    Inc(test.m_pointCount);
  630. end;
  631. { TTester }
  632. constructor TTester.Create;
  633. const
  634.    WorldLowerBound: TVector2 = (x: -200.0; y: -100.0);
  635.    WorldUpperBound: TVector2 = (x: 200.0; y: 200.0);
  636. var
  637.    gravity: TVector2;
  638. begin
  639.    m_RemainTime := 0.0;
  640.    m_frameCount := 0;
  641.    m_destructionListener := TDestructionListener.Create;
  642.    m_boundaryListener := TBoundaryListener.Create;
  643.    m_contactListener := TContactListener.Create;
  644.    m_worldAABB.lowerBound := WorldLowerBound;
  645.    m_worldAABB.upperBound := WorldUpperBound;
  646.    gravity.x := 0.0;
  647.    gravity.y := -10.0;
  648.    m_world := Tb2World.Create(m_worldAABB, gravity, True);
  649.    frmMain.editGravityX.Text := FloatToStr(gravity.x);
  650.    frmMain.editGravityY.Text := FloatToStr(gravity.y);
  651.    m_bomb := nil;
  652.    m_textLine := 30;
  653.    m_mouseJoint := nil;
  654.    m_pointCount := 0;
  655.    m_destructionListener.test := Self;
  656.    m_boundaryListener.test := Self;
  657.    m_contactListener.test := Self;
  658.    m_world.m_destructionListener := m_destructionListener;
  659.    m_world.m_boundaryListener := m_boundaryListener;
  660.    m_world.m_contactListener := m_contactListener;
  661.    m_world.m_debugDraw := Drawer;
  662.    m_debugDrawer := Drawer;
  663.    m_world.m_warmStarting := Settings.enableWarmStarting;
  664.    m_world.m_positionCorrection := Settings.enablePositionCorrection;
  665.    m_world.m_continuousPhysics := Settings.enableTOI;
  666. end;
  667. destructor TTester.Destroy;
  668. begin
  669.    m_world.Free;
  670.    m_destructionListener.Free;
  671.    m_boundaryListener.Free;
  672.    m_contactListener.Free;   
  673.    inherited;
  674. end;
  675. procedure TTester.NextLine;
  676. begin
  677.    m_textLine := m_textLine - 15;
  678. end;
  679. procedure TTester.Step(var settings: TSettings; timeStep: Float);
  680. const
  681.    k_axisScale = 0.4;
  682.    clAdd: RGBA = (0.3, 0.95, 0.3, 1.0);
  683.    clPersist: RGBA = (0.3, 0.3, 0.95, 1.0);
  684.    clRemove: RGBA = (0.95, 0.3, 0.3, 1.0);
  685.    clContactNormal: RGBA = (0.4, 0.9, 0.4, 1.0);
  686. var
  687.    i: Integer;
  688.    p1, p2: TVector2;
  689. begin
  690.    if not Settings.customedStep then
  691.    begin
  692.       m_pointCount := 0;
  693.       if not settings.realTime then
  694.          timeStep := DefaultStep;
  695.       if settings.pause then
  696.       begin
  697.          m_RemainTime := 0.0;
  698.          if settings.singleStep then
  699.          begin
  700.             settings.singleStep := False;
  701.             Inc(m_frameCount);
  702.          end
  703.          else
  704.             timeStep := 0.0;
  705.          DrawText('****PAUSED****');
  706.       end
  707.       else
  708.          Inc(m_frameCount);
  709.       if settings.realTime then // Make sure that every frame is processed using a time step pf 1/60s.
  710.       begin
  711.          timeStep := timeStep + m_RemainTime;
  712.          while timeStep > DefaultStep do
  713.          begin
  714.             m_world.Step(DefaultStep, 10, False);
  715.             timeStep := timeStep - DefaultStep;
  716.          end;
  717.          m_RemainTime := timeStep;
  718.          m_world.DrawDebugData;
  719.       end
  720.       else
  721.          m_world.Step(timeStep, 10, True);
  722.       m_world.Validate;
  723.       if Assigned(m_bomb) and m_bomb.IsFrozen then
  724.       begin
  725.          m_world.DestroyBody(m_bomb);
  726.          m_bomb := nil;
  727.       end;
  728.    end;
  729.    if settings.drawKeyInfo then
  730.       DrawText('Z:Zoom in   X:Zoom out   Space:Launch bomb   Arrows:Move view   Home:Reset view');
  731.    if settings.drawStats then
  732.    begin
  733.       DrawText(Format('proxies(max) = %d(%d), pairs(max) = %d(%d)',
  734.         [m_world.GetProxyCount, b2_maxProxies, m_world.GetPairCount, b2_maxPairs]));
  735.       DrawText(Format('bodies/contacts/joints = %d/%d/%d',
  736.          [m_world.GetBodyCount, m_world.GetContactCount, m_world.GetJointCount]));
  737.       NextLine;
  738.    end;
  739.    if Assigned(m_mouseJoint) then
  740.    begin
  741.       p1 := m_mouseJoint.GetBody2.GetWorldPoint(m_mouseJoint.m_localAnchor);
  742.       p2 := m_mouseJoint.m_target;
  743.       glPointSize(4.0);
  744.       glColor3f(0.0, 1.0, 0.0);
  745.       glBegin(GL_POINTS);
  746.       glVertex2f(p1.x, p1.y);
  747.       glVertex2f(p2.x, p2.y);
  748.       glEnd;
  749.       glPointSize(1.0);
  750.       glColor3f(0.8, 0.8, 0.8);
  751.       glBegin(GL_LINES);
  752.       glVertex2f(p1.x, p1.y);
  753.       glVertex2f(p2.x, p2.y);
  754.       glEnd;
  755.    end;
  756.    if settings.drawContactPoints then
  757.    begin
  758.       for i := 0 to m_pointCount - 1 do
  759.          with m_points[i] do
  760.          begin
  761.             if state = e_contactAdded then // Add
  762.                Drawer.DrawPoint(position, 10.0, clAdd)
  763.             else if state = e_contactPersisted then // Persist
  764.                Drawer.DrawPoint(position, 5.0, clPersist)
  765.             else // Remove
  766.                Drawer.DrawPoint(position, 10.0, clRemove);
  767.             if settings.drawContactNormals then
  768.                {$IFDEF OP_OVERLOAD}
  769.                Drawer.DrawSegment(position, position + k_axisScale * normal, clContactNormal);
  770.                {$ELSE}               
  771.                Drawer.DrawSegment(position, Add(position, Multiply(normal, k_axisScale)), clContactNormal);
  772.                {$ENDIF}
  773.          end;
  774.    end;
  775. end;
  776. procedure TTester.Keyboard(key: Byte);
  777. begin
  778. end;
  779. procedure TTester.MouseDown(const p: TVector2);
  780. const k_maxCount = 10;
  781. var
  782.    i: Integer;
  783.    aabb: Tb2AABB;
  784.    d: TVector2;
  785.    count: Int32;
  786.    body, shapeBody: Tb2Body;
  787.    shapes: TList;
  788.    md: Tb2MouseJointDef;
  789. begin
  790.    if Assigned(m_mouseJoint) then
  791.       Exit;
  792.    // Make a small box.
  793.    {$IFDEF OP_OVERLOAD}   
  794.    d.SetValue(0.001, 0.001);
  795.    aabb.lowerBound := p - d;
  796.    aabb.upperBound := p + d;
  797.    {$ELSE}   
  798.    SetValue(d, 0.001, 0.001);
  799.    aabb.lowerBound := Subtract(p, d);
  800.    aabb.upperBound := Add(p, d);
  801.    {$ENDIF}      
  802.    // Query the world for overlapping shapes.
  803.    shapes := TList.Create;
  804.    count := m_world.Query(aabb, shapes, k_maxCount);
  805.    body := nil;
  806.    for i := 0 to count - 1 do
  807.    begin
  808.       shapeBody := Tb2Shape(shapes[i]).GetBody;
  809.       if (not shapeBody.IsStatic) and (shapeBody.GetMass > 0.0) then
  810.          if Tb2Shape(shapes[i]).TestPoint(shapeBody.m_xf, p) then
  811.          begin
  812.             body := Tb2Shape(shapes[i]).GetBody;
  813.             Break;
  814.          end;
  815.    end;
  816.    if Assigned(body) then
  817.    begin
  818.       md := Tb2MouseJointDef.Create;
  819.       md.body1 := m_world.GetGroundBody;
  820.       md.body2 := body;
  821.       md.target := p;
  822.       md.maxForce := 1000.0 * body.GetMass;
  823.       m_mouseJoint := Tb2MouseJoint(m_world.CreateJoint(md));
  824.       body.WakeUp;
  825.    end;
  826. end;
  827. procedure TTester.MouseUp;
  828. begin
  829.    if Assigned(m_mouseJoint) then
  830.    begin
  831.       m_world.DestroyJoint(m_mouseJoint);
  832.       m_mouseJoint := nil;
  833.    end;
  834. end;
  835. procedure TTester.MouseMove(const p: TVector2);
  836. begin
  837.  if Assigned(m_mouseJoint) then
  838.       m_mouseJoint.SetTarget(p);
  839. end;
  840. procedure TTester.LaunchBomb(velocity_factor: Float = 1.0);
  841. var
  842.    bd: Tb2BodyDef;
  843.    sd: Tb2CircleDef;
  844. begin
  845.    if Assigned(m_bomb) then
  846.    begin
  847.      m_world.DestroyBody(m_bomb);
  848.      m_bomb := nil;
  849.    end;
  850.    bd := Tb2BodyDef.Create;
  851.    bd.allowSleep := True;
  852.    {$IFDEF OP_OVERLOAD}   
  853.    bd.position.SetValue(RandomRange(-15, 15), RandomRange(10, 30));
  854.    {$ELSE}
  855.    SetValue(bd.position, RandomRange(-15, 15), RandomRange(10, 30));
  856.    {$ENDIF}      
  857.    bd.isBullet := True;
  858.    m_bomb := m_world.CreateBody(bd);
  859.    {$IFDEF OP_OVERLOAD}   
  860.    m_bomb.SetLinearVelocity(-5.0 * bd.position * velocity_factor);
  861.    {$ELSE}   
  862.    m_bomb.SetLinearVelocity(Multiply(bd.position, -5.0 * velocity_factor));
  863.    {$ENDIF}      
  864.    sd := Tb2CircleDef.Create;
  865.    sd.radius := 0.3;
  866.    sd.density := 20.0;
  867.    sd.restitution := 0.1;
  868.    m_bomb.CreateShape(sd);
  869.    m_bomb.SetMassFromShapes;
  870. end;
  871. procedure TTester.DrawText(const text: string);
  872. begin
  873.    m_debugDrawer.Canvas.TextOutASCII(text, 5, m_textLine);
  874.    NextLine;
  875. end;
  876. procedure TTester.JointDestroyed(joint: Tb2Joint);
  877. begin
  878. end;
  879. procedure TTester.BoundaryViolated(body: Tb2Body);
  880. begin
  881. end;
  882. initialization
  883.    RegisterClass(TDrawPanel);
  884.    TestCount := 0;
  885.    ActiveEntry := nil;
  886. end.