1 //----------------------------------------------------------------------------
2 // EDGE OpenGL Rendering (Skies)
3 //----------------------------------------------------------------------------
4 //
5 // Copyright (c) 1999-2009 The EDGE Team.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 //----------------------------------------------------------------------------
18
19 #include "i_defs.h"
20 #include "i_defs_gl.h"
21
22 #include <math.h>
23
24 #include "epi/image_data.h"
25
26 #include "dm_state.h"
27 #include "m_math.h"
28 #include "r_misc.h"
29 #include "w_flat.h"
30 #include "r_sky.h"
31 #include "r_gldefs.h"
32 #include "r_sky.h"
33 #include "r_units.h"
34 #include "r_colormap.h"
35 #include "r_modes.h"
36 #include "r_image.h"
37 #include "r_texgl.h"
38 #include "w_wad.h"
39 #include "z_zone.h"
40
41 #define DEBUG 0
42
43
44 const image_c *sky_image;
45
46 bool custom_sky_box;
47
48 // needed for SKY
49 extern epi::image_data_c *ReadAsEpiBlock(image_c *rim);
50
51
52 typedef struct sec_sky_ring_s
53 {
54 // which group of connected skies (0 if none)
55 int group;
56
57 // link of sector in RING
58 struct sec_sky_ring_s *next;
59 struct sec_sky_ring_s *prev;
60
61 // maximal sky height of group
62 float max_h;
63 }
64 sec_sky_ring_t;
65
66 //
67 // R_ComputeSkyHeights
68 //
69 // This routine computes the sky height field in sector_t, which is
70 // the maximal sky height over all sky sectors (ceiling only) which
71 // are joined by 2S linedefs.
72 //
73 // Algorithm: Initially all sky sectors are in individual groups. Now
74 // we scan the linedef list. For each 2-sectored line with sky on
75 // both sides, merge the two groups into one. Simple :). We can
76 // compute the maximal height of the group as we go.
77 //
R_ComputeSkyHeights(void)78 void R_ComputeSkyHeights(void)
79 {
80 int i;
81 line_t *ld;
82 sector_t *sec;
83
84 // --- initialise ---
85
86 sec_sky_ring_t *rings = new sec_sky_ring_t[numsectors];
87
88 memset(rings, 0, numsectors * sizeof(sec_sky_ring_t));
89
90 for (i=0, sec=sectors; i < numsectors; i++, sec++)
91 {
92 if (! IS_SKY(sec->ceil))
93 continue;
94
95 rings[i].group = (i + 1);
96 rings[i].next = rings[i].prev = rings + i;
97 rings[i].max_h = sec->c_h;
98
99 // leave some room for tall sprites
100 static const float SPR_H_MAX = 256.0f;
101
102 if (sec->c_h < 30000.0f && (sec->c_h > sec->f_h) &&
103 (sec->c_h < sec->f_h + SPR_H_MAX))
104 {
105 rings[i].max_h = sec->f_h + SPR_H_MAX;
106 }
107 }
108
109 // --- make the pass over linedefs ---
110
111 for (i=0, ld=lines; i < numlines; i++, ld++)
112 {
113 sector_t *sec1, *sec2;
114 sec_sky_ring_t *ring1, *ring2, *tmp_R;
115
116 if (! ld->side[0] || ! ld->side[1])
117 continue;
118
119 sec1 = ld->frontsector;
120 sec2 = ld->backsector;
121
122 SYS_ASSERT(sec1 && sec2);
123
124 if (sec1 == sec2)
125 continue;
126
127 ring1 = rings + (sec1 - sectors);
128 ring2 = rings + (sec2 - sectors);
129
130 // we require sky on both sides
131 if (ring1->group == 0 || ring2->group == 0)
132 continue;
133
134 // already in the same group ?
135 if (ring1->group == ring2->group)
136 continue;
137
138 // swap sectors to ensure the lower group is added to the higher
139 // group, since we don't need to update the `max_h' fields of the
140 // highest group.
141
142 if (ring1->max_h < ring2->max_h)
143 {
144 tmp_R = ring1; ring1 = ring2; ring2 = tmp_R;
145 }
146
147 // update the group numbers in the second group
148
149 ring2->group = ring1->group;
150 ring2->max_h = ring1->max_h;
151
152 for (tmp_R=ring2->next; tmp_R != ring2; tmp_R=tmp_R->next)
153 {
154 tmp_R->group = ring1->group;
155 tmp_R->max_h = ring1->max_h;
156 }
157
158 // merge 'em baby...
159
160 ring1->next->prev = ring2;
161 ring2->next->prev = ring1;
162
163 tmp_R = ring1->next;
164 ring1->next = ring2->next;
165 ring2->next = tmp_R;
166 }
167
168 // --- now store the results, and free up ---
169
170 for (i=0, sec=sectors; i < numsectors; i++, sec++)
171 {
172 if (rings[i].group > 0)
173 sec->sky_h = rings[i].max_h;
174
175 #if 0 // DEBUG CODE
176 L_WriteDebug("SKY: sec %d group %d max_h %1.1f\n", i,
177 rings[i].group, rings[i].max_h);
178 #endif
179 }
180
181 delete[] rings;
182 }
183
184 //----------------------------------------------------------------------------
185
186
187 static bool need_to_draw_sky = false;
188
189
190 typedef struct
191 {
192 const image_c *base_sky;
193
194 const colourmap_c *fx_colmap;
195
196 int face_size;
197
198 GLuint tex[6];
199
200 // face images are only present for custom skyboxes.
201 // pseudo skyboxes are generated outside of the image system.
202 const image_c *face[6];
203 }
204 fake_skybox_t;
205
206 static fake_skybox_t fake_box[2] =
207 {
208 {
209 NULL, NULL, 1,
210 { 0,0,0,0,0,0 },
211 { NULL, NULL, NULL, NULL, NULL, NULL }
212 },
213 {
214 NULL, NULL, 1,
215 { 0,0,0,0,0,0 },
216 { NULL, NULL, NULL, NULL, NULL, NULL }
217 }
218 };
219
220
DeleteSkyTexGroup(int SK)221 static void DeleteSkyTexGroup(int SK)
222 {
223 for (int i = 0; i < 6; i++)
224 {
225 if (fake_box[SK].tex[i] != 0)
226 {
227 glDeleteTextures(1, &fake_box[SK].tex[i]);
228 fake_box[SK].tex[i] = 0;
229 }
230 }
231 }
232
DeleteSkyTextures(void)233 void DeleteSkyTextures(void)
234 {
235 for (int SK = 0; SK < 2; SK++)
236 {
237 fake_box[SK].base_sky = NULL;
238 fake_box[SK].fx_colmap = NULL;
239
240 DeleteSkyTexGroup(SK);
241 }
242 }
243
244
RGL_SetupSkyMatrices(float dist)245 static void RGL_SetupSkyMatrices(float dist)
246 {
247 glMatrixMode(GL_PROJECTION);
248 glPushMatrix();
249
250 glLoadIdentity();
251 glFrustum(-view_x_slope * r_nearclip.f, view_x_slope * r_nearclip.f,
252 -view_y_slope * r_nearclip.f, view_y_slope * r_nearclip.f,
253 r_nearclip.f, r_farclip.f);
254
255 glMatrixMode(GL_MODELVIEW);
256 glPushMatrix();
257
258 glLoadIdentity();
259
260 glRotatef(270.0f - ANG_2_FLOAT(viewvertangle), 1.0f, 0.0f, 0.0f);
261 glRotatef(90.0f - ANG_2_FLOAT(viewangle), 0.0f, 0.0f, 1.0f);
262 }
263
264
RGL_SetupSkyMatrices2D(void)265 static void RGL_SetupSkyMatrices2D(void)
266 {
267 glMatrixMode(GL_PROJECTION);
268 glPushMatrix();
269
270 glLoadIdentity();
271 glOrtho(0.0f, (float)SCREENWIDTH,
272 0.0f, (float)SCREENHEIGHT, -1.0f, 1.0f);
273
274 glMatrixMode(GL_MODELVIEW);
275 glPushMatrix();
276
277 glLoadIdentity();
278 }
279
280
RGL_RevertSkyMatrices(void)281 void RGL_RevertSkyMatrices(void)
282 {
283 glMatrixMode(GL_PROJECTION);
284 glPopMatrix();
285
286 glMatrixMode(GL_MODELVIEW);
287 glPopMatrix();
288 }
289
290
RGL_BeginSky(void)291 void RGL_BeginSky(void)
292 {
293 need_to_draw_sky = false;
294
295 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
296 glDisable(GL_TEXTURE_2D);
297
298 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
299 glEdgeFlag(GL_TRUE);
300 }
301
302
RGL_FinishSky(void)303 void RGL_FinishSky(void)
304 {
305 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
306
307 if (! need_to_draw_sky)
308 return;
309
310 // draw sky picture, but DON'T affect the depth buffering
311
312 glEnable(GL_TEXTURE_2D);
313
314 glDepthMask(GL_FALSE);
315
316 if (level_flags.mlook || custom_sky_box)
317 {
318 if (! r_dumbsky.d)
319 glDepthFunc(GL_GREATER);
320
321 RGL_DrawSkyBox();
322 }
323 else
324 {
325 RGL_DrawSkyOriginal();
326 }
327
328 glDepthFunc(GL_LEQUAL);
329 glDepthMask(GL_TRUE);
330
331 glDisable(GL_TEXTURE_2D);
332
333 #if 0
334 // clear buffer (EXPERIMENTAL) -- causes render problems: ceilings
335 // you shouldn't be able to see (MAP05, MAP12).
336 glClear(GL_DEPTH_BUFFER_BIT);
337 #endif
338 }
339
340
RGL_DrawSkyBox(void)341 void RGL_DrawSkyBox(void)
342 {
343 float dist = r_farclip.f / 2.0f;
344
345 int SK = RGL_UpdateSkyBoxTextures();
346
347 RGL_SetupSkyMatrices(dist);
348
349 float v0 = 0.0f;
350 float v1 = 1.0f;
351
352 if (r_dumbclamp.d)
353 {
354 float size = fake_box[SK].face_size;
355
356 v0 = 0.5f / size;
357 v1 = 1.0f - v0;
358 }
359
360 glEnable(GL_TEXTURE_2D);
361
362 float col[4];
363
364 col[0] = LT_RED(255);
365 col[1] = LT_GRN(255);
366 col[2] = LT_BLU(255);
367 col[3] = 1.0f;
368
369 if (r_colormaterial.d || ! r_colorlighting.d)
370 glColor4fv(col);
371 else
372 {
373 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, col);
374 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col);
375 }
376
377 // top
378 glBindTexture(GL_TEXTURE_2D, fake_box[SK].tex[WSKY_Top]);
379 glNormal3i(0, 0, -1);
380
381 glBegin(GL_QUADS);
382 glTexCoord2f(v0, v0); glVertex3f(-dist, dist, +dist);
383 glTexCoord2f(v0, v1); glVertex3f(-dist, -dist, +dist);
384 glTexCoord2f(v1, v1); glVertex3f( dist, -dist, +dist);
385 glTexCoord2f(v1, v0); glVertex3f( dist, dist, +dist);
386 glEnd();
387
388 // bottom
389 glBindTexture(GL_TEXTURE_2D, fake_box[SK].tex[WSKY_Bottom]);
390 glNormal3i(0, 0, +1);
391
392 glBegin(GL_QUADS);
393 glTexCoord2f(v0, v0); glVertex3f(-dist, -dist, -dist);
394 glTexCoord2f(v0, v1); glVertex3f(-dist, dist, -dist);
395 glTexCoord2f(v1, v1); glVertex3f( dist, dist, -dist);
396 glTexCoord2f(v1, v0); glVertex3f( dist, -dist, -dist);
397 glEnd();
398
399 // north
400 glBindTexture(GL_TEXTURE_2D, fake_box[SK].tex[WSKY_North]);
401 glNormal3i(0, -1, 0);
402
403 glBegin(GL_QUADS);
404 glTexCoord2f(v0, v0); glVertex3f(-dist, dist, -dist);
405 glTexCoord2f(v0, v1); glVertex3f(-dist, dist, +dist);
406 glTexCoord2f(v1, v1); glVertex3f( dist, dist, +dist);
407 glTexCoord2f(v1, v0); glVertex3f( dist, dist, -dist);
408 glEnd();
409
410 // east
411 glBindTexture(GL_TEXTURE_2D, fake_box[SK].tex[WSKY_East]);
412 glNormal3i(-1, 0, 0);
413
414 glBegin(GL_QUADS);
415 glTexCoord2f(v0, v0); glVertex3f( dist, dist, -dist);
416 glTexCoord2f(v0, v1); glVertex3f( dist, dist, +dist);
417 glTexCoord2f(v1, v1); glVertex3f( dist, -dist, +dist);
418 glTexCoord2f(v1, v0); glVertex3f( dist, -dist, -dist);
419 glEnd();
420
421 // south
422 glBindTexture(GL_TEXTURE_2D, fake_box[SK].tex[WSKY_South]);
423 glNormal3i(0, +1, 0);
424
425 glBegin(GL_QUADS);
426 glTexCoord2f(v0, v0); glVertex3f( dist, -dist, -dist);
427 glTexCoord2f(v0, v1); glVertex3f( dist, -dist, +dist);
428 glTexCoord2f(v1, v1); glVertex3f(-dist, -dist, +dist);
429 glTexCoord2f(v1, v0); glVertex3f(-dist, -dist, -dist);
430 glEnd();
431
432 // west
433 glBindTexture(GL_TEXTURE_2D, fake_box[SK].tex[WSKY_West]);
434 glNormal3i(+1, 0, 0);
435
436 glBegin(GL_QUADS);
437 glTexCoord2f(v0, v0); glVertex3f(-dist, -dist, -dist);
438 glTexCoord2f(v0, v1); glVertex3f(-dist, -dist, +dist);
439 glTexCoord2f(v1, v1); glVertex3f(-dist, dist, +dist);
440 glTexCoord2f(v1, v0); glVertex3f(-dist, dist, -dist);
441 glEnd();
442
443 glDisable(GL_TEXTURE_2D);
444
445 RGL_RevertSkyMatrices();
446 }
447
448
RGL_DrawSkyOriginal(void)449 void RGL_DrawSkyOriginal(void)
450 {
451 RGL_SetupSkyMatrices2D();
452
453 float white[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
454
455 if (r_colormaterial.d || ! r_colorlighting.d)
456 glColor4fv(white);
457 else
458 {
459 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, white);
460 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, white);
461 }
462
463 GLuint tex_id = W_ImageCache(sky_image, false, ren_fx_colmap);
464
465 glEnable(GL_TEXTURE_2D);
466 glBindTexture(GL_TEXTURE_2D, tex_id);
467
468 // divide screen into 32 vertical strips, since mapping is non-linear
469 glBegin(GL_QUAD_STRIP);
470
471 // FIXME for widescreen
472 float FIELDOFVIEW = CLAMP(5, r_fov.f, 175);
473
474 float focal_len = tan(FIELDOFVIEW * M_PI / 360.0);
475 float centerxfrac = SCREENWIDTH / 2.0f;
476
477 float ty1 = 200.0f / 128.0f;
478 float ty2 = 0;
479
480 for (int i = 0; i <= 32; i++)
481 {
482 int sx = i * SCREENWIDTH / 32;
483
484 // use formula from original Doom code
485 angle_t ang = ANG180 + M_ATan((1.0f - sx / centerxfrac) * focal_len);
486
487 // some mucking about here to prevent wrap-around
488 float tx = (((viewangle >> 2) + (ang >> 2) + (ANG180 >> 2)) >> 20);
489
490 if ((IM_WIDTH(sky_image) / IM_HEIGHT(sky_image)) < 2.28f)
491 tx = tx / 256.0f;
492 else
493 tx = tx / 1024.0f;
494
495 #if 0 // DEBUGGING
496 I_Printf("[%i] --> %1.2f tx %1.4f\n", i, ANG_2_FLOAT(ang), tx);
497 #endif
498 glTexCoord2f(tx, 1.0f - ty1);
499 glVertex2i(sx, 0);
500
501 glTexCoord2f(tx, 1.0f - ty2);
502 glVertex2i(sx, SCREENHEIGHT);
503 }
504
505 glEnd();
506
507 glDisable(GL_TEXTURE_2D);
508
509 RGL_RevertSkyMatrices();
510 }
511
512
RGL_DrawSkyPlane(subsector_t * sub,float h)513 void RGL_DrawSkyPlane(subsector_t *sub, float h)
514 {
515 need_to_draw_sky = true;
516
517 if (r_dumbsky.d)
518 return;
519
520 MIR_Height(h);
521
522 glNormal3f(0, 0, (viewz > h) ? 1.0f : -1.0f);
523
524 glBegin(GL_POLYGON);
525
526 for (seg_t *seg=sub->segs; seg; seg=seg->sub_next)
527 {
528 float x = seg->v1->x;
529 float y = seg->v1->y;
530
531 MIR_Coordinate(x, y);
532
533 glVertex3f(x, y, h);
534 }
535
536 glEnd();
537 }
538
539
RGL_DrawSkyWall(seg_t * seg,float h1,float h2)540 void RGL_DrawSkyWall(seg_t *seg, float h1, float h2)
541 {
542 need_to_draw_sky = true;
543
544 if (r_dumbsky.d)
545 return;
546
547 float x1 = seg->v1->x;
548 float y1 = seg->v1->y;
549 float x2 = seg->v2->x;
550 float y2 = seg->v2->y;
551
552 MIR_Coordinate(x1, y1);
553 MIR_Coordinate(x2, y2);
554
555 MIR_Height(h1);
556 MIR_Height(h2);
557
558 glNormal3f(y2 - y1, x1 - x2, 0);
559
560 glBegin(GL_QUADS);
561
562 glVertex3f(x1, y1, h1);
563 glVertex3f(x1, y1, h2);
564 glVertex3f(x2, y2, h2);
565 glVertex3f(x2, y2, h1);
566
567 glEnd();
568 }
569
570
571 //----------------------------------------------------------------------------
572
573
574 #define PIXEL_RED(pix) (what_palette[pix*3 + 0])
575 #define PIXEL_GRN(pix) (what_palette[pix*3 + 1])
576 #define PIXEL_BLU(pix) (what_palette[pix*3 + 2])
577
578
SkyIsNarrow(const image_c * sky)579 static bool SkyIsNarrow(const image_c *sky)
580 {
581 // check the aspect of the image
582 return (IM_WIDTH(sky) / IM_HEIGHT(sky)) < 2.28f;
583 }
584
585
CalcSkyCoord(int px,int py,int pw,int ph,int face,bool narrow,float * tx,float * ty)586 static void CalcSkyCoord(int px, int py, int pw, int ph, int face,
587 bool narrow, float *tx, float *ty)
588 {
589 // the 0.5 here ensures we never hit exactly zero
590 float ax = ((float)px + 0.5f) / (float)pw * 2.0f - 1.0f;
591 float ay = ((float)py + 0.5f) / (float)ph * 2.0f - 1.0f;
592
593 float sx, sy, sz;
594
595 switch (face)
596 {
597 case WSKY_North:
598 sx = ax; sy = 1.0f; sz = ay; break;
599
600 case WSKY_South:
601 sx = -ax; sy = -1.0f; sz = ay; break;
602
603 case WSKY_East:
604 sx = 1.0f; sy = -ax; sz = ay; break;
605
606 case WSKY_West:
607 sx = -1.0f; sy = ax; sz = ay; break;
608
609 case WSKY_Top:
610 sx = ax; sy = -ay; sz = 1.0f; break;
611
612 case WSKY_Bottom:
613 sx = ax; sy = ay; sz = -1.0f; break;
614
615 default:
616 I_Error("CalcSkyCoord: INTERNAL ERROR (lost face)\n");
617 sx = sy = sz = 0;
618 break; /* NOT REACHED */
619 }
620
621 float len2 = sqrt((sx) * (sx) + (sy) * (sy));
622
623 angle_t H = ANG0 + R_PointToAngle(0, 0, sx, sy);
624 angle_t V = ANG90 - R_PointToAngle(0, 0, len2, sz);
625
626 if (narrow)
627 *tx = (float)(H >> 1) / (float)(1 << 30);
628 else
629 *tx = (float)(H >> 2) / (float)(1 << 30);
630
631 // want yy to range from 0.0 (top) to 2.0 (bottom)
632 float yy = (float)(V) / (float)ANG90;
633
634 // this lowers the effective centre of the pseudo skybox to
635 // match the DOOM sky, which is 128 pixels on a 200 pixel high
636 // screen (so it dips 28 pixels below the horizon).
637 yy = yy / 1.15f;
638
639 // mirror it (vertically)
640 if (yy > 1.0f) yy = 2.0f - yy;
641
642 *ty = 1.0f - pow(yy, 2.2);
643 }
644
645
BlurCentre(epi::image_data_c & img)646 static void BlurCentre(epi::image_data_c& img)
647 {
648 // Blurs the center of the image (the top face of the
649 // pseudo sky box). The amount of blur is different at
650 // different places: from none at all at the edges upto
651 // maximum blur in the middle.
652
653 SYS_ASSERT(img.bpp == 3);
654
655 // create a copy to work from (as we cannot blur in-place)
656 epi::image_data_c orig(img.width, img.height, 3);
657
658 memcpy(orig.pixels, img.pixels, orig.width*orig.height*3);
659
660 for (int y = 1+img.height/4; y < img.height*3/4; y++)
661 for (int x = 1+img.width /4; x < img.width *3/4; x++)
662 {
663 int x_pos = 31 - ABS(x - img.width /2) * 127 / img.width;
664 int y_pos = 31 - ABS(y - img.height/2) * 127 / img.height;
665
666 // SYS_ASSERT(0 <= x_pos && x_pos <= 31);
667 // SYS_ASSERT(0 <= y_pos && y_pos <= 31);
668
669 int min_pos = MIN(x_pos, y_pos);
670
671 int size = 16 + min_pos*2; // range: 1.00 to 4.99 (times 16)
672
673 int d_size = (size | 15) / 16;
674
675 // compute average over the box
676 int r = 0;
677 int g = 0;
678 int b = 0;
679 int total = 0;
680
681 for (int dy = -d_size; dy <= +d_size; dy++)
682 for (int dx = -d_size; dx <= +d_size; dx++)
683 {
684 u8_t *src = orig.PixelAt(x+dx, y+dy);
685
686 int qty = ( (ABS(dx) < d_size) ? 16 : (size & 15) ) *
687 ( (ABS(dy) < d_size) ? 16 : (size & 15) );
688
689 total += qty;
690
691 r += src[0] * qty;
692 g += src[1] * qty;
693 b += src[2] * qty;
694 }
695
696 SYS_ASSERT(total > 0);
697
698 u8_t *dest = img.PixelAt(x, y);
699
700 dest[0] = r / total;
701 dest[1] = g / total;
702 dest[2] = b / total;
703 }
704 }
705
BuildFace(const epi::image_data_c * sky,int face,fake_skybox_t * info,const byte * what_palette)706 static GLuint BuildFace(const epi::image_data_c *sky, int face,
707 fake_skybox_t *info, const byte *what_palette)
708
709 {
710 int img_size = info->face_size;
711
712 epi::image_data_c img(img_size, img_size, 3);
713
714
715 bool narrow = SkyIsNarrow(info->base_sky);
716
717 const byte *src = sky->pixels;
718
719 int sky_w = sky->width;
720 int sky_h = sky->height;
721
722 for (int y=0; y < img_size; y++)
723 {
724 u8_t *dest = img.PixelAt(0, y);
725
726 for (int x=0; x < img_size; x++, dest += 3)
727 {
728 float tx, ty;
729
730 CalcSkyCoord(x, y, img_size, img_size, face, narrow, &tx, &ty);
731
732 // Bilinear Filtering
733
734 int TX = (int)(tx * sky_w * 16);
735 int TY = (int)(ty * sky_h * 16);
736
737 // negative values shouldn't occur, but just in case...
738 TX = (TX + sky_w * 64) % (sky_w * 16);
739 TY = (TY + sky_h * 64) % (sky_h * 16);
740
741 // SYS_ASSERT(TX >= 0 && TY >= 0);
742
743 int FX = TX % 16; TX >>= 4;
744 int FY = TY % 16; TY >>= 4;
745
746 // SYS_ASSERT(TX < sky_w && TY < sky_h);
747
748
749 int TX2 = (TX + 1) % sky_w;
750 int TY2 = (TY < sky_h-1) ? (TY+1) : TY;
751
752 byte rA, rB, rC, rD;
753 byte gA, gB, gC, gD;
754 byte bA, bB, bC, bD;
755
756 switch (sky->bpp)
757 {
758 case 1:
759 {
760 byte src_A = src[TY * sky_w + TX];
761 byte src_B = src[TY * sky_w + TX2];
762 byte src_C = src[TY2 * sky_w + TX];
763 byte src_D = src[TY2 * sky_w + TX2];
764
765 rA = PIXEL_RED(src_A); rB = PIXEL_RED(src_B);
766 rC = PIXEL_RED(src_C); rD = PIXEL_RED(src_D);
767
768 gA = PIXEL_GRN(src_A); gB = PIXEL_GRN(src_B);
769 gC = PIXEL_GRN(src_C); gD = PIXEL_GRN(src_D);
770
771 bA = PIXEL_BLU(src_A); bB = PIXEL_BLU(src_B);
772 bC = PIXEL_BLU(src_C); bD = PIXEL_BLU(src_D);
773 }
774 break;
775
776 case 3:
777 {
778 rA = src[(TY * sky_w + TX) * 3 + 0];
779 gA = src[(TY * sky_w + TX) * 3 + 1];
780 bA = src[(TY * sky_w + TX) * 3 + 2];
781
782 rB = src[(TY * sky_w + TX2) * 3 + 0];
783 gB = src[(TY * sky_w + TX2) * 3 + 1];
784 bB = src[(TY * sky_w + TX2) * 3 + 2];
785
786 rC = src[(TY2 * sky_w + TX) * 3 + 0];
787 gC = src[(TY2 * sky_w + TX) * 3 + 1];
788 bC = src[(TY2 * sky_w + TX) * 3 + 2];
789
790 rD = src[(TY2 * sky_w + TX2) * 3 + 0];
791 gD = src[(TY2 * sky_w + TX2) * 3 + 1];
792 bD = src[(TY2 * sky_w + TX2) * 3 + 2];
793 }
794 break;
795
796 case 4:
797 {
798 rA = src[(TY * sky_w + TX) * 4 + 0];
799 gA = src[(TY * sky_w + TX) * 4 + 1];
800 bA = src[(TY * sky_w + TX) * 4 + 2];
801
802 rB = src[(TY * sky_w + TX2) * 4 + 0];
803 gB = src[(TY * sky_w + TX2) * 4 + 1];
804 bB = src[(TY * sky_w + TX2) * 4 + 2];
805
806 rC = src[(TY2 * sky_w + TX) * 4 + 0];
807 gC = src[(TY2 * sky_w + TX) * 4 + 1];
808 bC = src[(TY2 * sky_w + TX) * 4 + 2];
809
810 rD = src[(TY2 * sky_w + TX2) * 4 + 0];
811 gD = src[(TY2 * sky_w + TX2) * 4 + 1];
812 bD = src[(TY2 * sky_w + TX2) * 4 + 2];
813 }
814 break;
815
816 default: // remove compiler warning
817 rA = rB = rC = rD = 0;
818 gA = gB = gC = gD = 0;
819 bA = bB = bC = bD = 0;
820 break;
821 }
822
823 int r = (int)rA * (FX^15) * (FY^15) +
824 (int)rB * (FX ) * (FY^15) +
825 (int)rC * (FX^15) * (FY ) +
826 (int)rD * (FX ) * (FY );
827
828 int g = (int)gA * (FX^15) * (FY^15) +
829 (int)gB * (FX ) * (FY^15) +
830 (int)gC * (FX^15) * (FY ) +
831 (int)gD * (FX ) * (FY );
832
833 int b = (int)bA * (FX^15) * (FY^15) +
834 (int)bB * (FX ) * (FY^15) +
835 (int)bC * (FX^15) * (FY ) +
836 (int)bD * (FX ) * (FY );
837
838 dest[0] = r / 225;
839 dest[1] = g / 225;
840 dest[2] = b / 225;
841 }
842 }
843
844 // make the top surface look less bad
845 if (face == WSKY_Top)
846 {
847 BlurCentre(img);
848 }
849
850 return R_UploadTexture(&img, UPL_Smooth|UPL_Clamp);
851 }
852
853
UserSkyFaceName(const char * base,int face)854 static const char *UserSkyFaceName(const char *base, int face)
855 {
856 static char buffer[64];
857 static const char letters[] = "NESWTB";
858
859 sprintf(buffer, "%s_%c", base, letters[face]);
860 return buffer;
861 }
862
863
RGL_UpdateSkyBoxTextures(void)864 int RGL_UpdateSkyBoxTextures(void)
865 {
866 int SK = ren_fx_colmap ? 1 : 0;
867
868 fake_skybox_t *info = &fake_box[SK];
869
870 if (info->base_sky == sky_image &&
871 info->fx_colmap == ren_fx_colmap)
872 {
873 return SK;
874 }
875
876 info->base_sky = sky_image;
877 info->fx_colmap = ren_fx_colmap;
878
879
880 // check for custom sky boxes
881 info->face[WSKY_North] = W_ImageLookup(
882 UserSkyFaceName(sky_image->name, WSKY_North), INS_Texture, ILF_Null);
883
884 if (info->face[WSKY_North])
885 {
886 custom_sky_box = true;
887
888 info->face_size = info->face[WSKY_North]->total_w;
889
890 for (int i = WSKY_East; i < 6; i++)
891 info->face[i] = W_ImageLookup(
892 UserSkyFaceName(sky_image->name, i), INS_Texture);
893
894 for (int k = 0; k < 6; k++)
895 info->tex[k] = W_ImageCache(info->face[k], false, ren_fx_colmap);
896
897 return SK;
898 }
899
900
901 // Create pseudo sky box
902
903 info->face_size = 256;
904
905 custom_sky_box = false;
906
907
908 // Intentional Const Override
909 const epi::image_data_c *block = ReadAsEpiBlock((image_c*)sky_image);
910 SYS_ASSERT(block);
911
912 // get correct palette
913 const byte *what_pal = (const byte *) &playpal_data[0];
914 bool what_pal_cached = false;
915
916 static byte trans_pal[256*3];
917
918 if (ren_fx_colmap)
919 {
920 R_TranslatePalette(trans_pal, what_pal, ren_fx_colmap);
921 what_pal = trans_pal;
922 }
923 else if (sky_image->source_palette >= 0)
924 {
925 what_pal = (const byte *) W_CacheLumpNum(sky_image->source_palette);
926 what_pal_cached = true;
927 }
928
929 DeleteSkyTexGroup(SK);
930
931 info->tex[WSKY_North] = BuildFace(block, WSKY_North, info, what_pal);
932 info->tex[WSKY_East] = BuildFace(block, WSKY_East, info, what_pal);
933 info->tex[WSKY_Top] = BuildFace(block, WSKY_Top, info, what_pal);
934 info->tex[WSKY_Bottom] = BuildFace(block, WSKY_Bottom, info, what_pal);
935
936 // optimisation: can share side textures when narrow
937
938 info->tex[WSKY_South] = SkyIsNarrow(sky_image) ? info->tex[WSKY_North] :
939 BuildFace(block, WSKY_South, info, what_pal );
940
941 info->tex[WSKY_West] = SkyIsNarrow(sky_image) ? info->tex[WSKY_East] :
942 BuildFace(block, WSKY_West, info, what_pal );
943
944 delete block;
945
946 if (what_pal_cached)
947 W_DoneWithLump(what_pal);
948
949 return SK;
950 }
951
952
RGL_PreCacheSky(void)953 void RGL_PreCacheSky(void)
954 {
955 // TODO
956 }
957
958 //--- editor settings ---
959 // vi:ts=4:sw=4:noexpandtab
960