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