diff --git a/animation.h b/animation.h new file mode 100644 index 0000000..459a9d9 --- /dev/null +++ b/animation.h @@ -0,0 +1,24 @@ +#pragma once + +typedef struct { + char* name; + byte* imgData; + u16 animCount; + u16 width; + u16 height; +} SpriteSheet; + +typedef struct { + char* name; + f32 posX; + f32 posY; + u16 rows; + u16 cols; + u16 width; + u16 height; +} Animation; + +typedef struct { + float timeElapsed; + int frame; +} AnimationPlayback; diff --git a/assets/player.png b/assets/player.png new file mode 100644 index 0000000..8809f43 Binary files /dev/null and b/assets/player.png differ diff --git a/lib.h b/lib.h index 0def033..3c39aeb 100644 --- a/lib.h +++ b/lib.h @@ -8,6 +8,7 @@ typedef uint8_t u8; // typedef char16_t c16; typedef uint16_t u16; +typedef int16_t i16; typedef int32_t b32; typedef int32_t i32; typedef uint32_t u32; @@ -19,16 +20,6 @@ typedef char byte; typedef ptrdiff_t size; typedef size_t usize; -typedef struct Animation { - char* name; - u16 x_pos; - u16 y_pos; - u16 rows; - u16 cols; - u16 width; - u16 height; -} Animation; - typedef struct s8 { u8* data; usize size; diff --git a/main.c b/main.c index b181208..35bffb2 100644 --- a/main.c +++ b/main.c @@ -7,6 +7,7 @@ #include "lib.h" #include "stb_image.h" #include "rendering.h" +#include "animation.h" #include "libcyaml/include/cyaml/cyaml.h" #define PI 3.14159f @@ -20,6 +21,7 @@ typedef struct State { float px; float py; int spriteY; + int currentAnim; } State; void framebuffer_size_callback(GLFWwindow* window, int width, int height) { @@ -35,11 +37,17 @@ void processInput(GLFWwindow *window, State* state) { } float amount = 1.0f; - if (glfwGetKey(window, GLFW_KEY_J) == GLFW_RELEASE) { - state->spriteY -= 1; + if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS) { + state->currentAnim = 0; } - if (glfwGetKey(window, GLFW_KEY_K) == GLFW_RELEASE) { - state->spriteY += 1; + if (glfwGetKey(window, GLFW_KEY_2) == GLFW_PRESS) { + state->currentAnim = 1; + } + if (glfwGetKey(window, GLFW_KEY_3) == GLFW_PRESS) { + state->currentAnim = 2; + } + if (glfwGetKey(window, GLFW_KEY_4) == GLFW_PRESS) { + state->currentAnim = 3; } if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) { state->camY -= amount; @@ -53,7 +61,7 @@ void processInput(GLFWwindow *window, State* state) { if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) { state->camX += amount; } - amount = 1.1f; + amount = 2.1f; if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { state->py -= amount; } @@ -128,13 +136,63 @@ int main(void) { unsigned int textureID; int width, height, channels; - char* data = (char*)stbi_load("assets/player.png", &width, &height, &channels, 4); + byte* data = (char*)stbi_load("assets/player.png", &width, &height, &channels, 4); // char* data = (char*)stbi_load("imports/sprites/player/idle.png", &width, &height, &channels, 4); if (data == NULL) { fprintf(stderr, "Could not load texture\n"); return -1; } + SpriteSheet spriteSheet = { + .name = "player", + .imgData = data, + .animCount = 4, + .width = width, + .height = height, + }; + + Animation idle = { + .name = "idle", + .posX = 0, + .posY = 0, + .rows = 1, + .cols = 10, + .width = 48, + .height = 48, + }; + + Animation run = { + .name = "run", + .posX = 0, + .posY = 48 * 3, + .rows = 1, + .cols = 8, + .width = 48, + .height = 48, + }; + + Animation jump = { + .name = "jump", + .posX = 0, + .posY = 48, + .rows = 1, + .cols = 3, + .width = 48, + .height = 48, + }; + + Animation land = { + .name = "land", + .posX = 0, + .posY = 48 * 2, + .rows = 1, + .cols = 9, + .width = 48, + .height = 48, + }; + + Animation playerAnims[4] = {idle, run, jump, land}; + glGenTextures(1, &textureID); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID); @@ -169,7 +227,6 @@ int main(void) { glUseProgram(shaderProgram); - // vec4 vec = {1.0f, 0.0f, 0.0f, 1.0f}; mat4 model; mat4 projection; glm_mat4_identity(model); @@ -179,10 +236,8 @@ int main(void) { glm_translate(model, (vec3){state.px, state.py, 0.0f}); glm_translate(model, (vec3){0.f, 0.f, 0.0f}); glm_translate(model, (vec3){pivotx, pivoty, 0.0f}); - // glm_rotate(model, currentFrame, (vec3){0.0f, 0.0f, 1.0f}); glm_scale(model, (vec3){100.0f, 100.0f, 0.0f}); glm_translate(model, (vec3){-pivotx, -pivoty, 0.0f}); - // 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; @@ -197,26 +252,56 @@ int main(void) { location = glGetUniformLocation(shaderProgram, "projection"); glUniformMatrix4fv(location, 1, GL_FALSE, projection[0]); - location = glGetUniformLocation(shaderProgram, "spriteColor"); - glUniform3f(location, 1.0f, 1.0f, 1.0f); + glUniform1i(glGetUniformLocation(shaderProgram, "image"), 0); + + Animation anim = playerAnims[state.currentAnim]; elapsed += deltaTime; if (elapsed > 0.1f) { frameCount += 1; - if (frameCount > 9) { + if (frameCount >= anim.cols) { frameCount = 0; } elapsed = 0.0f; } - location = glGetUniformLocation(shaderProgram, "spriteX"); - float spriteX = (float)frameCount / 10; - glUniform1f(location, spriteX); + location = glGetUniformLocation(shaderProgram, "posX"); + glUniform1f(location, anim.posX); - location = glGetUniformLocation(shaderProgram, "spriteY"); - glUniform1f(location, state.camY); + location = glGetUniformLocation(shaderProgram, "posY"); + glUniform1f(location, anim.posY); + + location = glGetUniformLocation(shaderProgram, "animRow"); + glUniform1i(location, frameCount); + + // We don't animate on the Y axis yet + location = glGetUniformLocation(shaderProgram, "animCol"); + glUniform1i(location, 0); + + location = glGetUniformLocation(shaderProgram, "rows"); + glUniform1i(location, anim.rows); + + location = glGetUniformLocation(shaderProgram, "cols"); + glUniform1i(location, anim.cols); + + location = glGetUniformLocation(shaderProgram, "spriteWidth"); + glUniform1i(location, anim.width); + + location = glGetUniformLocation(shaderProgram, "spriteHeight"); + glUniform1i(location, anim.height); + + location = glGetUniformLocation(shaderProgram, "atlasWidth"); + glUniform1i(location, spriteSheet.width); + + location = glGetUniformLocation(shaderProgram, "atlasHeight"); + glUniform1i(location, spriteSheet.height); + + // location = glGetUniformLocation(shaderProgram, "spriteColor"); + // glUniform3f(location, 1.0f, 1.0f, 1.0f); + + // SpriteSheet spriteSheet = spriteSheet; + // printf("%i\n", state.currentAnim); - glUniform1i(glGetUniformLocation(shaderProgram, "image"), 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID); diff --git a/shaders/main.frag b/shaders/main.frag index 72d9912..5fba5a9 100644 --- a/shaders/main.frag +++ b/shaders/main.frag @@ -3,20 +3,33 @@ in vec2 TexCoords; out vec4 color; uniform sampler2D image; + +uniform float posX; +uniform float posY; +uniform int animRow; +uniform int animCol; +uniform int rows; +uniform int cols; +uniform int spriteWidth; +uniform int spriteHeight; +uniform int atlasWidth; +uniform int atlasHeight; + +// Unused for now uniform vec3 spriteColor; -uniform float spriteX; -uniform float spriteY; void main() { - float r = (48.0 / 512.0); - float x = TexCoords.x * r + (int(spriteX * 10)) * r; - // float y = TexCoords.y * r + (int(spriteY * 10)) * r; - float y = TexCoords.y * r; + float rw = (float(spriteWidth) / float(atlasWidth)); + float rh = (float(spriteHeight) / float(atlasHeight)); + float x = TexCoords.x * rw + posX + animRow * rw; + float y = TexCoords.y * rh + (posY / float(atlasHeight)) + animCol * rh; float minb = 0.005; float maxb = 0.995; - if (TexCoords.x <= minb || TexCoords.x >= maxb - || TexCoords.y <= minb || TexCoords.y >= maxb) { + bool drawDebugBorders = + TexCoords.x <= minb || TexCoords.x >= maxb + || TexCoords.y <= minb || TexCoords.y >= maxb; + if (drawDebugBorders) { color = vec4(1,0,0,1); } else { color = texture(image, vec2(x, y));