1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19*/
20// r_surf.c: surface-related refresh code
21
22#include "quakedef.h"
23
24int			skytexturenum;
25
26#ifndef GL_RGBA4
27#define	GL_RGBA4	0
28#endif
29
30
31int		lightmap_bytes;		// 1, 2, or 4
32
33int		lightmap_textures;
34
35unsigned		blocklights[18*18];
36
37#define	BLOCK_WIDTH		128
38#define	BLOCK_HEIGHT	128
39
40#define	MAX_LIGHTMAPS	64
41int			active_lightmaps;
42
43typedef struct glRect_s {
44  unsigned char l,t,w,h;
45} glRect_t;
46
47glpoly_t	*lightmap_polys[MAX_LIGHTMAPS];
48qboolean	lightmap_modified[MAX_LIGHTMAPS];
49glRect_t	lightmap_rectchange[MAX_LIGHTMAPS];
50
51int			allocated[MAX_LIGHTMAPS][BLOCK_WIDTH];
52
53// the lightmap texture data needs to be kept in
54// main memory so texsubimage can update properly
55byte		lightmaps[4*MAX_LIGHTMAPS*BLOCK_WIDTH*BLOCK_HEIGHT];
56
57// For gl_texsort 0
58msurface_t  *skychain = NULL;
59msurface_t  *waterchain = NULL;
60
61void R_RenderDynamicLightmaps (msurface_t *fa);
62
63/*
64===============
65R_AddDynamicLights
66===============
67*/
68void R_AddDynamicLights (msurface_t *surf)
69{
70  int			lnum;
71  int			sd, td;
72  float		dist, rad, minlight;
73  vec3_t		impact, local;
74  int			s, t;
75  int			i;
76  int			smax, tmax;
77  mtexinfo_t	*tex;
78
79  smax = (surf->extents[0]>>4)+1;
80  tmax = (surf->extents[1]>>4)+1;
81  tex = surf->texinfo;
82
83  for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
84  {
85    if ( !(surf->dlightbits & (1<<lnum) ) )
86      continue;		// not lit by this light
87
88    rad = cl_dlights[lnum].radius;
89    dist = DotProduct (cl_dlights[lnum].origin, surf->plane->normal) -
90        surf->plane->dist;
91    rad -= fabs(dist);
92    minlight = cl_dlights[lnum].minlight;
93    if (rad < minlight)
94      continue;
95    minlight = rad - minlight;
96
97    for (i=0 ; i<3 ; i++)
98    {
99      impact[i] = cl_dlights[lnum].origin[i] -
100          surf->plane->normal[i]*dist;
101    }
102
103    local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];
104    local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];
105
106    local[0] -= surf->texturemins[0];
107    local[1] -= surf->texturemins[1];
108
109    for (t = 0 ; t<tmax ; t++)
110    {
111      td = (int)(local[1] - t*16);
112      if (td < 0)
113        td = -td;
114      for (s=0 ; s<smax ; s++)
115      {
116        sd = (int)(local[0] - s*16);
117        if (sd < 0)
118          sd = -sd;
119        if (sd > td)
120          dist = sd + (td>>1);
121        else
122          dist = td + (sd>>1);
123        if (dist < minlight)
124          blocklights[t*smax + s] += (int)((rad - dist)*256);
125      }
126    }
127  }
128}
129
130
131/*
132===============
133R_BuildLightMap
134
135Combine and scale multiple lightmaps into the 8.8 format in blocklights
136===============
137*/
138void R_BuildLightMap (msurface_t *surf, byte *dest, int stride)
139{
140  int			smax, tmax;
141  int			t;
142  int			i, j, size;
143  byte		*lightmap;
144  unsigned	scale;
145  int			maps;
146  int			lightadj[4];
147  unsigned	*bl;
148
149  surf->cached_dlight = (surf->dlightframe == r_framecount);
150
151  smax = (surf->extents[0]>>4)+1;
152  tmax = (surf->extents[1]>>4)+1;
153  size = smax*tmax;
154  lightmap = surf->samples;
155
156// set to full bright if no light data
157  if (r_fullbright.value || !cl.worldmodel->lightdata)
158  {
159    for (i=0 ; i<size ; i++)
160      blocklights[i] = 255*256;
161    goto store;
162  }
163
164// clear to no light
165  for (i=0 ; i<size ; i++)
166    blocklights[i] = 0;
167
168// add all the lightmaps
169  if (lightmap)
170    for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ;
171       maps++)
172    {
173      scale = d_lightstylevalue[surf->styles[maps]];
174      surf->cached_light[maps] = scale;	// 8.8 fraction
175      for (i=0 ; i<size ; i++)
176        blocklights[i] += lightmap[i] * scale;
177      lightmap += size;	// skip to next lightmap
178    }
179
180// add all the dynamic lights
181  if (surf->dlightframe == r_framecount)
182    R_AddDynamicLights (surf);
183
184// bound, invert, and shift
185store:
186  switch (gl_lightmap_format)
187  {
188  case GL_RGBA:
189    stride -= (smax<<2);
190    bl = blocklights;
191    for (i=0 ; i<tmax ; i++, dest += stride)
192    {
193      for (j=0 ; j<smax ; j++)
194      {
195        t = *bl++;
196        t >>= 7;
197        if (t > 255)
198          t = 255;
199        dest[3] = 255-t;
200        dest += 4;
201      }
202    }
203    break;
204  case GL_ALPHA:
205  case GL_LUMINANCE:
206  case GL_INTENSITY:
207    bl = blocklights;
208    for (i=0 ; i<tmax ; i++, dest += stride)
209    {
210      for (j=0 ; j<smax ; j++)
211      {
212        t = *bl++;
213        t >>= 7;
214        if (t > 255)
215          t = 255;
216        dest[j] = 255-t;
217      }
218    }
219    break;
220  default:
221    Sys_Error ("Bad lightmap format");
222  }
223}
224
225
226/*
227===============
228R_TextureAnimation
229
230Returns the proper texture for a given time and base texture
231===============
232*/
233texture_t *R_TextureAnimation (texture_t *base)
234{
235  int		reletive;
236  int		count;
237
238  if (currententity->frame)
239  {
240    if (base->alternate_anims)
241      base = base->alternate_anims;
242  }
243
244  if (!base->anim_total)
245    return base;
246
247  reletive = (int)(cl.time*10) % base->anim_total;
248
249  count = 0;
250  while (base->anim_min > reletive || base->anim_max <= reletive)
251  {
252    base = base->anim_next;
253    if (!base)
254      Sys_Error ("R_TextureAnimation: broken cycle");
255    if (++count > 100)
256      Sys_Error ("R_TextureAnimation: infinite cycle");
257  }
258
259  return base;
260}
261
262
263/*
264=============================================================
265
266  BRUSH MODELS
267
268=============================================================
269*/
270
271
272extern	int		solidskytexture;
273extern	int		alphaskytexture;
274extern	float	speedscale;		// for top sky and bottom sky
275
276void DrawGLWaterPoly (glpoly_t *p);
277void DrawGLWaterPolyLightmap (glpoly_t *p);
278
279#ifdef _WIN32
280lpMTexFUNC qglMTexCoord2fSGIS = NULL;
281lpSelTexFUNC qglSelectTextureSGIS = NULL;
282#endif
283
284qboolean mtexenabled = false;
285
286void GL_SelectTexture (GLenum target);
287
288void GL_DisableMultitexture(void)
289{
290  if (mtexenabled) {
291    glDisable(GL_TEXTURE_2D);
292    GL_SelectTexture(TEXTURE0_SGIS);
293    mtexenabled = false;
294  }
295}
296
297void GL_EnableMultitexture(void)
298{
299  if (gl_mtexable) {
300    GL_SelectTexture(TEXTURE1_SGIS);
301    glEnable(GL_TEXTURE_2D);
302    mtexenabled = true;
303  }
304}
305
306#if 0
307/*
308================
309R_DrawSequentialPoly
310
311Systems that have fast state and texture changes can
312just do everything as it passes with no need to sort
313================
314*/
315void R_DrawSequentialPoly (msurface_t *s)
316{
317  glpoly_t	*p;
318  float		*v;
319  int			i;
320  texture_t	*t;
321
322  //
323  // normal lightmaped poly
324  //
325  if (! (s->flags & (SURF_DRAWSKY|SURF_DRAWTURB|SURF_UNDERWATER) ) )
326  {
327    p = s->polys;
328
329    t = R_TextureAnimation (s->texinfo->texture);
330    GL_Bind (t->gl_texturenum);
331    glBegin (GL_POLYGON);
332    v = p->verts[0];
333    for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
334    {
335      glTexCoord2f (v[3], v[4]);
336      glVertex3fv (v);
337    }
338    glEnd ();
339
340    GL_Bind (lightmap_textures + s->lightmaptexturenum);
341    glEnable (GL_BLEND);
342    glBegin (GL_POLYGON);
343    v = p->verts[0];
344    for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
345    {
346      glTexCoord2f (v[5], v[6]);
347      glVertex3fv (v);
348    }
349    glEnd ();
350
351    glDisable (GL_BLEND);
352
353    return;
354  }
355
356  //
357  // subdivided water surface warp
358  //
359  if (s->flags & SURF_DRAWTURB)
360  {
361    GL_Bind (s->texinfo->texture->gl_texturenum);
362    EmitWaterPolys (s);
363    return;
364  }
365
366  //
367  // subdivided sky warp
368  //
369  if (s->flags & SURF_DRAWSKY)
370  {
371    GL_Bind (solidskytexture);
372    speedscale = realtime*8;
373    speedscale -= (int)speedscale;
374
375    EmitSkyPolys (s);
376
377    glEnable (GL_BLEND);
378    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
379    GL_Bind (alphaskytexture);
380    speedscale = realtime*16;
381    speedscale -= (int)speedscale;
382    EmitSkyPolys (s);
383    if (gl_lightmap_format == GL_LUMINANCE)
384      glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
385
386    glDisable (GL_BLEND);
387  }
388
389  //
390  // underwater warped with lightmap
391  //
392  p = s->polys;
393
394  t = R_TextureAnimation (s->texinfo->texture);
395  GL_Bind (t->gl_texturenum);
396  DrawGLWaterPoly (p);
397
398  GL_Bind (lightmap_textures + s->lightmaptexturenum);
399  glEnable (GL_BLEND);
400  DrawGLWaterPolyLightmap (p);
401  glDisable (GL_BLEND);
402}
403#else
404/*
405================
406R_DrawSequentialPoly
407
408Systems that have fast state and texture changes can
409just do everything as it passes with no need to sort
410================
411*/
412void R_DrawSequentialPoly (msurface_t *s)
413{
414  glpoly_t	*p;
415  float		*v;
416  int			i;
417  texture_t	*t;
418  vec3_t		nv, dir;
419  float		ss, ss2, length;
420  float		s1, t1;
421  glRect_t	*theRect;
422
423  //
424  // normal lightmaped poly
425  //
426
427  if (! (s->flags & (SURF_DRAWSKY|SURF_DRAWTURB|SURF_UNDERWATER) ) )
428  {
429    R_RenderDynamicLightmaps (s);
430    if (gl_mtexable) {
431      p = s->polys;
432
433      t = R_TextureAnimation (s->texinfo->texture);
434      // Binds world to texture env 0
435      GL_SelectTexture(TEXTURE0_SGIS);
436      GL_Bind (t->gl_texturenum);
437      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
438
439      // Binds lightmap to texenv 1
440      GL_EnableMultitexture(); // Same as SelectTexture (TEXTURE1)
441      GL_Bind (lightmap_textures + s->lightmaptexturenum);
442      i = s->lightmaptexturenum;
443      if (lightmap_modified[i])
444      {
445        lightmap_modified[i] = false;
446        theRect = &lightmap_rectchange[i];
447        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
448          BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
449          lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
450        theRect->l = BLOCK_WIDTH;
451        theRect->t = BLOCK_HEIGHT;
452        theRect->h = 0;
453        theRect->w = 0;
454      }
455      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
456
457#ifdef USE_OPENGLES
458
459      glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][3]);
460            glClientActiveTexture(GL_TEXTURE1);
461            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
462      glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][5]);
463      glVertexPointer(3, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][0]);
464            glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
465            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
466            glClientActiveTexture(GL_TEXTURE0);
467
468#else
469      glBegin(GL_POLYGON);
470      v = p->verts[0];
471      for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
472      {
473        qglMTexCoord2fSGIS (TEXTURE0_SGIS, v[3], v[4]);
474        qglMTexCoord2fSGIS (TEXTURE1_SGIS, v[5], v[6]);
475        glVertex3fv (v);
476      }
477      glEnd ();
478#endif
479      return;
480    } else {
481      p = s->polys;
482
483      t = R_TextureAnimation (s->texinfo->texture);
484      GL_Bind (t->gl_texturenum);
485#ifdef USE_OPENGLES
486      glVertexPointer(3, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][0]);
487      glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][3]);
488      glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
489#else
490      glBegin (GL_POLYGON);
491      v = p->verts[0];
492      for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
493      {
494        glTexCoord2f (v[3], v[4]);
495        glVertex3fv (v);
496      }
497      glEnd ();
498#endif
499
500      GL_Bind (lightmap_textures + s->lightmaptexturenum);
501      glEnable (GL_BLEND);
502#ifdef USE_OPENGLES
503      glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][5]);
504      glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
505#else
506      glBegin (GL_POLYGON);
507      v = p->verts[0];
508      for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
509      {
510        glTexCoord2f (v[5], v[6]);
511        glVertex3fv (v);
512      }
513      glEnd ();
514#endif
515
516      glDisable (GL_BLEND);
517    }
518
519    return;
520  }
521
522  //
523  // subdivided water surface warp
524  //
525
526  if (s->flags & SURF_DRAWTURB)
527  {
528    GL_DisableMultitexture();
529    GL_Bind (s->texinfo->texture->gl_texturenum);
530    EmitWaterPolys (s);
531    return;
532  }
533
534  //
535  // subdivided sky warp
536  //
537  if (s->flags & SURF_DRAWSKY)
538  {
539    GL_DisableMultitexture();
540    GL_Bind (solidskytexture);
541    speedscale = realtime*8;
542    speedscale -= (int)speedscale & ~127;
543
544    EmitSkyPolys (s);
545
546    glEnable (GL_BLEND);
547    GL_Bind (alphaskytexture);
548    speedscale = realtime*16;
549    speedscale -= (int)speedscale & ~127;
550    EmitSkyPolys (s);
551
552    glDisable (GL_BLEND);
553    return;
554  }
555
556  //
557  // underwater warped with lightmap
558  //
559  R_RenderDynamicLightmaps (s);
560  if (gl_mtexable) {
561    p = s->polys;
562
563    t = R_TextureAnimation (s->texinfo->texture);
564    GL_SelectTexture(TEXTURE0_SGIS);
565    GL_Bind (t->gl_texturenum);
566    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
567    GL_EnableMultitexture();
568    GL_Bind (lightmap_textures + s->lightmaptexturenum);
569    i = s->lightmaptexturenum;
570    if (lightmap_modified[i])
571    {
572      lightmap_modified[i] = false;
573      theRect = &lightmap_rectchange[i];
574      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
575        BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
576        lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
577      theRect->l = BLOCK_WIDTH;
578      theRect->t = BLOCK_HEIGHT;
579      theRect->h = 0;
580      theRect->w = 0;
581    }
582    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
583#ifdef USE_OPENGLES
584    {
585      float* pPos = gVertexBuffer;
586      v = p->verts[0];
587      for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
588      {
589        *pPos++ = v[0] + 8*sinf(v[1]*0.05f+realtime)*sinf(v[2]*0.05f+realtime);
590        *pPos++ = v[1] + 8*sinf(v[0]*0.05f+realtime)*sinf(v[2]*0.05f+realtime);
591        *pPos++ = v[2];
592      }
593    }
594        glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][3]);
595        glClientActiveTexture(GL_TEXTURE1);
596        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
597        glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][5]);
598        glVertexPointer(3, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][0]);
599        glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
600        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
601        glClientActiveTexture(GL_TEXTURE0);
602#else
603    glBegin (GL_TRIANGLE_FAN);
604    v = p->verts[0];
605    for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
606    {
607      qglMTexCoord2fSGIS (TEXTURE0_SGIS, v[3], v[4]);
608      qglMTexCoord2fSGIS (TEXTURE1_SGIS, v[5], v[6]);
609
610      nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
611      nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
612      nv[2] = v[2];
613
614      glVertex3fv (nv);
615    }
616    glEnd ();
617#endif
618
619  } else {
620    p = s->polys;
621
622    t = R_TextureAnimation (s->texinfo->texture);
623    GL_Bind (t->gl_texturenum);
624    DrawGLWaterPoly (p);
625
626    GL_Bind (lightmap_textures + s->lightmaptexturenum);
627    glEnable (GL_BLEND);
628    DrawGLWaterPolyLightmap (p);
629    glDisable (GL_BLEND);
630  }
631}
632#endif
633
634
635/*
636================
637DrawGLWaterPoly
638
639Warp the vertex coordinates
640================
641*/
642void DrawGLWaterPoly (glpoly_t *p)
643{
644  int		i;
645  float	*v;
646  float	s, t, os, ot;
647  vec3_t	nv;
648
649  GL_DisableMultitexture();
650
651#ifdef USE_OPENGLES
652  glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
653  glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][3]);
654
655  v = p->verts[0];
656  {
657    float* pnv = gVertexBuffer;
658    for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
659    {
660      pnv[0] = v[0] + 8*sinf(v[1]*0.05f+realtime)*sinf(v[2]*0.05f+realtime);
661      pnv[1] = v[1] + 8*sinf(v[0]*0.05f+realtime)*sinf(v[2]*0.05f+realtime);
662      pnv[2] = v[2];
663
664      pnv += 3;
665    }
666  }
667  glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
668#else
669  glBegin (GL_TRIANGLE_FAN);
670  v = p->verts[0];
671  for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
672  {
673    glTexCoord2f (v[3], v[4]);
674
675    nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
676    nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
677    nv[2] = v[2];
678
679    glVertex3fv (nv);
680  }
681  glEnd ();
682#endif
683}
684
685void DrawGLWaterPolyLightmap (glpoly_t *p)
686{
687  int		i;
688  float	*v;
689  float	s, t, os, ot;
690  vec3_t	nv;
691
692  GL_DisableMultitexture();
693
694#ifdef USE_OPENGLES
695  glVertexPointer(3, GL_FLOAT, 0, gVertexBuffer);
696  glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][5]);
697
698  v = p->verts[0];
699  {
700    float* pnv = gVertexBuffer;
701    for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
702    {
703      pnv[0] = v[0] + 8*sinf(v[1]*0.05f+realtime)*sinf(v[2]*0.05f+realtime);
704      pnv[1] = v[1] + 8*sinf(v[0]*0.05f+realtime)*sinf(v[2]*0.05f+realtime);
705      pnv[2] = v[2];
706
707      pnv += 3;
708    }
709  }
710  glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
711
712#else
713  glBegin (GL_TRIANGLE_FAN);
714  v = p->verts[0];
715  for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
716  {
717    glTexCoord2f (v[5], v[6]);
718
719    nv[0] = v[0] + 8*sin(v[1]*0.05+realtime)*sin(v[2]*0.05+realtime);
720    nv[1] = v[1] + 8*sin(v[0]*0.05+realtime)*sin(v[2]*0.05+realtime);
721    nv[2] = v[2];
722
723    glVertex3fv (nv);
724  }
725  glEnd ();
726#endif
727}
728
729/*
730================
731DrawGLPoly
732================
733*/
734void DrawGLPoly (glpoly_t *p)
735{
736  int		i;
737  float	*v;
738
739#ifdef USE_OPENGLES
740  glVertexPointer(3, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][0]);
741  glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][3]);
742  glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
743#else
744  glBegin (GL_POLYGON);
745  v = p->verts[0];
746  for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
747  {
748    glTexCoord2f (v[3], v[4]);
749    glVertex3fv (v);
750  }
751  glEnd ();
752#endif
753}
754
755
756/*
757================
758R_BlendLightmaps
759================
760*/
761void R_BlendLightmaps (void)
762{
763  int			i, j;
764  glpoly_t	*p;
765  float		*v;
766  glRect_t	*theRect;
767
768  if (r_fullbright.value)
769    return;
770  if (!gl_texsort.value)
771    return;
772
773  glDepthMask (0);		// don't bother writing Z
774
775  if (gl_lightmap_format == GL_LUMINANCE)
776    glBlendFunc (GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
777  else if (gl_lightmap_format == GL_INTENSITY)
778  {
779    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
780    glColor4f (0,0,0,1);
781    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
782  }
783
784  if (!r_lightmap.value)
785  {
786    glEnable (GL_BLEND);
787  }
788
789  for (i=0 ; i<MAX_LIGHTMAPS ; i++)
790  {
791    p = lightmap_polys[i];
792    if (!p)
793      continue;
794    GL_Bind(lightmap_textures+i);
795    if (lightmap_modified[i])
796    {
797      lightmap_modified[i] = false;
798      theRect = &lightmap_rectchange[i];
799//			glTexImage2DHelper (GL_TEXTURE_2D, 0, lightmap_bytes
800//			, BLOCK_WIDTH, BLOCK_HEIGHT, 0,
801//			gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes);
802//			glTexImage2DHelper (GL_TEXTURE_2D, 0, lightmap_bytes
803//				, BLOCK_WIDTH, theRect->h, 0,
804//				gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+(i*BLOCK_HEIGHT+theRect->t)*BLOCK_WIDTH*lightmap_bytes);
805      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
806        BLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
807        lightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);
808      theRect->l = BLOCK_WIDTH;
809      theRect->t = BLOCK_HEIGHT;
810      theRect->h = 0;
811      theRect->w = 0;
812    }
813    for ( ; p ; p=p->chain)
814    {
815      if (p->flags & SURF_UNDERWATER)
816        DrawGLWaterPolyLightmap (p);
817      else
818      {
819#ifdef USE_OPENGLES
820        glVertexPointer(3, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][0]);
821        glTexCoordPointer(2, GL_FLOAT, VERTEXSIZE*sizeof(float), &p->verts[0][5]);
822        glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
823#else
824        glBegin (GL_POLYGON);
825        v = p->verts[0];
826        for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE)
827        {
828          glTexCoord2f (v[5], v[6]);
829          glVertex3fv (v);
830        }
831        glEnd ();
832#endif
833      }
834    }
835  }
836
837  glDisable (GL_BLEND);
838  if (gl_lightmap_format == GL_LUMINANCE)
839    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
840  else if (gl_lightmap_format == GL_INTENSITY)
841  {
842    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
843    glColor4f (1,1,1,1);
844  }
845
846  glDepthMask (1);		// back to normal Z buffering
847}
848
849/*
850================
851R_RenderBrushPoly
852================
853*/
854void R_RenderBrushPoly (msurface_t *fa)
855{
856  texture_t	*t;
857  byte		*base;
858  int			maps;
859  glRect_t    *theRect;
860  int smax, tmax;
861
862  c_brush_polys++;
863
864  if (fa->flags & SURF_DRAWSKY)
865  {	// warp texture, no lightmaps
866    EmitBothSkyLayers (fa);
867    return;
868  }
869
870  t = R_TextureAnimation (fa->texinfo->texture);
871  GL_Bind (t->gl_texturenum);
872
873  if (fa->flags & SURF_DRAWTURB)
874  {	// warp texture, no lightmaps
875    EmitWaterPolys (fa);
876    return;
877  }
878
879  if (fa->flags & SURF_UNDERWATER)
880    DrawGLWaterPoly (fa->polys);
881  else
882    DrawGLPoly (fa->polys);
883
884  // add the poly to the proper lightmap chain
885
886  fa->polys->chain = lightmap_polys[fa->lightmaptexturenum];
887  lightmap_polys[fa->lightmaptexturenum] = fa->polys;
888
889  // check for lightmap modification
890  for (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ;
891     maps++)
892    if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps])
893      goto dynamic;
894
895  if (fa->dlightframe == r_framecount	// dynamic this frame
896    || fa->cached_dlight)			// dynamic previously
897  {
898dynamic:
899    if (r_dynamic.value)
900    {
901      lightmap_modified[fa->lightmaptexturenum] = true;
902      theRect = &lightmap_rectchange[fa->lightmaptexturenum];
903      if (fa->light_t < theRect->t) {
904        if (theRect->h)
905          theRect->h += theRect->t - fa->light_t;
906        theRect->t = fa->light_t;
907      }
908      if (fa->light_s < theRect->l) {
909        if (theRect->w)
910          theRect->w += theRect->l - fa->light_s;
911        theRect->l = fa->light_s;
912      }
913      smax = (fa->extents[0]>>4)+1;
914      tmax = (fa->extents[1]>>4)+1;
915      if ((theRect->w + theRect->l) < (fa->light_s + smax))
916        theRect->w = (fa->light_s-theRect->l)+smax;
917      if ((theRect->h + theRect->t) < (fa->light_t + tmax))
918        theRect->h = (fa->light_t-theRect->t)+tmax;
919      base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
920      base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
921      R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes);
922    }
923  }
924}
925
926/*
927================
928R_RenderDynamicLightmaps
929Multitexture
930================
931*/
932void R_RenderDynamicLightmaps (msurface_t *fa)
933{
934  texture_t	*t;
935  byte		*base;
936  int			maps;
937  glRect_t    *theRect;
938  int smax, tmax;
939
940  c_brush_polys++;
941
942  if (fa->flags & ( SURF_DRAWSKY | SURF_DRAWTURB) )
943    return;
944
945  fa->polys->chain = lightmap_polys[fa->lightmaptexturenum];
946  lightmap_polys[fa->lightmaptexturenum] = fa->polys;
947
948  // check for lightmap modification
949  for (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ;
950     maps++)
951    if (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps])
952      goto dynamic;
953
954  if (fa->dlightframe == r_framecount	// dynamic this frame
955    || fa->cached_dlight)			// dynamic previously
956  {
957dynamic:
958    if (r_dynamic.value)
959    {
960      lightmap_modified[fa->lightmaptexturenum] = true;
961      theRect = &lightmap_rectchange[fa->lightmaptexturenum];
962      if (fa->light_t < theRect->t) {
963        if (theRect->h)
964          theRect->h += theRect->t - fa->light_t;
965        theRect->t = fa->light_t;
966      }
967      if (fa->light_s < theRect->l) {
968        if (theRect->w)
969          theRect->w += theRect->l - fa->light_s;
970        theRect->l = fa->light_s;
971      }
972      smax = (fa->extents[0]>>4)+1;
973      tmax = (fa->extents[1]>>4)+1;
974      if ((theRect->w + theRect->l) < (fa->light_s + smax))
975        theRect->w = (fa->light_s-theRect->l)+smax;
976      if ((theRect->h + theRect->t) < (fa->light_t + tmax))
977        theRect->h = (fa->light_t-theRect->t)+tmax;
978      base = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
979      base += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;
980      R_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes);
981    }
982  }
983}
984
985/*
986================
987R_MirrorChain
988================
989*/
990void R_MirrorChain (msurface_t *s)
991{
992  if (mirror)
993    return;
994  mirror = true;
995  mirror_plane = s->plane;
996}
997
998
999#if 0
1000/*
1001================
1002R_DrawWaterSurfaces
1003================
1004*/
1005void R_DrawWaterSurfaces (void)
1006{
1007  int			i;
1008  msurface_t	*s;
1009  texture_t	*t;
1010
1011  if (r_wateralpha.value == 1.0)
1012    return;
1013
1014  //
1015  // go back to the world matrix
1016  //
1017    glLoadMatrixf (r_world_matrix);
1018
1019  glEnable (GL_BLEND);
1020  glColor4f (1,1,1,r_wateralpha.value);
1021  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1022
1023  for (i=0 ; i<cl.worldmodel->numtextures ; i++)
1024  {
1025    t = cl.worldmodel->textures[i];
1026    if (!t)
1027      continue;
1028    s = t->texturechain;
1029    if (!s)
1030      continue;
1031    if ( !(s->flags & SURF_DRAWTURB) )
1032      continue;
1033
1034    // set modulate mode explicitly
1035    GL_Bind (t->gl_texturenum);
1036
1037    for ( ; s ; s=s->texturechain)
1038      R_RenderBrushPoly (s);
1039
1040    t->texturechain = NULL;
1041  }
1042
1043  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1044
1045  glColor4f (1,1,1,1);
1046  glDisable (GL_BLEND);
1047}
1048#else
1049/*
1050================
1051R_DrawWaterSurfaces
1052================
1053*/
1054void R_DrawWaterSurfaces (void)
1055{
1056  int			i;
1057  msurface_t	*s;
1058  texture_t	*t;
1059
1060  if (r_wateralpha.value == 1.0 && gl_texsort.value)
1061    return;
1062
1063  //
1064  // go back to the world matrix
1065  //
1066
1067    glLoadMatrixf (r_world_matrix);
1068
1069  if (r_wateralpha.value < 1.0) {
1070    glEnable (GL_BLEND);
1071    glColor4f (1,1,1,r_wateralpha.value);
1072    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1073  }
1074
1075  if (!gl_texsort.value) {
1076    if (!waterchain)
1077      return;
1078
1079    for ( s = waterchain ; s ; s=s->texturechain) {
1080      GL_Bind (s->texinfo->texture->gl_texturenum);
1081      EmitWaterPolys (s);
1082    }
1083
1084    waterchain = NULL;
1085  } else {
1086
1087    for (i=0 ; i<cl.worldmodel->numtextures ; i++)
1088    {
1089      t = cl.worldmodel->textures[i];
1090      if (!t)
1091        continue;
1092      s = t->texturechain;
1093      if (!s)
1094        continue;
1095      if ( !(s->flags & SURF_DRAWTURB ) )
1096        continue;
1097
1098      // set modulate mode explicitly
1099
1100      GL_Bind (t->gl_texturenum);
1101
1102      for ( ; s ; s=s->texturechain)
1103        EmitWaterPolys (s);
1104
1105      t->texturechain = NULL;
1106    }
1107
1108  }
1109
1110  if (r_wateralpha.value < 1.0) {
1111    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1112
1113    glColor4f (1,1,1,1);
1114    glDisable (GL_BLEND);
1115  }
1116
1117}
1118
1119#endif
1120
1121/*
1122================
1123DrawTextureChains
1124================
1125*/
1126void DrawTextureChains (void)
1127{
1128  int		i;
1129  msurface_t	*s;
1130  texture_t	*t;
1131
1132  if (!gl_texsort.value) {
1133    GL_DisableMultitexture();
1134
1135    if (skychain) {
1136      R_DrawSkyChain(skychain);
1137      skychain = NULL;
1138    }
1139
1140    return;
1141  }
1142
1143  for (i=0 ; i<cl.worldmodel->numtextures ; i++)
1144  {
1145    t = cl.worldmodel->textures[i];
1146    if (!t)
1147      continue;
1148    s = t->texturechain;
1149    if (!s)
1150      continue;
1151    if (i == skytexturenum)
1152      R_DrawSkyChain (s);
1153    else if (i == mirrortexturenum && r_mirroralpha.value != 1.0)
1154    {
1155      R_MirrorChain (s);
1156      continue;
1157    }
1158    else
1159    {
1160      if ((s->flags & SURF_DRAWTURB) && r_wateralpha.value != 1.0)
1161        continue;	// draw translucent water later
1162      for ( ; s ; s=s->texturechain)
1163        R_RenderBrushPoly (s);
1164    }
1165
1166    t->texturechain = NULL;
1167  }
1168}
1169
1170/*
1171=================
1172R_DrawBrushModel
1173=================
1174*/
1175void R_DrawBrushModel (entity_t *e)
1176{
1177  int			j, k;
1178  vec3_t		mins, maxs;
1179  int			i, numsurfaces;
1180  msurface_t	*psurf;
1181  float		dot;
1182  mplane_t	*pplane;
1183  model_t		*clmodel;
1184  qboolean	rotated;
1185
1186  currententity = e;
1187  currenttexture = -1;
1188
1189  clmodel = e->model;
1190
1191  if (e->angles[0] || e->angles[1] || e->angles[2])
1192  {
1193    rotated = true;
1194    for (i=0 ; i<3 ; i++)
1195    {
1196      mins[i] = e->origin[i] - clmodel->radius;
1197      maxs[i] = e->origin[i] + clmodel->radius;
1198    }
1199  }
1200  else
1201  {
1202    rotated = false;
1203    VectorAdd (e->origin, clmodel->mins, mins);
1204    VectorAdd (e->origin, clmodel->maxs, maxs);
1205  }
1206
1207  if (R_CullBox (mins, maxs))
1208    return;
1209
1210  glColor3f (1,1,1);
1211  memset (lightmap_polys, 0, sizeof(lightmap_polys));
1212
1213  VectorSubtract (r_refdef.vieworg, e->origin, modelorg);
1214  if (rotated)
1215  {
1216    vec3_t	temp;
1217    vec3_t	forward, right, up;
1218
1219    VectorCopy (modelorg, temp);
1220    AngleVectors (e->angles, forward, right, up);
1221    modelorg[0] = DotProduct (temp, forward);
1222    modelorg[1] = -DotProduct (temp, right);
1223    modelorg[2] = DotProduct (temp, up);
1224  }
1225
1226  psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
1227
1228// calculate dynamic lighting for bmodel if it's not an
1229// instanced model
1230  if (clmodel->firstmodelsurface != 0 && !gl_flashblend.value)
1231  {
1232    for (k=0 ; k<MAX_DLIGHTS ; k++)
1233    {
1234      if ((cl_dlights[k].die < cl.time) ||
1235        (!cl_dlights[k].radius))
1236        continue;
1237
1238      R_MarkLights (&cl_dlights[k], 1<<k,
1239        clmodel->nodes + clmodel->hulls[0].firstclipnode);
1240    }
1241  }
1242
1243    glPushMatrix ();
1244e->angles[0] = -e->angles[0];	// stupid quake bug
1245  R_RotateForEntity (e);
1246e->angles[0] = -e->angles[0];	// stupid quake bug
1247
1248  //
1249  // draw texture
1250  //
1251  for (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++)
1252  {
1253  // find which side of the node we are on
1254    pplane = psurf->plane;
1255
1256    dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
1257
1258  // draw the polygon
1259    if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
1260      (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
1261    {
1262      if (gl_texsort.value)
1263        R_RenderBrushPoly (psurf);
1264      else
1265        R_DrawSequentialPoly (psurf);
1266    }
1267  }
1268
1269  R_BlendLightmaps ();
1270
1271  glPopMatrix ();
1272}
1273
1274/*
1275=============================================================
1276
1277  WORLD MODEL
1278
1279=============================================================
1280*/
1281
1282/*
1283================
1284R_RecursiveWorldNode
1285================
1286*/
1287void R_RecursiveWorldNode (mnode_t *node)
1288{
1289  int			i, c, side, *pindex;
1290  vec3_t		acceptpt, rejectpt;
1291  mplane_t	*plane;
1292  msurface_t	*surf, **mark;
1293  mleaf_t		*pleaf;
1294  double		d, dot;
1295  vec3_t		mins, maxs;
1296
1297  if (node->contents == CONTENTS_SOLID)
1298    return;		// solid
1299
1300  if (node->visframe != r_visframecount)
1301    return;
1302  if (R_CullBox (node->minmaxs, node->minmaxs+3))
1303    return;
1304
1305// if a leaf node, draw stuff
1306  if (node->contents < 0)
1307  {
1308    pleaf = (mleaf_t *)node;
1309
1310    mark = pleaf->firstmarksurface;
1311    c = pleaf->nummarksurfaces;
1312
1313    if (c)
1314    {
1315      do
1316      {
1317        (*mark)->visframe = r_framecount;
1318        mark++;
1319      } while (--c);
1320    }
1321
1322  // deal with model fragments in this leaf
1323    if (pleaf->efrags)
1324      R_StoreEfrags (&pleaf->efrags);
1325
1326    return;
1327  }
1328
1329// node is just a decision point, so go down the apropriate sides
1330
1331// find which side of the node we are on
1332  plane = node->plane;
1333
1334  switch (plane->type)
1335  {
1336  case PLANE_X:
1337    dot = modelorg[0] - plane->dist;
1338    break;
1339  case PLANE_Y:
1340    dot = modelorg[1] - plane->dist;
1341    break;
1342  case PLANE_Z:
1343    dot = modelorg[2] - plane->dist;
1344    break;
1345  default:
1346    dot = DotProduct (modelorg, plane->normal) - plane->dist;
1347    break;
1348  }
1349
1350  if (dot >= 0)
1351    side = 0;
1352  else
1353    side = 1;
1354
1355// recurse down the children, front side first
1356  R_RecursiveWorldNode (node->children[side]);
1357
1358// draw stuff
1359  c = node->numsurfaces;
1360
1361  if (c)
1362  {
1363    surf = cl.worldmodel->surfaces + node->firstsurface;
1364
1365    if (dot < 0 -BACKFACE_EPSILON)
1366      side = SURF_PLANEBACK;
1367    else if (dot > BACKFACE_EPSILON)
1368      side = 0;
1369    {
1370      for ( ; c ; c--, surf++)
1371      {
1372        if (surf->visframe != r_framecount)
1373          continue;
1374
1375        // don't backface underwater surfaces, because they warp
1376        if ( !(surf->flags & SURF_UNDERWATER) && ( (dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) )
1377          continue;		// wrong side
1378
1379        // if sorting by texture, just store it out
1380        if (gl_texsort.value)
1381        {
1382          if (!mirror
1383          || surf->texinfo->texture != cl.worldmodel->textures[mirrortexturenum])
1384          {
1385            surf->texturechain = surf->texinfo->texture->texturechain;
1386            surf->texinfo->texture->texturechain = surf;
1387          }
1388        } else if (surf->flags & SURF_DRAWSKY) {
1389          surf->texturechain = skychain;
1390          skychain = surf;
1391        } else if (surf->flags & SURF_DRAWTURB) {
1392          surf->texturechain = waterchain;
1393          waterchain = surf;
1394        } else
1395          R_DrawSequentialPoly (surf);
1396
1397      }
1398    }
1399
1400  }
1401
1402// recurse down the back side
1403  R_RecursiveWorldNode (node->children[!side]);
1404}
1405
1406
1407
1408/*
1409=============
1410R_DrawWorld
1411=============
1412*/
1413void R_DrawWorld (void)
1414{
1415  entity_t	ent;
1416  int			i;
1417
1418  memset (&ent, 0, sizeof(ent));
1419  ent.model = cl.worldmodel;
1420
1421  VectorCopy (r_refdef.vieworg, modelorg);
1422
1423  currententity = &ent;
1424  currenttexture = -1;
1425
1426  glColor3f (1,1,1);
1427  memset (lightmap_polys, 0, sizeof(lightmap_polys));
1428#ifdef QUAKE2
1429  R_ClearSkyBox ();
1430#endif
1431
1432  R_RecursiveWorldNode (cl.worldmodel->nodes);
1433
1434  DrawTextureChains ();
1435
1436  R_BlendLightmaps ();
1437
1438#ifdef QUAKE2
1439  R_DrawSkyBox ();
1440#endif
1441}
1442
1443
1444/*
1445===============
1446R_MarkLeaves
1447===============
1448*/
1449void R_MarkLeaves (void)
1450{
1451  byte	*vis;
1452  mnode_t	*node;
1453  int		i;
1454  byte	solid[4096];
1455
1456  if (r_oldviewleaf == r_viewleaf && !r_novis.value)
1457    return;
1458
1459  if (mirror)
1460    return;
1461
1462  r_visframecount++;
1463  r_oldviewleaf = r_viewleaf;
1464
1465  if (r_novis.value)
1466  {
1467    vis = solid;
1468    memset (solid, 0xff, (cl.worldmodel->numleafs+7)>>3);
1469  }
1470  else
1471    vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
1472
1473  for (i=0 ; i<cl.worldmodel->numleafs ; i++)
1474  {
1475    if (vis[i>>3] & (1<<(i&7)))
1476    {
1477      node = (mnode_t *)&cl.worldmodel->leafs[i+1];
1478      do
1479      {
1480        if (node->visframe == r_visframecount)
1481          break;
1482        node->visframe = r_visframecount;
1483        node = node->parent;
1484      } while (node);
1485    }
1486  }
1487}
1488
1489
1490
1491/*
1492=============================================================================
1493
1494  LIGHTMAP ALLOCATION
1495
1496=============================================================================
1497*/
1498
1499// returns a texture number and the position inside it
1500int AllocBlock (int w, int h, int *x, int *y)
1501{
1502  int		i, j;
1503  int		best, best2;
1504  int		bestx;
1505  int		texnum;
1506
1507  for (texnum=0 ; texnum<MAX_LIGHTMAPS ; texnum++)
1508  {
1509    best = BLOCK_HEIGHT;
1510
1511    for (i=0 ; i<BLOCK_WIDTH-w ; i++)
1512    {
1513      best2 = 0;
1514
1515      for (j=0 ; j<w ; j++)
1516      {
1517        if (allocated[texnum][i+j] >= best)
1518          break;
1519        if (allocated[texnum][i+j] > best2)
1520          best2 = allocated[texnum][i+j];
1521      }
1522      if (j == w)
1523      {	// this is a valid spot
1524        *x = i;
1525        *y = best = best2;
1526      }
1527    }
1528
1529    if (best + h > BLOCK_HEIGHT)
1530      continue;
1531
1532    for (i=0 ; i<w ; i++)
1533      allocated[texnum][*x + i] = best + h;
1534
1535    return texnum;
1536  }
1537
1538  Sys_Error ("AllocBlock: full");
1539  return 0;
1540}
1541
1542
1543mvertex_t	*r_pcurrentvertbase;
1544model_t		*currentmodel;
1545
1546int	nColinElim;
1547
1548/*
1549================
1550BuildSurfaceDisplayList
1551================
1552*/
1553void BuildSurfaceDisplayList (msurface_t *fa)
1554{
1555  int			i, lindex, lnumverts, s_axis, t_axis;
1556  float		dist, lastdist, lzi, scale, u, v, frac;
1557  unsigned	mask;
1558  vec3_t		local, transformed;
1559  medge_t		*pedges, *r_pedge;
1560  mplane_t	*pplane;
1561  int			vertpage, newverts, newpage, lastvert;
1562  qboolean	visible;
1563  float		*vec;
1564  float		s, t;
1565  glpoly_t	*poly;
1566
1567// reconstruct the polygon
1568  pedges = currentmodel->edges;
1569  lnumverts = fa->numedges;
1570  vertpage = 0;
1571
1572  //
1573  // draw texture
1574  //
1575  poly = (glpoly_t*) Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float));
1576  poly->next = fa->polys;
1577  poly->flags = fa->flags;
1578  fa->polys = poly;
1579  poly->numverts = lnumverts;
1580
1581  for (i=0 ; i<lnumverts ; i++)
1582  {
1583    lindex = currentmodel->surfedges[fa->firstedge + i];
1584
1585    if (lindex > 0)
1586    {
1587      r_pedge = &pedges[lindex];
1588      vec = r_pcurrentvertbase[r_pedge->v[0]].position;
1589    }
1590    else
1591    {
1592      r_pedge = &pedges[-lindex];
1593      vec = r_pcurrentvertbase[r_pedge->v[1]].position;
1594    }
1595    s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
1596    s /= fa->texinfo->texture->width;
1597
1598    t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
1599    t /= fa->texinfo->texture->height;
1600
1601    VectorCopy (vec, poly->verts[i]);
1602    poly->verts[i][3] = s;
1603    poly->verts[i][4] = t;
1604
1605    //
1606    // lightmap texture coordinates
1607    //
1608    s = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];
1609    s -= fa->texturemins[0];
1610    s += fa->light_s*16;
1611    s += 8;
1612    s /= BLOCK_WIDTH*16; //fa->texinfo->texture->width;
1613
1614    t = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];
1615    t -= fa->texturemins[1];
1616    t += fa->light_t*16;
1617    t += 8;
1618    t /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height;
1619
1620    poly->verts[i][5] = s;
1621    poly->verts[i][6] = t;
1622  }
1623
1624  //
1625  // remove co-linear points - Ed
1626  //
1627  if (!gl_keeptjunctions.value && !(fa->flags & SURF_UNDERWATER) )
1628  {
1629    for (i = 0 ; i < lnumverts ; ++i)
1630    {
1631      vec3_t v1, v2;
1632      float *prev, *thiz, *next;
1633      float f;
1634
1635      prev = poly->verts[(i + lnumverts - 1) % lnumverts];
1636      thiz = poly->verts[i];
1637      next = poly->verts[(i + 1) % lnumverts];
1638
1639      VectorSubtract( thiz, prev, v1 );
1640      VectorNormalize( v1 );
1641      VectorSubtract( next, prev, v2 );
1642      VectorNormalize( v2 );
1643
1644      // skip co-linear points
1645      #define COLINEAR_EPSILON 0.001
1646      if ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) &&
1647        (fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) &&
1648        (fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON))
1649      {
1650        int j;
1651        for (j = i + 1; j < lnumverts; ++j)
1652        {
1653          int k;
1654          for (k = 0; k < VERTEXSIZE; ++k)
1655            poly->verts[j - 1][k] = poly->verts[j][k];
1656        }
1657        --lnumverts;
1658        ++nColinElim;
1659        // retry next vertex next time, which is now current vertex
1660        --i;
1661      }
1662    }
1663  }
1664  poly->numverts = lnumverts;
1665
1666}
1667
1668/*
1669========================
1670GL_CreateSurfaceLightmap
1671========================
1672*/
1673void GL_CreateSurfaceLightmap (msurface_t *surf)
1674{
1675  int		smax, tmax, s, t, l, i;
1676  byte	*base;
1677
1678  if (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))
1679    return;
1680
1681  smax = (surf->extents[0]>>4)+1;
1682  tmax = (surf->extents[1]>>4)+1;
1683
1684  surf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);
1685  base = lightmaps + surf->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;
1686  base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;
1687  R_BuildLightMap (surf, base, BLOCK_WIDTH*lightmap_bytes);
1688}
1689
1690
1691
1692void GL_UploadLightmaps()
1693{
1694   if (!gl_texsort.value)
1695     GL_SelectTexture(TEXTURE1_SGIS);
1696
1697  //
1698  // upload all lightmaps that were filled
1699  //
1700  for (int i=0 ; i<MAX_LIGHTMAPS ; i++)
1701  {
1702    if (!allocated[i][0])
1703      break;		// no more used
1704    lightmap_modified[i] = false;
1705    lightmap_rectchange[i].l = BLOCK_WIDTH;
1706    lightmap_rectchange[i].t = BLOCK_HEIGHT;
1707    lightmap_rectchange[i].w = 0;
1708    lightmap_rectchange[i].h = 0;
1709    GL_Bind(lightmap_textures + i);
1710    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1711    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1712    glTexImage2DHelper (GL_TEXTURE_2D, 0, lightmap_bytes
1713    , BLOCK_WIDTH, BLOCK_HEIGHT, 0,
1714    gl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes);
1715  }
1716
1717   if (!gl_texsort.value)
1718     GL_SelectTexture(TEXTURE0_SGIS);
1719
1720}
1721
1722/*
1723==================
1724GL_BuildLightmaps
1725
1726Builds the lightmap texture
1727with all the surfaces from all brush models
1728==================
1729*/
1730void GL_BuildLightmaps (void)
1731{
1732  int		i, j;
1733  model_t	*m;
1734  extern qboolean isPermedia;
1735
1736  memset (allocated, 0, sizeof(allocated));
1737
1738  r_framecount = 1;		// no dlightcache
1739
1740  if (!lightmap_textures)
1741  {
1742    lightmap_textures = texture_extension_number;
1743    texture_extension_number += MAX_LIGHTMAPS;
1744  }
1745
1746  gl_lightmap_format = GL_LUMINANCE;
1747  // default differently on the Permedia
1748  if (isPermedia)
1749    gl_lightmap_format = GL_RGBA;
1750
1751  if (COM_CheckParm ("-lm_1"))
1752    gl_lightmap_format = GL_LUMINANCE;
1753  if (COM_CheckParm ("-lm_a"))
1754    gl_lightmap_format = GL_ALPHA;
1755  if (COM_CheckParm ("-lm_i"))
1756    gl_lightmap_format = GL_INTENSITY;
1757  if (COM_CheckParm ("-lm_2"))
1758    gl_lightmap_format = GL_RGBA4;
1759  if (COM_CheckParm ("-lm_4"))
1760    gl_lightmap_format = GL_RGBA;
1761
1762  switch (gl_lightmap_format)
1763  {
1764  case GL_RGBA:
1765    lightmap_bytes = 4;
1766    break;
1767  case GL_RGBA4:
1768    lightmap_bytes = 2;
1769    break;
1770  case GL_LUMINANCE:
1771  case GL_INTENSITY:
1772  case GL_ALPHA:
1773    lightmap_bytes = 1;
1774    break;
1775  }
1776
1777  for (j=1 ; j<MAX_MODELS ; j++)
1778  {
1779    m = cl.model_precache[j];
1780    if (!m)
1781      break;
1782    if (m->name[0] == '*')
1783      continue;
1784    r_pcurrentvertbase = m->vertexes;
1785    currentmodel = m;
1786    for (i=0 ; i<m->numsurfaces ; i++)
1787    {
1788      GL_CreateSurfaceLightmap (m->surfaces + i);
1789      if ( m->surfaces[i].flags & SURF_DRAWTURB )
1790        continue;
1791#ifndef QUAKE2
1792      if ( m->surfaces[i].flags & SURF_DRAWSKY )
1793        continue;
1794#endif
1795      BuildSurfaceDisplayList (m->surfaces + i);
1796    }
1797  }
1798
1799  GL_UploadLightmaps();
1800}
1801
1802
1803