From a9705edfb8f5303f4a3d9c946aad78e2eb7cf4f2 Mon Sep 17 00:00:00 2001 From: Cubitect Date: Sun, 15 Mar 2020 16:09:06 +0100 Subject: [PATCH] Made compatible with g++ and clang compilers + better docu for getting started. --- README.md | 148 +++++++++++++++++++++++++++++----- find_compactbiomes.c | 6 +- find_quadhuts.c | 59 +++++++------- finders.c | 84 +++++++++++-------- finders.h | 15 ++-- generator.h | 12 ++- layers.c | 18 +++-- layers.h | 29 +++++-- makefile | 19 ++++- xmapview.c | 188 ++----------------------------------------- xmapview.h | 5 -- 11 files changed, 287 insertions(+), 296 deletions(-) diff --git a/README.md b/README.md index 0780529..9f9e6c0 100644 --- a/README.md +++ b/README.md @@ -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 + +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 | diff --git a/find_compactbiomes.c b/find_compactbiomes.c index 0a67b96..fc16859 100644 --- a/find_compactbiomes.c +++ b/find_compactbiomes.c @@ -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]; diff --git a/find_quadhuts.c b/find_quadhuts.c index c577ec6..a5f9283 100644 --- a/find_quadhuts.c +++ b/find_quadhuts.c @@ -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", ®PosX) != 1) regPosX = 0; - if(sscanf(argv[2], "%d", ®PosZ) != 1) regPosZ = 0; + if (sscanf(argv[1], "%d", ®PosX) != 1) regPosX = 0; + if (sscanf(argv[2], "%d", ®PosZ) != 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++; } } diff --git a/finders.c b/finders.c index 5750b75..2f2713d 100644 --- a/finders.c +++ b/finders.c @@ -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 { diff --git a/finders.h b/finders.h index ba868b0..dff103d 100644 --- a/finders.h +++ b/finders.h @@ -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_ */ diff --git a/generator.h b/generator.h index 6c89e3e..63ce85b 100644 --- a/generator.h +++ b/generator.h @@ -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_ */ diff --git a/layers.c b/layers.c index e4beb98..da3455c 100644 --- a/layers.c +++ b/layers.c @@ -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]; diff --git a/layers.h b/layers.h index e8d5979..1b92c20 100644 --- a/layers.h +++ b/layers.h @@ -3,6 +3,8 @@ #include "javarnd.h" +#define __STDC_FORMAT_MACROS 1 + #include #include #include @@ -11,15 +13,21 @@ #define NULL ((void*)0) #endif +#define SIMD_NOTIFY 0 + #if defined USE_SIMD && __AVX2__ #include #include #include +#if SIMD_NOTIFY #warning "Using AVX2 extensions." +#endif #elif defined USE_SIMD && defined __SSE4_2__ #include #include +#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_ */ diff --git a/makefile b/makefile index c6efeba..723aa4a 100644 --- a/makefile +++ b/makefile @@ -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 diff --git a/xmapview.c b/xmapview.c index 4cd744c..29154a4 100644 --- a/xmapview.c +++ b/xmapview.c @@ -1,133 +1,10 @@ #include "xmapview.h" +#include "util.h" + #include #include -/* 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; } diff --git a/xmapview.h b/xmapview.h index d477755..afe015f 100644 --- a/xmapview.h +++ b/xmapview.h @@ -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);