summaryrefslogtreecommitdiff
path: root/src/texture.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/texture.c')
-rw-r--r--src/texture.c268
1 files changed, 268 insertions, 0 deletions
diff --git a/src/texture.c b/src/texture.c
new file mode 100644
index 0000000..37e38e9
--- /dev/null
+++ b/src/texture.c
@@ -0,0 +1,268 @@
+#include "texture.h"
+
+static int honey_lua_texture_new(lua_State* L)
+{
+ honey_texture* texture = lua_newuserdata(L, sizeof(honey_texture));
+ return 1;
+}
+
+static int honey_lua_texture_create(lua_State* L)
+{
+ honey_texture* texture;
+ int width, height;
+ char* type;
+ honey_lua_parse_arguments(L, 4,
+ HONEY_USERDATA, &texture,
+ HONEY_STRING, &type,
+ HONEY_INTEGER, &width,
+ HONEY_INTEGER, &height);
+
+ if (strcmp(type, "greyscale") == 0)
+ honey_texture_new_greyscale(texture, width, height, NULL);
+ else if (strcmp(type, "rgb") == 0)
+ honey_texture_new_rgb(texture, width, height, NULL);
+ else if (strcmp(type, "rgba") == 0)
+ honey_texture_new_rgba(texture, width, height, NULL);
+ else if (strcmp(type, "depth") == 0)
+ honey_texture_new_depth(texture, width, height, NULL);
+ else {
+ char* error;
+ honey_format_string(&error,
+ "unknown texture type '%s'",
+ type);
+ lua_pushstring(L, error);
+ free(error);
+ lua_error(L);
+ }
+ return 0;
+}
+
+static int honey_lua_texture_load(lua_State* L)
+{
+ honey_texture* texture;
+ char* texture_path;
+ honey_lua_parse_arguments(L, 3,
+ HONEY_USERDATA, &texture,
+ 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,
+ "failed to load '%s'",
+ texture_path);
+ lua_pushstring(L, error);
+ free(error);
+ lua_error(L);
+ }
+
+ return 0;
+}
+
+static int honey_lua_texture_use(lua_State* L)
+{
+ honey_texture* texture;
+ int texture_unit;
+ honey_lua_parse_arguments(L, 2,
+ HONEY_USERDATA, &texture,
+ HONEY_INTEGER, &texture_unit);
+ honey_texture_use(*texture, texture_unit);
+ return 0;
+}
+
+static int honey_lua_framebuffer_new(lua_State* L)
+{
+ honey_texture* draw, *depth;
+ if (lua_isuserdata(L, 1))
+ draw = lua_touserdata(L, 1);
+ else
+ draw = NULL;
+
+ if (lua_isuserdata(L, 2))
+ depth = lua_touserdata(L, 2);
+ else
+ depth = NULL;
+
+ int width, height;
+ honey_lua_parse_arguments(L, 4, HONEY_ANY, HONEY_ANY,
+ HONEY_INTEGER, &width,
+ HONEY_INTEGER, &height);
+
+ unsigned int framebuffer;
+ honey_texture_framebuffer_object_new(&framebuffer,
+ draw, depth,
+ width, height);
+ lua_pushinteger(L, framebuffer);
+ return 1;
+}
+
+void honey_setup_texture(lua_State* L)
+{
+ honey_lua_element texture_elements[] = {
+ { "new", HONEY_FUNCTION, { .function = honey_lua_texture_new } },
+ { "new_framebuffer", HONEY_FUNCTION, { .function = honey_lua_framebuffer_new } },
+ { "create", HONEY_FUNCTION, { .function = honey_lua_texture_create } },
+ { "load", HONEY_FUNCTION, { .function = honey_lua_texture_load } },
+ { "use", HONEY_FUNCTION, { .function = honey_lua_texture_use } },
+ };
+
+ honey_lua_create_table(L, texture_elements, 5);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+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)
+{
+ 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.id);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+void honey_texture_framebuffer_object_new(unsigned int* destination,
+ honey_texture* draw,
+ honey_texture* depth,
+ int width, int height)
+{
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ glGenFramebuffers(1, destination);
+ glBindFramebuffer(GL_FRAMEBUFFER, *destination);
+
+ if (draw != NULL)
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, draw->id, 0);
+ else {
+ glDrawBuffer(GL_NONE);
+ glReadBuffer(GL_NONE);
+ }
+
+ if (depth != NULL)
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth->id, 0);
+
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+ printf("framebuffer is not complete!\n");
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}