#pragma once #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include #include class Map { public: // In addition to traversing the voxel hierarchy, we must also be able to // tell which block a given voxel resides in.This is accomplished us - // ing 32 - bit page headers spread amongst the child descriptors.Page // headers are placed at every 8 kilobyte boundary, and each contains // a relative pointer to the block info section.By placing the begin - // ning of the child descriptor array at such a boundary, we can always // find a page header by simply clearing the lowest bits of any child // descriptor pointer. struct page_header { int bitmask; }; struct leaf_node { long bitmask; }; short scale; void generate_octree() { uint64_t *octree = new uint64_t[200]; long tree_node = 0; std::vector page_array; // Page placed every 8 kilobytes // contains a relative pointer to the block info section uint32_t page = 255; // Child pointer points to the first non-leaf child of this node uint16_t child_pointer = 20; uint32_t pointer = page | child_pointer; }; Map(sf::Vector3i dim) { //generate_octree(); //return; dimensions = dim; std::mt19937 gen; std::uniform_real_distribution dis(-1.0, 1.0); auto f_rand = std::bind(dis, gen); list = new char[dim.x * dim.y * dim.z]; height_map = new double[dim.x * dim.y]; for (int i = 0; i < dim.x * dim.y * dim.z; i++) { list[i] = 0; } for (int i = 0; i < dim.x * dim.y; i++) { height_map[i] = 0; } //for (int x = -dim.x / 2; x < dim.x/2; x++) { // for (int y = -dim.y / 2; y < dim.y/2; y++) { // // double height = 20; // height += std::pow(x / 50.0, 2) - 10 * std::cos(2 * 3.1415926 * x / 50.0); // height += std::pow(y / 50.0, 2) - 10 * std::cos(2 * 3.1415926 * y / 50.0); // // list[(x + dim.x/2) + dim.x * ((y +dim.y/2) + dim.z * (int)height)] = 5; // } //} //int xx = 0; //int yy = 0; //for (int x = -dim.x / 2; x < dim.x / 2; x++) { // for (int y = -dim.y / 2; y < dim.y / 2; y++) { // double z = 150; ////for (int x = 0; x < dim.x; x++) { //// for (int y = 0; y < dim.y; y++) { // double height = 0; // z += -x*2 * std::sin(std::sqrt(abs(x*2 - y*2 - 47))) - // (y*2 + 47) * std::sin(std::sqrt(std::abs(y*2 + 47 + x*2 / 2))); // // //z += x * std::sin(std::sqrt(std::abs(y - x + 1))) * // // std::cos(std::sqrt(std::abs(y + x + 1))) + // // (y + 1) * // // std::cos(std::sqrt(std::abs(y - x + 1))) * // // std::sin(std::sqrt(std::abs(y + x + 1))); // // // Pathological // //z += 0.5 + // // (std::pow(std::sin(std::sqrt(100 * std::pow(x/20, 2) + std::pow(y/20, 2))), 2) - 0.5) / // // (1 + 0.001 * std::pow(std::pow(x/20, 2) - 2 * x/20 * y/20 + std::pow(y/20, 2), 2)); // // Ackleys // //z += 20 + M_E - // // (20 / (std::pow(M_E, 0.2) * std::sqrt((std::pow(x / 16.0, 2) + std::pow(y / 16.0, 2) + 1) / 2))) - // // std::pow(M_E, 0.5 * std::cos(2 * M_PI * x / 16.0) + cos(2 * M_PI * y / 16.0)); // // // //z += -20 * std::pow(M_E, -0.2 * sqrt(0.5 * std::pow(x/64.0, 2) + std::pow(y/64.0, 2))) - std::pow(M_E, 0.5 * (cos(2 * M_PI * x/64.0) + (cos(2 * M_PI * y/64.0)))) + 20 + M_E; // // //list[x + dim.x * (y + dim.z * (int)height)] = 5; // double m = 0.2; // while ((z*m) > 0){ // list[xx + dim.x * (yy + dim.z * (int)(z*m))] = 5; // z -= 1/m; // } // yy++; // } // yy = 0; // xx++; //} // //return; //int featuresize = 2; //for (int y = 0; y < dim.y; y += featuresize) // for (int x = 0; x < dim.x; x += featuresize) { // double t = dis(gen); // setSample(x, y, t); //IMPORTANT: frand() is a random function that returns a value between -1 and 1. // } //int samplesize = featuresize; //double scale = 10.0; //while (samplesize > 1) { // DiamondSquare(samplesize, scale); // samplesize /= 2; // scale /= 2.0; //} //size of grid to generate, note this must be a //value 2^n+1 int DATA_SIZE = dim.x + 1; //an initial seed value for the corners of the data double SEED = rand() % 25 + 25; //seed the data setSample(0, 0, SEED); setSample(0, dim.y, SEED); setSample(dim.x, 0, SEED); setSample(dim.x, dim.y, SEED); double h = 30.0;//the range (-h -> +h) for the average offset //for the new value in range of h //side length is distance of a single square side //or distance of diagonal in diamond for (int sideLength = DATA_SIZE - 1; //side length must be >= 2 so we always have //a new value (if its 1 we overwrite existing values //on the last iteration) sideLength >= 2; //each iteration we are looking at smaller squares //diamonds, and we decrease the variation of the offset sideLength /= 2, h /= 2.0) { //half the length of the side of a square //or distance from diamond center to one corner //(just to make calcs below a little clearer) int halfSide = sideLength / 2; //generate the new square values for (int x = 0; x < DATA_SIZE - 1; x += sideLength) { for (int y = 0; y < DATA_SIZE - 1; y += sideLength) { //x, y is upper left corner of square //calculate average of existing corners double avg = sample(x, y) + //top left sample(x + sideLength,y) +//top right sample(x,y + sideLength) + //lower left sample(x + sideLength,y + sideLength);//lower right avg /= 4.0; //center is average plus random offset setSample(x + halfSide,y + halfSide, //We calculate random value in range of 2h //and then subtract h so the end value is //in the range (-h, +h) avg + (f_rand() * 2 * h) - h); } } //generate the diamond values //since the diamonds are staggered we only move x //by half side //NOTE: if the data shouldn't wrap then x < DATA_SIZE //to generate the far edge values for (int x = 0; x < DATA_SIZE - 1; x += halfSide) { //and y is x offset by half a side, but moved by //the full side length //NOTE: if the data shouldn't wrap then y < DATA_SIZE //to generate the far edge values for (int y = (x + halfSide) % sideLength; y < DATA_SIZE - 1; y += sideLength) { //x, y is center of diamond //note we must use mod and add DATA_SIZE for subtraction //so that we can wrap around the array to find the corners double avg = sample((x - halfSide + DATA_SIZE) % DATA_SIZE,y) + //left of center sample((x + halfSide) % DATA_SIZE,y) + //right of center sample(x,(y + halfSide) % DATA_SIZE) + //below center sample(x,(y - halfSide + DATA_SIZE) % DATA_SIZE); //above center avg /= 4.0; //new value = average plus random offset //We calculate random value in range of 2h //and then subtract h so the end value is //in the range (-h, +h) avg = avg + (f_rand() * 2 * h) - h; //update value for center of diamond setSample(x,y, avg); //wrap values on the edges, remove //this and adjust loop condition above //for non-wrapping values. if (x == 0) setSample(DATA_SIZE - 1,y, avg); if (y == 0) setSample(x, DATA_SIZE - 1, avg); } } } for (int x = 0; x < dim.x; x++) { for (int y = 0; y < dim.y; y++) { if (height_map[x + y * dim.x] > 0) { int z = height_map[x + y * dim.x]; while (z > 0){ list[x + dim.x * (y + dim.z * z)] = 5; z--; } } } } for (int x = 0; x < dim.x / 10; x++) { for (int y = 0; y < dim.y / 10; y++) { for (int z = 0; z < dim.z; z++) { if (rand() % 1000 < 1) list[x + dim.x * (y + dim.z * z)] = rand() % 6; } } } } ~Map() { } sf::Vector3i getDimensions(); char *list; sf::Vector3i dimensions; void setVoxel(sf::Vector3i position, int val){ list[position.x + dimensions.x * (position.y + dimensions.z * position.z)] = val; }; void moveLight(sf::Vector2f in); sf::Vector3f global_light; protected: private: double* height_map; double sample(int x, int y) { return height_map[(x & (dimensions.x - 1)) + (y & (dimensions.y - 1)) * dimensions.x]; } void setSample(int x, int y, double value) { height_map[(x & (dimensions.x - 1)) + (y & (dimensions.y - 1)) * dimensions.x] = value; } void sampleSquare(int x, int y, int size, double value) { int hs = size / 2; // a b // // x // // c d double a = sample(x - hs, y - hs); double b = sample(x + hs, y - hs); double c = sample(x - hs, y + hs); double d = sample(x + hs, y + hs); setSample(x, y, ((a + b + c + d) / 4.0) + value); } void sampleDiamond(int x, int y, int size, double value) { int hs = size / 2; // c // //a x b // // d double a = sample(x - hs, y); double b = sample(x + hs, y); double c = sample(x, y - hs); double d = sample(x, y + hs); setSample(x, y, ((a + b + c + d) / 4.0) + value); } void DiamondSquare(int stepsize, double scale) { std::mt19937 generator; std::uniform_real_distribution uniform_distribution(-1.0, 1.0); auto f_rand = std::bind(uniform_distribution, std::ref(generator)); int halfstep = stepsize / 2; for (int y = halfstep; y < dimensions.y + halfstep; y += stepsize) { for (int x = halfstep; x < dimensions.x + halfstep; x += stepsize) { sampleSquare(x, y, stepsize, f_rand() * scale); } } for (int y = 0; y < dimensions.y; y += stepsize) { for (int x = 0; x < dimensions.x; x += stepsize) { sampleDiamond(x + halfstep, y, stepsize, f_rand() * scale); sampleDiamond(x, y + halfstep, stepsize, f_rand() * scale); } } } };