Round 1: $HOME/.hhexen/ for configs and savegames.
[theoddone33/hhexen.git] / opengl / ogl_tex.c
1
2 //**************************************************************************
3 //**
4 //** OGL_TEX.C
5 //**
6 //**************************************************************************
7
8 // HEADER FILES ------------------------------------------------------------
9
10 #ifdef __WIN32
11 #define WIN32_LEAN_AND_MEAN
12 #include <windows.h>
13 #endif
14
15 #include <stdlib.h>
16 #include <GL/gl.h>
17 #include <GL/glu.h>
18 #include "h2def.h"
19 #include "r_local.h"
20 #include "ogl_def.h"
21
22 // MACROS ------------------------------------------------------------------
23
24 // TYPES -------------------------------------------------------------------
25
26 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
27
28 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
29
30 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
31
32 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
33
34                                 
35 extern int numtextures;
36 extern texture_t** textures;
37
38 int mipmapping = 0;
39 int linearRaw = 0;
40 extern int maxTexSize;          // Maximum supported texture size.
41 extern int ratioLimit;
42 extern int test3dfx;
43
44 // PUBLIC DATA DEFINITIONS -------------------------------------------------
45
46 int pallump;
47
48 // Properties of the current texture.
49 float   texw=1, texh=1;
50 int             texmask=0;      
51 GLuint  curtex = 0;
52 byte    topLineRGB[3];
53
54 texsize_t *lumptexsizes;        // Sizes for all the lumps. 
55 unsigned short *spriteheights;
56
57 // PRIVATE DATA DEFINITIONS ------------------------------------------------
58
59 // Texture names for all lumps. Although the list will contain names for 
60 // ALL lumps, only the graphics entries that aren't flats, wall textures or 
61 // sprites are used.
62 static GLuint *lumptexnames, *lumptexnames2;    // Support for two parts.
63 static int *rawlumps, numrawlumps;      // Raw screen lumps (just lump numbers).
64         
65 static GLuint *flattexnames, *texnames, *spritenames;
66 static char *texmasked;         // 1 if the texture is masked.
67 //static int total_texmem_used = 0;
68
69 static GLuint dltexname;        // Name of the dynamic light texture.
70
71 static int glmode[6] = // Indexed by 'mipmapping'.
72
73         GL_NEAREST,
74         GL_LINEAR,
75         GL_NEAREST_MIPMAP_NEAREST,
76         GL_LINEAR_MIPMAP_NEAREST,
77         GL_NEAREST_MIPMAP_LINEAR,
78         GL_LINEAR_MIPMAP_LINEAR
79 };
80
81
82 // CODE --------------------------------------------------------------------
83
84 int FindNextPower2(int num)
85 {
86         int cumul;
87         for(cumul=1; num > cumul; cumul *= 2);
88         return cumul;
89 }
90
91 float NextPower2Ratio(int num)
92 {
93         return num/(float)FindNextPower2(num);
94 }
95
96 void OGL_TexInit()
97 {
98         // Allocate memory for the flat texture numbers.
99         flattexnames = Z_Malloc(sizeof(GLuint)*numflats, PU_STATIC, 0); 
100         memset(flattexnames, 0, sizeof(GLuint)*numflats);
101
102         texnames = Z_Malloc(sizeof(GLuint)*numtextures, PU_STATIC, 0);
103         memset(texnames, 0, sizeof(GLuint)*numtextures);
104
105         texmasked = Z_Malloc(numtextures, PU_STATIC, 0);
106         memset(texmasked, 0, numtextures);
107
108         // Sprites.
109         spritenames = Z_Malloc(sizeof(GLuint)*numspritelumps, PU_STATIC, 0);
110         memset(spritenames, 0, sizeof(GLuint)*numspritelumps);  
111         spriteheights = Z_Malloc(sizeof(short)*numspritelumps, PU_STATIC, 0);
112         memset(spriteheights, 0, sizeof(short)*numspritelumps);
113
114         // Standard lump textures (raw images and other gfx).
115         // First parts.
116         lumptexnames = Z_Malloc(sizeof(GLuint)*numlumps, PU_STATIC, 0);
117         memset(lumptexnames, 0, sizeof(GLuint)*numlumps);
118         // Second parts.
119         lumptexnames2 = Z_Malloc(sizeof(GLuint)*numlumps, PU_STATIC, 0);
120         memset(lumptexnames2, 0, sizeof(GLuint)*numlumps);
121         // Size data.
122         lumptexsizes = Z_Malloc(sizeof(texsize_t)*numlumps, PU_STATIC, 0);
123         memset(lumptexsizes, 0, sizeof(texsize_t)*numlumps);
124
125         // Raw screen lump book keeping.
126         rawlumps = 0;
127         numrawlumps = 0;
128
129         // The dynamic light map.
130         dltexname = 0;
131
132         // The palette lump, for color information (really?).
133         pallump = W_GetNumForName("PLAYPAL");
134 }
135
136 void OGL_TexReset()
137 {
138         glDeleteTextures(numflats, flattexnames);
139         memset(flattexnames, 0, sizeof(GLuint)*numflats);
140
141         glDeleteTextures(numtextures, texnames);
142         memset(texnames, 0, sizeof(GLuint)*numtextures);
143         
144         memset(texmasked, 0, numtextures);
145
146         glDeleteTextures(numspritelumps, spritenames);
147         memset(spritenames, 0, sizeof(GLuint)*numspritelumps);
148         memset(spriteheights, 0, sizeof(short)*numspritelumps);
149
150 //      total_texmem_used = 0;
151
152         glDeleteTextures(1, &dltexname);
153         dltexname = 0;
154
155         // Normal patch/raw image textures aren't deleted here (see below).
156 }
157
158 void OGL_ResetLumpTexData()
159 {
160         glDeleteTextures(numlumps, lumptexnames);
161         glDeleteTextures(numlumps, lumptexnames2);
162         memset(lumptexnames, 0, sizeof(GLuint)*numlumps);
163         memset(lumptexnames2, 0, sizeof(GLuint)*numlumps);
164         memset(lumptexsizes, 0, sizeof(texsize_t)*numlumps);
165
166         // Free the raw lumps book keeping table.
167         free(rawlumps);
168         rawlumps = 0;
169         numrawlumps = 0;
170 }
171
172 // Binds the texture if necessary.
173 void OGL_BindTexture(GLuint texname)
174 {
175         if(curtex != texname) 
176         {
177                 glBindTexture(GL_TEXTURE_2D, texname);
178                 curtex = texname;
179         }
180 }
181
182 void PalToRGB(byte *palidx, byte *rgb)
183 {
184         int i;
185         for(i=0; i<3; i++) 
186         {
187                 *(rgb+i) = gammatable[usegamma][*(palidx+i)];
188         }
189 }
190
191 void PalIdxToRGB(byte *pal, int idx, byte *rgb)
192 {
193         PalToRGB(pal+idx*3, rgb);
194 }
195
196 unsigned int OGL_BindTexFlat(int lump)
197 {
198         GLuint name;
199         int p, i;
200         byte *flatptr = W_CacheLumpNum(lump, PU_STATIC);
201         byte *palette = W_CacheLumpNum(pallump=W_GetNumForName("PLAYPAL"), PU_CACHE);
202         byte *rgbflat = _alloca(3*lumpinfo[lump].size);
203         
204         //printf( "OGL_SetFlat: Loading flat %d.\n",idx);
205         // Convert the data to RGB.
206         for(i=0, p=0; i<lumpinfo[lump].size; i++)
207                 PalIdxToRGB(palette, flatptr[i], rgbflat+i*3);
208
209         // Generate and bind the texture.
210         glGenTextures(1, &name);//flattexnames+idx);
211         glBindTexture(GL_TEXTURE_2D, name);//flattexnames[idx]);
212         
213         // Set the texture properties.
214         if(test3dfx)
215         {
216                 glTexImage2D(GL_TEXTURE_2D, 0, 3, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, rgbflat);
217         }
218         else
219                 gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 64, 64, GL_RGB, GL_UNSIGNED_BYTE, rgbflat);
220         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glmode[mipmapping]);
221         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
222
223         // Change the tag.
224         Z_ChangeTag(flatptr, PU_CACHE);
225         return name;
226 }
227
228 // Returns the OpenGL name of the texture.
229 unsigned int OGL_PrepareFlat(int idx)
230 {
231         idx = flattranslation[idx];
232         if(!flattexnames[idx])
233         {
234                 // The flat isn't yet bound with OpenGL.
235                 flattexnames[idx] = OGL_BindTexFlat(firstflat+idx);
236         }
237         texw = texh = 64;
238         texmask = 0;
239         return flattexnames[idx];
240 }
241
242 void OGL_SetFlat(int idx)
243 {
244         glBindTexture(GL_TEXTURE_2D, OGL_PrepareFlat(idx));
245 }
246
247 // Return GL_RGB or GL_RGBA.
248 static int DrawRealPatch(byte *rgbflat, byte *rgbaflat, byte *palette, int texwidth,
249                                                  int texheight, patch_t *patch, boolean maskZero)
250 {
251         int count;
252         int col;
253         column_t *column;
254         byte *desttop1, *desttop2;
255         byte *dest1=NULL, *dest2=NULL;
256         byte *source;
257         int w, i;
258
259 /*      y -= SHORT(patch->topoffset);
260         x -= SHORT(patch->leftoffset);
261         if(x < 0 || x+SHORT(patch->width) > SCREENWIDTH || y < 0
262                 || y+SHORT(patch->height) > SCREENHEIGHT)
263         {
264                 I_Error("Bad V_DrawPatch");
265         }*/
266         col = 0;
267         desttop1 = rgbflat;// + y*SCREENWIDTH+x;
268         desttop2 = rgbaflat;
269         w = SHORT(patch->width);
270         for(; col < w; /*x++,*/ col++, desttop1+=3, desttop2+=4)
271         {
272                 column = (column_t *)((byte *)patch+LONG(patch->columnofs[col]));
273                 // Step through the posts in a column
274                 while(column->topdelta != 0xff)
275                 {
276                         source = (byte *)column+3;
277                         if(rgbflat) dest1 = desttop1 + column->topdelta*texwidth*3;
278                         if(rgbaflat) dest2 = desttop2 + column->topdelta*texwidth*4;
279                         count = column->length;
280                         while(count--)
281                         {
282                                 int palidx = *source++;
283                                 if(rgbflat)     
284                                 {
285                                         if(!maskZero || palidx) PalIdxToRGB(palette, palidx, dest1);
286                                         dest1 += texwidth*3;
287                                 }
288                                 if(rgbaflat)
289                                 {
290                                         if(!maskZero || palidx)
291                                         {
292                                                 PalIdxToRGB(palette, palidx, dest2);
293                                                 *(dest2+3) = 0xff;      // This pixel is not clear.
294                                         }
295                                         dest2 += texwidth*4;
296                                 }
297                         }
298                         column = (column_t *)((byte *)column+column->length+4);
299                 }
300         }
301         // Scan through the RGBA buffer and check for sub-0xff alpha.
302         if(rgbflat && rgbaflat) // Which one is it?
303         {
304                 for(i=0; i<texwidth*texheight; i++)
305                         if(*(rgbaflat + i*4 + 3) != 0xff) return GL_RGBA;                               
306         }
307         if(rgbflat) return GL_RGB;
308         return GL_RGBA;
309         //else return GL_RGBA;  // Must be rgba.
310         // No alpha was found, RGB is enough.
311         //return GL_RGB;
312 }
313
314 // Returns the OpenGL texture name.
315 unsigned int OGL_PrepareTexture(int idx)
316 {
317         if(idx == 0)
318         {
319                 // No texture?
320                 //glBindTexture(GL_TEXTURE_2D, 0);
321                 //curtex = 0;
322                 texw = 1;
323                 texh = 1;
324                 texmask = 0;
325                 return 0;
326         }
327         idx = texturetranslation[idx];
328         if(!texnames[idx])
329         {
330                 // The texture must be given to OpenGL.
331                 int i, k, textype;
332                 texture_t *tex = textures[idx];
333                 byte *palette = W_CacheLumpNum(pallump, PU_CACHE);
334                 byte *rgbflat = _alloca(3*tex->width*tex->height);
335                 byte *colptr;
336         
337                 if(tex->patchcount > 1)
338                 {
339                         textype = GL_RGB;
340                         for(i=0; i<tex->width; i++)
341                         {
342                                 colptr = R_GetColumn(idx,i);
343                                 for(k=0; k<tex->height; k++)
344                                         PalIdxToRGB(palette, colptr[k], rgbflat+(k*tex->width+i)*3);
345                         }
346                 }
347                 else 
348                 {
349                         // This texture has only only one patch. It might be masked.
350                         byte *rgbaflat = _alloca(4*tex->width*tex->height);
351                         memset(rgbaflat, 0, 4*tex->width*tex->height);
352                         textype = DrawRealPatch(rgbflat, rgbaflat, palette,     tex->width, tex->height,
353                                 W_CacheLumpNum(tex->patches[0].patch, PU_CACHE), false);
354                         if(textype == GL_RGBA) rgbflat = rgbaflat;
355                 }
356                                                 
357                 // Generate and bind the texture.
358                 glGenTextures(1, texnames+idx);
359                 glBindTexture(GL_TEXTURE_2D, texnames[idx]);
360                 gluBuild2DMipmaps(GL_TEXTURE_2D, (textype==GL_RGB)?3:4, tex->width, 
361                         tex->height, textype, GL_UNSIGNED_BYTE, rgbflat);
362                 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
363                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glmode[mipmapping]);
364                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
365
366                 if(textype == GL_RGBA) texmasked[idx] = 1;      // Yes it is.
367         }
368         texw = textures[idx]->width;
369         texh = textures[idx]->height;
370         texmask = texmasked[idx];
371         return texnames[idx];
372 }
373
374 void OGL_SetTexture(int idx)
375 {
376         glBindTexture(GL_TEXTURE_2D, OGL_PrepareTexture(idx));
377 }
378
379 int LineAverageRGB(byte *imgdata, int components, int width, int line, byte *rgb,
380                                         byte *palette)
381 {
382         byte    *start = imgdata + components*width*line;
383         int             i, c, count = 0;
384         int             integerRGB[3] = {0,0,0};
385
386         for(i=0; i<width; i++)
387         {
388                 byte *pixpos = start + i*components;
389                 if(*(pixpos+3) > 0)     // Not transparent?
390                 {
391                         count++;
392                         for(c=0; c<3; c++) integerRGB[c] += pixpos[c];
393                 }
394         }
395         // All transparent? Sorry...
396         if(!count) return 0;
397
398         // We're going to make it!
399         for(c=0; c<3; c++) rgb[c] = integerRGB[c]/count;
400         return 1;       // Successful.
401 }
402
403 void ImageAverageRGB(byte *imgdata, int components, int width, int height, byte *rgb,
404                                          byte *palette)
405 {
406         int     i, c, integerRGB[3] = {0,0,0}, count = 0;
407
408         for(i=0; i<height; i++)
409         {
410                 if(LineAverageRGB(imgdata, components, width, i, rgb, palette))
411                 {
412                         count++;
413                         for(c=0; c<3; c++) integerRGB[c] += rgb[c];
414                 }
415         }
416         if(count)       // If there were pixels...
417                 for(c=0; c<3; c++) 
418                         rgb[c] = integerRGB[c]/count;
419 }
420
421 unsigned int OGL_PrepareSky(int idx, boolean zeroMask)
422 {
423         if(idx != texturetranslation[idx])
424                 I_Error("Skytex: %d, translated: %d\n", idx, texturetranslation[idx]);
425         
426         idx = texturetranslation[idx];
427         
428         if(!texnames[idx])
429         {
430                 int                     i, k;
431                 byte            *palette = W_CacheLumpNum(pallump, PU_CACHE);
432                 texture_t       *tex = textures[idx];
433                 int                     textype, numpels = 256*256;     // 'Full' size.
434                 byte            *imgdata, *colptr;
435                 // Choose the right format.
436                 if(zeroMask)
437                 {
438                         textype = GL_RGBA;
439                         imgdata = _alloca(4*numpels);
440                         memset(imgdata, 0, 4*numpels);
441                 }
442                 else
443                 {
444                         textype = GL_RGB;
445                         imgdata = _alloca(3*numpels);
446                         memset(imgdata, 0, 3*numpels);
447                 }
448                 if(tex->patchcount > 1)
449                 {
450                         for(i=0; i<tex->width; i++)
451                         {
452                                 colptr = R_GetColumn(idx, i);
453                                 for(k=0; k<tex->height; k++)
454                                 {
455                                         if(textype == GL_RGB)
456                                                 PalIdxToRGB(palette, colptr[k], imgdata+(k*256+i)*3);
457                                         else if(textype == GL_RGBA && colptr[k])
458                                         {
459                                                 byte *imgpos = imgdata+(k*256+i)*4;
460                                                 PalIdxToRGB(palette, colptr[k], imgpos);
461                                                 *(imgpos+3) = 0xff;     // Not transparent, this pixel.
462                                         }
463                                 }
464                         }
465                 }
466                 else 
467                 {
468                         // This texture has only only one patch.
469                         if(textype == GL_RGB)
470                                 DrawRealPatch(imgdata, 0, palette, 256, tex->height, 
471                                         W_CacheLumpNum(tex->patches[0].patch, PU_CACHE), false);
472                         else if(textype == GL_RGBA) // Mask out zeros.
473                                 DrawRealPatch(0, imgdata, palette, 256, tex->height,
474                                         W_CacheLumpNum(tex->patches[0].patch, PU_CACHE), true);
475                 }
476                 if(textype == GL_RGBA)  // For masked data, calculate the alpha-fill color.
477                 {
478                         byte rgbAverage[3];     
479                         ImageAverageRGB(imgdata, 4, 256, 200, rgbAverage, palette);
480                         // Fill all the transparent places.
481                         for(i=0; i<256*200; i++)
482                         {
483                                 byte *pixel = imgdata + 4*i;
484                                 if(!pixel[3]) memcpy(pixel, rgbAverage, 3);
485                         }
486                 }
487                 // Calculate the topline RGB for sky top fadeouts.
488                 memset(topLineRGB, 0, 3);
489                 LineAverageRGB(imgdata, (textype==GL_RGB)?3:4, 256, 0, topLineRGB, palette);
490
491                 // Generate and bind the texture.
492                 glGenTextures(1, texnames+idx);
493                 glBindTexture(GL_TEXTURE_2D, texnames[idx]);
494                 if(test3dfx)
495                 {
496                         glTexImage2D(GL_TEXTURE_2D, 0, (textype==GL_RGB)?3:4, 256, 256, 0, GL_RGB, 
497                                 GL_UNSIGNED_BYTE, imgdata);
498                 }
499                 else
500                         gluBuild2DMipmaps(GL_TEXTURE_2D, (textype==GL_RGB)?3:4, 256, 256, textype, 
501                                 GL_UNSIGNED_BYTE, imgdata);
502 //              glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
503                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glmode[mipmapping]);
504                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
505
506                 // Do we have a masked texture?
507                 if(textype == GL_RGBA) 
508                         texmasked[idx] = 1;
509                 else
510                         texmasked[idx] = 0;
511         }
512         texw = textures[idx]->width;
513         texh = textures[idx]->height;
514         texmask = texmasked[idx];
515         return texnames[idx];
516 }
517
518 unsigned int OGL_PrepareSprite(int pnum)
519 {
520         if(!spritenames[pnum])
521         {
522                 // There's no name for this patch, load it in.
523                 patch_t *patch = W_CacheLumpNum(firstspritelump+pnum, PU_CACHE);
524                 int p2width = FindNextPower2(patch->width), 
525                         p2height = OGL_ValidTexHeight2(patch->width, patch->height);// FindNextPower2(patch->height);
526                 int flatsize = 4*p2width*p2height;
527                 byte *rgbaflat = _alloca(flatsize);
528                 
529                 //printf( "orig: %d x %d => %d x %d\n", patch->width, patch->height, p2width, p2height);
530
531                 memset(rgbaflat, 0, flatsize);
532                 DrawRealPatch(0, rgbaflat, W_CacheLumpNum(pallump,PU_CACHE),
533                         p2width, p2height, patch, false);
534
535                 // Generate and bind the texture.
536                 glGenTextures(1, spritenames+pnum);
537                 glBindTexture(GL_TEXTURE_2D, spritenames[pnum]);
538                 gluBuild2DMipmaps(GL_TEXTURE_2D, 4, p2width, p2height, GL_RGBA, 
539                         GL_UNSIGNED_BYTE, rgbaflat);
540                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glmode[mipmapping]);
541                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
542                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
543                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
544
545                 spriteheights[pnum] = patch->height;
546         }
547         return spritenames[pnum];
548 }
549  
550 void OGL_SetSprite(int pnum)
551 {
552         OGL_BindTexture(OGL_PrepareSprite(pnum));
553 }
554
555 void OGL_NewRawLump(int lump)
556 {
557         rawlumps = realloc(rawlumps, sizeof(int) * ++numrawlumps);
558         rawlumps[numrawlumps-1] = lump;
559 }
560
561 GLuint OGL_GetOtherPart(int lump)
562 {
563         return lumptexnames2[lump];
564 }
565
566 // Part is either 1 or 2. Part 0 means only the left side is loaded.
567 // No splittex is created in that case. Once a raw image is loaded
568 // as part 0 it must be deleted before the other part is loaded at the
569 // next loading.
570 void OGL_SetRawImage(int lump, int part)
571 {
572         if(part < 0 || part > 2) return;        // Check the part.
573
574         if(!lumptexnames[lump])
575         {
576                 // Load the raw texture data (320x200).
577                 // We'll create two textures (256x256 and 64x256).
578                 byte *raw = W_CacheLumpNum(lump, PU_CACHE);
579                 byte *dat1 = _alloca(3*256*256);        // Let's hope there's enough stack!
580                 byte *dat2 = _alloca(3*64*256);
581                 byte *palette = W_CacheLumpNum(pallump, PU_CACHE);
582                 int i,k;
583                 memset(dat1, 0, 3*256*256);     // Why must this be done?
584                 for(k=0; k<200; k++)
585                         for(i=0; i<256; i++)
586                         {
587                                 // We can't go over the end.
588                                 if(k*320+i > lumpinfo[lump].size-1) break;
589                                 // Part one.
590                                 PalIdxToRGB(palette, *(raw+(k*320+i)), dat1+3*(k*256+i));
591                                 if(i<64 && part) // Part two?
592                                         PalIdxToRGB(palette, *(raw+(k*320+i+256)), dat2+3*(k*64+i));
593                         }
594
595                 // Do a special fill for textures with h<200 (part 0).
596                 if(/*lumpinfo[lump].size/320 < 200 &&*/ !part)
597                 {
598                         int lines = lumpinfo[lump].size/320;
599                         // Copy the missing data from the beginning.
600                         memcpy(dat1+lines*256*3, dat1, 3*256*(256-lines));
601                 }
602                         
603                 // Generate and load the textures.
604                 glGenTextures(1, lumptexnames+lump);
605                 glBindTexture(GL_TEXTURE_2D, lumptexnames[lump]);
606                 glTexImage2D(GL_TEXTURE_2D, 0, 3, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, dat1);
607                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
608                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linearRaw? GL_LINEAR : GL_NEAREST);
609                 
610                 if(part)
611                 {
612                         // And the other part.
613                         glGenTextures(1, lumptexnames2+lump);
614                         glBindTexture(GL_TEXTURE_2D, lumptexnames2[lump]);
615                         glTexImage2D(GL_TEXTURE_2D, 0, 3, 64, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, dat2);
616                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
617                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linearRaw? GL_LINEAR : GL_NEAREST);
618                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
619
620                         // Add it to the list.
621                         OGL_NewRawLump(lump);
622                 }
623
624                 lumptexsizes[lump].w = 256;
625                 lumptexsizes[lump].w2 = 64;
626                 lumptexsizes[lump].h = 200;
627         }
628         // Bind the correct part.
629         if(part <= 1) glBindTexture(GL_TEXTURE_2D, lumptexnames[lump]);
630         if(part == 2) glBindTexture(GL_TEXTURE_2D, lumptexnames2[lump]);
631         // We don't track the current texture with raw images.
632         curtex = 0;
633 }
634
635 // Copies a rectangular region of the source buffer to the destination
636 // buffer. Doesn't perform clipping, so be careful.
637 static void pixBlt(byte *src, int srcWidth, byte *dest, int destWidth, int pixelSize, 
638                                    int srcRegX, int srcRegY, int destRegX, int destRegY,
639                                    int regWidth, int regHeight)
640 {
641         int     y;      // Y in the copy region.
642         for(y=0; y<regHeight; y++) // Copy line by line.
643                 memcpy(dest + pixelSize*(destRegX + (y+destRegY)*destWidth),
644                         src + pixelSize*(srcRegX + (y+srcRegY)*srcWidth),
645                         pixelSize*regWidth);
646 }
647
648 // Notices ratiolimit.
649 int OGL_ValidTexHeight2(int width, int height)
650 {
651         int p2w, p2h = FindNextPower2(height);
652         int minheight;
653
654         if(!ratioLimit) return p2h;
655
656         p2w = FindNextPower2(width);
657         // Do we have to notice that the texture will be split?
658         if(p2w > maxTexSize)
659         {
660                 int part2width = FindNextPower2(width - maxTexSize);
661                 int height1 = maxTexSize/ratioLimit,
662                         height2 = part2width/ratioLimit;
663                 minheight = height1 > height2? height1 : height2;
664         }
665         else minheight = p2w/ratioLimit;
666         // Do the test.
667         if(minheight > p2h) return minheight;
668         return p2h;
669 }
670
671 void OGL_SetPatch(int lump)     // No mipmaps are generated.
672 {
673         if(!lumptexnames[lump])
674         {
675                 // Load the patch.
676                 patch_t *patch = W_CacheLumpNum(lump, PU_CACHE);
677                 int             p2width = FindNextPower2(patch->width), 
678                                 p2height = OGL_ValidTexHeight2(patch->width, patch->height);//FindNextPower2(patch->height);
679                 int             numpels = p2width*p2height;
680                 byte    *rgbflat = _alloca(3*numpels), 
681                                 *rgbaflat = _alloca(4*numpels);
682                 int             ptype;
683                 
684                 memset(rgbaflat, 0, 4*numpels);
685                 ptype = DrawRealPatch(rgbflat, rgbaflat, W_CacheLumpNum(pallump,PU_CACHE),
686                         p2width, p2height, patch, false);
687
688                 // See if we have to split the patch into two parts.
689                 if(p2width > maxTexSize) // Nothing about the height...
690                 {
691                         // Notice: This is only vertical splitting, p2height 
692                         // applies to both parts. 
693                         // The width of the first part is maxTexSize.
694                         int part2width = FindNextPower2(patch->width - maxTexSize);
695                         byte *tempbuff = _alloca(4*maxTexSize*p2height);
696                         if(part2width > maxTexSize)
697                                 I_Error("OGL_SetPatch: Too wide texture (really: %d, pow2: %d).\n", patch->width, p2width);
698                         // We'll use a temporary buffer for doing to splitting.
699                         // First, part one.
700                         pixBlt(ptype==GL_RGB? rgbflat : rgbaflat, p2width, tempbuff,
701                                 maxTexSize, ptype==GL_RGB? 3 : 4,
702                                 0, 0, 0, 0, maxTexSize, p2height);
703                         // Generate a texture.
704                         glGenTextures(1, lumptexnames+lump);
705                         glBindTexture(GL_TEXTURE_2D, lumptexnames[lump]);
706                         // There won't be mipmapping versions.
707                         glTexImage2D(GL_TEXTURE_2D, 0, ptype==GL_RGB? 3 : 4, maxTexSize, p2height,
708                                 0, ptype, GL_UNSIGNED_BYTE, tempbuff);
709                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
710                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
711                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
712                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
713
714                         // Then part two.
715                         pixBlt(ptype==GL_RGB? rgbflat : rgbaflat, p2width, tempbuff,
716                                 part2width, ptype==GL_RGB? 3 : 4, 
717                                 maxTexSize, 0, 0, 0, part2width, p2height);
718                         // Generate a texture.
719                         glGenTextures(1, lumptexnames2+lump);
720                         glBindTexture(GL_TEXTURE_2D, lumptexnames2[lump]);
721                         // There won't be mipmapping versions.
722                         glTexImage2D(GL_TEXTURE_2D, 0, ptype==GL_RGB? 3 : 4, part2width, p2height,
723                                 0, ptype, GL_UNSIGNED_BYTE, tempbuff);
724                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
725                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
726                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
727                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
728
729                         OGL_BindTexture(lumptexnames[lump]);
730
731                         lumptexsizes[lump].w = maxTexSize;
732                         lumptexsizes[lump].w2 = patch->width - maxTexSize;
733                 }
734                 else // We can use the normal one-part method.
735                 {
736                         // Generate a texture.
737                         glGenTextures(1, lumptexnames+lump);
738                         glBindTexture(GL_TEXTURE_2D, lumptexnames[lump]);
739                         // There won't be mipmapping versions.
740                         glTexImage2D(GL_TEXTURE_2D, 0, (ptype==GL_RGB)?3:4, p2width, p2height,
741                                 0, ptype, GL_UNSIGNED_BYTE, (ptype==GL_RGB)?rgbflat:rgbaflat);
742                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
743                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
744
745                         lumptexsizes[lump].w = patch->width;
746                         lumptexsizes[lump].w2 = 0;
747                 }
748                 // The rest of the size information.
749                 lumptexsizes[lump].h = patch->height;
750                 lumptexsizes[lump].offx = -patch->leftoffset;
751                 lumptexsizes[lump].offy = -patch->topoffset;
752         }
753         else
754         {
755                 OGL_BindTexture(lumptexnames[lump]);
756         }
757         curtex = lumptexnames[lump];
758 }
759
760 #if 0
761 // Drawing polygons with an unset texture causes a segfault with Mesa 3.0.
762 // I guess Windows OpenGL handles this ok.
763 // I am disabling texturing when needed rather than binding an unset texture.
764 void OGL_SetNoTexture()
765 {
766
767         //glBindTexture(GL_TEXTURE_2D, 0);
768         glDisable( GL_TEXTURE_2D );
769
770         curtex = 0;
771 }
772 #endif
773
774 GLuint OGL_PrepareLightTexture()
775 {
776         if(!dltexname)
777         {
778                 // We need to generate the texture, I see.
779                 byte *image = W_CacheLumpName("DLIGHT", PU_CACHE);
780                 if(!image)
781                         I_Error("OGL_SetLightTexture: no dlight texture.\n");
782                 // The dynamic light map is a 64x64 grayscale 8-bit image.
783                 glGenTextures(1, &dltexname);
784                 glBindTexture(GL_TEXTURE_2D, dltexname);
785
786                 glTexImage2D(GL_TEXTURE_2D, 0, 1, 64, 64, 0, GL_LUMINANCE, 
787                         GL_UNSIGNED_BYTE, image);
788                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
789                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
790                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
791                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
792         }
793         // Set the info.
794         texw = texh = 64;
795         texmask = 0;
796         return dltexname;
797 }
798
799 int OGL_GetLumpTexWidth(int lump)
800 {
801         return lumptexsizes[lump].w;
802 }
803
804 int OGL_GetLumpTexHeight(int lump)
805 {
806         return lumptexsizes[lump].h;
807 }
808
809 // Updates the textures, flats and sprites.
810 void OGL_UpdateTexParams(int mipmode)
811 {
812         int     i;
813         
814         // Textures.
815         for(i=0; i<numtextures; i++)
816                 if(texnames[i]) // Is the texture loaded?
817                 {
818                         glBindTexture(GL_TEXTURE_2D, texnames[i]);
819                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glmode[mipmode]);
820                 }
821         // Flats.
822         for(i=0; i<numflats; i++)
823                 if(flattexnames[i]) // Is the texture loaded?
824                 {
825                         glBindTexture(GL_TEXTURE_2D, flattexnames[i]);
826                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glmode[mipmode]);
827                 }
828         // Sprites.
829         for(i=0; i<numspritelumps; i++)
830                 if(spritenames[i])
831                 {
832                         glBindTexture(GL_TEXTURE_2D, spritenames[i]);
833                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, glmode[mipmode]);
834                 }
835 }
836
837 // Updates the raw screen smoothing (linear magnification).
838 // This is the main reason for having the rawlumps table.
839 void OGL_UpdateRawScreenParams(int smoothing)
840 {
841         int             i;
842         int             glmode = (smoothing)? GL_LINEAR : GL_NEAREST;
843
844         for(i=0; i<numrawlumps; i++)
845         {
846                 // First part 1.
847                 glBindTexture(GL_TEXTURE_2D, lumptexnames[rawlumps[i]]);
848                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glmode);
849                 // Then part 2.
850                 glBindTexture(GL_TEXTURE_2D, lumptexnames2[rawlumps[i]]);
851                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, glmode);
852         }
853 }