From ad75604ec79d70d328595f114e65bac80db9999f Mon Sep 17 00:00:00 2001
From: sanine-a <sanine.not@pm.me>
Date: Sat, 31 Oct 2020 18:48:20 -0500
Subject: add additional texture types and refactor texture setup and loading

---
 demo/FPSCamera.lua    |   7 +++
 demo/main.lua         |  10 ++-
 src/texture/texture.c | 171 ++++++++++++++++++++++++++++++++++++++------------
 src/texture/texture.h |  81 ++++++++++++++++++++++--
 src/window/window.c   |   3 +
 5 files changed, 225 insertions(+), 47 deletions(-)

diff --git a/demo/FPSCamera.lua b/demo/FPSCamera.lua
index 7ee3cf8..7c33242 100644
--- a/demo/FPSCamera.lua
+++ b/demo/FPSCamera.lua
@@ -42,6 +42,13 @@ function camera:update(dt)
    
    movement:setAt(1, 0)
    movement:normalize()
+
+   if honey.input.key.is_down(honey.input.key.left_shift) then
+      movement:add(Vector.Vec3.Y_UNIT, movement)
+   end
+   if honey.input.key.is_down(honey.input.key.left_control) then
+      movement:sub(Vector.Vec3.Y_UNIT, movement)
+   end
    movement:muls(self.movement_speed*dt, movement)
    self.position:add(movement, self.position)
 
diff --git a/demo/main.lua b/demo/main.lua
index 9ca08be..3c32b6f 100644
--- a/demo/main.lua
+++ b/demo/main.lua
@@ -49,7 +49,7 @@ uniform sampler2D tex;
 out vec4 color;
 
 void main() { 
-  vec2 texture_coords = UV + (0.01 * time * vec2(1,1));
+  vec2 texture_coords = UV + (time * vec2(100,100));
   color = vec4(texture(tex, texture_coords).xyz, 1); 
 } ]]
 
@@ -60,15 +60,21 @@ local color1 = Vector.Vec4.new{1,0,0,1}
 local color2 = Vector.Vec4.new{0,0,1,1}
 local color = Vector.Vec4.new()
 
+local total_frames = 0
 local total_time = 0
 
 function honey.update(dt)
    total_time = total_time + dt
    FPSCamera:update(dt)
+   if total_time > 1 then
+      print('FPS: '..tostring(total_frames/total_time))
+      total_time = 0
+      total_frames = 0
+   end
 end
 
 function honey.draw()
-   
+   total_frames = total_frames + 1
    honey.shader.set_mat4(shader, 'model', model.array)
    honey.shader.set_mat4(shader, 'view', FPSCamera.view.array)
    honey.shader.set_mat4(shader, 'projection', FPSCamera.projection.array)
diff --git a/src/texture/texture.c b/src/texture/texture.c
index 1bb798a..6df19a7 100644
--- a/src/texture/texture.c
+++ b/src/texture/texture.c
@@ -10,12 +10,10 @@ static int honey_lua_texture_load(lua_State* L)
 {
     honey_texture* texture;
     char* texture_path;
-    bool use_alpha;
     honey_lua_parse_arguments(L, 3,
                               HONEY_USERDATA, &texture,
-                              HONEY_STRING, &texture_path,
-                              HONEY_BOOLEAN, &use_alpha);
-    enum honey_texture_result result = honey_texture_load(texture, texture_path, use_alpha);
+                              HONEY_STRING, &texture_path);
+    enum honey_texture_result result = honey_texture_load(texture, texture_path);
     if (result != TEXTURE_OK) {
         char* error;
         honey_format_string(&error,
@@ -53,46 +51,141 @@ void honey_setup_texture(lua_State* L)
 
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
+static void generate_texture(honey_texture* texture,
+                             int width, int height,
+                             int format, int type,
+                             void* data)
+{
+    unsigned int texture_id;
+    glGenTextures(1, &texture_id);
+    glBindTexture(GL_TEXTURE_2D, texture_id);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+    glTexImage2D(GL_TEXTURE_2D, 0,
+                 format,
+                 width, height, 0,
+                 format,
+                 type, data);
+
+    texture->id = texture_id;
+    texture->width = width;
+    texture->height = height;
+
+    switch(format) {
+    case GL_RED:
+        texture->type = GREY;
+        texture->channels = 1;
+        break;
+
+    case GL_RGB:
+        texture->type = RGB;
+        texture->channels = 3;
+        break;
+
+    case GL_RGBA:
+        texture->type = RGBA;
+        texture->channels = 4;
+        break;
+
+    case GL_DEPTH_COMPONENT:
+        texture->type = DEPTH;
+        texture->channels = 1;
+        break;
+
+    default:
+        break;
+    }
+    
+    return HONEY_OK;
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void honey_texture_new_greyscale(honey_texture* texture,
+                                 int height, int width,
+                                 unsigned char* data)
+{
+    generate_texture(texture, width, height, GL_RED, GL_UNSIGNED_BYTE, data);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void honey_texture_new_rgb(honey_texture* texture,
+                           int height, int width,
+                           unsigned char* data)
+{
+    generate_texture(texture, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void honey_texture_new_rgba(honey_texture* texture,
+                            int height, int width,
+                            unsigned char* data)
+{
+    generate_texture(texture, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void honey_texture_new_depth(honey_texture* texture,
+                             int height, int width,
+                             float* data)
+{
+    generate_texture(texture, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, data);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
 enum honey_texture_result honey_texture_load(honey_texture* texture,
-                                            char* texture_path,
-                                            bool alpha_channel) {
-  unsigned int texture_id;
-  glGenTextures(1, &texture_id);
-  glBindTexture(GL_TEXTURE_2D, texture_id);
-
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-  int width, height, channels;
-  unsigned char* image_data = stbi_load(texture_path, &width, &height, &channels, 0);
-  if (image_data == NULL) {
-    fprintf(stderr, "ERROR: failed to load '%s'\n", texture_path);
-    return TEXTURE_FAILED;
-  }
-
-  if (alpha_channel) {
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
-  }
-  else {
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image_data);
-  }
-
-  glGenerateMipmap(GL_TEXTURE_2D);
-  stbi_image_free(image_data);
-
-  (*texture).texture_id = texture_id;
-  (*texture).width = width;
-  (*texture).height = height;
-  (*texture).channels = channels;
-
-  return TEXTURE_OK;
+                                             char* texture_path)
+{
+    int width, height, channels;
+    unsigned char* image_data = stbi_load(texture_path, &width, &height, &channels, 0);
+    if (image_data == NULL) {
+        return TEXTURE_FAILED;
+    }
+
+    switch(channels) {
+    case 1:
+        honey_texture_new_greyscale(texture, width, height, image_data);
+        break;
+
+    case 3:
+        honey_texture_new_rgb(texture, width, height, image_data);
+        break;
+
+    case 4:
+        honey_texture_new_rgba(texture, width, height, image_data);
+        break;
+
+    default:
+        return TEXTURE_CHANNEL_ERROR;
+    }
+
+    glGenerateMipmap(GL_TEXTURE_2D);
+    stbi_image_free(image_data);
+
+    return TEXTURE_OK;
 }
 
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
 void honey_texture_use(honey_texture texture, int texture_unit) {
   glActiveTexture(GL_TEXTURE0 + texture_unit);
-  glBindTexture(GL_TEXTURE_2D, texture.texture_id);
+  glBindTexture(GL_TEXTURE_2D, texture.id);
 }
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+//honey_result honey_texture_framebuffer_object_new(unsigned int* destination,
+//                                                  int width, int height)
+//{
+//    glGenFramebuffers(1, destination);
+//    glBindFramebuffer(GL_FRAMEBUFFER, *destination);
+
+    
diff --git a/src/texture/texture.h b/src/texture/texture.h
index c9d1104..785fef0 100644
--- a/src/texture/texture.h
+++ b/src/texture/texture.h
@@ -11,18 +11,77 @@
 enum honey_texture_result {
   TEXTURE_OK,
   TEXTURE_FAILED,
+  TEXTURE_CHANNEL_ERROR,
   N_TEXTURE_RESULTS };
 
 typedef struct {
-  unsigned int texture_id;
-  int width;
-  int height;
-  int channels;
+    unsigned int id;
+    enum {
+        GREY,
+        RGB,
+        RGBA,
+        DEPTH
+    } type;
+    int width;
+    int height;
+    int channels;
 } honey_texture;
 
 /** @brief Place the honey.texture bindings as a table on the stack. */
 void honey_setup_texture(lua_State* L);
 
+/** @brief Create a greyscale texture.
+ *
+ * @param[out] texture Pointer to the destination texture.
+ * @param[in] width The width in pixels of the texture to create.
+ * @param[in] height The height in pixels of the texture to create.
+ * @param[in] data The data to populate the texture with, or NULL to leave it unpopulated.
+ *
+ * @returns HONEY_OK on success, and appropriate error on failure.
+ */
+void honey_texture_new_greyscale(honey_texture* texture,
+                                 int width, int height,
+                                 unsigned char* data);
+
+/** @brief Create an RGB texture.
+ *
+ * @param[out] texture Pointer to the destination texture.
+ * @param[in] width The width in pixels of the texture to create.
+ * @param[in] height The height in pixels of the texture to create.
+ * @param[in] data The data to populate the texture with, or NULL to leave it unpopulated.
+ *
+ * @returns HONEY_OK on success, and appropriate error on failure.
+ */
+void honey_texture_new_rgb(honey_texture* texture,
+                           int width, int height,
+                           unsigned char* data);
+
+/** @brief Create an RGBA texture.
+ *
+ * @param[out] texture Pointer to the destination texture.
+ * @param[in] width The width in pixels of the texture to create.
+ * @param[in] height The height in pixels of the texture to create.
+ * @param[in] data The data to populate the texture with, or NULL to leave it unpopulated.
+ *
+ * @returns HONEY_OK on success, and appropriate error on failure.
+ */
+void honey_texture_new_rgba(honey_texture* texture,
+                            int width, int height,
+                            unsigned char* data);
+
+/** @brief Create a depth texture.
+ *
+ * @param[out] texture Pointer to the destination texture.
+ * @param[in] width The width in pixels of the texture to create.
+ * @param[in] height The height in pixels of the texture to create.
+ * @param[in] data The data to populate the texture with, or NULL to leave it unpopulated.
+ *
+ * @returns HONEY_OK on success, and appropriate error on failure.
+ */
+void honey_texture_new_depth(honey_texture* texture,
+                             int width, int height,
+                             float* data);
+
 /** @brief Load a texture from disk.
  *
  * @param[out] texture Pointer to the destination texture
@@ -32,8 +91,7 @@ void honey_setup_texture(lua_State* L);
  * @return Success or failure type
  */
 enum honey_texture_result honey_texture_load(honey_texture* texture,
-                                             char* texture_path,
-                                             bool alpha_channel);
+                                             char* texture_path);
 
 /** @brief Load a texture into a texture unit.
  *
@@ -42,4 +100,15 @@ enum honey_texture_result honey_texture_load(honey_texture* texture,
  */
 void honey_texture_use(honey_texture texture, int texture_unit);
 
+/** @brief Create a framebuffer object.
+ *
+ * @param[out] destination Pointer to store the resulting OpenGL handle in.
+ * @param[in] width The width in pixels of the FBO.
+ * @param[in] height The height in pixels of the FBO.
+ *
+ * @returns HONEY_OK on success; appropriate error otherwise.
+ */
+honey_result honey_texture_framebuffer_object_new(unsigned int* destination,
+                                                  int width, int height);
+
 #endif
diff --git a/src/window/window.c b/src/window/window.c
index 37053a4..6a1fe6f 100644
--- a/src/window/window.c
+++ b/src/window/window.c
@@ -97,6 +97,9 @@ bool honey_setup_window(lua_State* L)
     // Enable depth testing
     glEnable(GL_DEPTH_TEST);
 
+    // Enable face culling
+    glEnable(GL_CULL_FACE);
+
     glfwSetWindowSizeCallback(info->window, honey_glfw_window_resize_callback);
     glfwSetWindowFocusCallback(info->window, honey_glfw_window_focus_callback);
     
-- 
cgit v1.2.1