From e799d50f7705e3407869a81daafa89c7473204b8 Mon Sep 17 00:00:00 2001 From: onezplpl Date: Thu, 18 Jul 2024 17:04:40 -0400 Subject: [PATCH] crosshair --- control.c | 24 ++++++++++++++++-------- cubes.c | 37 +++++++++++++++++++++++++++++++++++-- cubes.h | 5 ++++- main.c | 46 +++++++++++++++++++++++++++++++++++++++------- test.png | Bin 7509 -> 7813 bytes 5 files changed, 94 insertions(+), 18 deletions(-) diff --git a/control.c b/control.c index fc89c10..09cabce 100644 --- a/control.c +++ b/control.c @@ -134,8 +134,10 @@ struct v3f control_rtrace(double cx, double cy, vec3 pos, int mode) { vec3_add(temp_pos, temp_pos, temp_dir); - if (gen_cube(temp_pos[0],temp_pos[1],temp_pos[2],placeChunk,0,-1) != 0) { - if (mode == 0) vec3_sub(temp_pos,temp_pos,temp_dir); + if (gen_cube(temp_pos[0], temp_pos[1], temp_pos[2], placeChunk, 0, -1) != + 0) { + if (mode == 0) + vec3_sub(temp_pos, temp_pos, temp_dir); break; } } @@ -149,15 +151,21 @@ struct v3f control_rtrace(double cx, double cy, vec3 pos, int mode) { void control_lclick(double cx, double cy, vec3 pos) { struct v3f highlighted = control_rtrace(cx, cy, pos, 1); struct chunk placeChunk; - int cube = gen_cube(highlighted.pos[0],highlighted.pos[1],highlighted.pos[2],placeChunk,0,-1); - if (cube == 0) return; - gen_cube(highlighted.pos[0],highlighted.pos[1],highlighted.pos[2],placeChunk,0,0); + int cube = gen_cube(highlighted.pos[0], highlighted.pos[1], + highlighted.pos[2], placeChunk, 0, -1); + if (cube == 0) + return; + gen_cube(highlighted.pos[0], highlighted.pos[1], highlighted.pos[2], + placeChunk, 0, 0); } void control_rclick(double cx, double cy, vec3 pos) { struct v3f highlighted = control_rtrace(cx, cy, pos, 0); struct chunk placeChunk; - int cube = gen_cube(highlighted.pos[0],highlighted.pos[1],highlighted.pos[2],placeChunk,0,-1); - if (cube != 0) return; - gen_cube(highlighted.pos[0],highlighted.pos[1],highlighted.pos[2],placeChunk,0,1); + int cube = gen_cube(highlighted.pos[0], highlighted.pos[1], + highlighted.pos[2], placeChunk, 0, -1); + if (cube != 0) + return; + gen_cube(highlighted.pos[0], highlighted.pos[1], highlighted.pos[2], + placeChunk, 0, 1); } \ No newline at end of file diff --git a/cubes.c b/cubes.c index 24d5119..3cda73e 100644 --- a/cubes.c +++ b/cubes.c @@ -22,6 +22,38 @@ int oz = -1024; struct chunk *chunk_old = NULL; +void cubes_rect(struct v3f *cube, int *i, double x1, double x2, double y1, + double y2, int is_text, int text_x, int text_y) { + struct v3f a2 = {{x1, y1, 0}}; + if (is_text) { + a2.pos[0] = TEXT_GAP_H * text_x; + a2.pos[1] = TEXT_GAP_V * text_y; + a2.pos[2] = 0; + } + struct v3f b = a2; + struct v3f c = a2; + struct v3f d = a2; + + if (is_text) { + b.pos[0] += TEXT_GAP_H; + c.pos[1] += TEXT_GAP_V; + d.pos[0] += TEXT_GAP_H; + d.pos[1] += TEXT_GAP_V; + } else { + b.pos[0]++; + c.pos[1]++; + d.pos[0]++; + d.pos[1]++; + } + + cube[*i] = a2; + cube[*i + 1] = b; + cube[*i + 2] = c; + cube[*i + 3] = c; + cube[*i + 4] = b; + cube[*i + 5] = d; +} + void cubes_face(struct v3f *cube, int i, int x, int y, int z, int x2, int y2, int z2, int *j, int is_text, struct chunk dat, int ci, int a3) { struct v3i a = {{x, y, z}}; @@ -137,11 +169,12 @@ void cubes_free() { free(chunk_old); } void cubes_refresh(int x, int y, int z, struct chunk dat) { for (int i = 0; i < CHUNK_ALL; i++) { if (chunk_old[i].exists != 0 && abs(((int)chunk_old[i].x) - x) <= 1 && - abs(((int)chunk_old[i].y) - y) <= 1 && abs(((int)chunk_old[i].z) - z) <= 1) { + abs(((int)chunk_old[i].y) - y) <= 1 && + abs(((int)chunk_old[i].z) - z) <= 1) { chunk_old[i].exists = 0; } } - gen_save(dat); + gen_save(dat); } int cubes_vert(struct v3f *cube, struct v3f *text, struct v3f *cubeO, diff --git a/cubes.h b/cubes.h index eb2f12d..0f72abe 100644 --- a/cubes.h +++ b/cubes.h @@ -7,7 +7,7 @@ #define CHUNK_RADIUS_V 4 // 4 #define TEXT_GAP_H 1 / 6.0 -#define TEXT_GAP_V 1 / 6.0 +#define TEXT_GAP_V 1 / 7.0 #define CHUNK_DIAMETER_H (CHUNK_RADIUS_H * 2 + 1) #define CHUNK_DIAMETER_V (CHUNK_RADIUS_V * 2 + 1) @@ -15,6 +15,7 @@ #define BLOCK_ALL CHUNK_LENGTH *CHUNK_LENGTH *CHUNK_LENGTH #define CBLOCK_ALL BLOCK_ALL *CHUNK_ALL #define CBUF_ALL 2 +#define UI_ALL 1024 #define CTRI_ALL CBLOCK_ALL * 18 * sizeof(struct v3f) @@ -43,4 +44,6 @@ int cubes_vert(struct v3f *cube, struct v3f *text, struct v3f *cubeO, void cubes_free(); void cubes_refresh(int x, int y, int z, struct chunk dat); +void cubes_rect(struct v3f *cube, int *i, double x1, double x2, double y1, + double y2, int is_text, int text_x, int text_y); #endif \ No newline at end of file diff --git a/main.c b/main.c index 9f8b4c8..ea8174a 100644 --- a/main.c +++ b/main.c @@ -37,13 +37,16 @@ static const char *fragment_shader_text = "in vec3 v_pos_out;\n" "uniform sampler2D sampler_tex;\n" "uniform vec3 center;\n" + "uniform int use_shading;\n" "float dist;\n" "void main()\n" "{\n" //" color=vec4(v_tex.rg,0.5,0.5);\n" - " if (v_tex.x < 0.0 || v_tex.y < 0.0) { discard; }\n" + " if (v_tex.x < 0.0 || v_tex.y < 0.0 || texture(sampler_tex, v_tex).a " + "== 0.0) { discard; }\n" " dist = distance(v_pos_out, center + vec3(8,8,8))/65;\n" " if (dist > 1.0) { dist = 1.0; }\n" + " if (use_shading == 0) { dist = 0.0; }\n" " color=vec4(texture(sampler_tex, v_tex).rgb,1.0)*(1.0-(dist*dist)) + " "vec4(0.2,0.5,0.7,1.0)*(dist*dist);\n" "}\n"; @@ -144,8 +147,8 @@ int main(void) { struct v3f *cube = malloc(CTRI_ALL); struct v3f *text = malloc(CTRI_ALL); - struct v3f *cubeO = malloc(CTRI_ALL); - struct v3f *textO = malloc(CTRI_ALL); + struct v3f *cubeO = malloc(CTRI_ALL + UI_ALL * 18 * sizeof(struct v3f)); + struct v3f *textO = malloc(CTRI_ALL + UI_ALL * 18 * sizeof(struct v3f)); int bleh = (CHUNK_DIAMETER_H) * (CHUNK_DIAMETER_V); int *i2 = calloc(CHUNK_ALL, sizeof(int)); @@ -158,13 +161,13 @@ int main(void) { glGenBuffers(2, vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer[1]); - glBufferData(GL_ARRAY_BUFFER, CTRI_ALL, text, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, CTRI_ALL + UI_ALL* 18 * sizeof(struct v3f), textO, GL_STATIC_DRAW); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(struct v3f), (void *)0); glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer[0]); - glBufferData(GL_ARRAY_BUFFER, CTRI_ALL, cube, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, CTRI_ALL + UI_ALL * 18 * sizeof(struct v3f), cubeO, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(struct v3f), (void *)0); @@ -185,11 +188,12 @@ int main(void) { GLint tex_location = glGetUniformLocation(program, "sampler_tex"); GLint mvp_location = glGetUniformLocation(program, "mvp"); GLint center_location = glGetUniformLocation(program, "center"); + GLint use_shading = glGetUniformLocation(program, "use_shading"); unsigned char *pixels; int tx, ty, ch; - pixels = stbi_load("./test.png", &tx, &ty, &ch, 3); + pixels = stbi_load("./test.png", &tx, &ty, &ch, 4); glClearColor(0.2f, 0.5f, 0.7f, 1.0f); glEnable(GL_TEXTURE_2D); @@ -326,7 +330,7 @@ int main(void) { glBindTexture(GL_TEXTURE_2D, GL_TEXTURE0); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tx, ty, 0, GL_RGB, GL_UNSIGNED_BYTE, + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tx, ty, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -336,7 +340,35 @@ int main(void) { glBindVertexArray(vertex_array); + glUniform1i(use_shading, 1); + glDrawArrays(GL_TRIANGLES, 0, cube_count); + + glClear(GL_DEPTH_BUFFER_BIT); + + glUniform1i(use_shading, 0); + + int iz = CBLOCK_ALL * 18; + cubes_rect(cubeO, &iz, -0.5,0.5, -0.5, 0.5, 0, 0, 6); + cubes_rect(textO, &iz, -0.5, 0.5, -0.5, 0.5, 1, 0, 6); + + mat4x4_identity(v); + mat4x4_ortho(p, -ratio*15, ratio*15, -1.f*15, 1.f*15, 1.0f, -1.0f); + mat4x4_mul(mvp, p, v); + mat4x4_mul(mvp, mvp, m); + + glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat *)&mvp); + + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer[1]); + glBufferSubData(GL_ARRAY_BUFFER, CTRI_ALL, + (long)6 * sizeof(struct v3f), &textO[iz]); + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer[0]); + glBufferSubData(GL_ARRAY_BUFFER, CTRI_ALL, + (long)6 * sizeof(struct v3f), &cubeO[iz]); + + glBindVertexArray(vertex_array); + + glDrawArrays(GL_TRIANGLES, CBLOCK_ALL * 18, 6); } free(cube); diff --git a/test.png b/test.png index a6a41c895738ae8a712d174abb2ccc778aa0aca6..587bcdeb1984723b6856d0bef3f9252435c113e7 100644 GIT binary patch delta 3790 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