Made compatible with g++ and clang compilers + better docu for getting started.

This commit is contained in:
Cubitect 2020-03-15 16:09:06 +01:00
parent 8fa78be25b
commit a9705edfb8
11 changed files with 287 additions and 296 deletions

148
README.md
View File

@ -4,20 +4,130 @@ Cubiomes is a standalone library, written in C, that mimics the Minecraft biome
It is intended as a powerful tool to devise very fast, custom seed finding applications and large scale map viewers.
### Audience
#### Audience
You should be familiar with the C programming language, also a basic understanding of the Minecraft biome generation process would be helpful.
A POSIX environment is required to compile the finders library and examples, but the core generator library may also work on other platforms.
You should be familiar with the C programming language, also a basic understanding of the Minecraft biome generation process would be helpful.
### Documentation
## Getting Started
This section is meant to give you a quick starting point if you want to use this library to find your own biome dependent features.
### Biome Generator
Let's create a simple program called `find_jedge.c` which tests seeds for a Junge Edge biome at a predefined location.
```
#include "finders.h"
#include <stdio.h>
int main()
{
// First initialize the global biome table 'int biomes[256]'. This sets up
// properties such as the category and temperature of each biome.
initBiomes();
// Allocate and initialize a stack of biome layers that reflects the biome
// generation of Minecraft 1.14
LayerStack g = setupGenerator(MC_1_14);
int64_t seed;
Pos pos = {0,0}; // block position to be checked
for (seed = 0; ; seed++)
{
// Go through the layers in the layer stack and initialize the seed
// dependent aspects of the generator.
applySeed(&g, seed);
// To get the biome at single block position we can use getBiomeAtPos().
int biomeID = getBiomeAtPos(g, pos);
if (biomeID == jungle_edge)
break;
}
printf("Seed %" PRId64 " has a Junge Edge biome at block position "
"(%d, %d).\n", seed, pos.x, pos.z);
// Clean up.
freeGenerator(g);
return 0;
}
```
You can compile this code either by directly adding a target to the makefile, or you can compile and link to a cubiomes archive:
```
$ cd cubiomes
$ make libcubiomes
```
To compile, and link the cubiomes library you can use one of
```
$ cc find_jedge.c libcubiomes.a -lm # static
$ cc find_jedge.c -L. -lcubiomes -lm # dynamic
```
Both options assume that your source code is saved as `find_jedge.c` in the cubiomes working directory. If your makefile is configured to use pthreads you also may need to add the `-lpthread` option to the compiler. Running the program should output:
```
$ ./a.out
Seed 615 has a Junge Edge biome at block position (0, 0).
```
We can also generate the biomes for a rectangular region using `getArea()` which also offers control over the entry layer, see the layer documentation for more information.
```
#include "generator.h"
#include "util.h"
int main()
{
unsigned char biomeColours[256][3];
// Initialize global biome table.
initBiomes();
// Initialize a colour map for biomes.
initBiomeColours(biomeColours);
// Allocate and initialize a stack of biome layers.
LayerStack g = setupGenerator(MC_1_14);
// Extract the desired layer.
Layer *layer = &g.layers[L_SHORE_16];
int64_t seed = 1661454332289;
int areaX = -60, areaZ = -60;
unsigned int areaWidth = 120, areaHeight = 120;
unsigned int scale = 4;
unsigned int imgWidth = areaWidth*scale, imgHeight = areaHeight*scale;
// Allocate a sufficient buffer for the biomes and for the image pixels.
int *biomes = allocCache(layer, areaWidth, areaHeight);
unsigned char *rgb = (unsigned char *) malloc(3*imgWidth*imgHeight);
// Apply the seed only for the required layers and generate the area.
setWorldSeed(layer, seed);
genArea(layer, biomes, areaX, areaZ, areaWidth, areaHeight);
// Map the biomes to a color buffer and save to an image.
biomesToImage(rgb, biomeColours, biomes, areaWidth, areaHeight, scale, 2);
savePPM("biomes_at_layer.ppm", rgb, imgWidth, imgHeight);
// Clean up.
freeGenerator(g);
free(biomes);
free(rgb);
return 0;
}
```
### Layer Documentation
There is a reference document for the generator layers which contains a summary for most generator layers and their function within the generation process.
### Examples
There are two example programs in this repository which can be compiled using the makefile provided.
There are two example programs in this repository which can be compiled using the makefile.
#### Finding Quad-Witch-Huts at a Specific Location
@ -125,20 +235,20 @@ If you are looking to get the "Adventuring Time" achievment you might consider o
| Seed | All biome radius |
|---------------|------------------|
| -880424771806 | 644 |
| 48382691805 | 633 |
| 480800992945 | 649 |
| 1065757415811 | 612 |
| 1509124018794 | 645 |
| 1550633690354 | 616 |
| 1571479851306 | 631 |
| 1925837979058 | 621 |
| 2082386353360 | 649 |
| 2087339213306 | 632 |
| 2810140768300 | 637 |
| 3053313529066 | 648 |
| 3457626356584 | 649 |
| 3548624619264 | 646 |
| -880424771806 | 644 |
| 48382691805 | 633 |
| 480800992945 | 649 |
| 1065757415811 | 612 |
| 1509124018794 | 645 |
| 1550633690354 | 616 |
| 1571479851306 | 631 |
| 1925837979058 | 621 |
| 2082386353360 | 649 |
| 2087339213306 | 632 |
| 2810140768300 | 637 |
| 3053313529066 | 648 |
| 3457626356584 | 649 |
| 3548624619264 | 646 |

View File

@ -61,8 +61,8 @@ int main(int argc, char *argv[])
" range search range (in blocks) [uint, default=1024]\n");
exit(1);
}
if (argc <= 1 || sscanf(argv[1], "%"PRId64, &seedStart) != 1) seedStart = 0;
if (argc <= 2 || sscanf(argv[2], "%"PRId64, &seedEnd) != 1) seedEnd = 100000000LL;
if (argc <= 1 || sscanf(argv[1], "%" PRId64, &seedStart) != 1) seedStart = 0;
if (argc <= 2 || sscanf(argv[2], "%" PRId64, &seedEnd) != 1) seedEnd = 100000000LL;
if (argc <= 3 || sscanf(argv[3], "%u", &threads) != 1) threads = 1;
if (argc <= 4 || sscanf(argv[4], "%u", &range) != 1) range = 1024;
@ -70,7 +70,7 @@ int main(int argc, char *argv[])
filter = setupBiomeFilter(BIOMES_L13_OCEAN_MIX_4,
sizeof(BIOMES_L13_OCEAN_MIX_4)/sizeof(int));
printf("Starting search through seeds %"PRId64 " to %"PRId64", using %u threads.\n"
printf("Starting search through seeds %" PRId64 " to %" PRId64", using %u threads.\n"
"Search radius = %u.\n", seedStart, seedEnd, threads, range);
thread_id_t threadID[threads];

View File

@ -28,14 +28,14 @@ int main(int argc, char *argv[])
const char *seedFileName;
StructureConfig featureConfig;
if(argc > 2)
if (argc > 2)
{
if(sscanf(argv[1], "%d", &regPosX) != 1) regPosX = 0;
if(sscanf(argv[2], "%d", &regPosZ) != 1) regPosZ = 0;
if (sscanf(argv[1], "%d", &regPosX) != 1) regPosX = 0;
if (sscanf(argv[2], "%d", &regPosZ) != 1) regPosZ = 0;
if(argc > 3)
if (argc > 3)
{
if(sscanf(argv[3], "%d", &mcversion) != 1) mcversion = 0;
if (sscanf(argv[3], "%d", &mcversion) != 1) mcversion = 0;
}
else
{
@ -55,7 +55,7 @@ int main(int argc, char *argv[])
regPosX -= 1;
regPosZ -= 1;
if(mcversion == 113)
if (mcversion >= 113)
{
featureConfig = SWAMP_HUT_CONFIG;
seedFileName = "./seeds/quadhutbases_1_13_Q1.txt";
@ -73,7 +73,7 @@ int main(int argc, char *argv[])
g = setupGenerator(MC_1_7);
}
if(access(seedFileName, F_OK))
if (access(seedFileName, F_OK))
{
printf("Seed base file does not exist: Creating new one.\n"
"This may take a few minutes...\n");
@ -95,7 +95,7 @@ int main(int argc, char *argv[])
// so we can test the biome at these positions.
Pos qhpos[4];
// Setup a dummy layer for Layer 19: Biome.
// Setup a dummy layer for Layer 19: Biome, to make preliminary seed tests.
Layer layerBiomeDummy;
setupLayer(256, &layerBiomeDummy, NULL, 200, NULL);
@ -105,7 +105,7 @@ int main(int argc, char *argv[])
// Search for a swamp at the structure positions
for(i = 0; i < qhcnt; i++)
for (i = 0; i < qhcnt; i++)
{
base = moveStructure(qhcandidates[i], regPosX, regPosZ);
@ -115,7 +115,7 @@ int main(int argc, char *argv[])
qhpos[3] = getStructurePos(featureConfig, base, 1+regPosX, 1+regPosZ);
/*
for(j = 0; j < 4; j++)
for (j = 0; j < 4; j++)
{
printf("(%d,%d) ", qhpos[j].x, qhpos[j].z);
}
@ -124,29 +124,31 @@ int main(int argc, char *argv[])
// This little magic code checks if there is a meaningful chance for
// this seed base to generate swamps in the area.
// The idea is that the conversion from Lush temperature to swamp is
// independent of surroundings, so we can test the conversion
// beforehand. Furthermore biomes tend to leak into the negative
// The idea is, that the conversion from Lush temperature to swamp is
// independent of surroundings, so we can test for this conversion
// beforehand. Furthermore, biomes tend to leak into the negative
// coordinates because of the Zoom layers, so the majority of hits will
// occur when SouthEast corner (at a 1:256 scale) of the quad-hut has a
// swamp. (This assumption misses about 1 in 500 quad-hut seeds.)
// Finally, here we also exploit that the minecraft random number
// generator is quite bad, such that for the "mcNextRand() mod 6" check
// it has a period pattern of ~3 on the high seed-bits.
for(j = 0; j < 5; j++)
// generator is quite bad, the "mcNextRand() mod 6" check has a period
// pattern of ~3 on the high seed-bits, which means we can avoid
// checking all 16 high-bit combinations.
for (j = 0; j < 5; j++)
{
seed = base + ((j+0x53) << 48);
setWorldSeed(&layerBiomeDummy, seed);
setChunkSeed(&layerBiomeDummy, areaX+1, areaZ+1);
if(mcNextInt(&layerBiomeDummy, 6) == 5)
if (mcNextInt(&layerBiomeDummy, 6) == 5)
break;
}
if(j >= 5) continue;
if (j >= 5)
continue;
int64_t hits = 0, swpc;
for(j = 0; j < 0x10000; j++)
for (j = 0; j < 0x10000; j++)
{
seed = base + (j << 48);
@ -156,13 +158,13 @@ int main(int argc, char *argv[])
setWorldSeed(&layerBiomeDummy, seed);
setChunkSeed(&layerBiomeDummy, areaX+1, areaZ+1);
if(mcNextInt(&layerBiomeDummy, 6) != 5)
if (mcNextInt(&layerBiomeDummy, 6) != 5)
continue;
// This seed base does not seem to contain many quad huts, so make
// a more detailed analysis of the surroundings and see if there is
// enough potential for more swamps to justify searching further.
if(hits == 0 && (j & 0xfff) == 0xfff)
if (hits == 0 && (j & 0xfff) == 0xfff)
{
swpc = 0;
setChunkSeed(&layerBiomeDummy, areaX, areaZ+1);
@ -172,23 +174,24 @@ int main(int argc, char *argv[])
setChunkSeed(&layerBiomeDummy, areaX, areaZ);
swpc += mcNextInt(&layerBiomeDummy, 6) == 5;
if(swpc < (j > 0x1000 ? 2 : 1)) break;
if (swpc < (j > 0x1000 ? 2 : 1))
break;
}
// Dismiss seeds that don't have a swamp near the quad temple.
setWorldSeed(lFilterBiome, seed);
genArea(lFilterBiome, biomeCache, (regPosX<<1)+2, (regPosZ<<1)+2, 1, 1);
if(biomeCache[0] != swamp)
if (biomeCache[0] != swamp)
continue;
applySeed(&g, seed);
if(getBiomeAtPos(g, qhpos[0]) != swamp) continue;
if(getBiomeAtPos(g, qhpos[1]) != swamp) continue;
if(getBiomeAtPos(g, qhpos[2]) != swamp) continue;
if(getBiomeAtPos(g, qhpos[3]) != swamp) continue;
if (getBiomeAtPos(g, qhpos[0]) != swamp) continue;
if (getBiomeAtPos(g, qhpos[1]) != swamp) continue;
if (getBiomeAtPos(g, qhpos[2]) != swamp) continue;
if (getBiomeAtPos(g, qhpos[3]) != swamp) continue;
printf("%"PRId64 "\n", seed);
printf("%" PRId64 "\n", seed);
hits++;
}
}

View File

@ -73,7 +73,7 @@ int64_t *loadSavedSeeds(const char *fnam, int64_t *scnt)
while (!feof(fp))
{
if (fscanf(fp, "%"PRId64, &seed) == 1) (*scnt)++;
if (fscanf(fp, "%" PRId64, &seed) == 1) (*scnt)++;
else while (!feof(fp) && fgetc(fp) != '\n');
}
@ -83,7 +83,7 @@ int64_t *loadSavedSeeds(const char *fnam, int64_t *scnt)
for (int64_t i = 0; i < *scnt && !feof(fp);)
{
if (fscanf(fp, "%"PRId64, &baseSeeds[i]) == 1) i++;
if (fscanf(fp, "%" PRId64, &baseSeeds[i]) == 1) i++;
else while (!feof(fp) && fgetc(fp) != '\n');
}
@ -563,14 +563,14 @@ static DWORD WINAPI search4QuadBasesThread(LPVOID data)
if (i < 32 && !fseek(fp, 1-i, SEEK_END) && fread(buf, i-1, 1, fp) > 0)
{
if (sscanf(buf, "%"PRId64, &seed) == 1)
if (sscanf(buf, "%" PRId64, &seed) == 1)
{
while (lowerBits[lowerBitsIdx] <= (seed & 0xffff))
lowerBitsIdx++;
seed = (seed & 0x0000ffffffff0000) + lowerBits[lowerBitsIdx];
printf("Thread %d starting from: %"PRId64"\n", info.threadID, seed);
printf("Thread %d starting from: %" PRId64"\n", info.threadID, seed);
}
else
{
@ -586,9 +586,9 @@ static DWORD WINAPI search4QuadBasesThread(LPVOID data)
{
if (isQuadBase(info.sconf, seed, info.quality))
{
fprintf(fp, "%"PRId64"\n", seed);
fprintf(fp, "%" PRId64"\n", seed);
fflush(fp);
//printf("Thread %d: %"PRId64"\n", info.threadID, seed);
//printf("Thread %d: %" PRId64"\n", info.threadID, seed);
}
lowerBitsIdx++;
@ -851,7 +851,6 @@ int isTreasureChunk(int64_t seed, const int chunkX, const int chunkZ)
}
//==============================================================================
// Checking Biomes & Biome Helper Functions
//==============================================================================
@ -1134,31 +1133,50 @@ static double getGrassProbability(int64_t seed, int biome, int x, int z)
// TODO: Try to determine the actual probabilities and build a statistic.
switch (biome)
{
case plains: return 1.0;
case mountains: return 0.8; // height dependent
case forest: return 1.0;
case taiga: return 1.0;
case swamp: return 0.6; // height dependent
case river: return 0.2;
case beach: return 0.1;
case wooded_hills: return 1.0;
case taiga_hills: return 1.0;
case mountain_edge: return 1.0; // height dependent
case jungle: return 1.0;
case jungle_hills: return 1.0;
case jungleEdge: return 1.0;
case birch_forest: return 1.0;
case birch_forest_hills: return 1.0;
case dark_forest: return 0.9;
case snowy_taiga: return 0.1; // below trees
case snowy_taiga_hills: return 0.1; // below trees
case giant_tree_taiga: return 0.6;
case giant_tree_taiga_hills: return 0.6;
case wooded_mountains: return 0.2; // height dependent
case savanna: return 1.0;
case savanna_plateau: return 1.0;
case wooded_badlands_plateau: return 0.1; // height dependent
case badlands_plateau: return 0.1; // height dependent
case plains: return 1.0;
case mountains: return 0.8; // height dependent
case forest: return 1.0;
case taiga: return 1.0;
case swamp: return 0.6; // height dependent
case river: return 0.5;
case beach: return 0.1;
case wooded_hills: return 1.0;
case taiga_hills: return 1.0;
case mountain_edge: return 1.0; // height dependent
case jungle: return 1.0;
case jungle_hills: return 1.0;
case jungle_edge: return 1.0;
case birch_forest: return 1.0;
case birch_forest_hills: return 1.0;
case dark_forest: return 0.9;
case snowy_taiga: return 0.2; // below trees
case snowy_taiga_hills: return 0.2; // below trees
case giant_tree_taiga: return 0.6;
case giant_tree_taiga_hills: return 0.6;
case wooded_mountains: return 0.2; // height dependent
case savanna: return 1.0;
case savanna_plateau: return 1.0;
case wooded_badlands_plateau: return 0.1; // height dependent
case badlands_plateau: return 0.1; // height dependent
case sunflower_plains: return 1.0;
case gravelly_mountains: return 0.2;
case flower_forest: return 1.0;
case taiga_mountains: return 1.0;
case swamp_hills: return 0.9;
case modified_jungle: return 1.0;
case modified_jungle_edge: return 1.0;
case tall_birch_forest: return 1.0;
case tall_birch_hills: return 1.0;
case dark_forest_hills: return 0.9;
case snowy_taiga_mountains: return 0.2;
case giant_spruce_taiga: return 0.6;
case giant_spruce_taiga_hills: return 0.6;
case modified_gravelly_mountains: return 0.2;
case shattered_savanna: return 1.0;
case shattered_savanna_plateau: return 1.0;
case bamboo_jungle: return 0.4;
case bamboo_jungle_hills: return 0.4;
// NOTE: in rare circumstances you can get also get grassy islands that are
// completely in ocean variants...
default: return 0;
@ -1750,7 +1768,7 @@ BiomeFilter setupBiomeFilter(const int *biomeList, int listLen)
if (isShallowOcean(id))
{
bf.oceansToFind |= (1ULL < id);
bf.oceansToFind |= (1ULL << id);
}
else
{

View File

@ -128,14 +128,10 @@ STRUCT(BiomeFilter)
int doScale4Check;
};
//==============================================================================
// Globals
//==============================================================================
extern Biome biomes[256];
#ifdef __cplusplus
extern "C"
{
#endif
/******************************** SEED FINDING *********************************
*
@ -569,5 +565,8 @@ int64_t checkForBiomes(
const BiomeFilter filter,
const int minscale);
#ifdef __cplusplus
}
#endif
#endif /* FINDERS_H_ */

View File

@ -6,7 +6,8 @@
/* Minecraft versions */
enum MCversion
{
MC_1_7, MC_1_8, MC_1_9, MC_1_10, MC_1_11, MC_1_12, MC_1_13, MC_1_14,
MC_1_7, MC_1_8, MC_1_9, MC_1_10, MC_1_11, MC_1_12, MC_1_13, MC_1_14,
MC_1_15, MC_1_16,
MCBE = 256
};
@ -188,6 +189,11 @@ STRUCT(LayerStack)
int layerCnt;
};
#ifdef __cplusplus
extern "C"
{
#endif
/* Initialise an instance of a generator. */
LayerStack setupGenerator(const int mcversion);
@ -223,5 +229,9 @@ void applySeed(LayerStack *g, int64_t seed);
void genArea(Layer *layer, int *out, int areaX, int areaZ, int areaWidth, int areaHeight);
#ifdef __cplusplus
}
#endif
#endif /* GENERATOR_H_ */

View File

@ -183,6 +183,7 @@ void mapIsland(Layer *l, int * __restrict out, int areaX, int areaZ, int areaWid
}
}
// FIXME: currently SIMD only works properly for certain sizes
#if defined USE_SIMD && defined __AVX2__
void mapZoom(Layer *l, int* __restrict out, int areaX, int areaZ, int areaWidth, int areaHeight)
@ -200,7 +201,7 @@ void mapZoom(Layer *l, int* __restrict out, int areaX, int areaZ, int areaWidth,
int pX = areaX&0xFFFFFFFE;
__m256i xs = _mm256_set_epi32(pX+14, pX+12, pX+10, pX+8, pX+6, pX+4, pX+2, pX), zs;
__m256i v2 = _mm256_set1_epi32(2), v16 = _mm256_set1_epi32(16);
int* buf = malloc((newWidth+1)*((areaHeight+2)|1)*sizeof(*buf));
int* buf = (int*) malloc((newWidth+1)*((areaHeight+2)|1)*sizeof(*buf));
int* idx = buf;
int* outIdx = out;
//z first!
@ -262,7 +263,7 @@ void mapZoom(Layer *l, int* __restrict out, int areaX, int areaZ, int areaWidth,
int pX = areaX&0xFFFFFFFE;
__m128i xs = _mm_set_epi32(pX+6, pX+4, pX+2, pX), zs;
__m128i v2 = _mm_set1_epi32(2), v8 = _mm_set1_epi32(8);
int* buf = malloc((newWidth+1)*(areaHeight+2|1)*sizeof(*buf));
int* buf = (int*) malloc((newWidth+1)*(areaHeight+2|1)*sizeof(*buf));
int* idx = buf;
int* outIdx = out;
//z first!
@ -314,27 +315,28 @@ void mapZoom(Layer *l, int * __restrict out, int areaX, int areaZ, int areaWidth
{
int pX = areaX >> 1;
int pZ = areaZ >> 1;
int pWidth = (areaWidth >> 1) + 2;
int pHeight = (areaHeight >> 1) + 2;
int pWidth = ((areaX + areaWidth ) >> 1) - pX + 1;
int pHeight = ((areaZ + areaHeight) >> 1) - pZ + 1;
int x, z;
//printf("[%d %d] [%d %d]\n", pX, pZ, pWidth, pHeight);
l->p->getMap(l->p, out, pX, pZ, pWidth, pHeight);
int newWidth = (pWidth-1) << 1;
int newHeight = (pHeight-1) << 1;
int newWidth = (pWidth) << 1;
int newHeight = (pHeight) << 1;
int idx, a, b;
int *buf = (int *)malloc((newWidth+1)*(newHeight+1)*sizeof(*buf));
const int ws = (int)l->worldSeed;
const int ss = ws * (ws * 1284865837 + 4150755663);
for (z = 0; z < pHeight - 1; z++)
for (z = 0; z < pHeight; z++)
{
idx = (z << 1) * newWidth;
a = out[(z+0)*pWidth];
b = out[(z+1)*pWidth];
for (x = 0; x < pWidth - 1; x++)
for (x = 0; x < pWidth; x++)
{
int a1 = out[x+1 + (z+0)*pWidth];
int b1 = out[x+1 + (z+1)*pWidth];

View File

@ -3,6 +3,8 @@
#include "javarnd.h"
#define __STDC_FORMAT_MACROS 1
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
@ -11,15 +13,21 @@
#define NULL ((void*)0)
#endif
#define SIMD_NOTIFY 0
#if defined USE_SIMD && __AVX2__
#include <emmintrin.h>
#include <smmintrin.h>
#include <immintrin.h>
#if SIMD_NOTIFY
#warning "Using AVX2 extensions."
#endif
#elif defined USE_SIMD && defined __SSE4_2__
#include <emmintrin.h>
#include <smmintrin.h>
#if SIMD_NOTIFY
#warning "Using SSE4.2 extensions."
#endif
#else
//#warning "Using no SIMD extensions."
#endif
@ -164,6 +172,10 @@ STRUCT(Layer)
Layer *p, *p2; // parent layers
};
#ifdef __cplusplus
extern "C"
{
#endif
//==============================================================================
// Essentials
@ -352,10 +364,10 @@ static inline __m256i set8ChunkSeeds(int ws, __m256i xs, __m256i zs)
static inline __m256i mc8NextInt(__m256i* cs, int ws, int mask)
{
__m256i and = _mm256_set1_epi32(mask);
__m256i ret = _mm256_and_si256(and, _mm256_srli_epi32(*cs, 24));
__m256i andm = _mm256_set1_epi32(mask);
__m256i ret = _mm256_and_si256(andm, _mm256_srli_epi32(*cs, 24));
*cs = _mm256_add_epi32(_mm256_set1_epi32(ws), _mm256_mullo_epi32(*cs, _mm256_add_epi32(_mm256_set1_epi32(4150755663), _mm256_mullo_epi32(*cs, _mm256_set1_epi32(1284865837)))));
return _mm256_add_epi32(ret, _mm256_and_si256(and, _mm256_cmpgt_epi32(_mm256_set1_epi32(0), ret)));;
return _mm256_add_epi32(ret, _mm256_and_si256(andm, _mm256_cmpgt_epi32(_mm256_set1_epi32(0), ret)));
}
static inline __m256i select8Random2(__m256i* cs, int ws, __m256i a1, __m256i a2)
@ -431,10 +443,10 @@ static inline __m128i set4ChunkSeeds(int ws, __m128i xs, __m128i zs)
static inline __m128i mc4NextInt(__m128i* cs, int ws, int mask)
{
__m128i and = _mm_set1_epi32(mask);
__m128i ret = _mm_and_si128(and, _mm_srli_epi32(*cs, 24));
__m128i andm = _mm_set1_epi32(mask);
__m128i ret = _mm_and_si128(andm, _mm_srli_epi32(*cs, 24));
*cs = _mm_add_epi32( _mm_set1_epi32(ws), _mm_mullo_epi32(*cs, _mm_add_epi32(_mm_set1_epi32(4150755663), _mm_mullo_epi32(*cs, _mm_set1_epi32(1284865837)))));
return _mm_add_epi32(ret, _mm_and_si128(and, _mm_cmplt_epi32(ret, _mm_set1_epi32(0))));;
return _mm_add_epi32(ret, _mm_and_si128(andm, _mm_cmplt_epi32(ret, _mm_set1_epi32(0))));
}
static inline __m128i select4Random2(__m128i* cs, int ws, __m128i a1, __m128i a2)
@ -568,4 +580,9 @@ void mapOceanMix(Layer *l, int * __restrict out, int areaX, int areaZ, int areaW
void mapVoronoiZoom(Layer *l, int * __restrict out, int x, int z, int w, int h);
#ifdef __cplusplus
}
#endif
#endif /* LAYER_H_ */

View File

@ -1,21 +1,30 @@
CC = gcc
AR = ar
ARFLAGS = cr
override LDFLAGS = -lm
override CFLAGS += -Wall -fwrapv -march=native
#override CFLAGS += -DUSE_SIMD
ifeq ($(OS),Windows_NT)
override CFLAGS += -D_WIN32
RM = del
else
override LDFLAGS += -lX11 -pthread
#RM = rm
endif
.PHONY : all debug clean
.PHONY : all debug libcubiomes clean
all: CFLAGS += -O3
all: CFLAGS += -O3 -march=native
all: find_quadhuts find_compactbiomes clean
debug: CFLAGS += -DDEBUG -O0 -g
debug: CFLAGS += -DDEBUG -O0 -ggdb3
debug: find_quadhuts find_compactbiomes clean
libcubiomes: CFLAGS += -O3 -fPIC
libcubiomes: layers.o generator.o finders.o util.o
$(AR) $(ARFLAGS) libcubiomes.a $^
find_compactbiomes: find_compactbiomes.o layers.o generator.o finders.o
$(CC) -o $@ $^ $(LDFLAGS)
@ -41,7 +50,9 @@ generator.o: generator.c generator.h
layers.o: layers.c layers.h
$(CC) -c $(CFLAGS) $<
util.o: util.c util.h
$(CC) -c $(CFLAGS) $<
clean:
rm *.o
$(RM) *.o

View File

@ -1,133 +1,10 @@
#include "xmapview.h"
#include "util.h"
#include <string.h>
#include <stdio.h>
/* Global biome colour table. */
void setBiomeColour(unsigned char biomeColour[256][3], int biome,
unsigned char r, unsigned char g, unsigned char b)
{
biomeColour[biome][0] = r;
biomeColour[biome][1] = g;
biomeColour[biome][2] = b;
}
void initBiomeColours(unsigned char biomeColours[256][3])
{
// This colouring scheme is taken from the AMIDST program:
// https://github.com/toolbox4minecraft/amidst
// https://sourceforge.net/projects/amidst.mirror/
memset(biomeColours, 0, 256*3);
setBiomeColour(biomeColours, ocean, 0, 0, 112);
setBiomeColour(biomeColours, plains,141, 179, 96);
setBiomeColour(biomeColours, desert, 250, 148, 24);
setBiomeColour(biomeColours, mountains, 96, 96, 96);
setBiomeColour(biomeColours, forest, 5, 102, 33);
setBiomeColour(biomeColours, taiga, 11, 102, 89);
setBiomeColour(biomeColours, swamp, 7, 249, 178);
setBiomeColour(biomeColours, river, 0, 0, 255);
setBiomeColour(biomeColours, hell, 255, 0, 0);
setBiomeColour(biomeColours, sky, 128, 128, 255);
setBiomeColour(biomeColours, frozen_ocean, 112, 112, 214);
setBiomeColour(biomeColours, frozen_river, 160, 160, 255);
setBiomeColour(biomeColours, snowy_tundra, 255, 255, 255);
setBiomeColour(biomeColours, snowy_mountains, 160, 160, 160);
setBiomeColour(biomeColours, mushroom_fields, 255, 0, 255);
setBiomeColour(biomeColours, mushroom_field_shore, 160, 0, 255);
setBiomeColour(biomeColours, beach, 250, 222, 85);
setBiomeColour(biomeColours, desert_hills, 210, 95, 18);
setBiomeColour(biomeColours, wooded_hills, 34, 85, 28);
setBiomeColour(biomeColours, taiga_hills, 22, 57, 51);
setBiomeColour(biomeColours, mountain_edge, 114, 120, 154);
setBiomeColour(biomeColours, jungle, 83, 123, 9);
setBiomeColour(biomeColours, jungle_hills, 44, 66, 5);
setBiomeColour(biomeColours, jungleEdge, 98, 139, 23);
setBiomeColour(biomeColours, deep_ocean, 0, 0, 48);
setBiomeColour(biomeColours, stone_shore, 162, 162, 132);
setBiomeColour(biomeColours, snowy_beach, 250, 240, 192);
setBiomeColour(biomeColours, birch_forest, 48, 116, 68);
setBiomeColour(biomeColours, birch_forest_hills, 31, 95, 50);
setBiomeColour(biomeColours, dark_forest, 64, 81, 26);
setBiomeColour(biomeColours, snowy_taiga, 49, 85, 74);
setBiomeColour(biomeColours, snowy_taiga_hills, 36, 63, 54);
setBiomeColour(biomeColours, giant_tree_taiga, 89, 102, 81);
setBiomeColour(biomeColours, giant_tree_taiga_hills, 69, 79, 62);
setBiomeColour(biomeColours, wooded_mountains, 80, 112, 80);
setBiomeColour(biomeColours, savanna, 189, 178, 95);
setBiomeColour(biomeColours, savanna_plateau, 167, 157, 100);
setBiomeColour(biomeColours, badlands, 217, 69, 21);
setBiomeColour(biomeColours, wooded_badlands_plateau, 176, 151, 101);
setBiomeColour(biomeColours, badlands_plateau, 202, 140, 101);
setBiomeColour(biomeColours, warm_ocean, 0, 0, 172);
setBiomeColour(biomeColours, lukewarm_ocean, 0, 0, 144);
setBiomeColour(biomeColours, cold_ocean, 32, 32, 112);
setBiomeColour(biomeColours, deep_warm_ocean, 0, 0, 80);
setBiomeColour(biomeColours, deep_lukewarm_ocean, 0, 0, 64);
setBiomeColour(biomeColours, deep_cold_ocean, 32, 32, 56);
setBiomeColour(biomeColours, deep_frozen_ocean, 64, 64, 144);
setBiomeColour(biomeColours, ocean+128, 0, 0, 112);
setBiomeColour(biomeColours, plains+128, 141, 179, 96);
setBiomeColour(biomeColours, desert+128, 250, 148, 24);
setBiomeColour(biomeColours, mountains+128, 96, 96, 96);
setBiomeColour(biomeColours, forest+128, 5, 102, 33);
setBiomeColour(biomeColours, taiga+128, 11, 102, 89);
setBiomeColour(biomeColours, swamp+128, 7, 249, 178);
setBiomeColour(biomeColours, river+128, 0, 0, 255);
setBiomeColour(biomeColours, hell+128, 255, 0, 0);
setBiomeColour(biomeColours, sky+128, 128, 128, 255);
setBiomeColour(biomeColours, frozen_ocean+128, 144, 144, 160);
setBiomeColour(biomeColours, frozen_river+128, 160, 160, 255);
setBiomeColour(biomeColours, snowy_tundra+128, 140, 180, 180);
setBiomeColour(biomeColours, snowy_mountains+128, 160, 160, 160);
setBiomeColour(biomeColours, mushroom_fields+128, 255, 0, 255);
setBiomeColour(biomeColours, mushroom_field_shore+128, 160, 0, 255);
setBiomeColour(biomeColours, beach+128, 250, 222, 85);
setBiomeColour(biomeColours, desert_hills+128, 210, 95, 18);
setBiomeColour(biomeColours, wooded_hills+128, 34, 85, 28);
setBiomeColour(biomeColours, taiga_hills+128, 22, 57, 51);
setBiomeColour(biomeColours, mountain_edge+128, 114, 120, 154);
setBiomeColour(biomeColours, jungle+128, 83, 123, 9);
setBiomeColour(biomeColours, jungle_hills+128, 44, 66, 5);
setBiomeColour(biomeColours, jungleEdge+128, 98, 139, 23);
setBiomeColour(biomeColours, deep_ocean+128, 0, 0, 48);
setBiomeColour(biomeColours, stone_shore+128, 162, 162, 132);
setBiomeColour(biomeColours, snowy_beach+128, 250, 240, 192);
setBiomeColour(biomeColours, birch_forest+128, 48, 116, 68);
setBiomeColour(biomeColours, birch_forest_hills+128, 31, 95, 50);
setBiomeColour(biomeColours, dark_forest+128, 64, 81, 26);
setBiomeColour(biomeColours, snowy_taiga+128, 49, 85, 74);
setBiomeColour(biomeColours, snowy_taiga_hills+128, 36, 63, 54);
setBiomeColour(biomeColours, giant_tree_taiga+128, 89, 102, 81);
setBiomeColour(biomeColours, giant_tree_taiga_hills+128, 69, 79, 62);
setBiomeColour(biomeColours, wooded_mountains+128, 80, 112, 80);
setBiomeColour(biomeColours, savanna+128, 189, 178, 95);
setBiomeColour(biomeColours, savanna_plateau+128, 167, 157, 100);
setBiomeColour(biomeColours, badlands+128, 217, 69, 21);
setBiomeColour(biomeColours, wooded_badlands_plateau+128, 176, 151, 101);
setBiomeColour(biomeColours, badlands_plateau+128, 202, 140, 101);
setBiomeColour(biomeColours, bamboo_jungle, 118, 142, 20);
setBiomeColour(biomeColours, bamboo_jungle_hills, 59, 71, 10);
}
void initBiomeTypeColours(unsigned char biomeColours[256][3])
{
memset(biomeColours, 0, 256*3);
setBiomeColour(biomeColours, Oceanic, 0x00, 0x00, 0xa0);
setBiomeColour(biomeColours, Warm, 0xff, 0xc0, 0x00);
setBiomeColour(biomeColours, Lush, 0x00, 0xa0, 0x00);
setBiomeColour(biomeColours, Cold, 0x60, 0x60, 0x60);
setBiomeColour(biomeColours, Freezing, 0xff, 0xff, 0xff);
}
xwin_t init_x(uint sx, uint sy, const char *titel)
{
xwin_t w;
@ -167,57 +44,6 @@ void close_x(xwin_t w)
}
void getBiomeColourMap(uint *colbuf, const unsigned char biomeColour[256][3],
const int *ints, const uint sx, const uint sy, const uint pixscale)
{
uint i, j;
int containsInvalidBiomes = 0;
for(j = 0; j < sy; j++)
{
for(i = 0; i < sx; i++)
{
int id = ints[i*sx+j]; //if(id != swamp) id = 100;
uint r, g, b;
if(id < 0 || id >= 256)
{
// This may happen for some intermediate layers
containsInvalidBiomes = 1;
r = biomeColour[id&0x7f][0]-40; r = (r>0xff) ? 0x00 : r&0xff;
g = biomeColour[id&0x7f][1]-40; g = (g>0xff) ? 0x00 : g&0xff;
b = biomeColour[id&0x7f][2]-40; b = (b>0xff) ? 0x00 : b&0xff;
}
else
{
if(id < 128) {
r = biomeColour[id][0];
g = biomeColour[id][1];
b = biomeColour[id][2];
} else {
r = biomeColour[id][0]+40; r = (r>0xff) ? 0xff : r&0xff;
g = biomeColour[id][1]+40; g = (g>0xff) ? 0xff : g&0xff;
b = biomeColour[id][2]+40; b = (b>0xff) ? 0xff : b&0xff;
}
}
uint m, n;
for(m = 0; m < pixscale; m++){
for(n = 0; n < pixscale; n++){
colbuf[(j*pixscale+n) + sy*pixscale*(i*pixscale+m)] =
((r&0xff) << 16) + ((g&0xff) << 8) + (b&0xff);
}
}
}
}
if(containsInvalidBiomes)
{
printf("Warning: Ints contain invalid Biome IDs (Is this an intermediate layer?)\n");
}
}
void viewmap(Layer *layer, unsigned char biomeColour[256][3], int areaX, int areaZ, uint areaWidth, uint areaHeight, uint pixscale)
{
int *ints = allocCache(layer, areaWidth, areaHeight);
@ -227,7 +53,7 @@ void viewmap(Layer *layer, unsigned char biomeColour[256][3], int areaX, int are
// Calculate a hash for the area (useful to verify the accuracy of the map)
uint i, hash = 0;
for(i = 0; i < areaWidth*areaHeight; i++) hash = hash ^ (i*(ints[i]+1));
for (i = 0; i < areaWidth*areaHeight; i++) hash = hash ^ (i*(ints[i]+1));
printf("Hash:%3X\n", hash&0xfff);
// construct the X11 window
@ -242,19 +68,19 @@ void viewmap(Layer *layer, unsigned char biomeColour[256][3], int areaX, int are
uint *colbuf = (uint *) malloc(sizeof(uint) *
areaWidth*areaHeight*pixscale*pixscale);
getBiomeColourMap(colbuf, biomeColour, ints, areaWidth, areaHeight, pixscale);
biomesToImage(colbuf, biomeColour, ints, areaWidth, areaHeight, pixscale, 0);
XImage *ximg = XCreateImage(w.dis, DefaultVisual(w.dis,0), 24, ZPixmap, 0,
(char*)colbuf, areaWidth*pixscale, areaHeight*pixscale, 32, 0);
(char*)colbuf, areaWidth*pixscale, areaHeight*pixscale, 24, 0);
XSetForeground(w.dis, w.gc, 0xf00020);
// enter the event loop
while(1)
while (1)
{
XNextEvent(w.dis, &event);
if(event.type == ClientMessage)
if (event.type == ClientMessage)
{
break;
}

View File

@ -20,11 +20,6 @@ typedef struct xwin_t
} xwin_t;
void initBiomeColours(unsigned char biomeColours[256][3]);
void initBiomeTypeColours(unsigned char biomeColours[256][3]);
xwin_t init_x(uint sx, uint sy, const char *titel);
void close_x(xwin_t w);