-
Notifications
You must be signed in to change notification settings - Fork 104
/
util.c
584 lines (540 loc) · 23.1 KB
/
util.c
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
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
132
133
134
135
136
137
138
139
140
141
142
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
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
299
300
301
302
303
304
305
306
307
308
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
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
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
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
#include "util.h"
#include "finders.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
uint64_t *loadSavedSeeds(const char *fnam, uint64_t *scnt)
{
FILE *fp = fopen(fnam, "r");
uint64_t seed, i;
uint64_t *baseSeeds;
if (fp == NULL)
return NULL;
*scnt = 0;
while (!feof(fp))
{
if (fscanf(fp, "%" PRId64, (int64_t*)&seed) == 1) (*scnt)++;
else while (!feof(fp) && fgetc(fp) != '\n');
}
if (*scnt == 0)
return NULL;
baseSeeds = (uint64_t*) calloc(*scnt, sizeof(*baseSeeds));
rewind(fp);
for (i = 0; i < *scnt && !feof(fp);)
{
if (fscanf(fp, "%" PRId64, (int64_t*)&baseSeeds[i]) == 1) i++;
else while (!feof(fp) && fgetc(fp) != '\n');
}
fclose(fp);
return baseSeeds;
}
const char* mc2str(int mc)
{
switch (mc)
{
case MC_B1_7: return "Beta 1.7"; break;
case MC_B1_8: return "Beta 1.8"; break;
case MC_1_0: return "1.0"; break;
case MC_1_1: return "1.1"; break;
case MC_1_2: return "1.2"; break;
case MC_1_3: return "1.3"; break;
case MC_1_4: return "1.4"; break;
case MC_1_5: return "1.5"; break;
case MC_1_6: return "1.6"; break;
case MC_1_7: return "1.7"; break;
case MC_1_8: return "1.8"; break;
case MC_1_9: return "1.9"; break;
case MC_1_10: return "1.10"; break;
case MC_1_11: return "1.11"; break;
case MC_1_12: return "1.12"; break;
case MC_1_13: return "1.13"; break;
case MC_1_14: return "1.14"; break;
case MC_1_15: return "1.15"; break;
case MC_1_16_1: return "1.16.1"; break;
case MC_1_16: return "1.16"; break;
case MC_1_17: return "1.17"; break;
case MC_1_18: return "1.18"; break;
case MC_1_19_2: return "1.19.2"; break;
case MC_1_19: return "1.19"; break;
case MC_1_20: return "1.20"; break;
case MC_1_21_1: return "1.21.1"; break;
case MC_1_21_3: return "1.21.3"; break;
case MC_1_21_WD: return "1.21 WD"; break;
default: return "?";
}
}
int str2mc(const char *s)
{
if (!strcmp(s, "1.21")) return MC_1_21;
if (!strcmp(s, "1.21 WD")) return MC_1_21_WD;
if (!strcmp(s, "1.21.3")) return MC_1_21_3;
if (!strcmp(s, "1.21.2")) return MC_1_21_3; // backwards compatibility
if (!strcmp(s, "1.21.1")) return MC_1_21_1;
if (!strcmp(s, "1.20")) return MC_1_20;
if (!strcmp(s, "1.20.6")) return MC_1_20_6;
if (!strcmp(s, "1.19")) return MC_1_19;
if (!strcmp(s, "1.19.4")) return MC_1_19_4;
if (!strcmp(s, "1.19.2")) return MC_1_19_2;
if (!strcmp(s, "1.18")) return MC_1_18;
if (!strcmp(s, "1.18.2")) return MC_1_18_2;
if (!strcmp(s, "1.17")) return MC_1_17;
if (!strcmp(s, "1.17.1")) return MC_1_17_1;
if (!strcmp(s, "1.16")) return MC_1_16;
if (!strcmp(s, "1.16.5")) return MC_1_16_5;
if (!strcmp(s, "1.16.1")) return MC_1_16_1;
if (!strcmp(s, "1.15")) return MC_1_15;
if (!strcmp(s, "1.15.2")) return MC_1_15_2;
if (!strcmp(s, "1.14")) return MC_1_14;
if (!strcmp(s, "1.14.4")) return MC_1_14_4;
if (!strcmp(s, "1.13")) return MC_1_13;
if (!strcmp(s, "1.13.2")) return MC_1_13_2;
if (!strcmp(s, "1.12")) return MC_1_12;
if (!strcmp(s, "1.12.2")) return MC_1_12_2;
if (!strcmp(s, "1.11")) return MC_1_11;
if (!strcmp(s, "1.11.2")) return MC_1_11_2;
if (!strcmp(s, "1.10")) return MC_1_10;
if (!strcmp(s, "1.10.2")) return MC_1_10_2;
if (!strcmp(s, "1.9")) return MC_1_9;
if (!strcmp(s, "1.9.4")) return MC_1_9_4;
if (!strcmp(s, "1.8")) return MC_1_8;
if (!strcmp(s, "1.8.9")) return MC_1_8_9;
if (!strcmp(s, "1.7")) return MC_1_7;
if (!strcmp(s, "1.7.10")) return MC_1_7_10;
if (!strcmp(s, "1.6")) return MC_1_6;
if (!strcmp(s, "1.6.4")) return MC_1_6_4;
if (!strcmp(s, "1.5")) return MC_1_5;
if (!strcmp(s, "1.5.2")) return MC_1_5_2;
if (!strcmp(s, "1.4")) return MC_1_4;
if (!strcmp(s, "1.4.7")) return MC_1_4_7;
if (!strcmp(s, "1.3")) return MC_1_3;
if (!strcmp(s, "1.3.2")) return MC_1_3_2;
if (!strcmp(s, "1.2")) return MC_1_2;
if (!strcmp(s, "1.2.5")) return MC_1_2_5;
if (!strcmp(s, "1.1")) return MC_1_1;
if (!strcmp(s, "1.1.0")) return MC_1_1_0;
if (!strcmp(s, "1.0")) return MC_1_0;
if (!strcmp(s, "1.0.0")) return MC_1_0_0;
if (!strcmp(s, "Beta 1.8")) return MC_B1_8;
if (!strcmp(s, "Beta 1.7")) return MC_B1_7;
return MC_UNDEF;
}
const char *biome2str(int mc, int id)
{
if (mc >= MC_1_18)
{
// a bunch of 'new' biomes in 1.18 actually just got renamed
// (based on their features and biome id conversion when upgrading)
switch (id)
{
case old_growth_birch_forest: return "old_growth_birch_forest";
case old_growth_pine_taiga: return "old_growth_pine_taiga";
case old_growth_spruce_taiga: return "old_growth_spruce_taiga";
case snowy_plains: return "snowy_plains";
case sparse_jungle: return "sparse_jungle";
case stony_shore: return "stony_shore";
case windswept_hills: return "windswept_hills";
case windswept_forest: return "windswept_forest";
case windswept_gravelly_hills: return "windswept_gravelly_hills";
case windswept_savanna: return "windswept_savanna";
case wooded_badlands: return "wooded_badlands";
}
}
switch (id)
{
case ocean: return "ocean";
case plains: return "plains";
case desert: return "desert";
case mountains: return "mountains";
case forest: return "forest";
case taiga: return "taiga";
case swamp: return "swamp";
case river: return "river";
case nether_wastes: return "nether_wastes";
case the_end: return "the_end";
// 10
case frozen_ocean: return "frozen_ocean";
case frozen_river: return "frozen_river";
case snowy_tundra: return "snowy_tundra";
case snowy_mountains: return "snowy_mountains";
case mushroom_fields: return "mushroom_fields";
case mushroom_field_shore: return "mushroom_field_shore";
case beach: return "beach";
case desert_hills: return "desert_hills";
case wooded_hills: return "wooded_hills";
case taiga_hills: return "taiga_hills";
// 20
case mountain_edge: return "mountain_edge";
case jungle: return "jungle";
case jungle_hills: return "jungle_hills";
case jungle_edge: return "jungle_edge";
case deep_ocean: return "deep_ocean";
case stone_shore: return "stone_shore";
case snowy_beach: return "snowy_beach";
case birch_forest: return "birch_forest";
case birch_forest_hills: return "birch_forest_hills";
case dark_forest: return "dark_forest";
// 30
case snowy_taiga: return "snowy_taiga";
case snowy_taiga_hills: return "snowy_taiga_hills";
case giant_tree_taiga: return "giant_tree_taiga";
case giant_tree_taiga_hills: return "giant_tree_taiga_hills";
case wooded_mountains: return "wooded_mountains";
case savanna: return "savanna";
case savanna_plateau: return "savanna_plateau";
case badlands: return "badlands";
case wooded_badlands_plateau: return "wooded_badlands_plateau";
case badlands_plateau: return "badlands_plateau";
// 40 -- 1.13
case small_end_islands: return "small_end_islands";
case end_midlands: return "end_midlands";
case end_highlands: return "end_highlands";
case end_barrens: return "end_barrens";
case warm_ocean: return "warm_ocean";
case lukewarm_ocean: return "lukewarm_ocean";
case cold_ocean: return "cold_ocean";
case deep_warm_ocean: return "deep_warm_ocean";
case deep_lukewarm_ocean: return "deep_lukewarm_ocean";
case deep_cold_ocean: return "deep_cold_ocean";
// 50
case deep_frozen_ocean: return "deep_frozen_ocean";
// Alpha 1.2 - Beta 1.7
case seasonal_forest: return "seasonal_forest";
case shrubland: return "shrubland";
case rainforest: return "rainforest";
case the_void: return "the_void";
// mutated variants
case sunflower_plains: return "sunflower_plains";
case desert_lakes: return "desert_lakes";
case gravelly_mountains: return "gravelly_mountains";
case flower_forest: return "flower_forest";
case taiga_mountains: return "taiga_mountains";
case swamp_hills: return "swamp_hills";
case ice_spikes: return "ice_spikes";
case modified_jungle: return "modified_jungle";
case modified_jungle_edge: return "modified_jungle_edge";
case tall_birch_forest: return "tall_birch_forest";
case tall_birch_hills: return "tall_birch_hills";
case dark_forest_hills: return "dark_forest_hills";
case snowy_taiga_mountains: return "snowy_taiga_mountains";
case giant_spruce_taiga: return "giant_spruce_taiga";
case giant_spruce_taiga_hills: return "giant_spruce_taiga_hills";
case modified_gravelly_mountains: return "modified_gravelly_mountains";
case shattered_savanna: return "shattered_savanna";
case shattered_savanna_plateau: return "shattered_savanna_plateau";
case eroded_badlands: return "eroded_badlands";
case modified_wooded_badlands_plateau: return "modified_wooded_badlands_plateau";
case modified_badlands_plateau: return "modified_badlands_plateau";
// 1.14
case bamboo_jungle: return "bamboo_jungle";
case bamboo_jungle_hills: return "bamboo_jungle_hills";
// 1.16
case soul_sand_valley: return "soul_sand_valley";
case crimson_forest: return "crimson_forest";
case warped_forest: return "warped_forest";
case basalt_deltas: return "basalt_deltas";
// 1.17
case dripstone_caves: return "dripstone_caves";
case lush_caves: return "lush_caves";
// 1.18
case meadow: return "meadow";
case grove: return "grove";
case snowy_slopes: return "snowy_slopes";
case stony_peaks: return "stony_peaks";
case jagged_peaks: return "jagged_peaks";
case frozen_peaks: return "frozen_peaks";
// 1.19
case deep_dark: return "deep_dark";
case mangrove_swamp: return "mangrove_swamp";
// 1.20
case cherry_grove: return "cherry_grove";
// 1.21.4 (Winter Drop)
case pale_garden: return "pale_garden";
}
return NULL;
}
const char* struct2str(int stype)
{
switch (stype)
{
case Desert_Pyramid: return "desert_pyramid";
case Jungle_Temple: return "jungle_pyramid";
case Swamp_Hut: return "swamp_hut";
case Igloo: return "igloo";
case Village: return "village";
case Ocean_Ruin: return "ocean_ruin";
case Shipwreck: return "shipwreck";
case Monument: return "monument";
case Mansion: return "mansion";
case Outpost: return "pillager_outpost";
case Treasure: return "buried_treasure";
case Mineshaft: return "mineshaft";
case Desert_Well: return "desert_well";
case Ruined_Portal: return "ruined_portal";
case Ruined_Portal_N: return "ruined_portal_nether";
case Geode: return "amethyst_geode";
case Ancient_City: return "ancient_city";
case Trail_Ruins: return "trail_ruins";
case Trial_Chambers: return "trial_chambers";
case Fortress: return "fortress";
case Bastion: return "bastion_remnant";
case End_City: return "end_city";
case End_Gateway: return "end_gateway";
}
return NULL;
}
static void setColor(unsigned char colors[256][3], int id, uint32_t hex)
{
colors[id][0] = (hex >> 16) & 0xff;
colors[id][1] = (hex >> 8) & 0xff;
colors[id][2] = (hex >> 0) & 0xff;
}
void initBiomeColors(unsigned char colors[256][3])
{
// This coloring scheme is largely inspired by the AMIDST program:
// https://github.com/toolbox4minecraft/amidst/wiki/Biome-Color-Table
// but with additional biomes for 1.18+, and with some subtle changes to
// improve contrast for the new world generation.
memset(colors, 0, 256*3);
// biome hex color AMIDST
setColor(colors, ocean, 0x000070);
setColor(colors, plains, 0x8db360);
setColor(colors, desert, 0xfa9418);
setColor(colors, windswept_hills, 0x606060);
setColor(colors, forest, 0x056621);
setColor(colors, taiga, 0x0b6a5f); // 0b6659
setColor(colors, swamp, 0x07f9b2);
setColor(colors, river, 0x0000ff);
setColor(colors, nether_wastes, 0x572526); // bf3b3b
setColor(colors, the_end, 0x8080ff);
setColor(colors, frozen_ocean, 0x7070d6);
setColor(colors, frozen_river, 0xa0a0ff);
setColor(colors, snowy_plains, 0xffffff);
setColor(colors, snowy_mountains, 0xa0a0a0);
setColor(colors, mushroom_fields, 0xff00ff);
setColor(colors, mushroom_field_shore, 0xa000ff);
setColor(colors, beach, 0xfade55);
setColor(colors, desert_hills, 0xd25f12);
setColor(colors, wooded_hills, 0x22551c);
setColor(colors, taiga_hills, 0x163933);
setColor(colors, mountain_edge, 0x72789a);
setColor(colors, jungle, 0x507b0a); // 537b09
setColor(colors, jungle_hills, 0x2c4205);
setColor(colors, sparse_jungle, 0x60930f); // 628b17
setColor(colors, deep_ocean, 0x000030);
setColor(colors, stony_shore, 0xa2a284);
setColor(colors, snowy_beach, 0xfaf0c0);
setColor(colors, birch_forest, 0x307444);
setColor(colors, birch_forest_hills, 0x1f5f32);
setColor(colors, dark_forest, 0x40511a);
setColor(colors, snowy_taiga, 0x31554a);
setColor(colors, snowy_taiga_hills, 0x243f36);
setColor(colors, old_growth_pine_taiga, 0x596651);
setColor(colors, giant_tree_taiga_hills, 0x454f3e);
setColor(colors, windswept_forest, 0x5b7352); // 507050
setColor(colors, savanna, 0xbdb25f);
setColor(colors, savanna_plateau, 0xa79d64);
setColor(colors, badlands, 0xd94515);
setColor(colors, wooded_badlands, 0xb09765);
setColor(colors, badlands_plateau, 0xca8c65);
setColor(colors, small_end_islands, 0x4b4bab); // 8080ff
setColor(colors, end_midlands, 0xc9c959); // 8080ff
setColor(colors, end_highlands, 0xb5b536); // 8080ff
setColor(colors, end_barrens, 0x7070cc); // 8080ff
setColor(colors, warm_ocean, 0x0000ac);
setColor(colors, lukewarm_ocean, 0x000090);
setColor(colors, cold_ocean, 0x202070);
setColor(colors, deep_warm_ocean, 0x000050);
setColor(colors, deep_lukewarm_ocean, 0x000040);
setColor(colors, deep_cold_ocean, 0x202038);
setColor(colors, deep_frozen_ocean, 0x404090);
setColor(colors, seasonal_forest, 0x2f560f); // -
setColor(colors, rainforest, 0x47840e); // -
setColor(colors, shrubland, 0x789e31); // -
setColor(colors, the_void, 0x000000);
setColor(colors, sunflower_plains, 0xb5db88);
setColor(colors, desert_lakes, 0xffbc40);
setColor(colors, windswept_gravelly_hills, 0x888888);
setColor(colors, flower_forest, 0x2d8e49);
setColor(colors, taiga_mountains, 0x339287); // 338e81
setColor(colors, swamp_hills, 0x2fffda);
setColor(colors, ice_spikes, 0xb4dcdc);
setColor(colors, modified_jungle, 0x78a332); // 7ba331
setColor(colors, modified_jungle_edge, 0x88bb37); // 8ab33f
setColor(colors, old_growth_birch_forest, 0x589c6c);
setColor(colors, tall_birch_hills, 0x47875a);
setColor(colors, dark_forest_hills, 0x687942);
setColor(colors, snowy_taiga_mountains, 0x597d72);
setColor(colors, old_growth_spruce_taiga, 0x818e79);
setColor(colors, giant_spruce_taiga_hills, 0x6d7766);
setColor(colors, modified_gravelly_mountains, 0x839b7a); // 789878
setColor(colors, windswept_savanna, 0xe5da87);
setColor(colors, shattered_savanna_plateau, 0xcfc58c);
setColor(colors, eroded_badlands, 0xff6d3d);
setColor(colors, modified_wooded_badlands_plateau, 0xd8bf8d);
setColor(colors, modified_badlands_plateau, 0xf2b48d);
setColor(colors, bamboo_jungle, 0x849500); // 768e14
setColor(colors, bamboo_jungle_hills, 0x5c6c04); // 3b470a
setColor(colors, soul_sand_valley, 0x4d3a2e); // 5e3830
setColor(colors, crimson_forest, 0x981a11); // dd0808
setColor(colors, warped_forest, 0x49907b);
setColor(colors, basalt_deltas, 0x645f63); // 403636
setColor(colors, dripstone_caves, 0x4e3012); // -
setColor(colors, lush_caves, 0x283c00); // -
setColor(colors, meadow, 0x60a445); // -
setColor(colors, grove, 0x47726c); // -
setColor(colors, snowy_slopes, 0xc4c4c4); // -
setColor(colors, jagged_peaks, 0xdcdcc8); // -
setColor(colors, frozen_peaks, 0xb0b3ce); // -
setColor(colors, stony_peaks, 0x7b8f74); // -
setColor(colors, deep_dark, 0x031f29); // -
setColor(colors, mangrove_swamp, 0x2ccc8e); // -
setColor(colors, cherry_grove, 0xff91c8); // -
setColor(colors, pale_garden, 0x696d95); // -
}
void initBiomeTypeColors(unsigned char colors[256][3])
{
memset(colors, 0, 256*3);
setColor(colors, Oceanic, 0x0000a0);
setColor(colors, Warm, 0xffc000);
setColor(colors, Lush, 0x00a000);
setColor(colors, Cold, 0x606060);
setColor(colors, Freezing, 0xffffff);
}
// find the longest biome name contained in 's'
static int _str2id(const char *s)
{
if (*s == 0)
return -1;
const char *f = NULL;
int ret = -1, id;
for (id = 0; id < 256; id++)
{
const char *p = biome2str(MC_NEWEST, id);
if (p && (!f || strlen(f) < strlen(p)))
if (strstr(s, p)) {f = p; ret = id;}
const char *t = biome2str(MC_1_17, id);
if (t && t != p && (!f || strlen(f) < strlen(t)))
if (strstr(s, t)) {f = t; ret = id;}
}
return ret;
}
int parseBiomeColors(unsigned char biomeColors[256][3], const char *buf)
{
const char *p = buf;
char bstr[64];
int id, col[4], n, ib, ic;
n = 0;
while (*p)
{
for (ib = ic = 0; *p && *p != '\n' && *p != ';'; p++)
{
if ((size_t)ib+1 < sizeof(bstr))
{
if ((*p >= 'a' && *p <= 'z') || *p == '_')
bstr[ib++] = *p;
else if (*p >= 'A' && *p <= 'Z')
bstr[ib++] = (*p - 'A') + 'a';
}
if (ic < 4 && (*p == '#' || (p[0] == '0' && p[1] == 'x')))
col[ic++] = strtol(p+1+(*p=='0'), (char**)&p, 16);
else if (ic < 4 && *p >= '0' && *p <= '9')
col[ic++] = strtol(p, (char**)&p, 10);
if (*p == '\n' || *p == ';')
break;
}
while (*p && *p != '\n') p++;
while (*p == '\n') p++;
bstr[ib] = 0;
id = _str2id(bstr);
if (id >= 0 && id < 256)
{
if (ic == 3)
{
biomeColors[id][0] = col[0] & 0xff;
biomeColors[id][1] = col[1] & 0xff;
biomeColors[id][2] = col[2] & 0xff;
n++;
}
else if (ic == 1)
{
biomeColors[id][0] = (col[0] >> 16) & 0xff;
biomeColors[id][1] = (col[0] >> 8) & 0xff;
biomeColors[id][2] = (col[0] >> 0) & 0xff;
n++;
}
}
else if (ic == 4)
{
id = col[0] & 0xff;
biomeColors[id][0] = col[1] & 0xff;
biomeColors[id][1] = col[2] & 0xff;
biomeColors[id][2] = col[3] & 0xff;
n++;
}
else if (ic == 2)
{
id = col[0] & 0xff;
biomeColors[id][0] = (col[1] >> 16) & 0xff;
biomeColors[id][1] = (col[1] >> 8) & 0xff;
biomeColors[id][2] = (col[1] >> 0) & 0xff;
n++;
}
}
return n;
}
int biomesToImage(unsigned char *pixels,
unsigned char biomeColors[256][3], const int *biomes,
const unsigned int sx, const unsigned int sy,
const unsigned int pixscale, const int flip)
{
unsigned int i, j;
int containsInvalidBiomes = 0;
for (j = 0; j < sy; j++)
{
for (i = 0; i < sx; i++)
{
int id = biomes[j*sx+i];
unsigned int r, g, b;
if (id < 0 || id >= 256)
{
// This may happen for some intermediate layers
containsInvalidBiomes = 1;
r = biomeColors[id&0x7f][0]-40; r = (r>0xff) ? 0x00 : r&0xff;
g = biomeColors[id&0x7f][1]-40; g = (g>0xff) ? 0x00 : g&0xff;
b = biomeColors[id&0x7f][2]-40; b = (b>0xff) ? 0x00 : b&0xff;
}
else
{
r = biomeColors[id][0];
g = biomeColors[id][1];
b = biomeColors[id][2];
}
unsigned int m, n;
for (m = 0; m < pixscale; m++) {
for (n = 0; n < pixscale; n++) {
int idx = pixscale * i + n;
if (flip)
idx += (sx * pixscale) * ((pixscale * j) + m);
else
idx += (sx * pixscale) * ((pixscale * (sy-1-j)) + m);
unsigned char *pix = pixels + 3*idx;
pix[0] = (unsigned char)r;
pix[1] = (unsigned char)g;
pix[2] = (unsigned char)b;
}
}
}
}
return containsInvalidBiomes;
}
int savePPM(const char *path, const unsigned char *pixels, const unsigned int sx, const unsigned int sy)
{
FILE *fp = fopen(path, "wb");
if (!fp)
return -1;
fprintf(fp, "P6\n%d %d\n255\n", sx, sy);
size_t pixelsLen = 3 * sx * sy;
size_t written = fwrite(pixels, sizeof pixels[0], pixelsLen, fp);
fclose(fp);
return written != pixelsLen;
}