]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_textures.c
fix a char type problem
[xonotic/darkplaces.git] / gl_textures.c
1 #include "quakedef.h"
2
3 cvar_t          gl_max_size = {"gl_max_size", "1024"};
4 cvar_t          gl_picmip = {"gl_picmip", "0"};
5 cvar_t          gl_lerpimages = {"gl_lerpimages", "1"};
6 cvar_t          r_upload = {"r_upload", "1"};
7
8 int             gl_filter_min = GL_LINEAR_MIPMAP_LINEAR; //NEAREST;
9 int             gl_filter_max = GL_LINEAR;
10
11
12 int             texels;
13
14 // 4096x4096
15 #define MAXMIPS 12
16
17 typedef struct
18 {
19         int             texnum;
20         int             totaltexels;
21         byte    *texels[MAXMIPS];
22         unsigned short texelsize[MAXMIPS][2];
23         char    identifier[64];
24         short   width, height;
25 // LordHavoc: CRC to identify cache mismatchs
26         unsigned short crc;
27         char    mipmap;
28         char    alpha;
29         char    bytesperpixel;
30         char    lerped; // whether this texture was uploaded with or without interpolation
31 } gltexture_t;
32
33 #define MAX_GLTEXTURES  4096
34 gltexture_t     gltextures[MAX_GLTEXTURES];
35 int                     numgltextures;
36
37 typedef struct
38 {
39         char *name;
40         int     minimize, maximize;
41 } glmode_t;
42
43 glmode_t modes[] = {
44         {"GL_NEAREST", GL_NEAREST, GL_NEAREST},
45         {"GL_LINEAR", GL_LINEAR, GL_LINEAR},
46         {"GL_NEAREST_MIPMAP_NEAREST", GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST},
47         {"GL_LINEAR_MIPMAP_NEAREST", GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR},
48         {"GL_NEAREST_MIPMAP_LINEAR", GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST},
49         {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR}
50 };
51
52 /*
53 ===============
54 Draw_TextureMode_f
55 ===============
56 */
57 void Draw_TextureMode_f (void)
58 {
59         int             i;
60         gltexture_t     *glt;
61
62         if (Cmd_Argc() == 1)
63         {
64                 for (i=0 ; i< 6 ; i++)
65                         if (gl_filter_min == modes[i].minimize)
66                         {
67                                 Con_Printf ("%s\n", modes[i].name);
68                                 return;
69                         }
70                 Con_Printf ("current filter is unknown???\n");
71                 return;
72         }
73
74         for (i=0 ; i< 6 ; i++)
75         {
76                 if (!Q_strcasecmp (modes[i].name, Cmd_Argv(1) ) )
77                         break;
78         }
79         if (i == 6)
80         {
81                 Con_Printf ("bad filter name\n");
82                 return;
83         }
84
85         gl_filter_min = modes[i].minimize;
86         gl_filter_max = modes[i].maximize;
87
88         if (!r_upload.value)
89                 return;
90         // change all the existing mipmap texture objects
91         for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
92         {
93                 if (glt->mipmap)
94                 {
95                         glBindTexture(GL_TEXTURE_2D, glt->texnum);
96                         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
97                         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
98                 }
99         }
100 }
101
102 void GL_TextureStats_Print(char *name, int total, int crc, int mip, int alpha)
103 {
104         char n[64];
105         int c = 0;
106         if (!name[0])
107                 name = "<unnamed>";
108         while (name[c] && c < 28)
109                 n[c++] = name[c];
110         while (c < 28)
111                 n[c++] = ' ';
112         n[c] = 0;
113         Con_Printf("%s %5i %04X %s %s\n", n, total, crc, mip ? "yes" : "no ", alpha ? "yes  " : "no   ");
114 }
115
116 void GL_TextureStats_f(void)
117 {
118         int i, t = 0;
119         gltexture_t *glt;
120         Con_Printf("name                        kbytes crc  mip alpha\n");
121         for (i = 0, glt = gltextures;i < numgltextures;i++, glt++)
122         {
123                 GL_TextureStats_Print(glt->identifier, ((glt->totaltexels * 4) + 512) >> 10, glt->crc, glt->mipmap, glt->alpha);
124                 t += glt->totaltexels;
125         }
126         Con_Printf("%i textures, totalling %.3f mbytes\n", numgltextures, t / 1024.0 / 1024.0);
127 }
128
129 extern int buildnumber;
130
131 char engineversion[40];
132
133 void GL_UploadTexture (gltexture_t *glt);
134 void gl_textures_start()
135 {
136         int i;
137         gltexture_t *glt;
138         for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
139                 GL_UploadTexture(glt);
140 }
141
142 void gl_textures_shutdown()
143 {
144 }
145
146 void GL_Textures_Init (void)
147 {
148         Cmd_AddCommand("r_texturestats", GL_TextureStats_f);
149         Cvar_RegisterVariable (&gl_max_size);
150         Cvar_RegisterVariable (&gl_picmip);
151         Cvar_RegisterVariable (&gl_lerpimages);
152         Cvar_RegisterVariable (&r_upload);
153 #ifdef NORENDER
154         r_upload.value = 0;
155 #endif
156
157         // 3dfx can only handle 256 wide textures
158         if (!Q_strncasecmp ((char *)gl_renderer, "3dfx",4) || strstr((char *)gl_renderer, "Glide"))
159                 Cvar_Set ("gl_max_size", "256");
160
161         Cmd_AddCommand ("gl_texturemode", &Draw_TextureMode_f);
162
163         R_RegisterModule("GL_Textures", gl_textures_start, gl_textures_shutdown);
164 }
165
166 /*
167 ================
168 GL_FindTexture
169 ================
170 */
171 int GL_FindTexture (char *identifier)
172 {
173         int             i;
174         gltexture_t     *glt;
175
176         for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
177         {
178                 if (!strcmp (identifier, glt->identifier))
179                         return gltextures[i].texnum;
180         }
181
182         return -1;
183 }
184
185 void GL_ResampleTextureLerpLine (byte *in, byte *out, int inwidth, int outwidth)
186 {
187         int             j, xi, oldx = 0, f, fstep, l1, l2, endx;
188         fstep = (int) (inwidth*65536.0f/outwidth);
189         endx = (inwidth-1);
190         for (j = 0,f = 0;j < outwidth;j++, f += fstep)
191         {
192                 xi = (int) f >> 16;
193                 if (xi != oldx)
194                 {
195                         in += (xi - oldx) * 4;
196                         oldx = xi;
197                 }
198                 if (xi < endx)
199                 {
200                         l2 = f & 0xFFFF;
201                         l1 = 0x10000 - l2;
202                         *out++ = (byte) ((in[0] * l1 + in[4] * l2) >> 16);
203                         *out++ = (byte) ((in[1] * l1 + in[5] * l2) >> 16);
204                         *out++ = (byte) ((in[2] * l1 + in[6] * l2) >> 16);
205                         *out++ = (byte) ((in[3] * l1 + in[7] * l2) >> 16);
206                 }
207                 else // last pixel of the line has no pixel to lerp to
208                 {
209                         *out++ = in[0];
210                         *out++ = in[1];
211                         *out++ = in[2];
212                         *out++ = in[3];
213                 }
214         }
215 }
216
217 /*
218 ================
219 GL_ResampleTexture
220 ================
221 */
222 void GL_ResampleTexture (void *indata, int inwidth, int inheight, void *outdata,  int outwidth, int outheight)
223 {
224         if (gl_lerpimages.value)
225         {
226                 int             i, j, yi, oldy, f, fstep, l1, l2, endy = (inheight-1);
227                 byte    *inrow, *out, *row1, *row2;
228                 out = outdata;
229                 fstep = (int) (inheight*65536.0f/outheight);
230
231                 row1 = malloc(outwidth*4);
232                 row2 = malloc(outwidth*4);
233                 inrow = indata;
234                 oldy = 0;
235                 GL_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
236                 GL_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth);
237                 for (i = 0, f = 0;i < outheight;i++,f += fstep)
238                 {
239                         yi = f >> 16;
240                         if (yi != oldy)
241                         {
242                                 inrow = (byte *)indata + inwidth*4*yi;
243                                 if (yi == oldy+1)
244                                         memcpy(row1, row2, outwidth*4);
245                                 else
246                                         GL_ResampleTextureLerpLine (inrow, row1, inwidth, outwidth);
247                                 if (yi < endy)
248                                         GL_ResampleTextureLerpLine (inrow + inwidth*4, row2, inwidth, outwidth);
249                                 else
250                                         memcpy(row2, row1, outwidth*4);
251                                 oldy = yi;
252                         }
253                         if (yi < endy)
254                         {
255                                 l2 = f & 0xFFFF;
256                                 l1 = 0x10000 - l2;
257                                 for (j = 0;j < outwidth;j++)
258                                 {
259                                         *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16);
260                                         *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16);
261                                         *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16);
262                                         *out++ = (byte) ((*row1++ * l1 + *row2++ * l2) >> 16);
263                                 }
264                                 row1 -= outwidth*4;
265                                 row2 -= outwidth*4;
266                         }
267                         else // last line has no pixels to lerp to
268                         {
269                                 for (j = 0;j < outwidth;j++)
270                                 {
271                                         *out++ = *row1++;
272                                         *out++ = *row1++;
273                                         *out++ = *row1++;
274                                         *out++ = *row1++;
275                                 }
276                                 row1 -= outwidth*4;
277                         }
278                 }
279                 free(row1);
280                 free(row2);
281         }
282         else
283         {
284                 int             i, j;
285                 unsigned        frac, fracstep;
286                 byte    *inrow, *out, *inpix;
287                 out = outdata;
288
289                 fracstep = inwidth*0x10000/outwidth;
290                 for (i=0 ; i<outheight ; i++)
291                 {
292                         inrow = (byte *)indata + inwidth*(i*inheight/outheight)*4;
293                         frac = fracstep >> 1;
294                         for (j=0 ; j<outwidth ; j+=4)
295                         {
296                                 inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
297                                 inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
298                                 inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
299                                 inpix = inrow + ((frac >> 14) & ~3);*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ = qgamma[*inpix++];*out++ =       *inpix++ ;frac += fracstep;
300                         }
301                 }
302         }
303 }
304
305 void GL_FreeTexels(gltexture_t *glt)
306 {
307         if (glt->texels[0])
308                 free(glt->texels[0]);
309         glt->texels[0] = 0;
310 }
311
312 void GL_AllocTexels(gltexture_t *glt, int width, int height, int mipmapped)
313 {
314         int i, w, h, size, done;
315         if (glt->texels[0])
316                 GL_FreeTexels(glt);
317         glt->texelsize[0][0] = width;
318         glt->texelsize[0][1] = height;
319         if (mipmapped)
320         {
321                 size = 0;
322                 w = width;h = height;
323                 i = 0;
324                 done = false;
325                 for (i = 0;i < MAXMIPS;i++)
326                 {
327                         glt->texelsize[i][0] = w;
328                         glt->texelsize[i][1] = h;
329                         glt->texels[i] = (void *)size;
330                         size += w*h*4;
331                         if (w > 1)
332                         {
333                                 w >>= 1;
334                                 if (h > 1)
335                                         h >>= 1;
336                         }
337                         else if (h > 1)
338                                 h >>= 1;
339                         else
340                         {
341                                 i++;
342                                 break;
343                         }
344                 }
345                 glt->totaltexels = size;
346                 while (i < MAXMIPS)
347                         glt->texels[i++] = NULL;
348                 glt->texels[0] = malloc(size);
349                 for (i = 1;i < MAXMIPS && glt->texels[i];i++)
350                         glt->texels[i] += (int) glt->texels[0];
351         }
352         else
353         {
354                 size = width*height*4;
355                 glt->totaltexels = size;
356                 glt->texels[0] = malloc(size);
357                 for (i = 1;i < MAXMIPS;i++)
358                         glt->texels[i] = NULL;
359         }
360         if (!glt->texels[0])
361                 Sys_Error("GL_AllocTexels: out of memory\n");
362 }
363
364 // in can be the same as out
365 void GL_MipReduce(byte *in, byte *out, int width, int height, int destwidth, int destheight)
366 {
367         int x, y, width2, height2, nextrow;
368         if (width > destwidth)
369         {
370                 if (height > destheight)
371                 {
372                         // reduce both
373                         width2 = width >> 1;
374                         height2 = height >> 1;
375                         nextrow = width << 2;
376                         for (y = 0;y < height2;y++)
377                         {
378                                 for (x = 0;x < width2;x++)
379                                 {
380                                         out[0] = (byte) ((in[0] + in[4] + in[nextrow  ] + in[nextrow+4]) >> 2);
381                                         out[1] = (byte) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2);
382                                         out[2] = (byte) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2);
383                                         out[3] = (byte) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2);
384                                         out += 4;
385                                         in += 8;
386                                 }
387                                 in += nextrow; // skip a line
388                         }
389                 }
390                 else
391                 {
392                         // reduce width
393                         width2 = width >> 1;
394                         for (y = 0;y < height;y++)
395                         {
396                                 for (x = 0;x < width2;x++)
397                                 {
398                                         out[0] = (byte) ((in[0] + in[4]) >> 1);
399                                         out[1] = (byte) ((in[1] + in[5]) >> 1);
400                                         out[2] = (byte) ((in[2] + in[6]) >> 1);
401                                         out[3] = (byte) ((in[3] + in[7]) >> 1);
402                                         out += 4;
403                                         in += 8;
404                                 }
405                         }
406                 }
407         }
408         else
409         {
410                 if (height > destheight)
411                 {
412                         // reduce height
413                         height2 = height >> 1;
414                         nextrow = width << 2;
415                         for (y = 0;y < height2;y++)
416                         {
417                                 for (x = 0;x < width;x++)
418                                 {
419                                         out[0] = (byte) ((in[0] + in[nextrow  ]) >> 1);
420                                         out[1] = (byte) ((in[1] + in[nextrow+1]) >> 1);
421                                         out[2] = (byte) ((in[2] + in[nextrow+2]) >> 1);
422                                         out[3] = (byte) ((in[3] + in[nextrow+3]) >> 1);
423                                         out += 4;
424                                         in += 4;
425                                 }
426                                 in += nextrow; // skip a line
427                         }
428                 }
429                 else
430                         Sys_Error("GL_MipReduce: desired size already achieved\n");
431         }
432 }
433
434 void GL_UploadTexture (gltexture_t *glt)
435 {
436         int mip, width, height;
437         if (!r_upload.value)
438                 return;
439         glBindTexture(GL_TEXTURE_2D, glt->texnum);
440         width = glt->width;
441         height = glt->height;
442         for (mip = 0;mip < MAXMIPS && glt->texels[mip];mip++)
443                 glTexImage2D(GL_TEXTURE_2D, mip, glt->alpha ? 4 : 3, glt->texelsize[mip][0], glt->texelsize[mip][1], 0, GL_RGBA, GL_UNSIGNED_BYTE, glt->texels[mip]);
444         if (glt->mipmap)
445         {
446                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
447                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
448         }
449         else
450         {
451                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
452                 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
453         }
454         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
455 }
456
457 /*
458 ================
459 GL_LoadTexture
460 ================
461 */
462 int GL_LoadTexture (char *identifier, int width, int height, byte *data, qboolean mipmap, qboolean alpha, int bytesperpixel)
463 {
464         unsigned short  crc;
465         int                             i, width2, height2, width3, height3, w, h, mip;
466         gltexture_t             *glt;
467
468         if (isDedicated)
469                 return 1;
470
471         // LordHavoc: do a CRC to confirm the data really is the same as previous occurances.
472         crc = CRC_Block(data, width*height*bytesperpixel);
473         // see if the texture is already present
474         if (identifier[0])
475         {
476                 for (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)
477                 {
478                         if (!strcmp (identifier, glt->identifier))
479                         {
480                                 // LordHavoc: everyone hates cache mismatchs, so I fixed it
481                                 if (crc != glt->crc || width != glt->width || height != glt->height)
482                                 {
483                                         Con_DPrintf("GL_LoadTexture: cache mismatch, replacing old texture\n");
484                                         goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
485                                         //Sys_Error ("GL_LoadTexture: cache mismatch");
486                                 }
487                                 if ((gl_lerpimages.value != 0) != glt->lerped)
488                                         goto GL_LoadTexture_setup; // drop out with glt pointing to the texture to replace
489                                 return glt->texnum;
490                         }
491                 }
492         }
493         // LordHavoc: although this could be an else condition as it was in the original id code,
494         //            it is more clear this way
495         // LordHavoc: check if there are still slots available
496         if (numgltextures >= MAX_GLTEXTURES)
497                 Sys_Error ("GL_LoadTexture: ran out of texture slots (%d)\n", MAX_GLTEXTURES);
498         glt = &gltextures[numgltextures++];
499
500         strcpy (glt->identifier, identifier);
501         glt->texnum = texture_extension_number;
502         texture_extension_number++;
503 // LordHavoc: label to drop out of the loop into the setup code
504 GL_LoadTexture_setup:
505         // calculate power of 2 size
506         width2 = 1;while (width2 < width) width2 <<= 1;
507         height2 = 1;while (height2 < height) height2 <<= 1;
508         // calculate final size (mipmapped downward to this)
509         width3 = width2 >> (int) gl_picmip.value;
510         height3 = height2 >> (int) gl_picmip.value;
511         while (width3 > (int) gl_max_size.value) width3 >>= 1;
512         while (height3 > (int) gl_max_size.value) height3 >>= 1;
513         if (width3 < 1) width3 = 1;
514         if (height3 < 1) height3 = 1;
515
516         // final storage
517         GL_AllocTexels(glt, width3, height3, mipmap);
518         glt->crc = crc; // LordHavoc: used to verify textures are identical
519         glt->width = width;
520         glt->height = height;
521         glt->mipmap = mipmap;
522         glt->bytesperpixel = bytesperpixel;
523         glt->lerped = gl_lerpimages.value != 0;
524         glt->alpha = false; // updated later
525         if (width == width3 && height == height3) // perfect match
526         {
527                 if (bytesperpixel == 1) // 8bit
528                         Image_Copy8bitRGBA(data, glt->texels[0], width*height, d_8to24table);
529                 else
530                         Image_CopyRGBAGamma(data, glt->texels[0], width*height);
531         }
532         else if (width == width2 && height == height2) // perfect match for top level, but needs to be reduced
533         {
534                 byte *temptexels2;
535                 temptexels2 = malloc(width2*height2*4); // scaleup buffer
536                 if (bytesperpixel == 1) // 8bit
537                         Image_Copy8bitRGBA(data, temptexels2, width*height, d_8to24table);
538                 else
539                         Image_CopyRGBAGamma(data, temptexels2, width*height);
540                 while (width2 > width3 || height2 > height3)
541                 {
542                         w = width2;h = height2;
543                         if (width2 > width3) width2 >>= 1;
544                         if (height2 > height3) height2 >>= 1;
545                         if (width2 <= width3 && height2 <= height3) // size achieved
546                                 GL_MipReduce(temptexels2, glt->texels[0], w, h, width3, height3);
547                         else
548                                 GL_MipReduce(temptexels2, temptexels2, w, h, width3, height3);
549                 }
550                 free(temptexels2);
551         }
552         else // scaling...
553         {
554                 byte *temptexels;
555                 // pre-scaleup buffer
556                 temptexels = malloc(width*height*4);
557                 if (bytesperpixel == 1) // 8bit
558                         Image_Copy8bitRGBA(data, temptexels, width*height, d_8to24table);
559                 else
560                         Image_CopyRGBAGamma(data, temptexels, width*height);
561                 if (width2 != width3 || height2 != height3) // reduced by gl_pic_mip or gl_max_size
562                 {
563                         byte *temptexels2;
564                         temptexels2 = malloc(width2*height2*4); // scaleup buffer
565                         GL_ResampleTexture(temptexels, width, height, temptexels2, width2, height2);
566                         while (width2 > width3 || height2 > height3)
567                         {
568                                 w = width2;h = height2;
569                                 if (width2 > width3) width2 >>= 1;
570                                 if (height2 > height3) height2 >>= 1;
571                                 if (width2 <= width3 && height2 <= height3) // size achieved
572                                         GL_MipReduce(temptexels2, glt->texels[0], w, h, width3, height3);
573                                 else
574                                         GL_MipReduce(temptexels2, temptexels2, w, h, width3, height3);
575                         }
576                         free(temptexels2);
577                 }
578                 else // copy directly
579                         GL_ResampleTexture(temptexels, width, height, glt->texels[0], width2, height2);
580                 free(temptexels);
581         }
582         if (alpha)
583         {
584                 byte    *in = glt->texels[0] + 3;
585                 for (i = 0;i < width*height;i++, in += 4)
586                         if (*in < 255)
587                         {
588                                 glt->alpha = true;
589                                 break;
590                         }
591         }
592         // this loop is skipped if there are no mipmaps to generate
593         for (mip = 1;mip < MAXMIPS && glt->texels[mip];mip++)
594                 GL_MipReduce(glt->texels[mip-1], glt->texels[mip], glt->texelsize[mip-1][0], glt->texelsize[mip-1][1], 1, 1);
595         GL_UploadTexture(glt);
596         GL_FreeTexels(glt);
597
598 //      if (bytesperpixel == 1) // 8bit
599 //              GL_Upload8 (data, width, height, mipmap, alpha);
600 //      else // 32bit
601 //              GL_Upload32 (data, width, height, mipmap, true);
602
603         return glt->texnum;
604 }
605
606 /*
607 ================
608 GL_LoadPicTexture
609 ================
610 */
611 int GL_LoadPicTexture (qpic_t *pic)
612 {
613         return GL_LoadTexture ("", pic->width, pic->height, pic->data, false, true, 1);
614 }
615
616 int GL_GetTextureSlots (int count)
617 {
618         gltexture_t             *glt, *first;
619
620         first = glt = &gltextures[numgltextures];
621         while (count--)
622         {
623                 glt->identifier[0] = 0;
624                 glt->texnum = texture_extension_number++;
625                 glt->crc = 0;
626                 glt->width = 0;
627                 glt->height = 0;
628                 glt->bytesperpixel = 0;
629                 glt++;
630                 numgltextures++;
631         }
632         return first->texnum;
633 }