Add ability to load material maps into struct tga/struct array without OpenGL
authorNick Downing <nick@ndcode.org>
Wed, 20 Apr 2022 05:58:37 +0000 (15:58 +1000)
committerNick Downing <nick@ndcode.org>
Wed, 20 Apr 2022 05:58:48 +0000 (15:58 +1000)
Chest-diffuse.tga [new file with mode: 0644]
Chest-normal.tga [new file with mode: 0644]
Chest-specular.tga [new file with mode: 0644]
Makefile
obj.c
obj.h
tga.c [new file with mode: 0644]
tga.h [new file with mode: 0644]

diff --git a/Chest-diffuse.tga b/Chest-diffuse.tga
new file mode 100644 (file)
index 0000000..f621b54
Binary files /dev/null and b/Chest-diffuse.tga differ
diff --git a/Chest-normal.tga b/Chest-normal.tga
new file mode 100644 (file)
index 0000000..9c99c1b
Binary files /dev/null and b/Chest-normal.tga differ
diff --git a/Chest-specular.tga b/Chest-specular.tga
new file mode 100644 (file)
index 0000000..ac029bd
Binary files /dev/null and b/Chest-specular.tga differ
index 5611a82..a372bb7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 CFLAGS=-g -Og -Wall -Wno-format-overflow -Wno-format-truncation -DCONF_NO_GL
 
-render: render.o obj.o
+render: render.o obj.o tga.o
        ${CC} -o $@ $^ -lSDL2 -lm
 
 render.o: render.c array.h obj.h
diff --git a/obj.c b/obj.c
index 035dbac..5fb48ff 100644 (file)
--- a/obj.c
+++ b/obj.c
 #include <assert.h>
 #include <math.h>
 #include "obj.h"
-
-#define MAXSTR 1024
-#define OPT_CLAMP 1
+#include "tga.h"
 
 #ifndef CONF_NO_GL
+#ifdef __APPLE__
+#  include <OpenGL/gl3.h>
+#else
+#  include <GL/glew.h>
+#endif
+
 #ifdef OBJ_INDEX_IS_INT
 typedef GL_UNSIGNED_INT GL_INDEX_T;
 #else
@@ -37,6 +41,9 @@ typedef GL_UNSIGNED_SHORT GL_INDEX_T;
 #endif
 #endif
 
+#define MAXSTR 1024
+#define OPT_CLAMP 1
+
 static void invalidate(struct obj *);
 
 /*----------------------------------------------------------------------------*/
@@ -183,100 +190,54 @@ static void normal(float *n, const float *a,
 
 /*============================================================================*/
 
-#pragma pack(push, 1)
-struct tga_head
-{
-    unsigned char  id_length;
-    unsigned char  color_map_type;
-    unsigned char  image_type;
-    unsigned short color_map_offset;
-    unsigned short color_map_length;
-    unsigned char  color_map_size;
-    unsigned short image_x_origin;
-    unsigned short image_y_origin;
-    unsigned short image_width;
-    unsigned short image_height;
-    unsigned char  image_depth;
-    unsigned char  image_descriptor;
-};
-#pragma pack(pop)
-
-void *read_tga(const char *filename, int *w, int *h, int *d)
-{
-    struct tga_head head;
-    FILE *stream;
-
-    if ((stream = fopen(filename, "rb")))
-    {
-        if (fread(&head, sizeof (struct tga_head), 1, stream) == 1)
-        {
-            if (head.image_type == 2)
-            {
-                *w = (int) head.image_width;
-                *h = (int) head.image_height;
-                *d = (int) head.image_depth;
-
-                if (fseek(stream, head.id_length, SEEK_CUR) == 0)
-                {
-                    size_t s = (*d) / 8;
-                    size_t n = (*w) * (*h);
-                    void *p;
-
-                    if ((p = calloc(n, s)))
-                    {
-                        if (fread(p, s, n, stream) == n)
-                        {
-                            fclose(stream);
-                            return p;
-                        }
-                    }
-                }
-            }
-        }
-        fclose(stream);
-    }
-    return 0;
-}
-
+#ifdef CONF_NO_GL
+struct array *obj_load_image(const char *filename)
+#else
 unsigned int obj_load_image(const char *filename)
+#endif
 {
+#ifdef CONF_NO_GL
+    struct array *o = NULL;
+#else
     unsigned int o = 0;
+#endif
 
-#ifndef CONF_NO_GL
     if (filename)
     {
-        int   w;
-        int   h;
-        int   d;
-        void *p;
-
         /* Read the image data from the named file to a new pixel buffer. */
+        struct tga *tga = tga_read(filename);
 
-        if ((p = read_tga(filename, &w, &h, &d)))
-        {
-            /* Create an OpenGL texture object using these pixels. */
-
-            glGenTextures(1, &o);
-            glBindTexture(GL_TEXTURE_2D, o);
-
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
-
-            if (d == 32)
-                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0,
-                             GL_BGRA, GL_UNSIGNED_BYTE, p);
-            if (d == 24)
-                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,  w, h, 0,
-                             GL_BGR,  GL_UNSIGNED_BYTE, p);
-
-            glGenerateMipmap(GL_TEXTURE_2D);
-
-            /* Discard the unnecessary pixel buffer. */
+#ifdef CONF_NO_GL
+        /* We really do not need the TGA header, since coordinates are based */
+        /* on the data, rather than using the anchor position from header. */
+        o = tga->data;
+        tga->data = NULL;
+#else
+        int   h = (int)tga->data->dim[0];
+        int   w = (int)tga->data->dim[1];
+        int   d = (int)tga->data->dim[2];
+        void *p = array_index0(tga->data);
+
+        /* Create an OpenGL texture object using these pixels. */
+        glGenTextures(1, &o);
+        glBindTexture(GL_TEXTURE_2D, o);
+
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+
+        if (d == 4)
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0,
+                         GL_BGRA, GL_UNSIGNED_BYTE, p);
+        if (d == 3)
+            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,  w, h, 0,
+                         GL_BGR,  GL_UNSIGNED_BYTE, p);
+
+        glGenerateMipmap(GL_TEXTURE_2D);
+#endif
 
-            free(p);
-        }
+        /* Discard the unnecessary pixel buffer. */
+        tga_free(tga);
     }
-#endif
 
     return o;
 }
@@ -1269,8 +1230,10 @@ void obj_set_mtrl_map(struct obj *O, int mi, int ki, const char *str)
 {
     assert_prop(O, mi, ki);
 
-#ifndef CONF_NO_GL
     if (O->mv[mi].kv[ki].map)
+#ifdef CONF_NO_GL
+        array_free(O->mv[mi].kv[ki].map); // note: may be NULL
+#else
         glDeleteTextures(1, &O->mv[mi].kv[ki].map);
 #endif
 
@@ -1426,7 +1389,11 @@ const char *obj_get_mtrl_name(const struct obj *O, int mi)
     return O->mv[mi].name;
 }
 
+#ifdef CONF_NO_GL
+struct array *obj_get_mtrl_map(const struct obj *O, int mi, int ki)
+#else
 unsigned int obj_get_mtrl_map(const struct obj *O, int mi, int ki)
+#endif
 {
     assert_prop(O, mi, ki);
     return O->mv[mi].kv[ki].map;
diff --git a/obj.h b/obj.h
index 6eceff7..f769f23 100644 (file)
--- a/obj.h
+++ b/obj.h
 #ifndef UTIL3D_OBJ_H
 #define UTIL3D_OBJ_H
 
-#ifndef CONF_NO_GL
-#ifdef __APPLE__
-#  include <OpenGL/gl3.h>
-#else
-#  include <GL/glew.h>
-#endif
-#endif
-
 /*============================================================================*/
 
 #define OBJ_INDEX_IS_INT
@@ -61,7 +53,11 @@ struct obj_prop
 {
     char        *str;
     int          opt;
+#ifdef CONF_NO_GL
+    struct array *map;
+#else
     unsigned int map;
+#endif
 
     float c[4];
     float o[3];
@@ -185,7 +181,11 @@ void obj_set_prop_loc(struct obj *, int, int, int, int);
 /*----------------------------------------------------------------------------*/
 
 const char  *obj_get_mtrl_name(const struct obj *, int);
+#ifdef CONF_NO_GL
+struct array *obj_get_mtrl_map (const struct obj *, int, int);
+#else
 unsigned int obj_get_mtrl_map (const struct obj *, int, int);
+#endif
 unsigned int obj_get_mtrl_opt (const struct obj *, int, int);
 void         obj_get_mtrl_c   (const struct obj *, int, int, float *);
 void         obj_get_mtrl_o   (const struct obj *, int, int, float *);
@@ -207,7 +207,11 @@ void  obj_render_file(const struct obj *);
 
 /*----------------------------------------------------------------------------*/
 
+#ifdef CONF_NO_GL
+struct array *obj_load_image(const char *);
+#else
 unsigned int obj_load_image(const char *);
+#endif
 
 void  obj_mini(struct obj *);
 void  obj_norm(struct obj *);
diff --git a/tga.c b/tga.c
new file mode 100644 (file)
index 0000000..a990a45
--- /dev/null
+++ b/tga.c
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "tga.h"
+
+struct tga *tga_read(const char *filename) {
+  FILE *stream = fopen(filename, "rb");
+  if (stream == NULL) {
+    perror(filename);
+    exit(EXIT_FAILURE);
+  }
+
+  struct tga *p = malloc(sizeof(struct tga));
+  if (p == NULL) {
+    perror("malloc()");
+    exit(EXIT_FAILURE);
+  }
+  if (fread(&p->head, sizeof(struct tga_head), 1, stream) != 1) {
+    perror("fread()");
+    exit(EXIT_FAILURE);
+  }
+
+  if (p->head.image_type != 2) {
+    fprintf(stderr, "image_type %d, should be 2\n", p->head.image_type);
+    exit(EXIT_FAILURE);
+  }
+
+  if (fseek(stream, p->head.id_length, SEEK_CUR)) {
+    perror("fseek()");
+    exit(EXIT_FAILURE);
+  }
+
+  p->data = array_new3(
+    p->head.image_height,
+    p->head.image_width,
+    p->head.image_depth / 8
+  );
+  if (fread(array_index0(p->data), p->data->stride[0], 1, stream) != 1) {
+    perror("fread()");
+    exit(EXIT_FAILURE);
+  }
+
+  fclose(stream);
+  return p;
+}
+
+void tga_free(struct tga *self) {
+  array_free(self->data);
+  free(self);
+}
diff --git a/tga.h b/tga.h
new file mode 100644 (file)
index 0000000..b9268d3
--- /dev/null
+++ b/tga.h
@@ -0,0 +1,33 @@
+#ifndef _TGA_H
+#define _TGA_H
+
+#include <stdint.h>
+#include "array.h"
+
+#pragma pack(push, 1)
+struct tga_head
+{
+  uint8_t id_length;
+  uint8_t color_map_type;
+  uint8_t image_type;
+  uint16_t color_map_offset;
+  uint16_t color_map_length;
+  uint8_t color_map_size;
+  uint16_t image_x_origin;
+  uint16_t image_y_origin;
+  uint16_t image_width;
+  uint16_t image_height;
+  uint8_t image_depth;
+  uint8_t image_descriptor;
+};
+#pragma pack(pop)
+
+struct tga {
+  struct tga_head head;
+  struct array *data;
+};
+
+struct tga *tga_read(const char *filename);
+void tga_free(struct tga *self);
+
+#endif