diff --git a/images/container2_specular.png b/images/container2_specular.png
new file mode 100644
index 0000000..681bf6e
Binary files /dev/null and b/images/container2_specular.png differ
diff --git a/shaders/frag.glsl b/shaders/frag.glsl
index 32e9b20..4a6b971 100644
--- a/shaders/frag.glsl
+++ b/shaders/frag.glsl
@@ -2,7 +2,7 @@
 
 struct Material {
   sampler2D diffuse;
-  vec3 specular;
+  sampler2D specular;
   float shininess;
 };
 
@@ -35,7 +35,7 @@ void main() {
   vec3  diff_tex           = vec3(texture(material.diffuse, uv_coords));
   vec3  ambient            = light.ambient * diff_tex;
   vec3  diffuse            = light.diffuse * (diff * diff_tex);
-  vec3  specular           = light.specular * (spec * material.specular);
+  vec3  specular           = light.specular * (spec * vec3(texture(material.specular, uv_coords)));
 
   color = vec4(ambient + diffuse + specular, 1.0);
 };
diff --git a/src/main.cc b/src/main.cc
index ec0c26a..2d75f87 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -66,6 +66,20 @@ class Shader {
     static const char *get_shader_type_string(GLenum shader_type);
 };
 
+class Texture2D {
+  public:
+    Texture2D(const char *filename, GLint texture_unit);
+    ~Texture2D();
+    void activate();
+    int width;
+    int height;
+    int channels;
+  private:
+    GLuint texture;
+    GLint texture_unit;
+    GLint format;
+};
+
 int main() {
   if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
     return EXIT_CODE_SDL_INIT_FAILED;
@@ -181,28 +195,10 @@ int main() {
   Shader main_shader  {"shaders/vert.glsl", "shaders/frag.glsl"};
   Shader light_shader {"shaders/vert.glsl", "shaders/light_frag.glsl"};
 
-  int width, height, channels;
-  uint8_t *diffuse_map   = stbi_load("images/container2.png", &width, &height, &channels, 0);
-  GLuint diffuse_texture = 0; 
-  if (diffuse_map) {
-    glGenTextures(1, &diffuse_texture);
-
-    glActiveTexture(GL_TEXTURE0);
-    glBindTexture(GL_TEXTURE_2D, diffuse_texture);
-
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, diffuse_map);
-    glGenerateMipmap(GL_TEXTURE_2D);
-
-    main_shader.set_int("material.diffuse", 0);
-
-    glBindTexture(GL_TEXTURE_2D, 0);
-    stbi_image_free(diffuse_map);
-  }
+  Texture2D diffuse_map  = Texture2D("images/container2.png", GL_TEXTURE0);
+  Texture2D specular_map = Texture2D("images/container2_specular.png", GL_TEXTURE1);
+  main_shader.set_int("material.diffuse", 0);
+  main_shader.set_int("material.specular", 1);
 
   const float camera_speed   = 25.0f;
   glm::vec3 camera_position  = glm::vec3(-2.0f, 0.0f, 6.0f);
@@ -323,8 +319,8 @@ int main() {
     main_shader.set_vec3("light.diffuse", light_diffuse);
     main_shader.set_mat4("model", model);
     main_shader.set_mat3("normal_mat", normal_mat);
-    glActiveTexture(GL_TEXTURE0);
-    glBindTexture(GL_TEXTURE_2D, diffuse_texture);
+    diffuse_map.activate();
+    specular_map.activate();
     glBindVertexArray(vao);
     glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, (void *)0);
 
@@ -477,3 +473,34 @@ const char *Shader::get_shader_type_string(GLenum shader_type) {
 
   return output;
 }
+
+Texture2D::Texture2D(const char *filename, GLint texture_unit) : texture_unit(texture_unit) {
+  uint8_t *image = stbi_load(filename, &width, &height, &channels, 0);
+  if (!image) {
+    return;
+  }
+
+  // TODO (Abdelrahman): This doesn't handle all formats
+  format = channels > 3 ? GL_RGBA : GL_RGB;
+
+  glGenTextures(1, &texture);
+  activate();
+
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+  glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, image);
+  glGenerateMipmap(GL_TEXTURE_2D);
+
+  glBindTexture(GL_TEXTURE_2D, 0);
+  stbi_image_free(image);
+}
+
+Texture2D::~Texture2D() {}
+
+void Texture2D::activate() {
+  glActiveTexture(texture_unit);
+  glBindTexture(GL_TEXTURE_2D, texture);
+}