-
Notifications
You must be signed in to change notification settings - Fork 0
/
uDecal.pas
153 lines (122 loc) · 4.33 KB
/
uDecal.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
unit uDecal;
interface
uses OpenGL, u3DTypes, uCalc;
const MAX_DECALS = 20;
DECAL_SIZE = 48; //48x48 pixels
DECAL_TIMEOUT = 30000; //30 seconden
type
// Een face waarop decals worden afgebeeld, heeft een (gevulde) array van TDecalRec's.
TDecalRec = record
// de texture-handle van de decal
TextureID: GLuint;
// de 3D-positie van de decal op het vlak/face (inslag-positie van de kogel bv.)
Origin: TVector;
// de 4 (3D)hoekpunten van de (decal)texture
Quad: array[0..3] of TVector;
// De timestamp van het tijdstip voor wissen van deze decal
TimeOfDeath: Int64;
end;
TObjDecals = class(TObject)
private
Active: boolean; // decals afbeelden??
// de array met alle decals
Decal: array of TDecalRec;
N_Decals: Integer; // overall aantal decals
public
// object
constructor Create;
destructor Destroy; override;
// een nieuwe decal berekenen en toevoegen aan de wereld
// resulteer de index in de array Decal.
function Add_BulletHit(DecalOrigin, PlaneNormal, LineOfSight: TVector) : Integer;
procedure KillDecal(DecalIndex: Integer);
// teken Decal[Index], en check de TimeOfDeletion
procedure Render(DecalIndex: Integer);
end;
var Decals : TObjDecals;
implementation
uses Windows;
constructor TObjDecals.Create;
begin
Active := false; //zolang even uit..
N_Decals := 0;
SetLength(Decal, 0);
end;
destructor TObjDecals.Destroy;
begin
SetLength(Decal, 0);
//
inherited;
end;
function TObjDecals.Add_BulletHit(DecalOrigin, PlaneNormal, LineOfSight: TVector): Integer;
var Vx,Vy: TVector;
Freq,T: Int64;
TPms: Single;
begin
Result := -1;
if N_Decals >= MAX_DECALS then Exit;
// een element toevoegen aan de array Decal
Inc(N_Decals);
SetLength(Decal, N_Decals);
Result := N_Decals-1;
// een projectie van de decal, evenwijdig aan de normaal, op de face
// (zou eigenlijk evenwijdig aan de LineOfSight moeten zijn..)
Vx := ScaleVector(UnitVector(CrossProduct(Vector(0,1,0), PlaneNormal)), DECAL_SIZE);
// de lijn loodrecht op Vx en lineofsight..
Vy := ScaleVector(UnitVector(CrossProduct(Vx, PlaneNormal)), DECAL_SIZE);
// de 4 punten van de (decal)face
with Decal[Result] do begin
Quad[0] := AddVector(AddVector(DecalOrigin, InverseVector(Vx)), InverseVector(Vy));
Quad[1] := AddVector(AddVector(DecalOrigin, Vx), InverseVector(Vy));
Quad[2] := AddVector(AddVector(DecalOrigin, Vx), Vy);
Quad[3] := AddVector(AddVector(DecalOrigin, InverseVector(Vx)), Vy);
//
Origin := DecalOrigin;
// de actuele tijd-teller ophalen, en verhogen met de decal-timeout
QueryPerformanceFrequency(Freq);
TPms := Freq/1000; // het aantal ticks per milliseconde
QueryPerformanceCounter(TimeOfDeath);
TimeOfDeath := TimeOfDeath + Round(DECAL_TIMEOUT * TPms);
// kies een texture uit voor de BulletHit
TextureID := 1; //zolang maar even een willekeurige texture {!!!!!DEBUG!!!!!}
end;
end;
procedure TObjDecals.KillDecal(DecalIndex: Integer);
begin
// wis het element[DecalIndex] uit de array Decal..
// (verwissel het element met het laatste element uit de array, en maak de array 1 element korter)
Decal[DecalIndex] := Decal[N_Decals-1];
Dec(N_Decals);
SetLength(Decal, N_Decals);
end;
procedure TObjDecals.Render(DecalIndex: Integer);
var Freq, T: Int64;
begin
// De OpenGL programming guide geeft 2 methoden voor het afbeelden van decals
//--- methode 1:
// depth buffer test inschakelen
// depth buffer writing uitschakelen
// teken de face
// depth buffer writing inschakelen
// teken de decal
// color buffer writing uitschakelen
// teken de face
// color buffer writing aanzetten
//--- methode 2:
// stencil-buffer instellen om:
// een 1 te schrijven, als de depth-test "passes", en een 0 schrijven in de andere gevallen
// teken de face
// stencil-buffer instellen om:
// geen veranderingen maken aan de stencil waarden, maar alleen tekenen als de stencil-waarde == 1
// de depth-buffer-test uitschakelen (en de updates ervan)
// teken de decal
// herstel stencil- & depth-buffer instellingen
// controleer of de decal nog zichtbaar is, en zonodig verwijderen
QueryPerformanceCounter(T);
if T > Decal[DecalIndex].TimeOfDeath then KillDecal(DecalIndex);
end;
initialization
Decals := TObjDecals.Create;
finalization
Decals.Free;
end.