Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
cl_model.qc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011 Rudolf Polzer
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 * IN THE SOFTWARE.
21 */
22#include "cl_model.qh"
23
24#include "cl_player.qh"
25#include "common.qh"
26#include "interpolate.qh"
28
31
36
38{
40 {
41 this.frame3 = this.frame;
42 this.frame3time = this.frame1time;
43 }
45 {
46 this.frame4 = this.frame2;
47 this.frame4time = this.frame2time;
48 }
50 {
53 this.lerpfrac = this.csqcmodel_lerpfrac;
54 }
55}
57{
59 {
60 this.frame2 = this.frame;
61 this.frame2time = this.frame1time;
62 }
63}
65{
66#ifdef CSQCMODEL_HAVE_TWO_FRAMES
68#else
70#endif
71}
72
73void CSQCModel_InterpolateAnimation_2To4_Note(entity this, int sf, bool set_times)
74{
76 {
77 if(set_times)
78 this.frame1time = time;
79 }
81 {
82 if(set_times)
83 this.frame2time = time;
84 }
86 {
87 this.csqcmodel_lerpfrac = this.lerpfrac;
88 if(set_times)
90 }
91}
92void CSQCModel_InterpolateAnimation_1To2_Note(entity this, int sf, bool set_times)
93{
95 {
96 if(set_times)
97 this.frame1time = time;
98 }
99}
101{
102#ifdef CSQCMODEL_HAVE_TWO_FRAMES
104#else
106#endif
107}
108
110{
112 {
113 this.lerpfrac = this.csqcmodel_lerpfrac;
114 this.lerpfrac3 = 0;
115 this.lerpfrac4 = 0;
116 }
117 else
118 {
119 float l13, l24, llf;
120 float l24_13;
121
122 if(this.frame3time == 0) // if frame1/3 were not previously displayed, only frame1 can make sense
123 l13 = 1;
124 else
126
127 if(this.frame4time == 0) // if frame2/4 were not previously displayed, only frame2 can make sense
128 l24 = 1;
129 else
131
132 if(this.csqcmodel_lerpfrac2time == 0) // if there is no old lerpfrac (newly displayed model), only lerpfrac makes sense
133 llf = 1;
134 else
136
137 l24_13 = this.csqcmodel_lerpfrac * llf + this.csqcmodel_lerpfrac2 * (1 - llf);
138
139 this.lerpfrac = l24 * l24_13;
140 this.lerpfrac4 = (1 - l24) * l24_13;
141 this.lerpfrac3 = (1 - l13) * (1 - l24_13);
142
143 if(l24_13 == 0) // if frames 2/4 are not displayed, clear their frametime
144 {
145 this.frame2time = 0;
146 this.frame4time = 0;
147 }
148
149 if(l24_13 == 1) // if frames 1/3 are not displayed, clear their frametime
150 {
151 this.frame1time = 0;
152 this.frame3time = 0;
153 }
154 }
155}
157{
159 {
160 this.lerpfrac = 0;
161 }
162 else
163 {
164 if(this.frame2time == 0) // if frame2 was not previously displayed, only frame1 can make sense
165 this.lerpfrac = 0;
166 else
168 }
169}
171{
172#ifdef CSQCMODEL_HAVE_TWO_FRAMES
174#else
176#endif
177}
178
180{
181 // some nice flags for CSQCMODEL_IF and the hooks
182 bool isplayer = (this.isplayermodel & ISPLAYER_CLIENT);
183 noref bool islocalplayer = (this.entnum == player_localnum + 1);
184 noref bool isnolocalplayer = (isplayer && (this.entnum != player_localnum + 1));
185
186 // we don't do this for the local player as that one is already handled
187 // by CSQCPlayer_SetCamera()
189
191
192 CSQCModel_Hook_PreDraw(this, isplayer);
193
194 if(isplayer)
195 {
196 if(this.entnum == player_localentnum)
198 else
200 }
201
202 // inherit draw flags easily
203 entity root = this;
204 while(root.tag_entity)
205 root = root.tag_entity;
206 if(this != root)
207 {
209 this.renderflags |= (root.renderflags & (RF_EXTERNALMODEL | RF_VIEWMODEL));
210 }
211
212 // we're drawn, now teleporting is over
213 this.csqcmodel_teleported = 0;
214}
215
216entity CSQCModel_players[255]; // 255 is engine limit on maxclients
217
219{
220 CSQCModel_players[this.entnum - 1] = NULL;
221}
222
223NET_HANDLE(ENT_CLIENT_MODEL, bool isnew)
224{
225 int sf = ReadInt24_t();
226 int psf = ReadByte();
227
228 // some nice flags for CSQCMODEL_IF and the hooks
229 bool isplayer = (psf & ISPLAYER_CLIENT) || (this.entnum >= 1 && this.entnum <= maxclients);
230 if (isnew && isplayer)
231 {
232 CSQCModel_players[this.entnum - 1] = this;
233 this.entremove = CSQCModel_remove;
234 }
235 bool islocalplayer = (this.entnum == player_localnum + 1);
236 noref bool isnolocalplayer = (isplayer && !islocalplayer);
237
238 this.isplayermodel = BITSET(this.isplayermodel, ISPLAYER_CLIENT, isplayer);
239 this.isplayermodel = BITSET(this.isplayermodel, ISPLAYER_LOCAL, islocalplayer);
241
242 this.iflags |= IFLAG_ORIGIN; // interpolate origin too
243 this.iflags |= IFLAG_ANGLES; // interpolate angles too
244 this.iflags |= IFLAG_VELOCITY | IFLAG_AUTOVELOCITY; // let's calculate velocity automatically
245
246 CSQCModel_Hook_PreUpdate(this, isnew, isplayer, islocalplayer);
247
251
252#define CSQCMODEL_IF(cond) if(cond) {
253#define CSQCMODEL_ENDIF }
254#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
255 if(sf & flag) \
256 this.f = r();
257#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
258 if(sf & flag) \
259 this.f = (r() + mi) / s;
261#undef CSQCMODEL_PROPERTY_SCALED
262#undef CSQCMODEL_PROPERTY
263#undef CSQCMODEL_ENDIF
264#undef CSQCMODEL_IF
265
267 {
268 vector pmin = this.mins, pmax = this.maxs;
269 setmodelindex(this, this.modelindex); // this retrieves the .model key and sets mins/maxs/absmin/absmax
270 setsize(this, pmin, pmax);
271 }
272
274 {
275 this.iflags |= IFLAG_TELEPORTED;
276 this.csqcmodel_teleported = 1;
277 }
278
279 if(sf & BIT(3))
280 this.alpha = this.m_alpha;
281
282 if(sf & BIT(11))
283 viewloc_SetTags(this);
284
288
289 CSQCModel_Hook_PostUpdate(this, isnew, isplayer, islocalplayer);
290
291#ifdef CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
294#endif
295
296 // relink
297 setorigin(this, this.origin);
298
299 // set obvious render flags
300 if(this.entnum == player_localentnum)
302 else
304
305 // draw it
306 this.drawmask = MASK_NORMAL;
308 return true;
309}
310
315{
316 if (i < maxclients) return CSQCModel_players[i];
317 ++i;
318 LOG_DEBUGF("player out of bounds: %d", i);
319 return findfloat(NULL, entnum, i);
320}
float frame3time
start time of framegroup animation
Definition anim.qh:26
float frame1time
start time of framegroup animation
Definition anim.qh:22
float frame2time
start time of framegroup animation
Definition anim.qh:24
float frame2
secondary framegroup animation (strength = lerpfrac)
Definition anim.qh:8
float lerpfrac
strength of framegroup blend
Definition anim.qh:15
float frame3
tertiary framegroup animation (strength = lerpfrac3)
Definition anim.qh:10
float lerpfrac4
strength of framegroup blend
Definition anim.qh:19
float frame4time
start time of framegroup animation
Definition anim.qh:28
float lerpfrac3
strength of framegroup blend
Definition anim.qh:17
float frame4
quaternary framegroup animation (strength = lerpfrac4)
Definition anim.qh:12
float frame
primary framegroup animation (strength = 1 - lerpfrac - lerpfrac3 - lerpfrac4)
Definition anim.qh:6
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition bits.qh:8
#define BITSET(var, mask, flag)
Definition bits.qh:11
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float autocvar_cl_nolerp
Definition cl_model.qc:30
void CSQCModel_InterpolateAnimation_1To2_Do(entity this)
Definition cl_model.qc:156
void CSQCModel_InterpolateAnimation_2To4_PreNote(entity this, int sf)
Definition cl_model.qc:37
void CSQCModel_InterpolateAnimation_1To2_Note(entity this, int sf, bool set_times)
Definition cl_model.qc:92
void CSQCModel_InterpolateAnimation_1To2_PreNote(entity this, int sf)
Definition cl_model.qc:56
float csqcmodel_lerpfrac
Definition cl_model.qc:32
float csqcmodel_lerpfractime
Definition cl_model.qc:34
float csqcmodel_lerpfrac2time
Definition cl_model.qc:35
entity CSQCModel_server2csqc(int i)
Definition cl_model.qc:314
void CSQCModel_InterpolateAnimation_2To4_Note(entity this, int sf, bool set_times)
Definition cl_model.qc:73
void CSQCModel_InterpolateAnimation_Do(entity this)
Definition cl_model.qc:170
void CSQCModel_InterpolateAnimation_2To4_Do(entity this)
Definition cl_model.qc:109
void CSQCModel_remove(entity this)
Definition cl_model.qc:218
entity CSQCModel_players[255]
Definition cl_model.qc:216
void CSQCModel_InterpolateAnimation_Note(entity this, int sf)
Definition cl_model.qc:100
float autocvar_cl_lerpanim_maxdelta_framegroups
Definition cl_model.qc:29
void CSQCModel_Draw(entity this)
Definition cl_model.qc:179
float csqcmodel_lerpfrac2
Definition cl_model.qc:33
void CSQCModel_InterpolateAnimation_PreNote(entity this, int sf)
Definition cl_model.qc:64
float csqcmodel_teleported
Definition cl_model.qh:39
bool CSQCPlayer_PreUpdate(entity this)
Definition cl_player.qc:673
bool CSQCPlayer_PostUpdate(entity this)
Definition cl_player.qc:680
bool CSQCPlayer_IsLocalPlayer(entity this)
Definition cl_player.qc:210
float alpha
Definition items.qc:13
float renderflags
Definition main.qh:111
float drawmask
float maxclients
float modelindex
const float MASK_NORMAL
float player_localnum
vector mins
const float RF_VIEWMODEL
float time
vector maxs
float player_localentnum
float entnum
vector origin
const float RF_EXTERNALMODEL
void CSQCModel_Hook_PreDraw(entity this, bool isplayer)
void CSQCModel_Hook_PostUpdate(entity this, bool isnew, bool isplayer, bool islocalplayer)
void CSQCModel_Hook_PreUpdate(entity this, bool isnew, bool isplayer, bool islocalplayer)
int isplayermodel
float m_alpha
void InterpolateOrigin_Undo(entity this)
snap origin to iorigin2 (actual origin)
void InterpolateOrigin_Note(entity this)
void InterpolateOrigin_Do(entity this)
set origin based on iorigin1 (old pos), iorigin2 (desired pos), and time
const int IFLAG_AUTOVELOCITY
const int IFLAG_VELOCITY
const int IFLAG_ANGLES
const int IFLAG_ORIGIN
const int IFLAG_TELEPORTED
int iflags
const int CSQCMODEL_PROPERTY_MODELINDEX
Definition common.qh:63
const int ISPLAYER_PLAYER
Definition common.qh:59
const int CSQCMODEL_PROPERTY_FRAME2
Definition common.qh:67
const int ISPLAYER_LOCAL
Definition common.qh:58
const int CSQCMODEL_PROPERTY_FRAME
Definition common.qh:61
const int ISPLAYER_CLIENT
Definition common.qh:57
#define ALLPROPERTIES
Definition common.qh:93
const int CSQCMODEL_PROPERTY_LERPFRAC
Definition common.qh:68
const int CSQCMODEL_PROPERTY_TELEPORTED
Definition common.qh:62
#define NET_HANDLE(id, param)
Definition net.qh:15
int ReadInt24_t()
Definition net.qh:355
int ReadByte()
#define LOG_DEBUGF(...)
Definition log.qh:81
float bound(float min, float value, float max)
entity findfloat(entity start,.float field, float match)
#define NULL
Definition post.qh:14
vector
Definition self.qh:92
#define setpredraw(e, f)
Definition self.qh:84
void viewloc_SetTags(entity this)
Definition viewloc.qc:74