]> git.mxchange.org Git - simgear.git/blobdiff - simgear/screen/texture.cxx
Add a bunch of extensions in preparation of render-to-texture support.
[simgear.git] / simgear / screen / texture.cxx
index 67c5900e157a2ec4c8c54fc5a617b56b801fe814..2544354ed8399182b67cc9d233f3a4166a014b00 100644 (file)
@@ -19,6 +19,7 @@
 
 #include SG_GLU_H
 
+#include <math.h>
 #include <zlib.h>
 
 #include "texture.hxx"
@@ -34,7 +35,8 @@ const char *OUT_OF_MEMORY = "Out of memory.";
 SGTexture::SGTexture()
    : texture_id(0),
      texture_data(0),
-     num_colors(3)
+     num_colors(3),
+     file(0)
 {
 }
 
@@ -378,7 +380,7 @@ SGTexture::read_raw_texture(const char *name)
 
     ptr = texture_data;
     for(y=0; y<256; y++) {
-        gzread(image->gzfile, ptr, 256*3);
+        gzread(image->file, ptr, 256*3);
         ptr+=256*3;
     }
     ImageClose(image);
@@ -414,7 +416,7 @@ SGTexture::read_r8_texture(const char *name)
 
     ptr = texture_data;
     for(xy=0; xy<(256*256); xy++) {
-        gzread(image->gzfile, c, 1);
+        gzread(image->file, c, 1);
 
         //look in the table for the right colours
         ptr[0]=msfs_colour[c[0]][0];
@@ -438,7 +440,7 @@ SGTexture::write_texture(const char *name) {
            image->tmp[x]=*ptr;
             ptr = ptr + num_colors;
          }
-         fwrite(image->tmp, 1, texture_width, image->file);
+         fwrite(image->tmp, 1, texture_width, file);
       }
    }
 
@@ -447,34 +449,30 @@ SGTexture::write_texture(const char *name) {
 
 
 void
-SGTexture::set_pixel(GLuint x, GLuint y, sgVec3 &c)
+SGTexture::set_pixel(GLuint x, GLuint y, GLubyte *c)
 {
     if (!texture_data) {
         errstr = NO_TEXTURE;
         return;
     }
 
-    unsigned int pos = (x + y*texture_width)*3;
-    texture_data[pos]   = (unsigned char)(c[0] * 256);
-    texture_data[pos+1] = (unsigned char)(c[1] * 256);
-    texture_data[pos+2] = (unsigned char)(c[2] * 256);
+    unsigned int pos = (x + y*texture_width) * num_colors;
+    memcpy(texture_data+pos, c, num_colors);
 }
 
 
-float *
+GLubyte *
 SGTexture::get_pixel(GLuint x, GLuint y)
 {
-    static sgVec3 c;
+    static GLubyte c[4] = {0, 0, 0, 0};
 
-    sgSetVec3(c, 0, 0, 0);
     if (!texture_data) {
         errstr = NO_TEXTURE;
         return c;
     }
 
-    unsigned int pos = (x + y*texture_width)*3;
-
-    sgSetVec3(c, texture_data[pos], texture_data[pos+1], texture_data[pos+2]);
+    unsigned int pos = (x + y*texture_width)*num_colors;
+    memcpy(c, texture_data + pos, num_colors);
 
     return c;
 }
@@ -504,12 +502,12 @@ SGTexture::ImageOpen(const char *fileName)
         errstr = OUT_OF_MEMORY;
         return 0;
     }
-    if ((image->gzfile = gzopen(fileName, "rb")) == 0) {
+    if ((image->file = gzopen(fileName, "rb")) == 0) {
       errstr = FILE_OPEN_ERROR;
       return 0;
     }
 
-    gzread(image->gzfile, image, 12);
+    gzread(image->file, image, 12);
 
     if (swapFlag) {
         ConvertShort(&image->imagic, 6);
@@ -530,9 +528,9 @@ SGTexture::ImageOpen(const char *fileName)
             return 0;
         }
         image->rleEnd = 512 + (2 * x);
-        gzseek(image->gzfile, 512, SEEK_SET);
-        gzread(image->gzfile, image->rowStart, x);
-        gzread(image->gzfile, image->rowSize, x);
+        gzseek(image->file, 512, SEEK_SET);
+        gzread(image->file, image->rowStart, x);
+        gzread(image->file, image->rowSize, x);
         if (swapFlag) {
             ConvertUint(image->rowStart, x/(int) sizeof(unsigned));
             ConvertUint((unsigned *)image->rowSize, x/(int) sizeof(int));
@@ -544,8 +542,8 @@ SGTexture::ImageOpen(const char *fileName)
 
 void
 SGTexture::ImageClose(SGTexture::ImageRec *image) {
-    if (image->gzfile)  gzclose(image->gzfile);
-    if (image->file)    fclose(image->file);
+    if (image->file)  gzclose(image->file);
+    if (file) fclose(file);
     delete image->tmp;
     delete image;
 }
@@ -574,12 +572,12 @@ SGTexture::RawImageOpen(const char *fileName)
         errstr = OUT_OF_MEMORY;
         return 0;
     }
-    if ((image->gzfile = gzopen(fileName, "rb")) == 0) {
+    if ((image->file = gzopen(fileName, "rb")) == 0) {
       errstr = FILE_OPEN_ERROR;
       return 0;
     }
 
-    gzread(image->gzfile, image, 12);
+    gzread(image->file, image, 12);
 
     if (swapFlag) {
         ConvertShort(&image->imagic, 6);
@@ -621,7 +619,7 @@ SGTexture::ImageWriteOpen(const char *fileName)
         errstr = OUT_OF_MEMORY;
         return 0;
     }
-    if ((image->file = fopen(fileName, "wb")) == 0) {
+    if ((file = fopen(fileName, "wb")) == 0) {
         errstr = FILE_OPEN_ERROR;
         return 0;
     }
@@ -633,14 +631,13 @@ SGTexture::ImageWriteOpen(const char *fileName)
     image->ysize = texture_height;
     image->zsize = num_colors;
 
-    fwrite(image, 1, 12, image->file);
-
-    fseek(image->file, 512, SEEK_SET);
-
     if (swapFlag) {
         ConvertShort(&image->imagic, 6);
     }
 
+    fwrite(image, 1, 12, file);
+    fseek(file, 512, SEEK_SET);
+
     image->tmp = new GLubyte[ image->xsize * 256 ];
     if (image->tmp == 0) {
         errstr = OUT_OF_MEMORY;
@@ -656,9 +653,9 @@ SGTexture::ImageWriteOpen(const char *fileName)
             return 0;
         }
         image->rleEnd = 512 + (2 * x);
-        fseek(image->file, 512, SEEK_SET);
-        fwrite(image->rowStart, 1, x, image->file);
-        fwrite(image->rowSize, 1, x, image->file);
+        fseek(file, 512, SEEK_SET);
+        fread(image->rowStart, 1, x, file);
+        fread(image->rowSize, 1, x, file);
         if (swapFlag) {
             ConvertUint(image->rowStart, x/(int) sizeof(unsigned));
             ConvertUint((unsigned *)image->rowSize, x/(int) sizeof(int));
@@ -675,8 +672,8 @@ SGTexture::ImageGetRow(SGTexture::ImageRec *image, GLubyte *buf, int y, int z) {
     int count;
 
     if ((image->type & 0xFF00) == 0x0100) {
-        gzseek(image->gzfile, (long) image->rowStart[y+z*image->ysize], SEEK_SET);
-        gzread(image->gzfile, image->tmp,
+        gzseek(image->file, (long) image->rowStart[y+z*image->ysize], SEEK_SET);
+        gzread(image->file, image->tmp,
                (unsigned int)image->rowSize[y+z*image->ysize]);
 
         iPtr = image->tmp;
@@ -700,9 +697,9 @@ SGTexture::ImageGetRow(SGTexture::ImageRec *image, GLubyte *buf, int y, int z) {
             }
         }
     } else {
-        gzseek(image->gzfile, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
+        gzseek(image->file, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
               SEEK_SET);
-        gzread(image->gzfile, buf, image->xsize);
+        gzread(image->file, buf, image->xsize);
     }
 }
 
@@ -712,9 +709,9 @@ SGTexture::ImagePutRow(SGTexture::ImageRec *image, GLubyte *buf, int y, int z) {
     int count;
 
     if ((image->type & 0xFF00) == 0x0100) {
-        fseek(image->file, (long) image->rowStart[y+z*image->ysize], SEEK_SET);
+        fseek(file, (long) image->rowStart[y+z*image->ysize], SEEK_SET);
         fread( image->tmp, 1, (unsigned int)image->rowSize[y+z*image->ysize],
-               image->file);
+               file);
 
         iPtr = image->tmp;
         oPtr = buf;
@@ -737,9 +734,9 @@ SGTexture::ImagePutRow(SGTexture::ImageRec *image, GLubyte *buf, int y, int z) {
             }
         }
     } else {
-        fseek(image->file, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
+        fseek(file, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
               SEEK_SET);
-        fread(buf, 1, image->xsize, image->file);
+        fread(buf, 1, image->xsize, file);
     }
 }
 
@@ -796,3 +793,175 @@ SGTexture::ConvertUint(unsigned *array, unsigned int length) {
     }
 }
 
+
+void
+SGTexture::make_monochrome(float contrast, GLubyte r, GLubyte g, GLubyte b) {
+
+   if (num_colors >= 3)
+      return;
+
+   GLubyte ap[3];
+   for (int y=0; y<texture_height; y++)
+      for (int x=0; x<texture_width; x++)
+      {
+         GLubyte *rgb = get_pixel(x,y);
+         GLubyte avg = (rgb[0] + rgb[1] + rgb[2]) / 3;
+
+         if (contrast != 1.0) {
+            float pixcol = -1.0 + (avg/128);
+            avg = 128 + int(128*pow(pixcol, contrast));
+         }
+
+         ap[0] = avg*r/255;
+         ap[1] = avg*g/255;
+         ap[2] = avg*b/255;
+
+         set_pixel(x,y,ap);
+      }
+}
+
+
+void
+SGTexture::make_grayscale(float contrast) {
+   if (num_colors < 3)
+      return;
+
+   int colors = (num_colors == 3) ? 1 : 2;
+   GLubyte *map = (GLubyte *)malloc (texture_width * texture_height * colors);
+
+   for (int y=0; y<texture_height; y++)
+      for (int x=0; x<texture_width; x++)
+      {
+         GLubyte *rgb = get_pixel(x,y);
+         GLubyte avg = (rgb[0] + rgb[1] + rgb[2]) / 3;
+
+         if (contrast != 1.0) {
+            float pixcol = -1.0 + (avg/128);
+            avg = 128 + int(128*pow(pixcol, contrast));
+         }
+
+         int pos = (x + y*texture_width)*colors;
+         map[pos] = avg;
+         if (colors > 1)
+            map[pos+1] = rgb[3];
+      }
+
+   free (texture_data);
+   texture_data = map;
+   num_colors = colors;
+}
+
+
+void
+SGTexture::make_maxcolorwindow() {
+   GLubyte minmaxc[2] = {255, 0};
+
+   unsigned int pos = 0;
+   unsigned int max = num_colors;
+   if (num_colors == 2) max = 1;
+   if (num_colors == 4) max = 3; 
+   while (pos < texture_width * texture_height * num_colors) {
+      for (int i=0; i < max; i++) {
+         GLubyte c = texture_data[pos+i];
+         if (c < minmaxc[0]) minmaxc[0] = c;
+         if (c > minmaxc[1]) minmaxc[1] = c;
+      }
+      pos += num_colors;
+   }
+
+   GLubyte offs = minmaxc[0];
+   float factor = 255.0 / float(minmaxc[1] - minmaxc[0]);
+   // printf("Min: %i, Max: %i, Factor: %f\n", offs, minmaxc[1], factor);
+
+   pos = 0;
+   while (pos < texture_width * texture_height * num_colors) {
+      for (int i=0; i < max; i++) {
+         texture_data[pos+i] -= offs;
+         texture_data[pos+i] = int(factor * texture_data[pos+i]);
+      }
+      pos += num_colors;
+   }
+}
+
+
+void
+SGTexture::make_normalmap(float brightness, float contrast) {
+   make_grayscale(contrast);
+   make_maxcolorwindow();
+
+   int colors = (num_colors == 1) ? 3 : 4;
+   bool alpha = (colors > 3);
+   int tsize = texture_width * texture_height * colors;
+   GLubyte *map = (GLubyte *)malloc (tsize);
+
+   int mpos = 0, dpos = 0;
+   for (int y=0; y<texture_height; y++) {
+      int ytw = y*texture_width;
+
+      for (int x=0; x<texture_width; x++)
+      {
+         int xp1 = (x < (texture_width-1)) ? x+1 : 0;
+         int yp1 = (y < (texture_height-1)) ? y+1 : 0;
+         int posxp1 = (xp1 + ytw)*num_colors;
+         int posyp1 = (x + yp1*texture_width)*num_colors;
+
+         GLubyte c = texture_data[dpos];
+         GLubyte cx1 = texture_data[posxp1];
+         GLubyte cy1 = texture_data[posyp1];
+
+         if (alpha) {
+            GLubyte a = texture_data[dpos+1];
+            GLubyte ax1 = texture_data[posxp1+1];
+            GLubyte ay1 = texture_data[posyp1+1];
+
+            c = (c + a)/2;
+            cx1 = (cx1 + ax1)/2;
+            cy1 = (cy1 + ay1)/2;
+
+            map[mpos+3] = a;
+         }
+
+         map[mpos+0] = (128+(cx1-c)/2);
+         map[mpos+1] = (128+(cy1-c)/2);
+         map[mpos+2] = 127+int(brightness*128); // 255-c/2;
+
+         mpos += colors;
+         dpos += num_colors;
+      }
+   }
+
+   free (texture_data);
+   texture_data = map;
+   num_colors = colors;
+}
+
+
+void
+SGTexture::make_bumpmap(float brightness, float contrast) {
+   make_grayscale(contrast);
+
+   int colors = (num_colors == 1) ? 1 : 2;
+   GLubyte *map = (GLubyte *)malloc (texture_width * texture_height * colors);
+
+   for (int y=0; y<texture_height; y++)
+      for (int x=0; x<texture_width; x++)
+      {
+         int mpos = (x + y*texture_width)*colors;
+         int dpos = (x + y*texture_width)*num_colors;
+
+         int xp1 = (x < (texture_width-1)) ? x+1 : 0;
+         int yp1 = (y < (texture_height-1)) ? y+1 : 0;
+         int posxp1 = (xp1 + y*texture_width)*num_colors;
+         int posyp1 = (x + yp1*texture_width)*num_colors;
+
+         map[mpos] = (127 - ((texture_data[dpos]-texture_data[posxp1]) -
+                            ((texture_data[dpos]-texture_data[posyp1]))/4))/2;
+         if (colors > 1)
+            map[mpos+1] = texture_data[dpos+1];
+      }
+
+   free (texture_data);
+   texture_data = map;
+   num_colors = colors;
+}
+