#include #include #include #include #include #include #include "PerlinNoise.hpp" #include "random.h" #include "graphics.h" #include "blocks.h" #include "player.h" #include "world.h" #include "math.h" //int min_render_distance=50; int render_distance_width=40; int render_distance_height=10; uint64_t sxyz[3]; Block *world; /*std::vector render_distance_average; void on_early() { // Increase the render distance render_distance += 1; } void on_late() { // Reduce the render distance if(render_distance > min_render_distance) { render_distance -= 1; } } */ void coords_to_int(int *id, int x, int y, int z) { *id = z * sxyz[1] * sxyz[0] + y * sxyz[0] + x; } void int_to_coords(int id, int *x, int *y, int *z) { *x = id % sxyz[0]; *y = (id/sxyz[0]) % sxyz[1]; *z = (id/sxyz[0]/sxyz[1]) % sxyz[2]; } // Say if the block is in the world bool block_in_world(int x, int y, int z) { return (x >= 0) && (x < sxyz[0]) && (y >= 0) && (y < sxyz[1]) && (z >= 0) && (z < sxyz[2]); } // Say if the player is in the world bool player_in_world(double x, double y, double z) { return (x >= 0) && (x <= sxyz[0]) && (y >= 0) && (y <= sxyz[1]) && (z >= 0) && (z <= sxyz[2]); } bool block_is_ramp(double x, double y, double z) { // Get the id int id; coords_to_int(&id, x, y, z); // Is the player on a ramp if(world[id].type == BTYPE_RAMP) { // Get the part of the slope the player is on double slope_part; // North if(world[id].direction == DIRECTION_N) { slope_part = 1-(z-int(z)); } // South if(world[id].direction == DIRECTION_S) { slope_part = z-int(z); } // East if(world[id].direction == DIRECTION_E) { slope_part = 1-(x-int(x)); } // West if(world[id].direction == DIRECTION_W) { slope_part = x-int(x); } // Is the player above the slope part return ((y-int(y)) < slope_part+0.25); } // The player isnt on a ramp return false; } bool block_isnt_solid(double x, double y, double z) { // Setup some varibles bool in_world_check = false; double d = 0.25; // Is the player inside the world if(player_in_world(x, y, z)) in_world_check = true; // Is the block in range if(in_world_check) { if(block_is_ramp(x, y, z)) { return false; } // Get the ids int id[8]; coords_to_int(&id[0], x+d, y+d, z+d); coords_to_int(&id[1], x-d, y+d, z+d); coords_to_int(&id[2], x-d, y+d, z-d); coords_to_int(&id[3], x+d, y+d, z-d); coords_to_int(&id[4], x+d, y-d, z+d); coords_to_int(&id[5], x-d, y-d, z+d); coords_to_int(&id[6], x-d, y-d, z-d); coords_to_int(&id[7], x+d, y-d, z-d); // Loop throgh the ids for(int i=0;i<8;i++) { // Convert the id to coordinates int cx, cy, cz; int_to_coords(id[i], &cx, &cy, &cz); // Are the coordinates out of range; then return true if(cx < 0 || cy < 0 || cz < 0 || cx >= sxyz[0] || cy >= sxyz[1] || cz >= sxyz[2]) { return true; } // Is the block not in the world if(!block_in_world(cx, cy, cz)) { // Return true return true; } // Return false if this is not air and is a block if( world[id[i]].id != BLOCK_AIR && world[id[i]].type == BTYPE_BLOCK ) return false; } // Return true return true; } // Return true return true; } bool block_is_fluid(double x, double y, double z) { // Get the fluid motion double fluid_motion = get_fluid_motion(x, z); // Get the id int id; coords_to_int(&id, x, y+1-fluid_motion, z); // Get the above id int a_id; coords_to_int(&a_id, x, y+2-fluid_motion, z); // Is the player in a fluid if(world[id].type == BTYPE_FLUID) { // Submurged under the water if(world[a_id].type == BTYPE_FLUID) { // Return true return true; } // Is the decimal height greater than the block height and the fluid motion return y < int(y) + fluid_motion; } // Return false return false; } int relative_block(int id, int x, int y, int z) { // Get the position of the current block int cx, cy, cz; int_to_coords(id, &cx, &cy, &cz); // Add the relative coordinates cx += x; cy += y; cz += z; // Is this valid if(cx < 0) return -1; if(cy < 0) return -1; if(cz < 0) return -1; if(cx >= sxyz[0]) return -1; if(cy >= sxyz[1]) return -1; if(cz >= sxyz[2]) return -1; // Get the id int cid; coords_to_int(&cid, cx, cy, cz); // Return the block id return cid; } bool relative_block_optimise(int id, int x, int y, int z, bool check) { // Is the check varible already false if(!check) return false; // Get the id of the relative block int rb = relative_block(id, x, y, z); // Is the result out of range (-1) if(rb == -1) return false; if(!( // Is not air world[rb].id != BLOCK_AIR && ( // Is the same type as the other block world[rb].type == world[id].type || // Is the other block a block world[rb].type == BTYPE_BLOCK ) )) return true; return ( (!blockGetSettings(world[id].id).transparent) && blockGetSettings(world[rb].id).transparent ); /*// Check the angle of the face and the player // Get the blocks coordinates int cx, cy, cz; int_to_coords(id, &cx, &cy, &cz); double a; if(x != 0 || z != 0) { a = atan2(cx-player_pos[0], cz-player_pos[2])*180.0/PI } // North / South if(x != 0) { // Get the angle a -= player_angle[0]; a *= x; } // East / West if(z != 0) { // Get the angle a = ; a -= player_angle[0] - 90; a *= z; } // Up / Down if(y != 0) { // Get the angle a = atan2(cy-player_pos[1], cz-player_pos[2])*180.0/PI; a -= player_angle[0]; a *= y; } // Fix the angle while(a < 0) a += 360; while(a > 360) a -= 360; return a > 0 && a < 180;*/ } void world_load(const char *dir) { /*// Open the file std::ifstream file(dir, std::ios::binary); // Load the map size file.read((char*)&sxyz[0], sizeof(uint64_t)); file.read((char*)&sxyz[1], sizeof(uint64_t)); file.read((char*)&sxyz[2], sizeof(uint64_t)); // Setup the world varible world = new World[sxyz[0]*sxyz[1]*sxyz[2]]; // Read the world data file.read((char*)world, sizeof(World)*sxyz[0]*sxyz[1]*sxyz[2]); // Close the file file.close();*/ } void player_respawn() { // Set the player to the middle and at the top of the map player_pos[0] = sxyz[0]/2; player_pos[1] = sxyz[1]-2; player_pos[2] = sxyz[2]/2; } void world_init() { // Initialse the blocks blocks_init(); sxyz[0] = 256; sxyz[1] = 120; sxyz[2] = 256; // Set the players spawn point player_respawn(); // Setup the world varible world = new Block[sxyz[0]*sxyz[1]*sxyz[2]]; // Zero out the world varible zero_out_bytes((char*)world, sizeof(Block)*sxyz[0]*sxyz[1]*sxyz[2]); // Set the seed const siv::PerlinNoise perlin(random_get_seed()); // Set the frequency double frequency = 1; double xf = sxyz[0] / frequency; double zf = sxyz[2] / frequency; // Loop over x for(int x=0;x= 60) { // Make grass world[id] = make_block(BLOCK_GRASS); } else if(y == noise && y < 60) { // Make grass world[id] = make_block(BLOCK_SAND); } // Water level else if(y > noise && y < 60) { // Make water world[id] = make_block(BLOCK_WATER, BTYPE_FLUID); } // 1 block above ground else if(y == noise+1) { // Get some perlin noise double grass_noise = perlin.octaveNoise0_1(x / 10.0, z / 10.0, 10); // Over a certain threshold if(grass_noise > 0.6) { // Make grass plant world[id] = make_block(BLOCK_GRASS_PLANT, BTYPE_PLANT); } } } /* else if(y < 2) { world[id] = make_block(BLOCK_DIRT); } else if(y == 2) { world[id] = make_block(BLOCK_GRASS); } else if(x > 5 && y < z-100) { world[id] = make_block(BLOCK_DIRT); } else if(x > 5 && y == z-100) { world[id] = make_block(BLOCK_GRASS, BTYPE_RAMP, DIRECTION_S); } */ } } } } void render_coord(int x, int y, int z, int a1, int a2) { // Is this in range if(block_in_world(x, y, z)) { // Get the id int id; coords_to_int(&id, x, y, z); int b = 60; // Is this not air if(world[id].id != BLOCK_AIR) { // Setup a Block Face Map BlockFaceMap fm; fm.n = relative_block_optimise(id, 0, 0,-1, a1 > 90 -b && a1 < 270+b || (a2 < -40 || a2 > 40)); fm.s = relative_block_optimise(id, 0, 0, 1, a1 > 270-b || a1 < 90 +b || (a2 < -40 || a2 > 40)); fm.e = relative_block_optimise(id, 1, 0, 0, a1 < 0 +b || a1 > 180-b || (a2 < -40 || a2 > 40)); fm.w = relative_block_optimise(id,-1, 0, 0, a1 < 180+b || a1 > 360-b || (a2 < -40 || a2 > 40)); fm.t = relative_block_optimise(id, 0, 1, 0, a2 > 0-b || world[id].type == BTYPE_FLUID); fm.b = relative_block_optimise(id, 0,-1, 0, a2 < 0+b); // Render the block render_block(world[id], x, y, z, fm); } } } void world_render_block_inside_player() { // Bind the texture bind_block_texture(); // Get the id int id; coords_to_int(&id, player_pos[0], player_pos[1], player_pos[2]); // Render the block face infront of the player render_block_face_here(world[id]); } void world_render() { // Set the colour to maximum opacity and colour glColor4f(1.0f,1.0f,1.0f,1.0f); // Bind the texture bind_block_texture(); // Get the cameras angles int a1 = (int)player_angle[0] % 360; int a2 = (int)player_angle[1] % 180; // Set the cutof render angles int g1 = 80; int g2 = 40; // Render everything inwards for(int x=render_distance_width;x>0;x-=1) { for(int y=render_distance_height;y>0;y-=1) { for(int z=render_distance_width;z>0;z-=1) { // Render the blocks if((a1 < 180 +g1 && a1 > 90 -g1) || (a2 < 0 -g2)) render_coord(player_pos[0]+x, player_pos[1]+y, player_pos[2]+z, a1, a2); if((a1 < 270 +g1 && a1 > 180 -g1) || (a2 < 0 -g2)) render_coord(player_pos[0]-x, player_pos[1]+y, player_pos[2]+z, a1, a2); if((a1 < 0 +g1 || a1 > 270 -g1) || (a2 < 0 -g2)) render_coord(player_pos[0]-x, player_pos[1]+y, player_pos[2]-z, a1, a2); if((a1 < 90 +g1 || a1 > 360 -g1) || (a2 < 0 -g2)) render_coord(player_pos[0]+x, player_pos[1]+y, player_pos[2]-z, a1, a2); if((a1 < 180 +g1 && a1 > 90 -g1) || (a2 > 0 +g2)) render_coord(player_pos[0]+x, player_pos[1]-y, player_pos[2]+z, a1, a2); if((a1 < 270 +g1 && a1 > 180 -g1) || (a2 > 0 +g2)) render_coord(player_pos[0]-x, player_pos[1]-y, player_pos[2]+z, a1, a2); if((a1 < 0 +g1 || a1 > 270 -g1) || (a2 > 0 +g2)) render_coord(player_pos[0]-x, player_pos[1]-y, player_pos[2]-z, a1, a2); if((a1 < 90 +g1 || a1 > 360 -g1) || (a2 > 0 +g2)) render_coord(player_pos[0]+x, player_pos[1]-y, player_pos[2]-z, a1, a2); } } } for(int x=render_distance_width;x>0;x-=1) { for(int z=render_distance_width;z>0;z-=1) { // Render the coordinates render_coord(player_pos[0]+x, player_pos[1], player_pos[2]+z, a1, a2); render_coord(player_pos[0]+x, player_pos[1], player_pos[2]-z, a1, a2); render_coord(player_pos[0]-x, player_pos[1], player_pos[2]-z, a1, a2); render_coord(player_pos[0]-x, player_pos[1], player_pos[2]+z, a1, a2); } } for(int x=render_distance_width;x>0;x-=1) { for(int y=render_distance_height;y>0;y-=1) { // Render the coordinates render_coord(player_pos[0]+x, player_pos[1]+y, player_pos[2], a1, a2); render_coord(player_pos[0]+x, player_pos[1]-y, player_pos[2], a1, a2); render_coord(player_pos[0]-x, player_pos[1]-y, player_pos[2], a1, a2); render_coord(player_pos[0]-x, player_pos[1]+y, player_pos[2], a1, a2); } } for(int z=render_distance_width;z>0;z-=1) { for(int y=render_distance_height;y>0;y-=1) { // Render the coordinates render_coord(player_pos[0], player_pos[1]+y, player_pos[2]+z, a1, a2); render_coord(player_pos[0], player_pos[1]+y, player_pos[2]-z, a1, a2); render_coord(player_pos[0], player_pos[1]-y, player_pos[2]-z, a1, a2); render_coord(player_pos[0], player_pos[1]-y, player_pos[2]+z, a1, a2); } } for(int x=render_distance_width;x>0;x-=1) { // Render the coordinates render_coord(player_pos[0]+x, player_pos[1], player_pos[2], a1, a2); render_coord(player_pos[0]-x, player_pos[1], player_pos[2], a1, a2); } for(int y=render_distance_height;y>0;y-=1) { // Render the coordinates render_coord(player_pos[0], player_pos[1]+y, player_pos[2], a1, a2); render_coord(player_pos[0], player_pos[1]-y, player_pos[2], a1, a2); } for(int z=render_distance_width;z>0;z-=1) { // Render the coordinates render_coord(player_pos[0], player_pos[1], player_pos[2]+z, a1, a2); render_coord(player_pos[0], player_pos[1], player_pos[2]-z, a1, a2); } // Render a coordinate where the player is standing render_coord(player_pos[0], player_pos[1], player_pos[2], a1, a2); // Unbind the texture unbind_block_texture(); // Enable blending //glEnable(GL_BLEND); } void set_block_at(int x, int y, int z, uint8_t id, uint8_t type, uint8_t direction) { // Get the id int w_id; coords_to_int(&w_id, x, y, z); // Get the block Block b = make_block(id, type, direction); // Set the block world[w_id] = b; }