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

« back to all changes in this revision

Viewing changes to source/src/worldrender.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
// worldrender.cpp: goes through all cubes in top down quad tree fashion, determines what has to
 
2
// be rendered and how (depending on neighbouring cubes), then calls functions in rendercubes.cpp
 
3
 
 
4
#include "pch.h"
 
5
#include "cube.h"
 
6
 
 
7
void render_wall(sqr *o, sqr *s, int x1, int y1, int x2, int y2, int mip, sqr *d1, sqr *d2, bool topleft, int dir)
 
8
{
 
9
    if(minimap) return;
 
10
    if(SOLID(o) || o->type==SEMISOLID)
 
11
    {
 
12
        float c1 = s->floor;
 
13
        float c2 = s->floor;
 
14
        if(s->type==FHF) { c1 -= d1->vdelta/4.0f; c2 -= d2->vdelta/4.0f; }
 
15
        float f1 = s->ceil;
 
16
        float f2 = s->ceil;
 
17
        if(s->type==CHF) { f1 += d1->vdelta/4.0f; f2 += d2->vdelta/4.0f; }
 
18
        //if(f1-c1<=0 && f2-c2<=0) return;
 
19
        render_square(o->wtex, c1, c2, f1, f2, x1<<mip, y1<<mip, x2<<mip, y2<<mip, 1<<mip, d1, d2, topleft, dir);
 
20
        return;
 
21
    }
 
22
    {
 
23
        float f1 = s->floor;
 
24
        float f2 = s->floor;
 
25
        float c1 = o->floor;
 
26
        float c2 = o->floor;
 
27
        if(o->type==FHF && s->type!=FHF)
 
28
        {
 
29
            c1 -= d1->vdelta/4.0f;
 
30
            c2 -= d2->vdelta/4.0f;
 
31
        }
 
32
        if(s->type==FHF && o->type!=FHF)
 
33
        {
 
34
            f1 -= d1->vdelta/4.0f;
 
35
            f2 -= d2->vdelta/4.0f;
 
36
        }
 
37
        if(f1>=c1 && f2>=c2) goto skip;
 
38
        render_square(o->wtex, f1, f2, c1, c2, x1<<mip, y1<<mip, x2<<mip, y2<<mip, 1<<mip, d1, d2, topleft, dir);
 
39
    }
 
40
    skip:
 
41
    {
 
42
        float f1 = o->ceil;
 
43
        float f2 = o->ceil;
 
44
        float c1 = s->ceil;
 
45
        float c2 = s->ceil;
 
46
        if(o->type==CHF && s->type!=CHF)
 
47
        {
 
48
            f1 += d1->vdelta/4.0f;
 
49
            f2 += d2->vdelta/4.0f;
 
50
        }
 
51
        else if(s->type==CHF && o->type!=CHF)
 
52
        {
 
53
            c1 += d1->vdelta/4.0f;
 
54
            c2 += d2->vdelta/4.0f;
 
55
        }
 
56
        if(c1<=f1 && c2<=f2) return;
 
57
        render_square(o->utex, f1, f2, c1, c2, x1<<mip, y1<<mip, x2<<mip, y2<<mip, 1<<mip, d1, d2, topleft, dir);
 
58
    }
 
59
}
 
60
 
 
61
const int MAX_MIP = 5;   // 32x32 unit blocks
 
62
const int MIN_LOD = 2;
 
63
const int LOW_LOD = 25;
 
64
const int MAX_LOD = 250;
 
65
 
 
66
int lod = 40, lodtop, lodbot, lodleft, lodright;
 
67
int min_lod;
 
68
 
 
69
int lod_factor() { return lod; }
 
70
 
 
71
VARP(minlod, LOW_LOD, 60, MAX_LOD);
 
72
 
 
73
int stats[LARGEST_FACTOR];
 
74
 
 
75
// detect those cases where a higher mip solid has a visible wall next to lower mip cubes
 
76
// (used for wall rendering below)
 
77
 
 
78
bool issemi(int mip, int x, int y, int x1, int y1, int x2, int y2)      
 
79
{
 
80
    if(!(mip--)) return true;
 
81
    sqr *w = wmip[mip];
 
82
    int mfactor = sfactor - mip;
 
83
    x *= 2;
 
84
    y *= 2;
 
85
    switch(SWS(w, x+x1, y+y1, mfactor)->type)
 
86
    {
 
87
        case SEMISOLID: if(issemi(mip, x+x1, y+y1, x1, y1, x2, y2)) return true;
 
88
        case CORNER:
 
89
        case SOLID: break;
 
90
        default: return true;
 
91
    }
 
92
    switch(SWS(w, x+x2, y+y2, mfactor)->type)
 
93
    {
 
94
        case SEMISOLID: if(issemi(mip, x+x2, y+y2, x1, y1, x2, y2)) return true;
 
95
        case CORNER:
 
96
        case SOLID: break;
 
97
        default: return true;
 
98
    }
 
99
    return false;
 
100
}
 
101
 
 
102
bool render_floor, render_ceil;
 
103
 
 
104
// the core recursive function, renders a rect of cubes at a certain mip level from a viewer perspective
 
105
// call itself for lower mip levels, on most modern machines however this function will use the higher
 
106
// mip levels only for perfect mips.
 
107
 
 
108
void render_seg_new(float vx, float vy, float vh, int mip, int x, int y, int xs, int ys)
 
109
{
 
110
    sqr *w = wmip[mip];
 
111
    int mfactor = sfactor - mip;
 
112
    int sz = 1<<mfactor;
 
113
    int vxx = ((int)vx+(1<<mip)/2)>>mip;
 
114
    int vyy = ((int)vy+(1<<mip)/2)>>mip;
 
115
    int lx = vxx-lodleft;   // these mark the rect inside the current rest that we want to render using a lower mip level
 
116
    int ly = vyy-lodtop;
 
117
    int rx = vxx+lodright;
 
118
    int ry = vyy+lodbot;
 
119
 
 
120
    float fsize = (float)(1<<mip);
 
121
    for(int oy = y; oy<ys; oy++) for(int ox = x; ox<xs; ox++)       // first collect occlusion information for this block
 
122
    {
 
123
        SWS(w,ox,oy,mfactor)->occluded = isoccluded(camera1->o.x, camera1->o.y, (float)(ox<<mip), (float)(oy<<mip), fsize);
 
124
    }
 
125
    
 
126
    int pvx = (int)vx>>mip;
 
127
    int pvy = (int)vy>>mip;
 
128
    if(pvx>=0 && pvy>=0 && pvx<sz && pvy<sz)
 
129
    {
 
130
        //SWS(w,vxx,vyy,mfactor)->occluded = 0; 
 
131
        SWS(w, pvx, pvy, mfactor)->occluded = 0;  // player cell never occluded
 
132
    }
 
133
 
 
134
    #define df(x) s->floor-(x->vdelta/4.0f)
 
135
    #define dc(x) s->ceil+(x->vdelta/4.0f)
 
136
    
 
137
    // loop through the rect 3 times (for floor/ceil/walls seperately, to facilitate dynamic stripify)
 
138
    // for each we skip occluded cubes (occlusion at higher mip levels is a big time saver!).
 
139
    // during the first loop (ceil) we collect cubes that lie within the lower mip rect and are
 
140
    // also deferred, and render them recursively. Anything left (perfect mips and higher lods) we
 
141
    // render here.
 
142
 
 
143
    #define LOOPH {for(int yy = y; yy<ys; yy++) for(int xx = x; xx<xs; xx++) { \
 
144
                  sqr *s = SWS(w,xx,yy,mfactor); if(s->occluded) continue; \
 
145
                  if(s->defer && mip && xx>=lx && xx<rx && yy>=ly && yy<ry)
 
146
    #define LOOPD sqr *t = SWS(s,1,0,mfactor); \
 
147
                  sqr *u = SWS(s,1,1,mfactor); \
 
148
                  sqr *v = SWS(s,0,1,mfactor);
 
149
 
 
150
    int rendered = 0;
 
151
    LOOPH // floors
 
152
        {
 
153
            int start = xx;
 
154
            sqr *next;
 
155
            while(xx<xs-1 && (next = SWS(w,xx+1,yy,mfactor))->defer && !next->occluded) xx++;    // collect 2xN rect of lower mip
 
156
            render_seg_new(vx, vy, vh, mip-1, start*2, yy*2, xx*2+2, yy*2+2);
 
157
            continue;
 
158
        }
 
159
        rendered++;
 
160
        LOOPD
 
161
        switch(s->type)
 
162
        {
 
163
            case SPACE:
 
164
            case CHF:
 
165
                if(s->floor<=vh && render_floor)
 
166
                {
 
167
                    render_flat(s->ftex, xx<<mip, yy<<mip, 1<<mip, s->floor, s, t, u, v, false);
 
168
                    if(s->floor<hdr.waterlevel && !reflecting) addwaterquad(xx<<mip, yy<<mip, 1<<mip);
 
169
                }
 
170
                break;
 
171
            case FHF:
 
172
                render_flatdelta(s->ftex, xx<<mip, yy<<mip, 1<<mip, df(s), df(t), df(u), df(v), s, t, u, v, false);
 
173
                if(s->floor-s->vdelta/4.0f<hdr.waterlevel && !reflecting) addwaterquad(xx<<mip, yy<<mip, 1<<mip);
 
174
                break;
 
175
        }
 
176
    }}
 
177
 
 
178
    if(!rendered) return;
 
179
    stats[mip] += rendered;
 
180
 
 
181
    if(!minimap) LOOPH continue; // ceils
 
182
        LOOPD
 
183
        switch(s->type)
 
184
        {
 
185
            case SPACE:
 
186
            case FHF:
 
187
                if(s->ceil>=vh && render_ceil)
 
188
                    render_flat(s->ctex, xx<<mip, yy<<mip, 1<<mip, s->ceil, s, t, u, v, true);
 
189
                break;
 
190
            case CHF:
 
191
                render_flatdelta(s->ctex, xx<<mip, yy<<mip, 1<<mip, dc(s), dc(t), dc(u), dc(v), s, t, u, v, true);
 
192
                break;
 
193
        }
 
194
    }}
 
195
 
 
196
    LOOPH continue; // walls
 
197
        LOOPD
 
198
        //  w
 
199
        // zSt
 
200
        //  vu
 
201
 
 
202
        sqr *w = SWS(s,0,-1,mfactor);
 
203
        sqr *z = SWS(s,-1,0,mfactor);
 
204
        bool normalwall = true;
 
205
 
 
206
        if(s->type==CORNER)
 
207
        {
 
208
            // cull also
 
209
            bool topleft = true;
 
210
            sqr *h1 = NULL;
 
211
            sqr *h2 = NULL;
 
212
            if(SOLID(z))
 
213
            {
 
214
                if(SOLID(w))      { render_wall(w, h2 = s, xx+1, yy, xx, yy+1, mip, t, v, false, 4); topleft = false; }
 
215
                else if(SOLID(v)) { render_wall(v, h2 = s, xx, yy, xx+1, yy+1, mip, s, u, false, 5); }
 
216
            }
 
217
            else if(SOLID(t))
 
218
            {
 
219
                if(SOLID(w))      { render_wall(w, h1 = s, xx+1, yy+1, xx, yy, mip, u, s, false, 6); }
 
220
                else if(SOLID(v)) { render_wall(v, h1 = s, xx, yy+1, xx+1, yy, mip, v, t, false, 7); topleft = false; }
 
221
            }
 
222
            else
 
223
            {
 
224
                normalwall = false;
 
225
                bool wv = w->ceil-w->floor < v->ceil-v->floor;
 
226
                if(z->ceil-z->floor < t->ceil-t->floor)
 
227
                {
 
228
                    if(wv) { render_wall(h1 = s, h2 = v, xx+1, yy, xx, yy+1, mip, t, v, false, 4); topleft = false; }
 
229
                    else   { render_wall(h1 = s, h2 = w, xx, yy, xx+1, yy+1, mip, s, u, false, 5); }
 
230
                }
 
231
                else
 
232
                {
 
233
                    if(wv) { render_wall(h2 = s, h1 = v, xx+1, yy+1, xx, yy, mip, u, s, false, 6); }
 
234
                    else   { render_wall(h2 = s, h1 = w, xx, yy+1, xx+1, yy, mip, v, t, false, 7); topleft = false; }
 
235
                }
 
236
            }
 
237
            render_tris(xx<<mip, yy<<mip, 1<<mip, topleft, h1, h2, s, t, u, v);
 
238
        }
 
239
 
 
240
        if(normalwall)
 
241
        {
 
242
            bool inner = xx!=sz-1 && yy!=sz-1;
 
243
 
 
244
            if(xx>=vxx && xx!=0 && yy!=sz-1 && !SOLID(z) && (!SOLID(s) || z->type!=CORNER)
 
245
                && (z->type!=SEMISOLID || issemi(mip, xx-1, yy, 1, 0, 1, 1)))
 
246
                render_wall(s, z, xx,   yy,   xx,   yy+1, mip, s, v, true, 0);
 
247
            if(xx<=vxx && inner && !SOLID(t) && (!SOLID(s) || t->type!=CORNER)
 
248
                && (t->type!=SEMISOLID || issemi(mip, xx+1, yy, 0, 0, 0, 1)))
 
249
                render_wall(s, t, xx+1, yy,   xx+1, yy+1, mip, t, u, false, 1);
 
250
            if(yy>=vyy && yy!=0 && xx!=sz-1 && !SOLID(w) && (!SOLID(s) || w->type!=CORNER)
 
251
                && (w->type!=SEMISOLID || issemi(mip, xx, yy-1, 0, 1, 1, 1)))
 
252
                render_wall(s, w, xx,   yy,   xx+1, yy,   mip, s, t, false, 2);
 
253
            if(yy<=vyy && inner && !SOLID(v) && (!SOLID(s) || v->type!=CORNER)
 
254
                && (v->type!=SEMISOLID || issemi(mip, xx, yy+1, 0, 0, 1, 0)))
 
255
                render_wall(s, v, xx,   yy+1, xx+1, yy+1, mip, v, u, true, 3);
 
256
        }
 
257
    }}
 
258
}
 
259
 
 
260
void distlod(int &low, int &high, int angle, float widef)
 
261
{
 
262
    float f = 90.0f/lod/widef;
 
263
    low = (int)((90-angle)/f);
 
264
    high = (int)(angle/f);
 
265
    if(low<min_lod) low = min_lod;
 
266
    if(high<min_lod) high = min_lod;
 
267
}
 
268
 
 
269
// does some out of date view frustrum optimisation that doesn't contribute much anymore
 
270
 
 
271
void render_world(float vx, float vy, float vh, float changelod, int yaw, int pitch, float fov, float fovy, int w, int h)
 
272
{
 
273
    loopi(LARGEST_FACTOR) stats[i] = 0;
 
274
    min_lod = minimap ? MAX_LOD : MIN_LOD+abs(pitch)/12;
 
275
    yaw = 360-yaw;
 
276
    float widef = fov/75.0f;
 
277
    int cdist = abs(yaw%90-45);
 
278
    if(cdist<7)    // hack to avoid popup at high fovs at 45 yaw
 
279
    {
 
280
        min_lod = max(min_lod, (int)(MIN_LOD+(10-cdist)/1.0f*widef)); // less if lod worked better
 
281
        widef = 1.0f;
 
282
    }
 
283
    lod = (int)(lod*changelod);
 
284
    if(lod<minlod) lod = minlod;
 
285
    if(lod>MAX_LOD) lod = MAX_LOD;
 
286
    lodtop = lodbot = lodleft = lodright = min_lod;
 
287
    if(yaw>45 && yaw<=135)
 
288
    {
 
289
        lodleft = lod;
 
290
        distlod(lodtop, lodbot, yaw-45, widef);
 
291
    }
 
292
    else if(yaw>135 && yaw<=225)
 
293
    {
 
294
        lodbot = lod;
 
295
        distlod(lodleft, lodright, yaw-135, widef);
 
296
    }
 
297
    else if(yaw>225 && yaw<=315)
 
298
    {
 
299
        lodright = lod;
 
300
        distlod(lodbot, lodtop, yaw-225, widef);
 
301
    }
 
302
    else
 
303
    {
 
304
        lodtop = lod;
 
305
        distlod(lodright, lodleft, yaw<=45 ? yaw+45 : yaw-315, widef);
 
306
    }
 
307
    render_floor = pitch<0.5f*fovy;
 
308
    render_ceil  = -pitch<0.5f*fovy;
 
309
 
 
310
    render_seg_new(vx, vy, vh, MAX_MIP, 0, 0, ssize>>MAX_MIP, ssize>>MAX_MIP);
 
311
    mipstats(stats[0], stats[1], stats[2]);
 
312
}
 
313