#include #include #include #include RenderBatch* texture_quad_batch = NULL; int max_textures; void setup_textures() { texture_quad_batch = create_texture_quad_batch(); glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_textures); if(max_textures > 32) max_textures = 32; } uint32_t load_texture(const char* path) { uint32_t id; glCreateTextures(GL_TEXTURE_2D, 1, &id); uint8_t default_texture[] = { 0, 0, 0, 255, 255, 0, 255, 255, 255, 0, 255, 255, 0, 0, 0, 255 }; int width = 2, height = 2, channels; uint8_t* pixels = stbi_load(path, &width, &height, &channels, 4); if(pixels) { glTextureParameteri(id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTextureParameteri(id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTextureParameteri(id, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTextureParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTextureStorage2D(id, 1, GL_RGBA8, width, height); glTextureSubImage2D(id, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); printf("[Texture %d, %s] Loaded successfully (%dx%d, %d channels)\n", id, path, width, height, channels); } else { glTextureParameteri(id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTextureParameteri(id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTextureParameteri(id, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTextureParameteri(id, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTextureStorage2D(id, 1, GL_RGBA8, width, height); glTextureSubImage2D(id, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, default_texture); printf("[Texture %d, %s] Failed to load image data: %s\n", id, path, stbi_failure_reason()); } return id; } vec2 texture_quad_texcoords[] = { { 0.0f, 1.0f }, { 0.0f, 0.0f }, { 1.0f, 0.0f }, { 0.0f, 1.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f } }; void draw_texture(Texture id, vec2 pos, vec2 size, vec4 tint) { mat4 transform = mat4Multiply( mat4Scale(size.x, size.y, 1.0f), mat4Translate(pos.x, pos.y, 0.0f)); draw_texture_trans(id, transform, tint); } void draw_texture_trans(Texture id, mat4 transform, vec4 tint) { assert(texture_quad_batch != NULL && "texture_quad_batch is null, was setup_textures() called?"); batch_draw_texture(texture_quad_batch, id, transform, tint); } void batch_draw_texture(RenderBatch* batch, Texture texture, mat4 transform, vec4 color) { TextureQuadBatchData* batch_data = (TextureQuadBatchData*)batch->data; uint32_t vertex_add = 6; if(batch_needs_flush(batch, vertex_add) || batch_data->texture_index >= max_textures) flush_batch(batch); uint32_t tex_id = batch_data->texture_index++; glBindTextureUnit(tex_id, texture); for(int i = 0; i < vertex_add; i++) { TextureQuadVertex* vertex = (TextureQuadVertex*)batch->vertex_ptr; vertex->Position = vec3Transform(quad_vertex_positions[i], transform); vertex->Tint = color; vertex->TexCoord = texture_quad_texcoords[i]; vertex->TexID = tex_id; batch->vertex_ptr = (TextureQuadVertex*)batch->vertex_ptr + 1; batch->vertex_count++; } } void texture_flush_callback(RenderBatch* batch) { TextureQuadBatchData* data = (TextureQuadBatchData*)batch->data; data->texture_index = 0; } RenderBatch* create_texture_quad_batch() { RenderBatch* texture_quad_batch = create_batch(sizeof(TextureQuadVertex), MAX_VERTICES); texture_quad_batch->shader = load_shader_program( compile_shader("assets/texture.vert", GL_VERTEX_SHADER), compile_shader("assets/texture.frag", GL_FRAGMENT_SHADER), 0); texture_quad_batch->data = new TextureQuadBatchData(); texture_quad_batch->flush_callback = &texture_flush_callback; batch_add_attrib(texture_quad_batch, (VertexAttrib){ .type = GL_FLOAT, .size = sizeof(float), .count = 3 }); // pos batch_add_attrib(texture_quad_batch, (VertexAttrib){ .type = GL_FLOAT, .size = sizeof(float), .count = 4 }); // color batch_add_attrib(texture_quad_batch, (VertexAttrib){ .type = GL_FLOAT, .size = sizeof(float), .count = 2 }); // texcoord batch_add_attrib(texture_quad_batch, (VertexAttrib){ .type = GL_FLOAT, .size = sizeof(float), .count = 1 }); // texid batch_bind_attribs(texture_quad_batch); return texture_quad_batch; }