source: trunk/Packages/bgrabitmap/bgrascene3d.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 46.0 KB
Line 
1unit BGRAScene3D;
2
3{$mode objfpc}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, BGRABitmapTypes, BGRAColorInt,
9 BGRASSE, BGRAMatrix3D,
10 BGRASceneTypes, BGRARenderer3D;
11
12type
13 TProjection3D = BGRAMatrix3D.TProjection3D;
14 TLightingNormal3D = BGRASceneTypes.TLightingNormal3D;
15 TLightingInterpolation3D = BGRASceneTypes.TLightingInterpolation3D;
16 TAntialiasingMode3D = BGRASceneTypes.TAntialiasingMode3D;
17 TPerspectiveMode3D = BGRASceneTypes.TPerspectiveMode3D;
18 TRenderingOptions = BGRASceneTypes.TRenderingOptions;
19
20 IBGRAVertex3D = BGRASceneTypes.IBGRAVertex3D;
21 IBGRANormal3D = BGRASceneTypes.IBGRANormal3D;
22 IBGRALight3D = BGRASceneTypes.IBGRALight3D;
23 IBGRADirectionalLight3D = BGRASceneTypes.IBGRADirectionalLight3D;
24 IBGRAPointLight3D = BGRASceneTypes.IBGRAPointLight3D;
25 IBGRAMaterial3D = BGRASceneTypes.IBGRAMaterial3D;
26 IBGRAFace3D = BGRASceneTypes.IBGRAFace3D;
27 IBGRAPart3D = BGRASceneTypes.IBGRAPart3D;
28 IBGRAObject3D = BGRASceneTypes.IBGRAObject3D;
29
30 arrayOfIBGRAVertex3D = BGRASceneTypes.arrayOfIBGRAVertex3D;
31
32const
33 lnNone = BGRASceneTypes.lnNone;
34 lnFace = BGRASceneTypes.lnFace;
35 lnVertex = BGRASceneTypes.lnVertex;
36 lnFaceVertexMix = BGRASceneTypes.lnFaceVertexMix;
37
38 liLowQuality = BGRASceneTypes.liLowQuality;
39 liSpecularHighQuality = BGRASceneTypes.liSpecularHighQuality;
40 liAlwaysHighQuality = BGRASceneTypes.liAlwaysHighQuality;
41
42 am3dNone = BGRASceneTypes.am3dNone;
43 am3dMultishape = BGRASceneTypes.am3dMultishape;
44 am3dResample = BGRASceneTypes.am3dResample;
45
46 pmLinearMapping = BGRASceneTypes.pmLinearMapping;
47 pmPerspectiveMapping = BGRASceneTypes.pmPerspectiveMapping;
48 pmZBuffer = BGRASceneTypes.pmZBuffer;
49
50type
51
52 { TCamera3D }
53
54 TCamera3D = class
55 private
56 procedure ComputeMatrix;
57 function GetLookWhere: TPoint3D;
58 function GetMatrix: TMatrix3D;
59 function GetViewPoint: TPoint3D;
60 procedure SetMatrix(AValue: TMatrix3D);
61 procedure SetViewPoint(AValue: TPoint3D);
62 protected
63 FMatrix: TMatrix3D;
64 FMatrixComputed: boolean;
65 FViewPoint: TPoint3D_128;
66 FLookWhere, FTopDir: TPoint3D_128;
67 public
68 procedure LookAt(AWhere: TPoint3D; ATopDir: TPoint3D);
69 procedure LookDown(angleDeg: single);
70 procedure LookLeft(angleDeg: single);
71 procedure LookRight(angleDeg: single);
72 procedure LookUp(angleDeg: single);
73 property ViewPoint: TPoint3D read GetViewPoint write SetViewPoint;
74 property LookWhere: TPoint3D read GetLookWhere;
75 property Matrix: TMatrix3D read GetMatrix write SetMatrix;
76 end;
77
78 { TBGRAScene3D }
79
80 TBGRAScene3D = class
81 private
82 FSurface: TBGRACustomBitmap; //destination of software renderer
83 FViewCenter: TPointF; //where origin is drawn
84 FAutoViewCenter: boolean; //use middle of the screen
85 FZoom: TPointF; //how much the drawing is zoomed
86 FAutoZoom: Boolean; //display 1 as 80% of surface size
87 FProjection: TProjection3D; //current projection
88 FRenderedFaceCount: integer; //current counter of rendered faces
89
90 FCamera: TCamera3D;
91
92 FObjects: array of IBGRAObject3D;
93 FObjectCount: integer;
94 FMaterials: array of IBGRAMaterial3D;
95 FMaterialCount: integer;
96 FDefaultMaterial : IBGRAMaterial3D;
97
98 FAmbiantLightColorF: TColorF; //lightness without light sources
99 FLights: TList; //individual light sources
100
101 function GetAmbiantLightColorF: TColorF;
102 function GetAmbiantLightness: single;
103 function GetAmbiantLightColor: TBGRAPixel;
104 function GetFaceCount: integer;
105 function GetLight(AIndex: integer): IBGRALight3D;
106 function GetLightCount: integer;
107 function GetMaterial(AIndex: integer): IBGRAMaterial3D;
108 function GetNormalCount: integer;
109 function GetObject(AIndex: integer): IBGRAObject3D;
110 function GetVertexCount: integer;
111 function GetViewCenter: TPointF;
112 function GetViewPoint: TPoint3D;
113 function GetZoom: TPointF;
114 procedure SetAmbiantLightColorF(const AValue: TColorF);
115 procedure SetAmbiantLightness(const AValue: single);
116 procedure SetAmbiantLightColor(const AValue: TBGRAPixel);
117 procedure SetAutoViewCenter(const AValue: boolean);
118 procedure SetAutoZoom(const AValue: boolean);
119 procedure SetViewCenter(const AValue: TPointF);
120 procedure SetViewPoint(const AValue: TPoint3D);
121 procedure ComputeView(ScaleX,ScaleY: single);
122 function ComputeCoordinate(AViewCoord: TPoint3D_128): TPointF;
123 procedure AddObject(AObj: IBGRAObject3D);
124 procedure AddLight(ALight: TObject);
125 procedure AddMaterial(AMaterial: IBGRAMaterial3D);
126 procedure Init;
127
128 protected
129 FRenderer: TCustomRenderer3D;
130 FMaterialLibrariesFetched: array of string;
131 FTexturesFetched: array of record
132 Name: string;
133 Bitmap: TBGRACustomBitmap;
134 end;
135 procedure UseMaterial(AMaterialName: string; AFace: IBGRAFace3D); virtual;
136 function LoadBitmapFromFileUTF8(AFilenameUTF8: string): TBGRACustomBitmap; virtual;
137 function FetchTexture(AName: string; out texSize: TPointF): IBGRAScanner; virtual;
138 procedure HandleFetchException(AException: Exception); virtual;
139 procedure DoRender; virtual;
140 procedure DoClear; virtual;
141 function GetRenderWidth: integer;
142 function GetRenderHeight: integer;
143 procedure OnMaterialTextureChanged({%H-}ASender: TObject); virtual;
144 procedure SetDefaultMaterial(AValue: IBGRAMaterial3D);
145 procedure InvalidateMaterial;
146
147 public
148 DefaultLightingNormal: TLightingNormal3D;
149 RenderingOptions: TRenderingOptions;
150 UnknownColor: TBGRAPixel;
151 FetchDirectory: string;
152 FetchThrowsException: boolean;
153
154 constructor Create; overload;
155 constructor Create(ASurface: TBGRACustomBitmap); overload;
156 destructor Destroy; override;
157 procedure Clear; virtual;
158 function FetchObject(AName: string; SwapFacesOrientation: boolean = true): IBGRAObject3D;
159 procedure FetchMaterials(ALibraryName: string); virtual;
160 function LoadObjectFromFile(AFilename: string; SwapFacesOrientation: boolean = true): IBGRAObject3D;
161 function LoadObjectFromFileUTF8(AFilename: string; SwapFacesOrientation: boolean = true): IBGRAObject3D;
162 function LoadObjectFromStream(AStream: TStream; SwapFacesOrientation: boolean = true): IBGRAObject3D;
163 procedure LoadMaterialsFromFile(AFilename: string);
164 procedure LoadMaterialsFromFileUTF8(AFilename: string);
165 procedure LoadMaterialsFromStream(AStream: TStream);
166 procedure LookAt(AWhere: TPoint3D; ATopDir: TPoint3D);
167 procedure LookLeft(angleDeg: single);
168 procedure LookRight(angleDeg: single);
169 procedure LookUp(angleDeg: single);
170 procedure LookDown(angleDeg: single);
171 procedure Render; overload; virtual;
172 procedure Render(ARenderer: TCustomRenderer3D); overload;
173 function CreateObject: IBGRAObject3D; overload;
174 function CreateObject(ATexture: IBGRAScanner): IBGRAObject3D; overload;
175 function CreateObject(AColor: TBGRAPixel): IBGRAObject3D; overload;
176 function CreateSphere(ARadius: Single; AHorizPrecision: integer = 8; AVerticalPrecision : integer = 6): IBGRAObject3D; overload;
177 function CreateSphere(ARadius: Single; AColor: TBGRAPixel; AHorizPrecision: integer = 8; AVerticalPrecision : integer = 6): IBGRAObject3D; overload;
178 function CreateHalfSphere(ARadius: Single; AHorizPrecision: integer = 6; AVerticalPrecision : integer = 6): IBGRAObject3D; overload;
179 function CreateHalfSphere(ARadius: Single; AColor: TBGRAPixel; AHorizPrecision: integer = 6; AVerticalPrecision : integer = 6): IBGRAObject3D; overload;
180 procedure RemoveObject(AObject: IBGRAObject3D);
181 function AddDirectionalLight(ADirection: TPoint3D; ALightness: single = 1; AMinIntensity : single = 0): IBGRADirectionalLight3D; overload;
182 function AddDirectionalLight(ADirection: TPoint3D; AColor: TBGRAPixel; AMinIntensity: single = 0): IBGRADirectionalLight3D; overload;
183 function AddPointLight(AVertex: IBGRAVertex3D; AOptimalDistance: single; ALightness: single = 1; AMinIntensity : single = 0): IBGRAPointLight3D; overload;
184 function AddPointLight(AVertex: IBGRAVertex3D; AOptimalDistance: single; AColor: TBGRAPixel; AMinIntensity: single = 0): IBGRAPointLight3D; overload;
185 procedure RemoveLight(ALight: IBGRALight3D);
186 procedure SetZoom(value: Single); overload;
187 procedure SetZoom(value: TPointF); overload;
188 function CreateMaterial: IBGRAMaterial3D; overload;
189 function CreateMaterial(ASpecularIndex: integer): IBGRAMaterial3D; overload;
190 function GetMaterialByName(AName: string): IBGRAMaterial3D;
191 procedure UpdateMaterials; virtual;
192 procedure UpdateMaterial(AMaterialName: string); virtual;
193 procedure ForEachVertex(ACallback: TVertex3DCallback);
194 procedure ForEachFace(ACallback: TFace3DCallback);
195 function MakeLightList: TList;
196
197 property ViewCenter: TPointF read GetViewCenter write SetViewCenter;
198 property AutoViewCenter: boolean read FAutoViewCenter write SetAutoViewCenter;
199 property AutoZoom: boolean read FAutoZoom write SetAutoZoom;
200 property Surface: TBGRACustomBitmap read FSurface write FSurface;
201 property Object3D[AIndex: integer]: IBGRAObject3D read GetObject;
202 property Object3DCount: integer read FObjectCount;
203 property VertexCount: integer read GetVertexCount;
204 property NormalCount: integer read GetNormalCount;
205 property FaceCount: integer read GetFaceCount;
206 property Zoom: TPointF read GetZoom write SetZoom;
207 property AmbiantLightness: single read GetAmbiantLightness write SetAmbiantLightness;
208 property AmbiantLightColor: TBGRAPixel read GetAmbiantLightColor write SetAmbiantLightColor;
209 property AmbiantLightColorF: TColorF read GetAmbiantLightColorF write SetAmbiantLightColorF;
210 property LightCount: integer read GetLightCount;
211 property Light[AIndex: integer]: IBGRALight3D read GetLight;
212 property ViewPoint: TPoint3D read GetViewPoint write SetViewPoint;
213 property RenderedFaceCount : integer read FRenderedFaceCount;
214 property Material[AIndex: integer] : IBGRAMaterial3D read GetMaterial;
215 property MaterialCount: integer read FMaterialCount;
216 property Camera: TCamera3D read FCamera;
217 property DefaultMaterial: IBGRAMaterial3D read FDefaultMaterial write SetDefaultMaterial;
218 end;
219
220implementation
221
222uses BGRACoordPool3D, BGRAUTF8;
223
224{$i lightingclasses3d.inc}
225{$i vertex3d.inc}
226{$i face3d.inc}
227{$i part3d.inc}
228{$i object3d.inc}
229{$i shapes3d.inc}
230
231{ TCamera3D }
232
233function TCamera3D.GetLookWhere: TPoint3D;
234begin
235 result := Point3D(FLookWhere);
236end;
237
238function TCamera3D.GetMatrix: TMatrix3D;
239begin
240 if not FMatrixComputed then
241 begin
242 ComputeMatrix;
243 FMatrixComputed := true;
244 end;
245 result := FMatrix;
246end;
247
248function TCamera3D.GetViewPoint: TPoint3D;
249begin
250 result := Point3D(FViewPoint);
251end;
252
253procedure TCamera3D.SetMatrix(AValue: TMatrix3D);
254begin
255 FMatrix := AValue;
256 FMatrixComputed:= true;
257 FViewPoint := Point3D_128(FMatrix[1,4],FMatrix[2,4],FMatrix[3,4]);
258end;
259
260procedure TCamera3D.SetViewPoint(AValue: TPoint3D);
261begin
262 FViewPoint := Point3D_128(AValue);
263 FMatrix[1,4] := FViewPoint.x;
264 FMatrix[2,4] := FViewPoint.y;
265 FMatrix[3,4] := FViewPoint.z;
266 FMatrixComputed := false;
267end;
268
269procedure TCamera3D.ComputeMatrix;
270var ZDir, XDir, YDir: TPoint3D_128;
271begin
272 if IsPoint3D_128_Zero(FTopDir) then exit;
273 YDir := -FTopDir;
274 Normalize3D_128(YDir);
275
276 ZDir := FLookWhere-FViewPoint;
277 if IsPoint3D_128_Zero(ZDir) then exit;
278 Normalize3D_128(ZDir);
279
280 VectProduct3D_128(YDir,ZDir,XDir);
281 VectProduct3D_128(ZDir,XDir,YDir); //correct Y dir
282 Normalize3D_128(XDir);
283 Normalize3D_128(YDir);
284
285 FMatrix := Matrix3D(XDir,YDir,ZDir,FViewPoint);
286 FMatrix := MatrixInverse3D(FMatrix);
287end;
288
289procedure TCamera3D.LookAt(AWhere: TPoint3D; ATopDir: TPoint3D);
290begin
291 FLookWhere := Point3D_128(AWhere);
292 FTopDir := Point3D_128(ATopDir);
293 FMatrixComputed := false;
294end;
295
296procedure TCamera3D.LookLeft(angleDeg: single);
297var m,inv: TMatrix3D;
298begin
299 inv := MatrixInverse3D(Matrix);
300 m := MatrixRotateY(angleDeg*Pi/180);
301 FLookWhere := inv*m*Matrix*FLookWhere;
302 FMatrixComputed := false;
303end;
304
305procedure TCamera3D.LookRight(angleDeg: single);
306begin
307 LookLeft(-angleDeg);
308end;
309
310procedure TCamera3D.LookUp(angleDeg: single);
311var m,inv: TMatrix3D;
312begin
313 inv := MatrixInverse3D(Matrix);
314 m := MatrixRotateX(-angleDeg*Pi/180);
315 FLookWhere := inv*m*Matrix*FLookWhere;
316 FMatrixComputed := false;
317end;
318
319procedure TCamera3D.LookDown(angleDeg: single);
320begin
321 LookUp(-angleDeg);
322end;
323
324
325{ TBGRAScene3D }
326
327function TBGRAScene3D.GetViewCenter: TPointF;
328begin
329 if FAutoViewCenter then
330 begin
331 result := PointF((GetRenderWidth-1)/2,(GetRenderHeight-1)/2)
332 end
333 else
334 result := FViewCenter;
335end;
336
337function TBGRAScene3D.GetViewPoint: TPoint3D;
338begin
339 result := Camera.ViewPoint;
340end;
341
342function TBGRAScene3D.GetZoom: TPointF;
343var size: single;
344begin
345 if FAutoZoom then
346 begin
347 Size := sqrt(GetRenderWidth*GetRenderHeight)*0.8;
348 if Size = 0 then
349 result := PointF(1,1)
350 else
351 result := PointF(size,size);
352 end else
353 result := FZoom;
354end;
355
356procedure TBGRAScene3D.SetAmbiantLightColorF(const AValue: TColorF);
357begin
358 FAmbiantLightColorF := AValue;
359end;
360
361procedure TBGRAScene3D.SetAmbiantLightness(const AValue: single);
362begin
363 FAmbiantLightColorF := ColorF(AValue, AValue, AValue, 1);
364end;
365
366procedure TBGRAScene3D.SetAmbiantLightColor(const AValue: TBGRAPixel);
367begin
368 FAmbiantLightColorF := ColorInt65536ToColorF(BGRAToColorInt(AValue,True));
369end;
370
371function TBGRAScene3D.GetObject(AIndex: integer): IBGRAObject3D;
372begin
373 if (AIndex < 0) or (AIndex >= FObjectCount) then
374 raise exception.Create('Index out of bounds');
375 result := FObjects[AIndex];
376end;
377
378function TBGRAScene3D.GetVertexCount: integer;
379var i: integer;
380begin
381 result := 0;
382 for i := 0 to Object3DCount-1 do
383 result += Object3D[i].TotalVertexCount;
384end;
385
386function TBGRAScene3D.GetAmbiantLightColor: TBGRAPixel;
387begin
388 result := ColorIntToBGRA(ColorFToColorInt65536(FAmbiantLightColorF),True);
389end;
390
391function TBGRAScene3D.GetFaceCount: integer;
392var i: integer;
393begin
394 result := 0;
395 for i := 0 to Object3DCount-1 do
396 result += Object3D[i].FaceCount;
397end;
398
399function TBGRAScene3D.GetLight(AIndex: integer): IBGRALight3D;
400begin
401 if (AIndex < 0) or (AIndex >= FLights.Count) then
402 result := nil
403 else
404 result := TBGRALight3D(FLights[AIndex]);
405end;
406
407function TBGRAScene3D.GetLightCount: integer;
408begin
409 result := FLights.Count;
410end;
411
412function TBGRAScene3D.GetMaterial(AIndex: integer): IBGRAMaterial3D;
413begin
414 if (AIndex < 0) or (AIndex >= FMaterialCount) then
415 raise exception.Create('Index out of bounds');
416 result := FMaterials[AIndex];
417end;
418
419function TBGRAScene3D.GetNormalCount: integer;
420var i: integer;
421begin
422 result := 0;
423 for i := 0 to Object3DCount-1 do
424 result += Object3D[i].TotalNormalCount;
425end;
426
427function TBGRAScene3D.GetAmbiantLightness: single;
428begin
429 result := (FAmbiantLightColorF[1]+FAmbiantLightColorF[2]+FAmbiantLightColorF[3])/3;
430end;
431
432function TBGRAScene3D.GetAmbiantLightColorF: TColorF;
433begin
434 result := FAmbiantLightColorF;
435end;
436
437procedure TBGRAScene3D.SetAutoViewCenter(const AValue: boolean);
438begin
439 if FAutoViewCenter=AValue then exit;
440 if not AValue then
441 FViewCenter := ViewCenter;
442 FAutoViewCenter:=AValue;
443end;
444
445procedure TBGRAScene3D.SetAutoZoom(const AValue: boolean);
446begin
447 if FAutoZoom=AValue then exit;
448 if not AValue then
449 FZoom := Zoom;
450 FAutoZoom:=AValue;
451end;
452
453procedure TBGRAScene3D.SetDefaultMaterial(AValue: IBGRAMaterial3D);
454begin
455 if FDefaultMaterial=AValue then Exit;
456 FDefaultMaterial:=AValue;
457 InvalidateMaterial;
458end;
459
460procedure TBGRAScene3D.SetViewCenter(const AValue: TPointF);
461begin
462 FViewCenter := AValue;
463 FAutoViewCenter:= False;
464end;
465
466procedure TBGRAScene3D.SetViewPoint(const AValue: TPoint3D);
467begin
468 Camera.ViewPoint := AValue;
469end;
470
471procedure TBGRAScene3D.AddObject(AObj: IBGRAObject3D);
472begin
473 if FObjectCount = length(FObjects) then
474 setlength(FObjects, FObjectCount*2+1);
475 FObjects[FObjectCount] := AObj;
476 inc(FObjectCount);
477end;
478
479procedure TBGRAScene3D.AddLight(ALight: TObject);
480begin
481 FLights.Add(ALight);
482 IBGRALight3D(TBGRALight3D(ALight))._AddRef;
483end;
484
485procedure TBGRAScene3D.AddMaterial(AMaterial: IBGRAMaterial3D);
486begin
487 if FMaterialCount = length(FMaterials) then
488 setlength(FMaterials, FMaterialCount*2+1);
489 FMaterials[FMaterialCount] := AMaterial;
490 inc(FMaterialCount);
491end;
492
493procedure TBGRAScene3D.Init;
494begin
495 UnknownColor := BGRA(0,128,255);
496 FAutoZoom := True;
497 FAutoViewCenter := True;
498
499 FCamera := TCamera3D.Create;
500 Camera.ViewPoint := Point3D(0,0,-100);
501 Camera.LookAt(Point3D(0,0,0), Point3D(0,-1,0));
502 with RenderingOptions do
503 begin
504 TextureInterpolation := False;
505 PerspectiveMode := pmPerspectiveMapping;
506 LightingInterpolation := liSpecularHighQuality;
507 AntialiasingMode := am3dNone;
508 AntialiasingResampleLevel := 2;
509 end;
510 AmbiantLightness := 1;
511 AmbiantLightColor := BGRAWhite;
512 DefaultLightingNormal := lnFaceVertexMix;
513 FLights := TList.Create;
514 FRenderedFaceCount:= 0;
515 FMaterialCount := 0;
516 FObjectCount := 0;
517 DefaultMaterial := CreateMaterial;
518 RenderingOptions.MinZ := 1;
519end;
520
521constructor TBGRAScene3D.Create;
522begin
523 Init;
524end;
525
526constructor TBGRAScene3D.Create(ASurface: TBGRACustomBitmap);
527begin
528 FSurface := ASurface;
529 Init;
530end;
531
532destructor TBGRAScene3D.Destroy;
533var
534 i: Integer;
535begin
536 DoClear;
537 FreeAndNil(FLights);
538 FreeAndNil(FCamera);
539 for i := 0 to high(FTexturesFetched) do
540 FTexturesFetched[i].Bitmap.Free;
541 inherited Destroy;
542end;
543
544procedure TBGRAScene3D.Clear;
545begin
546 DoClear;
547 DefaultMaterial := CreateMaterial;
548end;
549
550function TBGRAScene3D.FetchObject(AName: string; SwapFacesOrientation: boolean
551 ): IBGRAObject3D;
552begin
553 if FetchDirectory = '' then raise exception.Create('Please define first the FetchDirectory');
554 try
555 result := LoadObjectFromFileUTF8(ConcatPaths([FetchDirectory,AName]), SwapFacesOrientation);
556 except
557 on ex:Exception do
558 HandleFetchException(ex);
559 end;
560end;
561
562procedure TBGRAScene3D.UseMaterial(AMaterialName: string; AFace: IBGRAFace3D);
563
564 function ParseColor(text: string): TBGRAPixel;
565 var
566 color,tempColor: TBGRAPixel;
567 begin
568 color := UnknownColor;
569
570 if copy(text,1,2) = 'dk' then
571 begin
572 tempcolor := ParseColor(copy(text,3,length(text)-2));
573 tempcolor := MergeBGRA(tempcolor,3,BGRABlack,1);
574 color := StrToBGRA('dark'+copy(text,3,length(text)-2),tempcolor);
575 end;
576 if copy(text,1,2) = 'lt' then
577 begin
578 tempcolor := ParseColor(copy(text,3,length(text)-2));
579 tempcolor := MergeBGRA(tempcolor,3,BGRAWhite,1);
580 color := StrToBGRA('light'+copy(text,3,length(text)-2),tempcolor);
581 end;
582 Color := StrToBGRA(StringReplace(text,'deep','dark',[]),Color);
583 Color := StrToBGRA(StringReplace(text,'dark','deep',[]),Color);
584 Color := StrToBGRA(text,Color);
585 result := color;
586 end;
587
588var
589 mat: IBGRAMaterial3D;
590 c: TBGRAPixel;
591begin
592 mat := GetMaterialByName(AMaterialName);
593 if mat = nil then
594 begin
595 mat := CreateMaterial;
596 mat.Name := AMaterialName;
597 c := ParseColor(AMaterialName);
598 mat.AmbiantColor := c;
599 mat.DiffuseColor := c;
600 end;
601 AFace.Material := mat;
602end;
603
604function TBGRAScene3D.LoadBitmapFromFileUTF8(AFilenameUTF8: string): TBGRACustomBitmap;
605begin
606 result := BGRABitmapFactory.Create(AfileNameUTF8,True);
607end;
608
609function TBGRAScene3D.FetchTexture(AName: string; out texSize: TPointF): IBGRAScanner;
610var
611 i: Integer;
612 bmp: TBGRACustomBitmap;
613begin
614 bmp := nil;
615 for i := 0 to high(FTexturesFetched) do
616 if FTexturesFetched[i].Name = AName then
617 begin
618 bmp := FTexturesFetched[i].Bitmap;
619 result := bmp;
620 texSize := PointF(bmp.Width,bmp.Height);
621 exit;
622 end;
623 if FetchDirectory <> '' then
624 begin
625 try
626 bmp := LoadBitmapFromFileUTF8(ConcatPaths([FetchDirectory,AName]));
627 except
628 on ex:Exception do
629 HandleFetchException(ex);
630 end;
631 end;
632 if bmp = nil then
633 begin
634 result := nil;
635 texSize := PointF(1,1);
636 end else
637 begin
638 setlength(FTexturesFetched, length(FTexturesFetched)+1);
639 FTexturesFetched[high(FTexturesFetched)].Name := AName;
640 FTexturesFetched[high(FTexturesFetched)].Bitmap := bmp;
641 result := bmp;
642 texSize := PointF(bmp.Width,bmp.Height);
643 end;
644end;
645
646procedure TBGRAScene3D.FetchMaterials(ALibraryName: string);
647var
648 i: Integer;
649begin
650 if FetchDirectory <> '' then
651 begin
652 for i := 0 to high(FMaterialLibrariesFetched) do
653 if FMaterialLibrariesFetched[i]=ALibraryName then exit;
654 setlength(FMaterialLibrariesFetched,length(FMaterialLibrariesFetched)+1);
655 FMaterialLibrariesFetched[high(FMaterialLibrariesFetched)] := ALibraryName;
656 try
657 LoadMaterialsFromFile(ConcatPaths([FetchDirectory,ALibraryName]));
658 except
659 on ex:Exception do
660 HandleFetchException(ex);
661 end;
662 end;
663end;
664
665procedure TBGRAScene3D.HandleFetchException(AException: Exception);
666begin
667 if FetchThrowsException then
668 raise AException;
669end;
670
671procedure TBGRAScene3D.DoClear;
672var i: integer;
673begin
674 for i := 0 to FLights.Count-1 do
675 TBGRALight3D(FLights[i]).ReleaseInterface;
676 FLights.Clear;
677
678 for i := 0 to FObjectCount-1 do
679 begin
680 FObjects[i].Clear;
681 FObjects[i] := nil;
682 end;
683 FObjects := nil;
684 FObjectCount := 0;
685
686 FMaterials := nil;
687 FMaterialCount := 0;
688 DefaultMaterial := nil;
689end;
690
691function TBGRAScene3D.GetRenderWidth: integer;
692begin
693 if Assigned(FRenderer) then
694 result := FRenderer.SurfaceWidth
695 else
696 if Assigned(FSurface) then
697 result := FSurface.Width
698 else
699 result := 0;
700end;
701
702function TBGRAScene3D.GetRenderHeight: integer;
703begin
704 if Assigned(FRenderer) then
705 result := FRenderer.SurfaceHeight
706 else
707 if Assigned(FSurface) then
708 result := FSurface.Height
709 else
710 result := 0;
711end;
712
713procedure TBGRAScene3D.OnMaterialTextureChanged(ASender: TObject);
714begin
715 InvalidateMaterial;
716end;
717
718procedure TBGRAScene3D.InvalidateMaterial;
719var
720 i: Integer;
721begin
722 for i := 0 to FObjectCount-1 do
723 FObjects[i].InvalidateMaterial;
724end;
725
726function TBGRAScene3D.LoadObjectFromFile(AFilename: string; SwapFacesOrientation: boolean): IBGRAObject3D;
727begin
728 result := LoadObjectFromFileUTF8(SysToUTF8(AFilename), SwapFacesOrientation);
729end;
730
731function TBGRAScene3D.LoadObjectFromFileUTF8(AFilename: string;
732 SwapFacesOrientation: boolean): IBGRAObject3D;
733var source: TFileStreamUTF8;
734begin
735 source := TFileStreamUTF8.Create(AFilename,fmOpenRead,fmShareDenyWrite);
736 try
737 result := LoadObjectFromStream(source,SwapFacesOrientation);
738 finally
739 source.free;
740 end;
741end;
742
743function TBGRAScene3D.LoadObjectFromStream(AStream: TStream;
744 SwapFacesOrientation: boolean): IBGRAObject3D;
745var s: string;
746 secondValue,thirdValue: string;
747
748 function GetNextToken: string;
749 var idxStart,idxEnd,idxSlash: integer;
750 begin
751 idxStart := 1;
752 while (idxStart <= length(s)) and (s[idxStart]in[' ',#9]) do inc(idxStart);
753 if idxStart > length(s) then
754 begin
755 result := '';
756 exit;
757 end;
758 idxEnd := idxStart;
759 while (idxEnd < length(s)) and not (s[idxEnd+1]in[' ',#9]) do inc(idxEnd);
760 result := copy(s,idxStart, idxEnd-idxStart+1);
761 delete(s,1,idxEnd);
762 idxSlash := pos('/',result);
763 if idxSlash <> 0 then
764 begin
765 secondValue:= copy(result,idxSlash+1,length(result)-idxSlash);
766 result := copy(result,1,idxSlash-1);
767 idxSlash:= pos('/',secondValue);
768 if idxSlash <> 0 then
769 begin
770 thirdValue:= copy(secondValue,idxSlash+1,length(secondValue)-idxSlash);
771 secondValue:= copy(secondValue,1,idxSlash-1);
772 end else
773 thirdValue:= '';
774 end else
775 begin
776 secondValue:= '';
777 thirdValue:= '';
778 end;
779 end;
780
781type
782 TFaceVertexExtra = record
783 normal: IBGRANormal3D;
784 texCoord: TPointF;
785 end;
786
787var lineType : string;
788 x,y,z : single;
789 code : integer;
790 faceVertices: array of IBGRAVertex3D;
791 faceExtra: array of TFaceVertexExtra;
792 NbFaceVertices,v,v2,v3,i: integer;
793 tempV: IBGRAVertex3D;
794 tempN: TFaceVertexExtra;
795 materialname: string;
796 face: IBGRAFace3D;
797 lines: TStringList;
798 lineIndex: integer;
799 texCoords: array of TPointF;
800 nbTexCoords: integer;
801
802begin
803 lines := TStringList.Create;
804 lines.LoadFromStream(AStream);
805 result := CreateObject;
806 faceVertices := nil;
807 faceExtra := nil;
808 NbFaceVertices:= 0;
809 materialname := 'default';
810 lineIndex := 0;
811 texCoords := nil;
812 nbTexCoords:= 0;
813 while lineIndex < lines.Count do
814 begin
815 s := lines[lineIndex];
816 if pos('#',s) <> 0 then
817 s := copy(s,1,pos('#',s)-1);
818 inc(lineIndex);
819 lineType := GetNextToken;
820 if lineType = 'v' then
821 begin
822 val(GetNextToken,x,code);
823 val(GetNextToken,y,code);
824 val(GetNextToken,z,code);
825 result.MainPart.Add(x,y,z);
826 end else
827 if lineType = 'vt' then
828 begin
829 val(GetNextToken,x,code);
830 val(GetNextToken,y,code);
831 if nbTexCoords >= length(texCoords) then
832 setlength(texCoords, length(texCoords)*2+1);
833 texCoords[nbTexCoords] := PointF(x,y);
834 inc(nbTexCoords);
835 end else
836 if lineType = 'vn' then
837 begin
838 val(GetNextToken,x,code);
839 val(GetNextToken,y,code);
840 val(GetNextToken,z,code);
841 result.MainPart.AddNormal(x,y,z);
842 result.LightingNormal := lnVertex;
843 end else
844 if lineType = 'mtllib' then
845 FetchMaterials(trim(s))
846 else
847 if lineType = 'usemtl' then
848 materialname := trim(s)
849 else
850 if lineType = 'f' then
851 begin
852 NbFaceVertices:= 0;
853 repeat
854 val(GetNextToken,v,code);
855 if (code = 0) and (v < 0) then v := result.MainPart.VertexCount+1+v;
856 if (code = 0) and (v >= 1) and (v <= result.MainPart.VertexCount) then
857 begin
858 if length(faceVertices) = NbFaceVertices then
859 begin
860 setlength(faceVertices, length(faceVertices)*2+1);
861 setlength(faceExtra, length(faceExtra)*2+1);
862 end;
863 faceVertices[NbFaceVertices] := result.MainPart.Vertex[v-1];
864 val(secondValue,v2,code);
865 if (code = 0) and (v2 < 0) then v2 := nbTexCoords+1+v2;
866 if (code = 0) and (v2 >= 1) and (v2-1 < nbTexCoords) then
867 faceExtra[NbFaceVertices].texCoord := texCoords[v2-1]
868 else if nbTexCoords > v-1 then
869 faceExtra[NbFaceVertices].texCoord := texCoords[v-1]
870 else
871 faceExtra[NbFaceVertices].texCoord := PointF(0,0);
872 val(thirdValue,v3,code);
873 if (code = 0) and (v3 < 0) then v3 := result.MainPart.NormalCount+1+v3;
874 if code = 0 then
875 faceExtra[NbFaceVertices].normal := result.MainPart.Normal[v3-1]
876 else if result.MainPart.NormalCount > v-1 then
877 faceExtra[NbFaceVertices].normal := result.MainPart.Normal[v-1]
878 else
879 faceExtra[NbFaceVertices].normal := nil;
880 inc(NbFaceVertices);
881 end else break;
882 until false;
883 if NbFaceVertices > 2 then
884 begin
885 if SwapFacesOrientation then
886 for i := 0 to NbFaceVertices div 2-1 do
887 begin
888 tempV := faceVertices[i];
889 faceVertices[i] := faceVertices[NbFaceVertices-1-i];
890 faceVertices[NbFaceVertices-1-i] := tempV;
891 tempN := faceExtra[i];
892 faceExtra[i] := faceExtra[NbFaceVertices-1-i];
893 faceExtra[NbFaceVertices-1-i] := tempN;
894 end;
895 face := result.AddFace(slice(faceVertices,NbFaceVertices));
896 for i := 0 to NbFaceVertices-1 do
897 begin
898 face.SetNormal(i, faceExtra[i].normal);
899 face.SetTexCoord(i, faceExtra[i].texCoord);
900 end;
901 face.MaterialName := materialname;
902 end;
903 end;
904 end;
905 lines.Free;
906end;
907
908procedure TBGRAScene3D.LoadMaterialsFromFile(AFilename: string);
909var source: TFileStream;
910begin
911 source := TFileStream.Create(AFilename,fmOpenRead,fmShareDenyWrite);
912 try
913 LoadMaterialsFromStream(source);
914 finally
915 source.free;
916 end;
917end;
918
919procedure TBGRAScene3D.LoadMaterialsFromFileUTF8(AFilename: string);
920var source: TFileStreamUTF8;
921begin
922 source := TFileStreamUTF8.Create(AFilename,fmOpenRead,fmShareDenyWrite);
923 try
924 LoadMaterialsFromStream(source);
925 finally
926 source.free;
927 end;
928end;
929
930procedure TBGRAScene3D.LoadMaterialsFromStream(AStream: TStream);
931var
932 s: String;
933
934 function GetNextToken: string;
935 var idxStart,idxEnd: integer;
936 begin
937 idxStart := 1;
938 while (idxStart <= length(s)) and (s[idxStart]in[#9,' ']) do inc(idxStart);
939 if idxStart > length(s) then
940 begin
941 result := '';
942 exit;
943 end;
944 idxEnd := idxStart;
945 while (idxEnd < length(s)) and not (s[idxEnd+1]in[#9,' ']) do inc(idxEnd);
946 result := copy(s,idxStart, idxEnd-idxStart+1);
947 delete(s,1,idxEnd);
948 end;
949
950 function GetSingle: single;
951 var {%H-}code: integer;
952 begin
953 val(GetNextToken,result,{%H-}code);
954 end;
955
956 function GetColorF: TColorF;
957 var r,g,b: single;
958 {%H-}code: integer;
959 begin
960 val(GetNextToken,r,{%H-}code);
961 val(GetNextToken,g,{%H-}code);
962 val(GetNextToken,b,{%H-}code);
963 result := ColorF(r,g,b,1);
964 end;
965
966var
967 lines: TStringList;
968 lineIndex: integer;
969 lineType: String;
970 currentMaterial: IBGRAMaterial3D;
971 materialName: string;
972 texZoom: TPointF;
973 v: single;
974
975begin
976 lines := TStringList.Create;
977 lines.LoadFromStream(AStream);
978 lineIndex := 0;
979 while lineIndex < lines.Count do
980 begin
981 s := lines[lineIndex];
982 if pos('#',s) <> 0 then
983 s := copy(s,1,pos('#',s)-1);
984 inc(lineIndex);
985 lineType := GetNextToken;
986 if lineType = 'newmtl' then
987 begin
988 materialName := trim(s);
989 currentMaterial := GetMaterialByName(materialName);
990 if currentMaterial = nil then
991 begin
992 currentMaterial := CreateMaterial;
993 currentMaterial.Name := materialName;
994 end;
995 end else
996 if currentMaterial <> nil then
997 begin
998 if lineType = 'Ka' then currentMaterial.AmbiantColorF := GetColorF else
999 if lineType = 'Kd' then currentMaterial.DiffuseColorF := GetColorF else
1000 if lineType = 'Ks' then currentMaterial.SpecularColorF := GetColorF else
1001 if (lineType = 'map_Ka') or (lineType = 'map_Kd') then
1002 begin
1003 currentMaterial.Texture := FetchTexture(trim(s),texZoom);
1004 texZoom.y := -texZoom.y;
1005 currentMaterial.TextureZoom := texZoom;
1006 end else
1007 if lineType = 'Ns' then currentMaterial.SpecularIndex := round(GetSingle) else
1008 if lineType = 'd' then
1009 begin
1010 v := GetSingle;
1011 if v > 1 then
1012 currentMaterial.SimpleAlpha := 255
1013 else if v < 0 then
1014 currentMaterial.SimpleAlpha := 0
1015 else
1016 currentMaterial.SimpleAlpha := round(v*255);
1017 end;
1018 end;
1019 end;
1020 lines.Free;
1021end;
1022
1023procedure TBGRAScene3D.LookAt(AWhere: TPoint3D; ATopDir: TPoint3D);
1024begin
1025 Camera.LookAt(AWhere,ATopDir);
1026end;
1027
1028procedure TBGRAScene3D.LookLeft(angleDeg: single);
1029begin
1030 Camera.LookLeft(angleDeg);
1031end;
1032
1033procedure TBGRAScene3D.LookRight(angleDeg: single);
1034begin
1035 Camera.LookRight(angleDeg);
1036end;
1037
1038procedure TBGRAScene3D.LookUp(angleDeg: single);
1039begin
1040 Camera.LookUp(angleDeg);
1041end;
1042
1043procedure TBGRAScene3D.LookDown(angleDeg: single);
1044begin
1045 Camera.LookDown(angleDeg);
1046end;
1047
1048procedure TBGRAScene3D.Render;
1049begin
1050 FRenderer := TBGRARenderer3D.Create(FSurface, RenderingOptions,
1051 FAmbiantLightColorF,
1052 FLights);
1053 DoRender;
1054 FRenderer.Free;
1055end;
1056
1057procedure TBGRAScene3D.Render(ARenderer: TCustomRenderer3D);
1058begin
1059 FRenderer := ARenderer;
1060 DoRender;
1061 FRenderer := nil;
1062end;
1063
1064procedure TBGRAScene3D.ComputeView(ScaleX,ScaleY: single);
1065var
1066 i: Integer;
1067begin
1068 FProjection.Zoom := Zoom;
1069 FProjection.Zoom.X *= ScaleX;
1070 FProjection.Zoom.Y *= ScaleY;
1071 FProjection.Center := ViewCenter;
1072 FProjection.Center.X *= ScaleX;
1073 FProjection.Center.Y *= ScaleY;
1074 for i := 0 to FObjectCount-1 do
1075 FObjects[i].ComputeWithMatrix(Camera.Matrix, FProjection);
1076end;
1077
1078function TBGRAScene3D.ComputeCoordinate(AViewCoord: TPoint3D_128): TPointF;
1079var InvZ: single;
1080begin
1081 if AViewCoord.z > 0 then
1082 begin
1083 InvZ := 1/AViewCoord.z;
1084 result := PointF(AViewCoord.x*InvZ*FProjection.Zoom.x + FProjection.Center.x,
1085 AViewCoord.y*InvZ*FProjection.Zoom.Y + FProjection.Center.y);
1086 end else
1087 result := PointF(0,0);
1088end;
1089
1090type
1091 arrayOfTBGRAFace3D = array of TBGRAFace3D;
1092
1093procedure InsertionSortFaces(var a: arrayOfTBGRAFace3D);
1094var i,j: integer;
1095 temp: TBGRAFace3D;
1096begin
1097 for i := 1 to high(a) do
1098 begin
1099 Temp := a[i];
1100 j := i;
1101 while (j>0) and (a[j-1].ViewCenterZ > Temp.ViewCenterZ) do
1102 begin
1103 a[j] := a[j-1];
1104 dec(j);
1105 end;
1106 a[j] := Temp;
1107 end;
1108end;
1109
1110function PartitionFaces(var a: arrayOfTBGRAFace3D; left,right: integer): integer;
1111
1112 procedure Swap(idx1,idx2: integer); inline;
1113 var temp: TBGRAFace3D;
1114 begin
1115 temp := a[idx1];
1116 a[idx1] := a[idx2];
1117 a[idx2] := temp;
1118 end;
1119
1120var pivotIndex: integer;
1121 pivotValue: TBGRAFace3D;
1122 storeIndex: integer;
1123 i: integer;
1124
1125begin
1126 pivotIndex := left + random(right-left+1);
1127 pivotValue := a[pivotIndex];
1128 swap(pivotIndex,right);
1129 storeIndex := left;
1130 for i := left to right-1 do
1131 if a[i].ViewCenterZ <= pivotValue.ViewCenterZ then
1132 begin
1133 swap(i,storeIndex);
1134 inc(storeIndex);
1135 end;
1136 swap(storeIndex,right);
1137 result := storeIndex;
1138end;
1139
1140procedure QuickSortFaces(var a: arrayOfTBGRAFace3D; left,right: integer);
1141var pivotNewIndex: integer;
1142begin
1143 if right > left+9 then
1144 begin
1145 pivotNewIndex := PartitionFaces(a,left,right);
1146 QuickSortFaces(a,left,pivotNewIndex-1);
1147 QuickSortFaces(a,pivotNewIndex+1,right);
1148 end;
1149end;
1150
1151procedure SortFaces(var a: arrayOfTBGRAFace3D);
1152begin
1153 if length(a) < 10 then InsertionSortFaces(a) else
1154 begin
1155 QuickSortFaces(a,0,high(a));
1156 InsertionSortFaces(a);
1157 end;
1158end;
1159
1160function IsPolyVisible(const p : array of TPointF; ori: integer = 1) : boolean;
1161var i: integer;
1162begin
1163 i := 0;
1164 while i<=high(p)-2 do
1165 begin
1166 if ori*
1167 ( (p[i+1].x-p[i].x)*(p[i+2].y-p[i].y) -
1168 (p[i+1].y-p[i].y)*(p[i+2].x-p[i].x)) > 0 then
1169 begin
1170 result := true;
1171 exit;
1172 end;
1173 inc(i);
1174 end;
1175 result := false;
1176end;
1177
1178procedure TBGRAScene3D.DoRender;
1179var
1180 LFaces: array of TBGRAFace3D;
1181 LFaceOpaque: array of boolean;
1182 LFaceCount: integer;
1183
1184 procedure PrepareFaces;
1185 var i,j, LFaceIndex: integer;
1186 obj: IBGRAObject3D;
1187 begin
1188 LFaces := nil;
1189 LFaceCount := 0;
1190 for i := 0 to FObjectCount-1 do
1191 begin
1192 obj := FObjects[i];
1193 inc(LFaceCount, obj.GetFaceCount);
1194 obj.Update;
1195 end;
1196 setlength(LFaces, LFaceCount);
1197 LFaceIndex := 0;
1198 for i := 0 to FObjectCount-1 do
1199 with FObjects[i] do
1200 begin
1201 for j := 0 to GetFaceCount-1 do
1202 begin
1203 LFaces[LFaceIndex] := TBGRAFace3D(GetFace(j).GetAsObject);
1204 inc(LFaceIndex);
1205 end;
1206 end;
1207 end;
1208
1209var
1210 faceDesc: TFaceRenderingDescription;
1211 LVertices: array of TBGRAVertex3D;
1212
1213 procedure DrawFace(numFace: integer);
1214 var
1215 j,k: Integer;
1216 VCount,NewVCount: integer;
1217 NegNormals: boolean;
1218 LastVisibleVertex: integer;
1219
1220 procedure AddZIntermediate(n1,n2: integer);
1221 var t: single;
1222 v1,v2: TBGRAVertex3D;
1223 begin
1224 v1 := LVertices[n1];
1225 v2 := LVertices[n2];
1226 t := (RenderingOptions.MinZ - v1.ViewCoord.z)/(v2.ViewCoord.z - v1.ViewCoord.z);
1227 LVertices[NewVCount] := nil; //computed
1228
1229 faceDesc.Colors[NewVCount] := MergeBGRA(faceDesc.Colors[n1],round((1-t)*65536),faceDesc.Colors[n2],round(t*65536));
1230 faceDesc.TexCoords[NewVCount] := faceDesc.TexCoords[n1]*(1-t) + faceDesc.TexCoords[n2]*t;
1231 faceDesc.Positions3D[NewVCount] := faceDesc.Positions3D[n1]*(1-t) + faceDesc.Positions3D[n2]*t;
1232 faceDesc.Normals3D[NewVCount] := faceDesc.Normals3D[n1]*(1-t) + faceDesc.Normals3D[n2]*t;
1233 faceDesc.Projections[NewVCount] := ComputeCoordinate(faceDesc.Positions3D[NewVCount]);
1234 NewVCount += 1;
1235 end;
1236
1237 procedure LoadVertex(idxL: integer; idxV: integer);
1238 var vertexDesc: PBGRAFaceVertexDescription;
1239 tempV: TBGRAVertex3D;
1240 begin
1241 with LFaces[numFace] do
1242 begin
1243 vertexDesc := VertexDescription[idxV];
1244 with vertexDesc^ do
1245 begin
1246 tempV := TBGRAVertex3D(vertex.GetAsObject);
1247 LVertices[idxL] := tempV;
1248
1249 faceDesc.Colors[idxL] := ActualColor;
1250 faceDesc.TexCoords[idxL] := ActualTexCoord;
1251
1252 with tempV.CoordData^ do
1253 begin
1254 faceDesc.Positions3D[idxL] := viewCoord;
1255 facedesc.Normals3D[idxL] := viewNormal;
1256 faceDesc.Projections[idxL] := projectedCoord;
1257 end;
1258 if Normal <> nil then
1259 facedesc.Normals3D[idxL] := Normal.ViewNormal_128;
1260 Normalize3D_128(facedesc.Normals3D[idxL]);
1261 end;
1262 end;
1263 end;
1264
1265 begin
1266 with LFaces[numFace] do
1267 begin
1268 VCount := VertexCount;
1269 if VCount < 3 then exit;
1270
1271 faceDesc.NormalsMode := Object3D.LightingNormal;
1272
1273 faceDesc.Material := ActualMaterial;
1274 if faceDesc.Material = nil then exit;
1275 faceDesc.Texture := ActualTexture;
1276
1277 if length(LVertices) < VCount+3 then //keep margin for z-clip
1278 begin
1279 setlength(LVertices, (VCount+3)*2);
1280 setlength(faceDesc.Colors, length(LVertices));
1281 setlength(faceDesc.TexCoords, length(LVertices));
1282 setlength(faceDesc.Projections, length(LVertices));
1283 setlength(faceDesc.Positions3D, length(LVertices));
1284 setlength(faceDesc.Normals3D, length(LVertices));
1285 end;
1286
1287 if FRenderer.HandlesNearClipping then
1288 begin
1289 for j := 0 to VCount-1 do
1290 LoadVertex(j,j);
1291 end else
1292 begin
1293 NewVCount := 0;
1294 LastVisibleVertex := -1;
1295 for k := VCount-1 downto 0 do
1296 if Vertex[k].ViewCoordZ >= RenderingOptions.MinZ then
1297 begin
1298 LastVisibleVertex := k;
1299 break;
1300 end;
1301 if LastVisibleVertex = -1 then exit;
1302
1303 k := VCount-1;
1304 for j := 0 to VCount-1 do
1305 begin
1306 if Vertex[j].ViewCoordZ >= RenderingOptions.MinZ then
1307 begin
1308 if k <> LastVisibleVertex then //one or more vertices is out
1309 begin
1310 LoadVertex(NewVCount+1, LastVisibleVertex);
1311 LoadVertex(NewVCount+2, (LastVisibleVertex+1) mod VertexCount);
1312 AddZIntermediate(NewVCount+1,NewVCount+2);
1313
1314 LoadVertex(NewVCount+1, j);
1315 LoadVertex(NewVCount+2, k);
1316
1317 AddZIntermediate(NewVCount+1,NewVCount+2);
1318 inc(NewVCount);
1319 end else
1320 begin
1321 LoadVertex(NewVCount, j);
1322 NewVCount += 1;
1323 end;
1324 LastVisibleVertex := j;
1325 end;
1326 k := j;
1327 end;
1328 VCount := NewVCount;
1329 if VCount < 3 then exit; //after z-clipping
1330 end;
1331
1332 if not FRenderer.HandlesFaceCulling then
1333 begin
1334 if not IsPolyVisible(slice(faceDesc.Projections,VCount)) then
1335 begin
1336 if not Biface then exit;
1337 NegNormals := True;
1338 end else
1339 begin
1340 NegNormals := False;
1341 end;
1342 end else
1343 NegNormals := false;
1344
1345 //compute normals
1346 case faceDesc.NormalsMode of
1347 lnFace: for j := 0 to VCount-1 do
1348 faceDesc.Normals3D[j] := ViewNormal_128;
1349 lnFaceVertexMix:
1350 for j := 0 to VCount-1 do
1351 begin
1352 faceDesc.Normals3D[j] += ViewNormal_128;
1353 Normalize3D_128(faceDesc.Normals3D[j]);
1354 end;
1355 end;
1356 if NegNormals then
1357 for j := 0 to VCount-1 do
1358 faceDesc.Normals3D[j] := -faceDesc.Normals3D[j];
1359
1360 if LightThroughFactorOverride then
1361 faceDesc.LightThroughFactor := LightThroughFactor
1362 else
1363 faceDesc.LightThroughFactor := faceDesc.Material.GetLightThroughFactor;
1364
1365 faceDesc.NbVertices:= VCount;
1366 faceDesc.Biface := Biface;
1367
1368 if FRenderer.RenderFace(faceDesc, @ComputeCoordinate) then
1369 inc(FRenderedFaceCount);
1370 end;
1371 end;
1372
1373var i,j: integer;
1374
1375begin
1376 FRenderedFaceCount:= 0;
1377
1378 PrepareFaces;
1379 ComputeView(FRenderer.GlobalScale,FRenderer.GlobalScale);
1380 FRenderer.Projection := FProjection;
1381
1382 SortFaces(LFaces);
1383 LVertices := nil;
1384
1385 //if there is a Z-Buffer, it is possible to avoid drawing things that
1386 //are hidden by opaque faces by drawing first all opaque faces
1387 if FRenderer.HasZBuffer then
1388 begin
1389 setlength(LFaceOpaque, length(LFaces));
1390 for i := 0 to High(LFaces) do
1391 begin
1392 if (LFaces[i].Texture = nil) then
1393 begin
1394 LFaceOpaque[i] := true;
1395 with LFaces[i] do
1396 for j := 0 to VertexCount-1 do
1397 if VertexColor[j].alpha <> 255 then
1398 begin
1399 LFaceOpaque[i] := false;
1400 break;
1401 end;
1402 end else
1403 LFaceOpaque[i] := true;
1404 end;
1405
1406 //draw near opaque faces first
1407 for i := 0 to High(LFaces) do
1408 if LFaceOpaque[i] then DrawFace(i);
1409
1410 //draw other faces
1411 for i := High(LFaces) downto 0 do
1412 if not LFaceOpaque[i] then DrawFace(i);
1413 end else
1414 begin
1415 for i := High(LFaces) downto 0 do
1416 DrawFace(i);
1417 end;
1418end;
1419
1420function TBGRAScene3D.CreateObject: IBGRAObject3D;
1421begin
1422 result := TBGRAObject3D.Create(self);
1423 AddObject(result);
1424end;
1425
1426function TBGRAScene3D.CreateObject(ATexture: IBGRAScanner): IBGRAObject3D;
1427begin
1428 result := TBGRAObject3D.Create(self);
1429 result.Texture := ATexture;
1430 AddObject(result);
1431end;
1432
1433function TBGRAScene3D.CreateObject(AColor: TBGRAPixel): IBGRAObject3D;
1434begin
1435 result := TBGRAObject3D.Create(self);
1436 result.Color := AColor;
1437 AddObject(result);
1438end;
1439
1440function TBGRAScene3D.CreateSphere(ARadius: Single; AHorizPrecision: integer; AVerticalPrecision : integer): IBGRAObject3D;
1441begin
1442 result := TBGRASphere3D.Create(self, ARadius, AHorizPrecision, AVerticalPrecision);
1443 AddObject(result);
1444end;
1445
1446function TBGRAScene3D.CreateSphere(ARadius: Single; AColor: TBGRAPixel; AHorizPrecision: integer; AVerticalPrecision : integer): IBGRAObject3D;
1447begin
1448 result := TBGRASphere3D.Create(self, ARadius, AHorizPrecision, AVerticalPrecision);
1449 result.Color := AColor;
1450 AddObject(result);
1451end;
1452
1453function TBGRAScene3D.CreateHalfSphere(ARadius: Single;
1454 AHorizPrecision: integer; AVerticalPrecision: integer): IBGRAObject3D;
1455begin
1456 result := TBGRASphere3D.Create(self, ARadius, AHorizPrecision, AVerticalPrecision, True);
1457 AddObject(result);
1458end;
1459
1460function TBGRAScene3D.CreateHalfSphere(ARadius: Single; AColor: TBGRAPixel;
1461 AHorizPrecision: integer; AVerticalPrecision: integer): IBGRAObject3D;
1462begin
1463 result := TBGRASphere3D.Create(self, ARadius, AHorizPrecision, AVerticalPrecision, True);
1464 result.Color := AColor;
1465 AddObject(result);
1466end;
1467
1468procedure TBGRAScene3D.RemoveObject(AObject: IBGRAObject3D);
1469var
1470 i,j: Integer;
1471begin
1472 for i := FObjectCount-1 downto 0 do
1473 if FObjects[i] = AObject then
1474 begin
1475 dec(FObjectCount);
1476 FObjects[i] := nil;
1477 for j := i to FObjectCount-1 do
1478 FObjects[j] := FObjects[j+1];
1479 end;
1480end;
1481
1482function TBGRAScene3D.AddDirectionalLight(ADirection: TPoint3D;
1483 ALightness: single; AMinIntensity: single): IBGRADirectionalLight3D;
1484var lightObj: TBGRADirectionalLight3D;
1485begin
1486 lightObj := TBGRADirectionalLight3D.Create(ADirection);
1487 result := lightObj;
1488 result.ColorF := ColorF(ALightness,ALightness,ALightness,1);
1489 result.MinIntensity := AMinIntensity;
1490 AddLight(lightObj);
1491end;
1492
1493function TBGRAScene3D.AddPointLight(AVertex: IBGRAVertex3D;
1494 AOptimalDistance: single; ALightness: single; AMinIntensity: single
1495 ): IBGRAPointLight3D;
1496var lightObj: TBGRAPointLight3D;
1497begin
1498 lightObj := TBGRAPointLight3D.Create(AVertex, ALightness*sqr(AOptimalDistance));
1499 result := lightObj;
1500 result.MinIntensity := AMinIntensity;
1501 AddLight(lightObj);
1502end;
1503
1504function TBGRAScene3D.AddDirectionalLight(ADirection: TPoint3D;
1505 AColor: TBGRAPixel; AMinIntensity: single): IBGRADirectionalLight3D;
1506var lightObj: TBGRADirectionalLight3D;
1507begin
1508 lightObj := TBGRADirectionalLight3D.Create(ADirection);
1509 result := lightObj;
1510 result.MinIntensity := AMinIntensity;
1511 result.Color := AColor;
1512 AddLight(lightObj);
1513end;
1514
1515function TBGRAScene3D.AddPointLight(AVertex: IBGRAVertex3D;
1516 AOptimalDistance: single; AColor: TBGRAPixel; AMinIntensity: single
1517 ): IBGRAPointLight3D;
1518var lightObj: TBGRAPointLight3D;
1519begin
1520 lightObj := TBGRAPointLight3D.Create(AVertex,sqr(AOptimalDistance));
1521 result := lightObj;
1522 result.Color := AColor;
1523 result.MinIntensity := AMinIntensity;
1524 AddLight(lightObj);
1525end;
1526
1527procedure TBGRAScene3D.RemoveLight(ALight: IBGRALight3D);
1528var idx: integer;
1529begin
1530 idx := FLights.IndexOf(ALight.GetAsObject);
1531 if idx <> -1 then
1532 begin
1533 ALight._Release;
1534 FLights.Delete(Idx);
1535 end;
1536end;
1537
1538procedure TBGRAScene3D.SetZoom(value: Single);
1539begin
1540 SetZoom(PointF(value,value));
1541end;
1542
1543procedure TBGRAScene3D.SetZoom(value: TPointF);
1544begin
1545 FZoom := value;
1546 FAutoZoom := false;
1547end;
1548
1549function TBGRAScene3D.CreateMaterial: IBGRAMaterial3D;
1550var m: TBGRAMaterial3D;
1551begin
1552 m := TBGRAMaterial3D.Create;
1553 m.OnTextureChanged := @OnMaterialTextureChanged;
1554 result := m;
1555 AddMaterial(result);
1556end;
1557
1558function TBGRAScene3D.CreateMaterial(ASpecularIndex: integer): IBGRAMaterial3D;
1559var m: TBGRAMaterial3D;
1560begin
1561 m := TBGRAMaterial3D.Create;
1562 m.SetSpecularIndex(ASpecularIndex);
1563 m.SetSpecularColor(BGRAWhite);
1564 m.OnTextureChanged := @OnMaterialTextureChanged;
1565 result := m;
1566 AddMaterial(result);
1567end;
1568
1569function TBGRAScene3D.GetMaterialByName(AName: string): IBGRAMaterial3D;
1570var i: integer;
1571begin
1572 for i := 0 to MaterialCount-1 do
1573 if AName = Material[i].Name then
1574 begin
1575 result := Material[i];
1576 exit;
1577 end;
1578 result := nil;
1579end;
1580
1581procedure TBGRAScene3D.UpdateMaterials;
1582var i,j: integer;
1583 obj: IBGRAObject3D;
1584 face: IBGRAFace3D;
1585begin
1586 for i := 0 to Object3DCount-1 do
1587 begin
1588 obj := Object3D[i];
1589 for j := 0 to obj.FaceCount-1 do
1590 begin
1591 face := obj.Face[j];
1592 if face.MaterialName <> '' then
1593 UseMaterial(face.MaterialName,face);
1594 end;
1595 end;
1596end;
1597
1598procedure TBGRAScene3D.UpdateMaterial(AMaterialName: string);
1599var i,j: integer;
1600 obj: IBGRAObject3D;
1601 face: IBGRAFace3D;
1602begin
1603 for i := 0 to Object3DCount-1 do
1604 begin
1605 obj := Object3D[i];
1606 for j := 0 to obj.FaceCount-1 do
1607 begin
1608 face := obj.Face[j];
1609 if face.MaterialName = AMaterialName then
1610 UseMaterial(face.MaterialName,face);
1611 end;
1612 end;
1613end;
1614
1615procedure TBGRAScene3D.ForEachVertex(ACallback: TVertex3DCallback);
1616var i: integer;
1617begin
1618 for i := 0 to Object3DCount-1 do
1619 Object3D[i].ForEachVertex(ACallback);
1620end;
1621
1622procedure TBGRAScene3D.ForEachFace(ACallback: TFace3DCallback);
1623var i: integer;
1624begin
1625 for i := 0 to Object3DCount-1 do
1626 Object3D[i].ForEachFace(ACallback);
1627end;
1628
1629function TBGRAScene3D.MakeLightList: TList;
1630var i: integer;
1631begin
1632 result := TList.Create;
1633 for i := 0 to FLights.Count-1 do
1634 result.Add(FLights[i]);
1635end;
1636
1637initialization
1638
1639 Randomize;
1640
1641end.
1642
Note: See TracBrowser for help on using the repository browser.