520 lines
16 KiB
C
520 lines
16 KiB
C
#include "../include/app.h"
|
|
#include <GL/gl.h>
|
|
|
|
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]));
|
|
//}
|
|
}
|
|
|