123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit GXS.Feedback;
- (*
- A scene object encapsulating the OpenGL feedback buffer.
- This object, when Active, will render it's children using
- the GL_FEEDBACK render mode. This will render the children
- into the feedback Buffer rather than into the frame buffer.
- Mesh data can be extracted from the buffer using the
- BuildMeshFromBuffer procedure. For custom parsing of the
- buffer use the Buffer SingleList. The Buffered property
- will indicate if there is valid data in the buffer.
- *)
- interface
- {$I Stage.Defines.inc}
- uses
- Winapi.OpenGL,
- Winapi.OpenGLext,
- System.Classes,
- System.SysUtils,
- GXS.PersistentClasses,
- Stage.VectorGeometry,
- GXS.VectorLists,
- Stage.VectorTypes,
- Stage.Strings,
- GXS.Scene,
- GXS.VectorFileObjects,
- GXS.Texture,
- GXS.RenderContextInfo,
- GXS.Context,
- GXS.State,
- Stage.PipelineTransform,
- GXS.MeshUtils;
- type
- TFeedbackMode = (fm2D, fm3D, fm3DColor, fm3DColorTexture, fm4DColorTexture);
- // An object encapsulating the feedback rendering mode.
- TgxFeedback = class(TgxBaseSceneObject)
- private
- FActive: Boolean;
- FBuffer: TgxSingleList;
- FMaxBufferSize: Cardinal;
- FBuffered: Boolean;
- FCorrectionScaling: Single;
- FMode: TFeedbackMode;
- protected
- procedure SetMaxBufferSize(const Value: Cardinal);
- procedure SetMode(const Value: TFeedbackMode);
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure DoRender(var ARci: TgxRenderContextInfo;
- ARenderSelf, ARenderChildren: Boolean); override;
- (* Parse the feedback buffer for polygon data and build
- a mesh into the assigned lists. *)
- procedure BuildMeshFromBuffer(
- Vertices: TgxAffineVectorList = nil;
- Normals: TgxAffineVectorList = nil;
- Colors: TgxVectorList = nil;
- TexCoords: TgxAffineVectorList = nil;
- VertexIndices: TgxIntegerList = nil);
- // True when there is data in the buffer ready for parsing
- property Buffered: Boolean read FBuffered;
- // The feedback buffer
- property Buffer: TgxSingleList read FBuffer;
- (* Vertex positions in the buffer needs to be scaled by
- CorrectionScaling to get correct coordinates. *)
- property CorrectionScaling: Single read FCorrectionScaling;
- published
- // Maximum size allocated for the feedback buffer
- property MaxBufferSize: Cardinal read FMaxBufferSize write SetMaxBufferSize;
- // Toggles the feedback rendering
- property Active: Boolean read FActive write FActive;
- // The type of data that is collected in the feedback buffer
- property Mode: TFeedbackMode read FMode write SetMode;
- property Visible;
- end;
- // ----------------------------------------------------------------------
- implementation
- // ----------------------------------------------------------------------
- // ----------
- // ---------- TgxFeedback ----------
- // ----------
- constructor TgxFeedback.Create(AOwner: TComponent);
- begin
- inherited;
- FMaxBufferSize := $100000;
- FBuffer := TgxSingleList.Create;
- FBuffer.Capacity := FMaxBufferSize div SizeOf(Single);
- FBuffered := False;
- FActive := False;
- FMode := fm3DColorTexture;
- end;
- destructor TgxFeedback.Destroy;
- begin
- FBuffer.Free;
- inherited;
- end;
- procedure TgxFeedback.DoRender(var ARci: TgxRenderContextInfo;
- ARenderSelf, ARenderChildren: Boolean);
- function RecursChildRadius(obj: TgxBaseSceneObject): Single;
- var
- i: Integer;
- childRadius: Single;
- begin
- childRadius := 0;
- Result := obj.BoundingSphereRadius + VectorLength(obj.AbsolutePosition);
- for i := 0 to obj.Count - 1 do
- childRadius := RecursChildRadius(obj.Children[i]);
- if childRadius > Result then
- Result := childRadius;
- end;
- var
- i: integer;
- radius: Single;
- atype: cardinal;
- begin
- FBuffer.Count := 0;
- try
- if (csDesigning in ComponentState) or not Active then
- exit;
- if not ARenderChildren then
- exit;
- FCorrectionScaling := 1.0;
- for i := 0 to Count - 1 do
- begin
- radius := RecursChildRadius(Children[i]);
- if radius > FCorrectionScaling then
- FCorrectionScaling := radius + 1e-5;
- end;
- case FMode of
- fm2D: aType := GL_2D;
- fm3D: aType := GL_3D;
- fm3DColor: aType := GL_3D_COLOR;
- fm3DColorTexture: aType := GL_3D_COLOR_TEXTURE;
- fm4DColorTexture: aType := GL_4D_COLOR_TEXTURE;
- else
- aType := GL_3D_COLOR_TEXTURE;
- end;
- FBuffer.Count := FMaxBufferSize div SizeOf(Single);
- glFeedBackBuffer(FMaxBufferSize, atype, @FBuffer.List[0]);
- ARci.gxStates.Disable(stCullFace);
- ARci.ignoreMaterials := FMode < fm3DColor;
- ARci.PipelineTransformation.Push;
- ARci.PipelineTransformation.SetProjectionMatrix(IdentityHmgMatrix);
- ARci.PipelineTransformation.SetViewMatrix(
- CreateScaleMatrix(VectorMake(
- 1.0 / FCorrectionScaling,
- 1.0 / FCorrectionScaling,
- 1.0 / FCorrectionScaling)));
- ARci.gxStates.ViewPort := Vector4iMake(-1, -1, 2, 2);
- glRenderMode(GL_FEEDBACK);
- Self.RenderChildren(0, Count - 1, ARci);
- FBuffer.Count := glRenderMode(GL_RENDER);
- ARci.PipelineTransformation.Pop;
- finally
- ARci.ignoreMaterials := False;
- FBuffered := (FBuffer.Count > 0);
- if ARenderChildren then
- Self.RenderChildren(0, Count - 1, ARci);
- end;
- ARci.gxStates.ViewPort :=
- Vector4iMake(0, 0, ARci.viewPortSize.cx, ARci.viewPortSize.cy);
- end;
- procedure TgxFeedback.BuildMeshFromBuffer(
- Vertices: TgxAffineVectorList = nil;
- Normals: TgxAffineVectorList = nil;
- Colors: TgxVectorList = nil;
- TexCoords: TgxAffineVectorList = nil;
- VertexIndices: TgxIntegerList = nil);
- var
- value: Single;
- i, j, LCount, skip: Integer;
- vertex, color, texcoord: TVector4f;
- tempVertices, tempNormals, tempTexCoords: TgxAffineVectorList;
- tempColors: TgxVectorList;
- tempIndices: TgxIntegerList;
- ColorBuffered, TexCoordBuffered: Boolean;
- begin
- Assert(FMode <> fm2D, 'Cannot build mesh from fm2D feedback mode.');
- tempVertices := TgxAffineVectorList.Create;
- tempColors := TgxVectorList.Create;
- tempTexCoords := TgxAffineVectorList.Create;
- ColorBuffered := (FMode = fm3DColor) or
- (FMode = fm3DColorTexture) or
- (FMode = fm4DColorTexture);
- TexCoordBuffered := (FMode = fm3DColorTexture) or
- (FMode = fm4DColorTexture);
- i := 0;
- skip := 3;
- if FMode = fm4DColorTexture then
- Inc(skip, 1);
- if ColorBuffered then
- Inc(skip, 4);
- if TexCoordBuffered then
- Inc(skip, 4);
- while i < FBuffer.Count - 1 do
- begin
- value := FBuffer[i];
- if value = GL_POLYGON_TOKEN then
- begin
- Inc(i);
- value := FBuffer[i];
- LCount := Round(value);
- Inc(i);
- if LCount = 3 then
- begin
- for j := 0 to 2 do
- begin
- vertex.X := FBuffer[i];
- Inc(i);
- vertex.Y := FBuffer[i];
- Inc(i);
- vertex.Z := FBuffer[i];
- Inc(i);
- if FMode = fm4DColorTexture then
- Inc(i);
- if ColorBuffered then
- begin
- color.X := FBuffer[i];
- Inc(i);
- color.Y := FBuffer[i];
- Inc(i);
- color.Z := FBuffer[i];
- Inc(i);
- color.W := FBuffer[i];
- Inc(i);
- end;
- if TexCoordBuffered then
- begin
- texcoord.X := FBuffer[i];
- Inc(i);
- texcoord.Y := FBuffer[i];
- Inc(i);
- texcoord.Z := FBuffer[i];
- Inc(i);
- texcoord.W := FBuffer[i];
- Inc(i);
- end;
- vertex.Z := 2 * vertex.Z - 1;
- ScaleVector(vertex, FCorrectionScaling);
- tempVertices.Add(AffineVectorMake(vertex));
- tempColors.Add(color);
- tempTexCoords.Add(AffineVectorMake(texcoord));
- end;
- end
- else
- begin
- Inc(i, skip * LCount);
- end;
- end
- else
- begin
- Inc(i);
- end;
- end;
- if Assigned(VertexIndices) then
- begin
- tempIndices := BuildVectorCountOptimizedIndices(tempVertices, nil, nil);
- RemapAndCleanupReferences(tempVertices, tempIndices);
- VertexIndices.Assign(tempIndices);
- end
- else
- begin
- tempIndices := TgxIntegerList.Create;
- tempIndices.AddSerie(0, 1, tempVertices.Count);
- end;
- tempNormals := BuildNormals(tempVertices, tempIndices);
- if Assigned(Vertices) then
- Vertices.Assign(tempVertices);
- if Assigned(Normals) then
- Normals.Assign(tempNormals);
- if Assigned(Colors) and ColorBuffered then
- Colors.Assign(tempColors);
- if Assigned(TexCoords) and TexCoordBuffered then
- TexCoords.Assign(tempTexCoords);
- tempVertices.Destroy;
- tempNormals.Destroy;
- tempColors.Destroy;
- tempTexCoords.Destroy;
- tempIndices.Destroy;
- end;
- procedure TgxFeedback.SetMaxBufferSize(const Value: Cardinal);
- begin
- if Value <> FMaxBufferSize then
- begin
- FMaxBufferSize := Value;
- FBuffered := False;
- FBuffer.Count := 0;
- FBuffer.Capacity := FMaxBufferSize div SizeOf(Single);
- end;
- end;
- procedure TgxFeedback.SetMode(const Value: TFeedbackMode);
- begin
- if Value <> FMode then
- begin
- FMode := Value;
- FBuffered := False;
- FBuffer.Count := 0;
- end;
- end;
- initialization
- RegisterClasses([TgxFeedback]);
- end.
|