#include "../include/app.h" #include void init_app(App *app, uint w, uint h) { srand(time(NULL)); int err; err = SDL_Init(SDL_INIT_EVERYTHING); if (err != 0) { printf("Failed to initialize SDL. Error: %s\n", SDL_GetError()); exit(1); } app->window = SDL_CreateWindow( "test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_OPENGL); if (app->window == NULL) { printf("Failed to create window.\n"); exit(1); } app->context = SDL_GL_CreateContext(app->window); if (app->context == NULL) { printf("Failed to create OpenGL context.\n"); exit(1); } //SDL_ShowCursor(SDL_DISABLE); init_camera(&app->camera); init_opengl(); reshape(w, h); init_camera(&app->camera); app->camera.cm = app->cm; app->surface_count = BLOCKTYPE_COUNT-2; app->surfaces = malloc(app->surface_count+1*sizeof(Type_surface)); app_load_textures(app); app->cm->textures = app->surfaces; app->cm->texture_count = app->surface_count; app->particle_count = 0; app_generate_world(app, 10); app->is_running = true; } void app_load_textures(App *app) { app->surfaces[0].type = BLOCKTYPE_DIRT; app->surfaces[1].type = BLOCKTYPE_STONE; app->surfaces[0].surface = IMG_Load("assets/dirt.png"); app->surfaces[1].surface = IMG_Load("assets/stone.png"); for (int i = 0; i < 1; i++) { if(app->surfaces[i].surface == NULL) { printf("error loading texture\n"); exit(1); } glGenTextures(1, &app->surfaces[i].tid); glBindTexture(GL_TEXTURE_2D, app->surfaces[i].tid); int Mode = GL_RGB; if(app->surfaces[i].surface->format->BytesPerPixel == 4) { Mode = GL_RGBA; } glTexImage2D(GL_TEXTURE_2D, 0, Mode, app->surfaces[i].surface->w, app->surfaces[i].surface->h, 0, Mode, GL_UNSIGNED_BYTE, app->surfaces[i].surface->pixels); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, app->surfaces[i].tid); } } void update_app(App* app) { update_camera(&(app->camera), app->frame_time/1000); app_update_particles(app); } void init_opengl() { // https://gitlab.com/imre-piller/me-courses/ alapjan. glShadeModel(GL_SMOOTH); glEnable(GL_NORMALIZE); glEnable(GL_AUTO_NORMAL); glClearColor(0.1, 0.1, 0.1, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_DEPTH_TEST); glClearDepth(1.0); glEnable(GL_TEXTURE_2D); } void reshape(GLsizei width, GLsizei height) { int x, y, w, h; double ratio; ratio = (double)width / height; if (ratio > VIEWPORT_RATIO) { w = (int)((double)height * VIEWPORT_RATIO); h = height; x = (width - w) / 2; y = 0; } else { w = width; h = (int)((double)width / VIEWPORT_RATIO); x = 0; y = (height - h) / 2; } glViewport(x, y, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum( -.16, .16, -.09, .09, .1, 1000 ); } void handle_events(App* app) { SDL_Event event; static bool is_mouse_down = false; static int mouse_x = 0; static int mouse_y = 0; int x; int y; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_KEYDOWN: switch (event.key.keysym.scancode) { case SDL_SCANCODE_ESCAPE: app->is_running = false; break; case SDL_SCANCODE_W: camera_set_speed(&(app->camera), SPEED); break; case SDL_SCANCODE_S: camera_set_speed(&(app->camera), -SPEED); break; case SDL_SCANCODE_A: camera_set_side_speed(&(app->camera), SPEED); break; case SDL_SCANCODE_D: camera_set_side_speed(&(app->camera), -SPEED); break; case SDL_SCANCODE_SPACE: camera_set_vertical_speed(&app->camera, SPEED); break; case SDL_SCANCODE_LSHIFT: camera_set_vertical_speed(&app->camera, -SPEED); break; default: break; } break; case SDL_KEYUP: switch (event.key.keysym.scancode) { case SDL_SCANCODE_W: case SDL_SCANCODE_S: camera_set_speed(&(app->camera), 0); break; case SDL_SCANCODE_A: case SDL_SCANCODE_D: camera_set_side_speed(&(app->camera), 0); break; case SDL_SCANCODE_SPACE: case SDL_SCANCODE_LSHIFT: camera_set_vertical_speed(&app->camera, -0); default: break; } break; case SDL_MOUSEBUTTONDOWN: if (event.button.button == SDL_BUTTON_LEFT) { app_break_block(app); break; } else if (event.button.button == SDL_BUTTON_RIGHT) { app_place_block(app); break; } case SDL_MOUSEMOTION: SDL_GetMouseState(&x, &y); rotate_camera(&(app->camera), mouse_x - x, mouse_y - y); mouse_x = x; mouse_y = y; break; case SDL_MOUSEBUTTONUP: is_mouse_down = false; break; case SDL_QUIT: app->is_running = false; break; default: break; } } } float calc_frame_time(struct timespec *start, struct timespec *end) { float elapsed_time = (end->tv_sec - start->tv_sec)*1000; elapsed_time += (float)(end->tv_nsec - start->tv_nsec)/1000000; return elapsed_time; } void app_generate_world(App *app, int a) { app->cm->chunk_count = a*a; app->cm->chunks = malloc(a*a*sizeof(Chunk)); memset(app->cm->chunks, 0, a*a*sizeof(Chunk)); long block_count = 0; unsigned char ptable[512]; noise_init_ptable(ptable); int r = irand_range(-10000, 10000); for (int i = 0; i < a; i++) { for (int j = 0; j < a; j++) { Chunk c; c.start_pos.x = i*CHUNK_MAX_X; c.start_pos.y = j*CHUNK_MAX_Y; c.start_pos.z = 0; for (int x = 0; x < CHUNK_MAX_X; x++) { for (int y = 0; y < CHUNK_MAX_Y; y++) { //printf("x: %d y:%d noise: %f\n", x, y, round((noise_noise2(ptable, // (c.start_pos.x+x)*0.03, (c.start_pos.y+y)*0.03) + 1) * 0.5 * 15); int mz = round((noise_noise2(ptable, (c.start_pos.x+x+r)*0.02, (c.start_pos.y+y+r)*0.02)+1)* 0.5 * 10); if (mz < 0) mz = 0; else if (mz > CHUNK_MAX_Z) mz = CHUNK_MAX_Z-1; for (int z = 0; z < mz; z++) { c.blocks[x][y][z].type = BLOCKTYPE_DIRT; block_count++; } for (int z = mz; z < CHUNK_MAX_Z; z++) c.blocks[x][y][z].type = BLOCKTYPE_AIR; } } chunk_set_blocks_visibility(&c); chunk_create_displayl(app->cm, &c); app->cm->chunks[i+(j*a)] = c; } } printf("block count: %d\n", block_count); } bool is_block(Block b) { if(b.type != BLOCKTYPE_AIR) return true; return false; } //bool app_check_collision(App *app) //{ // int i = app_get_current_chunk_index(app); // // if (i < 0) // return false; // // vec3f c_pos = app->camera.position; // vec3i c_index = { floor(c_pos.x), floor(c_pos.y), floor(c_pos.z) }; // // //for (int x = c_index.x-1; x < c_index.x+1; x++) { // // for (int y = c_index.y-1; y < c_index.y+1; y++) { // // for (int z = c_index.z-1; y < c_index.z+1; z++) { // // if(!check_index(x, y, z)) // // continue; // // if(is_block(app->chunks[i].blocks[x][y][z])) { // // // // } // // } // // } // //} // // int x = c_index.x; // int y = c_index.y; // int z = c_index.z; // // if (check_index(x-1, y, z)) // if (is_block(app->chunks[i].blocks[x-1][y][z])) // //camera_set_side_speed(&app->camera, 0.0); // if (check_index(x+1, y, z)) // if (is_block(app->chunks[i].blocks[x+1][y][z])) // //camera_set_side_speed(&app->camera, 0.0); // if (check_index(x, y-1, z)) // if (is_block(app->chunks[i].blocks[x][y-1][z])) // //camera_set_speed(&app->camera, 0.0); // if (check_index(x, y+1, z)) // if (is_block(app->chunks[i].blocks[x][y+1][z])) // //camera_set_speed(&app->camera, 0.0); // if (check_index(x, y, z-1)) // if (is_block(app->chunks[i].blocks[x][y][z-1])) // camera_set_vertical_speed(&app->camera, 0.0); // if (check_index(x, y, z+1)) // if (is_block(app->chunks[i].blocks[x][y][z+1])) // camera_set_vertical_speed(&app->camera, 0.0); // // return false; //} int check_intersection_block(App *app, vec3i *retv, int *chunk_index) { printf("%s\n", __func__); int i = chunk_get_current_chunk_index(app->cm, app->camera.position); *chunk_index = i; vec3f c_pos = app->camera.position; vec3f c_dir = get_camera_dir_vec3f(&app->camera); if (i < 0) return -1; for (int x = 0; x < CHUNK_MAX_X; x++) { for (int y = 0; y < CHUNK_MAX_Y; y++) { for (int z = 0; z < CHUNK_MAX_Z; z++) { if (app->cm->chunks[i].blocks[x][y][z].visible) { for (float j = 0; j < 5; j+=0.1) { vec3f ray = {(c_pos.x - app->cm->chunks[i].start_pos.x) + c_dir.x * j, (c_pos.y - app->cm->chunks[i].start_pos.y) + c_dir.y * j, (c_pos.z - app->cm->chunks[i].start_pos.z) + c_dir.z * j}; printf("ray x: %f y: %f z: %f\n", ray.x, ray.y, ray.z); vec3i rayi = {(int)ray.x, (int)ray.y, (int)ray.z}; if (is_block(app->cm->chunks[i].blocks[rayi.x][rayi.y][rayi.z])) { retv->x = rayi.x; retv->y = rayi.y; retv->z = rayi.z; return 0; } } } } } } return -1; } void app_draw_particles(App *app, vec3i b) { unsigned char index = app->particle_count; if (index >= MAX_PARTICLE_GROUPS) return; for (int i = 0; i < PARTICLES_PER_GROUP; i++) { vec3f p = {b.x+i/50+frand_range(-0.1,0.1), b.y+i/50+frand_range(-0.1,0.1), b.z+frand_range(-0.1, 0.1)}; app->particles[index].pos[i] = p; } app->particles[index].time = SDL_GetTicks(); app->particle_count++; } void app_update_particles(App *app) { unsigned char particles = app->particle_count; for (int i = 0; i < particles; i++) { unsigned int time = SDL_GetTicks(); if (time - app->particles[i].time > 1000) { memset(&app->particles[i], 0, sizeof(ParticleGroup)); app->particle_count--; } else { for (int j = 0; j < PARTICLES_PER_GROUP; j++) { app->particles[i].pos[j].z -= GRAVITY * app->frame_time/1000; draw_cube(app->cm, 0, app->particles[i].pos[j].x, app->particles[i].pos[j].y, app->particles[i].pos[j].z, 0.1); } } } } void app_break_block(App *app) { printf("%s\n", __func__); vec3i block; int i; int ret = check_intersection_block(app, &block, &i); //printf("chunk index: %d\n", i); //printf("player x: %f y: %f z: %f\n", app->camera.position.x, app->camera.position.y, app->camera.position.z); //printf("chunk %d. min x: %f y: %f max x: %f y: %f\n", i, app->chunks[i].start_pos.x, // app->chunks[i].start_pos.y, app->chunks[i].start_pos.x+CHUNK_MAX_X, app->chunks[i].start_pos.y+CHUNK_MAX_Y); //printf("broken block x: %f y: %f z: %f\n", block.x+app->chunks[i].start_pos.x, block.y+app->chunks[i].start_pos.y, block.z+app->chunks[i].start_pos.z); if (ret < 0) return; app->cm->chunks[i].blocks[block.x][block.y][block.z].type = BLOCKTYPE_AIR; chunk_update(app->cm, &(app->cm->chunks[i])); app_draw_particles(app, block); } void app_place_block(App *app) { float dist = 5.0; vec3f cam_pos = app->camera.position; vec3i block; int i; int ret = check_intersection_block(app, &block, &i); if (ret < 0) return; vec3f t = { (float) cam_pos.x - block.x, (float) cam_pos.y - block.y, (float) cam_pos.z - block.z }; printf("t x: %f\n", t.x); printf("t y: %f\n", t.y); //printf("t x: %f\n", t.x); if (t.z > 0) { app->cm->chunks[i].blocks[block.x][block.y][block.z+1].type = BLOCKTYPE_STONE; chunk_update(app->cm, &(app->cm->chunks[i])); puts("block blaced, +z"); return; } else { app->cm->chunks[i].blocks[block.x][block.y][block.z+1].type = BLOCKTYPE_STONE; chunk_update(app->cm, &(app->cm->chunks[i])); puts("block blaced, -z"); return; } if (t.x > 0) { if (t.z > 0) { app->cm->chunks[i].blocks[block.x][block.y][block.z+1].type = BLOCKTYPE_STONE; chunk_update(app->cm, &(app->cm->chunks[i])); puts("block blaced, +z"); return; } else { app->cm->chunks[i].blocks[block.x][block.y][block.z+1].type = BLOCKTYPE_STONE; chunk_update(app->cm, &(app->cm->chunks[i])); puts("block blaced, -z"); return; } if (t.y < t.x && t.y > -t.x && !is_block(app->cm->chunks[i].blocks[block.x+1][block.y][block.z])) { app->cm->chunks[i].blocks[block.x+1][block.y][block.z].type = BLOCKTYPE_STONE; chunk_update(app->cm, &(app->cm->chunks[i])); puts("block blaced, +x"); return; } } else { if (t.y < -t.x && t.y > t.x && !is_block(app->cm->chunks[i].blocks[block.x-1][block.y][block.z])) { app->cm->chunks[i].blocks[block.x-1][block.y][block.z].type = BLOCKTYPE_STONE; chunk_update(app->cm, &(app->cm->chunks[i])); puts("block blaced, -x"); return; } } if (t.y > 0) { app->cm->chunks[i].blocks[block.x][block.y+1][block.z].type = BLOCKTYPE_STONE; chunk_update(app->cm, &(app->cm->chunks[i])); puts("block blaced, +y"); return; } else { app->cm->chunks[i].blocks[block.x][block.y-1][block.z].type = BLOCKTYPE_STONE; chunk_update(app->cm, &(app->cm->chunks[i])); puts("block blaced, -y"); return; } //if (cam_pos.x < (float)block.x+dist/2 && // cam_pos.x > (float)block.x-dist/2) { // if (cam_pos.x > block.x) // app->cm->chunks[i].blocks[block.x+1][block.y][block.z].type = BLOCKTYPE_STONE; // if (cam_pos.x < block.x) // app->cm->chunks[i].blocks[block.x-1][block.y][block.z].type = BLOCKTYPE_STONE; // chunk_update(app->cm, &(app->cm->chunks[i])); //} //if (cam_pos.y < (float)block.y+dist/2 && // cam_pos.y > (float)block.y-dist/2) { // if (cam_pos.y > block.y) // app->cm->chunks[i].blocks[block.x][block.y+1][block.z].type = BLOCKTYPE_STONE; // if (cam_pos.y < block.y) // app->cm->chunks[i].blocks[block.x][block.y-1][block.z].type = BLOCKTYPE_STONE; // chunk_update(app->cm, &(app->cm->chunks[i])); //} }