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
project('Cube', ['c', 'objc', 'objcpp'],
  meson_version: '>=1.5.0',
  default_options: {
    'optimization': '2'
  })

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

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

|





<
|
|
|
|
|
|
<







1
2
3
4
5
6

7
8
9
10
11
12

13
14
15
16
17
18
19
project('Cube', ['c', 'objc'],
  meson_version: '>=1.5.0',
  default_options: {
    'optimization': '2'
  })


add_global_arguments(
  [
    '-fobjc-arc',
    '-fobjc-arc-exceptions'
  ],
  language: 'objc')


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
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*/)
{
	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







|
|







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, 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
#include <vector>

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


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

void
enqueueInit(void (^init)(void))
{

	if (queue == NULL)
		queue = new std::vector<void (^)(void)>();

	queue->push_back(init);
}

void
processInitQueue(void)
{
	for (auto &init : *queue)
		init();

	queue->clear();

}
<
<

<

>
|




>

|

|





|
|

|
>



1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24


#import "cube.h"


static void **queue;
static size_t queueCount;

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

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

void
processInitQueue(void)
{
	for (size_t i = 0; i < queueCount; i++)
		((__bridge void (^)())queue[i])();

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







|





|
|
|
|
|
|

|





|
|
|
|
|







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.m',
    'menus.m',
    'monster.m',
    'physics.m',
    'rendercubes.m',
    'renderextras.m',
    'rendergl.m',
    'rendermd2.m',
    'renderparticles.m',
    'rendertext.m',
    'rndmap.m',
    'savegamedemo.m',
    'server.m',
    'serverbrowser.m',
    'serverms.m',
    'serverutil.m',
    'sound.m',
    'tools.m',
    'weapon.m',
    '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
		curtex++;
		return tnum;
	} else {
		return mapping[tex][frame] = FIRSTTEX; // temp fix
	}
}

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

	if (hasoverbright) {







|
|







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
	}
}

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
static OFMutableData *strips;

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

	const strip *items = (const strip *)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;
	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);







|











|







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 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 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
		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)];


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

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








|
>

|







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(struct strip)];

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

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







|







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

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








|







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)) {
		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
// 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;
};
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;
		parempty = p->next;
		p->o = *o;
		p->d = *d;
		p->fade = fade;
		p->type = type;
		p->millis = lastmillis;
		p->next = parlist;












|

|
















|







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;
	struct particle *next;
};
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) {
		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
		{ 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];

		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?







|
|







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 (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
		    amplitude;
		seed += seedstep;
	}
	return total;
}

void
perlinarea(const 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);
			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);







|







|







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 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++) {
			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
static gzFile f = NULL;
bool demorecording = false;
bool demoplayback = false;
bool demoloading = false;
static OFMutableArray<DynamicEntity *> *playerhistory;
int democlientnum = 0;

void startdemo();

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

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

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

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

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

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

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

void
stop()
{
	if (f) {
		if (demorecording)







|

|





|





|
|

|


|






|






|







|
|

|







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;

extern void startdemo();

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

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

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

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

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

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

static void
gzgetv(OFVector3D *v)
{
	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
		gzput(player1.armourtype);
		loopi(NUMGUNS) gzput(player1.ammo[i]);
		gzput(player1.state);
		gzputi(bdamage);
		bdamage = 0;
		gzputi(ddamage);
		if (ddamage) {
			gzputv(dorig);
			ddamage = 0;
		}
		// FIXME: add all other client state which is not send through
		// the network
	}
}








|







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);
			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
			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);
				particle_splash(3, ddamage, 1000, &dorig);
			}
			// FIXME: set more client state here
		}

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







|







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);
				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
				si.sdesc = @(text);
				break;
			}
		}
	}
}

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







|







198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
				si.sdesc = @(text);
				break;
			}
		}
	}
}

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
// 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;
int sfactor, ssize, cubicsize, mipsize;

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);
		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 };
	if (maxx)
		remip(&b, 0); // remip minimal area of changed geometry
}

void
resettagareas()
{









|


|









|



















|







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

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

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)
	{
		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;
		}
	}
	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
// 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)
{
	if (level >= SMALLEST_FACTOR)
		return;

	int lighterr = getvar(@"lighterror") * 3;
	sqr *w = wmip[level];
	sqr *v = wmip[level + 1];
	int ws = ssize >> level;
	int vs = ssize >> (level + 1);
	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];
			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);
			*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;







|





|
|


|












|





|







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 struct block *b, int level)
{
	if (level >= SMALLEST_FACTOR)
		return;

	int lighterr = getvar(@"lighterror") * 3;
	struct sqr *w = wmip[level];
	struct sqr *v = wmip[level + 1];
	int ws = ssize >> level;
	int vs = ssize >> (level + 1);
	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) {
			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
			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
	s.y /= 2;
	s.xs /= 2;
	s.ys /= 2;
	remip(&s, level + 1);
}

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

	if (bb.x > 1)
		bb.x--;
	if (bb.y > 1)
		bb.y--;
	if (bb.xs < ssize - 3)
		bb.xs++;







|

|







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 struct block *b, int level)
{
	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
	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];

void
setupworld(int factor)
{
	ssize = 1 << (sfactor = factor);
	cubicsize = ssize * ssize;
	mipsize = cubicsize * 134 / 100;

	sqr *w = world = (sqr *)OFAllocZeroedMemory(mipsize, sizeof(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;
	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);
		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.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 };
		edittypexy(SPACE, &b);
	}

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







|







>
|
















|













|













|




















|







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

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 =
	    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);
	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)
	{
		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(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];
		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
// 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)
{
	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);
		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)
{
	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;
	if (SOLID(s)) {
		loopi(4) if (!SOLID(o[i]))
		{
			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;
			}
			if (o[i]->ceil > s->ceil) {
				ut = s->utex;
				uf = false;
			}
		}
	}
}

void
toptimize() // FIXME: only does 2x2, make atleast for 4x4 also
{
	bool wf[4], uf[4];
	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);
			loopi(4)
			{
				if (wf[i])
					s[i]->wtex = wt;
				if (uf[i])
					s[i]->utex = ut;
			}







|









|









|
|

|




|
|



|
|
|






|
|


|
|









|




|
|
|
|
|
|
|







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(struct sqr *s)
{
	return s->type != FHF && s->type != CHF;
}

void
voptimize() // reset vdeltas on non-hf cubes
{
	loop(x, ssize) loop(y, ssize)
	{
		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;
	}
}

static void
topt(struct sqr *s, bool *wf, bool *uf, int *wt, int *ut)
{
	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;
	if (SOLID(s)) {
		loopi(4) if (!SOLID(o[i]))
		{
			*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;
			}
			if (o[i]->ceil > s->ceil) {
				*ut = s->utex;
				*uf = false;
			}
		}
	}
}

void
toptimize() // FIXME: only does 2x2, make atleast for 4x4 also
{
	bool wf[4], uf[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);
			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
		return;
	}
	hdr.version = MAPVERSION;
	hdr.numents = 0;
	for (Entity *e in ents)
		if (e.type != NOTUSED)
			hdr.numents++;
	header tmp = hdr;
	endianswap(&tmp.version, sizeof(int), 4);
	endianswap(&tmp.waterlevel, sizeof(int), 16);
	gzwrite(f, &tmp, sizeof(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));
		}
	}
	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];
#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)








|


|





|


|














|







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++;
	struct header tmp = hdr;
	endianswap(&tmp.version, sizeof(int), 4);
	endianswap(&tmp.waterlevel, sizeof(int), 16);
	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(struct persistent_entity));
		}
	}
	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)
	{
		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
	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);
	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));
		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;







|

















|







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(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(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
				e.attr1 = 32; // 12_03 and below
		}
	}
	free(world);
	setupworld(hdr.sfactor);
	char texuse[256];
	loopi(256) texuse[i] = 0;
	sqr *t = NULL;
	loopk(cubicsize)
	{
		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));
			k--;
			break;
		}
		case 254: // only in MAPVERSION<=2
		{
			memcpy(s, t, sizeof(sqr));
			s->r = s->g = s->b = gzgetc(f);
			gzgetc(f);
			break;
		}
		case SOLID: {
			s->type = SOLID;
			s->wtex = gzgetc(f);







|


|





|





|







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;
	struct sqr *t = NULL;
	loopk(cubicsize)
	{
		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(struct sqr));
			k--;
			break;
		}
		case 254: // only in MAPVERSION<=2
		{
			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
		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);
	conoutf(@"read map %@ (%d milliseconds)", cgzname,
	    SDL_GetTicks() - lastmillis);
	conoutf(@"%s", hdr.maptitle);
	startmap(mname);
	loopl(256)
	{
		// can this be done smarter?







|







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[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
			int stepb = fast_f2nat(b / (float)steps);
			g /= lightscale;
			stepg /= lightscale;
			b /= lightscale;
			stepb /= lightscale;
			loopi(steps)
			{
				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))







|







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)
			{
				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
			y += stepy * dimness;

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

			loopi(steps)
			{
				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);
			int light = l >> PRECBITS;
			if (light > s->r)
				s->r = s->g = s->b = (uchar)light;
			if (SOLID(s))
				return;
			x += stepx;
			y += stepy;







|















|







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)
			{
				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)
		{
			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
		lightray((float)sx, sy2, l);
		lightray((float)ex, sy2, l);
	}

	rndtime();
}


void
postlightarea(block &a) // median filter, smooths out random noise in light and
                        // makes it more mipable
{
	loop(x, a.xs) loop(y, a.ys) // assumes area not on edge of world
	{
		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);
}

void
calclight()
{
	loop(x, ssize) loop(y, ssize)
	{
		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);
	setvar(@"fullbright", 0);
}

VARP(dynlight, 0, 16, 32);

static OFMutableData *dlights;

void
cleardlights()
{
	while (dlights.count > 0) {
		block *backup = *(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 };

	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 *)];

	// backup area before rendering in dynlight
	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);
}

// utility functions also used by editing code

block *
blockcopy(const block *s)
{
	block *b = (block *)OFAllocZeroedMemory(
	    1, sizeof(block) + s->xs * s->ys * sizeof(sqr));
	*b = *s;
	sqr *q = (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)
{
	sqr *q = (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);
}







>

|
<

|

|











|







|







|
|











|




















|
|











|
|


|










|




|
|

|
|

|







|

|





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(const struct block *a)

{
	loop(x, a->xs) loop(y, a->ys) // assumes area not on edge of world
	{
		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);
}

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

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

	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) {
		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!
	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(struct block *)];

	// backup area before rendering in dynlight
	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);
}

// utility functions also used by editing code

struct block *
blockcopy(const struct block *s)
{
	struct block *b = OFAllocZeroedMemory(
	    1, sizeof(struct block) + s->xs * s->ys * sizeof(struct sqr));
	*b = *s;
	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 struct block *b)
{
	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
// 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)
{
	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;









|
|







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(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
// 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];
	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;







|







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;
	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
// 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];
	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;







|







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)
{
	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
	// 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);           \
				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);

	LOOPH // ceils
	{
		int start = yy;
		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;
	}







|





|
|
|
|




|







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++) {              \
				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;
	}
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);
bool normalwall = true;

if (s->type == CORNER) {
	// cull also
	bool topleft = true;
	sqr *h1 = NULL;
	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,







|
|





|
|







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

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,
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)
{
	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(







|
|


|
|
|
|
|
|







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

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







|


|


|


<
|
>









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