Convert remaining files to pure Objective-C
FossilOrigin-Name: 12cac9666ac09097e06d34da46bf50d15c8571dea22fd2a6d8a1fad076999689
This commit is contained in:
parent
61bf59bbfc
commit
fd09d38b8c
17 changed files with 182 additions and 182 deletions
356
src/worldrender.m
Normal file
356
src/worldrender.m
Normal file
|
@ -0,0 +1,356 @@
|
|||
// worldrender.cpp: goes through all cubes in top down quad tree fashion,
|
||||
// determines what has to be rendered and how (depending on neighbouring cubes),
|
||||
// then calls functions in rendercubes.cpp
|
||||
|
||||
#include "cube.h"
|
||||
|
||||
#import "DynamicEntity.h"
|
||||
|
||||
void
|
||||
render_wall(struct sqr *o, struct sqr *s, int x1, int y1, int x2, int y2,
|
||||
int mip, struct sqr *d1, struct sqr *d2, bool topleft)
|
||||
{
|
||||
if (SOLID(o) || o->type == SEMISOLID) {
|
||||
float c1 = s->floor;
|
||||
float c2 = s->floor;
|
||||
if (s->type == FHF) {
|
||||
c1 -= d1->vdelta / 4.0f;
|
||||
c2 -= d2->vdelta / 4.0f;
|
||||
}
|
||||
float f1 = s->ceil;
|
||||
float f2 = s->ceil;
|
||||
if (s->type == CHF) {
|
||||
f1 += d1->vdelta / 4.0f;
|
||||
f2 += d2->vdelta / 4.0f;
|
||||
}
|
||||
// if(f1-c1<=0 && f2-c2<=0) return;
|
||||
render_square(o->wtex, c1, c2, f1, f2, x1 << mip, y1 << mip,
|
||||
x2 << mip, y2 << mip, 1 << mip, d1, d2, topleft);
|
||||
return;
|
||||
}
|
||||
{
|
||||
float f1 = s->floor;
|
||||
float f2 = s->floor;
|
||||
float c1 = o->floor;
|
||||
float c2 = o->floor;
|
||||
if (o->type == FHF && s->type != FHF) {
|
||||
c1 -= d1->vdelta / 4.0f;
|
||||
c2 -= d2->vdelta / 4.0f;
|
||||
}
|
||||
if (s->type == FHF && o->type != FHF) {
|
||||
f1 -= d1->vdelta / 4.0f;
|
||||
f2 -= d2->vdelta / 4.0f;
|
||||
}
|
||||
if (f1 >= c1 && f2 >= c2)
|
||||
goto skip;
|
||||
render_square(o->wtex, f1, f2, c1, c2, x1 << mip, y1 << mip,
|
||||
x2 << mip, y2 << mip, 1 << mip, d1, d2, topleft);
|
||||
}
|
||||
skip: {
|
||||
float f1 = o->ceil;
|
||||
float f2 = o->ceil;
|
||||
float c1 = s->ceil;
|
||||
float c2 = s->ceil;
|
||||
if (o->type == CHF && s->type != CHF) {
|
||||
f1 += d1->vdelta / 4.0f;
|
||||
f2 += d2->vdelta / 4.0f;
|
||||
} else if (s->type == CHF && o->type != CHF) {
|
||||
c1 += d1->vdelta / 4.0f;
|
||||
c2 += d2->vdelta / 4.0f;
|
||||
}
|
||||
if (c1 <= f1 && c2 <= f2)
|
||||
return;
|
||||
render_square(o->utex, f1, f2, c1, c2, x1 << mip, y1 << mip, x2 << mip,
|
||||
y2 << mip, 1 << mip, d1, d2, topleft);
|
||||
}
|
||||
}
|
||||
|
||||
const int MAX_MIP = 5; // 32x32 unit blocks
|
||||
const int MIN_LOD = 2;
|
||||
const int LOW_LOD = 25;
|
||||
const int MAX_LOD = 1000;
|
||||
|
||||
int lod = 40, lodtop, lodbot, lodleft, lodright;
|
||||
int min_lod;
|
||||
|
||||
int stats[LARGEST_FACTOR];
|
||||
|
||||
// detect those cases where a higher mip solid has a visible wall next to lower
|
||||
// mip cubes (used for wall rendering below)
|
||||
|
||||
bool
|
||||
issemi(int mip, int x, int y, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
if (!(mip--))
|
||||
return true;
|
||||
struct sqr *w = wmip[mip];
|
||||
int msize = ssize >> mip;
|
||||
x *= 2;
|
||||
y *= 2;
|
||||
switch (SWS(w, x + x1, y + y1, msize)->type) {
|
||||
case SEMISOLID:
|
||||
if (issemi(mip, x + x1, y + y1, x1, y1, x2, y2))
|
||||
return true;
|
||||
case CORNER:
|
||||
case SOLID:
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
switch (SWS(w, x + x2, y + y2, msize)->type) {
|
||||
case SEMISOLID:
|
||||
if (issemi(mip, x + x2, y + y2, x1, y1, x2, y2))
|
||||
return true;
|
||||
case CORNER:
|
||||
case SOLID:
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool render_floor, render_ceil;
|
||||
|
||||
// the core recursive function, renders a rect of cubes at a certain mip level
|
||||
// from a viewer perspective call itself for lower mip levels, on most modern
|
||||
// machines however this function will use the higher mip levels only for
|
||||
// perfect mips.
|
||||
|
||||
void
|
||||
render_seg_new(
|
||||
float vx, float vy, float vh, int mip, int x, int y, int xs, int ys)
|
||||
{
|
||||
struct sqr *w = wmip[mip];
|
||||
int sz = ssize >> mip;
|
||||
int vxx = ((int)vx + (1 << mip) / 2) >> mip;
|
||||
int vyy = ((int)vy + (1 << mip) / 2) >> mip;
|
||||
int lx =
|
||||
vxx - lodleft; // these mark the rect inside the current rest that
|
||||
// we want to render using a lower mip level
|
||||
int ly = vyy - lodtop;
|
||||
int rx = vxx + lodright;
|
||||
int ry = vyy + lodbot;
|
||||
|
||||
float fsize = (float)(1 << mip);
|
||||
for (int ox = x; ox < xs; ox++) {
|
||||
// first collect occlusion information for this block
|
||||
for (int oy = y; oy < ys; oy++) {
|
||||
SWS(w, ox, oy, sz)->occluded =
|
||||
isoccluded(player1.o.x, player1.o.y,
|
||||
(float)(ox << mip), (float)(oy << mip), fsize);
|
||||
}
|
||||
}
|
||||
|
||||
int pvx = (int)vx >> mip;
|
||||
int pvy = (int)vy >> mip;
|
||||
if (pvx >= 0 && pvy >= 0 && pvx < sz && pvy < sz) {
|
||||
// SWS(w,vxx,vyy,sz)->occluded = 0;
|
||||
// player cell never occluded
|
||||
SWS(w, pvx, pvy, sz)->occluded = 0;
|
||||
}
|
||||
|
||||
#define df(x) s->floor - (x->vdelta / 4.0f)
|
||||
#define dc(x) s->ceil + (x->vdelta / 4.0f)
|
||||
|
||||
// loop through the rect 3 times (for floor/ceil/walls seperately, to
|
||||
// facilitate dynamic stripify) for each we skip occluded cubes
|
||||
// (occlusion at higher mip levels is a big time saver!). during the
|
||||
// first loop (ceil) we collect cubes that lie within the lower mip rect
|
||||
// and are also deferred, and render them recursively. Anything left
|
||||
// (perfect mips and higher lods) we render here.
|
||||
|
||||
#define LOOPH \
|
||||
{ \
|
||||
for (int xx = x; xx < xs; xx++) \
|
||||
for (int yy = y; yy < ys; yy++) { \
|
||||
struct sqr *s = SWS(w, xx, yy, sz); \
|
||||
if (s->occluded == 1) \
|
||||
continue; \
|
||||
if (s->defer && !s->occluded && mip && \
|
||||
xx >= lx && xx < rx && yy >= ly && \
|
||||
yy < ry)
|
||||
#define LOOPD \
|
||||
struct sqr *t = SWS(s, 1, 0, sz); \
|
||||
struct sqr *u = SWS(s, 1, 1, sz); \
|
||||
struct sqr *v = SWS(s, 0, 1, sz);
|
||||
|
||||
LOOPH // ceils
|
||||
{
|
||||
int start = yy;
|
||||
struct sqr *next;
|
||||
while (yy < ys - 1 && (next = SWS(w, xx, yy + 1, sz))->defer &&
|
||||
!next->occluded)
|
||||
yy++; // collect 2xN rect of lower mip
|
||||
render_seg_new(vx, vy, vh, mip - 1, xx * 2, start * 2,
|
||||
xx * 2 + 2, yy * 2 + 2);
|
||||
continue;
|
||||
}
|
||||
stats[mip]++;
|
||||
LOOPD
|
||||
if ((s->type == SPACE || s->type == FHF) && s->ceil >= vh &&
|
||||
render_ceil)
|
||||
render_flat(s->ctex, xx << mip, yy << mip, 1 << mip, s->ceil, s,
|
||||
t, u, v, true);
|
||||
if (s->type == CHF) // if(s->ceil>=vh)
|
||||
render_flatdelta(s->ctex, xx << mip, yy << mip, 1 << mip, dc(s),
|
||||
dc(t), dc(u), dc(v), s, t, u, v, true);
|
||||
}
|
||||
}
|
||||
|
||||
LOOPH continue; // floors
|
||||
LOOPD
|
||||
if ((s->type == SPACE || s->type == CHF) && s->floor <= vh && render_floor) {
|
||||
render_flat(s->ftex, xx << mip, yy << mip, 1 << mip, s->floor, s, t, u,
|
||||
v, false);
|
||||
if (s->floor < hdr.waterlevel && !SOLID(s))
|
||||
addwaterquad(xx << mip, yy << mip, 1 << mip);
|
||||
}
|
||||
if (s->type == FHF) {
|
||||
render_flatdelta(s->ftex, xx << mip, yy << mip, 1 << mip, df(s), df(t),
|
||||
df(u), df(v), s, t, u, v, false);
|
||||
if (s->floor - s->vdelta / 4.0f < hdr.waterlevel && !SOLID(s))
|
||||
addwaterquad(xx << mip, yy << mip, 1 << mip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOOPH continue; // walls
|
||||
LOOPD
|
||||
// w
|
||||
// zSt
|
||||
// vu
|
||||
|
||||
struct sqr *w = SWS(s, 0, -1, sz);
|
||||
struct sqr *z = SWS(s, -1, 0, sz);
|
||||
bool normalwall = true;
|
||||
|
||||
if (s->type == CORNER) {
|
||||
// cull also
|
||||
bool topleft = true;
|
||||
struct sqr *h1 = NULL;
|
||||
struct sqr *h2 = NULL;
|
||||
if (SOLID(z)) {
|
||||
if (SOLID(w)) {
|
||||
render_wall(w, h2 = s, xx + 1, yy, xx, yy + 1, mip, t,
|
||||
v, false);
|
||||
topleft = false;
|
||||
} else if (SOLID(v)) {
|
||||
render_wall(v, h2 = s, xx, yy, xx + 1, yy + 1, mip, s,
|
||||
u, false);
|
||||
}
|
||||
} else if (SOLID(t)) {
|
||||
if (SOLID(w)) {
|
||||
render_wall(w, h1 = s, xx + 1, yy + 1, xx, yy, mip, u,
|
||||
s, false);
|
||||
} else if (SOLID(v)) {
|
||||
render_wall(v, h1 = s, xx, yy + 1, xx + 1, yy, mip, v,
|
||||
t, false);
|
||||
topleft = false;
|
||||
}
|
||||
} else {
|
||||
normalwall = false;
|
||||
bool wv = w->ceil - w->floor < v->ceil - v->floor;
|
||||
if (z->ceil - z->floor < t->ceil - t->floor) {
|
||||
if (wv) {
|
||||
render_wall(h1 = s, h2 = v, xx + 1, yy, xx,
|
||||
yy + 1, mip, t, v, false);
|
||||
topleft = false;
|
||||
} else {
|
||||
render_wall(h1 = s, h2 = w, xx, yy, xx + 1,
|
||||
yy + 1, mip, s, u, false);
|
||||
}
|
||||
} else {
|
||||
if (wv) {
|
||||
render_wall(h2 = s, h1 = v, xx + 1, yy + 1, xx,
|
||||
yy, mip, u, s, false);
|
||||
} else {
|
||||
render_wall(h2 = s, h1 = w, xx, yy + 1, xx + 1,
|
||||
yy, mip, v, t, false);
|
||||
topleft = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
render_tris(
|
||||
xx << mip, yy << mip, 1 << mip, topleft, h1, h2, s, t, u, v);
|
||||
}
|
||||
|
||||
if (normalwall) {
|
||||
bool inner = xx != sz - 1 && yy != sz - 1;
|
||||
|
||||
if (xx >= vxx && xx != 0 && yy != sz - 1 && !SOLID(z) &&
|
||||
(!SOLID(s) || z->type != CORNER) &&
|
||||
(z->type != SEMISOLID || issemi(mip, xx - 1, yy, 1, 0, 1, 1)))
|
||||
render_wall(s, z, xx, yy, xx, yy + 1, mip, s, v, true);
|
||||
if (xx <= vxx && inner && !SOLID(t) &&
|
||||
(!SOLID(s) || t->type != CORNER) &&
|
||||
(t->type != SEMISOLID || issemi(mip, xx + 1, yy, 0, 0, 0, 1)))
|
||||
render_wall(s, t, xx + 1, yy, xx + 1, yy + 1, mip, t, u, false);
|
||||
if (yy >= vyy && yy != 0 && xx != sz - 1 && !SOLID(w) &&
|
||||
(!SOLID(s) || w->type != CORNER) &&
|
||||
(w->type != SEMISOLID || issemi(mip, xx, yy - 1, 0, 1, 1, 1)))
|
||||
render_wall(s, w, xx, yy, xx + 1, yy, mip, s, t, false);
|
||||
if (yy <= vyy && inner && !SOLID(v) &&
|
||||
(!SOLID(s) || v->type != CORNER) &&
|
||||
(v->type != SEMISOLID || issemi(mip, xx, yy + 1, 0, 0, 1, 0)))
|
||||
render_wall(s, v, xx, yy + 1, xx + 1, yy + 1, mip, v, u, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
distlod(int *low, int *high, int angle, float widef)
|
||||
{
|
||||
float f = 90.0f / lod / widef;
|
||||
*low = (int)((90 - angle) / f);
|
||||
*high = (int)(angle / f);
|
||||
if (*low < min_lod)
|
||||
*low = min_lod;
|
||||
if (*high < min_lod)
|
||||
*high = min_lod;
|
||||
}
|
||||
|
||||
// does some out of date view frustrum optimisation that doesn't contribute much
|
||||
// anymore
|
||||
|
||||
void
|
||||
render_world(
|
||||
float vx, float vy, float vh, int yaw, int pitch, float fov, int w, int h)
|
||||
{
|
||||
loopi(LARGEST_FACTOR) stats[i] = 0;
|
||||
min_lod = MIN_LOD + abs(pitch) / 12;
|
||||
yaw = 360 - yaw;
|
||||
float widef = fov / 75.0f;
|
||||
int cdist = abs(yaw % 90 - 45);
|
||||
// hack to avoid popup at high fovs at 45 yaw
|
||||
if (cdist < 7) {
|
||||
// less if lod worked better
|
||||
min_lod =
|
||||
max(min_lod, (int)(MIN_LOD + (10 - cdist) / 1.0f * widef));
|
||||
widef = 1.0f;
|
||||
}
|
||||
lod = MAX_LOD;
|
||||
lodtop = lodbot = lodleft = lodright = min_lod;
|
||||
if (yaw > 45 && yaw <= 135) {
|
||||
lodleft = lod;
|
||||
distlod(&lodtop, &lodbot, yaw - 45, widef);
|
||||
} else if (yaw > 135 && yaw <= 225) {
|
||||
lodbot = lod;
|
||||
distlod(&lodleft, &lodright, yaw - 135, widef);
|
||||
} else if (yaw > 225 && yaw <= 315) {
|
||||
lodright = lod;
|
||||
distlod(&lodbot, &lodtop, yaw - 225, widef);
|
||||
} else {
|
||||
lodtop = lod;
|
||||
distlod(&lodright, &lodleft, yaw <= 45 ? yaw + 45 : yaw - 315,
|
||||
widef);
|
||||
}
|
||||
float hyfov = fov * h / w / 2;
|
||||
render_floor = pitch < hyfov;
|
||||
render_ceil = -pitch < hyfov;
|
||||
|
||||
render_seg_new(
|
||||
vx, vy, vh, MAX_MIP, 0, 0, ssize >> MAX_MIP, ssize >> MAX_MIP);
|
||||
mipstats(stats[0], stats[1], stats[2]);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue