~ubuntu-branches/debian/stretch/assaultcube-data/stretch

« back to all changes in this revision

Viewing changes to source/src/rendermodel.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Gonéri Le Bouder, Ansgar Burchardt, Gonéri Le Bouder
  • Date: 2010-04-02 23:37:55 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100402233755-kf74fxwlu634o6vg
Tags: 1.0.4+repack1-1
[ Ansgar Burchardt ]
* debian/control: fix typo in short description

[ Gonéri Le Bouder ]
* Upgrade to 1.0.4
* bump standards-version to 3.8.4
* Add Depends: ${misc:Depends} just to avoid a lintian warning
* Add a debian/source/format file for the same reason

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "pch.h"
 
2
#include "cube.h"
 
3
 
 
4
VARP(animationinterpolationtime, 0, 150, 1000);
 
5
 
 
6
model *loadingmodel = NULL;
 
7
 
 
8
#include "tristrip.h"
 
9
#include "modelcache.h"
 
10
#include "vertmodel.h"
 
11
#include "md2.h"
 
12
#include "md3.h"
 
13
 
 
14
#define checkmdl if(!loadingmodel) { conoutf("not loading a model"); return; }
 
15
 
 
16
void mdlcullface(int cullface)
 
17
{
 
18
    checkmdl;
 
19
    loadingmodel->cullface = cullface!=0;
 
20
}
 
21
 
 
22
COMMAND(mdlcullface, ARG_1INT);
 
23
 
 
24
void mdlvertexlight(int vertexlight)
 
25
{
 
26
    checkmdl;
 
27
    loadingmodel->vertexlight = vertexlight!=0;
 
28
}
 
29
 
 
30
COMMAND(mdlvertexlight, ARG_1INT);
 
31
 
 
32
void mdltranslucent(int translucency)
 
33
{
 
34
    checkmdl;
 
35
    loadingmodel->translucency = translucency/100.0f;
 
36
}
 
37
 
 
38
COMMAND(mdltranslucent, ARG_1INT);
 
39
 
 
40
void mdlalphatest(int alphatest)
 
41
{
 
42
    checkmdl;
 
43
    loadingmodel->alphatest = alphatest/100.0f;
 
44
}
 
45
 
 
46
COMMAND(mdlalphatest, ARG_1INT);
 
47
 
 
48
void mdlscale(int percent)
 
49
{
 
50
    checkmdl;
 
51
    float scale = 0.3f;
 
52
    if(percent>0) scale = percent/100.0f;
 
53
    else if(percent<0) scale = 0.0f;
 
54
    loadingmodel->scale = scale;
 
55
}
 
56
 
 
57
COMMAND(mdlscale, ARG_1INT);
 
58
 
 
59
void mdltrans(char *x, char *y, char *z)
 
60
{
 
61
    checkmdl;
 
62
    loadingmodel->translate = vec(atof(x), atof(y), atof(z));
 
63
}
 
64
 
 
65
COMMAND(mdltrans, ARG_3STR);
 
66
 
 
67
void mdlshadowdist(int dist)
 
68
{
 
69
    checkmdl;
 
70
    loadingmodel->shadowdist = dist;
 
71
}
 
72
 
 
73
COMMAND(mdlshadowdist, ARG_1INT);
 
74
 
 
75
void mdlcachelimit(int limit)
 
76
{
 
77
    checkmdl;
 
78
    loadingmodel->cachelimit = limit;
 
79
}
 
80
 
 
81
COMMAND(mdlcachelimit, ARG_1INT);
 
82
 
 
83
vector<mapmodelinfo> mapmodels;
 
84
 
 
85
void mapmodel(char *rad, char *h, char *zoff, char *snap, char *name)
 
86
{
 
87
    mapmodelinfo &mmi = mapmodels.add();
 
88
    mmi.rad = atoi(rad);
 
89
    mmi.h = atoi(h);
 
90
    mmi.zoff = atoi(zoff);
 
91
    s_sprintf(mmi.name)("mapmodels/%s", name);
 
92
}
 
93
 
 
94
void mapmodelreset()
 
95
{
 
96
    if(execcontext==IEXC_MAPCFG) mapmodels.setsize(0);
 
97
}
 
98
 
 
99
mapmodelinfo &getmminfo(int i) { return mapmodels.inrange(i) ? mapmodels[i] : *(mapmodelinfo *)0; }
 
100
 
 
101
COMMAND(mapmodel, ARG_5STR);
 
102
COMMAND(mapmodelreset, ARG_NONE);
 
103
 
 
104
hashtable<const char *, model *> mdllookup;
 
105
 
 
106
model *loadmodel(const char *name, int i)
 
107
{
 
108
    if(!name)
 
109
    {
 
110
        if(!mapmodels.inrange(i)) return NULL;
 
111
        mapmodelinfo &mmi = mapmodels[i];
 
112
        if(mmi.m) return mmi.m;
 
113
        name = mmi.name;
 
114
    }
 
115
    model **mm = mdllookup.access(name);
 
116
    model *m;
 
117
    if(mm) m = *mm;
 
118
    else
 
119
    {
 
120
        m = new md2(name);
 
121
        loadingmodel = m;
 
122
        if(!m->load())
 
123
        {
 
124
            delete m;
 
125
            m = new md3(name);
 
126
            loadingmodel = m;
 
127
            if(!m->load())
 
128
            {
 
129
                delete m;
 
130
                loadingmodel = NULL;
 
131
                return NULL;
 
132
            }
 
133
        }
 
134
        loadingmodel = NULL;
 
135
        mdllookup.access(m->name(), m);
 
136
    }
 
137
    if(mapmodels.inrange(i) && !mapmodels[i].m) mapmodels[i].m = m;
 
138
    return m;
 
139
}
 
140
 
 
141
void cleanupmodels()
 
142
{
 
143
    enumerate(mdllookup, model *, m, m->cleanup());
 
144
}
 
145
 
 
146
VARP(dynshadow, 0, 40, 100);
 
147
VARP(dynshadowdecay, 0, 1000, 3000);
 
148
 
 
149
struct batchedmodel
 
150
{
 
151
    vec o;
 
152
    int anim, varseed, tex;
 
153
    float yaw, pitch, speed;
 
154
    int basetime;
 
155
    playerent *d;
 
156
    int attached;
 
157
    float scale;
 
158
};
 
159
struct modelbatch
 
160
{
 
161
    model *m;
 
162
    vector<batchedmodel> batched;
 
163
};
 
164
static vector<modelbatch *> batches;
 
165
static vector<modelattach> modelattached;
 
166
static int numbatches = -1;
 
167
 
 
168
void startmodelbatches()
 
169
{
 
170
    numbatches = 0;
 
171
    modelattached.setsizenodelete(0);
 
172
}
 
173
 
 
174
batchedmodel &addbatchedmodel(model *m)
 
175
{
 
176
    modelbatch *b = NULL;
 
177
    if(m->batch>=0 && m->batch<numbatches && batches[m->batch]->m==m) b = batches[m->batch];
 
178
    else
 
179
    {
 
180
        if(numbatches<batches.length())
 
181
        {
 
182
            b = batches[numbatches];
 
183
            b->batched.setsizenodelete(0);
 
184
        }
 
185
        else b = batches.add(new modelbatch);
 
186
        b->m = m;
 
187
        m->batch = numbatches++;
 
188
    }
 
189
    return b->batched.add();
 
190
}
 
191
 
 
192
void renderbatchedmodel(model *m, batchedmodel &b)
 
193
{
 
194
    modelattach *a = NULL;
 
195
    if(b.attached>=0) a = &modelattached[b.attached];
 
196
 
 
197
    if(stenciling)
 
198
    {
 
199
        m->render(b.anim|ANIM_NOSKIN, b.varseed, b.speed, b.basetime, b.o, b.yaw, b.pitch, b.d, a, b.scale);
 
200
        return;
 
201
    }
 
202
 
 
203
    int x = (int)b.o.x, y = (int)b.o.y;
 
204
    if(!OUTBORD(x, y))
 
205
    {
 
206
        sqr *s = S(x, y);
 
207
        glColor3ub(s->r, s->g, s->b);
 
208
    }
 
209
    else glColor3f(1, 1, 1);
 
210
 
 
211
    m->setskin(b.tex);
 
212
 
 
213
    if(b.anim&ANIM_TRANSLUCENT)
 
214
    {
 
215
        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
 
216
        m->render(b.anim|ANIM_NOSKIN, b.varseed, b.speed, b.basetime, b.o, b.yaw, b.pitch, b.d, a, b.scale);
 
217
        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
 
218
 
 
219
        glDepthFunc(GL_LEQUAL);
 
220
        glEnable(GL_BLEND);
 
221
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
222
 
 
223
        GLfloat color[4];
 
224
        glGetFloatv(GL_CURRENT_COLOR, color);
 
225
        glColor4f(color[0], color[1], color[2], m->translucency);
 
226
    }
 
227
 
 
228
    m->render(b.anim, b.varseed, b.speed, b.basetime, b.o, b.yaw, b.pitch, b.d, a, b.scale);
 
229
 
 
230
    if(b.anim&ANIM_TRANSLUCENT)
 
231
    {
 
232
        glDepthFunc(GL_LESS);
 
233
        glDisable(GL_BLEND);
 
234
    }
 
235
}
 
236
 
 
237
void renderbatchedmodelshadow(model *m, batchedmodel &b)
 
238
{
 
239
    int x = (int)b.o.x, y = (int)b.o.y;
 
240
    if(OUTBORD(x, y)) return;
 
241
    sqr *s = S(x, y);
 
242
    vec center(b.o.x, b.o.y, s->floor);
 
243
    if(s->type==FHF) center.z -= s->vdelta/4.0f;
 
244
    if(dynshadowquad && center.z-0.1f>b.o.z) return;
 
245
    center.z += 0.1f;
 
246
    modelattach *a = NULL;
 
247
    if(b.attached>=0) a = &modelattached[b.attached];
 
248
    float intensity = dynshadow/100.0f;
 
249
    if(dynshadowdecay) switch(b.anim&ANIM_INDEX)
 
250
    {
 
251
        case ANIM_DECAY:
 
252
        case ANIM_LYING_DEAD:
 
253
            intensity *= max(1.0f - float(lastmillis - b.basetime)/dynshadowdecay, 0.0f);
 
254
            break;
 
255
    }
 
256
    glColor4f(0, 0, 0, intensity);
 
257
    m->rendershadow(b.anim, b.varseed, b.speed, b.basetime, dynshadowquad ? center : b.o, b.yaw, a);
 
258
}
 
259
 
 
260
static int sortbatchedmodels(const batchedmodel *x, const batchedmodel *y)
 
261
{
 
262
    if(x->tex < y->tex) return -1;
 
263
    if(x->tex > y->tex) return 1;
 
264
    return 0;
 
265
}
 
266
 
 
267
struct translucentmodel
 
268
{
 
269
    model *m;
 
270
    batchedmodel *batched;
 
271
    float dist;
 
272
};
 
273
 
 
274
static int sorttranslucentmodels(const translucentmodel *x, const translucentmodel *y)
 
275
{
 
276
    if(x->dist > y->dist) return -1;
 
277
    if(x->dist < y->dist) return 1;
 
278
    return 0;
 
279
}
 
280
 
 
281
void clearmodelbatches()
 
282
{
 
283
    numbatches = -1;
 
284
}
 
285
 
 
286
void endmodelbatches(bool flush)
 
287
{
 
288
    vector<translucentmodel> translucent;
 
289
    loopi(numbatches)
 
290
    {
 
291
        modelbatch &b = *batches[i];
 
292
        if(b.batched.empty()) continue;
 
293
        loopvj(b.batched) if(b.batched[j].tex) { b.batched.sort(sortbatchedmodels); break; }
 
294
        b.m->startrender();
 
295
        loopvj(b.batched)
 
296
        {
 
297
            batchedmodel &bm = b.batched[j];
 
298
            if(bm.anim&ANIM_TRANSLUCENT)
 
299
            {
 
300
                translucentmodel &tm = translucent.add();
 
301
                tm.m = b.m;
 
302
                tm.batched = &bm;
 
303
                tm.dist = camera1->o.dist(bm.o);
 
304
                continue;
 
305
            }
 
306
            renderbatchedmodel(b.m, bm);
 
307
        }
 
308
        if(dynshadow && b.m->hasshadows() && (!reflecting || refracting) && (!stencilshadow || !hasstencil || stencilbits < 8))
 
309
        {
 
310
            loopvj(b.batched)
 
311
            {
 
312
                batchedmodel &bm = b.batched[j];
 
313
                if(bm.anim&ANIM_TRANSLUCENT) continue;
 
314
                renderbatchedmodelshadow(b.m, bm);
 
315
            }
 
316
        }
 
317
        b.m->endrender();
 
318
    }
 
319
    if(translucent.length())
 
320
    {
 
321
        translucent.sort(sorttranslucentmodels);
 
322
        model *lastmodel = NULL;
 
323
        loopv(translucent)
 
324
        {
 
325
            translucentmodel &tm = translucent[i];
 
326
            if(lastmodel!=tm.m)
 
327
            {
 
328
                if(lastmodel) lastmodel->endrender();
 
329
                (lastmodel = tm.m)->startrender();
 
330
            }
 
331
            renderbatchedmodel(tm.m, *tm.batched);
 
332
        }
 
333
        if(lastmodel) lastmodel->endrender();
 
334
    }
 
335
    if(flush) clearmodelbatches();
 
336
}
 
337
 
 
338
VAR(dbgmbatch, 0, 0, 1);
 
339
 
 
340
void rendermodel(const char *mdl, int anim, int tex, float rad, const vec &o, float yaw, float pitch, float speed, int basetime, playerent *d, modelattach *a, float scale)
 
341
{
 
342
    model *m = loadmodel(mdl);
 
343
    if(!m || (stenciling && (m->shadowdist <= 0 || anim&ANIM_TRANSLUCENT))) return;
 
344
 
 
345
    if(rad >= 0)
 
346
    {
 
347
        if(!rad) rad = m->radius;
 
348
        if(isoccluded(camera1->o.x, camera1->o.y, o.x-rad, o.y-rad, rad*2)) return;
 
349
    }
 
350
 
 
351
    if(stenciling && d && !raycubelos(camera1->o, o, d->radius))
 
352
    {
 
353
        vec target(o);
 
354
        target.z += d->eyeheight;
 
355
        if(!raycubelos(camera1->o, target, d->radius)) return;
 
356
    }
 
357
 
 
358
    int varseed = 0;
 
359
    if(d) switch(anim&ANIM_INDEX)
 
360
    {
 
361
        case ANIM_DEATH:
 
362
        case ANIM_LYING_DEAD: varseed = (int)(size_t)d + d->lastpain; break;
 
363
        default: varseed = (int)(size_t)d + d->lastaction; break;
 
364
    }
 
365
 
 
366
    if(a) for(int i = 0; a[i].tag; i++)
 
367
    {
 
368
        if(a[i].name) a[i].m = loadmodel(a[i].name);
 
369
        //if(a[i].m && a[i].m->type()!=m->type()) a[i].m = NULL;
 
370
    }
 
371
 
 
372
    if(numbatches>=0 && !dbgmbatch)
 
373
    {
 
374
        batchedmodel &b = addbatchedmodel(m);
 
375
        b.o = o;
 
376
        b.anim = anim;
 
377
        b.varseed = varseed;
 
378
        b.tex = tex;
 
379
        b.yaw = yaw;
 
380
        b.pitch = pitch;
 
381
        b.speed = speed;
 
382
        b.basetime = basetime;
 
383
        b.d = d;
 
384
        b.attached = a ? modelattached.length() : -1;
 
385
        if(a) for(int i = 0;; i++) { modelattached.add(a[i]); if(!a[i].tag) break; }
 
386
        b.scale = scale;
 
387
        return;
 
388
    }
 
389
 
 
390
    if(stenciling)
 
391
    {
 
392
        m->startrender();
 
393
        m->render(anim|ANIM_NOSKIN, varseed, speed, basetime, o, yaw, pitch, d, a, scale);
 
394
        m->endrender();
 
395
        return;
 
396
    }
 
397
 
 
398
    m->startrender();
 
399
 
 
400
    int x = (int)o.x, y = (int)o.y;
 
401
    if(!OUTBORD(x, y))
 
402
    {
 
403
        sqr *s = S(x, y);
 
404
        if(!(anim&ANIM_TRANSLUCENT) && dynshadow && m->hasshadows() && (!reflecting || refracting) && (!stencilshadow || !hasstencil || stencilbits < 8))
 
405
        {
 
406
            vec center(o.x, o.y, s->floor);
 
407
            if(s->type==FHF) center.z -= s->vdelta/4.0f;
 
408
            if(!dynshadowquad || center.z-0.1f<=o.z)
 
409
            {
 
410
                center.z += 0.1f;
 
411
                float intensity = dynshadow/100.0f;
 
412
                if(dynshadowdecay) switch(anim&ANIM_INDEX)
 
413
                {
 
414
                    case ANIM_DECAY:
 
415
                    case ANIM_LYING_DEAD:
 
416
                        intensity *= max(1.0f - float(lastmillis - basetime)/dynshadowdecay, 0.0f);
 
417
                        break;
 
418
                }
 
419
                glColor4f(0, 0, 0, intensity);
 
420
                m->rendershadow(anim, varseed, speed, basetime, dynshadowquad ? center : o, yaw, a);
 
421
            }
 
422
        }
 
423
        glColor3ub(s->r, s->g, s->b);
 
424
    }
 
425
    else glColor3f(1, 1, 1);
 
426
 
 
427
    m->setskin(tex);
 
428
 
 
429
    if(anim&ANIM_TRANSLUCENT)
 
430
    {
 
431
        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
 
432
        m->render(anim|ANIM_NOSKIN, varseed, speed, basetime, o, yaw, pitch, d, a, scale);
 
433
        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
 
434
 
 
435
        glDepthFunc(GL_LEQUAL);
 
436
        glEnable(GL_BLEND);
 
437
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
438
 
 
439
        GLfloat color[4];
 
440
        glGetFloatv(GL_CURRENT_COLOR, color);
 
441
        glColor4f(color[0], color[1], color[2], m->translucency);
 
442
    }
 
443
 
 
444
    m->render(anim, varseed, speed, basetime, o, yaw, pitch, d, a, scale);
 
445
 
 
446
    if(anim&ANIM_TRANSLUCENT)
 
447
    {
 
448
        glDepthFunc(GL_LESS);
 
449
        glDisable(GL_BLEND);
 
450
    }
 
451
 
 
452
    m->endrender();
 
453
}
 
454
 
 
455
int findanim(const char *name)
 
456
{
 
457
    const char *names[] = { "idle", "run", "attack", "pain", "jump", "land", "flipoff", "salute", "taunt", "wave", "point", "crouch idle", "crouch walk", "crouch attack", "crouch pain", "crouch death", "death", "lying dead", "flag", "gun idle", "gun shoot", "gun reload", "gun throw", "mapmodel", "trigger", "decay", "all" };
 
458
    loopi(sizeof(names)/sizeof(names[0])) if(!strcmp(name, names[i])) return i;
 
459
    return -1;
 
460
}
 
461
 
 
462
void loadskin(const char *dir, const char *altdir, Texture *&skin) // model skin sharing
 
463
{
 
464
    #define ifnoload if((skin = textureload(path))==notexture)
 
465
    s_sprintfd(path)("packages/models/%s/skin.jpg", dir);
 
466
    ifnoload
 
467
    {
 
468
        strcpy(path+strlen(path)-3, "png");
 
469
        ifnoload
 
470
        {
 
471
            s_sprintf(path)("packages/models/%s/skin.jpg", altdir);
 
472
            ifnoload
 
473
            {
 
474
                strcpy(path+strlen(path)-3, "png");
 
475
                ifnoload return;
 
476
            }
 
477
        }
 
478
    }
 
479
}
 
480
 
 
481
void preload_playermodels()
 
482
{
 
483
    model *playermdl = loadmodel("playermodels");
 
484
    if(dynshadow && playermdl) playermdl->genshadows(8.0f, 4.0f);
 
485
    loopi(NUMGUNS)
 
486
    {
 
487
        s_sprintfd(vwep)("weapons/%s/world", guns[i].modelname);
 
488
        model *vwepmdl = loadmodel(vwep);
 
489
        if(dynshadow && vwepmdl) vwepmdl->genshadows(8.0f, 4.0f);
 
490
    }
 
491
}
 
492
 
 
493
void preload_entmodels()
 
494
{
 
495
    extern const char *entmdlnames[];
 
496
    loopi(I_AKIMBO-I_CLIPS+1)
 
497
    {
 
498
        model *mdl = loadmodel(entmdlnames[i]);
 
499
        if(dynshadow && mdl) mdl->genshadows(8.0f, 2.0f);
 
500
    }
 
501
    static const char *bouncemdlnames[] = { "misc/gib01", "misc/gib02", "misc/gib03", "weapons/grenade/static" };
 
502
    loopi(sizeof(bouncemdlnames)/sizeof(bouncemdlnames[0]))
 
503
    {
 
504
        model *mdl = loadmodel(bouncemdlnames[i]);
 
505
        if(dynshadow && mdl) mdl->genshadows(8.0f, 2.0f);
 
506
    }
 
507
}
 
508
 
 
509
void preload_mapmodels()
 
510
{
 
511
    loopv(ents)
 
512
    {
 
513
        entity &e = ents[i];
 
514
        if(e.type!=MAPMODEL || !mapmodels.inrange(e.attr2)) continue;
 
515
        if(!loadmodel(NULL, e.attr2)) continue;
 
516
        if(e.attr4) lookuptexture(e.attr4);
 
517
    }
 
518
}
 
519
 
 
520
VAR(dbghbox, 0, 0, 1);
 
521
 
 
522
void renderhbox(playerent *d)
 
523
{
 
524
    glDisable(GL_TEXTURE_2D);
 
525
    glColor3f(1, 1, 1);
 
526
 
 
527
    float y = d->yaw*RAD, p = (d->pitch/4+90)*RAD, c = cosf(p);
 
528
    vec bottom(d->o), up(sinf(y)*c, -cosf(y)*c, sinf(p)), top(up);
 
529
    bottom.z -= d->eyeheight;
 
530
    top.mul(d->eyeheight + d->aboveeye).add(bottom);
 
531
 
 
532
    if(d->state==CS_ALIVE && d->head.x >= 0)
 
533
    {
 
534
        glBegin(GL_LINE_LOOP);
 
535
        loopi(8)
 
536
        {
 
537
            vec pos(camright);
 
538
            pos.rotate(2*M_PI*i/8.0f, camdir).mul(HEADSIZE).add(d->head);
 
539
            glVertex3fv(pos.v);
 
540
        }
 
541
        glEnd();
 
542
 
 
543
        glBegin(GL_LINES);
 
544
        glVertex3fv(bottom.v);
 
545
        glVertex3fv(d->head.v);
 
546
        glEnd();
 
547
    }
 
548
 
 
549
    vec spoke;
 
550
    spoke.orthogonal(up);
 
551
    spoke.normalize().mul(d->radius);
 
552
 
 
553
    glBegin(GL_LINE_LOOP);
 
554
    loopi(8)
 
555
    {
 
556
        vec pos(spoke);
 
557
        pos.rotate(2*M_PI*i/8.0f, up).add(top);
 
558
        glVertex3fv(pos.v);
 
559
    }
 
560
    glEnd();
 
561
    glBegin(GL_LINE_LOOP);
 
562
    loopi(8)
 
563
    {
 
564
        vec pos(spoke);
 
565
        pos.rotate(2*M_PI*i/8.0f, up).add(bottom);
 
566
        glVertex3fv(pos.v);
 
567
    }
 
568
    glEnd();
 
569
    glBegin(GL_LINES);
 
570
    loopi(8)
 
571
    {
 
572
        vec pos(spoke);
 
573
        pos.rotate(2*M_PI*i/8.0f, up).add(bottom);
 
574
        glVertex3fv(pos.v);
 
575
        pos.sub(bottom).add(top);
 
576
        glVertex3fv(pos.v);
 
577
    }
 
578
    glEnd();
 
579
 
 
580
    glEnable(GL_TEXTURE_2D);
 
581
}
 
582
 
 
583
void renderclient(playerent *d, const char *mdlname, const char *vwepname, int tex)
 
584
{
 
585
    int varseed = (int)(size_t)d;
 
586
    int anim = ANIM_IDLE|ANIM_LOOP;
 
587
    float speed = 0.0;
 
588
    vec o(d->o);
 
589
    o.z -= d->eyeheight;
 
590
    int basetime = -((int)(size_t)d&0xFFF);
 
591
    if(d->state==CS_DEAD)
 
592
    {
 
593
        if(d==player1 && d->allowmove()) return;
 
594
        loopv(bounceents) if(bounceents[i]->bouncetype==BT_GIB && bounceents[i]->owner==d) return;
 
595
        d->pitch = 0.1f;
 
596
        anim = ANIM_DEATH;
 
597
        varseed += d->lastpain;
 
598
        basetime = d->lastpain;
 
599
        int t = lastmillis-d->lastpain;
 
600
        if(t<0 || t>20000) return;
 
601
        if(t>2000)
 
602
        {
 
603
            anim = ANIM_LYING_DEAD|ANIM_NOINTERP|ANIM_LOOP;
 
604
            basetime += 2000;
 
605
            t -= 2000;
 
606
            o.z -= t*t/10000000000.0f*t;
 
607
        }
 
608
    }
 
609
    else if(d->state==CS_EDITING)                   { anim = ANIM_JUMP|ANIM_END; }
 
610
    else if(d->state==CS_LAGGED)                    { anim = ANIM_SALUTE|ANIM_LOOP|ANIM_TRANSLUCENT; }
 
611
    else if(lastmillis-d->lastpain<300)             { anim = d->crouching ? ANIM_CROUCH_PAIN : ANIM_PAIN; speed = 300.0f/4; varseed += d->lastpain; basetime = d->lastpain; }
 
612
    else if(!d->onfloor && d->timeinair>50)         { anim = ANIM_JUMP|ANIM_END; }
 
613
    else if(d->weaponsel==d->lastattackweapon && lastmillis-d->lastaction<300 && d->lastpain < d->lastaction) { anim = d->crouching ? ANIM_CROUCH_ATTACK : ANIM_ATTACK; speed = 300.0f/8; basetime = d->lastaction; }
 
614
    else if(!d->move && !d->strafe)                 { anim = (d->crouching ? ANIM_CROUCH_IDLE : ANIM_IDLE)|ANIM_LOOP; }
 
615
    else                                            { anim = (d->crouching ? ANIM_CROUCH_WALK : ANIM_RUN)|ANIM_LOOP; speed = 1860/d->maxspeed; }
 
616
    modelattach a[3];
 
617
    int numattach = 0;
 
618
    if(vwepname)
 
619
    {
 
620
        a[numattach].name = vwepname;
 
621
        a[numattach].tag = "tag_weapon";
 
622
        numattach++;
 
623
    }
 
624
 
 
625
    if(!stenciling && !reflecting && !refracting)
 
626
    {
 
627
        if(d->weaponsel==d->lastattackweapon && lastmillis-d->lastaction < d->weaponsel->flashtime())
 
628
            anim |= ANIM_PARTICLE;
 
629
        if(d != player1 && d->state==CS_ALIVE)
 
630
        {
 
631
            d->head = vec(-1, -1, -1);
 
632
            a[numattach].tag = "tag_head";
 
633
            a[numattach].pos = &d->head;
 
634
            numattach++;
 
635
        }
 
636
    }
 
637
    // FIXME: while networked my state as spectator seems to stay CS_DEAD, not CS_SPECTATE
 
638
    // flowtron: I fixed this for following at least (see followplayer())
 
639
    if(player1->isspectating() && d->clientnum == player1->followplayercn && player1->spectatemode == SM_FOLLOW3RD_TRANSPARENT)
 
640
    {
 
641
        anim |= ANIM_TRANSLUCENT; // see through followed player
 
642
        if(stenciling) return;
 
643
    }
 
644
    rendermodel(mdlname, anim|ANIM_DYNALLOC, tex, 1.5f, o, d->yaw+90, d->pitch/4, speed, basetime, d, a);
 
645
    if(!stenciling && !reflecting && !refracting)
 
646
    {
 
647
        if(isteam(player1->team, d->team)) renderaboveheadicon(d);
 
648
        if(dbghbox) renderhbox(d);
 
649
    }
 
650
}
 
651
 
 
652
VARP(teamdisplaymode, 0, 1, 2);
 
653
 
 
654
#define SKINBASE "packages/models/playermodels"
 
655
VARP(hidecustomskins, 0, 0, 2);
 
656
static cvector playerskinlist;
 
657
 
 
658
const char *getclientskin(const char *name, const char *suf)
 
659
{
 
660
    static string tmp;
 
661
    int suflen = (int)strlen(suf), namelen = (int)strlen(name);
 
662
    const char *s, *r = NULL;
 
663
    loopv(playerskinlist)
 
664
    {
 
665
        s = playerskinlist[i];
 
666
        int sl = (int)strlen(s) - suflen;
 
667
        if(sl > 0 && !strcmp(s + sl, suf))
 
668
        {
 
669
            if(namelen == sl && !strncmp(name, s, namelen)) return s; // exact match
 
670
            if(s[sl - 1] == '_')
 
671
            {
 
672
                s_strcpy(tmp, s);
 
673
                tmp[sl - 1] = '\0';
 
674
                if(strstr(name, tmp)) r = s; // partial match
 
675
            }
 
676
        }
 
677
    }
 
678
    return r;
 
679
}
 
680
 
 
681
void updateclientname(playerent *d)
 
682
{
 
683
    static bool gotlist = false;
 
684
    if(!gotlist) listfiles(SKINBASE "/custom", "jpg", playerskinlist);
 
685
    gotlist = true;
 
686
    if(!d || !playerskinlist.length()) return;
 
687
    d->skin_noteam = getclientskin(d->name, "_ffa");
 
688
    d->skin_cla = getclientskin(d->name, "_cla");
 
689
    d->skin_rvsf = getclientskin(d->name, "_rvsf");
 
690
}
 
691
 
 
692
void renderclient(playerent *d)
 
693
{
 
694
    if(!d) return;
 
695
    const char *cs = NULL, *skinbase = SKINBASE;
 
696
    int team = team_int(d->team);
 
697
    int skinid = 1 + max(0, min(d->skin, (team==TEAM_CLA ? 3 : 5)));
 
698
    string skin;
 
699
    if(hidecustomskins == 0 || (hidecustomskins == 1 && !m_teammode))
 
700
    {
 
701
        cs = team ? d->skin_rvsf : d->skin_cla;
 
702
        if(!m_teammode && d->skin_noteam) cs = d->skin_noteam;
 
703
    }
 
704
    if(cs)
 
705
        s_sprintf(skin)("%s/custom/%s.jpg", skinbase, cs);
 
706
    else
 
707
    {
 
708
        if(!m_teammode || !teamdisplaymode) s_sprintf(skin)("%s/%s/%02i.jpg", skinbase, team_string(team), skinid);
 
709
        else switch(teamdisplaymode)
 
710
        {
 
711
            case 1: s_sprintf(skin)("%s/%s/%02i_%svest.jpg", skinbase, team_string(team), skinid, team ? "blue" : "red"); break;
 
712
            case 2: default: s_sprintf(skin)("%s/%s/%s.jpg", skinbase, team_string(team), team ? "blue" : "red"); break;
 
713
        }
 
714
    }
 
715
    string vwep;
 
716
    if(d->weaponsel) s_sprintf(vwep)("weapons/%s/world", d->weaponsel->info.modelname);
 
717
    else vwep[0] = 0;
 
718
    renderclient(d, "playermodels", vwep[0] ? vwep : NULL, -(int)textureload(skin)->id);
 
719
}
 
720
 
 
721
void renderclients()
 
722
{
 
723
    playerent *d;
 
724
    loopv(players) if((d = players[i]) && d->state!=CS_SPAWNING && (!player1->isspectating() || player1->spectatemode != SM_FOLLOW1ST || player1->followplayercn != i)) renderclient(d);
 
725
    if(player1->state==CS_DEAD || (reflecting && !refracting)) renderclient(player1);
 
726
}
 
727