]> git.mxchange.org Git - flightgear.git/blob - utils/Modeller/texture.cxx
initial commit for a python based terrasync client
[flightgear.git] / utils / Modeller / texture.cxx
1 /*
2  * Texture manipulation routines
3  *
4  * Copyright (c) Mark J. Kilgard, 1997.
5  * Code added in april 2003 by Erik Hofman
6  *
7  * This program is freely distributable without licensing fees 
8  * and is provided without guarantee or warrantee expressed or 
9  * implied. This program is -not- in the public domain.
10  *
11  * $Id$
12  */
13
14 #include <simgear/compiler.h>
15
16 #ifdef WIN32
17 # include <windows.h>
18 #endif
19
20 #include <osg/Matrixf>
21
22 #include <math.h>
23 #include <zlib.h>
24
25 #include "texture.hxx"
26 #include "colours.h"
27
28
29 const char *FILE_OPEN_ERROR = "Unable to open file.";
30 const char *WRONG_COUNT = "Unsupported number of color channels.";
31 const char *NO_TEXTURE = "No texture data resident.";
32 const char *OUT_OF_MEMORY = "Out of memory.";
33
34
35 SGTexture::SGTexture()
36    : texture_id(0),
37      texture_data(0),
38      num_colors(3),
39      file(0)
40 {
41 }
42
43 SGTexture::SGTexture(unsigned int width, unsigned int height)
44    : texture_id(0),
45      errstr("")
46 {
47     texture_data = new GLubyte[ width * height * 3 ];
48 }
49
50 SGTexture::~SGTexture()
51 {
52     delete[] texture_data;
53
54     if ( texture_id != 0 ) {
55         free_id();
56     }
57 }
58
59 void
60 SGTexture::bind()
61 {
62     bool gen = false;
63     if (!texture_id) {
64 #ifdef GL_VERSION_1_1
65         glGenTextures(1, &texture_id);
66
67 #elif GL_EXT_texture_object
68         glGenTexturesEXT(1, &texture_id);
69 #endif
70         gen = true;
71     }
72
73 #ifdef GL_VERSION_1_1
74     glBindTexture(GL_TEXTURE_2D, texture_id);
75
76 #elif GL_EXT_texture_object
77     glBindTextureEXT(GL_TEXTURE_2D, texture_id);
78 #endif
79
80     if (gen) {
81         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
82         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
83         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
84         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
85     }
86 }
87
88 /**
89  * A function to resize the OpenGL window which will be used by
90  * the dynamic texture generating routines.
91  *
92  * @param width The width of the new window
93  * @param height The height of the new window
94  */
95 void
96 SGTexture::resize(unsigned int width, unsigned int height)
97 {
98     using namespace osg;
99     GLfloat aspect;
100
101     // Make sure that we don't get a divide by zero exception
102     if (height == 0)
103         height = 1;
104
105     // Set the viewport for the OpenGL window
106     glViewport(0, 0, width, height);
107
108     // Calculate the aspect ratio of the window
109     aspect = width/height;
110
111     // Go to the projection matrix, this gets modified by the perspective
112     // calulations
113     glMatrixMode(GL_PROJECTION);
114
115     // Do the perspective calculations
116     Matrixf proj = Matrixf::perspective(45.0, aspect, 1.0, 400.0);
117     glLoadMatrix(proj.ptr());
118
119     // Return to the modelview matrix
120     glMatrixMode(GL_MODELVIEW);
121 }
122
123 /**
124  * A function to prepare the OpenGL state machine for dynamic
125  * texture generation.
126  *
127  * @param width The width of the texture
128  * @param height The height of the texture
129  */
130 void
131 SGTexture::prepare(unsigned int width, unsigned int height) {
132
133     texture_width = width;
134     texture_height = height;
135
136     // Resize the OpenGL window to the size of our dynamic texture
137     resize(texture_width, texture_height);
138
139     glClearColor(0.0, 0.0, 0.0, 1.0);
140 }
141
142 /**
143  * A function to generate the dynamic texture.
144  *
145  * The actual texture can be accessed by calling get_texture()
146  *
147  * @param width The width of the previous OpenGL window
148  * @param height The height of the previous OpenGL window
149  */
150 void
151 SGTexture::finish(unsigned int width, unsigned int height) {
152     // If a texture hasn't been created then it gets created, and the contents
153     // of the frame buffer gets copied into it. If the texture has already been
154     // created then its contents just get updated.
155     bind();
156     if (!texture_data)
157     {
158       // Copies the contents of the frame buffer into the texture
159       glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0,
160                                       texture_width, texture_height, 0);
161
162     } else {
163       // Copies the contents of the frame buffer into the texture
164       glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
165                                          texture_width, texture_height);
166     }
167
168     // Set the OpenGL window back to its previous size
169     resize(width, height);
170
171     // Clear the window back to black
172     glClearColor(0.0, 0.0, 0.0, 1.0);
173     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
174 }
175
176
177 void
178 SGTexture::read_alpha_texture(const char *name)
179 {
180     GLubyte *lptr;
181     SGTexture::ImageRec *image;
182     int y;
183
184     delete[] texture_data;
185
186     image = ImageOpen(name);
187     if(!image) {
188         errstr = FILE_OPEN_ERROR;
189         return;
190     }
191
192     texture_width = image->xsize;
193     texture_height = image->ysize;
194
195     // printf("image->zsize = %d\n", image->zsize);
196
197     if (image->zsize != 1) {
198       ImageClose(image);
199       errstr = WRONG_COUNT;
200       return;
201     }
202
203     texture_data = new GLubyte[ image->xsize * image->ysize ];
204     num_colors = 1;
205     if (!texture_data) {
206         errstr = NO_TEXTURE;
207         return;
208     }
209
210     lptr = texture_data;
211     for(y=0; y<image->ysize; y++) {
212         ImageGetRow(image,lptr,y,0);
213         lptr += image->xsize;
214     }
215     ImageClose(image);
216 }
217
218 void
219 SGTexture::read_rgb_texture(const char *name)
220 {
221     GLubyte *ptr;
222     GLubyte *rbuf, *gbuf, *bbuf;
223     SGTexture::ImageRec *image;
224     int y;
225
226     delete[] texture_data;
227
228     image = ImageOpen(name);
229     if(!image) {
230         errstr = FILE_OPEN_ERROR;
231         return;
232     }
233
234     texture_width = image->xsize;
235     texture_height = image->ysize;
236     if (image->zsize < 1 || image->zsize > 4) {
237       ImageClose(image);
238       errstr = WRONG_COUNT;
239       return;
240     }
241
242     num_colors = 3;
243     texture_data = new GLubyte[ image->xsize * image->ysize * num_colors ];
244     rbuf = new GLubyte[ image->xsize ];
245     gbuf = new GLubyte[ image->xsize ];
246     bbuf = new GLubyte[ image->xsize ];
247     if(!texture_data || !rbuf || !gbuf || !bbuf) {
248       delete[] texture_data;
249       delete[] rbuf;
250       delete[] gbuf;
251       delete[] bbuf;
252       errstr = OUT_OF_MEMORY;
253       return;
254     }
255
256     ptr = texture_data;
257     for(y=0; y<image->ysize; y++) {
258         if(image->zsize == 4 || image->zsize == 3) {
259             ImageGetRow(image,rbuf,y,0);
260             ImageGetRow(image,gbuf,y,1);
261             ImageGetRow(image,bbuf,y,2);
262         } else {
263             ImageGetRow(image,rbuf,y,0);
264             memcpy(gbuf,rbuf,image->xsize);
265             memcpy(bbuf,rbuf,image->xsize);
266         }
267         rgbtorgb(rbuf,gbuf,bbuf,ptr,image->xsize);
268         ptr += (image->xsize * num_colors);
269     }
270
271     ImageClose(image);
272     delete[] rbuf;
273     delete[] gbuf;
274     delete[] bbuf;
275 }
276
277
278
279 void
280 SGTexture::read_rgba_texture(const char *name)
281 {
282     GLubyte *ptr;
283     GLubyte *rbuf, *gbuf, *bbuf, *abuf;
284     SGTexture::ImageRec *image;
285     int y;
286
287     delete[] texture_data;
288
289     image = ImageOpen(name);
290     if(!image) {
291         errstr = FILE_OPEN_ERROR;
292         return;
293     }
294
295     texture_width = image->xsize;
296     texture_height = image->ysize;
297     if (image->zsize < 1 || image->zsize > 4) {
298       ImageClose(image);
299       errstr = WRONG_COUNT;
300       return;
301     }
302
303     num_colors = 4;
304     texture_data = new GLubyte[ image->xsize * image->ysize * num_colors ];
305     rbuf = new GLubyte[ image->xsize ];
306     gbuf = new GLubyte[ image->xsize ];
307     bbuf = new GLubyte[ image->xsize ];
308     abuf = new GLubyte[ image->xsize ];
309     if(!texture_data || !rbuf || !gbuf || !bbuf || !abuf) {
310       delete[] texture_data;
311       delete[] rbuf;
312       delete[] gbuf;
313       delete[] bbuf;
314       delete[] abuf;
315       errstr = OUT_OF_MEMORY;
316       return;
317     }
318
319     ptr = texture_data;
320     for(y=0; y<image->ysize; y++) {
321         if(image->zsize == 4) {
322             ImageGetRow(image,rbuf,y,0);
323             ImageGetRow(image,gbuf,y,1);
324             ImageGetRow(image,bbuf,y,2);
325             ImageGetRow(image,abuf,y,3);
326         } else if(image->zsize == 3) {
327             ImageGetRow(image,rbuf,y,0);
328             ImageGetRow(image,gbuf,y,1);
329             ImageGetRow(image,bbuf,y,2);
330             memset(abuf, 255, image->xsize);
331         } else if(image->zsize == 2) {
332             ImageGetRow(image,rbuf,y,0);
333             memcpy(gbuf,rbuf,image->xsize);
334             memcpy(bbuf,rbuf,image->xsize);
335             ImageGetRow(image,abuf,y,1);
336         } else {
337             ImageGetRow(image,rbuf,y,0);
338             memcpy(gbuf,rbuf,image->xsize);
339             memcpy(bbuf,rbuf,image->xsize);
340             memset(abuf, 255, image->xsize);
341         }
342         rgbatorgba(rbuf,gbuf,bbuf,abuf,ptr,image->xsize);
343         ptr += (image->xsize * num_colors);
344     }
345
346     ImageClose(image);
347     delete[] rbuf;
348     delete[] gbuf;
349     delete[] bbuf;
350     delete[] abuf;
351 }
352
353 void
354 SGTexture::read_raw_texture(const char *name)
355 {
356     GLubyte *ptr;
357     SGTexture::ImageRec *image;
358     int y;
359
360     delete[] texture_data;
361
362     image = RawImageOpen(name);
363
364     if(!image) {
365         errstr = FILE_OPEN_ERROR;
366         return;
367     }
368
369     texture_width = 256;
370     texture_height = 256;
371
372     texture_data = new GLubyte[ 256 * 256 * 3 ];
373     if(!texture_data) {
374       errstr = OUT_OF_MEMORY;
375       return;
376     }
377
378     ptr = texture_data;
379     for(y=0; y<256; y++) {
380         gzread(image->file, ptr, 256*3);
381         ptr+=256*3;
382     }
383     ImageClose(image);
384 }
385
386 void
387 SGTexture::read_r8_texture(const char *name)
388 {
389     unsigned char c[1];
390     GLubyte *ptr;
391     SGTexture::ImageRec *image;
392     int xy;
393
394     delete[] texture_data;
395
396     //it wouldn't make sense to write a new function ...
397     image = RawImageOpen(name);
398
399     if(!image) {
400         errstr = FILE_OPEN_ERROR;
401         return;
402     }
403
404     texture_width = 256;
405     texture_height = 256;
406
407     texture_data = new GLubyte [ 256 * 256 * 3 ];
408     if(!texture_data) {
409         errstr = OUT_OF_MEMORY;
410         return;
411     }
412
413     ptr = texture_data;
414     for(xy=0; xy<(256*256); xy++) {
415         gzread(image->file, c, 1);
416
417         //look in the table for the right colours
418         ptr[0]=msfs_colour[c[0]][0];
419         ptr[1]=msfs_colour[c[0]][1];
420         ptr[2]=msfs_colour[c[0]][2];
421
422         ptr+=3;
423     }
424     ImageClose(image);
425 }
426
427
428 void
429 SGTexture::write_texture(const char *name) {
430    SGTexture::ImageRec *image = ImageWriteOpen(name);
431
432    for (int c=0; c<num_colors; c++) {
433       GLubyte *ptr = texture_data + c;
434       for (int y=0; y<texture_height; y++) {
435          for (int x=0; x<texture_width; x++) {
436             image->tmp[x]=*ptr;
437             ptr = ptr + num_colors;
438          }
439          fwrite(image->tmp, 1, texture_width, file);
440       }
441    }
442
443    ImageClose(image);
444 }
445
446
447 void
448 SGTexture::set_pixel(GLuint x, GLuint y, GLubyte *c)
449 {
450     if (!texture_data) {
451         errstr = NO_TEXTURE;
452         return;
453     }
454
455     unsigned int pos = (x + y*texture_width) * num_colors;
456     memcpy(texture_data+pos, c, num_colors);
457 }
458
459
460 GLubyte *
461 SGTexture::get_pixel(GLuint x, GLuint y)
462 {
463     static GLubyte c[4] = {0, 0, 0, 0};
464
465     if (!texture_data) {
466         errstr = NO_TEXTURE;
467         return c;
468     }
469
470     unsigned int pos = (x + y*texture_width)*num_colors;
471     memcpy(c, texture_data + pos, num_colors);
472
473     return c;
474 }
475
476 SGTexture::ImageRec *
477 SGTexture::ImageOpen(const char *fileName)
478 {
479      union {
480        int testWord;
481        char testByte[4];
482      } endianTest;
483
484     SGTexture::ImageRec *image;
485     int swapFlag;
486     int x;
487
488     endianTest.testWord = 1;
489     if (endianTest.testByte[0] == 1) {
490         swapFlag = 1;
491     } else {
492         swapFlag = 0;
493     }
494
495     image = new SGTexture::ImageRec;
496     memset(image, 0, sizeof(SGTexture::ImageRec));
497     if (image == 0) {
498         errstr = OUT_OF_MEMORY;
499         return 0;
500     }
501     if ((image->file = gzopen(fileName, "rb")) == 0) {
502       errstr = FILE_OPEN_ERROR;
503       return 0;
504     }
505
506     gzread(image->file, image, 12);
507
508     if (swapFlag) {
509         ConvertShort(&image->imagic, 6);
510     }
511
512     image->tmp = new GLubyte[ image->xsize * 256 ];
513     if (image->tmp == 0) {
514         errstr = OUT_OF_MEMORY;
515         return 0;
516     }
517
518     if ((image->type & 0xFF00) == 0x0100) {
519         x = image->ysize * image->zsize * (int) sizeof(unsigned);
520         image->rowStart = new unsigned[x];
521         image->rowSize = new int[x];
522         if (image->rowStart == 0 || image->rowSize == 0) {
523             errstr = OUT_OF_MEMORY;
524             return 0;
525         }
526         image->rleEnd = 512 + (2 * x);
527         gzseek(image->file, 512, SEEK_SET);
528         gzread(image->file, image->rowStart, x);
529         gzread(image->file, image->rowSize, x);
530         if (swapFlag) {
531             ConvertUint(image->rowStart, x/(int) sizeof(unsigned));
532             ConvertUint((unsigned *)image->rowSize, x/(int) sizeof(int));
533         }
534     }
535     return image;
536 }
537
538
539 void
540 SGTexture::ImageClose(SGTexture::ImageRec *image) {
541     if (image->file)  gzclose(image->file);
542     if (file) fclose(file);
543     delete[] image->tmp;
544     delete[] image->rowStart;
545     delete[] image->rowSize;
546     delete image;
547 }
548
549 SGTexture::ImageRec *
550 SGTexture::RawImageOpen(const char *fileName)
551 {
552      union {
553        int testWord;
554        char testByte[4];
555      } endianTest;
556
557     SGTexture::ImageRec *image;
558     int swapFlag;
559
560     endianTest.testWord = 1;
561     if (endianTest.testByte[0] == 1) {
562         swapFlag = 1;
563     } else {
564         swapFlag = 0;
565     }
566
567     image = new SGTexture::ImageRec;
568     memset(image, 0, sizeof(SGTexture::ImageRec));
569     if (image == 0) {
570         errstr = OUT_OF_MEMORY;
571         return 0;
572     }
573     if ((image->file = gzopen(fileName, "rb")) == 0) {
574       errstr = FILE_OPEN_ERROR;
575       return 0;
576     }
577
578     gzread(image->file, image, 12);
579
580     if (swapFlag) {
581         ConvertShort(&image->imagic, 6);
582     }
583
584
585     //just allocate a pseudo value as I'm too lazy to change ImageClose()...
586     image->tmp = new GLubyte[1];
587
588     if (image->tmp == 0) {
589         errstr = OUT_OF_MEMORY;
590         return 0;
591     }
592
593     return image;
594 }
595
596 SGTexture::ImageRec *
597 SGTexture::ImageWriteOpen(const char *fileName)
598 {
599     union {
600         int testWord;
601         char testByte[4];
602     } endianTest;
603     ImageRec* image;
604     int swapFlag;
605     int x;
606
607     endianTest.testWord = 1;
608     if (endianTest.testByte[0] == 1) {
609         swapFlag = 1;
610     } else {
611         swapFlag = 0;
612     }
613
614     image = new SGTexture::ImageRec;
615     memset(image, 0, sizeof(SGTexture::ImageRec));
616     if (image == 0) {
617         errstr = OUT_OF_MEMORY;
618         return 0;
619     }
620     if ((file = fopen(fileName, "wb")) == 0) {
621         errstr = FILE_OPEN_ERROR;
622         return 0;
623     }
624
625     image->imagic = 474;
626     image->type = 0x0001;
627     image->dim = (num_colors > 1) ? 3 : 2;
628     image->xsize = texture_width;
629     image->ysize = texture_height;
630     image->zsize = num_colors;
631
632     if (swapFlag) {
633         ConvertShort(&image->imagic, 6);
634     }
635
636     fwrite(image, 1, 12, file);
637     fseek(file, 512, SEEK_SET);
638
639     image->tmp = new GLubyte[ image->xsize * 256 ];
640     if (image->tmp == 0) {
641         errstr = OUT_OF_MEMORY;
642         return 0;
643     }
644
645     if ((image->type & 0xFF00) == 0x0100) {
646         x = image->ysize * image->zsize * (int) sizeof(unsigned);
647         image->rowStart = new unsigned[x];
648         image->rowSize = new int[x];
649         if (image->rowStart == 0 || image->rowSize == 0) {
650             errstr = OUT_OF_MEMORY;
651             return 0;
652         }
653         image->rleEnd = 512 + (2 * x);
654         fseek(file, 512, SEEK_SET);
655         fread(image->rowStart, 1, x, file);
656         fread(image->rowSize, 1, x, file);
657         if (swapFlag) {
658             ConvertUint(image->rowStart, x/(int) sizeof(unsigned));
659             ConvertUint((unsigned *)image->rowSize, x/(int) sizeof(int));
660         }
661     }
662
663     return image;
664
665 }
666
667 void
668 SGTexture::ImageGetRow(SGTexture::ImageRec *image, GLubyte *buf, int y, int z) {
669     GLubyte *iPtr, *oPtr, pixel;
670     int count;
671
672     if ((image->type & 0xFF00) == 0x0100) {
673         gzseek(image->file, (long) image->rowStart[y+z*image->ysize], SEEK_SET);
674         int size = image->rowSize[y+z*image->ysize];
675         gzread(image->file, image->tmp, size);
676
677         iPtr = image->tmp;
678         oPtr = buf;
679         for (GLubyte *limit = iPtr + size; iPtr < limit;) {
680             pixel = *iPtr++;
681             count = (int)(pixel & 0x7F);
682             if (!count) {
683                 errstr = WRONG_COUNT;
684                 return;
685             }
686             if (pixel & 0x80) {
687                 while (iPtr < limit && count--) {
688                     *oPtr++ = *iPtr++;
689                 }
690             } else if (iPtr < limit) {
691                 pixel = *iPtr++;
692                 while (count--) {
693                     *oPtr++ = pixel;
694                 }
695             }
696         }
697     } else {
698         gzseek(image->file, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
699               SEEK_SET);
700         gzread(image->file, buf, image->xsize);
701     }
702 }
703
704 void
705 SGTexture::ImagePutRow(SGTexture::ImageRec *image, GLubyte *buf, int y, int z) {
706     GLubyte *iPtr, *oPtr, pixel;
707     int count;
708
709     if ((image->type & 0xFF00) == 0x0100) {
710         fseek(file, (long) image->rowStart[y+z*image->ysize], SEEK_SET);
711         fread( image->tmp, 1, (unsigned int)image->rowSize[y+z*image->ysize],
712                file);
713
714         iPtr = image->tmp;
715         oPtr = buf;
716         for (;;) {
717             pixel = *iPtr++;
718             count = (int)(pixel & 0x7F);
719             if (!count) {
720                 errstr = WRONG_COUNT;
721                 return;
722             }
723             if (pixel & 0x80) {
724                 while (count--) {
725                     *oPtr++ = *iPtr++;
726                 }
727             } else {
728                 pixel = *iPtr++;
729                 while (count--) {
730                     *oPtr++ = pixel;
731                 }
732             }
733         }
734     } else {
735         fseek(file, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
736               SEEK_SET);
737         fread(buf, 1, image->xsize, file);
738     }
739 }
740
741
742 void
743 SGTexture::rgbtorgb(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *l, int n) {
744     while(n--) {
745         l[0] = r[0];
746         l[1] = g[0];
747         l[2] = b[0];
748         l += 3; r++; g++; b++;
749     }
750 }
751
752 void
753 SGTexture::rgbatorgba(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *a,
754                       GLubyte *l, int n) {
755     while(n--) {
756         l[0] = r[0];
757         l[1] = g[0];
758         l[2] = b[0];
759         l[3] = a[0];
760         l += 4; r++; g++; b++; a++;
761     }
762 }
763
764
765 void
766 SGTexture::ConvertShort(unsigned short *array, unsigned int length) {
767     unsigned short b1, b2;
768     unsigned char *ptr;
769
770     ptr = (unsigned char *)array;
771     while (length--) {
772         b1 = *ptr++;
773         b2 = *ptr++;
774         *array++ = (b1 << 8) | (b2);
775     }
776 }
777
778
779 void
780 SGTexture::ConvertUint(unsigned *array, unsigned int length) {
781     unsigned int b1, b2, b3, b4;
782     unsigned char *ptr;
783
784     ptr = (unsigned char *)array;
785     while (length--) {
786         b1 = *ptr++;
787         b2 = *ptr++;
788         b3 = *ptr++;
789         b4 = *ptr++;
790         *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
791     }
792 }
793
794
795 void
796 SGTexture::make_monochrome(float contrast, GLubyte r, GLubyte g, GLubyte b) {
797
798    if (num_colors >= 3)
799       return;
800
801    GLubyte ap[3];
802    for (int y=0; y<texture_height; y++)
803       for (int x=0; x<texture_width; x++)
804       {
805          GLubyte *rgb = get_pixel(x,y);
806          GLubyte avg = (rgb[0] + rgb[1] + rgb[2]) / 3;
807
808          if (contrast != 1.0) {
809             float pixcol = -1.0 + (avg/128);
810             avg = 128 + int(128*pow(pixcol, contrast));
811          }
812
813          ap[0] = avg*r/255;
814          ap[1] = avg*g/255;
815          ap[2] = avg*b/255;
816
817          set_pixel(x,y,ap);
818       }
819 }
820
821
822 void
823 SGTexture::make_grayscale(float contrast) {
824    if (num_colors < 3)
825       return;
826
827    int colors = (num_colors == 3) ? 1 : 2;
828    GLubyte *map = new GLubyte[ texture_width * texture_height * colors ];
829
830    for (int y=0; y<texture_height; y++)
831       for (int x=0; x<texture_width; x++)
832       {
833          GLubyte *rgb = get_pixel(x,y);
834          GLubyte avg = (rgb[0] + rgb[1] + rgb[2]) / 3;
835
836          if (contrast != 1.0) {
837             float pixcol = -1.0 + (avg/128);
838             avg = 128 + int(128*pow(pixcol, contrast));
839          }
840
841          int pos = (x + y*texture_width)*colors;
842          map[pos] = avg;
843          if (colors > 1)
844             map[pos+1] = rgb[3];
845       }
846
847    delete[] texture_data;
848    texture_data = map;
849    num_colors = colors;
850 }
851
852
853 void
854 SGTexture::make_maxcolorwindow() {
855    GLubyte minmaxc[2] = {255, 0};
856
857    int pos = 0;
858    int max = num_colors;
859    if (num_colors == 2) max = 1;
860    if (num_colors == 4) max = 3; 
861    while (pos < texture_width * texture_height * num_colors) {
862       for (int i=0; i < max; i++) {
863          GLubyte c = texture_data[pos+i];
864          if (c < minmaxc[0]) minmaxc[0] = c;
865          if (c > minmaxc[1]) minmaxc[1] = c;
866       }
867       pos += num_colors;
868    }
869
870    GLubyte offs = minmaxc[0];
871    float factor = 255.0 / float(minmaxc[1] - minmaxc[0]);
872    // printf("Min: %i, Max: %i, Factor: %f\n", offs, minmaxc[1], factor);
873
874    pos = 0;
875    while (pos < texture_width * texture_height * num_colors) {
876       for (int i=0; i < max; i++) {
877          texture_data[pos+i] -= offs;
878          texture_data[pos+i] = int(factor * texture_data[pos+i]);
879       }
880       pos += num_colors;
881    }
882 }
883
884
885 void
886 SGTexture::make_normalmap(float brightness, float contrast) {
887    make_grayscale(contrast);
888    make_maxcolorwindow();
889
890    int colors = (num_colors == 1) ? 3 : 4;
891    bool alpha = (colors > 3);
892    int tsize = texture_width * texture_height * colors;
893    GLubyte *map = new GLubyte[ tsize ];
894
895    int mpos = 0, dpos = 0;
896    for (int y=0; y<texture_height; y++) {
897       int ytw = y*texture_width;
898
899       for (int x=0; x<texture_width; x++)
900       {
901          int xp1 = (x < (texture_width-1)) ? x+1 : 0;
902          int yp1 = (y < (texture_height-1)) ? y+1 : 0;
903          int posxp1 = (xp1 + ytw)*num_colors;
904          int posyp1 = (x + yp1*texture_width)*num_colors;
905          float fx,fy;
906
907          GLubyte c = texture_data[dpos];
908          GLubyte cx1 = texture_data[posxp1];
909          GLubyte cy1 = texture_data[posyp1];
910
911          if (alpha) {
912             GLubyte a = texture_data[dpos+1];
913             GLubyte ax1 = texture_data[posxp1+1];
914             GLubyte ay1 = texture_data[posyp1+1];
915
916             c = (c + a)/2;
917             cx1 = (cx1 + ax1)/2;
918             cy1 = (cy1 + ay1)/2;
919
920             map[mpos+3] = a;
921          }
922
923          fx = asin((c/256.0-cx1/256.0))/1.57079633;
924          fy = asin((cy1/256.0-c/256.0))/1.57079633;
925
926          map[mpos+0] = (GLuint)(fx*256.0)-128;
927          map[mpos+1] = (GLuint)(fy*256.0)-128;
928          map[mpos+2] = 127+int(brightness*128); // 255-c/2;
929
930          mpos += colors;
931          dpos += num_colors;
932       }
933    }
934
935    delete[] texture_data;
936    texture_data = map;
937    num_colors = colors;
938 }
939
940
941 void
942 SGTexture::make_bumpmap(float brightness, float contrast) {
943    make_grayscale(contrast);
944
945    int colors = (num_colors == 1) ? 1 : 2;
946    GLubyte *map = new GLubyte[ texture_width * texture_height * colors ];
947
948    for (int y=0; y<texture_height; y++)
949       for (int x=0; x<texture_width; x++)
950       {
951          int mpos = (x + y*texture_width)*colors;
952          int dpos = (x + y*texture_width)*num_colors;
953
954          int xp1 = (x < (texture_width-1)) ? x+1 : 0;
955          int yp1 = (y < (texture_height-1)) ? y+1 : 0;
956          int posxp1 = (xp1 + y*texture_width)*num_colors;
957          int posyp1 = (x + yp1*texture_width)*num_colors;
958
959          map[mpos] = (127 - ((texture_data[dpos]-texture_data[posxp1]) -
960                             ((texture_data[dpos]-texture_data[posyp1]))/4))/2;
961          if (colors > 1)
962             map[mpos+1] = texture_data[dpos+1];
963       }
964
965    delete[] texture_data;
966    texture_data = map;
967    num_colors = colors;
968 }
969