commit 13072c6043e79e12badb50ddf4451615fe328699
parent c93afd7ea41eaf47dbfb879f082bb47f40aa253e
Author: evenfri <evenfri@4plt.ch>
Date: Sun, 1 Nov 2026 22:59:23 +0800
feat: blocks, textures
Diffstat:
13 files changed, 159 insertions(+), 58 deletions(-)
diff --git a/assets/cobblestone.png b/assets/cobblestone.png
Binary files differ.
diff --git a/assets/dirt.png b/assets/dirt.png
Binary files differ.
diff --git a/assets/grass_side.png b/assets/grass_side.png
Binary files differ.
diff --git a/assets/grass_top.png b/assets/grass_top.png
Binary files differ.
diff --git a/assets/stone.png b/assets/stone.png
Binary files differ.
diff --git a/assets/terrain.png b/assets/terrain.png
Binary files differ.
diff --git a/blocks.c b/blocks.c
@@ -0,0 +1,75 @@
+#include "minecraft.h"
+#include "stb_image.h"
+
+Block blocks[] = {
+ { BLOCK_GRASS, {
+ "assets/grass_side.png", /* back */
+ "assets/grass_side.png", /* front */
+ "assets/grass_side.png", /* left */
+ "assets/grass_side.png", /* right */
+ "assets/dirt.png", /* bottom */
+ "assets/grass_top.png", /* top */
+ }},
+ { BLOCK_STONE, {
+ "assets/stone.png", "assets/stone.png",
+ "assets/stone.png", "assets/stone.png",
+ "assets/stone.png", "assets/stone.png",
+ }},
+ { BLOCK_DIRT, {
+ "assets/dirt.png", "assets/dirt.png",
+ "assets/dirt.png", "assets/dirt.png",
+ "assets/dirt.png", "assets/dirt.png",
+ }},
+};
+int block_count = sizeof(blocks) / sizeof(blocks[0]);
+
+static unsigned int *block_textures = NULL;
+
+static unsigned int load_texture(const char *path) {
+ unsigned int tex;
+ glGenTextures(1, &tex);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ int w, h, nrChannels;
+ stbi_set_flip_vertically_on_load(true);
+ unsigned char *data = stbi_load(path, &w, &h, &nrChannels, 0);
+ if (!data) {
+ printf("err: failed to load texture %s\n", path);
+ return 0;
+ }
+ GLenum fmt = (nrChannels == 4) ? GL_RGBA
+ : (nrChannels == 3) ? GL_RGB
+ : GL_RED;
+ glTexImage2D(GL_TEXTURE_2D, 0, fmt, w, h, 0, fmt,
+ GL_UNSIGNED_BYTE, data);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ stbi_image_free(data);
+ return tex;
+}
+
+void blocks_init(void) {
+ block_textures = malloc(sizeof(unsigned int) * block_count * FACE_COUNT);
+ for (int i = 0; i < block_count; i++)
+ for (int f = 0; f < FACE_COUNT; f++)
+ block_textures[i * FACE_COUNT + f] =
+ load_texture(blocks[i].texture_paths[f]);
+}
+
+void blocks_end(void) {
+ if (block_textures) {
+ glDeleteTextures(block_count * FACE_COUNT, block_textures);
+ free(block_textures);
+ block_textures = NULL;
+ }
+}
+
+unsigned int block_texture(unsigned int id, int face) {
+ if (face < 0 || face >= FACE_COUNT) return 0;
+ for (int i = 0; i < block_count; i++)
+ if (blocks[i].id == id)
+ return block_textures[i * FACE_COUNT + face];
+ return 0;
+}
diff --git a/camera.c b/camera.c
@@ -76,6 +76,14 @@ mat4 mat4_perspective(float fovy, float aspect, float znear, float zfar) {
return r;
}
+mat4 mat4_translate(float x, float y, float z) {
+ mat4 r = mat4_identity();
+ r.m[12] = x;
+ r.m[13] = y;
+ r.m[14] = z;
+ return r;
+}
+
void camera_process_keyboard(float dt) {
float v = camera.speed * dt;
diff --git a/dat.h b/dat.h
@@ -5,7 +5,6 @@
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
-// #define WINDOW_TITLE "Minecraft"
#define WINDOW_TITLE "window"
typedef struct { float x, y, z; } vec3;
@@ -24,8 +23,28 @@ typedef struct {
float fov;
} Camera;
+#define FACE_BACK 0
+#define FACE_FRONT 1
+#define FACE_LEFT 2
+#define FACE_RIGHT 3
+#define FACE_BOTTOM 4
+#define FACE_TOP 5
+#define FACE_COUNT 6
+
+typedef struct {
+ unsigned int id;
+ char *texture_paths[FACE_COUNT];
+} Block;
+
+#define BLOCK_GRASS 1
+#define BLOCK_STONE 2
+#define BLOCK_DIRT 3
+#define BLOCK_COBBLESTONE 4
+
extern GLFWwindow *Window;
extern unsigned int Shader;
extern Camera camera;
+extern Block blocks[];
+extern int block_count;
#endif /* DAT_H */
diff --git a/fns.h b/fns.h
@@ -18,8 +18,14 @@ mat4 camera_get_view(void);
mat4 mat4_identity(void);
mat4 mat4_perspective(float fovy, float aspect, float znear, float zfar);
+mat4 mat4_translate(float x, float y, float z);
void camera_process_keyboard(float dt);
void camera_process_mouse(float dx, float dy);
+void blocks_init(void);
+void blocks_end(void);
+unsigned int block_texture(unsigned int id, int face);
+void render_block(unsigned int block_id, vec3 pos);
+
#endif /* FNS_H */
diff --git a/mkfile b/mkfile
@@ -10,6 +10,7 @@ ofiles = \
render.$o \
shader.$o \
camera.$o \
+ blocks.$o \
main.$o
hfiles = \
diff --git a/render.c b/render.c
@@ -8,6 +8,7 @@ static int u_model, u_view, u_proj;
void render_init() {
float vertices[] = {
+ /* back */
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
@@ -15,6 +16,7 @@ void render_init() {
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
+ /* front */
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
@@ -22,20 +24,23 @@ void render_init() {
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
- -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
- -0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
- -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
- -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
- -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
- -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
+ /* left */
+ -0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
+ -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
+ -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
+ -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
+ -0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
+ -0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
- 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
- 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
- 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
- 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
- 0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
- 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
+ /* right */
+ 0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
+ 0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
+ 0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
+ 0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
+ 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
+ 0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
+ /* bottom */
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
@@ -43,17 +48,19 @@ void render_init() {
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
+ /* top */
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
- -0.5f, 0.5f, -0.5f, 0.0f, 1.0f};
+ -0.5f, 0.5f, -0.5f, 0.0f, 1.0f
+ };
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
- glBindVertexArray(VAO);
+ glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
@@ -69,65 +76,50 @@ void render_init() {
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- glGenTextures(1, &Texture);
- glBindTexture(GL_TEXTURE_2D, Texture);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
- int width, height, nrChannels;
- stbi_set_flip_vertically_on_load(true);
- unsigned char *data = stbi_load("terrain.png",
- &width, &height, &nrChannels, 0);
- if (data) {
- GLenum format;
- if (nrChannels == 1)
- format = GL_RED;
- else if (nrChannels == 3)
- format = GL_RGB;
- else if (nrChannels == 4)
- format = GL_RGBA;
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, format,
- GL_UNSIGNED_BYTE, data);
- glGenerateMipmap(GL_TEXTURE_2D);
- } else {
- printf("err: failed to load texture\n");
- }
- stbi_image_free(data);
-
glUseProgram(Shader);
glUniform1i(glGetUniformLocation(Shader, "texture1"), 0);
-
u_model = glGetUniformLocation(Shader, "model");
u_view = glGetUniformLocation(Shader, "view");
u_proj = glGetUniformLocation(Shader, "projection");
+ blocks_init();
+}
+
+void render_block(unsigned int block_id, vec3 pos) {
+ mat4 model = mat4_translate(pos.x, pos.y, pos.z);
+ glUniformMatrix4fv(u_model, 1, GL_FALSE, model.m);
+
+ for (int face = 0; face < FACE_COUNT; face++) {
+ unsigned int tex = block_texture(block_id, face);
+ if (!tex) continue;
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glDrawArrays(GL_TRIANGLES, face * 6, 6);
+ }
}
void render_frame() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, Texture);
-
glUseProgram(Shader);
- mat4 model = mat4_identity();
- mat4 view = camera_get_view();
+ mat4 view = camera_get_view();
mat4 projection = mat4_perspective(camera.fov,
- (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT,
- 0.1f, 100.0f);
-
- glUniformMatrix4fv(u_model, 1, GL_FALSE, model.m);
- glUniformMatrix4fv(u_view, 1, GL_FALSE, view.m);
- glUniformMatrix4fv(u_proj, 1, GL_FALSE, projection.m);
+ (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT,
+ 0.1f, 100.0f);
+ glUniformMatrix4fv(u_view, 1, GL_FALSE, view.m);
+ glUniformMatrix4fv(u_proj, 1, GL_FALSE, projection.m);
glBindVertexArray(VAO);
- glDrawArrays(GL_TRIANGLES, 0, 36);
+
+ for (int x = 0; x < 16; x++) {
+ for (int z = 0; z < 16; z++) {
+ render_block(BLOCK_GRASS, (vec3){ x, 0.0f, z });
+ render_block(BLOCK_DIRT, (vec3){ x, -1.0f, z });
+ render_block(BLOCK_STONE, (vec3){ x, -2.0f, z });
+ }
+ }
+
glfwPollEvents();
glfwSwapBuffers(Window);
}
diff --git a/terrain.png b/terrain.png
Binary files differ.