Cube  Check-in [12cac9666a]

Overview
Comment:Convert remaining files to pure Objective-C
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 12cac9666ac09097e06d34da46bf50d15c8571dea22fd2a6d8a1fad076999689
User & Date: js on 2025-03-20 22:22:40
Other Links: manifest | tags
Context
2025-03-20
22:40
Fix all warnings check-in: 0e7605d101 user: js tags: trunk
22:22
Convert remaining files to pure Objective-C check-in: 12cac9666a user: js tags: trunk
21:52
Convert more files to pure Objective-C check-in: 46c5779570 user: js tags: trunk
Changes

Modified meson.build from [7cbc99fda4] to [09e98c7860].

1

2
3
4
5
6
7
8
9
10
11
12
13






14
15
16
17
18
19
20
21

1
2
3
4
5
6







7
8
9
10
11
12

13
14
15
16
17
18
19
-
+





-
-
-
-
-
-
-
+
+
+
+
+
+
-







project('Cube', ['c', 'objc', 'objcpp'],
project('Cube', ['c', 'objc'],
  meson_version: '>=1.5.0',
  default_options: {
    'optimization': '2'
  })

foreach lang : ['objc', 'objcpp']
  add_global_arguments(
    [
      '-fobjc-arc',
      '-fobjc-arc-exceptions'
    ],
    language: lang)
add_global_arguments(
  [
    '-fobjc-arc',
    '-fobjc-arc-exceptions'
  ],
  language: 'objc')
endforeach

objfw_dep = dependency('objfw')
sdl_dep = dependency('SDL2')
sdlimage_dep = dependency('SDL2_image')
sdlmixer_dep = dependency('SDL2_mixer')
zlib_dep = dependency('zlib')

Modified src/entities.m from [df6381198b] to [415631efe6].

26
27
28
29
30
31
32
33
34


35
36
37
38
39
40
41
26
27
28
29
30
31
32


33
34
35
36
37
38
39
40
41







-
-
+
+







void
initEntities()
{
	ents = [[OFMutableArray alloc] init];
}

static void
renderent(Entity *e, OFString *mdlname, float z, float yaw, int frame /* = 0*/,
    int numf /* = 1*/, int basetime /* = 0*/, float speed /* = 10.0f*/)
renderent(Entity *e, OFString *mdlname, float z, float yaw, int frame, int numf,
    int basetime, float speed)
{
	rendermodel(mdlname, frame, numf, 0, 1.1f,
	    OFMakeVector3D(e.x, z + S(e.x, e.y)->floor, e.y), yaw, 0, false,
	    1.0f, speed, 0, basetime);
}

void

Renamed and modified src/init.mm [1613c5c115] to src/init.m [f9de6a81da].

1
2
3
4
5

6

7
8
9
10

11
12

13
14

15
16
17
18
19
20
21


22
23


24


1

2
3

4
5
6
7
8
9
10

11
12

13
14
15
16
17
18


19
20
21

22
23
24
-
-

-

+
-
+




+

-
+

-
+





-
-
+
+

-
+
+

#include <vector>

#import "cube.h"
#import "protos.h"

static void **queue;
static std::vector<void (^)(void)> *queue;
static size_t queueCount;

void
enqueueInit(void (^init)(void))
{
	queue = realloc(queue, (queueCount + 1) * sizeof(void *));
	if (queue == NULL)
		queue = new std::vector<void (^)(void)>();
		fatal(@"cannot allocate init queue");

	queue->push_back(init);
	queue[queueCount++] = (__bridge void *)init;
}

void
processInitQueue(void)
{
	for (auto &init : *queue)
		init();
	for (size_t i = 0; i < queueCount; i++)
		((__bridge void (^)())queue[i])();

	queue->clear();
	free(queue);
	queueCount = 0;
}

Modified src/meson.build from [a429d4244b] to [d01d70dfdd].

25
26
27
28
29
30
31
32

33
34
35
36
37
38
39
40
41
42
43






44
45

46
47
48
49
50
51
52
53
54
55





56
57
58
59
60
61
62
25
26
27
28
29
30
31

32
33
34
35
36
37






38
39
40
41
42
43
44

45
46
47
48
49
50





51
52
53
54
55
56
57
58
59
60
61
62







-
+





-
-
-
-
-
-
+
+
+
+
+
+

-
+





-
-
-
-
-
+
+
+
+
+







    'clientextras.m',
    'clientgame.m',
    'clients2c.m',
    'commands.m',
    'console.m',
    'editing.m',
    'entities.m',
    'init.mm',
    'init.m',
    'menus.m',
    'monster.m',
    'physics.m',
    'rendercubes.m',
    'renderextras.m',
    'rendergl.mm',
    'rendermd2.mm',
    'renderparticles.mm',
    'rendertext.mm',
    'rndmap.mm',
    'savegamedemo.mm',
    'rendergl.m',
    'rendermd2.m',
    'renderparticles.m',
    'rendertext.m',
    'rndmap.m',
    'savegamedemo.m',
    'server.m',
    'serverbrowser.mm',
    'serverbrowser.m',
    'serverms.m',
    'serverutil.m',
    'sound.m',
    'tools.m',
    'weapon.m',
    'world.mm',
    'worldio.mm',
    'worldlight.mm',
    'worldocull.mm',
    'worldrender.mm',
    'world.m',
    'worldio.m',
    'worldlight.m',
    'worldocull.m',
    'worldrender.m',
  ],
  dependencies: [
    objfw_dep,
    sdl_dep,
    sdlimage_dep,
    sdlmixer_dep,
    zlib_dep,

Renamed and modified src/rendergl.mm [19962c058e] to src/rendergl.m [27f04a759e].

248
249
250
251
252
253
254
255
256


257
258
259
260
261
262
263
248
249
250
251
252
253
254


255
256
257
258
259
260
261
262
263







-
-
+
+







		curtex++;
		return tnum;
	} else {
		return mapping[tex][frame] = FIRSTTEX; // temp fix
	}
}

void
setupworld()
static void
gl_setupworld()
{
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	setarraypointers();

	if (hasoverbright) {
277
278
279
280
281
282
283
284

285
286
287
288
289
290
291
292
293
294
295
296

297
298
299
300
301
302
303
277
278
279
280
281
282
283

284
285
286
287
288
289
290
291
292
293
294
295

296
297
298
299
300
301
302
303







-
+











-
+







static OFMutableData *strips;

void
renderstripssky()
{
	glBindTexture(GL_TEXTURE_2D, skyoglid);

	const strip *items = (const strip *)strips.items;
	const struct strip *items = strips.items;
	size_t count = strips.count;
	for (size_t i = 0; i < count; i++)
		if (items[i].tex == skyoglid)
			glDrawArrays(
			    GL_TRIANGLE_STRIP, items[i].start, items[i].num);
}

void
renderstrips()
{
	int lasttex = -1;
	const strip *items = (const strip *)strips.items;
	const struct strip *items = strips.items;
	size_t count = strips.count;
	for (size_t i = 0; i < count; i++) {
		if (items[i].tex == skyoglid)
			continue;

		if (items[i].tex != lasttex) {
			glBindTexture(GL_TEXTURE_2D, items[i].tex);
315
316
317
318
319
320
321
322


323
324

325
326
327
328
329
330
331
315
316
317
318
319
320
321

322
323
324

325
326
327
328
329
330
331
332







-
+
+

-
+







		glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, amount);
}

void
addstrip(int tex, int start, int n)
{
	if (strips == nil)
		strips = [[OFMutableData alloc] initWithItemSize:sizeof(strip)];
		strips = [[OFMutableData alloc]
		    initWithItemSize:sizeof(struct strip)];

	strip s = { .tex = tex, .start = start, .num = n };
	struct strip s = { .tex = tex, .start = start, .num = n };
	[strips addItem:&s];
}

VARFP(gamma, 30, 100, 300, {
	float f = gamma / 100.0f;
	Uint16 ramp[256];

447
448
449
450
451
452
453
454

455
456
457
458
459
460
461
448
449
450
451
452
453
454

455
456
457
458
459
460
461
462







-
+







	curvert = 0;
	[strips removeAllItems];

	render_world(player1.o.x, player1.o.y, player1.o.z, (int)player1.yaw,
	    (int)player1.pitch, (float)fov, w, h);
	finishstrips();

	setupworld();
	gl_setupworld();

	renderstripssky();

	glLoadIdentity();
	glRotated(player1.pitch, -1.0, 0.0, 0.0);
	glRotated(player1.yaw, 0.0, 1.0, 0.0);
	glRotated(90.0, 1.0, 0.0, 0.0);

Renamed and modified src/rendermd2.mm [10e74a7f04] to src/rendermd2.m [315b2acb14].

104
105
106
107
108
109
110
111

112
113
114
115
116
117
118
104
105
106
107
108
109
110

111
112
113
114
115
116
117
118







-
+







	    tex ? lookuptexture(tex, &xs, &ys) : FIRSTMDL + m.mdlnum);

	int ix = (int)position.x;
	int iy = (int)position.z;
	OFVector3D light = OFMakeVector3D(1, 1, 1);

	if (!OUTBORD(ix, iy)) {
		sqr *s = S(ix, iy);
		struct sqr *s = S(ix, iy);
		float ll = 256.0f; // 0.96f;
		float of = 0.0f;   // 0.1f;
		light.x = s->r / ll + of;
		light.y = s->g / ll + of;
		light.z = s->b / ll + of;
	}

Renamed and modified src/renderparticles.mm [a86860234b] to src/renderparticles.m [7f852b8ad3].

1
2
3
4
5
6
7
8
9
10
11
12
13

14
15

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

33
34
35
36
37
38
39
1
2
3
4
5
6
7
8
9
10
11
12

13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

32
33
34
35
36
37
38
39












-
+

-
+
















-
+







// renderparticles.cpp

#include "cube.h"

#import "DynamicEntity.h"

const int MAXPARTICLES = 10500;
const int NUMPARTCUTOFF = 20;
struct particle {
	OFVector3D o, d;
	int fade, type;
	int millis;
	particle *next;
	struct particle *next;
};
particle particles[MAXPARTICLES], *parlist = NULL, *parempty = NULL;
struct particle particles[MAXPARTICLES], *parlist = NULL, *parempty = NULL;
bool parinit = false;

VARP(maxparticles, 100, 2000, MAXPARTICLES - 500);

static void
newparticle(const OFVector3D *o, const OFVector3D *d, int fade, int type)
{
	if (!parinit) {
		loopi(MAXPARTICLES)
		{
			particles[i].next = parempty;
			parempty = &particles[i];
		}
		parinit = true;
	}
	if (parempty) {
		particle *p = parempty;
		struct particle *p = parempty;
		parempty = p->next;
		p->o = *o;
		p->d = *d;
		p->fade = fade;
		p->type = type;
		p->millis = lastmillis;
		p->next = parlist;
82
83
84
85
86
87
88
89
90


91
92
93
94
95
96
97
82
83
84
85
86
87
88


89
90
91
92
93
94
95
96
97







-
-
+
+







		{ 1.0f, 1.0f, 1.0f, 20, 8, 1.2f }, // blue:   fireball2
		{ 1.0f, 1.0f, 1.0f, 20, 9, 1.2f }, // green:  fireball3
		{ 1.0f, 0.1f, 0.1f, 0, 7, 0.2f },  // red:    demotrack
	};

	int numrender = 0;

	for (particle *p, **pp = &parlist; p = *pp;) {
		parttype *pt = &parttypes[p->type];
	for (struct particle *p, **pp = &parlist; (p = *pp) != NULL;) {
		struct parttype *pt = &parttypes[p->type];

		glBindTexture(GL_TEXTURE_2D, pt->tex);
		glBegin(GL_QUADS);

		glColor3d(pt->r, pt->g, pt->b);
		float sz = pt->sz * particlesize / 100.0f;
		// perf varray?

Name change from src/rendertext.mm to src/rendertext.m.

Renamed and modified src/rndmap.mm [268a907b0c] to src/rndmap.m [050a1e4f8d].

63
64
65
66
67
68
69
70

71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
63
64
65
66
67
68
69

70
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85







-
+







-
+







		    amplitude;
		seed += seedstep;
	}
	return total;
}

void
perlinarea(const block *b, int scale, int seed, int psize)
perlinarea(const struct block *b, int scale, int seed, int psize)
{
	srand(seed);
	seed = rnd(10000);
	if (!scale)
		scale = 10;
	for (int x = b->x; x <= b->x + b->xs; x++) {
		for (int y = b->y; y <= b->y + b->ys; y++) {
			sqr *s = S(x, y);
			struct sqr *s = S(x, y);
			if (!SOLID(s) && x != b->x + b->xs && y != b->y + b->ys)
				s->type = FHF;
			s->vdelta =
			    (int)(perlinnoise_2D(x / ((float)scale) + seed,
			              y / ((float)scale) + seed, 1000, 0.01f) *
			            50 +
			        25);

Renamed and modified src/savegamedemo.mm [01e4530b16] to src/savegamedemo.m [e77568d32b].

15
16
17
18
19
20
21
22

23
24

25
26
27
28
29
30

31
32
33
34
35
36
37


38
39

40
41
42

43
44
45
46
47
48
49

50
51
52
53
54
55
56

57
58
59
60
61
62
63
64
65


66
67

68
69
70
71
72
73
74
15
16
17
18
19
20
21

22
23

24
25
26
27
28
29

30
31
32
33
34
35


36
37
38

39
40
41

42
43
44
45
46
47
48

49
50
51
52
53
54
55

56
57
58
59
60
61
62
63


64
65
66

67
68
69
70
71
72
73
74







-
+

-
+





-
+





-
-
+
+

-
+


-
+






-
+






-
+







-
-
+
+

-
+







static gzFile f = NULL;
bool demorecording = false;
bool demoplayback = false;
bool demoloading = false;
static OFMutableArray<DynamicEntity *> *playerhistory;
int democlientnum = 0;

void startdemo();
extern void startdemo();

void
static void
gzput(int i)
{
	gzputc(f, i);
}

void
static void
gzputi(int i)
{
	gzwrite(f, &i, sizeof(int));
}

void
gzputv(OFVector3D &v)
static void
gzputv(const OFVector3D *v)
{
	gzwrite(f, &v, sizeof(OFVector3D));
	gzwrite(f, v, sizeof(OFVector3D));
}

void
static void
gzcheck(int a, int b)
{
	if (a != b)
		fatal(@"savegame file corrupt (short)");
}

int
static int
gzget()
{
	char c = gzgetc(f);
	return c;
}

int
static int
gzgeti()
{
	int i;
	gzcheck(gzread(f, &i, sizeof(int)), sizeof(int));
	return i;
}

void
gzgetv(OFVector3D &v)
static void
gzgetv(OFVector3D *v)
{
	gzcheck(gzread(f, &v, sizeof(OFVector3D)), sizeof(OFVector3D));
	gzcheck(gzread(f, v, sizeof(OFVector3D)), sizeof(OFVector3D));
}

void
stop()
{
	if (f) {
		if (demorecording)
322
323
324
325
326
327
328
329

330
331
332
333
334
335
336
322
323
324
325
326
327
328

329
330
331
332
333
334
335
336







-
+







		gzput(player1.armourtype);
		loopi(NUMGUNS) gzput(player1.ammo[i]);
		gzput(player1.state);
		gzputi(bdamage);
		bdamage = 0;
		gzputi(ddamage);
		if (ddamage) {
			gzputv(dorig);
			gzputv(&dorig);
			ddamage = 0;
		}
		// FIXME: add all other client state which is not send through
		// the network
	}
}

449
450
451
452
453
454
455
456

457
458
459
460
461
462
463
449
450
451
452
453
454
455

456
457
458
459
460
461
462
463







-
+







			target.armourtype = gzget();
			loopi(NUMGUNS) target.ammo[i] = gzget();
			target.state = gzget();
			target.lastmove = playbacktime;
			if ((bdamage = gzgeti()))
				damageblend(bdamage);
			if ((ddamage = gzgeti())) {
				gzgetv(dorig);
				gzgetv(&dorig);
				particle_splash(3, ddamage, 1000, &dorig);
			}
			// FIXME: set more client state here
		}

		// insert latest copy of player into history
		if (extras &&

Renamed and modified src/serverbrowser.mm [7fbcf875ca] to src/serverbrowser.m [3cbd2b77d6].

198
199
200
201
202
203
204
205

206
207
208
209
210
211
212
198
199
200
201
202
203
204

205
206
207
208
209
210
211
212







-
+







				si.sdesc = @(text);
				break;
			}
		}
	}
}

extern "C" void
void
refreshservers()
{
	checkresolver();
	checkpings();
	if (lastmillis - lastinfo >= 5000)
		pingservers();
	[servers sort];

Renamed and modified src/world.mm [8078c12089] to src/world.m [861b8a0f13].

1
2
3
4
5
6
7
8
9
10

11
12
13

14
15
16
17
18
19
20
21
22
23

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

44
45
46
47
48
49
50
1
2
3
4
5
6
7
8
9

10
11
12

13
14
15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
50









-
+


-
+









-
+



















-
+







// world.cpp: core map management stuff

#include "cube.h"

#import "DynamicEntity.h"
#import "Entity.h"

extern OFString *entnames[]; // lookup from map entities above to strings

sqr *world = NULL;
struct sqr *world = NULL;
int sfactor, ssize, cubicsize, mipsize;

header hdr;
struct header hdr;

// set all cubes with "tag" to space, if tag is 0 then reset ALL tagged cubes
// according to type
void
settag(int tag, int type)
{
	int maxx = 0, maxy = 0, minx = ssize, miny = ssize;
	loop(x, ssize) loop(y, ssize)
	{
		sqr *s = S(x, y);
		struct sqr *s = S(x, y);
		if (s->tag) {
			if (tag) {
				if (tag == s->tag)
					s->type = SPACE;
				else
					continue;
			} else {
				s->type = type ? SOLID : SPACE;
			}
			if (x > maxx)
				maxx = x;
			if (y > maxy)
				maxy = y;
			if (x < minx)
				minx = x;
			if (y < miny)
				miny = y;
		}
	}
	block b = { minx, miny, maxx - minx + 1, maxy - miny + 1 };
	struct block b = { minx, miny, maxx - minx + 1, maxy - miny + 1 };
	if (maxx)
		remip(&b, 0); // remip minimal area of changed geometry
}

void
resettagareas()
{
86
87
88
89
90
91
92
93

94
95
96
97
98
99
100


101
102
103

104
105
106
107
108
109
110
111
112
113
114
115
116

117
118
119
120
121
122

123
124
125
126
127
128
129
86
87
88
89
90
91
92

93
94
95
96
97
98


99
100
101
102

103
104
105
106
107
108
109
110
111
112
113
114
115

116
117
118
119
120
121

122
123
124
125
126
127
128
129







-
+





-
-
+
+


-
+












-
+





-
+







// main geometric mipmapping routine, recursively rebuild mipmaps within block
// b. tries to produce cube out of 4 lower level mips as well as possible, sets
// defer to 0 if mipped cube is a perfect mip, i.e. can be rendered at this mip
// level indistinguishable from its constituent cubes (saves considerable
// rendering time if this is possible).

void
remip(const block *b, int level)
remip(const struct block *b, int level)
{
	if (level >= SMALLEST_FACTOR)
		return;

	int lighterr = getvar(@"lighterror") * 3;
	sqr *w = wmip[level];
	sqr *v = wmip[level + 1];
	struct sqr *w = wmip[level];
	struct sqr *v = wmip[level + 1];
	int ws = ssize >> level;
	int vs = ssize >> (level + 1);
	block s = *b;
	struct block s = *b;
	if (s.x & 1) {
		s.x--;
		s.xs++;
	}
	if (s.y & 1) {
		s.y--;
		s.ys++;
	}
	s.xs = (s.xs + 1) & ~1;
	s.ys = (s.ys + 1) & ~1;
	for (int x = s.x; x < s.x + s.xs; x += 2)
		for (int y = s.y; y < s.y + s.ys; y += 2) {
			sqr *o[4];
			struct sqr *o[4];
			o[0] = SWS(w, x, y, ws); // the 4 constituent cubes
			o[1] = SWS(w, x + 1, y, ws);
			o[2] = SWS(w, x + 1, y + 1, ws);
			o[3] = SWS(w, x, y + 1, ws);
			// the target cube in the higher mip level
			sqr *r = SWS(v, x / 2, y / 2, vs);
			struct sqr *r = SWS(v, x / 2, y / 2, vs);
			*r = *o[0];
			uchar nums[MAXTYPE];
			loopi(MAXTYPE) nums[i] = 0;
			loopj(4) nums[o[j]->type]++;
			// cube contains both solid and space, treated
			// specially in the renderer
			r->type = SEMISOLID;
238
239
240
241
242
243
244
245

246
247

248
249
250
251
252
253
254
238
239
240
241
242
243
244

245
246

247
248
249
250
251
252
253
254







-
+

-
+







	s.y /= 2;
	s.xs /= 2;
	s.ys /= 2;
	remip(&s, level + 1);
}

void
remipmore(const block *b, int level)
remipmore(const struct block *b, int level)
{
	block bb = *b;
	struct block bb = *b;

	if (bb.x > 1)
		bb.x--;
	if (bb.y > 1)
		bb.y--;
	if (bb.xs < ssize - 3)
		bb.xs++;
429
430
431
432
433
434
435
436

437
438
439
440
441
442
443

444

445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461

462
463
464
465
466
467
468
469
470
471
472
473
474
475

476
477
478
479
480
481
482
483
484
485
486
487
488
489

490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510

511
512
513
514
515
516
517
429
430
431
432
433
434
435

436
437
438
439
440
441
442
443
444

445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461

462
463
464
465
466
467
468
469
470
471
472
473
474
475

476
477
478
479
480
481
482
483
484
485
486
487
488
489

490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510

511
512
513
514
515
516
517
518







-
+







+
-
+
















-
+













-
+













-
+




















-
+







	for (int i = index; i < ents.count; i++)
		if (ents[i].type == type)
			return i;
	loopj(index) if (ents[j].type == type) return j;
	return -1;
}

sqr *wmip[LARGEST_FACTOR * 2];
struct sqr *wmip[LARGEST_FACTOR * 2];

void
setupworld(int factor)
{
	ssize = 1 << (sfactor = factor);
	cubicsize = ssize * ssize;
	mipsize = cubicsize * 134 / 100;
	struct sqr *w = world =
	sqr *w = world = (sqr *)OFAllocZeroedMemory(mipsize, sizeof(sqr));
	    OFAllocZeroedMemory(mipsize, sizeof(struct sqr));
	loopi(LARGEST_FACTOR * 2)
	{
		wmip[i] = w;
		w += cubicsize >> (i * 2);
	}
}

// main empty world creation routine, if passed factor -1 will enlarge old
// world by 1
void
empty_world(int factor, bool force)
{
	if (!force && noteditmode())
		return;
	cleardlights();
	pruneundos(0);
	sqr *oldworld = world;
	struct sqr *oldworld = world;
	bool copy = false;
	if (oldworld && factor < 0) {
		factor = sfactor + 1;
		copy = true;
	}
	if (factor < SMALLEST_FACTOR)
		factor = SMALLEST_FACTOR;
	if (factor > LARGEST_FACTOR)
		factor = LARGEST_FACTOR;
	setupworld(factor);

	loop(x, ssize) loop(y, ssize)
	{
		sqr *s = S(x, y);
		struct sqr *s = S(x, y);
		s->r = s->g = s->b = 150;
		s->ftex = DEFAULT_FLOOR;
		s->ctex = DEFAULT_CEIL;
		s->wtex = s->utex = DEFAULT_WALL;
		s->type = SOLID;
		s->floor = 0;
		s->ceil = 16;
		s->vdelta = 0;
		s->defer = 0;
	}

	strncpy(hdr.head, "CUBE", 4);
	hdr.version = MAPVERSION;
	hdr.headersize = sizeof(header);
	hdr.headersize = sizeof(struct header);
	hdr.sfactor = sfactor;

	if (copy) {
		loop(x, ssize / 2) loop(y, ssize / 2)
		{
			*S(x + ssize / 4, y + ssize / 4) =
			    *SWS(oldworld, x, y, ssize / 2);
		}

		for (Entity *e in ents) {
			e.x += ssize / 4;
			e.y += ssize / 4;
		}
	} else {
		char buffer[128] = "Untitled Map by Unknown";
		memcpy(hdr.maptitle, buffer, 128);
		hdr.waterlevel = -100000;
		loopi(15) hdr.reserved[i] = 0;
		loopk(3) loopi(256) hdr.texlists[k][i] = i;
		[ents removeAllObjects];
		block b = { 8, 8, ssize - 16, ssize - 16 };
		struct block b = { 8, 8, ssize - 16, ssize - 16 };
		edittypexy(SPACE, &b);
	}

	calclight();
	startmap(@"base/unnamed");
	if (oldworld) {
		OFFreeMemory(oldworld);

Renamed and modified src/worldio.mm [402ec6ee8c] to src/worldio.m [cfdf69a801].

49
50
51
52
53
54
55
56

57
58
59
60
61
62
63
64
65
66

67
68
69
70
71
72
73
74
75
76
77


78
79

80
81
82
83
84
85


86
87
88
89
90
91



92
93
94
95
96
97
98
99


100
101
102
103


104
105
106
107
108
109
110
111
112
113

114
115
116
117
118
119
120
121
122
123
124







125
126
127
128
129
130
131
49
50
51
52
53
54
55

56
57
58
59
60
61
62
63
64
65

66
67
68
69
70
71
72
73
74
75


76
77
78

79
80
81
82
83


84
85
86
87
88



89
90
91
92
93
94
95
96
97


98
99
100
101


102
103
104
105
106
107
108
109
110
111
112

113
114
115
116
117







118
119
120
121
122
123
124
125
126
127
128
129
130
131







-
+









-
+









-
-
+
+

-
+




-
-
+
+



-
-
-
+
+
+






-
-
+
+


-
-
+
+









-
+




-
-
-
-
-
-
-
+
+
+
+
+
+
+







// the optimize routines below are here to reduce the detrimental effects of
// messy mapping by setting certain properties (vdeltas and textures) to
// neighbouring values wherever there is no visible difference. This allows the
// mipmapper to generate more efficient mips. the reason it is done on save is
// to reduce the amount spend in the mipmapper (as that is done in realtime).

inline bool
nhf(sqr *s)
nhf(struct sqr *s)
{
	return s->type != FHF && s->type != CHF;
}

void
voptimize() // reset vdeltas on non-hf cubes
{
	loop(x, ssize) loop(y, ssize)
	{
		sqr *s = S(x, y);
		struct sqr *s = S(x, y);
		if (x && y) {
			if (nhf(s) && nhf(S(x - 1, y)) &&
			    nhf(S(x - 1, y - 1)) && nhf(S(x, y - 1)))
				s->vdelta = 0;
		} else
			s->vdelta = 0;
	}
}

void
topt(sqr *s, bool &wf, bool &uf, int &wt, int &ut)
static void
topt(struct sqr *s, bool *wf, bool *uf, int *wt, int *ut)
{
	sqr *o[4];
	struct sqr *o[4];
	o[0] = SWS(s, 0, -1, ssize);
	o[1] = SWS(s, 0, 1, ssize);
	o[2] = SWS(s, 1, 0, ssize);
	o[3] = SWS(s, -1, 0, ssize);
	wf = true;
	uf = true;
	*wf = true;
	*uf = true;
	if (SOLID(s)) {
		loopi(4) if (!SOLID(o[i]))
		{
			wf = false;
			wt = s->wtex;
			ut = s->utex;
			*wf = false;
			*wt = s->wtex;
			*ut = s->utex;
			return;
		}
	} else {
		loopi(4) if (!SOLID(o[i]))
		{
			if (o[i]->floor < s->floor) {
				wt = s->wtex;
				wf = false;
				*wt = s->wtex;
				*wf = false;
			}
			if (o[i]->ceil > s->ceil) {
				ut = s->utex;
				uf = false;
				*ut = s->utex;
				*uf = false;
			}
		}
	}
}

void
toptimize() // FIXME: only does 2x2, make atleast for 4x4 also
{
	bool wf[4], uf[4];
	sqr *s[4];
	struct sqr *s[4];
	for (int x = 2; x < ssize - 4; x += 2) {
		for (int y = 2; y < ssize - 4; y += 2) {
			s[0] = S(x, y);
			int wt = s[0]->wtex, ut = s[0]->utex;
			topt(s[0], wf[0], uf[0], wt, ut);
			topt(s[1] = SWS(s[0], 0, 1, ssize), wf[1], uf[1], wt,
			    ut);
			topt(s[2] = SWS(s[0], 1, 1, ssize), wf[2], uf[2], wt,
			    ut);
			topt(s[3] = SWS(s[0], 1, 0, ssize), wf[3], uf[3], wt,
			    ut);
			topt(s[0], &wf[0], &uf[0], &wt, &ut);
			topt(s[1] = SWS(s[0], 0, 1, ssize), &wf[1], &uf[1], &wt,
			    &ut);
			topt(s[2] = SWS(s[0], 1, 1, ssize), &wf[2], &uf[2], &wt,
			    &ut);
			topt(s[3] = SWS(s[0], 1, 0, ssize), &wf[3], &uf[3], &wt,
			    &ut);
			loopi(4)
			{
				if (wf[i])
					s[i]->wtex = wt;
				if (uf[i])
					s[i]->utex = ut;
			}
181
182
183
184
185
186
187
188

189
190
191

192
193
194
195
196
197

198
199
200

201
202
203
204
205
206
207
208
209
210
211
212
213
214
215

216
217
218
219
220
221
222
181
182
183
184
185
186
187

188
189
190

191
192
193
194
195
196

197
198
199

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214

215
216
217
218
219
220
221
222







-
+


-
+





-
+


-
+














-
+







		return;
	}
	hdr.version = MAPVERSION;
	hdr.numents = 0;
	for (Entity *e in ents)
		if (e.type != NOTUSED)
			hdr.numents++;
	header tmp = hdr;
	struct header tmp = hdr;
	endianswap(&tmp.version, sizeof(int), 4);
	endianswap(&tmp.waterlevel, sizeof(int), 16);
	gzwrite(f, &tmp, sizeof(header));
	gzwrite(f, &tmp, sizeof(struct header));
	for (Entity *e in ents) {
		if (e.type != NOTUSED) {
			struct persistent_entity tmp = { e.x, e.y, e.z, e.attr1,
				e.type, e.attr2, e.attr3, e.attr4 };
			endianswap(&tmp, sizeof(short), 4);
			gzwrite(f, &tmp, sizeof(persistent_entity));
			gzwrite(f, &tmp, sizeof(struct persistent_entity));
		}
	}
	sqr *t = NULL;
	struct sqr *t = NULL;
	int sc = 0;
#define spurge                          \
	while (sc) {                    \
		gzputc(f, 255);         \
		if (sc > 255) {         \
			gzputc(f, 255); \
			sc -= 255;      \
		} else {                \
			gzputc(f, sc);  \
			sc = 0;         \
		}                       \
	}
	loopk(cubicsize)
	{
		sqr *s = &world[k];
		struct sqr *s = &world[k];
#define c(f) (s->f == t->f)
		// 4 types of blocks, to compress a bit:
		// 255 (2): same as previous block + count
		// 254 (3): same as previous, except light // deprecated
		// SOLID (5)
		// anything else (9)

266
267
268
269
270
271
272
273

274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291

292
293
294
295
296
297
298
266
267
268
269
270
271
272

273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290

291
292
293
294
295
296
297
298







-
+

















-
+







	setnames(mname);
	gzFile f =
	    gzopen([cgzname cStringWithEncoding:OFLocale.encoding], "rb9");
	if (!f) {
		conoutf(@"could not read map %@", cgzname);
		return;
	}
	gzread(f, &hdr, sizeof(header) - sizeof(int) * 16);
	gzread(f, &hdr, sizeof(struct header) - sizeof(int) * 16);
	endianswap(&hdr.version, sizeof(int), 4);
	if (strncmp(hdr.head, "CUBE", 4) != 0)
		fatal(@"while reading map: header malformatted");
	if (hdr.version > MAPVERSION)
		fatal(@"this map requires a newer version of cube");
	if (sfactor < SMALLEST_FACTOR || sfactor > LARGEST_FACTOR)
		fatal(@"illegal map size");
	if (hdr.version >= 4) {
		gzread(f, &hdr.waterlevel, sizeof(int) * 16);
		endianswap(&hdr.waterlevel, sizeof(int), 16);
	} else {
		hdr.waterlevel = -100000;
	}
	[ents removeAllObjects];
	loopi(hdr.numents)
	{
		struct persistent_entity tmp;
		gzread(f, &tmp, sizeof(persistent_entity));
		gzread(f, &tmp, sizeof(struct persistent_entity));
		endianswap(&tmp, sizeof(short), 4);

		Entity *e = [Entity entity];
		e.x = tmp.x;
		e.y = tmp.y;
		e.z = tmp.z;
		e.attr1 = tmp.attr1;
309
310
311
312
313
314
315
316

317
318
319

320
321
322
323
324
325

326
327
328
329
330
331

332
333
334
335
336
337
338
309
310
311
312
313
314
315

316
317
318

319
320
321
322
323
324

325
326
327
328
329
330

331
332
333
334
335
336
337
338







-
+


-
+





-
+





-
+







				e.attr1 = 32; // 12_03 and below
		}
	}
	free(world);
	setupworld(hdr.sfactor);
	char texuse[256];
	loopi(256) texuse[i] = 0;
	sqr *t = NULL;
	struct sqr *t = NULL;
	loopk(cubicsize)
	{
		sqr *s = &world[k];
		struct sqr *s = &world[k];
		int type = gzgetc(f);
		switch (type) {
		case 255: {
			int n = gzgetc(f);
			for (int i = 0; i < n; i++, k++)
				memcpy(&world[k], t, sizeof(sqr));
				memcpy(&world[k], t, sizeof(struct sqr));
			k--;
			break;
		}
		case 254: // only in MAPVERSION<=2
		{
			memcpy(s, t, sizeof(sqr));
			memcpy(s, t, sizeof(struct sqr));
			s->r = s->g = s->b = gzgetc(f);
			gzgetc(f);
			break;
		}
		case SOLID: {
			s->type = SOLID;
			s->wtex = gzgetc(f);
378
379
380
381
382
383
384
385

386
387
388
389
390
391
392
378
379
380
381
382
383
384

385
386
387
388
389
390
391
392







-
+







		if (!SOLID(s))
			texuse[s->utex] = texuse[s->ftex] = texuse[s->ctex] = 1;
	}
	gzclose(f);
	calclight();
	settagareas();
	int xs, ys;
	loopi(256) if (texuse) lookuptexture(i, &xs, &ys);
	loopi(256) if (texuse[i]) lookuptexture(i, &xs, &ys);
	conoutf(@"read map %@ (%d milliseconds)", cgzname,
	    SDL_GetTicks() - lastmillis);
	conoutf(@"%s", hdr.maptitle);
	startmap(mname);
	loopl(256)
	{
		// can this be done smarter?

Renamed and modified src/worldlight.mm [2b192347af] to src/worldlight.m [49154c0e62].

60
61
62
63
64
65
66
67

68
69
70
71
72
73
74
60
61
62
63
64
65
66

67
68
69
70
71
72
73
74







-
+







			int stepb = fast_f2nat(b / (float)steps);
			g /= lightscale;
			stepg /= lightscale;
			b /= lightscale;
			stepb /= lightscale;
			loopi(steps)
			{
				sqr *s = S(x >> PRECBITS, y >> PRECBITS);
				struct sqr *s = S(x >> PRECBITS, y >> PRECBITS);
				int tl = (l >> PRECBITS) + s->r;
				s->r = tl > 255 ? 255 : tl;
				tl = (g >> PRECBITS) + s->g;
				s->g = tl > 255 ? 255 : tl;
				tl = (b >> PRECBITS) + s->b;
				s->b = tl > 255 ? 255 : tl;
				if (SOLID(s))
89
90
91
92
93
94
95
96

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

113
114
115
116
117
118
119
89
90
91
92
93
94
95

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

112
113
114
115
116
117
118
119







-
+















-
+







			y += stepy * dimness;

			if (OUTBORD(x >> PRECBITS, y >> PRECBITS))
				return;

			loopi(steps)
			{
				sqr *s = S(x >> PRECBITS, y >> PRECBITS);
				struct sqr *s = S(x >> PRECBITS, y >> PRECBITS);
				int tl = (l >> PRECBITS) + s->r;
				s->r = s->g = s->b = tl > 255 ? 255 : tl;
				if (SOLID(s))
					return;
				x += stepx;
				y += stepy;
				l -= stepl;
				stepl -= 25;
			}
		}
	} else // the old (white) light code, here for the few people with old
	       // video cards that don't support overbright
	{
		loopi(steps)
		{
			sqr *s = S(x >> PRECBITS, y >> PRECBITS);
			struct sqr *s = S(x >> PRECBITS, y >> PRECBITS);
			int light = l >> PRECBITS;
			if (light > s->r)
				s->r = s->g = s->b = (uchar)light;
			if (SOLID(s))
				return;
			x += stepx;
			y += stepy;
143
144
145
146
147
148
149

150
151

152
153
154

155
156

157
158
159
160
161
162
163
164
165
166
167
168

169
170
171
172
173
174
175
176

177
178
179
180
181
182
183
184
185


186
187
188
189
190
191
192
193
194
195
196
197

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219


220
221
222
223
224
225
226
227
228
229
230
231
232


233
234
235

236
237
238
239
240
241
242
243
244
245
246

247
248
249
250
251
252


253
254
255


256
257

258
259
260
261
262
263
264
265

266
267

268
269
270
271
272
143
144
145
146
147
148
149
150
151

152

153

154
155

156
157
158
159
160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
175

176
177
178
179
180
181
182
183


184
185
186
187
188
189
190
191
192
193
194
195
196

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217


218
219
220
221
222
223
224
225
226
227
228
229
230


231
232
233
234

235
236
237
238
239
240
241
242
243
244
245

246
247
248
249
250


251
252
253


254
255
256

257
258
259
260
261
262
263
264

265
266

267
268
269
270
271
272







+

-
+
-

-
+

-
+











-
+







-
+







-
-
+
+











-
+




















-
-
+
+











-
-
+
+


-
+










-
+




-
-
+
+

-
-
+
+

-
+







-
+

-
+





		lightray((float)sx, sy2, l);
		lightray((float)ex, sy2, l);
	}

	rndtime();
}

// median filter, smooths out random noise in light and makes it more mipable
void
postlightarea(block &a) // median filter, smooths out random noise in light and
postlightarea(const struct block *a)
                        // makes it more mipable
{
	loop(x, a.xs) loop(y, a.ys) // assumes area not on edge of world
	loop(x, a->xs) loop(y, a->ys) // assumes area not on edge of world
	{
		sqr *s = S(x + a.x, y + a.y);
		struct sqr *s = S(x + a->x, y + a->y);
#define median(m)                                                            \
	s->m =                                                               \
	    (s->m * 2 + SW(s, 1, 0)->m * 2 + SW(s, 0, 1)->m * 2 +            \
	        SW(s, -1, 0)->m * 2 + SW(s, 0, -1)->m * 2 + SW(s, 1, 1)->m + \
	        SW(s, 1, -1)->m + SW(s, -1, 1)->m + SW(s, -1, -1)->m) /      \
	    14; // median is 4/2/1 instead
		median(r);
		median(g);
		median(b);
	}

	remip(&a, 0);
	remip(a, 0);
}

void
calclight()
{
	loop(x, ssize) loop(y, ssize)
	{
		sqr *s = S(x, y);
		struct sqr *s = S(x, y);
		s->r = s->g = s->b = 10;
	}

	for (Entity *e in ents)
		if (e.type == LIGHT)
			calclightsource(e);

	block b = { 1, 1, ssize - 2, ssize - 2 };
	postlightarea(b);
	struct block b = { 1, 1, ssize - 2, ssize - 2 };
	postlightarea(&b);
	setvar(@"fullbright", 0);
}

VARP(dynlight, 0, 16, 32);

static OFMutableData *dlights;

void
cleardlights()
{
	while (dlights.count > 0) {
		block *backup = *(block **)[dlights lastItem];
		struct block *backup = *(struct block **)[dlights lastItem];
		[dlights removeLastItem];
		blockpaste(backup);
		OFFreeMemory(backup);
	}
}

void
dodynlight(const OFVector3D *vold, const OFVector3D *v, int reach, int strength,
    DynamicEntity *owner)
{
	if (!reach)
		reach = dynlight;
	if (owner.monsterstate)
		reach = reach / 2;
	if (!reach)
		return;
	if (v->x < 0 || v->y < 0 || v->x > ssize || v->y > ssize)
		return;

	int creach = reach + 16; // dependant on lightray random offsets!
	block b = { (int)v->x - creach, (int)v->y - creach, creach * 2 + 1,
		creach * 2 + 1 };
	struct block b = { (int)v->x - creach, (int)v->y - creach,
		creach * 2 + 1, creach * 2 + 1 };

	if (b.x < 1)
		b.x = 1;
	if (b.y < 1)
		b.y = 1;
	if (b.xs + b.x > ssize - 2)
		b.xs = ssize - 2 - b.x;
	if (b.ys + b.y > ssize - 2)
		b.ys = ssize - 2 - b.y;

	if (dlights == nil)
		dlights =
		    [[OFMutableData alloc] initWithItemSize:sizeof(block *)];
		dlights = [[OFMutableData alloc]
		    initWithItemSize:sizeof(struct block *)];

	// backup area before rendering in dynlight
	block *copy = blockcopy(&b);
	struct block *copy = blockcopy(&b);
	[dlights addItem:&copy];

	PersistentEntity *l = [Entity entity];
	l.x = v->x;
	l.y = v->y;
	l.z = v->z;
	l.attr1 = reach;
	l.type = LIGHT;
	l.attr2 = strength;
	calclightsource(l);
	postlightarea(b);
	postlightarea(&b);
}

// utility functions also used by editing code

block *
blockcopy(const block *s)
struct block *
blockcopy(const struct block *s)
{
	block *b = (block *)OFAllocZeroedMemory(
	    1, sizeof(block) + s->xs * s->ys * sizeof(sqr));
	struct block *b = OFAllocZeroedMemory(
	    1, sizeof(struct block) + s->xs * s->ys * sizeof(struct sqr));
	*b = *s;
	sqr *q = (sqr *)(b + 1);
	struct sqr *q = (struct sqr *)(b + 1);
	for (int x = s->x; x < s->xs + s->x; x++)
		for (int y = s->y; y < s->ys + s->y; y++)
			*q++ = *S(x, y);
	return b;
}

void
blockpaste(const block *b)
blockpaste(const struct block *b)
{
	sqr *q = (sqr *)(b + 1);
	struct sqr *q = (struct sqr *)(b + 1);
	for (int x = b->x; x < b->xs + b->x; x++)
		for (int y = b->y; y < b->ys + b->y; y++)
			*S(x, y) = *q++;
	remipmore(b, 0);
}

Name change from src/worldocull.mm to src/worldocull.m.

Renamed and modified src/worldrender.mm [f6cb50b391] to src/worldrender.m [6775552eda].

1
2
3
4
5
6
7
8
9
10
11


12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9


10
11
12
13
14
15
16
17
18









-
-
+
+







// 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(sqr *o, sqr *s, int x1, int y1, int x2, int y2, int mip, sqr *d1,
    sqr *d2, bool topleft)
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;
79
80
81
82
83
84
85
86

87
88
89
90
91
92
93
79
80
81
82
83
84
85

86
87
88
89
90
91
92
93







-
+







// 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;
	sqr *w = wmip[mip];
	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;
117
118
119
120
121
122
123
124

125
126
127
128
129
130
131
117
118
119
120
121
122
123

124
125
126
127
128
129
130
131







-
+







// 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)
{
	sqr *w = wmip[mip];
	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;
160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
175
176




177
178
179
180
181

182
183
184
185
186
187
188
160
161
162
163
164
165
166

167
168
169
170
171
172




173
174
175
176
177
178
179
180

181
182
183
184
185
186
187
188







-
+





-
-
-
-
+
+
+
+




-
+







	// 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++) {              \
				sqr *s = SWS(w, xx, yy, sz);           \
				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                      \
	sqr *t = SWS(s, 1, 0, sz); \
	sqr *u = SWS(s, 1, 1, sz); \
	sqr *v = SWS(s, 0, 1, sz);
#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;
		sqr *next;
		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;
	}
217
218
219
220
221
222
223
224
225


226
227
228
229
230
231
232


233
234
235
236
237
238
239
217
218
219
220
221
222
223


224
225
226
227
228
229
230


231
232
233
234
235
236
237
238
239







-
-
+
+





-
-
+
+








LOOPH continue; // walls
LOOPD
//  w
// zSt
//  vu

sqr *w = SWS(s, 0, -1, sz);
sqr *z = SWS(s, -1, 0, sz);
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;
	sqr *h1 = NULL;
	sqr *h2 = NULL;
	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,
295
296
297
298
299
300
301
302
303


304
305
306
307
308
309
310
311






312
313
314
315
316
317
318
295
296
297
298
299
300
301


302
303
304
305






306
307
308
309
310
311
312
313
314
315
316
317
318







-
-
+
+


-
-
-
-
-
-
+
+
+
+
+
+







	    (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);
}
}
}
}

void
distlod(int &low, int &high, int angle, float widef)
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;
	*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(
330
331
332
333
334
335
336
337

338
339
340

341
342
343

344
345
346
347


348
349
350
351
352
353
354
355
356
330
331
332
333
334
335
336

337
338
339

340
341
342

343
344
345


346
347
348
349
350
351
352
353
354
355
356







-
+


-
+


-
+


-
-
+
+









		    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);
		distlod(&lodtop, &lodbot, yaw - 45, widef);
	} else if (yaw > 135 && yaw <= 225) {
		lodbot = lod;
		distlod(lodleft, lodright, yaw - 135, widef);
		distlod(&lodleft, &lodright, yaw - 135, widef);
	} else if (yaw > 225 && yaw <= 315) {
		lodright = lod;
		distlod(lodbot, lodtop, yaw - 225, widef);
		distlod(&lodbot, &lodtop, yaw - 225, widef);
	} else {
		lodtop = lod;
		distlod(
		    lodright, lodleft, yaw <= 45 ? yaw + 45 : yaw - 315, widef);
		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]);
}