gzdoom/src/r_sky.cpp

155 lines
4.9 KiB
C++
Raw Normal View History

// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This source is available for distribution and/or modification
// only under the terms of the DOOM Source Code License as
// published by id Software. All rights reserved.
//
// The source is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
// for more details.
//
// $Log:$
//
// DESCRIPTION:
// Sky rendering. The DOOM sky is a texture map like any
// wall, wrapping around. 1024 columns equal 360 degrees.
// The default sky map is 256 columns and repeats 4 times
// on a 320 screen.
//
//
//-----------------------------------------------------------------------------
// Needed for FRACUNIT.
#include "m_fixed.h"
#include "c_cvars.h"
#include "g_level.h"
#include "r_sky.h"
#include "r_utility.h"
#include "v_text.h"
#include "gi.h"
//
// sky mapping
//
FTextureID skyflatnum;
FTextureID sky1texture, sky2texture;
fixed_t skytexturemid;
fixed_t skyscale;
fixed_t skyiscale;
bool skystretch;
fixed_t sky1cyl, sky2cyl;
double sky1pos, sky2pos;
// [RH] Stretch sky texture if not taller than 128 pixels?
CUSTOM_CVAR (Bool, r_stretchsky, true, CVAR_ARCHIVE)
{
R_InitSkyMap ();
}
fixed_t freelookviewheight;
//==========================================================================
//
// R_InitSkyMap
//
// Called whenever the view size changes.
//
//==========================================================================
void R_InitSkyMap ()
{
int skyheight;
FTexture *skytex1, *skytex2;
skytex1 = TexMan(sky1texture, true);
skytex2 = TexMan(sky2texture, true);
if (skytex1 == NULL)
return;
if ((level.flags & LEVEL_DOUBLESKY) && skytex1->GetHeight() != skytex2->GetHeight())
{
Printf (TEXTCOLOR_BOLD "Both sky textures must be the same height." TEXTCOLOR_NORMAL "\n");
sky2texture = sky1texture;
}
// There are various combinations for sky rendering depending on how tall the sky is:
// h < 128: Unstretched and tiled, centered on horizon
// 128 <= h < 200: Can possibly be stretched. When unstretched, the baseline is
// 28 rows below the horizon so that the top of the texture
// aligns with the top of the screen when looking straight ahead.
// When stretched, it is scaled to 228 pixels with the baseline
// in the same location as an unstretched 128-tall sky, so the top
// of the texture aligns with the top of the screen when looking
// fully up.
// h == 200: Unstretched, baseline is on horizon, and top is at the top of
// the screen when looking fully up.
// h > 200: Unstretched, but the baseline is shifted down so that the top
// of the texture is at the top of the screen when looking fully up.
skyheight = skytex1->GetScaledHeight();
skystretch = false;
skytexturemid = 0;
if (skyheight >= 128 && skyheight < 200)
{
skystretch = (r_stretchsky
&& skyheight >= 128
&& level.IsFreelookAllowed()
&& !(level.flags & LEVEL_FORCENOSKYSTRETCH)) ? 1 : 0;
skytexturemid = -28*FRACUNIT;
}
else if (skyheight > 200)
{
skytexturemid = FixedMul((200 - skyheight) << FRACBITS, skytex1->yScale);
}
if (viewwidth != 0 && viewheight != 0)
{
- Ported vlinetallasm4 to AMD64 assembly. Even with the increased number of registers AMD64 provides, this routine still needs to be written as self- modifying code for maximum performance. The additional registers do allow for further optimization over the x86 version by allowing all four pixels to be in flight at the same time. The end result is that AMD64 ASM is about 2.18 times faster than AMD64 C and about 1.06 times faster than x86 ASM. (For further comparison, AMD64 C and x86 C are practically the same for this function.) Should I port any more assembly to AMD64, mvlineasm4 is the most likely candidate, but it's not used enough at this point to bother. Also, this may or may not work with Linux at the moment, since it doesn't have the eh_handler metadata. Win64 is easier, since I just need to structure the function prologue and epilogue properly and use some assembler directives/macros to automatically generate the metadata. And that brings up another point: You need YASM to assemble the AMD64 code, because NASM doesn't support the Win64 metadata directives. - Added an SSE version of DoBlending. This is strictly C intrinsics. VC++ still throws around unneccessary register moves. GCC seems to be pretty close to optimal, requiring only about 2 cycles/color. They're both faster than my hand-written MMX routine, so I don't need to feel bad about not hand-optimizing this for x64 builds. - Removed an extra instruction from DoBlending_MMX, transposed two instructions, and unrolled it once, shaving off about 80 cycles from the time required to blend 256 palette entries. Why? Because I tried writing a C version of the routine using compiler intrinsics and was appalled by all the extra movq's VC++ added to the code. GCC was better, but still generated extra instructions. I only wanted a C version because I can't use inline assembly with VC++'s x64 compiler, and x64 assembly is a bit of a pain. (It's a pain because Linux and Windows have different calling conventions, and you need to maintain extra metadata for functions.) So, the assembly version stays and the C version stays out. - Removed all the pixel doubling r_detail modes, since the one platform they were intended to assist (486) actually sees very little benefit from them. - Rewrote CheckMMX in C and renamed it to CheckCPU. - Fixed: CPUID function 0x80000005 is specified to return detailed L1 cache only for AMD processors, so we must not use it on other architectures, or we end up overwriting the L1 cache line size with 0 or some other number we don't actually understand. SVN r1134 (trunk)
2008-08-09 03:13:43 +00:00
skyiscale = (r_Yaspect*FRACUNIT) / ((freelookviewheight * viewwidth) / viewwidth);
skyscale = (((freelookviewheight * viewwidth) / viewwidth) << FRACBITS) /
(r_Yaspect);
skyiscale = Scale (skyiscale, FieldOfView, 2048);
skyscale = Scale (skyscale, 2048, FieldOfView);
}
if (skystretch)
{
skyscale = Scale(skyscale, SKYSTRETCH_HEIGHT, skyheight);
skyiscale = Scale(skyiscale, skyheight, SKYSTRETCH_HEIGHT);
skytexturemid = Scale(skytexturemid, skyheight, SKYSTRETCH_HEIGHT);
}
// The standard Doom sky texture is 256 pixels wide, repeated 4 times over 360 degrees,
// giving a total sky width of 1024 pixels. So if the sky texture is no wider than 1024,
// we map it to a cylinder with circumfrence 1024. For larger ones, we use the width of
// the texture as the cylinder's circumfrence.
sky1cyl = MAX(skytex1->GetWidth(), skytex1->xScale >> (16 - 10));
sky2cyl = MAX(skytex2->GetWidth(), skytex2->xScale >> (16 - 10));
}
//==========================================================================
//
// R_UpdateSky
//
// Performs sky scrolling
//
//==========================================================================
void R_UpdateSky (DWORD mstime)
{
// Scroll the sky
double ms = (double)mstime * FRACUNIT;
sky1pos = ms * level.skyspeed1;
sky2pos = ms * level.skyspeed2;
}