DEADSOFTWARE

1602f23e0d2b346d9c4f10e77665ca249486657d
[d2df-sdl.git] / src / game / opengl / r_playermodel.pas
1 (* Copyright (C) Doom 2D: Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 {$INCLUDE ../../shared/a_modes.inc}
16 unit r_playermodel;
18 interface
20 uses g_playermodel; // TPlayerModel
22 procedure r_PlayerModel_Load;
23 procedure r_PlayerModel_Free;
24 procedure r_PlayerModel_Draw (pm: TPlayerModel; X, Y: Integer; Alpha: Byte = 0);
26 implementation
28 uses
29 SysUtils, Classes, Math,
30 MAPDEF, utils,
31 ImagingTypes, Imaging, ImagingUtility,
32 r_graphics, g_options, r_animations, r_textures,
33 g_base, g_basic, g_map, g_weapons
34 ;
36 const
37 WeapNames: Array [WP_FIRST + 1..WP_LAST] of String = ('csaw', 'hgun', 'sg', 'ssg', 'mgun', 'rkt', 'plz', 'bfg', 'spl', 'flm');
39 type
40 TDirIdx = TDirection.D_LEFT..TDirection.D_RIGHT;
41 TAnimIdx = A_STAND..A_LAST;
43 var
44 WeaponID: Array [WP_FIRST + 1..WP_LAST, W_POS_NORMAL..W_POS_DOWN, W_ACT_NORMAL..W_ACT_FIRE] of DWORD;
45 Models: Array of record
46 Frames: Array [TDirIdx, TAnimIdx] of record
47 base: DWORD;
48 mask: DWORD;
49 end;
50 end;
52 procedure ExtAnimFromBaseAnim(MName: String; AIdx: Integer);
53 const
54 CopyAnim: array [A_LASTBASE+1..A_LASTEXT] of Integer = (
55 A_WALK, A_WALK, A_WALK, A_WALK, A_WALK,
56 A_STAND, A_WALK, A_ATTACK, A_WALK, A_SEEUP, A_SEEDOWN,
57 A_ATTACKUP, A_ATTACKDOWN
58 );
59 var
60 OIdx: Integer;
61 AName, OName: String;
62 begin
63 // HACK: shitty workaround to duplicate base animations
64 // in place of extended, replace with something better later
66 Assert((AIdx > A_LASTBASE) and (AIdx <= A_LASTEXT));
67 OIdx := CopyAnim[AIdx];
69 AName := MName + '_RIGHTANIM' + IntToStr(AIdx);
70 OName := MName + '_RIGHTANIM' + IntToStr(OIdx);
71 Assert(g_Frames_Dup(AName, OName));
72 Assert(g_Frames_Dup(AName + '_MASK', OName + '_MASK'));
73 AName := MName + '_LEFTANIM' + IntToStr(AIdx);
74 OName := MName + '_LEFTANIM' + IntToStr(OIdx);
75 if g_Frames_Exists(AName) then
76 begin
77 g_Frames_Dup(AName, OName);
78 g_Frames_Dup(AName + '_MASK', OName + '_MASK');
79 end;
80 end;
82 procedure r_PlayerModel_Load;
83 var ID1, ID2: DWORD; i, a, b: Integer; prefix, aname: String;
84 begin
85 for a := WP_FIRST + 1 to WP_LAST do
86 begin
87 g_Texture_CreateWAD(WeaponID[a][W_POS_NORMAL][W_ACT_NORMAL], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a]));
88 g_Texture_CreateWAD(WeaponID[a][W_POS_NORMAL][W_ACT_FIRE], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_FIRE');
89 g_Texture_CreateWAD(WeaponID[a][W_POS_UP][W_ACT_NORMAL], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_UP');
90 g_Texture_CreateWAD(WeaponID[a][W_POS_UP][W_ACT_FIRE], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_UP_FIRE');
91 g_Texture_CreateWAD(WeaponID[a][W_POS_DOWN][W_ACT_NORMAL], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_DN');
92 g_Texture_CreateWAD(WeaponID[a][W_POS_DOWN][W_ACT_FIRE], GameWAD+':WEAPONS\'+UpperCase(WeapNames[a])+'_DN_FIRE');
93 end;
94 Models := nil;
95 if PlayerModelsArray <> nil then
96 begin
97 SetLength(Models, Length(PlayerModelsArray));
98 for i := 0 to High(PlayerModelsArray) do
99 begin
100 prefix := PlayerModelsArray[i].FileName + ':TEXTURES\';
101 for b := A_STAND to A_LAST do
102 begin
103 aname := PlayerModelsArray[i].Info.Name + '_RIGHTANIM' + IntToStr(b);
104 with PlayerModelsArray[i].Anim[TDirection.D_RIGHT, b] do
105 begin
106 if not (g_Frames_CreateWAD(@ID1, aname, prefix + Resource, 64, 64, Frames, Back) and
107 g_Frames_CreateWAD(@ID2, aname + '_MASK', prefix + Mask, 64, 64, Frames, Back)) then
108 begin
109 if b > A_LASTBASE then
110 begin
111 ExtAnimFromBaseAnim(PlayerModelsArray[i].Info.Name, b);
112 continue
113 end
114 end;
115 Models[i].Frames[TDirection.D_RIGHT, b].base := ID1;
116 Models[i].Frames[TDirection.D_RIGHT, b].mask := ID2;
117 end;
118 with PlayerModelsArray[i].Anim[TDirection.D_LEFT, b] do
119 begin
120 if (Resource <> '') and (Mask <> '') then
121 begin
122 aname := PlayerModelsArray[i].Info.Name + '_LEFTANIM' + IntToStr(b);
123 g_Frames_CreateWAD(@ID1, aname, prefix + Resource, 64, 64, Frames, Back);
124 g_Frames_CreateWAD(@ID2, aname + '_MASK', prefix + Mask, 64, 64, Frames, Back);
125 Models[i].Frames[TDirection.D_LEFT, b].base := ID1;
126 Models[i].Frames[TDirection.D_LEFT, b].mask := ID2;
127 end
128 end
129 end
130 end
131 end
132 end;
134 procedure r_PlayerModel_Free;
135 var i, a, b, c: Integer;
136 begin
137 if PlayerModelsArray = nil then Exit;
138 for i := 0 to High(PlayerModelsArray) do
139 begin
140 with PlayerModelsArray[i] do
141 begin
142 for a := A_STAND to A_LAST do
143 begin
144 g_Frames_DeleteByName(Info.Name+'_LEFTANIM'+IntToStr(a));
145 g_Frames_DeleteByName(Info.Name+'_LEFTANIM'+IntToStr(a)+'_MASK');
146 g_Frames_DeleteByName(Info.Name+'_RIGHTANIM'+IntToStr(a));
147 g_Frames_DeleteByName(Info.Name+'_RIGHTANIM'+IntToStr(a)+'_MASK');
148 end;
149 if Gibs <> nil then
150 begin
151 for a := 0 to High(Gibs) do
152 begin
153 e_DeleteTexture(Gibs[a].ID);
154 e_DeleteTexture(Gibs[a].MaskID);
155 Gibs[a].ID := DWORD(-1);
156 Gibs[a].MaskID := DWORD(-1);
157 end
158 end
159 end
160 end;
161 for a := WP_FIRST + 1 to WP_LAST do
162 for b := W_POS_NORMAL to W_POS_DOWN do
163 for c := W_ACT_NORMAL to W_ACT_FIRE do
164 e_DeleteTexture(WeaponID[a][b][c])
165 end;
167 procedure r_PlayerModel_Draw (pm: TPlayerModel; X, Y: Integer; Alpha: Byte = 0);
168 var
169 Mirror: TMirrorType;
170 pos, act: Byte;
171 p: TDFPoint;
172 FramesID: DWORD;
173 begin
174 // Флаги:
175 if pm.Direction = TDirection.D_LEFT then
176 Mirror := TMirrorType.None
177 else
178 Mirror := TMirrorType.Horizontal;
180 if (pm.Flag <> FLAG_NONE) and (pm.FlagAnim <> nil) and (not (pm.CurrentAnimation in [A_DIE1, A_DIE2])) then
181 begin
182 p.X := IfThen(pm.Direction = TDirection.D_LEFT, FLAG_BASEPOINT.X, 64 - FLAG_BASEPOINT.X);
183 p.Y := FLAG_BASEPOINT.Y;
185 r_Animation_DrawEx(pm.FlagAnim, X+IfThen(pm.Direction = TDirection.D_LEFT, pm.FlagPoint.X-1, 2*FLAG_BASEPOINT.X-pm.FlagPoint.X+1)-FLAG_BASEPOINT.X,
186 Y+pm.FlagPoint.Y-FLAG_BASEPOINT.Y+1, Mirror, p,
187 IfThen(pm.Direction = TDirection.D_RIGHT, pm.FlagAngle, -pm.FlagAngle));
188 end;
190 // Оружие:
191 if pm.Direction = TDirection.D_RIGHT then
192 Mirror := TMirrorType.None
193 else
194 Mirror := TMirrorType.Horizontal;
196 if PlayerModelsArray[pm.id].Info.HaveWeapon and (not (pm.CurrentAnimation in [A_DIE1, A_DIE2, A_PAIN])) and (pm.CurrentWeapon in [WP_FIRST + 1..WP_LAST]) then
197 begin
198 if pm.CurrentAnimation in [A_SEEUP, A_ATTACKUP] then
199 pos := W_POS_UP
200 else
201 if pm.CurrentAnimation in [A_SEEDOWN, A_ATTACKDOWN] then
202 pos := W_POS_DOWN
203 else
204 pos := W_POS_NORMAL;
206 if (pm.CurrentAnimation in [A_ATTACK, A_ATTACKUP, A_ATTACKDOWN]) or pm.Fire then
207 act := W_ACT_FIRE
208 else
209 act := W_ACT_NORMAL;
211 if Alpha < 201 then
212 e_Draw(
213 WeaponID[pm.CurrentWeapon][pos][act],
214 X + PlayerModelsArray[pm.id].WeaponPoints[pm.CurrentWeapon, pm.CurrentAnimation, pm.Direction, pm.AnimState.CurrentFrame].X,
215 Y + PlayerModelsArray[pm.id].WeaponPoints[pm.CurrentWeapon, pm.CurrentAnimation, pm.Direction, pm.AnimState.CurrentFrame].Y,
216 0,
217 True,
218 False,
219 Mirror
220 );
221 end;
223 // Модель:
224 if (pm.Direction = TDirection.D_LEFT) and (Models[pm.id].Frames[TDirection.D_LEFT, pm.CurrentAnimation].base <> 0) then
225 begin
226 pm.AnimState.Alpha := Alpha; // !!!
227 FramesID := Models[pm.id].Frames[TDirection.D_LEFT, pm.CurrentAnimation].base;
228 r_AnimationState_Draw(FramesID, pm.AnimState, X, Y, TMirrorType.None);
229 end
230 else
231 begin
232 pm.AnimState.Alpha := Alpha; // !!!
233 FramesID := Models[pm.id].Frames[TDirection.D_RIGHT, pm.CurrentAnimation].base;
234 r_AnimationState_Draw(FramesID, pm.AnimState, X, Y, Mirror);
235 end;
237 // Маска модели:
238 e_Colors := pm.Color;
240 if (pm.Direction = TDirection.D_LEFT) and (Models[pm.id].Frames[TDirection.D_LEFT, pm.CurrentAnimation].mask <> 0) then
241 begin
242 pm.AnimState.Alpha := Alpha; // !!!
243 FramesID := Models[pm.id].Frames[TDirection.D_LEFT, pm.CurrentAnimation].mask;
244 r_AnimationState_Draw(FramesID, pm.AnimState, X, Y, TMirrorType.None);
245 end
246 else
247 begin
248 pm.AnimState.Alpha := Alpha; // !!!
249 FramesID := Models[pm.id].Frames[TDirection.D_RIGHT, pm.CurrentAnimation].mask;
250 r_AnimationState_Draw(FramesID, pm.AnimState, X, Y, Mirror);
251 end;
253 e_Colors.R := 255;
254 e_Colors.G := 255;
255 e_Colors.B := 255;
256 end;
258 end.