1 /*
2 
3 *************************************************************************
4 
5 ArmageTron -- Just another Tron Lightcycle Game in 3D.
6 Copyright (C) 2000  Manuel Moos (manuel@moosnet.de)
7 
8 **************************************************************************
9 
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23 
24 ***************************************************************************
25 
26 */
27 
28 #include "rSDL.h"
29 
30 #include "config.h"
31 
32 #include "rTexture.h"
33 #include "rDisplayList.h"
34 #include "tString.h"
35 #include "rScreen.h"
36 #include "tDirectories.h"
37 #include "tLocale.h"
38 #include "tException.h"
39 #include "tResourceManager.h"
40 
41 #include <sstream>
42 
43 #ifndef DEDICATED
44 #include "rRender.h"
45 #include "rGL.h"
46 
47 // Load the right SDL_IMAGE header
48 
49 #ifdef _MSC_VER
50 #include <SDL_image.h>
51 #else
52 #ifdef __MINGW32__
53 #include <SDL_image.h>
54 #else
55 #ifdef HAVE_SDL_IMG_H
56 #include <SDL_image.h>
57 #else
58 #ifdef HAVE_SDL_SDL_IMAGE_H
59 #include <SDL/SDL_image.h>
60 #else
61 #ifdef HAVE_IMG_H
62 #include <IMG.h>
63 #else
64 #ifdef HAVE_SDL_IMG_H
65 #include <SDL/IMG.h>
66 #else
67 #ifdef HAVE_LIBSDL
68 #include <SDL_image.h>
69 #else
70 #ifdef HAVE_LIBIMG
71 #include <IMG.h>
72 #else
73 // if the following include ( or one of the earlier ones ) fails, you don't have SDL_image properly installed.
74 #include <SDL_image.h>
75 #endif
76 #endif
77 #endif
78 #endif
79 #endif
80 #endif
81 #endif
82 #endif
83 #endif
84 
85 
86 // ******************************************************************************************
87 // *
88 // *	rSurface
89 // *
90 // ******************************************************************************************
91 //!
92 //!		@param	fileName	name of the file to load sufrace from
93 //!
94 // ******************************************************************************************
95 
rSurface(char const * fileName)96 rSurface::rSurface( char const * fileName )
97 {
98     Init();
99     Create( fileName );
100 }
101 
102 // ******************************************************************************************
103 // *
104 // *	~rSurface
105 // *
106 // ******************************************************************************************
107 //!
108 //!
109 // ******************************************************************************************
110 
~rSurface(void)111 rSurface::~rSurface( void )
112 {
113     Clear();
114 }
115 
116 // ******************************************************************************************
117 // *
118 // *	rSurface
119 // *
120 // ******************************************************************************************
121 //!
122 //!
123 // ******************************************************************************************
124 
rSurface(void)125 rSurface::rSurface( void )
126 {
127     Init();
128 }
129 
130 // ******************************************************************************************
131 // *
132 // *   rSurface
133 // *
134 // ******************************************************************************************
135 //!
136 //!        @param  other   source to copy from
137 //!
138 // ******************************************************************************************
139 
rSurface(rSurface const & other)140 rSurface::rSurface( rSurface const & other )
141 {
142     Init();
143     CopyFrom( other );
144 }
145 
146 // ******************************************************************************************
147 // *
148 // *   operator =
149 // *
150 // ******************************************************************************************
151 //!
152 //!        @param  other
153 //!        @return
154 //!
155 // ******************************************************************************************
156 
operator =(rSurface const & other)157 rSurface & rSurface::operator =( rSurface const & other )
158 {
159     if ( &other != this )
160     {
161         Clear();
162         CopyFrom( other );
163     }
164 
165     return *this;
166 }
167 
168 // ******************************************************************************************
169 // *
170 // *	Init
171 // *
172 // ******************************************************************************************
173 //!
174 //!
175 // ******************************************************************************************
176 
Init(void)177 void rSurface::Init( void )
178 {
179     surface_ = 0;
180     format_ = 0;
181 }
182 
183 // ******************************************************************************************
184 // *
185 // *   Clear
186 // *
187 // ******************************************************************************************
188 //!
189 //!
190 // ******************************************************************************************
191 
Clear(void)192 void rSurface::Clear( void )
193 {
194 #ifndef DEDICATED
195     // delete surface
196     if ( surface_ )
197         SDL_FreeSurface( surface_ );
198 
199 #endif
200     surface_ = 0;
201 }
202 
203 // ******************************************************************************************
204 // *
205 // *	Create
206 // *
207 // ******************************************************************************************
208 //!
209 //!		@param	fileName	name of the image file to load
210 //!
211 // ******************************************************************************************
212 
Create(char const * fileName)213 void rSurface::Create( char const * fileName )
214 {
215 #ifndef DEDICATED
216     sr_LockSDL();
217 
218     // find path of image
219     // tString s = tResourceManager::locateResource("", fileName);
220     tString s = tDirectories::Data().GetReadPath( fileName );
221 
222     // Load image
223     IMG_InvertAlpha(true);
224     Create( IMG_Load(s) );
225 
226     //if ( surface_ )
227     //    std::cerr << "loaded surface " << fileName << "\n";
228 
229     sr_UnlockSDL();
230 #endif
231 }
232 
233 // ******************************************************************************************
234 // *
235 // *	Create
236 // *
237 // ******************************************************************************************
238 //!
239 //!		@param	surface
240 //!
241 // ******************************************************************************************
242 
Create(SDL_Surface * surface)243 void rSurface::Create( SDL_Surface * surface )
244 {
245 #ifndef DEDICATED
246     // clear previous surface
247     Clear();
248 
249     // take ownership
250     surface_ = surface;
251 
252     // determine texture format
253     if ( surface_ )
254     {
255         switch (surface_->format->BytesPerPixel){
256         case 1:
257             format_ = GL_LUMINANCE;
258             break;
259 
260         case 2:
261             format_ = GL_LUMINANCE8_ALPHA8;
262             break;
263 
264         case 3:
265             format_ = GL_RGB;
266             break;
267 
268         case 4:
269             format_ = GL_RGBA;
270             break;
271 
272         default:
273             {
274                 // fallback: convert the texture into a known format.
275 
276                 SDL_Surface *dummy =
277                     SDL_CreateRGBSurface(SDL_SWSURFACE, 1, 1,
278                                          32,
279                                          0x0000FF, 0x00FF00,
280                                          0xFF0000 ,0xFF000000);
281 
282                 SDL_Surface *convtex =
283                     SDL_ConvertSurface(surface_, dummy->format, SDL_SWSURFACE);
284 
285                 SDL_FreeSurface(surface_);
286                 surface_ = convtex;
287                 SDL_FreeSurface(dummy);
288 
289                 format_ = GL_RGBA;
290             }
291             break;
292         }
293     }
294 #endif
295 }
296 
297 // ******************************************************************************************
298 // *
299 // *	CopyFrom
300 // *
301 // ******************************************************************************************
302 //!
303 //!		@param	other
304 //!
305 // ******************************************************************************************
306 
CopyFrom(rSurface const & other)307 void rSurface::CopyFrom( rSurface const & other )
308 {
309 #ifndef DEDICATED
310     tASSERT( 0 == surface_ );
311     tASSERT( other.surface_ );
312 
313     // copy surface
314     surface_ = SDL_ConvertSurface(other.surface_, other.surface_->format, SDL_SWSURFACE);
315 
316     // copy flags
317     format_ = other.format_;
318 #endif
319 }
320 
321 // ******************************************************************************************
322 // *
323 // *	~rITexture
324 // *
325 // ******************************************************************************************
326 //!
327 //!
328 // ******************************************************************************************
329 
~rITexture(void)330 rITexture::~rITexture( void )
331 {
332     s_textures_.Remove(this,id_);
333 }
334 
335 // ******************************************************************************************
336 // *
337 // *	UnloadAll
338 // *
339 // ******************************************************************************************
340 //!
341 //!
342 // ******************************************************************************************
343 
UnloadAll(void)344 void rITexture::UnloadAll( void )
345 {
346     for(int i=s_textures_.Len()-1;i>=0;i--)
347     {
348         s_textures_(i)->Unload();
349     }
350 }
351 
352 // ******************************************************************************************
353 // *
354 // *	LoadAll
355 // *
356 // ******************************************************************************************
357 //!
358 //!
359 // ******************************************************************************************
360 
LoadAll(void)361 void rITexture::LoadAll( void )
362 {
363     // s_reportErrors=false;
364     for(int i=s_textures_.Len()-1;i>=0;i--)
365     {
366         s_textures_(i)->Select();
367         //if (i>=s_textures.Len())
368         //    i=s_textures.Len()-1;
369     }
370     // s_reportErrors=true;
371 }
372 
373 // ******************************************************************************************
374 // *
375 // *	rITexture
376 // *
377 // ******************************************************************************************
378 //!
379 //!
380 // ******************************************************************************************
381 
rITexture(void)382 rITexture::rITexture( void )
383         : id_( -1 )
384 {
385 }
386 
387 // ******************************************************************************************
388 // *
389 // *	OnSelect
390 // *
391 // ******************************************************************************************
392 //!
393 //!		@param	enforce enforce when set to true, the texture should be loaded even if the configuration says it should not
394 //!
395 // ******************************************************************************************
396 
OnSelect(bool enforce)397 void rITexture::OnSelect( bool enforce )
398 {
399     if ( id_ < 0 )
400         s_textures_.Add(this,id_);
401 }
402 
403 // ******************************************************************************************
404 // *
405 // *	OnUnload
406 // *
407 // ******************************************************************************************
408 //!
409 //!
410 // ******************************************************************************************
411 
OnUnload(void)412 void rITexture::OnUnload( void )
413 {
414 }
415 
416 // ******************************************************************************************
417 // *
418 // *	rISurfaceTexture
419 // *
420 // ******************************************************************************************
421 //!
422 //!		@param	group	texture group ( floor/wall)
423 //!		@param	repx    flag indicating the x repeat mode
424 //!		@param	repy    flag indicating the y repeat mode
425 //!		@param	storeAlpha flag indicating whether the alpha channel should be stored
426 //!
427 // ******************************************************************************************
428 
rISurfaceTexture(int group,bool repx,bool repy,bool storeAlpha)429 rISurfaceTexture::rISurfaceTexture( int group, bool repx, bool repy, bool storeAlpha )
430         : group_( group ), textureModeLast_( -1), tint_( 0 ), repx_( repx ), repy_( repy ), storeAlpha_( storeAlpha )
431 {
432 }
433 
434 // ******************************************************************************************
435 // *
436 // *	~rISurfaceTexture
437 // *
438 // ******************************************************************************************
439 //!
440 //!
441 // ******************************************************************************************
442 
~rISurfaceTexture(void)443 rISurfaceTexture::~rISurfaceTexture( void )
444 {
445 #ifndef DEDICATED
446     if (tint_ > 0)
447     {
448         rDisplayList::ClearAll();
449 
450         glDeleteTextures(1,&tint_);
451         tint_ = 0;
452     }
453 #endif
454 }
455 
456 // ******************************************************************************************
457 // *
458 // *	ProcessImage
459 // *
460 // ******************************************************************************************
461 //!
462 //!		@param	surface the surface to process
463 //!
464 // ******************************************************************************************
465 
ProcessImage(SDL_Surface * surface)466 void rISurfaceTexture::ProcessImage( SDL_Surface * surface )
467 {
468 }
469 
470 // ******************************************************************************************
471 // *
472 // *	Upload
473 // *
474 // ******************************************************************************************
475 //!
476 //!		@param	surface
477 //!
478 // ******************************************************************************************
479 
Upload(rSurface & surface)480 void rISurfaceTexture::Upload( rSurface & surface )
481 {
482 #ifndef DEDICATED
483     sr_LockSDL();
484     GLenum texformat = surface.GetFormat();
485     SDL_Surface * tex = surface.GetSurface();
486     tASSERT( tex );
487 
488     bool texalpha=tex->format->Amask;
489 
490     ProcessImage(tex);
491 
492     if(repx_)
493         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
494     else
495         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
496     if(repy_)
497         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
498     else
499         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
500 
501     int format;
502     if (sr_texturesTruecolor)
503         if (storageHack_ || ( storeAlpha_ && texalpha ) )
504             format=GL_RGBA8;
505         else
506             format=GL_RGB8;
507     else
508         if (storageHack_ || ( storeAlpha_ && texalpha ) )
509             format=GL_RGBA4;
510         else
511             format=GL_RGB5;
512 
513     gluBuild2DMipmaps(GL_TEXTURE_2D,format,tex->w,tex->h,
514                       texformat,GL_UNSIGNED_BYTE,tex->pixels);
515 
516     sr_UnlockSDL();
517  #endif
518 }
519 
520 // ******************************************************************************************
521 // *
522 // *	OnSelect
523 // *
524 // ******************************************************************************************
525 //!
526 //!		@param	enforce enforce when set to true, the texture should be loaded even if the configuration says it should not
527 //!
528 // ******************************************************************************************
529 
OnSelect(bool enforce)530 void rISurfaceTexture::OnSelect( bool enforce )
531 {
532 #ifndef DEDICATED
533     if(sr_glOut)
534     {
535         RenderEnd(true);
536 
537         int texmod=rTextureGroups::TextureMode[group_];
538         if (enforce && texmod<0) texmod=GL_NEAREST_MIPMAP_NEAREST;
539 
540         if(textureModeLast_!=texmod)
541         {
542             // unload texture if the mode changed
543             if ( tint_ > 0 )
544                 Unload();
545             tASSERT( tint_ == 0 );
546             // std::cerr << "loading texture " << fileName << ':' << tint << "\n";
547 
548             if (texmod>0){
549                 // don't generate textures inside display lists
550                 rDisplayList::Cancel();
551 
552                 glGenTextures(1, &tint_);
553                 glBindTexture(GL_TEXTURE_2D,tint_);
554 
555                 if (textureModeLast_<0)
556                 {
557                     // delegate core loading work to derived class
558                     OnSelect();
559                 }
560 
561                 //glEnable(GL_TEXTURE);
562                 glEnable(GL_TEXTURE_2D);
563 
564                 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
565                                 texmod);
566 
567                 switch(texmod)
568                 {
569                 case GL_NEAREST:
570                 case GL_NEAREST_MIPMAP_NEAREST:
571                     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,
572                                     GL_NEAREST);
573                     break;
574                 default:
575                     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,
576                                     GL_LINEAR);
577                     break;
578                 }
579 
580             }
581             else
582             {
583                 glDisable(GL_TEXTURE_2D);
584             }
585         }
586         else
587         {
588             glBindTexture(GL_TEXTURE_2D,tint_);
589             if (texmod>0)
590             {
591                 glEnable(GL_TEXTURE_2D);
592             }
593             else
594             {
595                 glDisable(GL_TEXTURE_2D);
596             }
597         }
598         textureModeLast_=texmod;
599     }
600     rITexture::OnSelect(enforce);
601 #endif
602 }
603 
604 // ******************************************************************************************
605 // *
606 // * OnSelect
607 // *
608 // ******************************************************************************************
609 //!
610 //!  In derived classes, this routine is supposed to do the work of loading the texture
611 //!  into memory and using the Upload() function to upload it to OpenGL.
612 //!
613 // ******************************************************************************************
614 
OnSelect()615 void rISurfaceTexture::OnSelect()
616 {
617 }
618 
619 // ******************************************************************************************
620 // *
621 // *	OnUnload
622 // *
623 // ******************************************************************************************
624 //!
625 //!
626 // ******************************************************************************************
627 
OnUnload(void)628 void rISurfaceTexture::OnUnload( void )
629 {
630 #ifndef DEDICATED
631     if (tint_ > 0)
632     {
633         rDisplayList::ClearAll();
634 
635         // std::cerr << "unloading texture " << fileName << ':' << tint_ << "\n";
636         glDeleteTextures(1,&tint_);
637         tint_ = 0;
638     }
639 
640     textureModeLast_=-100;
641     rITexture::OnUnload();
642 #endif
643 }
644 
645 // ******************************************************************************************
646 // *
647 // *	StoreAlpha
648 // *
649 // ******************************************************************************************
650 //!
651 //!
652 // ******************************************************************************************
653 
StoreAlpha(void)654 void rISurfaceTexture::StoreAlpha( void )
655 {
656     storeAlpha_ = true;
657 }
658 
659 // ******************************************************************************************
660 // *
661 // *	rFileTexture
662 // *
663 // ******************************************************************************************
664 //!
665 //!		@param	group	texture group ( floor/wall)
666 //!		@param	fileName the filename of the picture to load
667 //!		@param	repx    flag indicating the x repeat mode
668 //!		@param	repy    flag indicating the y repeat mode
669 //!		@param	storeAlpha flag indicating whether the alpha channel should be stored
670 //!
671 // ******************************************************************************************
672 
rFileTexture(int group,char const * fileName,bool repx,bool repy,bool storeAlpha)673 rFileTexture::rFileTexture( int group, char const * fileName, bool repx, bool repy, bool storeAlpha )
674         : rISurfaceTexture( group, repx, repy, storeAlpha )
675         ,  fileName_( fileName )
676 {
677 }
678 
679 // ******************************************************************************************
680 // *
681 // *	~rFileTexture
682 // *
683 // ******************************************************************************************
684 //!
685 //!
686 // ******************************************************************************************
687 
~rFileTexture(void)688 rFileTexture::~rFileTexture( void )
689 {
690 }
691 
692 // ******************************************************************************************
693 // *
694 // *	OnSelect
695 // *
696 // ******************************************************************************************
697 //!
698 //!
699 // ******************************************************************************************
700 
OnSelect()701 void rFileTexture::OnSelect()
702 {
703 #ifndef DEDICATED
704     // std::cerr << "loading texture " << fileName_ << "\n";
705     rSurface surface( fileName_ );
706     if ( surface.GetSurface() )
707     {
708         this->Upload( surface );
709     }
710     else if (s_reportErrors_)
711     {
712         throw tGenericException( tOutput( "$texture_error_filenotfound", fileName_ ), tOutput("$texture_error_filenotfound_title") );
713     }
714     rISurfaceTexture::OnSelect();
715 #endif
716 }
717 
718 // ******************************************************************************************
719 // *
720 // *	rSurfaceTexture
721 // *
722 // ******************************************************************************************
723 //!
724 //!		@param	group	texture group ( floor/wall)
725 //!		@param	surface
726 //!		@param	repx    flag indicating the x repeat mode
727 //!		@param	repy    flag indicating the y repeat mode
728 //!		@param	storeAlpha flag indicating whether the alpha channel should be stored
729 //!
730 // ******************************************************************************************
731 
rSurfaceTexture(int group,rSurface const & surface,bool repx,bool repy,bool storeAlpha)732 rSurfaceTexture::rSurfaceTexture( int group, rSurface const & surface, bool repx, bool repy, bool storeAlpha )
733         : rISurfaceTexture( group, repx, repy, storeAlpha )
734         , surface_( surface )
735 {
736 }
737 
738 // ******************************************************************************************
739 // *
740 // *	~rSurfaceTexture
741 // *
742 // ******************************************************************************************
743 //!
744 //!
745 // ******************************************************************************************
746 
~rSurfaceTexture(void)747 rSurfaceTexture::~rSurfaceTexture( void )
748 {
749 }
750 
751 // ******************************************************************************************
752 // *
753 // *	OnSelect
754 // *
755 // ******************************************************************************************
756 //!
757 //!
758 // ******************************************************************************************
759 
OnSelect()760 void rSurfaceTexture::OnSelect()
761 {
762 #ifndef DEDICATED
763     // upload a copy of the surface ( it may get modified )
764     if ( surface_.GetSurface() )
765     {
766         rSurface copy( surface_ );
767         this->Upload( copy );
768         rISurfaceTexture::OnSelect();
769     }
770 #endif
771 }
772 
773 
774 bool rISurfaceTexture::s_reportErrors_=false;
775 tList<rITexture> rITexture::s_textures_;
776 
777 int rTextureGroups::TextureMode[rTextureGroups::TEX_GROUPS];
778 
779 char const * rTextureGroups::TextureGroupDescription[rTextureGroups::TEX_GROUPS]=
780     {
781         "$texture_mode_0_help",
782         "$texture_mode_1_help",
783         "$texture_mode_2_help",
784         "$texture_mode_3_help",
785     };
786 
787 bool rISurfaceTexture::storageHack_ = false;
788 
789 //rTexture ArmageTron_eWall("wWall.png",1,0);
790 //rTexture ArmageTron_dir_eWall("wall.png",1,0);
791 
792 
793 static rCallbackBeforeScreenModeChange unload(&rITexture::UnloadAll);
794 
795 // static rCallbackAfterScreenModeChange load(&rITexture::LoadAll);
796