Back to index

extremetuxracer  0.5beta
snow.cpp
Go to the documentation of this file.
00001 /* 
00002  * PPRacer 
00003  * Copyright (C) 2004-2005 Volker Stroebel <volker@planetpenguin.de>
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version.
00009  * 
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00018  */
00019 
00020 #include "snow.h"
00021 #include "gl_util.h"
00022 #include "course_render.h"
00023 #include "render_util.h"
00024 #include "game_config.h"
00025 #include "player.h"
00026 #include "game_mgr.h"
00027 #include "textures.h"
00028 #include "loop.h"
00029 #include "ppgltk/alg/defs.h"
00030 #include "part_sys.h"
00031 
00032 static double XRANGE = 18;
00033 static double YRANGE = 26;
00034 static double ZRANGE = 27;
00035 
00036 static double NEAR_XRANGE = 12;
00037 static double NEAR_YRANGE = 16;
00038 static double NEAR_ZRANGE = 12;
00039 
00040 //default snowtype : light (decorative snow)
00041 
00042 static double speed = 8;
00043 static double minSize = 0.15; 
00044 static double maxSize = 0.45;
00045 static int MAXPART = 64;
00046 static int MAXNEAR = 30;
00047 
00048 //default windtype : no wind
00049 pp::Vec3d wind_vel(0.0,0.0,0.0);
00050 
00051 double wind_scale = 0.5;
00052 
00053 static double xdrift = 1;
00054 static double ydrift = 1;
00055 static double zdrift = 1;
00056 static double ZWindFactor = 0.0;
00057 static double XWindFactor = 0.0;
00058 
00059 #define MAXTYPES 8
00060 static SnowType snowtypes[MAXTYPES];
00061 static bool istyperegistered[MAXTYPES] = {false,false,false,false,false,false,false,false};
00062 
00063 static WindType windtypes[MAXTYPES];
00064 static bool iswindtyperegistered[MAXTYPES] = {false,false,false,false,false,false,false,false};
00065 
00066 static pp::Vec3d lastPos;
00067 
00068 typedef struct {
00069     pp::Vec3d pt;
00070     double size;
00071     pp::Vec3d vel;
00072     int index_tex;
00073     pp::Vec2d tex_min;
00074     pp::Vec2d tex_max;
00075 } TParticle;
00076 
00077 typedef struct {
00078        double left;
00079        double right;
00080        double bottom;
00081        double top;
00082        double front;
00083        double back;
00084 } TArea;  // the cuboid for the snow flakes
00085 
00086 TParticle* PartArr;
00087 static TArea area;
00088 TParticle* NearArr;
00089 static TArea neararea;
00090 static GLuint snow_tex[4];
00091 
00092 
00093 static double xrand (double min, double max) {
00094               return (double)rand() / RAND_MAX * (max - min) + min; }
00095         
00096 void UpdateArea(pp::Vec3d pos) {
00097     area.left = pos.x - XRANGE / 2;
00098        area.right = area.left + XRANGE;
00099        area.back = pos.z + ZRANGE/3;
00100        area.front = area.back - ZRANGE;
00101        area.top = pos.y + 0.5*YRANGE;
00102        area.bottom = area.top - YRANGE;
00103 
00104 // some remarks about the neararea:
00105 //============================
00106 
00107 // If the size of the flakes is very low they won't appear dense enough
00108 // If the flakes are sized very large they seem to be snowballs in the near area
00109 // This problem can be solved by using two areas, one for the far and ond for the 
00110 // near with smaller flakes
00111 
00112 //if the Yarea doesnt go below the player's Z, then the player can see the snow ahead of him just stopping in midair
00113 //if the Zarea doesnt go behind the player, the player can see that there is no snow behind, when he turns around
00114 
00115        neararea.left = pos.x - NEAR_XRANGE / 2;
00116        neararea.right = neararea.left + NEAR_XRANGE;
00117        neararea.back = pos.z + NEAR_ZRANGE/3;
00118        neararea.front = neararea.back - NEAR_ZRANGE;
00119        neararea.top = pos.y + 0.5*NEAR_YRANGE;
00120        neararea.bottom = neararea.top - NEAR_YRANGE;
00121     
00122     //std::cout << "[snow.cpp] Player position as passed to UpdateArea() : " << pos.x << " " << pos.y << " " << pos.z << "\n";
00123     //std::cout << "[snow.cpp] Updated snow area : " << neararea.left << " " << neararea.back << " " <<neararea.top  << "\n";
00124 }
00125 
00126 //There should be no harm in re-registering wind and snow types... or we should add deregistering at the end of each course
00127 
00128 void RegisterSnowType (int index, SnowType type) {
00129     if((index < MAXTYPES) && (index > -1)) {
00130 //        if(istyperegistered[index] == false) {
00131             snowtypes[index] = type;
00132             istyperegistered[index] = true;
00133 //       } else {
00134 //            std::cerr << "RegisterSnowType, index : " << index << " [ERROR] Type is already registered !\n";
00135 //        }
00136     } else {
00137         std::cerr << "RegisterSnowType, index : " << index << " [ERROR] Index must be in range [0 .. " << MAXTYPES << "]\n";
00138     }
00139 }
00140 
00141 void RegisterWindType (int index, WindType type) {
00142     if((index < MAXTYPES) && (index > -1)) {
00143 //     if(iswindtyperegistered[index] == false) {
00144             windtypes[index] = type;
00145             iswindtyperegistered[index] = true;
00146 //        } else {
00147 //            std::cerr << "RegisterWindType, index : " << index << " [ERROR] Type is already registered !\n";
00148 //        }
00149     } else {
00150         std::cerr << "RegisterWindType, index : " << index << " [ERROR] Index must be in range [0 .. " << MAXTYPES << "]\n";
00151     }
00152 }
00153 
00154 void SetSnowType (int index) {
00155     if((index < MAXTYPES) && (index > -1)) {
00156         if(istyperegistered[index]){
00157             speed = snowtypes[index].speed;
00158             minSize = snowtypes[index].minSize;
00159             maxSize = snowtypes[index].maxSize;
00160             MAXPART = snowtypes[index].MAXPART;
00161             MAXNEAR = snowtypes[index].MAXNEAR;
00162         } else {
00163             std::cerr << "SetSnowType, index : " << index << " [ERROR] No type has been registered with this index !\n";
00164         }
00165     } else {
00166         std::cerr << "RegisterSnowType, index : " << index << " [ERROR] Index must be in range [0 .. " << MAXTYPES << "]\n";
00167     }
00168 }
00169 
00170 void SetWindType (int index) {
00171     if((index < MAXTYPES) && (index > -1)) {
00172         if(iswindtyperegistered[index]){
00173             wind_vel = windtypes[index].wind_vel;
00174         } else {
00175             std::cerr << "SetWindType, index : " << index << " [ERROR] No type has been registered with this index !\n";
00176         }
00177     } else {
00178         std::cerr << "RegisterWindType, index : " << index << " [ERROR] Index must be in range [0 .. " << MAXTYPES << "]\n";
00179     }
00180 }
00181 
00182 static void MakeSnowParticle (int i) {
00183 
00184     double tmp;
00185     int type;
00186        PartArr[i].pt.x = xrand (area.left, area.right);  
00187        PartArr[i].pt.y = xrand (area.bottom, area.top);
00188        PartArr[i].pt.z = xrand(area.back, area.front);
00189 
00190     PartArr[i].size = xrand (minSize, maxSize);
00191        PartArr[i].vel.x = 0;
00192        PartArr[i].vel.y = -PartArr[i].size * speed;
00193        PartArr[i].vel.z = 0;       
00194     
00195     tmp = xrand(0.0,1.0) * (4.0 - EPS);
00196        PartArr[i].index_tex = (int)tmp;
00197     
00198     /*
00199     tmp = xrand(0.0,1.0) * (4.0 - EPS);
00200        type = (int)tmp;
00201        if (type == 0) {
00202               PartArr[i].tex_min = pp::Vec2d(0.0, 0.0);
00203               PartArr[i].tex_max = pp::Vec2d(0.5, 0.5);
00204     } else if (type == 1) {
00205               PartArr[i].tex_min = pp::Vec2d(0.5, 0.0);
00206               PartArr[i].tex_max = pp::Vec2d(1.0, 0.5);
00207     } else if (type == 2) {
00208               PartArr[i].tex_min = pp::Vec2d(0.5, 0.5);
00209               PartArr[i].tex_max = pp::Vec2d(1.0, 1.0);
00210     } else {
00211               PartArr[i].tex_min = pp::Vec2d(0.0, 0.5);
00212               PartArr[i].tex_max = pp::Vec2d(0.5, 1.0);
00213     }
00214     */
00215     PartArr[i].tex_min = pp::Vec2d(0.0, 0.0);
00216     PartArr[i].tex_max = pp::Vec2d(1.0, 1.0);
00217     
00218     //std::cout << "[snow.cpp] Particle, index " << i << " created at " << PartArr[i].pt.x << " " << PartArr[i].pt.y << " " << PartArr[i].pt.z << "\n";
00219 }
00220 
00221 static void MakeNearParticle (int i) {
00222 
00223     double tmp;
00224     int type;
00225        NearArr[i].pt.x = xrand (neararea.left, neararea.right);  
00226        NearArr[i].pt.y = xrand (neararea.bottom, neararea.top);
00227        NearArr[i].pt.z = xrand(neararea.back, neararea.front);
00228 
00229     NearArr[i].size = xrand (minSize / 6, maxSize / 6);
00230        NearArr[i].vel.x = 0;
00231        NearArr[i].vel.y = -NearArr[i].size * speed;
00232        NearArr[i].vel.z = 0;       
00233     
00234     tmp = xrand(0.0,1.0) * (4.0 - EPS);
00235        NearArr[i].index_tex = (int)tmp;
00236     
00237        /*tmp = xrand(0.0,1.0) * (4.0 - EPS);
00238        type = (int)tmp;
00239        if (type == 0) {
00240               NearArr[i].tex_min = pp::Vec2d(0.0, 0.0);
00241               NearArr[i].tex_max = pp::Vec2d(0.5, 0.5);
00242     } else if (type == 1) {
00243               NearArr[i].tex_min = pp::Vec2d(0.5, 0.0);
00244               NearArr[i].tex_max = pp::Vec2d(1.0, 0.5);
00245     } else if (type == 2) {
00246               NearArr[i].tex_min = pp::Vec2d(0.5, 0.5);
00247               NearArr[i].tex_max = pp::Vec2d(1.0, 1.0);
00248     } else {
00249               NearArr[i].tex_min = pp::Vec2d(0.0, 0.5);
00250               NearArr[i].tex_max = pp::Vec2d(0.5, 1.0);
00251     }*/
00252     NearArr[i].tex_min = pp::Vec2d(0.0, 0.0);
00253        NearArr[i].tex_max = pp::Vec2d(1.0, 1.0);
00254     
00255     //std::cout << "[snow.cpp] Near particle, index " << i << " created at " << NearArr[i].pt.x << " " << NearArr[i].pt.y << " " << NearArr[i].pt.z << "\n";
00256 }
00257 
00258 void init_snow( pp::Vec3d playerPos )
00259 {
00260     //tried to call this function in course_load::course_load()
00261     //init_snow(players[0].pos);
00262     //init_snow(players[0].view.pos);
00263     //but both pos and view.pos werent initialized
00264     //now this function is called in racing::racing()
00265     if ( !get_texture_binding("c_snow_flake0", &(snow_tex[0]) ) ) {
00266         std::cerr << "Can't load snow texture : c_snow_flake0 ! Ay Ay Ay !\n";
00267     }
00268     if ( !get_texture_binding("c_snow_flake1", &(snow_tex[1]) ) ) {
00269         std::cerr << "Can't load snow texture : c_snow_flake1 ! Ay Ay Ay !\n";
00270     }
00271     if ( !get_texture_binding("c_snow_flake2", &(snow_tex[2]) ) ) {
00272         std::cerr << "Can't load snow texture : c_snow_flake2 ! Ay Ay Ay !\n";
00273     }
00274     if ( !get_texture_binding("c_snow_flake3", &(snow_tex[3]) ) ) {
00275         std::cerr << "Can't load snow texture : c_snow_flake3 ! Ay Ay Ay !\n";
00276     }
00277     
00278     UpdateArea(playerPos);
00279     NearArr = (TParticle*)malloc(sizeof(TParticle)*MAXNEAR);
00280     PartArr = (TParticle*)malloc(sizeof(TParticle)*MAXPART);
00281     int i;
00282     for(i = 0; i<MAXPART;i++) MakeSnowParticle(i);
00283     for(i = 0; i<MAXNEAR;i++) MakeNearParticle(i);
00284     
00285     lastPos = playerPos;
00286     
00287     /*
00288     UpdateArea(eyepoint);
00289     
00290     int i;
00291     for(i=0;i<MAXPART;i++) {
00292         MakeSnowParticle(i);
00293     }
00294     for(i=0;i<MAXNEAR;i++) {
00295         MakeNearParticle(i);
00296     }
00297     */
00298 }
00299 
00300 void reset_snow() {
00301     free(NearArr);
00302     free(PartArr);
00303 }
00304 
00305 void update_snow( double time_step, bool windy, pp::Vec3d playerPos )
00306 {
00307     UpdateArea(playerPos);
00308  
00309     if ( gameMgr->getCurrentRace().windy ) {
00310         XWindFactor = wind_vel.x * wind_scale * 0.03;
00311         ZWindFactor = wind_vel.z * wind_scale * 0.045;
00312     }
00313   
00314     double xdiff = playerPos.x - lastPos.x;
00315     double ydiff = playerPos.y - lastPos.y;
00316        double zdiff = playerPos.z - lastPos.z;
00317     double xNearCoeff = XWindFactor * time_step + 0.5*(xdiff * xdrift);//We slow down the xdrift for near particles because otherwise the correction would be too obvious when the player turns (having snow flakes "following" him along the x axis)
00318     double xcoeff = XWindFactor * time_step + (xdiff * xdrift);
00319        double ycoeff = (ydiff * ydrift) + (ZWindFactor * 0.025);      
00320        double zcoeff = (ZWindFactor * time_step) + (zdiff * zdrift);
00321     
00322     int i;
00323     
00324     for(i = 0; i<MAXPART;i++) {
00325         //PartArr[i].pt.x += (eyepoint.x - PartArr[0].pt.x);  
00326        //PartArr[i].pt.y += (eyepoint.y - PartArr[0].pt.y) + 1;
00327        //PartArr[i].pt.z += (eyepoint.z - PartArr[0].pt.z);
00328         
00329         //PartArr[i].pt.x += (eyepoint.x - PartArr[0].pt.x);  
00330        //PartArr[i].pt.y += (eyepoint.y - PartArr[0].pt.y) + 1;
00331        //PartArr[i].pt.y += (eyepoint.y - PartArr[0].pt.y);
00332         //PartArr[i].pt.z += PartArr[i].vel.z;
00333         //PartArr[i].pt.z += (eyepoint.z - PartArr[0].pt.z) - 1;
00334         
00335         
00336         if (PartArr[i].pt.x < area.left) {
00337                      PartArr[i].pt.x += XRANGE;
00338               } else if (PartArr[i].pt.x > area.right) {
00339                      PartArr[i].pt.x -= XRANGE;
00340               } else if (PartArr[i].pt.y < area.bottom) {
00341                      PartArr[i].pt.y += YRANGE;  
00342               } else if (PartArr[i].pt.y > area.top) {
00343                      PartArr[i].pt.y -= YRANGE;                
00344               } else if (PartArr[i].pt.z < area.front) {
00345                      PartArr[i].pt.z += ZRANGE;         
00346               } else if (PartArr[i].pt.z > area.back) {
00347                      PartArr[i].pt.z -= ZRANGE;         
00348               }
00349         
00350         PartArr[i].pt.x += xcoeff;
00351               PartArr[i].pt.y += PartArr[i].vel.y * time_step + ycoeff;
00352               PartArr[i].pt.z += zcoeff;
00353     }
00354     for(i = 0; i<MAXNEAR;i++) {
00355         //NearArr[i].pt.x += (eyepoint.x - PartArr[0].pt.x);  
00356         //NearArr[i].pt.y += (eyepoint.y - PartArr[0].pt.y) + 1;
00357         //NearArr[i].pt.z += (eyepoint.z - PartArr[0].pt.z);
00358         //NearArr[i].pt.x += (eyepoint.x - PartArr[0].pt.x);
00359         //NearArr[i].pt.x += NearArr[i].vel.x;
00360         //NearArr[i].pt.y += (eyepoint.y - PartArr[0].pt.y) + 1;
00361         //NearArr[i].pt.y += (eyepoint.y - PartArr[0].pt.y);
00362         //NearArr[i].pt.z += (eyepoint.z - PartArr[0].pt.z) - 1;
00363         
00364         
00365         if (NearArr[i].pt.x < neararea.left) {
00366             NearArr[i].pt.x += NEAR_XRANGE;
00367               } else if (NearArr[i].pt.x > neararea.right) {
00368                      NearArr[i].pt.x -= NEAR_XRANGE;
00369               } else if (NearArr[i].pt.y < neararea.bottom) {
00370                      NearArr[i].pt.y += NEAR_YRANGE;    
00371               } else if (NearArr[i].pt.y > neararea.top) {
00372                      NearArr[i].pt.y -= NEAR_YRANGE;
00373               } else if (NearArr[i].pt.z < neararea.front) {
00374                      NearArr[i].pt.z += NEAR_ZRANGE;           
00375               } else if (NearArr[i].pt.z > neararea.back) {
00376                      NearArr[i].pt.z -= NEAR_ZRANGE;           
00377               }
00378         
00379         NearArr[i].pt.x += xNearCoeff;//We disable the xdrift for near particles because it is too obvious when the player turns
00380               NearArr[i].pt.y += NearArr[i].vel.y * time_step + ycoeff;
00381               NearArr[i].pt.z += zcoeff;
00382     }
00383     
00384     lastPos = playerPos;
00385     
00386     
00387     /*
00388     UpdateArea(eyepoint);
00389     
00390     int i;
00391     for(i=0;i<MAXPART;i++) {
00392         MakeSnowParticle(i);
00393     }
00394     for(i=0;i<MAXNEAR;i++) {
00395         MakeNearParticle(i);
00396     }
00397     */
00398 } 
00399 
00400 void update_wind() {
00401     static float last_time_called = -1;
00402     if ( gameMgr->getCurrentRace().windy ) {
00403         /* adjust wind_scale with a random walk */
00404        if ( last_time_called != gameMgr->time ) {
00405            wind_scale = wind_scale + 
00406               (rand()/(double)RAND_MAX-0.50) * 0.15;
00407            wind_scale = MIN( 1.0, MAX( 0.0, wind_scale ) );
00408        }
00409         last_time_called = gameMgr->time;
00410     }
00411 }
00412 
00413 void draw_snow( pp::Vec3d eyepoint )
00414 {
00415     int i;
00416     double size;
00417 
00418     set_gl_options (PARTICLES);
00419     glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00420     
00421     glColor4f( particleColor[0], particleColor[1], particleColor[2],particleColor[3] );
00422     
00423     //color unspecified : shows snow
00424     //glColor4f( 1.0, 1.0, 1.0,1.0); shows snow
00425     //glColor4f( 0.0, 0.0, 0.0,0.0); doesnt show any snow
00426     
00427     //its the alpha vaolue in the color... if the alpha is null (total transparence), the textured color is also totally transparent => invisible
00428     
00429     //the snow only shows up near the start flag... why ?
00430     //because the y axis grows upwards. And in udateArea(), you had top = pos.y - YRANGE...and bottom = pos.y Also, in make*Particle(), you have part.y = -xrand(bottom,top)
00431     //  so it doesnt show too much on the strt line, for some reason...
00432     
00433     //a totally grey snowflake :-)
00434     //glColor4f(0.0,0.0,0.0,0.5);
00435     
00436     //glColor4f(0.0,1.0,0.0,0.5);
00437     
00438     //hardly visible with this color ! too... white :-)
00439     //glColor4f(1.0,1.0,1.0,0.5);
00440     
00441     
00442     
00443     for(i=0;i<MAXPART;i++) {
00444     
00445         /*
00446         if(i==0) {
00447             glColor4f(0.0,1.0,0.0,1.0);
00448         }*/
00449     
00450         size = PartArr[i].size;
00451         glBindTexture(GL_TEXTURE_2D, snow_tex[PartArr[i].index_tex]);
00452         draw_sprite( eyepoint, PartArr[i].pt, size, PartArr[i].tex_min, PartArr[i].tex_max );
00453         /*
00454         glPushMatrix();
00455         glTranslatef(PartArr[i].pt.x,PartArr[i].pt.y,PartArr[i].pt.z);
00456         glBegin( GL_QUADS );
00457         glTexCoord2f(PartArr[i].tex_min.x,PartArr[i].tex_min.y);
00458         glVertex3f(0,0,0);
00459         glTexCoord2f(PartArr[i].tex_min.x,PartArr[i].tex_max.y);
00460         glVertex3f(0,size,0);
00461         glTexCoord2f(PartArr[i].tex_max.x,PartArr[i].tex_max.y);
00462         glVertex3f(size,size,0);
00463         glTexCoord2f(PartArr[i].tex_max.x,PartArr[i].tex_min.y);
00464         glVertex3f(size,0,0);
00465         glEnd();
00466         glPopMatrix();
00467         */
00468         
00469         /*if(i==0) {
00470             glColor4f(0.0,0.0,0.0,0.5);
00471         }*/
00472     }
00473     
00474     for(i=0;i<MAXNEAR;i++) {
00475         size = NearArr[i].size;
00476         glBindTexture(GL_TEXTURE_2D, snow_tex[NearArr[i].index_tex]);
00477         /*
00478         glPushMatrix();
00479         glTranslatef(NearArr[i].pt.x,NearArr[i].pt.y,NearArr[i].pt.z);
00480         
00481         glBegin( GL_QUADS );
00482         glTexCoord2f(NearArr[i].tex_min.x,NearArr[i].tex_min.y);
00483         glVertex3f(0,0,0);
00484         glTexCoord2f(NearArr[i].tex_min.x,NearArr[i].tex_max.y);
00485         glVertex3f(0,size,0);
00486         glTexCoord2f(NearArr[i].tex_max.x,NearArr[i].tex_max.y);
00487         glVertex3f(size,size,0);
00488         glTexCoord2f(NearArr[i].tex_max.x,NearArr[i].tex_min.y);
00489         glVertex3f(size,0,0);
00490         glEnd();
00491         
00492         glPopMatrix();
00493         */
00494         draw_sprite( eyepoint, NearArr[i].pt, size, NearArr[i].tex_min, NearArr[i].tex_max );
00495     }
00496     
00497     
00498 
00499 }
00500 
00501 //copied from the code that draws herrings & other collectible items
00502 void draw_sprite( pp::Vec3d eyepoint, pp::Vec3d spriteLoc, double spriteSize, pp::Vec2d tex_min, pp::Vec2d tex_max ) {
00503     pp::Vec3d normal = eyepoint - spriteLoc;
00504     normal.normalize();
00505     if(normal.y == 1) return; // ||normal||==1 so if normal.y == 1 then normal == (0,1,0) and then we dont want to draw a "flat" sprite (contained in the (x,z) plane)
00506     glPushMatrix();
00507         glTranslatef( spriteLoc.x, spriteLoc.y, spriteLoc.z );
00508         glNormal3f(normal.x,normal.y,normal.z);//for lightning purposes... dont know if this is relevant here, so i put it just in case
00509         normal.y = 0; //the sprite has to be drawn using a normal vector contained in the (x,z) plane in order to appear as a billboard
00510         normal.normalize();
00511         glBegin( GL_QUADS );
00512            {
00513             double spriteRadius = spriteSize/2; //we assume the sprite to occupy the space of a cube in 3d; so the radius is equal to size/2 here
00514             double spriteHeight = spriteSize;//we assume the sprite to occupy the space of a cube in 3d; so the height is equal to the size here
00515               glTexCoord2f( tex_min.x, tex_min.y );
00516               glVertex3f( -spriteRadius*normal.z, 0.0, spriteRadius*normal.x );
00517               glTexCoord2f( tex_max.x, tex_min.y );
00518               glVertex3f( spriteRadius*normal.z, 0.0, -spriteRadius*normal.x );
00519               glTexCoord2f( tex_max.x, tex_max.y );
00520               glVertex3f( spriteRadius*normal.z, spriteHeight, -spriteRadius*normal.x );
00521               glTexCoord2f( tex_min.x, tex_max.y );
00522               glVertex3f( -spriteRadius*normal.z, spriteHeight, spriteRadius*normal.x );
00523            }
00524            glEnd();
00525     glPopMatrix();
00526 }
00527 
00528 
00529 //Use for debugging purposes
00530 // !!! Doesn't work with most of the snow textures. Works with snow.png as the texture for snow flakes (probably because it has no transparent pixels)
00531 void draw_cuboid_areas() {
00532     glLineWidth(3.0);
00533     
00534     glPushMatrix();
00535     
00536     glColor4f(1.0,0.0,0.0,1.0);
00537     
00538     glBegin(GL_LINES);
00539     glVertex3f(neararea.left,neararea.bottom,neararea.front);
00540     glVertex3f(neararea.left,neararea.top,neararea.front);
00541     glEnd();
00542     
00543     glBegin(GL_LINES);
00544     glVertex3f(neararea.left,neararea.top,neararea.front);
00545     glVertex3f(neararea.right,neararea.top,neararea.front);
00546     glEnd();
00547     
00548     glBegin(GL_LINES);
00549     glVertex3f(neararea.right,neararea.top,neararea.front);
00550     glVertex3f(neararea.right,neararea.bottom,neararea.front);
00551     glEnd();
00552     
00553     glBegin(GL_LINES);
00554     glVertex3f(neararea.right,neararea.bottom,neararea.front);
00555     glVertex3f(neararea.left,neararea.bottom,neararea.front);
00556     glEnd();
00557     
00558     glBegin(GL_LINES);
00559     glVertex3f(neararea.left,neararea.bottom,neararea.back);
00560     glVertex3f(neararea.left,neararea.top,neararea.back);
00561     glEnd();
00562     
00563     glBegin(GL_LINES);
00564     glVertex3f(neararea.left,neararea.top,neararea.back);
00565     glVertex3f(neararea.right,neararea.top,neararea.back);
00566     glEnd();
00567     
00568     glBegin(GL_LINES);
00569     glVertex3f(neararea.right,neararea.top,neararea.back);
00570     glVertex3f(neararea.right,neararea.bottom,neararea.back);
00571     glEnd();
00572     
00573     glBegin(GL_LINES);
00574     glVertex3f(neararea.right,neararea.bottom,neararea.back);
00575     glVertex3f(neararea.left,neararea.bottom,neararea.back);
00576     glEnd();
00577     
00578     glPopMatrix();
00579     
00580     glPushMatrix();
00581     
00582     glColor4f(0.0,1.0,0.0,1.0);
00583     
00584     glBegin(GL_LINES);
00585     glVertex3f(area.left,area.bottom,area.front);
00586     glVertex3f(area.left,area.top,area.front);
00587     glEnd();
00588     
00589     glBegin(GL_LINES);
00590     glVertex3f(area.left,area.top,area.front);
00591     glVertex3f(area.right,area.top,area.front);
00592     glEnd();
00593     
00594     glBegin(GL_LINES);
00595     glVertex3f(area.right,area.top,area.front);
00596     glVertex3f(area.right,area.bottom,area.front);
00597     glEnd();
00598     
00599     glBegin(GL_LINES);
00600     glVertex3f(area.right,area.bottom,area.front);
00601     glVertex3f(area.left,area.bottom,area.front);
00602     glEnd();
00603     
00604     glBegin(GL_LINES);
00605     glVertex3f(area.left,area.bottom,area.back);
00606     glVertex3f(area.left,area.top,area.back);
00607     glEnd();
00608     
00609     glBegin(GL_LINES);
00610     glVertex3f(area.left,area.top,area.back);
00611     glVertex3f(area.right,area.top,area.back);
00612     glEnd();
00613     
00614     glBegin(GL_LINES);
00615     glVertex3f(area.right,area.top,area.back);
00616     glVertex3f(area.right,area.bottom,area.back);
00617     glEnd();
00618     
00619     glBegin(GL_LINES);
00620     glVertex3f(area.right,area.bottom,area.back);
00621     glVertex3f(area.left,area.bottom,area.back);
00622     glEnd();
00623     
00624     glPopMatrix();
00625 }