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

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(CAST II Engine visual items 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.  Unit contains basic classes of visual items
  6. *)
  7. {$Include GDefines.inc}
  8. {$Include C2Defines.inc}
  9. unit C2Visual;
  10. interface
  11. uses
  12.   SysUtils,
  13.   TextFile,
  14.   BaseTypes, Basics, Base3D, BaseMsg, ItemMsg, Props, Models, BaseCont, BaseClasses,
  15.   {$IFDEF EDITORMODE} BaseGraph, C2MapEditMsg, {$ENDIF}
  16.   C2Types, C2Msg, CAST2, C2Materials, C2Maps;
  17. const
  18.   // Vertex format
  19.   vwIndexedBlending = $8;
  20.   //Light source types
  21.   ltDirectional = 0; ltPoint = 1; ltSpot = 2;
  22.   //Light source types enumeration string
  23.   LightKindsEnum = 'Directional&Point&Spot';
  24.   // Size of data in index buffers
  25.   IndexSize = 2;
  26.   // Default capacity of technique => item hash map
  27.   DefaultTechToItemMapCapacity = 8;
  28.   // Max size of mapped item edit cursor size
  29.   MaxCursorSize = 64;
  30.   // Map edit mode: adjust heights
  31.   hmemAdjust = 0;
  32.   // Map edit mode: smooth heights
  33.   hmemSmooth = 1;
  34.   // Map edit modes string enumeration
  35.   MapEditModesEnum = 'Adjust' + StringDelimiter + 'Smooth';
  36. type
  37.   //  Tesselation status
  38.   TTesselationState = (// Tesselator was cardinally changed, including maximum number of vertices and/or indices
  39.                        tsMaxSizeChanged,
  40.                        // Tesselator data was changed
  41.                        tsChanged,
  42.                        // Tesselator data was not changed so no reason to tesselate it again
  43.                        tsTesselated);
  44.   // Type of tesselator used to render an item
  45.   TTesselatorType = (// Triangulated data of the tesselator rarely or never changes
  46.                      ttStatic,
  47.                      // Triangulated data changes nearly every frame (particle system, etc)
  48.                      ttDynamic);
  49.   { Current tesselation status data structure
  50.     <b>BufferIndex</b>      - index of buffer in API-independent buffers
  51.     <b>Offset</b>           - offset within the buffer in elements (vertices, indices, etc)
  52.     <b>Status</b>           - current tesselation state
  53.     <b>LastResetCounter</b> - reset counter
  54.     should not be modified manually }
  55.   TTesselationStatus = record
  56.     TesselatorType: TTesselatorType;
  57.     BufferIndex, Offset: Integer;
  58.     Status: TTesselationState;
  59.     LastResetCounter, LastBufferResetCounter: Integer;
  60.   end;
  61.   // Kind of tesselator
  62.   TTesselatorKind = (// Null tesselator. Used when the item is tesselated by other shared tesselator (GUI, impostors, etc)
  63.                      tkNone,
  64.                      // The item is tesselated by its own tesselator (default)
  65.                      tkOwn,
  66.                      // a shared tesselator used for items of several classes (2D primitives, particles, etc)
  67.                      tkShared);
  68.   { The delegate used to retrieve a custom texture matrix. See @Link(tmCustom).
  69.     <b>TextureSet</b> is an index of texture set to which the retrieved matrix will applied }
  70.   TTextureMatrixDelegate = procedure(TextureStage: Integer; out Matrix: TMatrix4s) of object;
  71.   // @Abstract(Camera which looks at a specified target point)
  72.   TLookAtCamera = class(CAST2.TCamera)
  73.   private
  74.     FRange: Single;
  75.     FFixedUp: Boolean;
  76.     FLookTarget, FixedUpVector: TVector3s;
  77.     procedure SetRange(const Value: Single);
  78.     procedure SetFixedUp(const Value: Boolean);
  79.     procedure SetLookTarget(const Value: TVector3s);
  80.   protected
  81.     procedure ComputeTransform; override;
  82.   public
  83.     procedure Move(XD, YD, ZD: Single); override;
  84.     procedure AddProperties(const Result: Props.TProperties); override;
  85.     procedure SetProperties(Properties: Props.TProperties); override;
  86.     // Look range
  87.     property Range: Single read FRange write SetRange;
  88.     // Setting this to True will fix the camera's UP vector
  89.     property FixedUp: Boolean read FFixedUp write SetFixedUp;
  90.     // Look target
  91.     property LookTarget: TVector3s read FLookTarget write SetLookTarget;
  92.   end;
  93.   // @Abstract(Light source)
  94.   TLight = class(CAST2.TProcessing)
  95.   private
  96.     function GetEnabled: Boolean;
  97.     procedure SetEnabled(const Value: Boolean);
  98.   protected
  99.     procedure SetState(const Value: TSet32); override;
  100.   public
  101.     // Determines which passes can be affected by the light source
  102.     GroupMask: TPassGroupSet;
  103.     // Kind of the light source
  104.     Kind: Integer;
  105.     // Diffuse color of the light source
  106.     Diffuse,
  107.     // Specular color of the light source
  108.     Specular,
  109.     // Ambient color of the light source
  110.     Ambient: BaseTypes.TColor4s;
  111.     // Effective range of the light source
  112.     Range: Single;
  113.     Falloff: Single;
  114.     // Constant attenuation
  115.     Attenuation0,
  116.     // Linear attenuation
  117.     Attenuation1,
  118.     // Quadratic attenuation
  119.     Attenuation2: Single;
  120.     // Inner angle of spotlight cone
  121.     Theta,
  122.     // Outer angle of spotlight cone
  123.     Phi: Single;
  124.     constructor Create(AManager: TItemsManager); override;
  125.     procedure HandleMessage(const Msg: TMessage); override;
  126.     procedure AddProperties(const Result: Props.TProperties); override;
  127.     procedure SetProperties(Properties: Props.TProperties); override;
  128.     // Setting <b>Enabled</b> to @True/@False turns on/off the light source
  129.     property Enabled: Boolean read GetEnabled write SetEnabled;
  130.   end;
  131.   { Data structure passed to tesselator buffer filling methods <br>
  132.     <b>Camera</b>      - currently applied camera <br>
  133.     <b>ModelMatrix</b> - model transform of visible items being rendered }
  134.   TTesselationParameters = record
  135.     Camera: TCamera;
  136.     ModelMatrix: TMatrix4s;
  137.   end;
  138.   CTesselator = class of TTesselator;
  139.   { @Abstract(Performs triangulation of visible items)
  140.     Visible items are different - GUI elements, 3D meshes, procedural models, etc. [b]TTesselator[/b] contains methods to
  141.     convert an item to its triangulated representation. }
  142.   TTesselator = class(TReferencedItem)
  143.   private
  144.     LastMaxAmount: array[TTesselationBuffer] of Integer;
  145.     Manager: TItemsManager;                   // For message sending
  146.   protected
  147.     // Informs engine core about bounding box change
  148.     procedure InvalidateBoundingBox;
  149.   public
  150.     // Total primitives in each strip
  151.     TotalPrimitives: Integer;
  152.     // Primitive type
  153.     PrimitiveType: TPrimitiveType;
  154.     // Total vetices in all strips
  155.     TotalVertices,
  156.     // Total indices in all strips
  157.     TotalIndices: Integer;
  158.     // Total strips
  159.     TotalStrips,
  160.     // Offset in vertex buffer for each strip
  161.     StripOffset: Integer;
  162.     // Number of vertices referenced by indices
  163.     IndexingVertices: Integer;
  164.     // Current tesselation status
  165.     TesselationStatus: array[TTesselationBuffer] of TTesselationStatus;
  166.     // If set to True a manual render method through @Link(DoManualRender) will be used instead of regular render
  167.     ManualRender: Boolean;
  168. // Old
  169. //    Index: Integer;
  170.     LastTotalIndices, LastTotalVertices: Integer;
  171.     // Command block ID For render speedup. E.g. OpenGL display list ID.
  172.     CommandBlock: Integer;
  173.     // Determines if command block is a currently valid ID
  174.     CommandBlockValid: Boolean;
  175.     VerticesRes, IndicesRes: Integer;
  176.     CompositeMember: Boolean;
  177.     CompositeOffset: ^TVector3s;
  178. //    {$IFDEF DEBUGMODE} LastMaxVertices: Integer; {$ENDIF}                 // Used only for debugging
  179.     constructor Create; virtual;
  180.     procedure Init; virtual;
  181.     { Can be overridden to add some properties in addition to ones of a visible item which uses the tesselator.
  182.       Called from AddProperties of @Link(TVisible). Object links can not be used or resolved here. }
  183.     procedure AddProperties(const Result: Props.TProperties; const PropNamePrefix: TNameString); virtual;
  184.     { Can be overridden to set some properties in addition to ones of a visible item which uses the tesselator.
  185.       Called from SetProperties of @Link(TVisible). Object links can not be used or resolved here. }
  186.     procedure SetProperties(Properties: Props.TProperties; const PropNamePrefix: TNameString); virtual;
  187.     { Returns number of elements in the specified buffer type which needs to be updated in an API buffers.
  188.       This function called by engine static buffers management routine to determine if lock/fill/unlock procedure needed
  189.       for each tesselator.
  190.       If the function returns 0 no update needed. }
  191.     function GetUpdatedElements(Buffer: TTesselationBuffer; const Params: TTesselationParameters): Integer; virtual;
  192.     // Returns maximum amount of elements in the specified buffer type
  193.     function GetMaxAmount(Buffer: TTesselationBuffer): Integer;
  194.     // Invalidates contents of buffers used by the tesselator at the API side. If <b>EntireBuffer</b> is True entire API buffer will become invalid so use only if necessary.
  195.     procedure Invalidate(ABuffer: TTesselationBufferSet; EntireBuffer: Boolean);
  196. // ToDo: Move these methods to protected:
  197.     // Returns True if mesh is valid. The basic implemetation simply tests all indices to point within correct vertices range.
  198.     function Validate: Boolean; virtual;
  199.     // Manual lighting begin
  200.     procedure BeginLighting; virtual; abstract;
  201.     // Perform manual lighting
  202.     function CalculateLighting(const ALight: TLight; const ALightToItem: TMatrix4s): Boolean; virtual; abstract;
  203.     // Bounding box containing
  204.     function GetBoundingBox: TBoundingBox; virtual;
  205.     function SetIndices(IBPTR: Pointer): Integer; virtual;
  206.     function Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer; virtual;
  207.   protected
  208.     // Vertex format as specified by @Link(GetVertexFormat)
  209.     FVertexFormat: Cardinal;
  210.     // Size of each vertex in bytes
  211.     FVertexSize: Integer;
  212.     // Offset of each element within a vertex in bytes
  213.     ElementOffs: array[vfiXYZ..vfiTEX7] of Integer;
  214.     // Init internal variables for the specified vertex format
  215.     procedure InitVertexFormat(Format: Cardinal); virtual;
  216.     { Should return a maximum possible amount of vertices for the tesselator object to reserve place in buffers. <br>
  217.       For rarely updated tesselators which still can have a variable number of vertices it's reasonable to use a static tesselator
  218.       with <b>GetMaxVertices</b> the maximum amount of vertices.
  219.       The return value of this function can vary but its change should be indicated with the @Link(tsMaxSizeChanged) teselation status and
  220.       will cause discarding of a buffer which may cause performance penalty at lest for static buffers. }
  221.     function GetMaxVertices: Integer; virtual;
  222.     { Should return a maximum possible amount of indices for the tesselator object to reserve place in buffers. <br>
  223.       For rarely updated tesselators which still can have a variable number of indices it's reasonable to use a static tesselator
  224.       with <b>GetMaxVertices</b> the maximum amount of indices.
  225.       The return value of this function can vary but its change should be indicated with the @Link(tsMaxSizeChanged) teselation status and
  226.       will cause discarding of a buffer which may cause performance penalty at lest for static buffers. }
  227.     function GetMaxIndices: Integer; virtual;
  228.     // Set a coordinate set in vertex buffer. [b]Index[/b] - element index, [b]VBuf[/b] - pointer to vertex buffer. Should be called from @Link(Tesselate) only
  229.     procedure SetVertexDataC(x, y, z: Single; Index: Integer; VBuf: Pointer); overload;
  230.     // Set a coordinate set in vertex buffer. [b]Index[/b] - element index, [b]VBuf[/b] - pointer to vertex buffer. Should be called from @Link(Tesselate) only
  231.     procedure SetVertexDataC(const Vec: TVector3s; Index: Integer; VBuf: Pointer); overload;
  232.     // Set a transformed coordinate set in vertex buffer. [b]Index[/b] - element index, [b]VBuf[/b] - pointer to vertex buffer. Should be called from @Link(Tesselate) only
  233.     procedure SetVertexDataCRHW(x, y, z, RHW: Single; Index: Integer; VBuf: Pointer);
  234.     // Set a normal in vertex buffer. [b]Index[/b] - element index, [b]VBuf[/b] - pointer to vertex buffer. Should be called from @Link(Tesselate) only
  235.     procedure SetVertexDataN(nx, ny, nz: Single; Index: Integer; VBuf: Pointer); overload;
  236.     // Set a normal in vertex buffer. [b]Index[/b] - element index, [b]VBuf[/b] - pointer to vertex buffer. Should be called from @Link(Tesselate) only
  237.     procedure SetVertexDataN(const Vec: TVector3s; Index: Integer; VBuf: Pointer); overload;
  238.     // Set a weight in vertex buffer. [b]Index[/b] - element index, [b]VBuf[/b] - pointer to vertex buffer. Should be called from @Link(Tesselate) only
  239.     procedure SetVertexDataW(w: Single; Index: Integer; VBuf: Pointer);
  240.     // Set a diffuse color (color 1) in vertex buffer. [b]Index[/b] - element index, [b]VBuf[/b] - pointer to vertex buffer. Should be called from @Link(Tesselate) only
  241.     procedure SetVertexDataD(Color: TColor; Index: Integer; VBuf: Pointer);
  242.     // Set a specular color (color 2) in vertex buffer. [b]Index[/b] - element index, [b]VBuf[/b] - pointer to vertex buffer. Should be called from @Link(Tesselate) only
  243.     procedure SetVertexDataS(Color: TColor; Index: Integer; VBuf: Pointer);
  244.     // Set first 2D-texture coordinates set in vertex buffer. [b]Index[/b] - element index, [b]VBuf[/b] - pointer to vertex buffer. Should be called from @Link(Tesselate) only
  245.     procedure SetVertexDataUV(u, v: Single; Index: Integer; VBuf: Pointer);
  246.     // Set first 3D-texture coordinates set in vertex buffer. [b]Index[/b] - element index, [b]VBuf[/b] - pointer to vertex buffer. Should be called from @Link(Tesselate) only
  247.     procedure SetVertexDataUV3(u, v, w: Single; Index: Integer; VBuf: Pointer);
  248.     // Set second 2D-texture coordinates set in vertex buffer. [b]Index[/b] - element index, [b]VBuf[/b] - pointer to vertex buffer. Should be called from @Link(Tesselate) only
  249.     procedure SetVertexData2UV(u, v: Single; Index: Integer; VBuf: Pointer);
  250.     // Sets an index in index buffer
  251.     procedure SetIndex(AValue, AOffset: Integer; AIBuf: Pointer);
  252.   public
  253.     // Returns an index from index buffer
  254.     function GetIndex(AOffset: Integer; AIBuf: Pointer): Integer;
  255.     // Get a coordinate set from vertex buffer. [b]AIndex[/b] - element index, [b]AVBuf[/b] - pointer to vertex buffer.
  256.     function GetVertexDataC(AIndex: Integer; AVBuf: Pointer): TVector3s;
  257.     // Performs render manually if ManualRender is True. Default implementation does nothing so the method should be overridden if manual render needed.
  258.     procedure DoManualRender(Item: TItem); virtual;
  259.     // Output format of vertices
  260.     property VertexFormat: Cardinal read FVertexFormat write InitVertexFormat;
  261.     // Size of each vertex
  262.     property VertexSize: Integer read FVertexSize;
  263.   end;
  264.   // This message informs all visible items that tesselator has changed its bounding box
  265.   TTessBBoxUpdateMsg = class(TMessage)
  266.     Tesselator: TTesselator;
  267.     constructor Create(ATesselator: TTesselator);
  268.   end;
  269.   // Base class of tesselator which used to tesselate several different items
  270.   TSharedTesselator = class(TTesselator)
  271.     // Clear tesselation
  272.     procedure Clear; virtual; abstract;
  273.   end;
  274. //  TVisibilityCheckerDelegate = function(const Camera: TCamera): Boolean of object;
  275.   TVisible = class(CAST2.TProcessing)
  276.   private
  277.     VisibilityFlag: Boolean;
  278.     FCurrentLOD: Single;
  279.     procedure SetTesselatorKind(const Value: TTesselatorKind);
  280.   protected
  281.     // A set of tesselators used to geometrically represent the item in various LOD's
  282.     FTesselators: array of TTesselator;
  283.     // True if the item should be lit by its own code
  284.     FCustomLighting: Boolean;
  285.     // Current render technique
  286.     FCurTechnique: TTechnique;
  287.     // Index in TRenderPass.Items array
  288.     IndexInPass: array of Int32;
  289.     // Determines what kind tesselator will be used to tesselated the item
  290.     FTesselatorKind: TTesselatorKind;
  291.     // Reference to current tesselator
  292.     FCurrentTesselator: TTesselator;
  293.     procedure SetParent(NewParent: TItem); override;
  294.     procedure SetState(const Value: TSet32); override;
  295.     procedure AddToPasses;
  296.     procedure RemoveFromPasses;
  297.     procedure DoShow;
  298.     procedure DoHide;
  299.     // Returns <b>True</b> if visibility mask of all parents has @Link(isVisible) flag included
  300.     function isParentsVisible: Boolean;
  301.     // Returns <b>True</b> if visibility mask of the item and all its parents has @Link(isVisible) flag included
  302.     function isActuallyVisible: Boolean;
  303.     function GetMaterial: TMaterial;
  304.     procedure SetMaterial(Value: TMaterial);
  305.     procedure SetCurTechnique(const Value: TTechnique);
  306.     procedure SetMesh; virtual;
  307.     procedure SetCurrentLOD(const Value: Single); virtual;
  308.   public
  309.     // This value is calculated every frame for any item which should be rendered. Override @Link(CalcSortValue) to change it.
  310.     SortValue: Single;
  311.     BlendMatrices: array of TMatrix4s;  // ToDO: optimize
  312.     RetrieveTextureMatrix: TTextureMatrixDelegate;
  313.     constructor Create(AManager: TItemsManager); override;
  314.     destructor Destroy; override;
  315.     class function IsAbstract: Boolean; override;
  316.     // Returns class of tesselator which will represent the item geometrically
  317.     function GetTesselatorClass: CTesselator; virtual;
  318.     procedure HandleMessage(const Msg: TMessage); override;
  319.     procedure OnInit; override;
  320.     procedure OnSceneAdd; override;
  321.     procedure OnSceneRemove; override;
  322.     // Shows the item
  323.     procedure Show; virtual;
  324.     // Hides the item
  325.     procedure Hide; virtual;
  326.     // To specify shader constants an item class should override this method
  327.     procedure RetrieveShaderConstants(var ConstList: TShaderConstants); virtual;
  328.     // Returns value by which to sort items containing sorted order passes in material
  329.     function CalcSortValue(const Camera: TCamera): Single; virtual;
  330.     // If the item is visible through the given camera returns True and sets current tesselator according to needed detail level
  331.     function VisibilityCheck(const Camera: TCamera): Boolean; virtual;
  332.     // Should be overriden to render item indirectly or other custom rendering mode
  333.     procedure Render; virtual;
  334.     // Prepares the item and tesselator for manual lighting. Called automatically.
  335.     procedure BeginLighting;
  336.     // Calls tesselator to perform manual lighting calculation
  337.     function CalculateLighting(const ALight: TLight): Boolean;
  338.     procedure AddProperties(const Result: Props.TProperties); override;
  339.     procedure SetProperties(Properties: Props.TProperties); override;
  340.   public
  341.     // True if the item should be lit by its own code
  342.     property CustomLighting: Boolean read FCustomLighting;
  343.     property Material: TMaterial read GetMaterial write SetMaterial;
  344.     property CurrentTesselator: TTesselator read FCurrentTesselator;
  345.     property CurTechnique: TTechnique read FCurTechnique{ write SetCurTechnique};
  346.     property TesselatorKind: TTesselatorKind read FTesselatorKind write SetTesselatorKind;
  347.     property CurrentLOD: Single read FCurrentLOD write SetCurrentLOD;
  348.   end;
  349.   TClassRec = record
  350.     TessClass: CTesselator;
  351.     TessMap: BaseCont.TPointerPointerMap;                 // Maps a technique to a visible item
  352.   end;
  353.   TTemporaryVisible = class(TVisible)
  354.   public
  355.     constructor Create(AManager: TItemsManager); override;
  356.     destructor Destroy; override;
  357.     procedure Clear;
  358.     function VisibilityCheck(const Camera: TCamera): Boolean; override;
  359.   end;
  360.   TSharedTesselators = class(CAST2.TBaseSharedTesselators)
  361.   private
  362.     Items: array of TVisible; TotalItems: Integer;
  363.     TessClasses: array of TClassRec;
  364.     function GetItemIndex(const AItem: TVisible): Integer;
  365.     function GetTesselatorIndex(const TessClass: CTesselator): Integer;
  366.     function AddTesselatorClass(const TessClass: CTesselator): Integer;
  367.     function GetTesselator(const TessClass: CTesselator; const Technique: TTechnique): TTesselator;
  368.     function DrawTechMap(Key, Value: Pointer): Boolean;
  369.     function DelTechMap(Key, Value: Pointer): Boolean;
  370.     function FreeTechMap(Key, Value: Pointer): Boolean;
  371.   public
  372.     procedure AddItem(const AItem: TVisible);
  373.     procedure RemoveItem(const AItem: TVisible);
  374.     procedure Clear; override;
  375.     procedure Reset; override;
  376.     procedure Render; override;
  377.     destructor Destroy; override;
  378.     property Tesselator[const TessClass: CTesselator; const Technique: TTechnique]: TTesselator read GetTesselator; default;
  379.   end;
  380.   TMappedTesselator = class(TTesselator)
  381.   protected
  382.     Item: CAST2.TProcessing;
  383.     FMap: C2Maps.TMap;
  384.   // Other
  385.     OldWidth, OldHeight: Integer;
  386.     OldCellWidthScale, OldCellHeightScale, OldDepthScale: Single;
  387.   public
  388.     procedure Init; override;
  389.     function GetMaxVertices: Integer; override;
  390.     function GetBoundingBox: TBoundingBox; override;
  391.     procedure SetMap(const AMap: C2Maps.TMap); virtual;
  392.   end;
  393.   THeighTMapEditOp = class(C2Maps.TMapEditOp)
  394.     // Inits the operation and returns True if it's valid and can be applied
  395.     function Init(AMap: TMap; ACellX, ACellZ, ACursorSize: Integer; AValueDelta: Single): Boolean; virtual; abstract;
  396.   end;
  397.   THeighTMapEditOpAdjust = class(THeighTMapEditOp)
  398.   private
  399.     Scale: Single;
  400.   public
  401.     function Init(AMap: TMap; ACellX, ACellZ, ACursorSize: Integer; AValueDelta: Single): Boolean; override;
  402.   end;
  403.   THeighTMapEditOpSmooth = class(THeighTMapEditOp)
  404.   private
  405.     Scale: Single;
  406.   public
  407.     function Init(AMap: TMap; ACellX, ACellZ, ACursorSize: Integer; AValueDelta: Single): Boolean; override;
  408.   end;
  409.   TMappedItem = class(TVisible)
  410.   protected
  411.     FMap: C2Maps.TMap;
  412.     {$IFDEF EDITORMODE}
  413.     EditCellX, EditCellZ: Integer;
  414.     EditMouseX, EditMouseY: Integer;
  415.     EditCursorSize: Integer;
  416.     EditMode: Boolean;
  417.     {$ENDIF}
  418.     procedure ResolveLinks; override;
  419.     procedure OnModify(const ARect: BaseTypes.TRect); virtual;
  420.     // Returns True if the specified cursor coordinates points to a map cell through the specified camera. Also returns the cell indices.
  421.     function PickCell(Camera: TCamera; MouseX, MouseY: Integer; out CellX, CellZ: Integer): Boolean; virtual;
  422.     {$IFDEF EDITORMODE}
  423.     function DrawCursor(Cursor: C2MapEditMsg.TMapCursor; Camera: TCamera; Screen: TScreen): Boolean; virtual;
  424.     procedure ModifyBegin(Cursor: TMapCursor; Camera: TCamera); virtual;
  425.     procedure Modify(Cursor: TMapCursor; Camera: TCamera); virtual;
  426.     procedure ModifyEnd(Cursor: TMapCursor; Camera: TCamera); virtual;
  427.     {$ENDIF}
  428.   public
  429.     class function IsAbstract: Boolean; override;
  430.     procedure SetMesh; override;
  431.     procedure AddProperties(const Result: Props.TProperties); override;
  432.     procedure SetProperties(Properties: Props.TProperties); override;
  433.     procedure HandleMessage(const Msg: TMessage); override;
  434.     property Map: C2Maps.TMap read FMap;
  435.   end;
  436.   /// Determines a vertex format which can include variuos components. VertexWeight can be OR'ed with vwIndexedBlending to indicate that last weight is actually a dword with indices
  437.   function GetVertexFormat(Transformed, Normals, Diffuse, Specular, PointSize: Boolean; VertexWeights: Word; TextureSets: array of Integer): Longword;
  438.   function GetVertexSize(VertexFormat: Longword): Cardinal;
  439.   function VertexContains(VertexFormat, ElementIndex: Longword): Boolean;
  440.   function GetVertexElementOffset(VertexFormat, ElementIndex: Longword): Integer;
  441.   function GetVertexTextureSetsCount(VertexFormat: Longword): Integer;
  442.   function GetVertexTextureCoordsCount(VertexFormat, TextureSetIndex: Longword): Integer;
  443.   function GetVertexWeightsCount(VertexFormat: Longword): Integer;
  444.   function GetVertexIndexedBlending(VertexFormat: Longword): Boolean;
  445.   procedure ConvertVertices(SrcFormat, DestFormat: Longword; TotalVertices: Integer; Src: Pointer; Dest: Pointer);
  446. var RGBA: Boolean;            // Determines whether is needed to swap R and B color components. Must be True for OpenGL renderer due to difference in OpenGL and DirectX color representation
  447. implementation
  448. function GetVertexFormat(Transformed, Normals, Diffuse, Specular, PointSize: Boolean; VertexWeights: Word; TextureSets: array of Integer): Longword;
  449. var i, TotalTextureSets: Integer; TextureBits: Integer;
  450. begin
  451.   Assert(((VertexWeights and $7) + Ord(VertexWeights and vwIndexedBlending > 0)<= 5) and
  452.          ((VertexWeights and $7 > 0) or (VertexWeights and vwIndexedBlending = 0)), 'GetVertexFormat: Invalid weights count');
  453.   Assert(not Transformed or (VertexWeights = 0), 'GetVertexFormat: Transformed vertices should not have weights');
  454.   TextureBits := 0;
  455.   TotalTextureSets := Length(TextureSets);
  456.   for i := 0 to TotalTextureSets-1 do begin
  457.     Assert((i < 8) and (TextureSets[i] > 0) and (TextureSets[i] <= 4), 'GetVertexFormat: Invalid texture sets');
  458.     TextureBits := TextureBits or ((TextureSets[i]-1) and 3) shl (i*2);
  459.   end;
  460.   Result := VertexWeights shl 28 + Cardinal(TotalTextureSets) shl 24 + Cardinal(TextureBits) shl 8 +
  461.             Cardinal(Ord(Transformed) * vfTRANSFORMED + Ord(Normals)  * vfNORMALS +
  462.                      Ord(Diffuse)     * vfDIFFUSE     + Ord(Specular) * vfSPECULAR + Ord(PointSize) * vfPOINTSIZE);
  463. end;
  464. function GetVertexSize(VertexFormat: Longword): Cardinal;
  465. var i, TextureSets: Integer; TextureBits: Cardinal;
  466. begin
  467.   Result := (3 + VertexFormat and vfTRANSFORMED    +
  468.              Cardinal(3*Ord(VertexFormat and vfNORMALS   > 0)  +
  469.                         Ord(VertexFormat and vfDIFFUSE   > 0)  + Ord(VertexFormat and vfSPECULAR > 0) +
  470.                         Ord(VertexFormat and vfPOINTSIZE > 0)) +
  471.              Cardinal(GetVertexWeightsCount(VertexFormat) + Ord(GetVertexIndexedBlending(VertexFormat))) ) shl 2;
  472.   TextureBits := (VertexFormat shr 8) and $FFFF;
  473.   TextureSets := (VertexFormat shr 24) and $F;
  474.   for i := 0 to TextureSets-1 do Result := Result + (TextureBits shr (i*2) and 3 + 1) shl 2;
  475. end;
  476. function VertexContains(VertexFormat, ElementIndex: Longword): Boolean;
  477. begin
  478.   Result := VertexFormat and ElementIndex > 0;
  479. end;
  480. function GetVertexElementOffset(VertexFormat, ElementIndex: Longword): Integer;
  481. var i, TextureSets: Integer; TextureBits: Cardinal;
  482. begin
  483.   Result := 0;
  484.   if ElementIndex = vfiXYZ then Exit;
  485.   if VertexFormat and vfTRANSFORMED > 0 then Result := 4*4 else Result := 3*4;
  486.   if (GetVertexWeightsCount(VertexFormat) > 0) and GetVertexIndexedBlending(VertexFormat) then Inc(Result, 4);
  487.   for i := 0 to GetVertexWeightsCount(VertexFormat)-1 do begin              // Through weights
  488.     if ElementIndex = vfiWEIGHT1 + Cardinal(i) then Exit;
  489.     Inc(Result, 4);
  490.   end;
  491.   if VertexFormat and vfNORMALS > 0 then begin
  492.     if ElementIndex = vfiNORM then Exit;
  493.     Inc(Result, 3*4);
  494.   end;
  495.   if VertexFormat and vfPOINTSIZE > 0 then begin
  496.     if ElementIndex = vfiPOINTSIZE then Exit;
  497.     Inc(Result, 4);
  498.   end;
  499.   if VertexFormat and vfDIFFUSE > 0 then begin
  500.     if ElementIndex = vfiDIFF then Exit;
  501.     Inc(Result, 4);
  502.   end;
  503.   if VertexFormat and vfSPECULAR > 0 then begin
  504.     if ElementIndex = vfiSPEC then Exit;
  505.     Inc(Result, 4);
  506.   end;
  507.   TextureBits := (VertexFormat shr 8) and $FFFF;
  508.   TextureSets := (VertexFormat shr 24) and $F;
  509.   for i := 0 to TextureSets-1 do begin       // Through texture sets
  510.     if ElementIndex = vfiTEX0 + Cardinal(i) then Exit;
  511.     Inc(Result, (TextureBits shr (i*2) and 3 + 1) shl 2);
  512.   end;
  513.   Result := -1;
  514. //  Assert(False, 'GetVertexElementOffset: Element not found');
  515. end;
  516. function GetVertexTextureSetsCount(VertexFormat: Longword): Integer;
  517. begin
  518.   Result := (VertexFormat shr 24) and $F;
  519. end;
  520. function GetVertexTextureCoordsCount(VertexFormat, TextureSetIndex: Longword): Integer;
  521. begin
  522.   Result := ((VertexFormat shr 8) and $FFFF) shr (TextureSetIndex*2) and 3 + 1;
  523. end;
  524. function GetVertexWeightsCount(VertexFormat: Longword): Integer;
  525. begin
  526.   Result := (VertexFormat shr 28) and $7;
  527. end;
  528. function GetVertexIndexedBlending(VertexFormat: Longword): Boolean;
  529. begin
  530.   Result := (GetVertexWeightsCount(VertexFormat) > 0) and ((VertexFormat shr 28) and vwIndexedBlending > 0);
  531. end;
  532. procedure ConvertVertices(SrcFormat, DestFormat: Longword; TotalVertices: Integer; Src: Pointer; Dest: Pointer);
  533. type TVBuf = array[0..$FFFFFF] of Byte;
  534. const
  535.   veiNorm = 0; veiDiff = 1; veiSpec = 2; veiWeight = 3; veiTex = 4;
  536.   riSrc = 0; riDest = 1;
  537.   elSize = 4;         // Element size (float)
  538. var
  539.   SVSize, DVSize, i: Integer; CoordsSize: Cardinal;
  540.   EOffset: array[riSrc..riDest, veiNorm..veiTex] of Integer;
  541. //  vfiXYZ = 0; vfiWEIGHT1 = 1; vfiWEIGHT2 = 2; vfiWEIGHT3 = 3; vfiNORM = 4; vfiPointSize = 5; vfiDIFF = 6; vfiSPEC = 7;
  542. //  vfiTEX0 = 8; vfiTEX1 = 9; vfiTEX2 = 10; vfiTEX3 = 11; vfiTEX4 = 12; vfiTEX5 = 13; vfiTEX6 = 14; v
  543. procedure CalcOffsets(Format, Res: Cardinal);
  544. begin
  545.   EOffset[Res, veiNorm]   := MaxI(0, GetVertexElementOffset(Format, vfiNorm));
  546.   EOffset[Res, veiDiff]   := MaxI(0, GetVertexElementOffset(Format, vfiDiff));
  547.   EOffset[Res, veiSpec]   := MaxI(0, GetVertexElementOffset(Format, vfiSpec));
  548.   EOffset[Res, veiWeight] := MaxI(0, GetVertexElementOffset(Format, vfiWeight1));
  549.   EOffset[Res, veiTex]    := MaxI(0, GetVertexElementOffset(Format, vfiTex0));
  550. end;
  551. function GetTextureSetsSize(Format: Longword): Integer;
  552. var i: Integer;
  553. begin
  554.   Result := 0;
  555.   for i := 0 to GetVertexTextureSetsCount(Format)-1 do Inc(Result, GetVertexTextureCoordsCount(Format, i) * elSize);
  556. end;
  557. begin
  558.   CalcOffsets(SrcFormat,  riSrc);
  559.   CalcOffsets(DestFormat, riDest);
  560.   SVSize := GetVertexSize(SrcFormat);
  561.   DVSize := GetVertexSize(DestFormat);
  562.   CoordsSize := 3*ElSize;                                         // XYZ compoments
  563.   if VertexContains(SrcFormat, vfTransformed) and VertexContains(DestFormat, vfTransformed) then CoordsSize := 4*ElSize;
  564.   if TotalVertices > 0 then FillChar(Dest^, TotalVertices * DVSize, 0);
  565.   for i := 0 to TotalVertices-1 do begin
  566.     Move(TVBuf(Src^)[i*SVSize], TVBuf(Dest^)[i*DVSize], CoordsSize);
  567.     // Move weights
  568.     Move(TVBuf(Src^)[i*SVSize + EOffset[riSrc, veiWeight]], TVBuf(Dest^)[i*DVSize + EOffset[riDest, veiWeight]],
  569.          MinI(GetVertexWeightsCount(SrcFormat)  + Ord(GetVertexIndexedBlending(SrcFormat)),
  570.               GetVertexWeightsCount(DestFormat) + Ord(GetVertexIndexedBlending(DestFormat)) ) * ElSize);
  571.     if VertexContains(SrcFormat, vfNormals) and VertexContains(DestFormat, vfNormals) then
  572.       Move(TVBuf(Src^)[i*SVSize + EOffset[riSrc, veiNorm]], TVBuf(Dest^)[i*DVSize + EOffset[riDest, veiNorm]], 3*ElSize);
  573.     if VertexContains(SrcFormat, vfDiffuse) and VertexContains(DestFormat, vfDiffuse) then
  574.       Move(TVBuf(Src^)[i*SVSize + EOffset[riSrc, veiDiff]], TVBuf(Dest^)[i*DVSize + EOffset[riDest, veiDiff]], ElSize);
  575.     if VertexContains(SrcFormat, vfSpecular) and VertexContains(DestFormat, vfSpecular) then
  576.       Move(TVBuf(Src^)[i*SVSize + EOffset[riSrc, veiSpec]], TVBuf(Dest^)[i*DVSize + EOffset[riDest, veiSpec]], ElSize);
  577.     Move(TVBuf(Src^)[i*SVSize + EOffset[riSrc, veiTex]], TVBuf(Dest^)[i*DVSize + EOffset[riDest, veiTex]],
  578.          MinI(GetTextureSetsSize(SrcFormat), GetTextureSetsSize(DestFormat)));
  579.     
  580.   end;
  581. end;
  582. { TLookAtCamera }
  583. procedure TLookAtCamera.SetRange(const Value: Single);
  584. begin
  585.   FRange := Value;
  586.   Position := SubVector3s(FLookTarget, ScaleVector3s(ForwardVector, Exp(FRange)));
  587. end;
  588. procedure TLookAtCamera.SetFixedUp(const Value: Boolean);
  589. begin
  590.   FFixedUp := Value;
  591.   if Value then FixedUpVector := UpVector;
  592. end;
  593. procedure TLookAtCamera.SetLookTarget(const Value: TVector3s);
  594. begin
  595.   FLookTarget := Value;
  596.   SetRange(Range);
  597. end;
  598. procedure TLookAtCamera.ComputeTransform;
  599. begin
  600.   inherited;
  601.   SetRange(Range);
  602. //  inherited;
  603. end;
  604. {function TLookAtCamera.GetPosition: TVector3s;
  605. begin
  606.   Result := inherited GetPosition;
  607.   Result := SubVector3s(Result, ScaleVector3s(ForwardVector, Exp(FRange)));
  608. end;}
  609. procedure TLookAtCamera.AddProperties(const Result: Props.TProperties);
  610. begin
  611.   inherited;
  612.   if not Assigned(Result) then Exit;
  613.   Result.Add('Range', vtSingle, [], FloatToStr(FRange), '');
  614.   Result.Add('Fixed up vector', vtBoolean, [], OnOffStr[FixedUp], '');
  615.   AddVector3sProperty(Result, 'Target', FLookTarget);
  616. end;
  617. procedure TLookAtCamera.SetProperties(Properties: Props.TProperties);
  618. begin
  619.   inherited;
  620.   if Properties.Valid('Range') then FRange := StrToFloatDef(Properties['Range'], 0);
  621.   if Properties.Valid('Fixed up vector') then FixedUp := Properties.GetAsInteger('Fixed up vector') > 0;
  622.   if SetVector3sProperty(Properties, 'Target', FLookTarget) then SetLookTarget(FLookTarget);
  623. end;
  624. procedure TLookAtCamera.Move(XD, YD, ZD: Single);
  625. begin
  626.   LookTarget := AddVector3s(LookTarget, AddVector3s(AddVector3s(ScaleVector3s(RightVector, XD), ScaleVector3s(UpVector, YD)), ScaleVector3s(ForwardVector, ZD)));
  627. end;
  628. { TTessBBoxUpdateMsg }
  629. constructor TTessBBoxUpdateMsg.Create(ATesselator: TTesselator);
  630. begin
  631.   Tesselator := ATesselator;
  632. end;
  633. { TTesselator }
  634. procedure TTesselator.InvalidateBoundingBox;
  635. begin
  636.   if Assigned(Manager) then Manager.SendMessage(TTessBBoxUpdateMsg.Create(Self), nil, [mfBroadcast]);
  637. end;
  638. constructor TTesselator.Create;
  639. var i: TTesselationBuffer;
  640. begin
  641.   InitVertexFormat(GetVertexFormat(False, True, False, False, False, 0, [2]));
  642.   PrimitiveType := ptTRIANGLELIST;
  643.   for i := Low(TTesselationBuffer) to High(TTesselationBuffer) do begin
  644.     TesselationStatus[i].BufferIndex            := -1;
  645.     TesselationStatus[i].Offset                 := 0;
  646.     TesselationStatus[i].Status                 := tsChanged;
  647.     TesselationStatus[i].LastResetCounter       := 0;
  648.     TesselationStatus[i].LastBufferResetCounter := 0;
  649.     TesselationStatus[i].TesselatorType         := ttStatic;
  650.     LastMaxAmount[i] := MaxInt;
  651.   end;
  652.   LastTotalIndices  := 0;
  653.   LastTotalVertices := 0;
  654.   TotalIndices      := 0;
  655.   IndexingVertices  := 0;
  656.   TotalStrips       := 1;
  657.   StripOffset       := 0;
  658.   VerticesRes       := -1;
  659.   IndicesRes        := -1;
  660.   CompositeOffset   := nil;
  661.   CompositeMember   := False;
  662.   CommandBlock := -1;
  663.   CommandBlockValid := False;
  664. end;
  665. procedure TTesselator.Init;
  666. var ParNum: Integer; Par1, Par2: Pointer;
  667. begin
  668.   ParNum := RetrieveParameters(Par1, False);
  669.   RetrieveParameters(Par2, True);
  670.   if ParNum > 0 then Move(Par1^, Par2^, ParNum * SizeOf(Cardinal));                        // Fill internal parameters with public ones
  671.   Invalidate([tbVertex, tbIndex], False);
  672. end;
  673. procedure TTesselator.AddProperties(const Result: TProperties; const PropNamePrefix: TNameString);
  674. begin
  675.   if Assigned(Result) then begin
  676.     Result.Add(PropNamePrefix + 'Manual render', vtBoolean, [], OnOffStr[ManualRender], '');
  677.   end;
  678. end;
  679. procedure TTesselator.SetProperties(Properties: TProperties; const PropNamePrefix: TNameString);
  680. begin
  681.   if Properties.Valid(PropNamePrefix + 'Manual render') then ManualRender := Properties.GetAsInteger(PropNamePrefix + 'Manual render') > 0;
  682. end;
  683. procedure TTesselator.InitVertexFormat(Format: Cardinal);
  684. var i: Integer;
  685. begin
  686.   FVertexFormat := Format;
  687.   FVertexSize   := GetVertexSize(FVertexFormat);
  688.   for i := vfiXYZ to vfiTEX7 do ElementOffs[i] := GetVertexElementOffset(FVertexFormat, i);
  689. end;
  690. procedure TTesselator.Invalidate(ABuffer: TTesselationBufferSet; EntireBuffer: Boolean);
  691. var BType: TTesselationBuffer;
  692. begin
  693.   for BType := Low(BType) to High(BType) do if BType in ABuffer then                                            
  694.     if TesselationStatus[BType].TesselatorType = ttStatic then begin
  695.       if EntireBuffer then
  696.         TesselationStatus[BType].Status := tsMaxSizeChanged else
  697.           TesselationStatus[BType].Status := tsChanged;
  698.     end;
  699.   CommandBlockValid := False;
  700. end;
  701. function TTesselator.GetMaxVertices: Integer;
  702. begin
  703.   Result := TotalVertices;
  704. end;
  705. function TTesselator.GetMaxIndices: Integer;
  706. begin
  707.   Result := TotalIndices;
  708. end;
  709. function TTesselator.GetBoundingBox: TBoundingBox;
  710. begin
  711.   Result.P1 := GetVector3s(-1, -1, -1);
  712.   Result.P2 := GetVector3s( 1,  1,  1);
  713. end;
  714. procedure TTesselator.SetIndex(AValue, AOffset: Integer; AIBuf: Pointer);
  715. begin
  716.   TWordBuffer(AIBuf^)[AOffset] := AValue;
  717. end;
  718. function TTesselator.GetIndex(AOffset: Integer; AIBuf: Pointer): Integer;
  719. begin
  720.   case IndexSize of
  721.     2: Result := TWordBuffer(AIBuf^)[AOffset];
  722.   end;
  723. end;
  724. function TTesselator.GetVertexDataC(AIndex: Integer; AVBuf: Pointer): TVector3s;
  725. begin
  726.   Assert(VertexFormat and vfTRANSFORMED = 0, ClassName + '.SetVertexDataC: This call is not allowed with existing vertex format');
  727.   {$IFDEF DEBUGMODE}
  728.   Assert(AIndex < GetMaxVertices, Format('%S.%S: Vertice index (%D) is greater than max vertices (%D)', [ClassName, 'GetVertexDataC', AIndex, GetMaxVertices]));
  729.   {$ENDIF}
  730.   Result := TVector3s(PtrOffs(AVBuf, AIndex * FVertexSize)^);
  731. end;
  732. function TTesselator.SetIndices(IBPTR: Pointer): Integer;
  733. begin
  734.   Result := 0;
  735. end;
  736. function TTesselator.Tesselate(const Params: TTesselationParameters; VBPTR: Pointer): Integer;
  737. begin
  738.   Result := 0;
  739.   LastTotalVertices := TotalVertices;
  740. end;
  741. procedure TTesselator.SetVertexDataC(x, y, z: Single; Index: Integer; VBuf: Pointer);
  742. begin
  743.   Assert(VertexFormat and vfTRANSFORMED = 0, ClassName + '.SetVertexDataC: This call is not allowed with existing vertex format');
  744.   {$IFDEF DEBUGMODE}
  745.   Assert(Index < GetMaxVertices, Format('%S.%S: Vertice index (%D) is greater than max vertices (%D)', [ClassName, 'SetVertexDataC', Index, GetMaxVertices]));
  746.   {$ENDIF}
  747.   TVector3s(Pointer(Integer(VBuf) + Index * FVertexSize)^).X := x;
  748.   TVector3s(Pointer(Integer(VBuf) + Index * FVertexSize)^).Y := y;
  749.   TVector3s(Pointer(Integer(VBuf) + Index * FVertexSize)^).Z := z;
  750. end;
  751. procedure TTesselator.SetVertexDataC(const Vec: TVector3s; Index: Integer; VBuf: Pointer);
  752. begin
  753.   Assert(VertexFormat and vfTRANSFORMED = 0, ClassName + '.SetVertexDataC: This call is not allowed with existing vertex format');
  754.   {$IFDEF DEBUGMODE}
  755.   Assert(Index < GetMaxVertices, Format('%S.%S: Vertice index (%D) is greater than max vertices (%D)', [ClassName, 'SetVertexDataC', Index, GetMaxVertices]));
  756.   {$ENDIF}
  757.   TVector3s(Pointer(Integer(VBuf) + Index * FVertexSize)^) := Vec;
  758. end;
  759. procedure TTesselator.SetVertexDataCRHW(x, y, z, RHW: Single; Index: Integer; VBuf: Pointer);
  760. begin
  761.   Assert(VertexFormat and vfTRANSFORMED = vfTRANSFORMED, ClassName + '.SetVertexDataCRHW: This call is not allowed with existing vertex format');
  762.   TVector4s(Pointer(Integer(VBuf) + Index * FVertexSize)^).X := x;
  763.   TVector4s(Pointer(Integer(VBuf) + Index * FVertexSize)^).Y := y;
  764.   TVector4s(Pointer(Integer(VBuf) + Index * FVertexSize)^).Z := z;
  765.   TVector4s(Pointer(Integer(VBuf) + Index * FVertexSize)^).W := RHW;
  766. end;
  767. procedure TTesselator.SetVertexDataD(Color: TColor; Index: Integer; VBuf: Pointer);
  768. begin
  769.   Assert(VertexFormat and vfDIFFUSE = vfDIFFUSE, ClassName + '.SetVertexDataD: This call is not allowed with existing vertex format');
  770.   {$IFDEF DEBUGMODE}
  771.   Assert(Index < GetMaxVertices, Format('%S.%S: Vertice index (%D) is greater than max vertices (%D)', [ClassName, 'SetVertexDataD', Index, GetMaxVertices]));
  772.   {$ENDIF}
  773.   if RGBA then asm        // Swap R and B components in Color
  774.   end;
  775.   TColor(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiDIFF])^) := Color;
  776. end;
  777. procedure TTesselator.SetVertexDataN(nx, ny, nz: Single; Index: Integer; VBuf: Pointer);
  778. begin
  779.   Assert(VertexFormat and vfNORMALS = vfNORMALS, ClassName + '.SetVertexDataN: This call is not allowed with existing vertex format');
  780.   TVector3s(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiNORM])^).X := nx;
  781.   TVector3s(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiNORM])^).Y := ny;
  782.   TVector3s(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiNORM])^).Z := nz;
  783. end;
  784. procedure TTesselator.SetVertexDataN(const Vec: TVector3s; Index: Integer; VBuf: Pointer);
  785. begin
  786.   Assert(VertexFormat and vfNORMALS = vfNORMALS, ClassName + '.SetVertexDataN: This call is not allowed with existing vertex format');
  787.   TVector3s(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiNORM])^) := Vec;
  788. end;
  789. procedure TTesselator.SetVertexDataS(Color: TColor; Index: Integer; VBuf: Pointer);
  790. begin
  791.   Assert(VertexFormat and vfSPECULAR = vfSPECULAR, ClassName + '.SetVertexDataS: This call is not allowed with existing vertex format');
  792.   if RGBA then asm        // Swap R and B components in Color
  793.   end;
  794.   TColor(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiSPEC])^) := Color;
  795. end;
  796. procedure TTesselator.SetVertexDataUV(u, v: Single; Index: Integer; VBuf: Pointer);
  797. begin
  798.   Assert(GetVertexElementOffset(VertexFormat, vfiTEX0) <> -1, ClassName + '.SetVertexDataUV: This call is not allowed with existing vertex format');
  799.   Single(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiTEX0])^) := u;
  800.   Single(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiTEX0] + 4)^) := v;
  801. end;
  802. procedure TTesselator.SetVertexDataUV3(u, v, w: Single; Index: Integer; VBuf: Pointer);
  803. begin
  804.   Assert(GetVertexElementOffset(VertexFormat, vfiTEX0) <> -1, ClassName + '.SetVertexDataUV: This call is not allowed with existing vertex format');
  805.   Single(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiTEX0])^) := u;
  806.   Single(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiTEX0] + 4)^) := v;
  807.   Single(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiTEX0] + 8)^) := w;
  808. end;
  809. procedure TTesselator.SetVertexData2UV(u, v: Single; Index: Integer; VBuf: Pointer);
  810. begin
  811.   Assert(GetVertexElementOffset(VertexFormat, vfiTEX1) <> -1, ClassName + '.SetVertexDataUV2: This call is not allowed with existing vertex format');
  812.   Single(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiTEX1])^) := u;
  813.   Single(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiTEX1] + 4)^) := v;
  814. end;
  815. procedure TTesselator.SetVertexDataW(w: Single; Index: Integer; VBuf: Pointer);
  816. begin
  817.   Assert(GetVertexElementOffset(VertexFormat, vfiWEIGHT1) <> -1, ClassName + '.SetVertexDataW: This call is not allowed with existing vertex format');
  818.   Single(Pointer(Integer(VBuf) + Index * FVertexSize + ElementOffs[vfiWEIGHT1])^) := w;
  819. end;
  820. function TTesselator.Validate: Boolean;
  821. var i, MaxVertices, LTotalIndices: Integer; IBuf: Pointer;
  822. begin
  823.   Result := True;
  824.   if GetMaxIndices = 0 then Exit;
  825.   GetMem(IBuf, GetMaxIndices * IndexSize);
  826.   MaxVertices   := GetMaxVertices;
  827.   LTotalIndices := SetIndices(IBuf);
  828.   i := 0;
  829.   while (i < LTotalIndices) and (TWordBuffer(IBuf^)[i] < MaxVertices) do Inc(i);
  830.   if (i < LTotalIndices) then begin
  831.     {$IFDEF LOGGING} Log.Log(Format('%S.%S: Index #%D = %D (exceedes total vertices = %D)', [ClassName, 'Validate', i, TWordBuffer(IBuf^)[i], MaxVertices]), lkWarning); {$ENDIF}
  832.     Result := False;
  833.   end;
  834.   FreeMem(IBuf);
  835. end;
  836. function TTesselator.GetUpdatedElements(Buffer: TTesselationBuffer; const Params: TTesselationParameters): Integer;
  837. begin
  838.   Result := 0;
  839.   case Buffer of
  840.     tbVertex: Result := TotalVertices * Ord(TesselationStatus[Buffer].Status <> tsTesselated);
  841.     tbIndex:  Result := TotalIndices  * Ord(TesselationStatus[Buffer].Status <> tsTesselated);
  842.   end;  
  843. end;
  844. function TTesselator.GetMaxAmount(Buffer: TTesselationBuffer): Integer;
  845. begin
  846.   case Buffer of
  847.     tbVertex: Result := GetMaxVertices;
  848.     tbIndex:  Result := GetMaxIndices;
  849.     else Result := 0;
  850.   end;
  851.   LastMaxAmount[Buffer] := Result;
  852. {  Assert((TesselationStatus[Buffer].TesselatorType <> ttStatic) or (Result <= LastMaxAmount[Buffer]),
  853.          Format('%S.%S: Maximum amount of vertices or indices should not increase for tesselators placed in a static buffer',
  854.                 [ClassName, 'GetMaxAmount']));
  855.   Result := Result * Ord((TesselationStatus[Buffer].TesselatorType <> ttStatic) or (Result <= LastMaxAmount[Buffer]));}
  856. end;
  857. procedure TTesselator.DoManualRender(Item: TItem);
  858. begin
  859. end;
  860. { TVisible }
  861. constructor TVisible.Create(AManager: TItemsManager);
  862. begin
  863.   inherited;
  864.   FState := FState + [isVisible];
  865.   BlendMatrices := nil;
  866.   IndexInPass   := nil;
  867.   SetLength(FTesselators, 1);
  868.   FTesselatorKind := tkOwn;
  869.   
  870. //  SetMesh;
  871. end;
  872. destructor TVisible.Destroy;
  873. begin
  874.   BlendMatrices := nil;
  875.   IndexInPass   := nil;
  876.   inherited;
  877. end;
  878. class function TVisible.IsAbstract: Boolean;
  879. begin
  880.   Result := Self = TVisible;
  881. end;
  882. function TVisible.GetTesselatorClass: CTesselator;
  883. begin
  884.   Result := nil;
  885. end;
  886. procedure TVisible.HandleMessage(const Msg: TMessage);
  887. var i: Integer; OldCurTechnique: TTechnique;
  888. begin
  889.   inherited;
  890.   if Msg.ClassType = TSceneLoadedMsg then begin
  891.     GetMaterial;
  892.   end else if Msg.ClassType = TTechniqueModificationBeginMsg then begin
  893.     if TTechniqueModificationBeginMsg(Msg).Item = FCurTechnique then
  894.       RemoveFromPasses;
  895.   end else if Msg.ClassType = TTechniqueModificationEndMsg then begin
  896.     if TTechniqueModificationBeginMsg(Msg).Item = FCurTechnique then begin
  897.       OldCurTechnique := FCurTechnique;
  898.       SetCurTechnique(nil);
  899.       SetCurTechnique(OldCurTechnique);
  900.     end;  
  901. {  end else if Msg.ClassType = TParentStateChangeMsg then with TParentStateChangeMsg(Msg) do begin
  902.     if not (isVisible in OldValue) and (isVisible in NewValue) then DoShow;
  903.     if (isVisible in OldValue) and not (isVisible in NewValue) then DoHide;}
  904.   end else if Msg.ClassType = ItemMsg.TReplaceMsg then begin
  905.     with ItemMsg.TReplaceMsg(Msg) do if (OldItem = Self) then begin
  906.       if VisibilityFlag then RemoveFromPasses;
  907.       if NewItem is TVisible then begin
  908.         SetLength(TVisible(NewItem).BlendMatrices, Length(BlendMatrices));
  909.         for i := 0 to High(TVisible(NewItem).BlendMatrices) do TVisible(NewItem).BlendMatrices[i] := BlendMatrices[i];
  910.         BlendMatrices := nil;
  911. //        TVisible(NewItem).DoShow;
  912.       end;
  913.     end;
  914.   end else if Msg.ClassType = C2Msg.TValidationResultChangedMsg then begin
  915.     if TValidationResultChangedMsg(Msg).Item = Material then SetCurrentLOD(CurrentLOD);
  916.   end else if Msg.ClassType = TTessBBoxUpdateMsg then begin
  917.     if TTessBBoxUpdateMsg(Msg).Tesselator = FCurrentTesselator then
  918.       BoundingBox := TTessBBoxUpdateMsg(Msg).Tesselator.GetBoundingBox;
  919.   end;
  920. end;
  921. function TVisible.isParentsVisible: Boolean;
  922. // Returns True if isVisible state is on for the item and all its predecessors which are TVisible
  923. var Item: TItem;
  924. begin
  925.   Item := Self.Parent;
  926.   while Assigned(Item) and
  927.        ( not (Item is TVisible) or (isVisible in Item.State) ) do
  928.     Item := Item.Parent;
  929.   Result := not Assigned(Item);
  930. end;
  931. function TVisible.isActuallyVisible: Boolean;
  932. begin
  933.   Result := (isVisible in State) and isParentsVisible;
  934. end;
  935. procedure TVisible.OnInit;
  936. begin
  937.   inherited;
  938.   SetMesh;
  939. end;
  940. procedure TVisible.OnSceneAdd;
  941. begin
  942.   inherited;
  943.   if Assigned(IndexInPass) and (IndexInPass[0] = -1) then AddToPasses;
  944. end;
  945. procedure TVisible.OnSceneRemove;
  946. begin
  947.   inherited;
  948.   RemoveFromPasses;
  949. end;
  950. procedure TVisible.Show;
  951. begin
  952.   State := FState + [isVisible];
  953. end;
  954. procedure TVisible.Hide;
  955. begin
  956.   State := FState - [isVisible];
  957. end;
  958. procedure TVisible.RetrieveShaderConstants(var ConstList: TShaderConstants);
  959. begin
  960.   ConstList := nil;
  961. end;
  962. function TVisible.CalcSortValue(const Camera: TCamera): Single;
  963. begin
  964.   SortValue := SqrMagnitude(SubVector3s(Camera.GetAbsLocation, GetAbsLocation));
  965.   Result    := SortValue;
  966. end;
  967. procedure TVisible.SetMesh;
  968.   procedure SetTesselator(var Tess: TTesselator);
  969.   var NewTesselator: TTesselator;
  970.   begin
  971.     Assert(GetTesselatorClass() <> nil);
  972.     if GetTesselatorClass() = nil then Exit;
  973.     if Assigned(Tess) then begin
  974.       if Tess.RefCount > 1 then begin                                   // tesselator defined and used by another item. Duplication may need.
  975.         Tess.DecRef;
  976.         if GetTesselatorClass() = Tess.ClassType then
  977.           Tess := (FManager as CAST2.TBaseCore).TesselatorManager.FindSameItem(Tess) as TTesselator
  978.         else
  979.           Tess := nil;
  980.       end else if GetTesselatorClass() <> Tess.ClassType then Tess := nil;
  981.     end;  
  982.     if not Assigned(Tess) then begin
  983.       NewTesselator := GetTesselatorClass.Create;                                                    // Create a new tesselator
  984.       Tess := (FManager as CAST2.TBaseCore).TesselatorManager.AddItem(NewTesselator) as TTesselator; // Try to add it to manager
  985.       if Tess <> NewTesselator then NewTesselator.Free;                                              // Release it if the same found in manager
  986.     end;  
  987. (*    if (Tess <> nil) then begin
  988.       if Tess.RefCount > 1 then begin                                   // tesselator defined and used by another item. Duplication may need.
  989.         Tess.DecRef;
  990.         Tess := (FManager as CAST2.TBaseCore).TesselatorManager.FindSameItem(Tess) as TTesselator;
  991.         if Tess = nil then Tess := GetTesselatorClass.Create;
  992.       end;
  993.     end else if (GetTesselatorClass <> nil) then begin
  994.       NewTesselator := GetTesselatorClass.Create;                                         // Create a new tesselator
  995.       Tess := (FManager as CAST2.TBaseCore).TesselatorManager.AddItem(NewTesselator) as TTesselator; // Try to add it to manager
  996.       if Tess <> NewTesselator then NewTesselator.Free;                             // Release it if the same found in manager
  997.     end;*)
  998.     if Tess <> nil then begin
  999.       Tess.Manager := FManager;
  1000.       Tess.Init;
  1001.     end;
  1002.   end;
  1003. var i: Integer;
  1004. begin
  1005.   if (FManager = nil) or (FManager.Root = nil) then Exit;
  1006.   Assert(High(FTesselators) >= 0);
  1007.   if GetTesselatorClass <> nil then begin
  1008.     for i := 0 to High(FTesselators) do begin
  1009. //      if GetTesselatorClass <> FTesselators[i].ClassType then FTesselators[i] := nil;
  1010.       SetTesselator(FTesselators[i]);
  1011.     end;
  1012.     FCurrentTesselator := FTesselators[0];
  1013.   end;  
  1014. //  SetTesselator(FCurrentTesselator);
  1015.   if Assigned(FCurrentTesselator) then BoundingBox := FCurrentTesselator.GetBoundingBox;
  1016. end;
  1017. procedure TVisible.SetCurrentLOD(const Value: Single);
  1018. var Tech: TTechnique;
  1019. begin
  1020.   FCurrentLOD := Value;
  1021.   Tech := Material.GetTechniqueByLOD(Value);
  1022.   if Tech <> FCurTechnique then SetCurTechnique(Tech);
  1023. end;
  1024. procedure TVisible.AddProperties(const Result: Props.TProperties);
  1025. var i: Integer;
  1026. begin
  1027.   inherited;
  1028.   AddItemLink(Result, 'Material', [], 'TMaterial');
  1029.   if Assigned(CurrentTesselator) then CurrentTesselator.AddProperties(Result, '');
  1030.   for i := 0 to High(FTesselators) do if Assigned(FTesselators[i]) then
  1031.     FTesselators[i].AddProperties(Result, 'Tesselator #' + IntToStr(i) + '');
  1032. end;
  1033. procedure TVisible.SetProperties(Properties: Props.TProperties);
  1034. var i: Integer;
  1035. begin
  1036.   inherited;
  1037.   if Properties.Valid('Material') then SetLinkProperty('Material', Properties['Material']);
  1038.   GetMaterial;
  1039.   if Assigned(CurrentTesselator) then CurrentTesselator.SetProperties(Properties, '');
  1040.   for i := 0 to High(FTesselators) do if Assigned(FTesselators[i]) then
  1041.     FTesselators[i].SetProperties(Properties, 'Tesselator #' + IntToStr(i) + '');  
  1042. end;
  1043. function TVisible.VisibilityCheck(const Camera: TCamera): Boolean;
  1044. var d: Single; LOD: Integer;
  1045. begin
  1046.   Result := Camera.IsSpehereVisible(GetAbsLocation, BoundingSphereRadius) <> fcOutside;
  1047.   if Result then begin
  1048.     d := Sqrt(SqrMagnitude(SubVector3s(Camera.GetAbsLocation, GetAbsLocation)))/Camera.ZFar;
  1049.     LOD := ClampI(Round(High(FTesselators) * d), 0, High(FTesselators));
  1050.     FCurrentTesselator := FTesselators[LOD];
  1051.   end;
  1052. end;
  1053. procedure TVisible.Render;
  1054. begin
  1055. end;
  1056. procedure TVisible.BeginLighting;
  1057. begin
  1058.   if Assigned(FCurrentTesselator) then FCurrentTesselator.BeginLighting;
  1059. end;
  1060. function TVisible.CalculateLighting(const ALight: TLight): Boolean;
  1061. var LightToItem: TMatrix4s;
  1062. begin
  1063.   Assert(CustomLighting, Format('%S.%S: CustomLighting should be True', [ClassName, 'CalculateLighting']));
  1064.   if Assigned(FCurrentTesselator) then begin
  1065.     MulMatrix4s(LightToItem, InvertMatrix4s(Transform), ALight.Transform);
  1066.     Result := FCurrentTesselator.CalculateLighting(ALight, LightToItem);
  1067.   end else Result := False;
  1068. end;
  1069. procedure TVisible.AddToPasses;
  1070. var i: Integer;
  1071. begin
  1072.   if not isActuallyVisible then Exit;
  1073.   case TesselatorKind of
  1074.     tkOwn: if FCurTechnique <> nil then for i := 0 to FCurTechnique.TotalPasses-1 do begin
  1075.       Assert(IndexInPass[i] = -1, ClassName + '("' + GetFullName + '").DoShow: IndexInPass should be -1');
  1076.       if (IndexInPass[i] = -1) and (FCurTechnique.Passes[i] <> nil) then IndexInPass[i] := FCurTechnique.Passes[i].AddItem(Self);
  1077.     end;
  1078.     tkShared: ((FManager as CAST2.TBaseCore).SharedTesselators as TSharedTesselators).AddItem(Self);
  1079.   end;
  1080. end;
  1081. procedure TVisible.RemoveFromPasses;
  1082. var i: Integer;
  1083. begin
  1084.   case TesselatorKind of
  1085.     tkOwn: if FCurTechnique <> nil then for i := 0 to High(IndexInPass) do begin
  1086.       if IndexInPass[i] <> -1 then begin
  1087.         Assert((FCurTechnique.Passes[i].Items[IndexInPass[i]] = Self), ClassName + '("' + GetFullName + '").DoHide: Item do not match');
  1088.         if FCurTechnique.Passes[i].RemoveItem(IndexInPass[i]) then
  1089.           TVisible(FCurTechnique.Passes[i].Items[IndexInPass[i]]).IndexInPass[i] := IndexInPass[i];   // ToDo: try to remove
  1090.         IndexInPass[i] := -1;
  1091.       end;
  1092.     end;
  1093.     tkShared: if Assigned((FManager as CAST2.TBaseCore).SharedTesselators) then
  1094.       ((FManager as CAST2.TBaseCore).SharedTesselators as TSharedTesselators).RemoveItem(Self);
  1095.   end;
  1096. end;
  1097. procedure TVisible.DoShow;
  1098. begin
  1099.   VisibilityFlag := True;
  1100.   AddToPasses;
  1101. end;
  1102. procedure TVisible.DoHide;
  1103. begin
  1104.   VisibilityFlag := False;
  1105.   RemoveFromPasses;  
  1106. end;
  1107. procedure TVisible.SetState(const Value: TSet32);
  1108.   procedure PropagateToChilds(Item: TItem; NewState: Boolean);
  1109.   var i: Integer;
  1110.   begin
  1111.     for i := 0 to Item.TotalChilds-1 do begin
  1112.       if (Item.Childs[i] is TVisible) then
  1113. //        if (TVisible(Item.Childs[i]).VisibilityFlag = NewState) then Continue else begin            // No neeed to propagate
  1114.           if NewState then TVisible(Item.Childs[i]).DoShow else TVisible(Item.Childs[i]).DoHide;
  1115. //        end;
  1116.       PropagateToChilds(Item.Childs[i], NewState);
  1117.     end;
  1118.   end;
  1119. var OldState: TItemFlags;
  1120. begin
  1121.   OldState := State;
  1122.   inherited;
  1123.   if isParentsVisible then begin
  1124.     if not (isVisible in OldState) and (isVisible in Value) then begin
  1125.       DoShow;
  1126.       PropagateToChilds(Self, True);
  1127.     end;
  1128.     if (isVisible in OldState) and not (isVisible in Value) then begin
  1129.       DoHide;
  1130.       PropagateToChilds(Self, False);
  1131.     end;
  1132.   end;
  1133. end;
  1134. function TVisible.GetMaterial: TMaterial;
  1135. var LMaterial: TMaterial; Item: TItem;
  1136. begin
  1137.   if ResolveLink('Material', Item) then ;
  1138.   if Assigned(Item) then begin
  1139.     LMaterial := Item as TMaterial;
  1140.     SetCurTechnique(LMaterial.GetTechniqueByLOD(CurrentLOD));
  1141.   end;
  1142.   Result := Item as TMaterial;
  1143. end;
  1144. procedure TVisible.SetMaterial(Value: TMaterial);
  1145. begin
  1146.   SetLinkedObject('Material', Value);
  1147. end;
  1148. procedure TVisible.SetCurTechnique(const Value: TTechnique);
  1149. begin
  1150.   if FCurTechnique = Value then Exit;
  1151.   RemoveFromPasses;
  1152.   FCurTechnique := Value;
  1153.   if Assigned(FCurTechnique) and (FCurTechnique.TotalPasses > Length(IndexInPass)) then begin
  1154.     SetLength(IndexInPass, FCurTechnique.TotalPasses);
  1155.     FillDWord(IndexInPass[0], FCurTechnique.TotalPasses, Cardinal(-1));
  1156.   end;
  1157.   AddToPasses;
  1158. end;
  1159. procedure TVisible.SetTesselatorKind(const Value: TTesselatorKind);
  1160. begin
  1161.   if FTesselatorKind = Value then Exit;
  1162.   RemoveFromPasses;
  1163.   FTesselatorKind := Value;
  1164.   AddToPasses;
  1165. end;
  1166. procedure TVisible.SetParent(NewParent: TItem);
  1167. begin
  1168. //  if isActuallyVisible then DoHide;
  1169.   inherited;
  1170. //  if isActuallyVisible then DoShow;
  1171. end;
  1172. { TTemporaryVisible }
  1173. function TTemporaryVisible.VisibilityCheck(const Camera: TCamera): Boolean;
  1174. begin
  1175.   Result := True;
  1176. end;
  1177. procedure TTemporaryVisible.Clear;
  1178. var i: Integer;
  1179. begin
  1180.   for i := FTotalChilds-1 downto 0 do TVisible(Childs[i]).ClearParent;
  1181.   FTotalChilds := 0;
  1182. end;
  1183. constructor TTemporaryVisible.Create(AManager: TItemsManager);
  1184. begin
  1185.   inherited;
  1186. end;
  1187. destructor TTemporaryVisible.Destroy;
  1188. begin
  1189.   Clear;
  1190.   inherited;
  1191. end;
  1192. { TSharedTesselators }
  1193. function TSharedTesselators.GetItemIndex(const AItem: TVisible): Integer;
  1194. begin
  1195.   Result := TotalItems-1;
  1196.   while (Result >= 0) and (Items[Result] <> AItem) do Dec(Result);
  1197. end;
  1198. function TSharedTesselators.GetTesselatorIndex(const TessClass: CTesselator): Integer;
  1199. begin
  1200.   Result := High(TessClasses);
  1201.   while (Result >= 0) and (TessClasses[Result].TessClass <> TessClass) do Dec(Result);
  1202. end;
  1203. function TSharedTesselators.AddTesselatorClass(const TessClass: CTesselator): Integer;
  1204. begin
  1205.   Assert(GetTesselatorIndex(TessClass) = -1, ClassName + '.AddTesselatorClass: Class already exists');
  1206.   Result := Length(TessClasses);
  1207.   SetLength(TessClasses, Result+1);
  1208.   TessClasses[Result].TessClass := TessClass;
  1209.   TessClasses[Result].TessMap   := BaseCont.TPointerPointerMap.Create(DefaultTechToItemMapCapacity);
  1210. end;
  1211. function TSharedTesselators.GetTesselator(const TessClass: CTesselator; const Technique: TTechnique): TTesselator;
  1212. var ClassIndex: Integer; Item: TVisible;
  1213. begin
  1214.   ClassIndex := GetTesselatorIndex(TessClass);
  1215.   if ClassIndex = -1 then ClassIndex := AddTesselatorClass(TessClass);
  1216.   Item := TVisible(TessClasses[ClassIndex].TessMap[Technique]);
  1217.   if Item = nil then begin
  1218.     Item := TTemporaryVisible.Create(Core);
  1219.     Item.Name := 'Temp visible';
  1220.     Result := TessClass.Create;
  1221.     Item.FCurrentTesselator := Result;
  1222.     TessClasses[ClassIndex].TessMap[Technique] := Item;
  1223.   end else Result := Item.CurrentTesselator;
  1224. end;
  1225. function TSharedTesselators.DrawTechMap(Key, Value: Pointer): Boolean;
  1226. var Technique: TTechnique; Item: TVisible;
  1227. begin
  1228.   Result := False;
  1229.   if (Key = nil) or (Value = nil) then Exit;
  1230.   Technique := TTechnique(Key);
  1231.   Item      := TVisible(Value);
  1232.   Item.SetCurTechnique(Technique);
  1233.   Core.TempItems.AddChild(Item);
  1234. end;
  1235. function TSharedTesselators.DelTechMap(Key, Value: Pointer): Boolean;
  1236. begin
  1237.   Result := False;
  1238.   if (Key = nil) or (Value = nil) then Exit;
  1239.   if Assigned(TVisible(Value).CurrentTesselator) then
  1240.   TSharedTesselator(TVisible(Value).CurrentTesselator).Clear;
  1241. end;
  1242. function TSharedTesselators.FreeTechMap(Key, Value: Pointer): Boolean;
  1243. begin
  1244.   Result := False;
  1245.   if (Key = nil) or (Value = nil) then Exit;
  1246.   TSharedTesselator(TVisible(Value).CurrentTesselator).Free;
  1247. //  Assert(Value <> nil);
  1248.   TVisible(Value).Free;
  1249. end;
  1250. procedure TSharedTesselators.AddItem(const AItem: TVisible);
  1251. begin
  1252.   Assert(GetItemIndex(AItem) = -1, ClassName + '.AddItem: Item already exists');
  1253.   if Length(Items) <= TotalItems then SetLength(Items, Length(Items) + ItemsCapacityStep);
  1254.   Items[TotalItems] := AItem;
  1255.   SetLength(AItem.IndexInPass, 1);
  1256.   AItem.IndexInPass[0] := TotalItems;
  1257.   Inc(TotalItems);
  1258. end;
  1259. procedure TSharedTesselators.RemoveItem(const AItem: TVisible);
  1260. var Index: Integer;
  1261. begin
  1262.   if AItem.IndexInPass = nil then Exit;                                  { TODO -cDebug : Figure out why RemoveItem can be called when IndexInPass = nil }
  1263.   if (AItem.IndexInPass[0] = -1) or (Items[AItem.IndexInPass[0]] = AItem) then Index := AItem.IndexInPass[0] else Index := GetItemIndex(AItem);
  1264.   if Index = -1 then Exit;
  1265.   Assert(TotalItems > 0, ClassName + '.RemoveItem: No items');
  1266. //  Assert(Index <> -1, ClassName + '.RemoveItem: Item not found');
  1267.   while Index < TotalItems-1 do begin
  1268.     Items[Index] := Items[Index+1];
  1269.     Items[Index].IndexInPass[0] := Index;
  1270.     Inc(Index);
  1271.   end;
  1272.   AItem.IndexInPass[0] := -1;
  1273.   Dec(TotalItems);
  1274. end;
  1275. procedure TSharedTesselators.Clear;
  1276. begin
  1277.   TotalItems := 0;
  1278. end;
  1279. procedure TSharedTesselators.Reset;
  1280. var i: Integer;
  1281. begin
  1282.   for i := 0 to High(TessClasses) do TessClasses[i].TessMap.DoForEach({$IFDEF OBJFPCEnable}@{$ENDIF}DelTechMap);
  1283. end;
  1284. procedure TSharedTesselators.Render;
  1285. var i: Integer;
  1286. begin
  1287. //  Items[0].Render;
  1288.   for i := 0 to TotalItems-1 do Items[i].Render;                      // Fill tesselators with commands
  1289.   for i := 0 to High(TessClasses) do TessClasses[i].TessMap.DoForEach({$IFDEF OBJFPCEnable}@{$ENDIF}DrawTechMap);
  1290. end;
  1291. destructor TSharedTesselators.Destroy;
  1292. var i: Integer;
  1293. begin
  1294.   Reset;
  1295.   for i := 0 to High(TessClasses) do begin
  1296.     TessClasses[i].TessMap.DoForEach({$IFDEF OBJFPCEnable}@{$ENDIF}FreeTechMap);
  1297.     FreeAndNil(TessClasses[i].TessMap);
  1298.   end;
  1299.   Clear;
  1300.   Items := nil;
  1301.   TessClasses := nil;
  1302.   inherited;
  1303. end;
  1304. { TLight }
  1305. constructor TLight.Create(AManager: TItemsManager);
  1306. begin
  1307.   inherited;
  1308.   Ambient   := GetColor4S(0.5, 0.5, 0.5, 0.5);
  1309.   Diffuse   := GetColor4S(0.5, 0.5, 0.5, 0.5);
  1310.   Specular  := GetColor4S(0.0, 0.0, 0.0, 0.0);
  1311.   Range     := 1;
  1312.   Theta     := pi/4;
  1313.   Phi       := pi/3;
  1314.   GroupMask := gmDefault
  1315. end;
  1316. procedure TLight.AddProperties(const Result: Props.TProperties);
  1317. var i: Integer;
  1318. begin
  1319.   inherited;
  1320.   if not Assigned(Result) then Exit;
  1321.   Result.AddEnumerated('Type',  [], Ord(Kind), LightKindsEnum);
  1322.   for i := 0 to PassGroupsCount-1 do Result.Add(Format('Pass groupsGroup %D', [i+1]), vtBoolean, [], OnOffStr[i in GroupMask], '');
  1323.   AddColor4sProperty(Result, 'ColorAmbient',  Ambient);
  1324.   AddColor4sProperty(Result, 'ColorDiffuse',  Diffuse);
  1325.   AddColor4sProperty(Result, 'ColorSpecular', Specular);
  1326.   Result.Add('Range',   vtSingle, [], FloatToStr(Range),   '0-100');
  1327.   Result.Add('Falloff', vtSingle, [], FloatToStr(Falloff), '');
  1328.   Result.Add('Constant attenuation',  vtSingle, [], FloatToStr(Attenuation0), '0-10');
  1329.   Result.Add('Linear attenuation',    vtSingle, [], FloatToStr(Attenuation1), '0-10');
  1330.   Result.Add('Quadratic attenuation', vtSingle, [], FloatToStr(Attenuation2), '0-10');
  1331.   Result.Add('Cone inner angle', vtSingle, [], FloatToStr(Theta * 180/pi), '0-180');
  1332.   Result.Add('Cone outer angle', vtSingle, [], FloatToStr(Phi * 180/pi),   '0-180');
  1333. end;
  1334. procedure TLight.SetProperties(Properties: Props.TProperties);
  1335. var i: Integer;
  1336. begin
  1337.   inherited;
  1338.   for i := 0 to PassGroupsCount-1 do
  1339.     if Properties.Valid(Format('Pass groupsGroup %D', [i+1])) then
  1340.       if Properties.GetAsInteger(Format('Pass groupsGroup %D', [i+1])) > 0 then
  1341.         GroupMask := GroupMask + [i] else
  1342.           GroupMask := GroupMask - [i];
  1343.   if Properties.Valid('Type')  then Kind  := Properties.GetAsInteger('Type');
  1344.   SetColor4sProperty(Properties, 'ColorAmbient',  Ambient);
  1345.   SetColor4sProperty(Properties, 'ColorDiffuse',  Diffuse);
  1346.   SetColor4sProperty(Properties, 'ColorSpecular', Specular);
  1347.   if Properties.Valid('Range')   then Range   := StrToFloatDef(Properties['Range'],   0);
  1348.   if Properties.Valid('Falloff') then Falloff := StrToFloatDef(Properties['Falloff'], 0);
  1349.   if Properties.Valid('Constant attenuation')  then Attenuation0 := StrToFloatDef(Properties['Constant attenuation'],  0);
  1350.   if Properties.Valid('Linear attenuation')    then Attenuation1 := StrToFloatDef(Properties['Linear attenuation'],    0);
  1351.   if Properties.Valid('Quadratic attenuation') then Attenuation2 := StrToFloatDef(Properties['Quadratic attenuation'], 0);
  1352.   if Properties.Valid('Cone inner angle') then Theta := StrToFloatDef(Properties['Cone inner angle'], 0) / 180*pi;
  1353.   if Properties.Valid('Cone outer angle') then Phi   := StrToFloatDef(Properties['Cone outer angle'], 0) / 180*pi;
  1354. end;
  1355. function TLight.GetEnabled: Boolean;
  1356. begin
  1357.   Result := isVisible in FState;
  1358. end;
  1359. procedure TLight.SetEnabled(const Value: Boolean);
  1360. begin
  1361.   if Value then FState := FState + [isVisible] else FState := FState - [isVisible];
  1362. end;
  1363. procedure TLight.HandleMessage(const Msg: TMessage);
  1364. begin
  1365.   inherited;
  1366.   if Msg.ClassType = ItemMsg.TReplaceMsg then with ItemMsg.TReplaceMsg(Msg) do if (OldItem = Self) then begin
  1367.   end;
  1368. end;
  1369. procedure TLight.SetState(const Value: TSet32);
  1370. begin
  1371.   if not (isVisible in FState) and (isVisible in Value) then Enabled := True;
  1372.   if (isVisible in FState) and not (isVisible in Value) then Enabled := False;
  1373.   inherited;
  1374. end;
  1375. { TMappedTesselator }
  1376. function TMappedTesselator.GetBoundingBox: TBoundingBox;
  1377. begin
  1378.   Result := EmptyBoundingBox;
  1379.   if not Assigned(FMap) or (FMap.Width = 0) or (FMap.Height = 0) then Exit;
  1380.   Result.P1 := GetVector3s(-(FMap.Width-1)  * FMap.CellWidthScale * 0.5,
  1381.                             0,
  1382.                            -(FMap.Height-1) * FMap.CellHeightScale * 0.5);
  1383.   Result.P2 := GetVector3s( (FMap.Width-1)  * FMap.CellWidthScale * 0.5,
  1384.                             FMap.MaxHeight * FMap.DepthScale,
  1385.                             (FMap.Height-1) * FMap.CellHeightScale * 0.5);
  1386. end;
  1387. procedure TMappedTesselator.SetMap(const AMap: TMap);
  1388. begin
  1389.   FMap := AMap;
  1390. end;
  1391. function TMappedTesselator.GetMaxVertices: Integer;
  1392. begin
  1393.   Result := 0;
  1394.   if not Assigned(FMap) then Exit;
  1395. //  Result := (FMap.Width) * (FMap.Height);
  1396.   if (FMap.Width <> OldWidth) or (FMap.Height <> OldHeight) or
  1397.      (FMap.CellWidthScale <> OldCellWidthScale) or (FMap.CellHeightScale <> OldCellHeightScale) or
  1398.      (FMap.DepthScale <> OldDepthScale) then Init;
  1399.   Result := inherited GetMaxVertices;
  1400. end;
  1401. procedure TMappedTesselator.Init;
  1402. begin
  1403.   inherited;
  1404.   if Assigned(FMap) then begin
  1405.     OldWidth           := FMap.Width;
  1406.     OldHeight          := FMap.Height;
  1407.     OldCellWidthScale  := FMap.CellWidthScale;
  1408.     OldCellHeightScale := FMap.CellHeightScale;
  1409.     OldDepthScale      := FMap.DepthScale;
  1410.   end else begin
  1411.     TotalVertices   := 0;
  1412.     TotalIndices    := 0;
  1413.     TotalPrimitives := 0;
  1414.   end;
  1415.   InvalidateBoundingBox;
  1416.   Invalidate([tbVertex, tbIndex], True);
  1417. end;
  1418. { TMappedItem }
  1419. const MapPropName = 'Map';
  1420. procedure TMappedItem.ResolveLinks;
  1421. var i: Integer; Item: TItem;
  1422. begin
  1423.   inherited;
  1424.   ResolveLink(MapPropName, Item);
  1425.   if Assigned(Item) then begin
  1426.     FMap := Item as C2Maps.TMap;
  1427.     for i := 0 to High(FTesselators) do if FTesselators[i] is TMappedTesselator then begin
  1428.       (FTesselators[i] as TMappedTesselator).SetMap(Item as C2Maps.TMap);
  1429.       FTesselators[i].Init;
  1430.     end;
  1431.   end;
  1432. end;
  1433. procedure TMappedItem.OnModify(const ARect: TRect);
  1434. begin
  1435. end;
  1436. class function TMappedItem.IsAbstract: Boolean;
  1437. begin
  1438.   Result := Self = TMappedItem;
  1439. end;
  1440. procedure TMappedItem.SetMesh;
  1441. begin
  1442.   inherited;
  1443.   (CurrentTesselator as TMappedTesselator).Item := Self;
  1444. end;
  1445. procedure TMappedItem.AddProperties(const Result: Props.TProperties);
  1446. begin
  1447.   inherited;
  1448.   if Assigned(Result) then begin
  1449.   end;
  1450.   AddItemLink(Result, MapPropName, [], 'TMap');
  1451. end;
  1452. procedure TMappedItem.SetProperties(Properties: Props.TProperties);
  1453. begin
  1454.   inherited;
  1455.   if Properties.Valid(MapPropName) then SetLinkProperty(MapPropName, Properties[MapPropName]);
  1456.   ResolveLinks;
  1457. end;
  1458. procedure TMappedItem.HandleMessage(const Msg: TMessage);
  1459. begin
  1460.   inherited;
  1461.   {$IFDEF EDITORMODE}
  1462.   if Msg.ClassType = TMapDrawCursorMsg  then with TMapDrawCursorMsg(Msg) do DrawCursor(Cursor, Cursor.Camera, Cursor.Screen);
  1463.   if Msg.ClassType = TMapModifyBeginMsg then with TMapEditorMessage(Msg) do ModifyBegin(Cursor, Cursor.Camera);
  1464.   if Msg.ClassType = TMapModifyMsg      then with TMapEditorMessage(Msg) do Modify(Cursor, Cursor.Camera);
  1465.   if Msg.ClassType = TMapModifyEndMsg   then with TMapEditorMessage(Msg) do ModifyEnd(Cursor, Cursor.Camera);
  1466.   if Msg.ClassType = TRequestMapEditVisuals then with TRequestMapEditVisuals(Msg) do begin
  1467.     Cursor.Params.Add('Size', vtNat, [], '1', '1-64', '');
  1468.     Cursor.Params.AddEnumerated('Mode', [], 0, 'Heights&Smooth');
  1469.   end;
  1470.   {$ENDIF}
  1471.   if (Msg.ClassType = TItemModifiedMsg) and (TItemModifiedMsg(Msg).Item = Map) then CurrentTesselator.Invalidate([tbVertex, tbIndex], False);
  1472. end;
  1473. function TMappedItem.PickCell(Camera: TCamera; MouseX, MouseY: Integer; out CellX, CellZ: Integer): Boolean;
  1474. var CameraPos, PickRay, PickPos: TVector3s; M: TMatrix4s;
  1475. begin
  1476.   Result := False;
  1477.   if not Assigned(FMap) then Exit;
  1478.   // Transform camera position and pick ray to model space
  1479.   M := InvertMatrix4s(Transform);
  1480.   CameraPos := Transform4Vector33s(M, Camera.Position);
  1481.   PickRay := Camera.GetPickRay(MouseX, MouseY);
  1482.   PickRay := Transform3Vector3s(CutMatrix3s(InvertAffineMatrix4s(Camera.ViewMatrix)), PickRay);
  1483.   PickRay.Y := PickRay.Y;
  1484.   PickRay := NormalizeVector3s(Transform3Vector3s(CutMatrix3s(M), PickRay));
  1485.   Result := FMap.TraceRay(CameraPos, PickRay, PickPos);
  1486.   if Result then Map.ObtainCell(PickPos.X, PickPos.Z, CellX, CellZ);
  1487. end;
  1488. {$IFDEF EDITORMODE}
  1489. function TMappedItem.DrawCursor(Cursor: TMapCursor; Camera: TCamera; Screen: TScreen): Boolean;
  1490.   procedure DrawCell(CellX, CellZ: Integer);
  1491.     function CalcLinePos: TVector3s;
  1492.     begin
  1493.       Result.X := (CellX - (FMap.Width -1) * 0.5) * FMap.CellWidthScale;
  1494.       Result.Y := FMap[CellX, CellZ] * FMap.DepthScale;
  1495.       Result.Z := (CellZ - (FMap.Height-1) * 0.5) * FMap.CellHeightScale;
  1496.       Result := Transform4Vector33s(Transform, Result);
  1497.     end;
  1498.     
  1499.   begin
  1500.     if (CellX < 1) or (CellZ < 1) or (CellX > FMap.Width-2) or (CellZ > FMap.Height-2) then Exit;
  1501.     Screen.MoveToVec(Camera.Project(CalcLinePos).xyz);
  1502.     Inc(CellX);
  1503.     Screen.LineToVec(Camera.Project(CalcLinePos).xyz);
  1504.     Inc(CellZ);
  1505.     Screen.LineToVec(Camera.Project(CalcLinePos).xyz);
  1506.     Dec(CellX);
  1507.     Screen.LineToVec(Camera.Project(CalcLinePos).xyz);
  1508.     Dec(CellZ);
  1509.     Screen.LineToVec(Camera.Project(CalcLinePos).xyz);
  1510.   end;
  1511.   procedure DrawCursorAt(CellX, CellZ, Size: Integer);
  1512.   var i, j: Integer;
  1513.   begin
  1514. //    Screen.MoveTo(0, 0);
  1515. //    Screen.LineTo(0, 0);
  1516.     for i := CellX - Size div 2 to CellX + Size div 2 do
  1517.       for j := CellZ - Size div 2 to CellZ + Size div 2 do DrawCell(i, j);
  1518.   end;
  1519. begin
  1520.   Result := False;
  1521.   if not Assigned(FMap) or not EditMode and not PickCell(Camera, Cursor.MouseX, Cursor.MouseY, EditCellX, EditCellZ) then Exit;
  1522.   DrawCursorAt(EditCellX, EditCellZ, Cursor.Params.GetAsInteger('Size'));
  1523.   Result := True;
  1524. end;
  1525. procedure TMappedItem.ModifyBegin(Cursor: TMapCursor; Camera: TCamera);
  1526. var Op: THeighTMapEditOp;
  1527. begin
  1528.   if FMap.Data = nil then Exit;
  1529.   EditMouseX     := Cursor.MouseX;
  1530.   EditMouseY     := Cursor.MouseY;
  1531.   EditCursorSize := ClampI(Cursor.Params.GetAsInteger('Size'), 1, MaxCursorSize);
  1532.   case Cursor.Params.GetAsInteger('Mode') of
  1533.     hmemSmooth: begin
  1534.       EditMode := True;
  1535.       Modify(Cursor, Camera);      
  1536.       Exit;
  1537.     end;
  1538.   end;
  1539.   if PickCell(Camera, Cursor.MouseX, Cursor.MouseY, EditCellX, EditCellZ) then begin
  1540.     EditMode := True;
  1541.     case Cursor.Params.GetAsInteger('Mode') of
  1542.       hmemAdjust: begin
  1543.         Op := THeighTMapEditOpAdjust.Create;
  1544.         Include(Op.Flags, ofIntermediate);
  1545.         Cursor.Operation := Op;
  1546.       end;
  1547.     end;
  1548.   end else EditMode := False;
  1549. end;
  1550. procedure TMappedItem.Modify(Cursor: TMapCursor; Camera: TCamera);
  1551. var Op: THeighTMapEditOp;
  1552. begin
  1553.   if not EditMode or (FMap.Data = nil) then Exit;
  1554.   case Cursor.Params.GetAsInteger('Mode') of
  1555.     hmemAdjust: begin
  1556.       Assert(Cursor.Operation is THeighTMapEditOpAdjust);
  1557.       with THeighTMapEditOpAdjust(Cursor.Operation) do begin
  1558.         OnModify(GetRect(EditCellX - EditCursorSize, EditCellZ - EditCursorSize, EditCellX + EditCursorSize+1, EditCellZ + EditCursorSize+1));
  1559.         Apply;                                       // Undo previous iteration
  1560.         Init(FMap, EditCellX, EditCellZ, EditCursorSize, Cursor.MouseY - EditMouseY);
  1561.       end;
  1562.     end;
  1563.     hmemSmooth: if PickCell(Camera, Cursor.MouseX, Cursor.MouseY, EditCellX, EditCellZ) then begin
  1564.       Op := THeighTMapEditOpSmooth.Create;
  1565.       if Op.Init(FMap, EditCellX, EditCellZ, EditCursorSize, Cursor.MouseY - EditMouseY) then
  1566.         Cursor.Operation := Op else
  1567.           Op.Free;
  1568.       OnModify(GetRect(EditCellX - EditCursorSize, EditCellZ - EditCursorSize, EditCellX + EditCursorSize+1, EditCellZ + EditCursorSize+1));
  1569.     end;
  1570.     else Assert(False);
  1571.   end;
  1572. end;
  1573. procedure TMappedItem.ModifyEnd(Cursor: TMapCursor; Camera: TCamera);
  1574. begin
  1575.   EditMode := False;
  1576.   case Cursor.Params.GetAsInteger('Mode') of
  1577.     hmemAdjust: begin
  1578.       Assert(Cursor.Operation is THeighTMapEditOpAdjust);
  1579.       with THeighTMapEditOpAdjust(Cursor.Operation) do begin
  1580.         Apply;                                       // Undo previous iteration
  1581.         if Init(FMap, EditCellX, EditCellZ, EditCursorSize, Cursor.MouseY - EditMouseY) then
  1582.           Exclude(Cursor.Operation.Flags, ofIntermediate) else
  1583.             FreeAndNil(Cursor.Operation);
  1584.       end;
  1585.     end;
  1586.     else OnModify(GetRect(EditCellX - EditCursorSize, EditCellZ - EditCursorSize, EditCellX + EditCursorSize+1, EditCellZ + EditCursorSize+1));
  1587.   end;
  1588. end;
  1589. {$ENDIF}
  1590. { THeighTMapEditOpAdjust }
  1591. function THeighTMapEditOpAdjust.Init(AMap: TMap; ACellX, ACellZ, ACursorSize: Integer; AValueDelta: Single): Boolean;
  1592. var i, j, StartI, StartJ, OfsI, OfsJ: Integer; Value, norm: Single;
  1593. begin
  1594.   Result := False;
  1595.   if (ACursorSize = 0) or not Assigned(AMap) or (Abs(AValueDelta) < epsilon) then Exit;
  1596.   Scale      := -1;
  1597.   Map        := AMap;
  1598.   CellX      := ACellX;
  1599.   CellZ      := ACellZ;
  1600.   CursorSize := ACursorSize;
  1601.   GetMem(Buffer, CursorSize * CursorSize * Map.ElementSize);
  1602.   Result := True;
  1603.   StartI := CellX - CursorSize div 2;
  1604.   if StartI < 0 then begin
  1605.     OfsI   := -StartI;
  1606.     StartI := 0;
  1607.   end else OfsI := 0;
  1608.   StartJ := CellZ - CursorSize div 2;
  1609.   if StartJ < 0 then begin
  1610.     OfsJ   := -StartJ;
  1611.     StartJ := 0;
  1612.   end else OfsJ := 0;
  1613.   norm := 1 / Sqr(CursorSize*0.5);
  1614.   case Map.ElementSize of
  1615.     1: for j := StartJ to MinI(Map.Height-1, CellZ - CursorSize div 2 + CursorSize-1) do
  1616.          for i := StartI to MinI(Map.Width-1, CellX - CursorSize div 2 + CursorSize-1) do begin
  1617.       Value := PByteBuffer (Map.Data)^[(j * Map.Width + i)];
  1618.       Value := ClampS(Value + AValueDelta * Scale * MaxS(0, (1-(Sqr(i-CellX) + Sqr(j-CellZ)) * norm)), 0, Map.MaxHeight);
  1619.       PByteBuffer (Buffer)^[((j-StartJ + OfsJ) * CursorSize + i - StartI + OfsI)]     := Round(Value);
  1620.     end;
  1621.     2: for j := StartJ to MinI(Map.Height-1, CellZ - CursorSize div 2 + CursorSize-1) do
  1622.          for i := StartI to MinI(Map.Width-1, CellX - CursorSize div 2 + CursorSize-1) do begin
  1623.       Value := PWordBuffer (Map.Data)^[(j * Map.Width + i) * 2];
  1624.       Value := ClampS(Value + AValueDelta * Scale * MaxS(0, (1-(Sqr(i-CellX) + Sqr(j-CellZ)) * norm)), 0, Map.MaxHeight);
  1625.       PWordBuffer (Buffer)^[((j-StartJ + OfsJ) * CursorSize + i - StartI + OfsI) * 2] := Round(Value);
  1626.     end;
  1627.     4: for j := StartJ to MinI(Map.Height-1, CellZ - CursorSize div 2 + CursorSize-1) do
  1628.          for i := StartI to MinI(Map.Width-1, CellX - CursorSize div 2 + CursorSize-1) do begin
  1629.       Value := PDWordBuffer(Map.Data)^[(j * Map.Width + i) * 4];
  1630.       Value := ClampS(Value + AValueDelta * Scale * MaxS(0, (1-(Sqr(i-CellX) + Sqr(j-CellZ)) * norm)), 0, Map.MaxHeight);
  1631.       PDWordBuffer(Buffer)^[((j-StartJ + OfsJ) * CursorSize + i - StartI + OfsI) * 4] := Round(Value);
  1632.     end;
  1633.   end;
  1634. end;
  1635. { THeighTMapEditOpSmooth }
  1636. function THeighTMapEditOpSmooth.Init(AMap: TMap; ACellX, ACellZ, ACursorSize: Integer; AValueDelta: Single): Boolean;
  1637. var i, j, i1, i2, j1, j2, StartI, StartJ, OfsI, OfsJ: Integer; Value, norm, k: Single;
  1638. begin
  1639.   Result := False;
  1640.   if (ACursorSize = 0) or not Assigned(AMap) then Exit;
  1641.   Scale      := -1;
  1642.   Map        := AMap;
  1643.   CellX      := ACellX;
  1644.   CellZ      := ACellZ;
  1645.   CursorSize := ACursorSize;
  1646.   GetMem(Buffer, CursorSize * CursorSize * Map.ElementSize);
  1647.   Result := True;
  1648.   StartI := CellX - CursorSize div 2;
  1649.   if StartI < 0 then begin
  1650.     OfsI   := -StartI;
  1651.     StartI := 0;
  1652.   end else OfsI := 0;
  1653.   StartJ := CellZ - CursorSize div 2;
  1654.   if StartJ < 0 then begin
  1655.     OfsJ   := -StartJ;
  1656.     StartJ := 0;
  1657.   end else OfsJ := 0;
  1658.   norm := 1 / {Sqr}(CursorSize*0.5);
  1659.   case Map.ElementSize of
  1660.     1: for j := StartJ to MinI(Map.Height-1, CellZ - CursorSize div 2 + CursorSize-1) do
  1661.          for i := StartI to MinI(Map.Width-1, CellX - CursorSize div 2 + CursorSize-1) do begin
  1662.       i1 := MaxI(i-1, 0);
  1663.       j1 := MaxI(j-1, 0);
  1664.       i2 := MinI(i+1, Map.Width-1);
  1665.       j2 := MinI(j+1, Map.Height-1);
  1666.       Value := (PByteBuffer (Map.Data)^[j1 * Map.Width + i1] +
  1667.                 PByteBuffer (Map.Data)^[j1 * Map.Width + i] +
  1668.                 PByteBuffer (Map.Data)^[j1 * Map.Width + i2] +
  1669.                 PByteBuffer (Map.Data)^[j * Map.Width + i1] +
  1670. //                PByteBuffer (Map.Data)^[(j * Map.Width + i)] +
  1671.                 PByteBuffer (Map.Data)^[j * Map.Width + i2] +
  1672.                 PByteBuffer (Map.Data)^[j2 * Map.Width + i1] +
  1673.                 PByteBuffer (Map.Data)^[j2 * Map.Width + i] +
  1674.                 PByteBuffer (Map.Data)^[j2 * Map.Width + i2]) div 8;
  1675. //      Value := ClampS(Value, 0, Map.MaxHeight);
  1676.       k := MaxS(0, (1-Sqrt(Sqr(i-CellX) + Sqr(j-CellZ)) * norm));
  1677.       Value := ClampS(PByteBuffer (Map.Data)^[(j * Map.Width + i)] * (1-k) +
  1678.                       Value * k, 0, Map.MaxHeight);
  1679.       PByteBuffer (Buffer)^[((j-StartJ + OfsJ) * CursorSize + i - StartI + OfsI)]     := Round(Value);
  1680.     end;
  1681.     2: ;//Value := PWordBuffer (Map.Data)^[(j * Map.Width + i) * 2];
  1682.     4: ;//Value := PDWordBuffer(Map.Data)^[(j * Map.Width + i) * 4];
  1683.   end;
  1684. {      case Map.ElementSize of
  1685.         1:
  1686.         2: PWordBuffer (Buffer)^[((j-StartJ + OfsJ) * CursorSize + i - StartI + OfsI) * 2] := Round(Value);
  1687.         4: PDWordBuffer(Buffer)^[((j-StartJ + OfsJ) * CursorSize + i - StartI + OfsI) * 4] := Round(Value);
  1688.       end;
  1689.     end;}
  1690. end;
  1691. end.