diff --git a/.gitignore b/.gitignore index c55a259..0e53370 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .godot/ /Assets/ /game/tenchu +/game/.idea/ diff --git a/Godot/Scenes/Player.tscn b/Godot/Scenes/Player.tscn index b1f3ea9..4e3ee85 100644 --- a/Godot/Scenes/Player.tscn +++ b/Godot/Scenes/Player.tscn @@ -47,84 +47,6 @@ tracks/2/keys = { "values": [0, 1, 2, 3, 4, 5, 5, 6, 7] } -[sub_resource type="Animation" id="Animation_1l7dh"] -length = 0.001 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath(".:frame") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [0] -} -tracks/1/type = "value" -tracks/1/imported = false -tracks/1/enabled = true -tracks/1/path = NodePath(".:texture") -tracks/1/interp = 1 -tracks/1/loop_wrap = true -tracks/1/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [ExtResource("1_h6xei")] -} -tracks/2/type = "value" -tracks/2/imported = false -tracks/2/enabled = true -tracks/2/path = NodePath(".:hframes") -tracks/2/interp = 1 -tracks/2/loop_wrap = true -tracks/2/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [10] -} - -[sub_resource type="Animation" id="Animation_dl063"] -resource_name = "Walk" -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath(".:texture") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [ExtResource("1_h6xei")] -} -tracks/1/type = "value" -tracks/1/imported = false -tracks/1/enabled = true -tracks/1/path = NodePath(".:hframes") -tracks/1/interp = 1 -tracks/1/loop_wrap = true -tracks/1/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [8] -} -tracks/2/type = "value" -tracks/2/imported = false -tracks/2/enabled = true -tracks/2/path = NodePath(".:frame") -tracks/2/interp = 1 -tracks/2/loop_wrap = true -tracks/2/keys = { -"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6), -"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1), -"update": 1, -"values": [0, 1, 2, 3, 4, 5, 6] -} - [sub_resource type="Animation" id="Animation_2yfkp"] resource_name = "Jump" tracks/0/type = "value" @@ -164,6 +86,45 @@ tracks/2/keys = { "values": [0, 1, 2] } +[sub_resource type="Animation" id="Animation_1l7dh"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:frame") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [0] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath(".:texture") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [ExtResource("1_h6xei")] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath(".:hframes") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [10] +} + [sub_resource type="Animation" id="Animation_oejr4"] resource_name = "Run" length = 0.75 @@ -204,6 +165,45 @@ tracks/2/keys = { "values": [0, 1, 2, 3, 4, 5, 6, 7] } +[sub_resource type="Animation" id="Animation_dl063"] +resource_name = "Walk" +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:texture") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [ExtResource("1_h6xei")] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath(".:hframes") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [8] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath(".:frame") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6), +"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1), +"update": 1, +"values": [0, 1, 2, 3, 4, 5, 6] +} + [sub_resource type="AnimationLibrary" id="AnimationLibrary_6srtp"] _data = { "Idle": SubResource("Animation_vrt4p"), diff --git a/game/Makefile b/game/Makefile index 375b380..2ca327b 100644 --- a/game/Makefile +++ b/game/Makefile @@ -1,8 +1,8 @@ P=tenchu -OBJECTS= +OBJECTS=-l:libcglm.so CFLAGS=-g -Wall -Wextra -O0 -LDLIBS=-lglfw -lOpenGL -INCLUDES=-I./libs/glad/include/ +LDLIBS=-lglfw -lOpenGL -lm +INCLUDES=-Ilibs/glad/include/ -Ilibs/ CC=gcc RM=rm -vf @@ -18,3 +18,5 @@ run: build clean: $(RM) $(P) +.PHONY: all +all: build diff --git a/game/README.org b/game/README.org index db0f386..155bc4a 100644 --- a/game/README.org +++ b/game/README.org @@ -19,3 +19,4 @@ gcc -Ilibs/glad/include/ -c libs/glad/src/glad.c * Terms VBO - vertex buffer objects VAO - vertex array object +EBO - element buffer objects diff --git a/game/assets/idle.png b/game/assets/idle.png new file mode 100644 index 0000000..4cf0c43 Binary files /dev/null and b/game/assets/idle.png differ diff --git a/game/assets/jump.png b/game/assets/jump.png new file mode 100644 index 0000000..dff105c Binary files /dev/null and b/game/assets/jump.png differ diff --git a/game/assets/land.png b/game/assets/land.png new file mode 100644 index 0000000..2c24d6f Binary files /dev/null and b/game/assets/land.png differ diff --git a/game/assets/run.png b/game/assets/run.png new file mode 100644 index 0000000..615b222 Binary files /dev/null and b/game/assets/run.png differ diff --git a/game/assets/walk.png b/game/assets/walk.png new file mode 100644 index 0000000..653bd2f Binary files /dev/null and b/game/assets/walk.png differ diff --git a/game/lib.h b/game/lib.h new file mode 100644 index 0000000..c9261f0 --- /dev/null +++ b/game/lib.h @@ -0,0 +1,117 @@ +#ifndef TENCHU_LIB_H +#define TENCHU_LIB_H + +#include + +void checkCode(int code, char* errorMsg) { + if (code < 0) { + fprintf(stderr, "Application Error %i: %s\n", code, errorMsg); + exit(1); + } +} + +void* checkPtr(void *ptr, char* errorMsg) { + if (ptr == NULL) { + fprintf(stderr, "Application Error: %s\n", errorMsg); + exit(1); + } + return ptr; +} + +void checkShader(unsigned int shader, int statusFlag, char* actionName) { + int success; + glGetShaderiv(shader, statusFlag, &success); + if (success < 0) { + fprintf(stderr, "%s Error %i\n", actionName, success); + exit(1); + } +} + +char* loadText(char* path) { + char* buffer = NULL; + long length; + FILE* f = fopen(path, "rb"); + if (f) { + fseek(f, 0, SEEK_END); + length = ftell(f); + fseek(f, 0, SEEK_SET); + buffer = calloc(length, sizeof(char)); + if (buffer) { + fread(buffer, 1, length, f); + } + fclose(f); + } + return buffer; +} + +void checkCompileErrors(unsigned int object, char* type) +{ + int success; + char infoLog[1024]; + if (strcmp("PROGRAM", type)) + { + glGetShaderiv(object, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(object, 1024, NULL, infoLog); + fprintf(stderr, "| ERROR::SHADER: Compile-time error: Type: %s \n %s\n", type, infoLog); + } + } + else + { + glGetProgramiv(object, GL_LINK_STATUS, &success); + if (!success) + { + glGetProgramInfoLog(object, 1024, NULL, infoLog); + fprintf(stderr, "| ERROR::Shader: Link-time error: Type: %s \n %s\n", type, infoLog); + } + } +} + +unsigned int compileShaderProgram(char* vertSrcPath, char* fragSrcPath, char* geoSrcPath) { + unsigned int vertShader, fragShader, geoShader; + + char* vertSrc = loadText(vertSrcPath); + vertShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertShader, 1, (const GLchar* const*)&vertSrc, NULL); + glCompileShader(vertShader); + checkCompileErrors(vertShader, "VERTEX"); + + char* fragSrc = loadText(fragSrcPath); + + fragShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragShader, 1, (const GLchar* const*)&fragSrc, NULL); + glCompileShader(fragShader); + checkCompileErrors(fragShader, "FRAGMENT"); + + char* geoSrc = NULL; + if (geoSrcPath != NULL) { + geoSrc = loadText(geoSrcPath); + geoShader = glCreateShader(GL_GEOMETRY_SHADER); + glShaderSource(geoShader, 1, (const GLchar* const*)&geoSrc, NULL); + glCompileShader(geoShader); + checkCompileErrors(geoShader, "GEOMETRY"); + } + + unsigned int program = glCreateProgram(); + glAttachShader(program, vertShader); + glAttachShader(program, fragShader); + if (geoSrcPath != NULL) { + glAttachShader(program, geoShader); + } + + glLinkProgram(program); + checkCompileErrors(program, "PROGRAM"); + + glDeleteShader(vertShader); + glDeleteShader(fragShader); + free(vertSrc); + free(fragSrc); + if (geoSrc != NULL) { + free(geoSrc); + } + + return program; +} + +#endif diff --git a/game/shaders/main.frag b/game/shaders/main.frag new file mode 100644 index 0000000..1b565a4 --- /dev/null +++ b/game/shaders/main.frag @@ -0,0 +1,10 @@ +#version 330 core +in vec2 TexCoords; +out vec4 color; + +uniform sampler2D image; +uniform vec3 spriteColor; + +void main() { + color = vec4(spriteColor, 1.0f) * texture(image, TexCoords); +} diff --git a/game/shaders/main.vert b/game/shaders/main.vert new file mode 100644 index 0000000..7afc638 --- /dev/null +++ b/game/shaders/main.vert @@ -0,0 +1,13 @@ +#version 330 core +layout (location = 0) in vec4 vertex; + +out vec2 TexCoords; + +uniform mat4 model; +uniform mat4 projection; + +void main() { + TexCoords = vertex.zw; + // gl_Position = model * vec4(vertex.xy, 0.0, 1.0); + gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0); +} diff --git a/game/tenchu.c b/game/tenchu.c index f2de21b..ca5373c 100644 --- a/game/tenchu.c +++ b/game/tenchu.c @@ -3,82 +3,62 @@ #include #include "glad/glad.h" #include +#include "cglm/cglm.h" +#include "lib.h" + +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + +#define PI 3.14159f int SCREEN_WIDTH = 1024; int SCREEN_HEIGHT = 768; -void checkCode(int code, char* errorMsg) { - if (code < 0) { - fprintf(stderr, "Application Error %i: %s\n", code, errorMsg); - exit(1); - } -} +struct State { + float camX; + float camY; + float px; + float py; +}; -void* checkPtr(void *ptr, char* errorMsg) { - if (ptr == NULL) { - fprintf(stderr, "Application Error: %s\n", errorMsg); - exit(1); - } - return ptr; -} - -void checkShader(unsigned int shader, int statusFlag, char* actionName) { - int success; - glGetShaderiv(shader, statusFlag, &success); - if (success < 0) { - fprintf(stderr, "%s Error %i\n", actionName, success); - exit(1); - } -} - -void framebuffer_size_callback(GLFWwindow* window, int width, int height) -{ +void framebuffer_size_callback(GLFWwindow* window, int width, int height) { (void)window; glViewport(0, 0, width, height); SCREEN_WIDTH = width; SCREEN_HEIGHT = height; } -void processInput(GLFWwindow *window) -{ - if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) +void processInput(GLFWwindow *window, struct State* state) { + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); -} + } -const char* vertSrc = - "#version 330 core\n" - "layout (location = 0) in vec3 aPos;\n" - "\n" - "void main()\n" - "{\n" - " gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n" - "}\n"; - -unsigned int compileVertShader() { - unsigned int vertexShader; - vertexShader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertexShader, 1, &vertSrc, NULL); - glCompileShader(vertexShader); - checkShader(vertexShader, GL_COMPILE_STATUS, "Vertex Shader"); - return vertexShader; -} - -const char* fragSrc = - "#version 330 core\n" - "out vec4 FragColor;\n" - "\n" - "void main()\n" - "{\n" - " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" - "}\n"; - -unsigned int compileFragShader() { - unsigned int fragmentShader; - fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragmentShader, 1, &fragSrc, NULL); - glCompileShader(fragmentShader); - checkShader(fragmentShader, GL_COMPILE_STATUS, "Fragment Shader"); - return fragmentShader; + float amount = 1.0f; + if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) { + state->camY -= amount; + } + if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) { + state->camY += amount; + } + if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) { + state->camX -= amount; + } + if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) { + state->camX += amount; + } + amount = 1.1f; + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { + state->py -= amount; + } + if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { + state->py += amount; + } + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { + state->px -= amount; + } + if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { + state->px += amount; + } } int main(void) { @@ -101,45 +81,143 @@ int main(void) { glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); - unsigned int vertexShader = compileVertShader(); - unsigned int fragmentShader = compileFragShader(); - unsigned int shaderProgram = glCreateProgram(); - glAttachShader(shaderProgram, vertexShader); - glAttachShader(shaderProgram, fragmentShader); - glLinkProgram(shaderProgram); - checkShader(vertexShader, GL_LINK_STATUS, "Shader Program"); + unsigned int shaderProgram = + compileShaderProgram("shaders/main.vert", "shaders/main.frag", NULL); - glDeleteShader(vertexShader); - glDeleteShader(fragmentShader); + glEnable(GL_FRAMEBUFFER_SRGB); + glDisable(0x809D); + glEnable(GL_BLEND); + // CHECK: Do we need this? + // glEnable(GL_DEPTH_TEST); + // glDepthFunc(GL_GREATER); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); float vertices[] = { - -0.5f, -0.5f, 0.0f, - 0.5f, -0.5f, 0.0f, - 0.0f, 0.5f, 0.0f + // pos // tex + 0.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + + 0.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 0.0f, 1.0f, 0.0f }; unsigned int VBO, VAO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); - glBindVertexArray(VAO); + glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); - glEnableVertexAttribArray(0); + glBindVertexArray(VAO); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); + mat4 camOrtho; + glm_ortho(0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, -1.0f, 1.0f, camOrtho); + + unsigned int textureID; + int width, height, channels; + char* data = (char*)stbi_load("assets/idle.png", &width, &height, &channels, 4); + if (data == NULL) { + fprintf(stderr, "Could not load texture"); + return -1; + } + + glGenTextures(1, &textureID); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textureID); + // // set Texture wrap and filter modes + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, data); + + stbi_image_free(data); + // glBindTexture(GL_TEXTURE_2D, 0); + + // float deltaTime = 0.0f; + // float lastFrame = 0.0f; + struct State state = {0}; while (!glfwWindowShouldClose(window)) { - processInput(window); + + float currentFrame = glfwGetTime(); + // deltaTime = currentFrame - lastFrame; + // lastFrame = currentFrame; + + processInput(window, &state); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(shaderProgram); + + // vec4 vec = {1.0f, 0.0f, 0.0f, 1.0f}; + mat4 model; + mat4 projection; + glm_mat4_identity(model); + glm_mat4_identity(projection); + // glm_ortho(0.0f, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0f, -1.0f, 1.0f, projection); + // glm_perspective(60.0f, 3.0f / 4.0f , 1.0f, 200.0f, projection); + // glm_scale(model, (vec3){4.0f, 0.5f, 1.0f}); + float pivotx = 0.5f; + float pivoty = 0.5f; + glm_translate(model, (vec3){pivotx, pivoty, 0.0f}); + glm_rotate(model, currentFrame, (vec3){0.0f, 0.0f, 1.0f}); + glm_scale(model, (vec3){400.0f, 50.0f, 0.0f}); + glm_translate(model, (vec3){-pivotx, -pivoty, 0.0f}); + // glm_translate(model, (vec3){-255.5f, 0.f, 0.0f}); + // glm_translate(model, (vec3){200.0f, 200.0f, 0.0f}); + // glm_translate(model, (vec3){-1.8f, -2.0f, 0.0f}); + // glm_translate(model, (vec3){-1.8f, -2.0f, 0.0f}); + // glm_translate(); + // printf("X:%f Y:%f Z:%f\n", projection[3][0], projection[3][1], projection[3][2]); + + float worldUnitSizeInPixels = 2; // Desired size of a 1x1 area on the screen + float hw = (SCREEN_WIDTH / 2.f) / worldUnitSizeInPixels; + float hh = (SCREEN_HEIGHT / 2.f) / worldUnitSizeInPixels; + + glm_ortho(-hw, hw, hh, -hh, -1.0f, 1.0f, projection); + glm_translate(projection, (vec3){0.0f + state.camX, 0.0f + state.camY, 0.0f}); + // float proj = ortho(-hw, hw, -hh, hh, ...); + // // or + // float proj = ortho(-hw, hw, hh, -hh, ...); + + mat4 final; + glm_mat4_identity(final); + glm_mat4_mul(final, projection, final); + glm_mat4_mul(final, model, final); + + // printf("X:%f Y:%f Z:%f\n", final[3][0], final[3][1], final[3][2]); + + GLint location = glGetUniformLocation(shaderProgram, "model"); + glUniformMatrix4fv(location, 1, GL_FALSE, model[0]); + + location = glGetUniformLocation(shaderProgram, "projection"); + glUniformMatrix4fv(location, 1, GL_FALSE, projection[0]); + // glm_mat4_identity(model); + + location = glGetUniformLocation(shaderProgram, "spriteColor"); + glUniform3f(location, 1.0f, 1.0f, 1.0f); + + glUniform1i(glGetUniformLocation(shaderProgram, "image"), 0); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textureID); + glBindVertexArray(VAO); - glDrawArrays(GL_TRIANGLES, 0, 3); + // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + glDrawArrays(GL_TRIANGLES, 0, 6); + // glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + // glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); glfwSwapBuffers(window); glfwPollEvents();