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
SGTexture()35 SGTexture::SGTexture()
36 : texture_id(0),
37 texture_data(0),
38 num_colors(3),
39 file(0)
40 {
41 }
42
SGTexture(unsigned int width,unsigned int height)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
~SGTexture()50 SGTexture::~SGTexture()
51 {
52 delete[] texture_data;
53
54 if ( texture_id != 0 ) {
55 free_id();
56 }
57 }
58
59 void
bind()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
resize(unsigned int width,unsigned int height)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
prepare(unsigned int width,unsigned int height)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
finish(unsigned int width,unsigned int height)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
read_alpha_texture(const char * name)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
read_rgb_texture(const char * name)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
read_rgba_texture(const char * name)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
read_raw_texture(const char * name)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
read_r8_texture(const char * name)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
write_texture(const char * name)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
set_pixel(GLuint x,GLuint y,GLubyte * c)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 *
get_pixel(GLuint x,GLuint y)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 *
ImageOpen(const char * fileName)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
ImageClose(SGTexture::ImageRec * image)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 *
RawImageOpen(const char * fileName)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 *
ImageWriteOpen(const char * fileName)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
ImageGetRow(SGTexture::ImageRec * image,GLubyte * buf,int y,int z)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
ImagePutRow(SGTexture::ImageRec * image,GLubyte * buf,int y,int z)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
rgbtorgb(GLubyte * r,GLubyte * g,GLubyte * b,GLubyte * l,int n)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
rgbatorgba(GLubyte * r,GLubyte * g,GLubyte * b,GLubyte * a,GLubyte * l,int n)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
ConvertShort(unsigned short * array,unsigned int length)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
ConvertUint(unsigned * array,unsigned int length)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
make_monochrome(float contrast,GLubyte r,GLubyte g,GLubyte b)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
make_grayscale(float contrast)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
make_maxcolorwindow()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
make_normalmap(float brightness,float contrast)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
make_bumpmap(float brightness,float contrast)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
970