1 /*
2 * This code is released under the GNU General Public License.  See COPYING for
3 * details.  Copyright 2003 John Spray: spray_john@users.sourceforge.net
4 */
5 
6 //Visual::SDL_GL_LoadTexture(SDL_Surface*, float*) is Copyright Sam Lantinga.
7 
8 #include <SDL_opengl.h>
9 #define GL_MIRRORED_REPEAT 0x8370
10 #include <SDL.h>
11 #include <string.h>
12 #include <string>
13 using namespace std;
14 #include <physfs.h>
15 #include <SDL_image.h>
16 #include <math.h>
17 #ifndef M_2PI
18 #define M_2PI 6.28318
19 #endif
20 
21 #include "Visual.h"
22 #include "LList.h"
23 #include "Particle.h"
24 #include "Texture.h"
25 #include "Camera.h"
26 #include "Config.h"
27 
28 
29 
30 extern Config GLOB_conf;
31 
~Visual()32 Visual::~Visual()
33 {
34 	LListItem<Texture>* texitem;
35 
36 	texitem=texturelist.head;
37 	while(texitem){
38 		glDeleteTextures(1,(GLuint*)&texitem->data.glid);
39 		texitem=texitem->next;
40 	}
41 
42 	cameralist.Flush();
43 
44 	glFinish();
45 
46 	if(scorefont){
47 		TTF_CloseFont(scorefont);
48 		if(verbose)
49 			printf("Visual::~Visual: Closing scorefont\n");
50 	}
51 
52 	if(menufont){
53 		TTF_CloseFont(menufont);
54 		if(verbose)
55 			printf("Visual::~Visual: Closing menufont\n");
56 	}
57 
58 }
59 
GetMainCam()60 Camera* Visual::GetMainCam()
61 {
62 	      return &cameralist.head->data;
63 }
64 
Visual(Game * newgame)65 Visual::Visual(Game* newgame)
66 {
67 	string fontpath,datadir,fontname;
68 
69 	fontname="helmetr.ttf";
70 	datadir=DATADIR;
71 	fontpath=datadir+fontname;
72 
73 	game=newgame;
74 
75 	texerrors=0;
76 
77 	verbose=newgame->verbose;
78 
79 	score=newgame->score;
80 
81 	scorefont=NULL;
82 	if(verbose)
83 		printf("Visual::Visual: opening scorefont\n");
84 	scorefont=TTF_OpenFont(fontpath.c_str(), 34);
85 	if(!scorefont){
86 			printf("Visual::Visual: failed to open scorefont with error %s\n",SDL_GetError());
87 			return;
88 	}
89 
90 	menufont=NULL;
91 	if(verbose)
92 		printf("Visual::Visual: opening menufont\n");
93 	menufont=TTF_OpenFont(fontpath.c_str(),40);
94 	if(!menufont){
95 		printf("Visual::Visual: failed to open menufont with error %s\n",SDL_GetError());
96 		return;
97 	}
98 
99 	strcpy(curtex,"NOTHING");
100 
101 	ResetCams();
102 }
103 
ResetCams()104 void Visual::ResetCams()
105 {
106 
107 	cameralist.Flush();
108 
109 	Camera* newcam=new Camera();
110 	if(!GLOB_conf.twoplayer){
111   newcam->scorefont=scorefont;
112 	newcam->visual=this;
113 	newcam->viewportwidth=game->screen->w;
114 	newcam->viewportheight=game->screen->h;
115 	newcam->viewporty=0;
116 	newcam->targetplayer=game->player;
117 	cameralist.Add(newcam);
118 	}
119 	else{
120   newcam->scorefont=scorefont;
121 	newcam->visual=this;
122 	newcam->viewportwidth=game->screen->w;
123 	newcam->viewportheight=game->screen->h/2;
124 	newcam->viewporty=0;
125 	newcam->targetplayer=game->player;
126 	cameralist.Add(newcam);
127 	newcam->viewporty=game->screen->h/2;
128 	newcam->targetplayer=game->player2;
129 	cameralist.Add(newcam);
130 	}
131 	delete newcam;
132 
133 }
134 
Draw()135 void Visual::Draw()
136 {
137 	if(score<game->score){
138 			score+=(int)game->dtf;
139 			if(score>game->score)
140 				score=game->score;
141 		}
142 
143 	glClear(GL_COLOR_BUFFER_BIT);
144 
145 	LListItem<Camera>* item=cameralist.head;
146 	while(item){
147 		item->data.Animate();
148 		item->data.Draw();
149 		item=item->next;
150 	}
151 
152 	SDL_GL_SwapBuffers();
153 }
154 
UpdateParticles()155 void Visual::UpdateParticles()
156 {
157 	LListItem<Particle>* item;
158 
159 	item=particlelist.head;
160 	while(item){
161 		item->data.Animate(game->dtf);
162 		if(item->data.life<=0){
163 			item=particlelist.Del(item);
164 			continue;
165 		}
166 		if(item->data.collide) if(item->data.Collide(game)){
167 			item=particlelist.Del(item);
168 			continue;
169 		}
170 		item=item->next;
171 	}
172 }
173 
174 
175 
LoadMesh(char * meshfile)176 int Visual::LoadMesh(char* meshfile)
177 {
178 	LListItem<Mesh>* item;
179 	Mesh* newmesh;
180 
181 	item=meshlist.head;
182 	while(item){
183 		if(!strcmp(meshfile,item->data.filename)){
184 			printf("Visual::LoadMesh: mesh %s already loaded!\n",meshfile);
185 			return 0;
186 		}
187 		item=item->next;
188 	}
189 
190 	newmesh=new Mesh();
191 	newmesh->visual=this;
192 	if(newmesh->Load(meshfile)){
193 					printf("Visual::LoadMesh: mesh %s could not be loaded\n",meshfile);
194 					return -1;
195 	}
196 
197 	meshlist.Add(newmesh);
198 	return 0;
199 	//deleting it segfaults!
200 	//delete newmesh;
201 }
202 
DrawMesh(char * meshfile)203 void Visual::DrawMesh(char* meshfile)
204 {
205 	LListItem<Mesh>* item;
206 
207 	item=meshlist.head;
208 	while(item){
209 		if(!strcmp(meshfile,item->data.filename)){
210 			item->data.Draw();
211 			return;
212 		}
213 		item=item->next;
214 	}
215 
216 	fprintf(stderr,"Visual::DrawMesh: %s is not loaded!\n",meshfile);
217 }
218 
LoadTexture(char * filename)219 int Visual::LoadTexture(char* filename)
220 {
221 
222 	LListItem<Texture>* item;
223 
224 	item=texturelist.head;
225 	while(item){
226 		if(!strcmp(filename,item->data.filename)){
227 			printf("Visual::LoadTexture: texture %s already loaded!\n",filename);
228 			return 0;
229 		}
230 		item=item->next;
231 	}
232 
233 	Texture newtex;
234 	SDL_Surface *TextureImage;
235 	SDL_RWops *RW;
236 	PHYSFS_file* filehandle;
237 	void* filedata;
238 	long filesize=0;
239 
240 
241 
242 	strcpy(newtex.filename,filename);
243 
244 	filehandle=PHYSFS_openRead(filename);
245 
246 	if(!filehandle) {printf("Visual::LoadTexture: PHYSFS_openRead failed on %s with error %s!\n",filename,PHYSFS_getLastError()); return 1;}
247 
248 	filesize=PHYSFS_fileLength(filehandle);
249 
250 	filedata=malloc(filesize);
251 	if(!filedata) {printf("Visual::LoadTexture: malloc failed!  Out of memory?\n"); return 1;}
252 	if(PHYSFS_read(filehandle,filedata,1,filesize)!=filesize){
253 		printf("Visual::LoadTexture: PHYSFS_read and PHYSFS_fileLength disagree!  Aborting.\n");
254 		free(filedata);
255 		if(!PHYSFS_close(filehandle))
256 			printf("ScoreBoard::Load: PHYSFS_close failed with error %s\n",PHYSFS_getLastError());
257 		return 1;
258 	}
259 
260 	RW=SDL_RWFromMem(filedata,filesize);
261 	if(!RW){
262 		printf("Visual::LoadTexture: SDL_RWFromMem failed with error %s\n",SDL_GetError());
263 		free(filedata);
264 		if(!PHYSFS_close(filehandle))
265 			printf("ScoreBoard::Load: PHYSFS_close failed with error %s\n",PHYSFS_getLastError());
266 		return 1;
267 	}
268 
269 	TextureImage=IMG_LoadPNG_RW(RW);
270 	if(!TextureImage){
271 		printf("Visual::LoadTexture: IMG_LoadPNG_RW failed with error %s\n",IMG_GetError());
272 		if(!PHYSFS_close(filehandle))
273 			printf("ScoreBoard::Load: PHYSFS_close failed with error %s\n",PHYSFS_getLastError());
274 		SDL_FreeRW(RW);
275 		free(filedata);
276 		return 1;
277 	}
278 
279 	free(filedata);
280 	if(!PHYSFS_close(filehandle))
281 		printf("ScoreBoard::Load: PHYSFS_close failed with error %s\n",PHYSFS_getLastError());
282 	SDL_FreeRW(RW);
283 
284 
285 
286 	int x;
287 	int y;
288 	unsigned char* pixels=(unsigned char*)TextureImage->pixels;
289 	unsigned char* pixels2=(unsigned char*)malloc(TextureImage->w*TextureImage->h*4);
290 	memcpy(pixels2,pixels,TextureImage->w*TextureImage->h*4);
291 	SDL_LockSurface(TextureImage);
292 	//all incoming surfaces get flipped in y:
293 	for(x=0;x<4*(TextureImage->w);x+=4){
294 	for(y=0;y<4*(TextureImage->h);y+=4){
295 		pixels[x+TextureImage->w*y+0]=pixels2[x+TextureImage->w*(TextureImage->h*4-y-4)+0];
296 		pixels[x+TextureImage->w*y+1]=pixels2[x+TextureImage->w*(TextureImage->h*4-y-4)+1];
297 		pixels[x+TextureImage->w*y+2]=pixels2[x+TextureImage->w*(TextureImage->h*4-y-4)+2];
298 		pixels[x+TextureImage->w*y+3]=pixels2[x+TextureImage->w*(TextureImage->h*4-y-4)+3];
299 
300 	}
301 	}
302 	int scalefactor=GLOB_conf.texscale;
303 	//and scaled down if scalefactor says so
304 	if(scalefactor!=1){
305 		memcpy(pixels2,pixels,TextureImage->w*TextureImage->h*4);
306 		for(x=0;x<4*(TextureImage->w/scalefactor);x+=4){
307 		for(y=0;y<4*(TextureImage->h/scalefactor);y+=4){
308 			pixels[x+(TextureImage->w/scalefactor)*y+0]=pixels2[(x*scalefactor)+TextureImage->w*(y*scalefactor)+0];
309 			pixels[x+(TextureImage->w/scalefactor)*y+1]=pixels2[(x*scalefactor)+TextureImage->w*(y*scalefactor)+1];
310 			pixels[x+(TextureImage->w/scalefactor)*y+2]=pixels2[(x*scalefactor)+TextureImage->w*(y*scalefactor)+2];
311 			pixels[x+(TextureImage->w/scalefactor)*y+3]=pixels2[(x*scalefactor)+TextureImage->w*(y*scalefactor)+3];
312 		}
313 		}
314   }
315 	free(pixels2);
316 	SDL_UnlockSurface(TextureImage);
317 
318 
319 	glGenTextures( 1, (GLuint*)&newtex.glid );
320 
321 
322 	glBindTexture(GL_TEXTURE_2D,newtex.glid);
323 
324 	glTexImage2D( GL_TEXTURE_2D, 0, 4, TextureImage->w/scalefactor,
325 		TextureImage->h/scalefactor, 0, GL_RGBA,
326 		GL_UNSIGNED_BYTE, TextureImage->pixels );
327 
328 
329 	gluBuild2DMipmaps( GL_TEXTURE_2D, 4,TextureImage->w/scalefactor,
330 			  TextureImage->h/scalefactor, GL_RGBA,
331 			  GL_UNSIGNED_BYTE, TextureImage->pixels );
332 
333 	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
334 	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
335 	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
336 	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
337 
338 	SDL_FreeSurface( TextureImage );
339 
340 	texturelist.Add(&newtex);
341 
342 	int errornumber;
343 	while((errornumber=glGetError())!=GL_NO_ERROR){
344 		printf("Visual::LoadTexture: OpenGL error: %s while loading %s\n",HandleGlError(errornumber),filename);
345 	}
346 
347 	if(verbose)
348 		printf("Visual::LoadTexture: Successfully loaded %s into glTexture %d\n",newtex.filename,newtex.glid);
349 
350 	return 0;
351 }
352 
NewParticle(Particle * newpart)353 void Visual::NewParticle(Particle* newpart)
354 {
355 	newpart->startlife=newpart->life;
356 	newpart->spinoffset=((float)rand()/(float)RAND_MAX)*180;
357 	particlelist.Add(newpart);
358 }
359 
InitGL()360 int Visual::InitGL()
361 {
362 	GLfloat backcolor[4]={0.0f,1.0f,0.0f,0.1f};
363 //	GLfloat fogcolor[4]={0.8f,0.8f,0.8f,0.1f};
364 
365 	if(GLOB_conf.verbose)
366 		printf("Visual::InitGL: SDL_Surface w=%d,h=%d,bpp=%d\n",game->screen->w,game->screen->h,game->screen->format->BitsPerPixel);
367 
368 	glShadeModel( GL_SMOOTH );
369 
370 	glEnable(GL_TEXTURE_2D);
371 
372 	glCullFace( GL_BACK );
373 	glFrontFace( GL_CCW );
374 	glEnable( GL_CULL_FACE );
375 	glEnable(GL_DEPTH_TEST);
376 	glDepthFunc(GL_LEQUAL);
377 
378 	glClearColor( backcolor[0],backcolor[1],backcolor[2],backcolor[3] );
379 
380   /*glFogi(GL_FOG_MODE, GL_LINEAR);
381 	glFogfv(GL_FOG_COLOR, fogcolor);
382 	glFogf(GL_FOG_DENSITY, 0.35f);
383 	glHint(GL_FOG_HINT, GL_NICEST);
384 	glFogf(GL_FOG_START, 50);
385 	glFogf(GL_FOG_END, 100);
386 	glEnable(GL_FOG);*/
387 
388 	glEnable(GL_BLEND);
389 	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
390 
391 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
392 
393 	return 0;
394 }
395 
UseTexture(char * filename)396 int Visual::UseTexture(char* filename)
397 {
398 	LListItem<Texture>* item=NULL;
399 
400 	if(!strcmp(filename,curtex))
401 		return 0;
402 
403 	item=texturelist.head;
404 	while(item){
405 		if(!strcmp(filename,item->data.filename)){
406 			glBindTexture(GL_TEXTURE_2D,item->data.glid);
407 			strcpy(curtex,filename);
408 			return 0;
409 		}
410 		item=item->next;
411 	}
412 
413 #ifndef RELEASE
414 
415 	if(texerrors>50)
416 		return -1;
417 	texerrors++;
418 
419 	printf("Visual::UseTexture: %s not loaded!  Loading.\n",filename);
420 	if(LoadTexture(filename))
421 		return -1;
422 	return UseTexture(filename);
423 
424 #else
425 
426 	printf("ERROR: Visual::UseTexture: %s not loaded!\n",filename);
427   return -1;
428 
429 #endif //RELEASE
430 }
431 
UnLoadTexture(char * filename)432 int Visual::UnLoadTexture(char* filename)
433 {
434 	LListItem<Texture>* item;
435 
436 	item=texturelist.head;
437 	while(item){
438 		if(!strcmp(filename,item->data.filename)){
439 			glDeleteTextures(1,(GLuint*)&item->data.glid);
440 			if(!strcmp(curtex,filename))
441 				strcpy(curtex,"NOTHING");
442 			item=texturelist.Del(item);
443 			if(verbose) printf("Unloaded texture %s successfully\n",filename);
444 			return 0;
445 		}
446 		item=item->next;
447 	}
448 
449 	printf("Visual::UnLoadTexture: Can't!  %s not loaded!\n",filename);
450 	  return -1;
451 
452 }
453 
UnLoadMesh(char * filename)454 int Visual::UnLoadMesh(char* filename)
455 {
456 	LListItem<Mesh>* item;
457 
458 	item=meshlist.head;
459 	while(item){
460 		if(!strcmp(filename,item->data.filename)){
461 			item=meshlist.Del(item);
462 			if(verbose) printf("Unloaded mesh %s successfully\n",filename);
463 			return 0;
464 		}
465 		item=item->next;
466 	}
467 
468 	printf("Visual::UnLoadMesh: Can't! %s not loaded!\n",filename);
469 	  return -1;
470 
471 }
472 
HandleGlError(int errornumber)473 char* Visual::HandleGlError(int errornumber)
474 {
475 	//FIXME:  waste of memory.  Do this properly.
476 	static char errorstring[128];
477 
478 	switch(errornumber){
479 			case GL_INVALID_VALUE:
480 				strcpy(errorstring,"GL_INVALID_VALUE");
481 				break;
482 			case GL_INVALID_ENUM:
483 				strcpy(errorstring,"GL_INVALID_ENUM");
484 				break;
485 			case GL_INVALID_OPERATION:
486 				strcpy(errorstring,"GL_INVALID_OPERATION");
487 				break;
488 			case GL_STACK_OVERFLOW:
489 				strcpy(errorstring,"GL_STACK_OVERFLOW");
490 				break;
491 			case GL_STACK_UNDERFLOW:
492 				strcpy(errorstring,"GL_STACK_UNDERFLOW");
493 				break;
494 			case GL_OUT_OF_MEMORY:
495 				strcpy(errorstring,"GL_OUT_OF_MEMORY");
496 				break;
497 			case GL_TABLE_TOO_LARGE:
498 				strcpy(errorstring,"GL_TABLE_TOO_LARGE");
499 				break;
500 			default:
501 				strcpy(errorstring,"Unknown error code");
502 				break;
503 		}
504 	return errorstring;
505 }
506 
MakeHash(char * source)507 unsigned int Visual::MakeHash(char* source){
508 	unsigned int hash=0;
509 	int i=0;
510 	while(source[i]!=0){
511 		hash^=source[i++];
512 	}
513 	return hash;
514 }
515 
516 
power_of_two(int target)517 int power_of_two(int target)
518 {
519 	int x=1;
520 	while(x<target)
521 		x*=2;
522 	return x;
523 }
524 
525 //This function from SDL_ttf example programs, (c) Sam Lantinga
SDL_GL_LoadTexture(SDL_Surface * surface,float * texcoord)526 int Visual::SDL_GL_LoadTexture(SDL_Surface *surface, float *texcoord)
527 {
528 	GLuint texture;
529 	int w, h;
530 	SDL_Surface *image;
531 	SDL_Rect area;
532 	Uint32 saved_flags;
533 	Uint8  saved_alpha;
534 
535 	/* Use the surface width and height expanded to powers of 2 */
536 	w = power_of_two(surface->w);
537 	h = power_of_two(surface->h);
538 	texcoord[0] = 0.0f;			/* Min X */
539 	texcoord[1] = 0.0f;			/* Min Y */
540 	texcoord[2] = (GLfloat)surface->w / w;	/* Max X */
541 	texcoord[3] = (GLfloat)surface->h / h;	/* Max Y */
542 
543 	image = SDL_CreateRGBSurface(
544 			SDL_SWSURFACE,
545 			w, h,
546 			32,
547 #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
548 			0x000000FF,
549 			0x0000FF00,
550 			0x00FF0000,
551 			0xFF000000
552 #else
553 			0xFF000000,
554 			0x00FF0000,
555 			0x0000FF00,
556 			0x000000FF
557 #endif
558 		       );
559 	if ( image == NULL ) {
560 		return 0;
561 	}
562 
563 	/* Save the alpha blending attributes */
564 	saved_flags = surface->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
565 	saved_alpha = surface->format->alpha;
566 	if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
567 			SDL_SetAlpha(surface, 0, 0);
568 	}
569 
570 	/* Copy the surface into the GL texture image */
571 	area.x = 0;
572 	area.y = 0;
573 	area.w = surface->w;
574 	area.h = surface->h;
575 	SDL_BlitSurface(surface, &area, image, &area);
576 
577 	/* Restore the alpha blending attributes */
578 	if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
579 		SDL_SetAlpha(surface, saved_flags, saved_alpha);
580 	}
581 
582 	/* Create an OpenGL texture for the image */
583 	glGenTextures(1, &texture);
584 	glBindTexture(GL_TEXTURE_2D, texture);
585 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
586 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
587 	glTexImage2D(GL_TEXTURE_2D,
588 		     0,
589 		     GL_RGBA,
590 		     w, h,
591 		     0,
592 		     GL_RGBA,
593 		     GL_UNSIGNED_BYTE,
594 		     image->pixels);
595 	SDL_FreeSurface(image); /* No longer needed */
596 
597 	strcpy(curtex,"NOTHING");
598 
599 	return texture;
600 }
601 
ShowLoading(float howfar)602 void Visual::ShowLoading(float howfar)
603 {
604 	glDisable(GL_DEPTH_TEST);
605 	glDisable(GL_LIGHTING);
606 	glMatrixMode(GL_PROJECTION);
607 	glPushMatrix();
608 	glLoadIdentity();
609 	gluOrtho2D(0,game->screen->w,0,game->screen->h);
610 	glMatrixMode(GL_MODELVIEW);
611 	glPushMatrix();
612 	glLoadIdentity();
613 
614 	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
615 
616 	LoadTexture("loading.png");
617 	if(UseTexture("loading.png")==-1){
618 		printf("Visual::ShowLoading: UseTexture returned -1\n");
619 		glPopMatrix();
620 		glMatrixMode(GL_PROJECTION);
621 		glPopMatrix();
622 		return;
623 	}
624 
625 	glColor4f(1.0f,1.0f,1.0f,1.0f);
626 	glBegin(GL_QUADS);
627 		glTexCoord2f(0.0f,0.0f);
628 		glVertex2f(0.0f,0.0f);
629 		glTexCoord2f(1.0f,0.0f);
630 		glVertex2f(game->screen->w,0.0f);
631 		glTexCoord2f(1.0f,1.0f);
632 		glVertex2f(game->screen->w,game->screen->h);
633 		glTexCoord2f(0.0f,1.0f);
634 		glVertex2f(0,game->screen->h);
635 	glEnd();
636 
637 	if(howfar!=-1.0f){
638 		glDisable(GL_TEXTURE_2D);
639 		glBegin(GL_QUADS);
640 			glColor4f(1.0f,0.0f,0.0f,0.7f);
641 			glVertex2f(game->screen->w/4,game->screen->h*0.2f);
642 			glVertex2f(game->screen->w/4,game->screen->h*0.17f);
643 			glColor4f(0.0f,howfar,0.0f,0.7f);
644 			glVertex2f(game->screen->w/4+(game->screen->w/2)*howfar,game->screen->h*0.17f);
645 			glVertex2f(game->screen->w/4+(game->screen->w/2)*howfar,game->screen->h*0.2f);
646 		glEnd();
647 		glEnable(GL_TEXTURE_2D);
648 	}
649 
650 	glPopMatrix();
651 
652 	SDL_GL_SwapBuffers();
653 
654 	UnLoadTexture("loading.png");
655 
656 	glMatrixMode(GL_PROJECTION);
657 	glPopMatrix();
658 	glMatrixMode(GL_MODELVIEW);
659 	glEnable(GL_DEPTH_TEST);
660 	glEnable(GL_LIGHTING);
661 }
662 
663