source: trunk/Packages/bgrabitmap/bgracoordpool3d.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 11.0 KB
Line 
1unit BGRACoordPool3D;
2
3{$mode objfpc}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, BGRABitmapTypes, BGRASSE, BGRAMatrix3D;
9
10type
11 PBGRACoordData3D = ^TBGRACoordData3D;
12 TBGRACoordData3D = packed record
13 {0} sceneCoord: TPoint3D_128;
14 {16} viewCoord: TPoint3D_128;
15 {32} projectedCoord: TPointF;
16 {40} InvZ: single;
17 {44} used: wordbool; customNormalUsed: wordbool;
18 {48} viewNormal: TPoint3D_128;
19 {64} customNormal: TPoint3D_128;
20 end; {80}
21
22 PBGRANormalData3D = ^TBGRANormalData3D;
23 TBGRANormalData3D = packed record
24 {0} customNormal: TPoint3D_128;
25 {16} viewNormal: TPoint3D_128;
26 {32} used: longbool;
27 {36} filler1,filler2,filler3: longword;
28 end; {48}
29
30 { TBGRAGenericPool }
31
32 TBGRAGenericPool = class
33 private
34 FFirstFree: integer;
35 FNbElements,FCapacity: integer;
36 FElementSize: PtrInt;
37 FUsedCapacity : integer;
38 function GetElement(AIndex: integer): Pointer;
39 procedure SetCapacity(ACapacity: integer);
40 protected
41 FPoolData: TMemoryBlockAlign128;
42 function GetUsed({%H-}AElement: integer): boolean; virtual;
43 procedure SetUsed({%H-}AElement: integer; {%H-}AUsed: boolean); virtual;
44 procedure Remove(AIndex: integer); //does not work if GetUsed/SetUsed are not implemented
45 public
46 constructor Create(ACapacity: integer; AElementSize: integer);
47 destructor Destroy; override;
48 function Add: integer;
49 property Element[AIndex: integer]: Pointer read GetElement;
50 property Capacity: integer read FCapacity;
51 property UsedCapacity: integer read FUsedCapacity;
52 end;
53
54 { TBGRACoordPool3D }
55
56 TBGRACoordPool3D = class(TBGRAGenericPool)
57 private
58 function GetCoordData(AIndex: integer): PBGRACoordData3D;
59 protected
60 function GetUsed(AElement: integer): boolean; override;
61 procedure SetUsed(AElement: integer; AUsed: boolean); override;
62 public
63 procedure Remove(AIndex: integer);
64 constructor Create(ACapacity: integer);
65 procedure ComputeWithMatrix(const AMatrix: TMatrix3D; const AProjection: TProjection3D);
66 property CoordData[AIndex: integer]: PBGRACoordData3D read GetCoordData;
67 end;
68
69 { TBGRANormalPool3D }
70
71 TBGRANormalPool3D = class(TBGRAGenericPool)
72 private
73 function GetNormalData(AIndex: integer): PBGRANormalData3D;
74 protected
75 function GetUsed(AElement: integer): boolean; override;
76 procedure SetUsed(AElement: integer; AUsed: boolean); override;
77 public
78 procedure Remove(AIndex: integer);
79 constructor Create(ACapacity: integer);
80 procedure ComputeWithMatrix(const AMatrix: TMatrix3D);
81 property NormalData[AIndex: integer]: PBGRANormalData3D read GetNormalData;
82 end;
83
84implementation
85
86{ TBGRAGenericPool }
87
88function TBGRAGenericPool.GetElement(AIndex: integer): Pointer;
89begin
90 result := Pointer(PByte(FPoolData.Data)+AIndex*FElementSize);
91end;
92
93procedure TBGRAGenericPool.SetCapacity(ACapacity: integer);
94var NewPoolData: TMemoryBlockAlign128;
95begin
96 if FCapacity <> ACapacity then
97 begin
98 if ACapacity = 0 then
99 FreeAndNil(FPoolData)
100 else
101 begin
102 NewPoolData := TMemoryBlockAlign128.Create(ACapacity*FElementSize);
103 if FCapacity <> 0 then
104 begin
105 //previous block is smaller
106 if FCapacity < ACapacity then
107 begin
108 move(FPoolData.Data^, NewPoolData.Data^, FCapacity*FElementSize);
109 //pad with zeros
110 fillchar((pbyte(NewPoolData.Data)+FCapacity*FElementSize)^,(ACapacity-FCapacity)*FElementSize,0);
111 end
112 else //previous block is greater or equal
113 move(FPoolData.Data^, NewPoolData.Data^, ACapacity*FElementSize);
114 FreeAndNil(FPoolData);
115 end else
116 //clear new block
117 fillchar(pbyte(NewPoolData.Data)^,ACapacity*FElementSize,0);
118
119 FPoolData := NewPoolData;
120 end;
121 FCapacity:= ACapacity;
122 end;
123end;
124
125function TBGRAGenericPool.GetUsed(AElement: integer): boolean;
126begin
127 result := false;
128end;
129
130procedure TBGRAGenericPool.SetUsed(AElement: integer; AUsed: boolean);
131begin
132 //nothing
133end;
134
135constructor TBGRAGenericPool.Create(ACapacity: integer; AElementSize: integer);
136begin
137 FCapacity := 0;
138 FPoolData := nil;
139 FNbElements:= 0;
140 FFirstFree := 0;
141 FUsedCapacity := 0;
142 FElementSize:= AElementSize;
143 SetCapacity(ACapacity);
144end;
145
146destructor TBGRAGenericPool.Destroy;
147begin
148 FreeAndNil(FPoolData);
149 FCapacity := 0;
150 FNbElements:= 0;
151 FFirstFree := 0;
152 FUsedCapacity := 0;
153 inherited Destroy;
154end;
155
156procedure TBGRAGenericPool.Remove(AIndex: integer);
157begin
158 if (AIndex < 0) or (AIndex >= FUsedCapacity) then
159 raise ERangeError.Create('Index out of bounds');
160 if GetUsed(AIndex) then
161 begin
162 SetUsed(AIndex, false);
163 if AIndex < FFirstFree then FFirstFree := AIndex;
164 if AIndex = FUsedCapacity-1 then
165 begin
166 while (FUsedCapacity > 0) and not GetUsed(FUsedCapacity-1) do
167 dec(FUsedCapacity);
168 end;
169 end;
170end;
171
172function TBGRAGenericPool.Add: integer;
173begin
174 //check for free space
175 while FFirstFree < FCapacity do
176 begin
177 if not GetUsed(FFirstFree) then
178 begin
179 SetUsed(FFirstFree,True);
180 result := FFirstFree;
181 inc(FFirstFree);
182 if FFirstFree > FUsedCapacity then
183 FUsedCapacity := FFirstFree;
184 exit;
185 end;
186 inc(FFirstFree);
187 end;
188
189 //no free space
190 SetCapacity(FCapacity*2+8);
191 SetUsed(FFirstFree, true);
192 result := FFirstFree;
193 inc(FFirstFree);
194 if FFirstFree > FUsedCapacity then
195 FUsedCapacity := FFirstFree;
196end;
197
198{ TBGRACoordPool3D }
199
200constructor TBGRACoordPool3D.Create(ACapacity: integer);
201begin
202 inherited Create(ACapacity,SizeOf(TBGRACoordData3D));
203end;
204
205procedure TBGRACoordPool3D.ComputeWithMatrix(const AMatrix: TMatrix3D;
206 const AProjection: TProjection3D);
207var
208 P: PBGRACoordData3D;
209 I: NativeInt;
210begin
211 if UsedCapacity = 0 then exit;
212 P := PBGRACoordData3D(FPoolData.Data);
213 {$IFDEF CPUI386}
214 {$IFDEF BGRASSE_AVAILABLE}
215 {$asmmode intel}
216 if UseSSE then
217 begin
218 Matrix3D_SSE_Load(AMatrix);
219 asm
220 mov eax,[AProjection]
221 movups xmm4,[eax]
222 xorps xmm1,xmm1
223 end;
224 i := UsedCapacity;
225 if UseSSE3 then
226 begin
227 while i > 0 do
228 with P^ do
229 begin
230 if used then
231 begin
232 MatrixMultiplyVect3D_SSE3_Aligned(sceneCoord,viewCoord);
233 if viewCoord.z > 0 then
234 begin
235 asm
236 mov eax, P
237 movaps xmm3, [eax+16] //viewCoord
238 movaps xmm2,xmm3
239 shufps xmm2,xmm3,2+8+32+128
240 rcpps xmm2,xmm2 //xmm2 = InvZ
241 movss [eax+40],xmm2 //-> InvZ
242
243 mulps xmm3,xmm4 //xmm3 *= Projection.Zoom
244 mulps xmm3,xmm2 //xmm3 *= InvZ
245
246 movhlps xmm0,xmm4 //xmm0 = Projection.Center
247 addps xmm3,xmm0 //xmm3 += Projection.Center
248
249 movlps [eax+32],xmm3 //->projectedCoord
250 movaps [eax+48],xmm1 //->normal
251 end;
252 end else
253 asm
254 mov eax, P
255 movlps [eax+32],xmm1 //0->projectedCoord
256 movaps [eax+48],xmm1 //->normal
257 end;
258 if customNormalUsed then
259 MatrixMultiplyVect3DWithoutTranslation_SSE3_Aligned(customNormal,viewNormal);
260 end;
261 dec(i);
262 inc(p);
263 end;
264 end else
265 begin
266 while i > 0 do
267 with P^ do
268 begin
269 if used then
270 begin
271 MatrixMultiplyVect3D_SSE_Aligned(sceneCoord,viewCoord);
272 if viewCoord.z > 0 then
273 begin
274 asm
275 mov eax, P
276 movaps xmm3, [eax+16] //viewCoord
277 movaps xmm2,xmm3
278 shufps xmm2,xmm3,2+8+32+128
279 rcpps xmm2,xmm2 //xmm2 = InvZ
280 movss [eax+40],xmm2 //-> InvZ
281
282 mulps xmm3,xmm4 //xmm3 *= Projection.Zoom
283 mulps xmm3,xmm2 //xmm3 *= InvZ
284
285 movhlps xmm0,xmm4 //xmm0 = Projection.Center
286 addps xmm3,xmm0 //xmm3 += Projection.Center
287
288 movlps [eax+32],xmm3 //->projectedCoord
289 movaps [eax+48],xmm1 //->normal
290 end;
291 end else
292 asm
293 mov eax, P
294 movlps [eax+32],xmm1 //0 ->projectedCoord
295 movaps [eax+48],xmm1 //->normal
296 end;
297 if customNormalUsed then
298 MatrixMultiplyVect3DWithoutTranslation_SSE_Aligned(customNormal,viewNormal);
299 end;
300 dec(i);
301 inc(p);
302 end;
303 end;
304 end
305 else
306 {$ENDIF}
307 {$ENDIF}
308 begin
309 i := UsedCapacity;
310 while i > 0 do
311 with P^ do
312 begin
313 if used then
314 begin
315 viewCoord := AMatrix*sceneCoord;
316 if customNormalUsed then
317 viewNormal := MultiplyVect3DWithoutTranslation(AMatrix,customNormal)
318 else
319 ClearPoint3D_128(viewNormal);
320 if viewCoord.z > 0 then
321 begin
322 InvZ := 1/viewCoord.z;
323 projectedCoord := PointF(viewCoord.x*InvZ*AProjection.Zoom.x + AProjection.Center.x,
324 viewCoord.y*InvZ*AProjection.Zoom.Y + AProjection.Center.y);
325 end else
326 projectedCoord := PointF(0,0);
327 end;
328 dec(i);
329 inc(p);
330 end;
331 end;
332end;
333
334function TBGRACoordPool3D.GetCoordData(AIndex: integer): PBGRACoordData3D;
335begin
336 result := PBGRACoordData3D(FPoolData.Data)+AIndex;
337end;
338
339function TBGRACoordPool3D.GetUsed(AElement: integer): boolean;
340begin
341 Result:= CoordData[AElement]^.used;
342end;
343
344procedure TBGRACoordPool3D.SetUsed(AElement: integer; AUsed: boolean);
345begin
346 CoordData[AElement]^.used := AUsed;
347end;
348
349procedure TBGRACoordPool3D.Remove(AIndex: integer);
350begin
351 inherited Remove(AIndex);
352end;
353
354{ TBGRANormalPool3D }
355
356function TBGRANormalPool3D.GetNormalData(AIndex: integer): PBGRANormalData3D;
357begin
358 result := PBGRANormalData3D(FPoolData.Data)+AIndex;
359end;
360
361function TBGRANormalPool3D.GetUsed(AElement: integer): boolean;
362begin
363 Result:= NormalData[AElement]^.used;
364end;
365
366procedure TBGRANormalPool3D.SetUsed(AElement: integer; AUsed: boolean);
367begin
368 NormalData[AElement]^.used := AUsed;
369end;
370
371procedure TBGRANormalPool3D.Remove(AIndex: integer);
372begin
373 inherited Remove(AIndex);
374end;
375
376constructor TBGRANormalPool3D.Create(ACapacity: integer);
377begin
378 inherited Create(ACapacity,SizeOf(TBGRANormalData3D));
379end;
380
381procedure TBGRANormalPool3D.ComputeWithMatrix(const AMatrix: TMatrix3D);
382var
383 P: PBGRANormalData3D;
384 I: NativeInt;
385begin
386 if UsedCapacity = 0 then exit;
387 P := PBGRANormalData3D(FPoolData.Data);
388 {$IFDEF CPUI386}
389 {$IFDEF BGRASSE_AVAILABLE}
390 {$asmmode intel}
391 if UseSSE then
392 begin
393 Matrix3D_SSE_Load(AMatrix);
394 i := UsedCapacity;
395 if UseSSE3 then
396 begin
397 while i > 0 do
398 with P^ do
399 begin
400 if used then
401 MatrixMultiplyVect3DWithoutTranslation_SSE3_Aligned(customNormal,viewNormal);
402 dec(i);
403 inc(p);
404 end;
405 end else
406 begin
407 while i > 0 do
408 with P^ do
409 begin
410 if used then
411 MatrixMultiplyVect3DWithoutTranslation_SSE_Aligned(customNormal,viewNormal);
412 dec(i);
413 inc(p);
414 end;
415 end;
416 end
417 else
418 {$ENDIF}
419 {$ENDIF}
420 begin
421 i := UsedCapacity;
422 while i > 0 do
423 with P^ do
424 begin
425 if used then
426 viewNormal := MultiplyVect3DWithoutTranslation(AMatrix,customNormal);
427 dec(i);
428 inc(p);
429 end;
430 end;
431end;
432
433end.
434
Note: See TracBrowser for help on using the repository browser.