diff --git a/include/window.h b/include/window.h
index a85f1e9..eaaad2e 100644
--- a/include/window.h
+++ b/include/window.h
@@ -47,6 +47,12 @@ bool add_event_listener(window_t *wnd, void *obj, event_listener_t listener);
 bool add_renderer_func(window_t *wnd, void *obj, render_func_t func);
 void fill_rect(const window_t *wnd, const render_rect_t *rect, colour_t colour);
 void draw_rect(const window_t *wnd, const render_rect_t *rect, colour_t colour);
+SDL_Texture *load_texture(const window_t *wnd, const char *path);
+void unload_texture(SDL_Texture *texture);
+void get_texture_size(SDL_Texture *texture, i32 *w, i32 *h);
+void render_texture(const window_t *wnd, SDL_Texture *texture,
+                    const render_rect_t *src_rect,
+                    const render_rect_t *dst_rect);
 bool aabb(u64 x, u64 y, const render_rect_t *rect);
 
 #endif // !WINDOW_H
diff --git a/src/window.c b/src/window.c
index dd3db67..2bce6f6 100644
--- a/src/window.c
+++ b/src/window.c
@@ -2,6 +2,7 @@
 #include "SDL_rect.h"
 #include "SDL_render.h"
 #include <SDL2/SDL.h>
+#include <SDL2/SDL_image.h>
 #include <SDL_events.h>
 
 void handle_quit(const window_t *wnd, void *obj, const SDL_Event *ev);
@@ -11,6 +12,8 @@ bool open_window(window_t *wnd, const char *title, u64 w, u64 h,
                  colour_t bg_colour) {
   SDL_Init(SDL_INIT_EVERYTHING);
 
+  IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF);
+
   wnd->window =
       SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w,
                        h, SDL_WINDOW_SHOWN);
@@ -86,6 +89,8 @@ void close_window(window_t *wnd) {
     SDL_DestroyWindow(wnd->window);
   }
 
+  IMG_Quit();
+
   SDL_Quit();
 }
 
@@ -137,6 +142,35 @@ void draw_rect(const window_t *wnd, const render_rect_t *rect,
   SDL_RenderDrawRect(wnd->renderer, &dest);
 }
 
+SDL_Texture *load_texture(const window_t *wnd, const char *path) {
+  return IMG_LoadTexture(wnd->renderer, path);
+}
+
+void unload_texture(SDL_Texture *texture) { SDL_DestroyTexture(texture); }
+
+void get_texture_size(SDL_Texture *texture, i32 *w, i32 *h) {
+  SDL_QueryTexture(texture, NULL, NULL, w, h);
+}
+
+void render_texture(const window_t *wnd, SDL_Texture *texture,
+                    const render_rect_t *src_rect,
+                    const render_rect_t *dst_rect) {
+  SDL_Rect src = {
+      .x = src_rect ? src_rect->x : 0,
+      .y = src_rect ? src_rect->y : 0,
+      .w = src_rect ? src_rect->width : 0,
+      .h = src_rect ? src_rect->height : 0,
+  };
+  SDL_Rect dst = {
+      .x = dst_rect ? dst_rect->x : 0,
+      .y = dst_rect ? dst_rect->y : 0,
+      .w = dst_rect ? dst_rect->width : 0,
+      .h = dst_rect ? dst_rect->height : 0,
+  };
+
+  SDL_RenderCopy(wnd->renderer, texture, src_rect ? &src : NULL, &dst);
+}
+
 bool aabb(u64 x, u64 y, const render_rect_t *rect) {
   return x >= rect->x && y >= rect->y && x < rect->x + rect->width &&
          y < rect->y + rect->height;
@@ -144,9 +178,9 @@ bool aabb(u64 x, u64 y, const render_rect_t *rect) {
 
 void handle_quit(const window_t *wnd, void *obj, const SDL_Event *ev) {
   if (ev->type == SDL_QUIT) {
-    window_t *wnd = obj;
+    window_t *window = (window_t *)obj;
 
-    wnd->running = false;
+    window->running = false;
   }
 }