mirror of
https://github.com/OpenTrespasser/JurassicParkTrespasser.git
synced 2024-12-18 22:51:56 +00:00
4183 lines
113 KiB
C++
4183 lines
113 KiB
C++
/***********************************************************************************************
|
|
*
|
|
* Copyright © DreamWorks Interactive. 1997
|
|
*
|
|
* Contents:
|
|
* Implementation of CSkyRender
|
|
*
|
|
* Bugs:
|
|
*
|
|
* To do:
|
|
*
|
|
* Notes:
|
|
* The bitmap for the texture must contain less than iNUM_SKY_COLOURS otherwise it will
|
|
* assert in the constructor. This define can be set to any number of colours but care
|
|
* should taken when chaning this value because the fog CLUT for the sky also changes
|
|
* size. At the moment we are set to 64 fog bands and 128 colours which creates a CLUT
|
|
* with 8192 entries at 2 bytes each - thus consuming 16384 bytes of memory. A full clut
|
|
* of 256 colours with 256 fog bands will consume 128K.
|
|
*
|
|
***********************************************************************************************
|
|
*
|
|
* $Log:: /JP2_PC/Source/Lib/Renderer/Sky.cpp $
|
|
*
|
|
* 61 98.10.03 11:09p Mmouni
|
|
* Put self moding code in code segment "SelfMod".
|
|
*
|
|
* 60 9/26/98 9:26p Pkeet
|
|
* Sky matches fill.
|
|
*
|
|
* 59 9/23/98 12:39p Pkeet
|
|
* Turned off Z buffering for the sky.
|
|
*
|
|
* 58 9/22/98 10:40p Pkeet
|
|
* Changed the overloaded '*' operator for CColour to use floats instead of doubles.
|
|
*
|
|
* 57 9/22/98 12:37a Pkeet
|
|
* Hardware states handled explicitly.
|
|
*
|
|
* 56 9/07/98 4:55p Pkeet
|
|
* Fixed bug clearing the background with a viewport smaller than the screen dimensions.
|
|
*
|
|
* 55 9/04/98 7:38p Agrant
|
|
* disable the long symbol warning
|
|
*
|
|
* 54 9/02/98 10:52p Mmouni
|
|
* Fixed a problem with the K6-3D scanline fill filling an extra 8 pixles if the starting
|
|
* address of the scanline was not 8 byte aligned.
|
|
*
|
|
* 53 9/02/98 5:48p Asouth
|
|
* added some specific 'float ptr' qualifiers in inline assembly
|
|
*
|
|
* 52 9/01/98 12:49a Pkeet
|
|
* Sky no longer sets the default render state.
|
|
*
|
|
* 51 8/31/98 2:59p Pkeet
|
|
* Changed the Direct3D rendering to use more typical Direct3D code.
|
|
*
|
|
* 50 98.08.13 4:26p Mmouni
|
|
* Changes for VC++ 5.0sp3 compatibility.
|
|
*
|
|
* 49 8/10/98 11:29p Pkeet
|
|
* Added the base offsets. Removed the clumsy file hack adjust value.
|
|
*
|
|
* 48 8/04/98 6:13p Pkeet
|
|
* Made sky work with the Z buffer on a Voodoo 2.
|
|
*
|
|
* 47 8/02/98 9:05p Pkeet
|
|
* Disabled filling the non-sky portion of the backdrop using a Direct3D primitive.
|
|
*
|
|
* 46 7/29/98 8:25p Pkeet
|
|
* Added code for Z buffering.
|
|
*
|
|
* 45 7/29/98 11:47a Pkeet
|
|
* The addressing mode for sky is made to wrap.
|
|
*
|
|
* 44 7/27/98 12:29p Pkeet
|
|
* Added an initialization class for 'CRasterD3D.'
|
|
*
|
|
* 43 7/23/98 9:08p Pkeet
|
|
* Added code to track the creation and deletion of Direct3D textures using a macro switch in
|
|
* 'RasterD3D.hpp.'
|
|
*
|
|
* 42 7/21/98 5:21p Rwyatt
|
|
* Set sky to use 128 colours.
|
|
*
|
|
* 41 7/20/98 10:27p Pkeet
|
|
* Upgraded to Direct3D 4's interface.
|
|
*
|
|
* 40 7/13/98 12:07a Pkeet
|
|
* Added the 'ResetScreenSize' member function. Fixed a crash bug associated with the sky. Added
|
|
* an offset to allow Direct3D to place its polygons in the right place when the size of the
|
|
* viewport is changed.
|
|
*
|
|
* 39 98/06/29 16:25 Speter
|
|
* Rendering functions now take CInstance*.
|
|
*
|
|
* 38 98.06.26 7:40p Mmouni
|
|
* Added sold fill mode to sky.
|
|
*
|
|
* 37 98.06.25 8:46p Mmouni
|
|
* No longer loads the bTextured flag.
|
|
*
|
|
* 36 6/22/98 12:17p Pkeet
|
|
* Fixed the sky flashing bug under Direct3D for certain configurations.
|
|
*
|
|
* 35 6/12/98 9:16p Pkeet
|
|
* Sky now uses a Direct3D parameter to optionally support software rendered sky under Direct3D.
|
|
* Sky forces its Direct3D raster to always be its required size.
|
|
*
|
|
* 34 98.05.26 4:29p Mmouni
|
|
* Fixed sky co-ordinates overflow due to honking big step time.
|
|
*
|
|
* 33 5/15/98 2:22a Rwyatt
|
|
* Adjusted the UV co-ords for when the sky wraps
|
|
*
|
|
* 32 5/14/98 8:06p Agrant
|
|
* Removed the defunct poval_renderer argument form rendertype constructor
|
|
*
|
|
* 31 5/01/98 5:13p Rwyatt
|
|
* Sky texture offsets now wrap instead of getting bigger and bigger.
|
|
*
|
|
* 30 4/22/98 12:36p Rwyatt
|
|
* New text prop to set the flat shade colour
|
|
*
|
|
* 29 4/21/98 2:55p Rwyatt
|
|
* Sky must have text props which specifiy no mip maps.
|
|
* Old VM system has been removed.
|
|
*
|
|
* 28 4/03/98 5:26p Pkeet
|
|
* Fixed bug that was causing sky to randomly switch between a filtered state and a non-filtered
|
|
* state.
|
|
*
|
|
* 27 98.04.03 1:01p Mmouni
|
|
* Added save/load methods to CSky.
|
|
*
|
|
* 26 98.03.31 6:26p Mmouni
|
|
* K63D optimized sky is now drawn in 64x64 blocks.
|
|
*
|
|
* 25 3/30/98 12:41p Pkeet
|
|
* Fixed Direct3D bug.
|
|
*
|
|
* 24 98.03.27 6:18p Mmouni
|
|
* Sky (on Pentium) is now drawn in 32x32 blocks.
|
|
*
|
|
* 23 3/27/98 5:30p Pkeet
|
|
* Fixed bug where the sky texture is not available under Direct3D.
|
|
*
|
|
* 22 98/03/27 16:15 Speter
|
|
* Fixed warnings.
|
|
*
|
|
* 21 98.03.19 5:07p Mmouni
|
|
* Optimized linear textured routine for 3dx.
|
|
*
|
|
* 20 3/18/98 4:06p Pkeet
|
|
* Added the 'PartitionPriv.hpp' include.
|
|
*
|
|
* 19 98/02/26 13:45 Speter
|
|
* Replaced CPolyIterator::sfSurface() with ptexTexture().
|
|
*
|
|
* 18 1/29/98 7:43p Rwyatt
|
|
* The Sky constructor no longer scans the bitmap as this causes the map to be loaded in virtual
|
|
* mode.
|
|
*
|
|
* 17 1/26/98 11:37a Pkeet
|
|
* Set the perspective flag on for Direct3D.
|
|
*
|
|
* 16 1/22/98 3:17p Pkeet
|
|
* Added a purge function for Direct3D.
|
|
*
|
|
* 15 98/01/16 12:34 Speter
|
|
* Turned on screen fill by default.
|
|
*
|
|
* 14 98.01.07 1:05p Mmouni
|
|
* Optimized Pentium version of linear sky drawing.
|
|
*
|
|
* 13 1/06/98 7:02p Pkeet
|
|
* Always enable fog for sky.
|
|
*
|
|
* 12 1/06/98 6:26p Pkeet
|
|
* Added fogging for sky.
|
|
*
|
|
* 11 1/05/98 7:29p Pkeet
|
|
* Fixed bug involving the render state being set after "Begin."
|
|
*
|
|
* 10 1/05/98 6:27p Pkeet
|
|
* Made the sky render correctly with Direct3D. Added the 'FillD3D' member function.
|
|
*
|
|
* 9 1/02/98 2:36p Pkeet
|
|
* Added structures and preliminary code to support Direct3D.
|
|
*
|
|
* 8 12/04/97 4:15p Rwyatt
|
|
* Inserted the protect macros around the sky renderer
|
|
*
|
|
* 7 97.11.11 10:47p Mmouni
|
|
* General assembly sky drawing optimizations.
|
|
*
|
|
* 6 10/22/97 5:07p Rwyatt
|
|
* Added perspective textured and flat for non horizontal skies.
|
|
* Optimized math and replaced constant expressions expressions
|
|
* Made fog linear.
|
|
* frustum vectors are now normalised direction vectors instead of the full length of the
|
|
* frustum,
|
|
* Sub division is variable.
|
|
*
|
|
* 5 10/16/97 2:04p Agrant
|
|
* Value table based constructor now allows instancing of CInfo-
|
|
* not relevant for Sky, but here for uniformity.
|
|
*
|
|
* 4 10/14/97 7:01p Rwyatt
|
|
* First Check in
|
|
*
|
|
* 3 10/14/97 4:26a Rwyatt
|
|
* Added sky/clouds move speed in m/s
|
|
*
|
|
* 2 10/13/97 8:46p Rwyatt
|
|
* Fixed assert in debug mode
|
|
*
|
|
* 1 10/13/97 1:22p Rwyatt
|
|
* Initial Implementation
|
|
*
|
|
**********************************************************************************************/
|
|
|
|
#include "Common.hpp"
|
|
#include "lib/W95/WinInclude.hpp"
|
|
#include "Lib/GeomDBase/PartitionPriv.hpp"
|
|
#include "Sky.hpp"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "Lib/Groff/ValueTable.hpp"
|
|
#include "Lib/Loader/Loader.hpp"
|
|
#include "Lib/Sys/W95/Render.hpp"
|
|
#include "Lib/Sys/VirtualMem.hpp"
|
|
#include "Lib/Sys/DebugConsole.hpp"
|
|
#include "Lib/Renderer/Camera.hpp"
|
|
#include "Lib/Renderer/Primitives/DrawTriangle.hpp"
|
|
#include "Lib/View/Clut.hpp"
|
|
#include "Lib/EntityDBase/Query/QRenderer.hpp"
|
|
#include "Lib/EntityDBase/MessageTypes/MsgStep.hpp"
|
|
#include "SkyPoly.hpp"
|
|
#include "AsmSupport.hpp"
|
|
#include "Lib/Loader/SaveFile.hpp"
|
|
#include "Lib/Loader/SaveFile.hpp"
|
|
#include "Lib/Groff/VTParse.hpp"
|
|
#include "Lib/View/Direct3DRenderState.hpp"
|
|
#include "Lib/Renderer/ScreenRenderAuxD3D.hpp"
|
|
#include "Lib/Renderer/ScreenRenderAuxD3DUtilities.hpp"
|
|
|
|
#pragma warning(disable:4786)
|
|
|
|
//#undef VER_ASM
|
|
//**********************************************************************************************
|
|
// Global sky render class this should ALWAYS be NULL if there is no sky present.
|
|
//
|
|
CSkyRender* gpskyRender = NULL;
|
|
//
|
|
//**************************************
|
|
|
|
|
|
//**********************************************************************************************
|
|
// static array initialized by the constructor to contain the normailzed co-ords of the frustum
|
|
// at the back clip plane.
|
|
//
|
|
CVector3<> CSkyRender::av3Frustum[u4NUM_SKY_TRANSFORM_VERT];
|
|
|
|
|
|
//**********************************************************************************************
|
|
// The transformed fustrum as unit vectors
|
|
//
|
|
CVector3<> CSkyRender::av3FrustTran[u4NUM_SKY_TRANSFORM_VERT];
|
|
|
|
|
|
//**********************************************************************************************
|
|
// The Camera in world space
|
|
//
|
|
CVector3<> CSkyRender::v3Camera;
|
|
|
|
|
|
|
|
//**********************************************************************************************
|
|
// Constructor requires a source sky bitmap and a destination render surface,
|
|
//
|
|
CSkyRender::CSkyRender(rptr<CRaster> pras_sky, rptr<CRaster> pras_screen)
|
|
//
|
|
//**************************************
|
|
{
|
|
// the width and height of the sky texture must be 256x256
|
|
Assert (pras_sky->iWidth == 256);
|
|
Assert (pras_sky->iHeight == 256);
|
|
// and the texture must be packed...
|
|
Assert (pras_sky->iLinePixels == 512);
|
|
|
|
// reference the sky texture so it remians when the mesh is deleted
|
|
prasSkyTexture = pras_sky;
|
|
prasRenderSurface = pras_screen;
|
|
|
|
|
|
// Setup the static array representing the back of the frustum in normalized
|
|
// camera space.
|
|
av3Frustum[u4FRUST_TL] = CVector3<>( -1.0f, 1.0f, 1.0f); //tl
|
|
av3Frustum[u4FRUST_TR] = CVector3<>( 1.0f, 1.0f, 1.0f); //tr
|
|
av3Frustum[u4FRUST_BL] = CVector3<>( -1.0f, 1.0f, -1.0f); //bl
|
|
av3Frustum[u4FRUST_BR] = CVector3<>( 1.0f, 1.0f, -1.0f); //br
|
|
av3Frustum[u4FRUST_TOP] = CVector3<>( 0.0f, 0.0f, 1.0f); //top
|
|
av3Frustum[u4FRUST_RIGHT] = CVector3<>( 1.0f, 0.0f, 0.0f); //right
|
|
|
|
|
|
// initial sky offsets
|
|
fSkyOffsetU = 0;
|
|
fSkyOffsetV = 0;
|
|
|
|
// Default flat shaded colour is the last in the palette
|
|
u4FlatColourIndex = iNUM_SKY_COLOURS - 1;
|
|
|
|
//
|
|
// Setup the working default sky paramaters.
|
|
//
|
|
SetWorkingConstants
|
|
(
|
|
fDEFAULT_SKY_PIXEL_SCALE,
|
|
fDEFAULT_SKY_HEIGHT,
|
|
fDEFAULT_SKY_NEAR_FOG,
|
|
fDEFAULT_SKY_FAR_FOG,
|
|
u4SCREEN_DIVIDE_PIXELS
|
|
);
|
|
|
|
|
|
//
|
|
// Set the default wind speed
|
|
//
|
|
SetSkyWind(fDEFAULT_SKY_WIND_U,fDEFAULT_SKY_WIND_V);
|
|
|
|
// fog colour = clrDefEndDepth;
|
|
SetSkyFogTable(clrDefEndDepth);
|
|
|
|
// sky is textured by default..
|
|
SetDrawMode(sdmTextured);
|
|
|
|
// the sky does fill by default
|
|
SetFilled(true);
|
|
|
|
// set the frame time so the clould movement can be calculated
|
|
sFrameTime = CMessageStep::sStaticTotal;
|
|
|
|
// Determine if Direct3D is to be used, and perform setup for it if it is.
|
|
//InitializeForD3D();
|
|
}
|
|
|
|
|
|
//**********************************************************************************************
|
|
// This calculates a linear fade from 0 to the back fog colour.
|
|
//
|
|
void CSkyRender::SetSkyFogTable
|
|
//
|
|
//**************************************
|
|
(
|
|
CColour clr_fog
|
|
)
|
|
{
|
|
for (uint32 u4_fog = 0; u4_fog<iNUM_SKY_FOG_BANDS; u4_fog++)
|
|
{
|
|
float f_fog_weight = (float)u4_fog / (float)(iNUM_SKY_FOG_BANDS-1);
|
|
|
|
for (uint32 u4_col = 0; u4_col<iNUM_SKY_COLOURS; u4_col++)
|
|
{
|
|
CColour clr = prasSkyTexture->clrFromPixel(u4_col);
|
|
CColour clr_local;
|
|
|
|
clr_local = (clr * (1.0f - f_fog_weight)) + (clr_fog * f_fog_weight);
|
|
|
|
u2FogTable[u4_fog][u4_col] = (uint16)prasRenderSurface->pixFromColour(clr_local);
|
|
}
|
|
}
|
|
|
|
// make a DWORD with the fog colour so we can set a scan line fast.
|
|
u4Fog = prasRenderSurface->pixFromColour(clr_fog);
|
|
u4Fog = u4Fog | (u4Fog<<16);
|
|
}
|
|
|
|
|
|
|
|
//**********************************************************************************************
|
|
// All the working constants for the screen are calculated here. Most of them are 1/x functions
|
|
// to save the divides.
|
|
//
|
|
void CSkyRender::SetWorkingConstants
|
|
//
|
|
//**************************************
|
|
(
|
|
float f_pixels_per_meter,
|
|
float f_sky_height,
|
|
float f_fog_near,
|
|
float f_fog_far,
|
|
uint32 u4_sub_division
|
|
)
|
|
{
|
|
//
|
|
// Do most of the asserts here, after here not much can go wrong.
|
|
//
|
|
Assert(prasRenderSurface);
|
|
Assert(prasRenderSurface->iWidth);
|
|
Assert(prasRenderSurface->iHeight);
|
|
Assert(f_sky_height>0);
|
|
Assert( (f_fog_near>=0) && (f_fog_near<=1.0) );
|
|
Assert( (f_fog_far>=0) && (f_fog_far<=1.0) );
|
|
|
|
// sub division must be an even number....
|
|
Assert((u4_sub_division & 1) == 0);
|
|
|
|
u4DivisionLength = u4_sub_division;
|
|
fDivisionsPerScanRep = 1.0f / ((float)prasRenderSurface->iWidth / (float)u4DivisionLength);
|
|
fPixelsPerMeter = f_pixels_per_meter;
|
|
fSkyHeight = f_sky_height;
|
|
fFogFar = f_fog_far;
|
|
fFogNear = f_fog_near;
|
|
fFogScale = (1.0f/(fFogFar-fFogNear)) * (iNUM_SKY_FOG_BANDS-1)*(1<<u4DEFAULT_SKY_FOG_BITS);
|
|
fScale = f_pixels_per_meter * 65536.0f;
|
|
fScreenWidthRep = 1.0f / (float)prasRenderSurface->iWidth;
|
|
fScreenHeightRep = 1.0f / (float)prasRenderSurface->iHeight;
|
|
fScreenWidthScaleRep = (1.0f / (float)prasRenderSurface->iWidth)*fScale;
|
|
fDivisionLengthRepScale = (1.0f/(float)u4DivisionLength)*fScale;
|
|
|
|
u4ScreenWidth = prasRenderSurface->iWidth;
|
|
u4ScreenHeight = prasRenderSurface->iHeight;
|
|
}
|
|
|
|
//**********************************************************************************************
|
|
void CSkyRender::ResetScreenSize()
|
|
{
|
|
Assert(prasRenderSurface);
|
|
|
|
NewRenderSurface(prasRenderSurface);
|
|
SetWorkingConstants
|
|
(
|
|
fPixelsPerMeter,
|
|
fSkyHeight,
|
|
fFogNear,
|
|
fFogFar,
|
|
u4DivisionLength
|
|
);
|
|
}
|
|
|
|
|
|
//**********************************************************************************************
|
|
// This is called when the destination raster changes. This happens when the screen is resized
|
|
// or the mode is changed.
|
|
//
|
|
void CSkyRender::NewRenderSurface(rptr<CRaster> pras_screen)
|
|
//
|
|
//**************************************
|
|
{
|
|
Assert(pras_screen);
|
|
Assert(pras_screen->iWidth);
|
|
Assert(pras_screen->iHeight);
|
|
|
|
prasRenderSurface = pras_screen;
|
|
fScreenHeightRep = 1.0f / (float)prasRenderSurface->iHeight;
|
|
fScreenWidthRep = 1.0f / (float)prasRenderSurface->iWidth;
|
|
fScreenWidthScaleRep = (1.0f / (float)prasRenderSurface->iWidth)*fScale;
|
|
fDivisionsPerScanRep = 1.0f / ((float)prasRenderSurface->iWidth / (float)u4DivisionLength);
|
|
|
|
u4ScreenWidth = prasRenderSurface->iWidth;
|
|
u4ScreenHeight = prasRenderSurface->iHeight;
|
|
|
|
SetSkyFogTable(clrDefEndDepth);
|
|
}
|
|
|
|
//**********************************************************************************************
|
|
// Entry point for drawing the sky.
|
|
//
|
|
// This will first decide if to use the linear or perspective sky primitve, the it checks to
|
|
// see if the sky is to be textured or shaded.
|
|
//
|
|
void CSkyRender::DrawSkyToHorizon()
|
|
//
|
|
//**************************************
|
|
{
|
|
// Get the vectors representing the orientation of the view frustum.
|
|
SetTransformedCameraCorners();
|
|
|
|
// Set the D3D use flag.
|
|
bUseD3D = d3dDriver.bUseD3DSky();
|
|
|
|
// Use Direct3D if possible.
|
|
if (bUseD3D)
|
|
{
|
|
// adjust the texture positions to simulate the wind moving the clouds
|
|
TSec s_elapsed = CMessageStep::sStaticTotal - sFrameTime;
|
|
sFrameTime = CMessageStep::sStaticTotal;
|
|
|
|
// adjust the sky origin...
|
|
fSkyOffsetU += (fSkyOffsetdU*s_elapsed * 0.000000025f);
|
|
fSkyOffsetV += (fSkyOffsetdV*s_elapsed * 0.000000025f);
|
|
|
|
// Keep the U and V offsets in the range 0..1.
|
|
fSkyOffsetU -= int(fSkyOffsetU);
|
|
fSkyOffsetV -= int(fSkyOffsetV);
|
|
DrawD3D();
|
|
return;
|
|
}
|
|
|
|
// get a pointer to the rendering surface.
|
|
prasRenderSurface->Lock();
|
|
pu2Raster = (uint16*)prasRenderSurface->pSurface;
|
|
i4Pitch = prasRenderSurface->iLinePixels;
|
|
|
|
if ( fabs(av3FrustTran[0].tZ - av3FrustTran[1].tZ) < fSKY_HORIZONTAL)
|
|
{
|
|
// Draw a Linear Sky....
|
|
if (sdmMode == sdmTextured)
|
|
{
|
|
DrawSkyTexturedLinear();
|
|
}
|
|
else if (sdmMode == sdmGradient)
|
|
{
|
|
DrawSkyFlatLinear();
|
|
}
|
|
else
|
|
{
|
|
// Color fill.
|
|
AlwaysAssert(prasRenderSurface.ptGet() == prasMainScreen.ptGet());
|
|
//prasRenderSurface->Clear(u4Fog & 0x0000ffff);
|
|
prasMainScreen->ClearSubRect(u4Fog & 0x0000ffff);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Draw a perspective sky
|
|
if (sdmMode == sdmTextured)
|
|
{
|
|
DrawSkyTexturedPerspective();
|
|
}
|
|
else if (sdmMode == sdmGradient)
|
|
{
|
|
DrawSkyFlatPerspective();
|
|
}
|
|
else
|
|
{
|
|
// Color fill.
|
|
AlwaysAssert(prasRenderSurface.ptGet() == prasMainScreen.ptGet());
|
|
//prasRenderSurface->Clear(u4Fog & 0x0000ffff);
|
|
prasMainScreen->ClearSubRect(u4Fog & 0x0000ffff);
|
|
}
|
|
}
|
|
|
|
// Unlock the render surface now we have finished with it
|
|
prasRenderSurface->Unlock();
|
|
|
|
{
|
|
// adjust the texture positions to simulate the wind moving the clouds
|
|
TSec s_elapsed = CMessageStep::sStaticTotal - sFrameTime;
|
|
sFrameTime = CMessageStep::sStaticTotal;
|
|
|
|
// Clamp the frame time.
|
|
if (s_elapsed > 1.0f)
|
|
s_elapsed = 1.0f;
|
|
|
|
// adjust the sky origin...
|
|
fSkyOffsetU += (fSkyOffsetdU * s_elapsed);
|
|
fSkyOffsetV += (fSkyOffsetdV * s_elapsed);
|
|
|
|
//
|
|
// Keep the sky co-ords to something sensible, otherwise the floating point offsets become
|
|
// too big and we get streaks.
|
|
//
|
|
if (fSkyOffsetU > 512.0f)
|
|
fSkyOffsetU -= 512.0f;
|
|
if (fSkyOffsetU < -512.0f)
|
|
fSkyOffsetU += 512.0f;
|
|
|
|
if (fSkyOffsetV > 512.0f)
|
|
fSkyOffsetV -= 512.0f;
|
|
if (fSkyOffsetV < -512.0f)
|
|
fSkyOffsetV += 512.0f;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//**********************************************************************************************
|
|
//
|
|
// Protected functions
|
|
//
|
|
|
|
//**********************************************************************************************
|
|
//
|
|
void CSkyRender::DrawSkyFlatLinear()
|
|
//
|
|
//**************************************
|
|
{
|
|
CVector3<> v3_delta; // frustum step vector for left edge of screen
|
|
CVector3<>* pv3;
|
|
float f_clip;
|
|
int32 i4_fog;
|
|
uint32 u4_lines = 0;
|
|
|
|
|
|
if (av3FrustTran[0].tZ<0)
|
|
{
|
|
// we are drawing from bottom to top
|
|
// calculate the deltas..
|
|
v3_delta = (av3FrustTran[0] - av3FrustTran[2]) * fScreenHeightRep;
|
|
|
|
// point to the base vector we are using (bottom in this case)
|
|
pv3 = &av3FrustTran[2];
|
|
|
|
// adjust the screen pointer to point to the left edge of the last scanline
|
|
pu2Raster = pu2Raster + (i4Pitch*((int32)u4ScreenHeight-1));
|
|
i4Pitch = - i4Pitch;
|
|
}
|
|
else
|
|
{
|
|
// we are drawing from bottom to top
|
|
// calculate the deltas..
|
|
v3_delta = (av3FrustTran[2] - av3FrustTran[0]) * fScreenHeightRep;
|
|
|
|
// point to the base vector we are using (bottom in this case)
|
|
pv3 = &av3FrustTran[0];
|
|
}
|
|
|
|
// get the parametric clip point for the vector and sky plane, relative to the player.
|
|
// This is the initial clip point used for the first scan line, the next clip point
|
|
// is calculated while the first scan line is being drawn..
|
|
f_clip = fSkyHeight / pv3->tZ;
|
|
|
|
while ( (pv3->tZ>fSKY_HORIZON_Z) && (u4_lines<u4ScreenHeight))
|
|
{
|
|
i4_fog = (int32) ((1.0f - fabs(pv3->tZ) - fFogNear) * fFogScale)>>u4DEFAULT_SKY_FOG_BITS;
|
|
|
|
// clamp the fog bands to the definded range...
|
|
if (i4_fog>iNUM_SKY_FOG_BANDS-1)
|
|
{
|
|
i4_fog = iNUM_SKY_FOG_BANDS-1;
|
|
}
|
|
else if (i4_fog<0)
|
|
{
|
|
i4_fog = 0;
|
|
}
|
|
|
|
// calculate the ray cast vectors for the next scan line and the next clip point
|
|
*pv3+=v3_delta;
|
|
f_clip = fSkyHeight / pv3->tZ;
|
|
|
|
// fast fill the scan line
|
|
FillSky
|
|
(
|
|
pu2Raster,
|
|
u4ScreenWidth,
|
|
0,
|
|
1,
|
|
u2FogTable[ i4_fog ][u4FlatColourIndex] | (u2FogTable[ i4_fog ][u4FlatColourIndex]<<16)
|
|
);
|
|
|
|
// the next scan line
|
|
pu2Raster = pu2Raster + i4Pitch;
|
|
u4_lines++;
|
|
}
|
|
|
|
|
|
// if the fill flag is set and the screen was not filled by the sky then fill it with the
|
|
// back fog colour.
|
|
if ((bFill) && (u4_lines<u4ScreenHeight))
|
|
{
|
|
FillSky
|
|
(
|
|
pu2Raster,
|
|
u4ScreenWidth,
|
|
((i4Pitch-(int32)u4ScreenWidth)*prasRenderSurface->iPixelBits/8),
|
|
u4ScreenHeight - u4_lines,
|
|
u4Fog
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
#if (VER_ASM && TARGET_PROCESSOR == PROCESSOR_PENTIUM)
|
|
|
|
//**********************************************************************************************
|
|
//
|
|
struct SaveValues
|
|
//
|
|
// Values saved between scanlines.
|
|
//
|
|
//**************************************
|
|
{
|
|
int i_uvint;
|
|
int i_ufrac;
|
|
int i_vfrac;
|
|
int ai_uvdelta[2];
|
|
int i_ufrac_delta;
|
|
int i_vfrac_delta;
|
|
void* pu2_dest;
|
|
void* pv_fog;
|
|
};
|
|
|
|
#define iRENDER_BLOCK_SIZE 32
|
|
|
|
#pragma optimize("g", off)
|
|
#pragma code_seg("SelfMod")
|
|
|
|
//**********************************************************************************************
|
|
//
|
|
void CSkyRender::DrawSkyTexturedLinear()
|
|
//
|
|
//**************************************
|
|
{
|
|
CVector3<> v3_delta_left;
|
|
CVector3<> v3_delta_right;
|
|
CVector3<>* pv3_left;
|
|
CVector3<>* pv3_right;
|
|
float f_clip;
|
|
int32 i4_fog;
|
|
uint32 fp_u;
|
|
uint32 fp_v;
|
|
uint32 fp_delta_u;
|
|
uint32 fp_delta_v;
|
|
uint32 u4_lines = 0;
|
|
uint8* pu1_tex;
|
|
SaveValues asv_saved[iRENDER_BLOCK_SIZE];
|
|
|
|
static void* pvFogPointer;
|
|
static void* pvBaseOfLine;
|
|
static int32 i_ufrac_delta;
|
|
static int32 i_vfrac_delta;
|
|
static int32 ai_uvdelta[2];
|
|
|
|
typedef CVector3<> CVector3_float;
|
|
typedef CSkyRender myCSkyRender;
|
|
|
|
//Assert(iNUM_SKY_COLOURS == 64);
|
|
|
|
pu1_tex = (uint8*)prasSkyTexture->pSurface;
|
|
|
|
//
|
|
// If the World space Z component of the frustum top left vector is negative then we are
|
|
// drawing from bottom to top of the screen.
|
|
//
|
|
if (av3FrustTran[0].tZ < fSKY_HORIZON_Z)
|
|
{
|
|
// we are drawing from bottom to top
|
|
// calculate the per scan line deltas..
|
|
v3_delta_left = (av3FrustTran[0] - av3FrustTran[2]) * fScreenHeightRep;
|
|
v3_delta_right = (av3FrustTran[1] - av3FrustTran[3]) * fScreenHeightRep;
|
|
|
|
// point to the base vector we are using (bottom in this case)
|
|
pv3_left = &av3FrustTran[2];
|
|
pv3_right = &av3FrustTran[3];
|
|
|
|
// adjust the screen pointer to point to the left edge of the last scanline
|
|
pu2Raster = pu2Raster + (i4Pitch*((int)u4ScreenHeight-1));
|
|
i4Pitch = - i4Pitch;
|
|
}
|
|
else
|
|
{
|
|
// we are drawing from top to bottom
|
|
// calculate the per scan line deltas..
|
|
v3_delta_left = (av3FrustTran[2] - av3FrustTran[0]) * fScreenHeightRep;
|
|
v3_delta_right = (av3FrustTran[3] - av3FrustTran[1]) * fScreenHeightRep;
|
|
|
|
// point to the base vector we are using (bottom in this case)
|
|
pv3_left = &av3FrustTran[0];
|
|
pv3_right = &av3FrustTran[1];
|
|
}
|
|
|
|
// get the parametric clip point for the vector and sky plane, relative to the origin.
|
|
// This is the initial clip point used for the first scan line, the next clip point
|
|
// is calculated while the first scan line is being drawn..
|
|
f_clip = fSkyHeight / pv3_left->tZ;
|
|
|
|
__asm
|
|
{
|
|
mov ecx,[pu1_tex] // Texture pointer.
|
|
|
|
lea eax,MODIFY_FOR_TEXTUREPOINTER_A
|
|
mov [eax-4],ecx
|
|
|
|
lea eax,MODIFY_FOR_TEXTUREPOINTER_B
|
|
mov [eax-4],ecx
|
|
|
|
lea eax,MODIFY_FOR_TEXTUREPOINTER_C
|
|
mov [eax-4],ecx
|
|
|
|
lea eax,MODIFY_FOR_TEXTUREPOINTER_D
|
|
mov [eax-4],ecx
|
|
|
|
lea eax,MODIFY_FOR_TEXTUREPOINTER_E
|
|
mov [eax-4],ecx
|
|
|
|
lea eax,MODIFY_FOR_TEXTUREPOINTER_F
|
|
mov [eax-4],ecx
|
|
|
|
lea eax,MODIFY_FOR_TEXTUREPOINTER_G
|
|
mov [eax-4],ecx
|
|
|
|
lea eax,MODIFY_FOR_TEXTUREPOINTER_H
|
|
mov [eax-4],ecx
|
|
}
|
|
|
|
int i_line;
|
|
int i_lines_drawn;
|
|
|
|
// while not at the horizion and there are scan lines left.
|
|
bool b_done = false;
|
|
while (!b_done)
|
|
{
|
|
SaveValues* psv_saved = &asv_saved[0];
|
|
|
|
i_lines_drawn = iRENDER_BLOCK_SIZE;
|
|
|
|
// Do first block.
|
|
for (i_line = 0; i_line < iRENDER_BLOCK_SIZE; i_line++)
|
|
{
|
|
// Early out if necessary.
|
|
if (pv3_left->tZ <= fSKY_HORIZON_Z || u4_lines >= u4ScreenHeight)
|
|
{
|
|
b_done = true;
|
|
i_lines_drawn = i_lines_drawn + i_line - iRENDER_BLOCK_SIZE;
|
|
break;
|
|
}
|
|
|
|
// calculate the fog band based on the Z component the ray vectors for this scan line,
|
|
// we need to shift down u4DEFAULT_SKY_FOG_BITS because the linear version does not
|
|
// use the fog fraction.
|
|
i4_fog = (int32)((1.0f - fabs(pv3_left->tZ) - fFogNear) * fFogScale) >> u4DEFAULT_SKY_FOG_BITS;
|
|
|
|
//
|
|
// clamp the fog bands to the definded range...
|
|
// If we above or equal to the last fog band then we can set the whole scan line to
|
|
// a flat shaded colour.
|
|
//
|
|
if (i4_fog < 0)
|
|
{
|
|
i4_fog = 0;
|
|
}
|
|
else if (i4_fog >= iNUM_SKY_FOG_BANDS-1)
|
|
{
|
|
// next ray cast vectors...
|
|
*pv3_left += v3_delta_left;
|
|
*pv3_right += v3_delta_right;
|
|
|
|
// fire off the divide
|
|
f_clip = fSkyHeight / (pv3_left->tZ);
|
|
|
|
// fill 1 scan line
|
|
FillSky(pu2Raster, u4ScreenWidth, 0, 1, u4Fog);
|
|
|
|
// Deduct this line from the number to texture.
|
|
i_lines_drawn--;
|
|
|
|
// goto the next address
|
|
pu2Raster = pu2Raster + i4Pitch;
|
|
u4_lines++;
|
|
continue;
|
|
}
|
|
|
|
// calculate the intersection points with the sky plane, scale it and convert it to
|
|
// 16.16 fixed point.
|
|
fp_u = (uint32)(((v3Camera.tX + (pv3_left->tX * f_clip)) * fScale) + fSkyOffsetU);
|
|
fp_v = (uint32)(((v3Camera.tY + (pv3_left->tY * f_clip)) * fScale) + fSkyOffsetV);
|
|
|
|
// scale the f_clip by the screen width scale so the U,V deltas come out from below
|
|
// ready scaled.
|
|
// fScreenWidthScaleRep contains a scale of 65536.0 to adjust for the fixed point
|
|
f_clip *= fScreenWidthScaleRep;
|
|
|
|
// vec_right and vec_left contain the intersection points of the frustum vectors for
|
|
// this scan line and the sky plane (in world space, with constant height).
|
|
// The UVs are calculated as the difference between these positions divided by the
|
|
// number of steps/pixels in the screen width.
|
|
// These deltas are then scaled by the pixel/world size and the fixed point constant
|
|
// 65536.0f
|
|
fp_delta_u = (uint32)(((pv3_right->tX) - (pv3_left->tX)) * f_clip);
|
|
fp_delta_v = (uint32)(((pv3_right->tY) - (pv3_left->tY)) * f_clip);
|
|
|
|
// calculate the ray cast vectors for the next scan line
|
|
*pv3_left += v3_delta_left;
|
|
*pv3_right += v3_delta_right;
|
|
|
|
__asm
|
|
{
|
|
mov ecx,this // Load object pointer.
|
|
mov eax,[pv3_left] // Load vertex pointer.
|
|
|
|
fld [ecx]myCSkyRender.fSkyHeight // Load sky height.
|
|
fdiv [eax]CVector3_float.tZ // fSkyHeight / (pv3_left->tZ)
|
|
// Overlap division with scanline.
|
|
|
|
//
|
|
// Per scanline loop.
|
|
//
|
|
lea esi,[ecx]myCSkyRender.u2FogTable // Pointer to fog table.
|
|
mov eax,[i4_fog] // Load fog value.
|
|
|
|
shl eax,8 // Shift for width of table.
|
|
mov ebx,[ecx]myCSkyRender.pu2Raster // Pointer to destination.
|
|
|
|
mov edi,iRENDER_BLOCK_SIZE // Load width of scanline.
|
|
add esi,eax // Adjust fog table base for i4_fog.
|
|
|
|
push ebp // Save ebp.
|
|
mov [pvFogPointer],esi // Global fog pointer.
|
|
|
|
lea ecx,[ebx+edi*2] // Start + width of scanline.
|
|
mov eax,[fp_u] // Load fixed point U.
|
|
|
|
neg edi // Negative width.
|
|
|
|
mov [pvBaseOfLine],ecx // One past end of scanline pointer.
|
|
mov ebx,[fp_v] // Load fixed point V.
|
|
|
|
//
|
|
// eax = fp_u
|
|
// ebx = fp_v
|
|
// ecx = pvBaseOfLine
|
|
// edi = -width
|
|
//
|
|
sar eax,16 // integral u
|
|
mov esi,[fp_delta_u] // u step
|
|
|
|
sar ebx,(16 - 9) // integral v
|
|
and eax,0xff // mask u for tiling
|
|
|
|
and ebx,(0xff << 9) // mask v for tiling
|
|
mov ecx,[fp_delta_v] // v step
|
|
|
|
sar esi,16 // shift for integral u
|
|
add eax,ebx // integer start
|
|
|
|
sar ecx,(16 - 9) // shift for integral v
|
|
mov edx,eax // copy to edx
|
|
|
|
and ecx,(0xffffffff << 9) // mask fractiontal bits
|
|
mov eax,[fp_delta_u] // u step
|
|
|
|
add ecx,esi // add integer and frational parts
|
|
mov ebx,[fp_delta_v] // v step
|
|
|
|
shl eax,16
|
|
mov [ai_uvdelta+4],ecx
|
|
|
|
shl ebx,16
|
|
add ecx,(1 << 9) // Add one line to step.
|
|
|
|
mov [ai_uvdelta],ecx
|
|
mov [i_ufrac_delta],eax
|
|
|
|
mov [i_vfrac_delta],ebx
|
|
mov esi,[fp_u] // get copy of u
|
|
|
|
shl esi,16 // u fraction
|
|
mov ecx,[fp_v] // get copy of v
|
|
|
|
shl ecx,16 // v fraction
|
|
mov ebp,[pvBaseOfLine]
|
|
|
|
//
|
|
// eax = 0
|
|
// ecx = vfrac
|
|
// edx = integer offset
|
|
// esi = ufrac
|
|
//
|
|
xor eax,eax
|
|
lea ebp,[ebp+edi*2]
|
|
|
|
and ebp,3
|
|
jz ALIGNED
|
|
|
|
// Check for one pixel before starting.
|
|
inc edi
|
|
jz FINISH_REMAINDER
|
|
|
|
// Do one pixel to align?
|
|
mov al,[edx + 0xDEADBEEF] // Read texture value.
|
|
MODIFY_FOR_TEXTUREPOINTER_A:
|
|
mov ebx,[i_vfrac_delta] // Load V fraction.
|
|
|
|
add ecx,ebx // Step V fraction.
|
|
mov ebx,[pvFogPointer] // Load base of fog table.
|
|
|
|
sbb ebp,ebp // Get borrow from V fraction step.
|
|
mov cl,[eax*2 + ebx] // Do CLUT lookup (low).
|
|
|
|
mov ch,[eax*2 + ebx + 1] // Do CLUT lookup (high).
|
|
mov ebx,[i_ufrac_delta] // Load U fraction.
|
|
|
|
add esi,ebx // Step U fraction.
|
|
/*
|
|
mov ebp,[pvBaseOfLine] // Load pointer to destination.
|
|
|
|
adc edx,ai_uvdelta[ebp*4 + 4] // integer step.
|
|
*/
|
|
adc edx,ai_uvdelta[ebp*4 + 4] // integer step.
|
|
mov ebp,[pvBaseOfLine] // Load pointer to destination.
|
|
|
|
mov [ebp + edi*2 - 2],cx // Store pixel.
|
|
and edx,((0xff << 9) | 0xff) // Mask for tiling.
|
|
|
|
ALIGNED:
|
|
add edi,2
|
|
jg FINISH_REMAINDER
|
|
|
|
X_LOOP:
|
|
mov al,[edx + 0xDEADBEEF] // Read texture value.
|
|
MODIFY_FOR_TEXTUREPOINTER_B:
|
|
mov ebx,[i_vfrac_delta] // Load V fraction delta.
|
|
|
|
add ecx,ebx // Step V fraction.
|
|
mov ebx,[i_ufrac_delta] // Load U fraction delta.
|
|
|
|
sbb ebp,ebp // Get carry from V fraction step.
|
|
add esi,ebx // Step U fraction.
|
|
|
|
adc edx,ai_uvdelta[ebp*4 + 4] // Integer step.
|
|
add ecx,[i_vfrac_delta] // Step V fraction.
|
|
|
|
sbb ebp,ebp // Get carry from V fraction step.
|
|
mov ebx,[pvFogPointer] // Load base of fog table.
|
|
|
|
and edx,((0xff << 9) | 0xff) // Mask for tiling.
|
|
nop
|
|
|
|
mov ch,[eax*2 + ebx] // Do CLUT lookup (low).
|
|
mov ebp,ai_uvdelta[ebp*4 + 4] // Integer step based on carry.
|
|
|
|
mov cl,[eax*2 + ebx + 1] // Do CLUT lookup (high).
|
|
mov ebx,[i_ufrac_delta] // Load U fraction delta.
|
|
|
|
add esi,ebx // Step U fraction.
|
|
mov al,[edx + 0xDEADBEEF] // Read texture value.
|
|
MODIFY_FOR_TEXTUREPOINTER_C:
|
|
|
|
adc edx,ebp // Integer step + u carry.
|
|
mov ebp,[pvFogPointer] // Load base of fog table.
|
|
|
|
and edx,((0xff << 9) | 0xff) // Mask for tiling.
|
|
mov ebx,ecx // Copy first pixel.
|
|
|
|
shl ebx,16 // Shift first pixel up.
|
|
|
|
mov bh,[eax*2 + ebp] // Do CLUT lookup (low).
|
|
add edi,2 // Step count.
|
|
|
|
mov bl,[eax*2 + ebp + 1] // Do CLUT lookup (high).
|
|
mov ebp,[pvBaseOfLine] // Load pointer to destination.
|
|
|
|
bswap ebx // Reverse pixels.
|
|
|
|
mov [ebp + edi*2 - 8],ebx // Store pixel.
|
|
jle X_LOOP
|
|
|
|
FINISH_REMAINDER:
|
|
cmp edi,1
|
|
jne LINE_DONE
|
|
|
|
// Do left over pixel.
|
|
mov al,[edx + 0xDEADBEEF] // Read texture value.
|
|
MODIFY_FOR_TEXTUREPOINTER_D:
|
|
mov ebx,[pvFogPointer] // Load base of fog table.
|
|
|
|
mov cl,[eax*2 + ebx] // Do CLUT lookup (low).
|
|
mov ebp,[pvBaseOfLine] // Load pointer to destination.
|
|
|
|
mov ch,[eax*2 + ebx + 1] // Do CLUT lookup (high).
|
|
|
|
mov [ebp - 2],cx // Store pixel.
|
|
|
|
LINE_DONE:
|
|
pop ebp // Restore ebp.
|
|
|
|
//
|
|
// Save updated values.
|
|
//
|
|
mov eax,[pvFogPointer]
|
|
mov ebx,[pvBaseOfLine]
|
|
|
|
mov edi,[psv_saved]
|
|
|
|
fstp [f_clip] // Store f_clip
|
|
|
|
mov [edi]SaveValues.i_uvint,edx
|
|
mov [edi]SaveValues.i_ufrac,esi
|
|
|
|
mov [edi]SaveValues.i_vfrac,ecx
|
|
|
|
mov [edi]SaveValues.pu2_dest,ebx
|
|
mov [edi]SaveValues.pv_fog,eax
|
|
|
|
mov eax,ai_uvdelta[0]
|
|
mov ebx,ai_uvdelta[4]
|
|
|
|
mov [edi]SaveValues.ai_uvdelta[0],eax
|
|
mov [edi]SaveValues.ai_uvdelta[4],ebx
|
|
|
|
mov eax,[i_ufrac_delta]
|
|
mov ebx,[i_vfrac_delta]
|
|
|
|
mov [edi]SaveValues.i_ufrac_delta,eax
|
|
mov [edi]SaveValues.i_vfrac_delta,ebx
|
|
}
|
|
|
|
psv_saved++;
|
|
|
|
// we have done a scan line so adjust the start pointer to the next
|
|
pu2Raster = pu2Raster + i4Pitch;
|
|
u4_lines++;
|
|
}
|
|
|
|
// Do subsequent blocks.
|
|
for (int i_pixel = iRENDER_BLOCK_SIZE; i_pixel < u4ScreenWidth; i_pixel += iRENDER_BLOCK_SIZE)
|
|
{
|
|
psv_saved = &asv_saved[0];
|
|
int i4_width = std::min(iRENDER_BLOCK_SIZE, (int)u4ScreenWidth - i_pixel);
|
|
|
|
for (i_line = 0; i_line < i_lines_drawn; i_line++)
|
|
{
|
|
__asm
|
|
{
|
|
//
|
|
// Load saved values.
|
|
//
|
|
mov edi,[psv_saved]
|
|
|
|
mov edx,[edi]SaveValues.i_uvint
|
|
mov esi,[edi]SaveValues.i_ufrac
|
|
|
|
mov ecx,[edi]SaveValues.i_vfrac
|
|
|
|
mov eax,[edi]SaveValues.ai_uvdelta[0]
|
|
mov ebx,[edi]SaveValues.ai_uvdelta[4]
|
|
|
|
mov ai_uvdelta[0],eax
|
|
mov ai_uvdelta[4],ebx
|
|
|
|
mov eax,[edi]SaveValues.i_ufrac_delta
|
|
mov ebx,[edi]SaveValues.i_vfrac_delta
|
|
|
|
mov [i_ufrac_delta],eax
|
|
mov [i_vfrac_delta],ebx
|
|
|
|
mov ebx,[edi]SaveValues.pu2_dest
|
|
mov eax,[edi]SaveValues.pv_fog
|
|
|
|
mov edi,[i4_width]
|
|
push ebp
|
|
|
|
mov [pvFogPointer],eax // Global fog pointer.
|
|
|
|
lea ebp,[ebx+edi*2] // Start + width of scanline.
|
|
|
|
neg edi
|
|
|
|
mov [pvBaseOfLine],ebp // End of line pointer.
|
|
|
|
//
|
|
// ecx = vfrac
|
|
// edx = integer uv
|
|
// esi = ufrac
|
|
// edi = -width
|
|
//
|
|
// pvBaseOfLine, pvFogPointer set.
|
|
//
|
|
xor eax,eax
|
|
and ebx,3
|
|
|
|
jz ALIGNED2
|
|
|
|
// Check for one pixel before starting.
|
|
inc edi
|
|
jz FINISH_REMAINDER2
|
|
|
|
// Do one pixel to align?
|
|
mov al,[edx + 0xDEADBEEF] // Read texture value.
|
|
MODIFY_FOR_TEXTUREPOINTER_E:
|
|
mov ebx,[i_vfrac_delta] // Load V fraction.
|
|
|
|
add ecx,ebx // Step V fraction.
|
|
mov ebx,[pvFogPointer] // Load base of fog table.
|
|
|
|
sbb ebp,ebp // Get borrow from V fraction step.
|
|
mov cl,[eax*2 + ebx] // Do CLUT lookup (low).
|
|
|
|
mov ch,[eax*2 + ebx + 1] // Do CLUT lookup (high).
|
|
mov ebx,[i_ufrac_delta] // Load U fraction.
|
|
|
|
add esi,ebx // Step U fraction.
|
|
/*
|
|
mov ebp,[pvBaseOfLine] // Load pointer to destination.
|
|
|
|
adc edx,ai_uvdelta[ebp*4 + 4] // integer step.
|
|
*/
|
|
adc edx,ai_uvdelta[ebp*4 + 4] // integer step.
|
|
mov ebp,[pvBaseOfLine] // Load pointer to destination.
|
|
|
|
mov [ebp + edi*2 - 2],cx // Store pixel.
|
|
and edx,((0xff << 9) | 0xff) // Mask for tiling.
|
|
|
|
ALIGNED2:
|
|
add edi,2
|
|
jg FINISH_REMAINDER2
|
|
|
|
X_LOOP2:
|
|
mov al,[edx + 0xDEADBEEF] // Read texture value.
|
|
MODIFY_FOR_TEXTUREPOINTER_F:
|
|
mov ebx,[i_vfrac_delta] // Load V fraction delta.
|
|
|
|
add ecx,ebx // Step V fraction.
|
|
mov ebx,[i_ufrac_delta] // Load U fraction delta.
|
|
|
|
sbb ebp,ebp // Get carry from V fraction step.
|
|
add esi,ebx // Step U fraction.
|
|
|
|
adc edx,ai_uvdelta[ebp*4 + 4] // Integer step.
|
|
add ecx,[i_vfrac_delta] // Step V fraction.
|
|
|
|
sbb ebp,ebp // Get carry from V fraction step.
|
|
mov ebx,[pvFogPointer] // Load base of fog table.
|
|
|
|
and edx,((0xff << 9) | 0xff) // Mask for tiling.
|
|
nop
|
|
|
|
mov ch,[eax*2 + ebx] // Do CLUT lookup (low).
|
|
mov ebp,ai_uvdelta[ebp*4 + 4] // Integer step based on carry.
|
|
|
|
mov cl,[eax*2 + ebx + 1] // Do CLUT lookup (high).
|
|
mov ebx,[i_ufrac_delta] // Load U fraction delta.
|
|
|
|
add esi,ebx // Step U fraction.
|
|
mov al,[edx + 0xDEADBEEF] // Read texture value.
|
|
MODIFY_FOR_TEXTUREPOINTER_G:
|
|
|
|
adc edx,ebp // Integer step + u carry.
|
|
mov ebp,[pvFogPointer] // Load base of fog table.
|
|
|
|
and edx,((0xff << 9) | 0xff) // Mask for tiling.
|
|
mov ebx,ecx // Copy first pixel.
|
|
|
|
shl ebx,16 // Shift first pixel up.
|
|
|
|
mov bh,[eax*2 + ebp] // Do CLUT lookup (low).
|
|
add edi,2 // Step count.
|
|
|
|
mov bl,[eax*2 + ebp + 1] // Do CLUT lookup (high).
|
|
mov ebp,[pvBaseOfLine] // Load pointer to destination.
|
|
|
|
bswap ebx // Reverse pixels.
|
|
|
|
mov [ebp + edi*2 - 8],ebx // Store pixel.
|
|
jle X_LOOP2
|
|
|
|
FINISH_REMAINDER2:
|
|
cmp edi,1
|
|
jne LINE_DONE2
|
|
|
|
// Do left over pixel.
|
|
mov al,[edx + 0xDEADBEEF] // Read texture value.
|
|
MODIFY_FOR_TEXTUREPOINTER_H:
|
|
mov ebx,[pvFogPointer] // Load base of fog table.
|
|
|
|
mov cl,[eax*2 + ebx] // Do CLUT lookup (low).
|
|
mov ebp,[pvBaseOfLine] // Load pointer to destination.
|
|
|
|
mov ch,[eax*2 + ebx + 1] // Do CLUT lookup (high).
|
|
|
|
mov [ebp - 2],cx // Store pixel.
|
|
|
|
LINE_DONE2:
|
|
pop ebp // Restore ebp.
|
|
|
|
//
|
|
// Save updated values.
|
|
//
|
|
mov edi,[psv_saved]
|
|
mov ebx,[pvBaseOfLine]
|
|
|
|
mov [edi]SaveValues.i_uvint,edx
|
|
mov [edi]SaveValues.i_ufrac,esi
|
|
|
|
mov [edi]SaveValues.i_vfrac,ecx
|
|
mov [edi]SaveValues.pu2_dest,ebx
|
|
}
|
|
|
|
psv_saved++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if the fill flag is set and the screen was not filled by the sky then fill it with the
|
|
// back fog colour.
|
|
if (bFill && u4_lines < u4ScreenHeight)
|
|
{
|
|
FillSky
|
|
(
|
|
pu2Raster,
|
|
u4ScreenWidth,
|
|
((i4Pitch-(int32)u4ScreenWidth)*prasRenderSurface->iPixelBits/8),
|
|
u4ScreenHeight - u4_lines,
|
|
u4Fog
|
|
);
|
|
}
|
|
}
|
|
|
|
#pragma code_seg()
|
|
#pragma optimize("", on)
|
|
|
|
#elif (VER_ASM && TARGET_PROCESSOR == PROCESSOR_PENTIUMPRO)
|
|
|
|
//**********************************************************************************************
|
|
//
|
|
void CSkyRender::DrawSkyTexturedLinear()
|
|
//
|
|
//**************************************
|
|
{
|
|
CVector3<> v3_delta_left;
|
|
CVector3<> v3_delta_right;
|
|
CVector3<>* pv3_left;
|
|
CVector3<>* pv3_right;
|
|
float f_clip;
|
|
int32 i4_fog;
|
|
uint32 fp_u;
|
|
uint32 fp_v;
|
|
uint32 u4_lines = 0;
|
|
|
|
static uint8* pu1_tex;
|
|
static uint32 fp_delta_u;
|
|
static uint32 fp_delta_v;
|
|
static void* pvFogPointer;
|
|
static void* pvBaseOfLine;
|
|
|
|
pu1_tex = (uint8*)prasSkyTexture->pSurface;
|
|
|
|
//
|
|
// If the World space Z component of the frustum top left vector is negative then we are
|
|
// drawing from bottom to top of the screen.
|
|
//
|
|
if (av3FrustTran[0].tZ < fSKY_HORIZON_Z)
|
|
{
|
|
// we are drawing from bottom to top
|
|
// calculate the per scan line deltas..
|
|
v3_delta_left = (av3FrustTran[0] - av3FrustTran[2]) * fScreenHeightRep;
|
|
v3_delta_right = (av3FrustTran[1] - av3FrustTran[3]) * fScreenHeightRep;
|
|
|
|
// point to the base vector we are using (bottom in this case)
|
|
pv3_left = &av3FrustTran[2];
|
|
pv3_right = &av3FrustTran[3];
|
|
|
|
// adjust the screen pointer to point to the left edge of the last scanline
|
|
pu2Raster = pu2Raster + (i4Pitch*((int)u4ScreenHeight-1));
|
|
i4Pitch = - i4Pitch;
|
|
}
|
|
else
|
|
{
|
|
// we are drawing from top to bottom
|
|
// calculate the per scan line deltas..
|
|
v3_delta_left = (av3FrustTran[2] - av3FrustTran[0]) * fScreenHeightRep;
|
|
v3_delta_right = (av3FrustTran[3] - av3FrustTran[1]) * fScreenHeightRep;
|
|
|
|
// point to the base vector we are using (bottom in this case)
|
|
pv3_left = &av3FrustTran[0];
|
|
pv3_right = &av3FrustTran[1];
|
|
}
|
|
|
|
//Assert(iNUM_SKY_COLOURS == 64);
|
|
|
|
typedef CVector3<> CVector3_float;
|
|
typedef CSkyRender myCSkyRender;
|
|
static int32 i_ufrac_delta;
|
|
static int32 i_vfrac_delta;
|
|
static int32 ai_uvdelta[2];
|
|
|
|
// get the parametric clip point for the vector and sky plane, relative to the origin.
|
|
// This is the initial clip point used for the first scan line, the next clip point
|
|
// is calculated while the first scan line is being drawn..
|
|
f_clip = fSkyHeight / pv3_left->tZ;
|
|
|
|
// while not at the horizion and there are scan lines left.
|
|
while ( (pv3_left->tZ>fSKY_HORIZON_Z) && (u4_lines<u4ScreenHeight) )
|
|
{
|
|
// calculate the fog band based on the Z component the ray vectors for this scan line,
|
|
// we need to shift down u4DEFAULT_SKY_FOG_BITS because the linear version does not
|
|
// use the fog fraction.
|
|
i4_fog = (int32) ((1.0f - fabs(pv3_left->tZ) - fFogNear) * fFogScale)>>u4DEFAULT_SKY_FOG_BITS;
|
|
|
|
//
|
|
// clamp the fog bands to the definded range...
|
|
// If we above or equal to the last fog band then we can set the whole scan line to
|
|
// a flat shaded colour.
|
|
//
|
|
if (i4_fog<0)
|
|
{
|
|
i4_fog = 0;
|
|
}
|
|
else if (i4_fog>=iNUM_SKY_FOG_BANDS-1)
|
|
{
|
|
// next ray cast vectors...
|
|
*pv3_left+=v3_delta_left;
|
|
*pv3_right+=v3_delta_right;
|
|
|
|
// fire off the divide
|
|
f_clip = fSkyHeight / (pv3_left->tZ);
|
|
|
|
// fill 1 scan line
|
|
FillSky(pu2Raster,u4ScreenWidth,0,1, u4Fog);
|
|
|
|
// goto the next address
|
|
pu2Raster = pu2Raster + i4Pitch;
|
|
u4_lines++;
|
|
continue;
|
|
}
|
|
|
|
// calculate the intersection points with the sky plane, scale it and convert it to
|
|
// 16.16 fixed point.
|
|
fp_u = (uint32) ( ((v3Camera.tX+(pv3_left->tX*f_clip))*fScale) + fSkyOffsetU);
|
|
fp_v = (uint32) ( ((v3Camera.tY+(pv3_left->tY*f_clip))*fScale) + fSkyOffsetV);
|
|
|
|
|
|
// scale the f_clip by the screen width scale so the U,V deltas come out from below
|
|
// ready scaled.
|
|
// fScreenWidthScaleRep contains a scale of 65536.0 to adjust for the fixed point
|
|
f_clip *= fScreenWidthScaleRep;
|
|
|
|
// vec_right and vec_left contain the intersection points of the frustum vectors for
|
|
// this scan line and the sky plane (in world space, with constant height).
|
|
// The UVs are calculated as the difference between these positions divided by the
|
|
// number of steps/pixels in the screen width.
|
|
// These deltas are then scaled by the pixel/world size and the fixed point constant
|
|
// 65536.0f
|
|
fp_delta_u = (uint32) ( ((pv3_right->tX) - (pv3_left->tX) ) * f_clip);
|
|
fp_delta_v = (uint32) ( ((pv3_right->tY) - (pv3_left->tY) ) * f_clip);
|
|
|
|
// calculate the ray cast vectors for the next scan line
|
|
*pv3_left+=v3_delta_left;
|
|
*pv3_right+=v3_delta_right;
|
|
|
|
__asm
|
|
{
|
|
mov ecx,this // Load object pointer.
|
|
mov eax,[pv3_left] // Load vertex pointer.
|
|
|
|
fld [ecx]myCSkyRender.fSkyHeight // Load sky height.
|
|
fdiv [eax]CVector3_float.tZ // fSkyHeight / (pv3_left->tZ)
|
|
// Overlap division with scanline.
|
|
|
|
//
|
|
// Per scanline loop.
|
|
//
|
|
lea esi,[ecx]myCSkyRender.u2FogTable // Pointer to fog table.
|
|
mov eax,[i4_fog] // Load fog value.
|
|
|
|
shl eax,8 // Shift for width of table.
|
|
mov ebx,[ecx]myCSkyRender.pu2Raster // Pointer to destination.
|
|
|
|
mov edi,[ecx]myCSkyRender.u4ScreenWidth // Load width of scanline.
|
|
add esi,eax // Adjust fog table base for i4_fog.
|
|
|
|
push ebp // Save ebp.
|
|
mov [pvFogPointer],esi // Global fog pointer.
|
|
|
|
lea ecx,[ebx+edi*2] // Start + width of scanline.
|
|
mov eax,[fp_u] // Load fixed point U.
|
|
|
|
neg edi // Negative width.
|
|
|
|
mov [pvBaseOfLine],ecx // One past end of scanline pointer.
|
|
mov ebx,[fp_v] // Load fixed point V.
|
|
|
|
X_LOOP:
|
|
mov ebp,eax // get copy of u
|
|
mov ecx,ebx // get copy of v
|
|
|
|
sar ebp,16 // integral u
|
|
mov esi,[pu1_tex] // load base of texture.
|
|
|
|
sar ecx,(16 - 9) // integral v
|
|
and ebp,0xff // mask u for tiling
|
|
|
|
and ecx,(0xff << 9) // mask v for tiling
|
|
add ebp,esi // add texture base to u.
|
|
|
|
xor edx,edx // Zero edx.
|
|
mov esi,[pvFogPointer] // load base of fog table.
|
|
|
|
mov dl,[ebp+ecx] // fetch pixel
|
|
mov ebp,[pvBaseOfLine] // base of end of line.
|
|
|
|
add eax,[fp_delta_u] // Step U.
|
|
add ebx,[fp_delta_v] // Step V.
|
|
|
|
mov dx,[esi + edx*2] // Lookup fogged pixel.
|
|
|
|
mov [ebp + edi*2],dx // Store pixel.
|
|
|
|
inc edi
|
|
jnz X_LOOP
|
|
|
|
pop ebp // Restore ebp.
|
|
|
|
fstp [f_clip] // Store f_clip
|
|
}
|
|
|
|
// we have done a scan line so adjust the start pointer to the next
|
|
pu2Raster = pu2Raster + i4Pitch;
|
|
u4_lines++;
|
|
}
|
|
|
|
// if the fill flag is set and the screen was not filled by the sky then fill it with the
|
|
// back fog colour.
|
|
if (bFill && u4_lines<u4ScreenHeight)
|
|
{
|
|
FillSky
|
|
(
|
|
pu2Raster,
|
|
u4ScreenWidth,
|
|
((i4Pitch-(int32)u4ScreenWidth)*prasRenderSurface->iPixelBits/8),
|
|
u4ScreenHeight - u4_lines,
|
|
u4Fog
|
|
);
|
|
}
|
|
}
|
|
|
|
#elif (VER_ASM && TARGET_PROCESSOR == PROCESSOR_K6_3D)
|
|
|
|
//**********************************************************************************************
|
|
//
|
|
struct SaveValues
|
|
//
|
|
// Values saved between scanlines.
|
|
//
|
|
//**************************************
|
|
{
|
|
uint64 pd_uv;
|
|
uint64 pd_uvstep;
|
|
void* pu2_dest;
|
|
void* pv_fog;
|
|
};
|
|
|
|
#define iRENDER_BLOCK_SIZE 64
|
|
|
|
#define ieeeSKY_HORIZON_Z 0x3d4ccccd
|
|
|
|
//**********************************************************************************************
|
|
//
|
|
void CSkyRender::DrawSkyTexturedLinear()
|
|
//
|
|
//**************************************
|
|
{
|
|
CVector3<> v3_delta_left;
|
|
CVector3<> v3_delta_right;
|
|
CVector3<>* pv3_left;
|
|
CVector3<>* pv3_right;
|
|
uint32 u4_lines;
|
|
uint8* pu1_tex;
|
|
SaveValues asv_saved[iRENDER_BLOCK_SIZE];
|
|
|
|
const float fOne = 1.0f;
|
|
const uint64 pdMFactor = 0x0200000102000001;
|
|
const uint64 pwUVMasks = 0x00ff00ff00ff00ff;
|
|
|
|
static uint64 pdIndexTemp;
|
|
|
|
typedef CVector3<> CVector3_float;
|
|
typedef CSkyRender myCSkyRender;
|
|
|
|
#if (VER_DEBUG)
|
|
//Assert(iNUM_SKY_COLOURS == 64);
|
|
float f_temp = fSKY_HORIZON_Z;
|
|
Assert(*(int *)&f_temp == ieeeSKY_HORIZON_Z);
|
|
#endif
|
|
|
|
u4_lines = 0;
|
|
pu1_tex = (uint8*)prasSkyTexture->pSurface;
|
|
|
|
//
|
|
// If the World space Z component of the frustum top left vector is negative then we are
|
|
// drawing from bottom to top of the screen.
|
|
//
|
|
if (av3FrustTran[0].tZ < fSKY_HORIZON_Z)
|
|
{
|
|
// we are drawing from bottom to top
|
|
// calculate the per scan line deltas..
|
|
v3_delta_left = (av3FrustTran[0] - av3FrustTran[2]) * fScreenHeightRep;
|
|
v3_delta_right = (av3FrustTran[1] - av3FrustTran[3]) * fScreenHeightRep;
|
|
|
|
// point to the base vector we are using (bottom in this case)
|
|
pv3_left = &av3FrustTran[2];
|
|
pv3_right = &av3FrustTran[3];
|
|
|
|
// adjust the screen pointer to point to the left edge of the last scanline
|
|
pu2Raster = pu2Raster + (i4Pitch*((int)u4ScreenHeight-1));
|
|
i4Pitch = - i4Pitch;
|
|
}
|
|
else
|
|
{
|
|
// we are drawing from top to bottom
|
|
// calculate the per scan line deltas..
|
|
v3_delta_left = (av3FrustTran[2] - av3FrustTran[0]) * fScreenHeightRep;
|
|
v3_delta_right = (av3FrustTran[3] - av3FrustTran[1]) * fScreenHeightRep;
|
|
|
|
// point to the base vector we are using (bottom in this case)
|
|
pv3_left = &av3FrustTran[0];
|
|
pv3_right = &av3FrustTran[1];
|
|
}
|
|
|
|
CVector3_float v3CameraCopy = v3Camera;
|
|
|
|
int b_done;
|
|
int i_line;
|
|
int i_lines_drawn;
|
|
int i_pixel;
|
|
int i_width;
|
|
SaveValues *psv_saved;
|
|
|
|
__asm
|
|
{
|
|
femms // ensure fast switch.
|
|
|
|
mov [b_done],0 // b_done = false
|
|
|
|
//
|
|
// while (!b_done)
|
|
//
|
|
SCANLINE_LOOP:
|
|
lea eax,[asv_saved]
|
|
mov ecx,iRENDER_BLOCK_SIZE
|
|
|
|
mov [psv_saved],eax // psv_saved = &asv_saved[0]
|
|
|
|
mov [i_lines_drawn],ecx // i_lines_drawn = iRENDER_BLOCK_SIZE
|
|
mov eax,[pv3_left] // left vertex.
|
|
|
|
mov ebx,0
|
|
mov esi,this // this pointer.
|
|
|
|
mov [i_line],ebx // i_line = 0
|
|
mov edx,[u4_lines] // number of lines to draw.
|
|
|
|
//
|
|
// for (i_line = 0; i_line < iRENDER_BLOCK_SIZE; i_line++)
|
|
//
|
|
// eax = pv3_left
|
|
// ebx = i_line
|
|
// edx = u4_lines
|
|
// esi = this
|
|
//
|
|
FIRST_BLOCK_LINE_LOOP:
|
|
cmp ebx,iRENDER_BLOCK_SIZE
|
|
jge EXIT_FB_LINE_LOOP
|
|
|
|
//
|
|
// Early out of loop if needed.
|
|
//
|
|
mov ebx,[eax]CVector3_float.tZ
|
|
|
|
mov ecx,[esi]myCSkyRender.u4ScreenHeight
|
|
|
|
cmp ebx,ieeeSKY_HORIZON_Z // pv3_left->tZ > fSKY_HORIZON_Z
|
|
jle EXIT_FB_LINE_LOOP_FINISHED
|
|
|
|
movd mm1,ebx // pv3_left->tZ
|
|
and ebx,0x7fffffff // fabs(pv3_left->tZ)
|
|
|
|
cmp edx,ecx // u4_lines < u4ScreenHeight
|
|
jge EXIT_FB_LINE_LOOP_FINISHED
|
|
|
|
// i4_fog = (int32) ((1.0f - fabs(pv3_left->tZ) - fFogNear) * fFogScale)>>u4DEFAULT_SKY_FOG_BITS;
|
|
movd mm2,ebx
|
|
|
|
movd mm3,[fOne]
|
|
|
|
movd mm4,[esi]myCSkyRender.fFogNear
|
|
|
|
movd mm5,[esi]myCSkyRender.fFogScale
|
|
pfsubr (m2,m3)
|
|
|
|
pfsub (m2,m4)
|
|
|
|
pfmul (m2,m5)
|
|
|
|
pf2id (m2,m2)
|
|
|
|
movd ebx,mm2
|
|
|
|
sar ebx,u4DEFAULT_SKY_FOG_BITS
|
|
|
|
cmp ebx,0
|
|
jge I4FOG_POSITIVE
|
|
|
|
mov ebx,0
|
|
jmp short I4FOG_IN_RANGE
|
|
|
|
I4FOG_POSITIVE:
|
|
cmp ebx,iNUM_SKY_FOG_BANDS-1
|
|
jl I4FOG_IN_RANGE
|
|
|
|
// FillSky(pu2Raster, u4ScreenWidth, 0, 1, u4Fog);
|
|
mov ebx,[esi]myCSkyRender.u4Fog
|
|
|
|
mov eax,[esi]myCSkyRender.u4ScreenWidth
|
|
|
|
movd mm0,ebx
|
|
|
|
mov edi,[esi]myCSkyRender.pu2Raster
|
|
punpckldq mm0,mm0
|
|
|
|
// align to a 64 bit boundardry
|
|
ALIGN_64:
|
|
test edi,7 // are we aligned to a 64 bit (8 byte) boundary??
|
|
jz ALIGNED_64
|
|
mov [edi],bx
|
|
add edi,2
|
|
dec eax
|
|
jnz ALIGN_64
|
|
jmp short FILLSKY_DONE
|
|
|
|
ALIGNED_64:
|
|
sub eax,8 // can we do 8 pixels (16 bytes)
|
|
jl FINISH_X
|
|
|
|
LOOPX:
|
|
movq [edi],mm0
|
|
|
|
movq [edi+8],mm0
|
|
add edi,16
|
|
|
|
sub eax,8 // can we do 8 pixels (16 bytes)
|
|
jge LOOPX
|
|
|
|
FINISH_X:
|
|
add eax,8
|
|
jz FILLSKY_DONE
|
|
|
|
LOOP_FINISH_X:
|
|
mov [edi],bx
|
|
add edi,2
|
|
dec eax
|
|
jnz LOOP_FINISH_X
|
|
|
|
FILLSKY_DONE:
|
|
dec [i_lines_drawn] // i_lines_drawn--
|
|
jmp END_OF_SCANLINE_NO_SAVE
|
|
|
|
I4FOG_IN_RANGE:
|
|
// f_clip = fSkyHeight / pv3_left->tZ;
|
|
// fp_u = (uint32) (((v3Camera.tX + (pv3_left->tX * f_clip)) * fScale) + fSkyOffsetU);
|
|
// fp_v = (uint32) (((v3Camera.tY + (pv3_left->tY * f_clip)) * fScale) + fSkyOffsetV);
|
|
// fp_delta_u = (uint32) (((pv3_right->tX) - (pv3_left->tX)) * f_clip * fScreenWidthScaleRep);
|
|
// fp_delta_v = (uint32) (((pv3_right->tY) - (pv3_left->tY)) * f_clip * fScreenWidthScaleRep);
|
|
pfrcp (m1,m1)
|
|
movd mm0,[esi]myCSkyRender.fSkyHeight
|
|
|
|
mov ecx,[pv3_right]
|
|
|
|
pfmul (m0,m1)
|
|
|
|
movq mm7,[eax]CVector3_float.tX
|
|
|
|
movq mm6,[ecx]CVector3_float.tX
|
|
punpckldq mm0,mm0
|
|
|
|
movq mm1,[v3CameraCopy.tX]
|
|
|
|
pfsub (m6,m7)
|
|
pfmul (m7,m0)
|
|
|
|
pfadd (m7,m1)
|
|
movq mm2,[esi]myCSkyRender.fScale
|
|
|
|
punpckldq mm2,mm2
|
|
|
|
pfmul (m7,m2)
|
|
|
|
movd mm3,[esi]myCSkyRender.fSkyOffsetU
|
|
|
|
punpckldq mm3,[esi]myCSkyRender.fSkyOffsetV
|
|
|
|
pfadd (m7,m3)
|
|
|
|
pfmul (m6,m0)
|
|
|
|
movd mm4,[esi]myCSkyRender.fScreenWidthScaleRep
|
|
|
|
punpckldq mm4,mm4
|
|
|
|
pfmul (m6,m4)
|
|
|
|
pf2id (m7,m7) // Convert texture values to 16.16 fixed.
|
|
|
|
pf2id (m6,m6) // Convert texture values to 16.16 fixed.
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Draw the scanline.
|
|
//
|
|
// mm6,mm7 = texture values.
|
|
//
|
|
// Setup registers:
|
|
//
|
|
// eax = texel_index2 ebx = texel_index1
|
|
// ecx = fog_table_ptr edx = dest_base_ptr
|
|
// esi = texture_base_ptr edi = pixel_offset & count
|
|
// ebp = base pointer
|
|
//
|
|
// mm0 = temp mm1 = temp
|
|
// mm2 = mfactor (512,1) mm3 = uvmask (0x00ff, 0x00ff, 0x00ff, 0x00ff)
|
|
// mm6 = uvslope mm7 = uv (stepped once)
|
|
//
|
|
lea ecx,[esi]myCSkyRender.u2FogTable // Pointer to fog table.
|
|
|
|
shl ebx,8 // Shift for width of table.
|
|
|
|
add ecx,ebx // Adjust fog table base for i4_fog.
|
|
|
|
sub ecx,4 // Hack to force SIB + offset in loop
|
|
|
|
mov edx,[esi]myCSkyRender.pu2Raster // Pointer to destination.
|
|
|
|
mov edi,iRENDER_BLOCK_SIZE // Load width of scanline.
|
|
|
|
lea edx,[edx+edi*2] // Start + width of scanline.
|
|
|
|
neg edi // Negative width.
|
|
|
|
movq mm2,[pdMFactor] // Load [width,1]
|
|
|
|
movq mm3,[pwUVMasks] // Load masks.
|
|
|
|
movq mm0,mm7 // Copy U1,V1
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
movq mm1,mm7 // Copy U2,V2
|
|
|
|
psrad mm1,16 // Shift for integer U2,V2
|
|
|
|
packssdw mm0,mm1 // Pack integer texture values
|
|
|
|
pand mm0,mm3 // Mask for tiling
|
|
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
mov esi,[pu1_tex] // load base of texture.
|
|
|
|
sub esi,4 // Hack to force SIB + offset in loop
|
|
|
|
//
|
|
// Align to a quadword boundry.
|
|
//
|
|
lea eax,[edx + edi*2]
|
|
|
|
and eax,3
|
|
jz ALIGNED2_A
|
|
|
|
inc edi // One pixel left?
|
|
jz ONE_PIXEL_LEFT_A
|
|
|
|
//
|
|
// Do one pixel for alignment.
|
|
//
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
movq mm0,mm7 // Copy U1,V1
|
|
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
packssdw mm1,mm0 // Pack integer texture values.
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
movq mm0,mm1 // Put values back into mm0
|
|
|
|
pand mm0,mm3 // Mask for tiling
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 1
|
|
lea eax,[edx + edi*2]
|
|
|
|
mov [edx + edi*2 - 2],bx // Store pixel
|
|
|
|
ALIGNED2_A:
|
|
and eax,7
|
|
jz ALIGNED4_A
|
|
|
|
add edi,2 // Two pixels left?
|
|
jge FINISH_REMAINDER2_A
|
|
|
|
//
|
|
// Do two pixels for alignment.
|
|
//
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
movq mm0,mm7 // Copy U1,V1
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
movq mm1,mm7 // Copy U2,V2
|
|
|
|
psrad mm1,16 // Shift for integer U2,V2
|
|
packssdw mm0,mm1 // Pack integer texture values.
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 1
|
|
pand mm0,mm3 // Mask for tiling
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 2
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
shl eax,16 // Shift pixel 2 up.
|
|
or ebx,eax // Combine pixels.
|
|
|
|
mov [edx + edi*2 - 4],ebx // Store pixels
|
|
|
|
ALIGNED4_A:
|
|
add edi,4
|
|
jl INNER_LOOP_4P_A // Four pixles left?
|
|
|
|
jmp FINISH_REMAINDER4_A
|
|
|
|
// Align start of loop to 0 past the beginning of a cache line.
|
|
ALIGN 16
|
|
|
|
//
|
|
// Do four pixels at a time.
|
|
//
|
|
// mm0 = packed & masked U1,V1,U2,V2
|
|
// mm7 is stepped once.
|
|
//
|
|
INNER_LOOP_4P_A:
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
movq mm0,mm7 // Copy U1,V1
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
movq mm1,mm7 // Copy U2,V2
|
|
|
|
psrad mm1,16 // Shift for integer U2,V2
|
|
packssdw mm0,mm1 // Pack integer texture values.
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 2
|
|
pand mm0,mm3 // Mask for tiling
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 1
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
shl eax,16 // Shift second pixel up.
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
|
|
or ebx,eax // Combine 2 pixels.
|
|
movd mm4,ebx // Put in MMX register.
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
movq mm0,mm7 // Copy U1,V1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
movq mm1,mm7 // Copy U2,V2
|
|
psrad mm1,16 // Shift for integer U2,V2
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 2
|
|
packssdw mm0,mm1 // Pack integer texture values.
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 1
|
|
pand mm0,mm3 // Mask for tiling
|
|
|
|
shl eax,16 // Shift second pixel up.
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
or ebx,eax // Combine 2 pixels.
|
|
movd mm1,ebx // Put in MMX register.
|
|
|
|
punpckldq mm4,mm1 // Combine all four pixels.
|
|
movq [edx + edi*2 - 8],mm4 // Store 4 pixels
|
|
|
|
add edi,4 // Inrcement index by 4
|
|
jl INNER_LOOP_4P_A // Loop (while >4 pixels)
|
|
|
|
FINISH_REMAINDER4_A:
|
|
//
|
|
// One (edi == 3), two (edi == 2), three (edi == 1) or four (edi == 0) pixels left.
|
|
//
|
|
jnz THREE_OR_LESS_A
|
|
|
|
//
|
|
// Four pixels left, step co-ordinates 3 times.
|
|
//
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
movq mm0,mm7 // Copy U1,V1
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
movq mm1,mm7 // Copy U2,V2
|
|
|
|
psrad mm1,16 // Shift for integer U2,V2
|
|
packssdw mm0,mm1 // Pack integer texture values.
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 2
|
|
pand mm0,mm3 // Mask for tiling
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 1
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
shl eax,16 // Shift second pixel up.
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
|
|
or ebx,eax // Combine 2 pixels.
|
|
movd mm4,ebx // Put in MMX register.
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 2
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 1
|
|
|
|
shl eax,16 // Shift second pixel up.
|
|
|
|
or ebx,eax // Combine 2 pixels.
|
|
movd mm1,ebx // Put in MMX register.
|
|
|
|
punpckldq mm4,mm1 // Combine all four pixels.
|
|
movq [edx - 8],mm4 // Store 4 pixels
|
|
|
|
jmp END_OF_SCANLINE_A
|
|
|
|
THREE_OR_LESS_A:
|
|
sub edi,2
|
|
jge FINISH_REMAINDER2_A
|
|
|
|
//
|
|
// Three pixels left, step co-ordinates twice.
|
|
//
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
movq mm0,mm7 // Copy U1,V1
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
movq mm1,mm7 // Copy U2,V2
|
|
|
|
psrad mm1,16 // Shift for integer U2,V2
|
|
packssdw mm0,mm1 // Pack integer texture values.
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 1
|
|
pand mm0,mm3 // Mask for tiling
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 2
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
shl eax,16 // Shift pixel 2 up.
|
|
or ebx,eax // Combine pixels.
|
|
|
|
mov [edx - 6],ebx // Store pixels
|
|
|
|
movd ebx,mm0 // Get texture index 1
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
|
|
mov bx,word ptr[ecx + ebx*2 + 4] // Clut lookup for p1
|
|
|
|
mov [edx - 2],bx // Store pixel 1
|
|
|
|
jmp short END_OF_SCANLINE_A
|
|
|
|
FINISH_REMAINDER2_A:
|
|
//
|
|
// One pixel (edi == 1) or two pixels (edi == 0) left.
|
|
//
|
|
jnz ONE_PIXEL_LEFT_A
|
|
|
|
//
|
|
// Two pixels left, only step texture co-ordinates once.
|
|
//
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 2
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 1
|
|
|
|
shl eax,16 // Shift pixel 2 up.
|
|
or ebx,eax // Combine pixels.
|
|
|
|
mov [edx - 4],ebx // Store pixels
|
|
|
|
jmp short END_OF_SCANLINE_A
|
|
|
|
ONE_PIXEL_LEFT_A:
|
|
//
|
|
// One pixel left, don't step texture co-ordinates.
|
|
//
|
|
movd ebx,mm0 // Get texture index 1
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
|
|
mov bx,word ptr[ecx + ebx*2 + 4] // Clut lookup for p1
|
|
|
|
mov [edx - 2],bx // Store pixel 1
|
|
|
|
END_OF_SCANLINE_A:
|
|
//
|
|
// Save values.
|
|
//
|
|
mov edi,[psv_saved]
|
|
|
|
movq [edi]SaveValues.pd_uv,mm7
|
|
movq [edi]SaveValues.pd_uvstep,mm6
|
|
mov [edi]SaveValues.pu2_dest,edx
|
|
mov [edi]SaveValues.pv_fog,ecx
|
|
|
|
// psv_saved++;
|
|
add edi,SIZE SaveValues
|
|
mov [psv_saved],edi
|
|
|
|
END_OF_SCANLINE_NO_SAVE:
|
|
//
|
|
// *pv3_left += v3_delta_left;
|
|
// *pv3_right += v3_delta_right;
|
|
//
|
|
mov eax,[pv3_left]
|
|
|
|
mov ebx,[pv3_right]
|
|
|
|
movq mm0,[eax]CVector3_float.tX
|
|
|
|
movd mm1,[eax]CVector3_float.tZ
|
|
|
|
movq mm2,v3_delta_left.tX
|
|
|
|
movd mm3,v3_delta_left.tZ
|
|
|
|
pfadd (m0,m2)
|
|
|
|
pfadd (m1,m3)
|
|
|
|
movq [eax]CVector3_float.tX,mm0
|
|
|
|
movd [eax]CVector3_float.tZ,mm1
|
|
|
|
movq mm0,[ebx]CVector3_float.tX
|
|
|
|
movd mm1,[ebx]CVector3_float.tZ
|
|
|
|
movq mm2,v3_delta_left.tX
|
|
|
|
movd mm3,v3_delta_left.tZ
|
|
|
|
pfadd (m0,m2)
|
|
|
|
pfadd (m1,m3)
|
|
|
|
movq [ebx]CVector3_float.tX,mm0
|
|
|
|
movd [ebx]CVector3_float.tZ,mm1
|
|
|
|
//
|
|
// pu2Raster = pu2Raster + i4Pitch;
|
|
// u4_lines++;
|
|
// i_line++;
|
|
//
|
|
mov esi,this
|
|
|
|
mov ecx,[esi]myCSkyRender.pu2Raster
|
|
|
|
mov ebx,[esi]myCSkyRender.i4Pitch
|
|
|
|
lea ecx,[ecx + ebx*2]
|
|
mov [esi]myCSkyRender.pu2Raster,ecx
|
|
|
|
mov edx,[u4_lines]
|
|
|
|
inc edx
|
|
mov [u4_lines],edx
|
|
|
|
mov ebx,[i_line]
|
|
|
|
inc ebx
|
|
mov [i_line],ebx
|
|
|
|
jmp FIRST_BLOCK_LINE_LOOP
|
|
|
|
EXIT_FB_LINE_LOOP_FINISHED:
|
|
mov [b_done],1 // set b_done flag.
|
|
|
|
//
|
|
// i_lines_drawn = i_lines_drawn + i_line - iRENDER_BLOCK_SIZE;
|
|
//
|
|
mov eax,[i_lines_drawn]
|
|
mov ebx,[i_line]
|
|
sub eax,iRENDER_BLOCK_SIZE
|
|
add eax,ebx
|
|
mov [i_lines_drawn],eax
|
|
|
|
EXIT_FB_LINE_LOOP:
|
|
mov ebx,iRENDER_BLOCK_SIZE
|
|
mov [i_pixel],ebx
|
|
|
|
mov esi,this
|
|
|
|
//
|
|
// for (int i_pixel = iRENDER_BLOCK_SIZE; i_pixel < u4ScreenWidth; i_pixel += iRENDER_BLOCK_SIZE)
|
|
//
|
|
// ebx = i_pixel
|
|
// esi = this
|
|
//
|
|
BLOCK_LOOP:
|
|
// psv_saved = &asv_saved[0];
|
|
lea edi,[asv_saved]
|
|
|
|
mov [psv_saved],edi // psv_saved = &asv_saved[0]
|
|
|
|
// i_width = min(iRENDER_BLOCK_SIZE, (int)u4ScreenWidth - i_pixel)
|
|
mov ecx,[esi]myCSkyRender.u4ScreenWidth
|
|
|
|
sub ecx,ebx
|
|
|
|
cmp ecx,iRENDER_BLOCK_SIZE
|
|
jle ECX_IS_MIN
|
|
|
|
mov ecx,iRENDER_BLOCK_SIZE
|
|
|
|
ECX_IS_MIN:
|
|
mov [i_width],ecx
|
|
mov eax,0
|
|
|
|
mov [i_line],eax
|
|
jmp ENTER_BLOCK_LINE_LOOP
|
|
|
|
//
|
|
// for (i_line = 0; i_line < i_lines_drawn; i_line++)
|
|
//
|
|
// esi = this
|
|
// edi = psv_saved
|
|
//
|
|
BLOCK_LINE_LOOP:
|
|
//
|
|
// Load saved values.
|
|
//
|
|
movq mm7,[edi]SaveValues.pd_uv
|
|
movq mm6,[edi]SaveValues.pd_uvstep
|
|
mov edx,[edi]SaveValues.pu2_dest
|
|
mov ecx,[edi]SaveValues.pv_fog
|
|
|
|
mov edi,[i_width]
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Draw the scanline.
|
|
//
|
|
// mm6,mm7 = texture values.
|
|
//
|
|
// Setup registers:
|
|
//
|
|
// eax = texel_index2 ebx = texel_index1
|
|
// ecx = fog_table_ptr edx = dest_base_ptr
|
|
// esi = texture_base_ptr edi = pixel_offset & count
|
|
// ebp = base pointer
|
|
//
|
|
// mm0 = temp mm1 = temp
|
|
// mm2 = mfactor (512,1) mm3 = uvmask (0x00ff, 0x00ff, 0x00ff, 0x00ff)
|
|
// mm6 = uvslope mm7 = uv (stepped once)
|
|
//
|
|
lea edx,[edx+edi*2] // Start + width of scanline.
|
|
|
|
neg edi // Negative width.
|
|
|
|
movq mm2,[pdMFactor] // Load [width,1]
|
|
|
|
movq mm3,[pwUVMasks] // Load masks.
|
|
|
|
movq mm0,mm7 // Copy U1,V1
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
movq mm1,mm7 // Copy U2,V2
|
|
|
|
psrad mm1,16 // Shift for integer U2,V2
|
|
|
|
packssdw mm0,mm1 // Pack integer texture values
|
|
|
|
pand mm0,mm3 // Mask for tiling
|
|
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
mov esi,[pu1_tex] // load base of texture.
|
|
|
|
sub esi,4 // Hack to force SIB + offset in loop
|
|
|
|
//
|
|
// Align to a quadword boundry.
|
|
//
|
|
lea eax,[edx + edi*2]
|
|
|
|
and eax,3
|
|
jz ALIGNED2_B
|
|
|
|
inc edi // One pixel left?
|
|
jz ONE_PIXEL_LEFT_B
|
|
|
|
//
|
|
// Do one pixel for alignment.
|
|
//
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
movq mm0,mm7 // Copy U1,V1
|
|
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
packssdw mm1,mm0 // Pack integer texture values.
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
movq mm0,mm1 // Put values back into mm0
|
|
|
|
pand mm0,mm3 // Mask for tiling
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 1
|
|
lea eax,[edx + edi*2]
|
|
|
|
mov [edx + edi*2 - 2],bx // Store pixel
|
|
|
|
ALIGNED2_B:
|
|
and eax,7
|
|
jz ALIGNED4_B
|
|
|
|
add edi,2 // Two pixels left?
|
|
jge FINISH_REMAINDER2_B
|
|
|
|
//
|
|
// Do two pixels for alignment.
|
|
//
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
movq mm0,mm7 // Copy U1,V1
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
movq mm1,mm7 // Copy U2,V2
|
|
|
|
psrad mm1,16 // Shift for integer U2,V2
|
|
packssdw mm0,mm1 // Pack integer texture values.
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 1
|
|
pand mm0,mm3 // Mask for tiling
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 2
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
shl eax,16 // Shift pixel 2 up.
|
|
or ebx,eax // Combine pixels.
|
|
|
|
mov [edx + edi*2 - 4],ebx // Store pixels
|
|
|
|
ALIGNED4_B:
|
|
add edi,4
|
|
jl INNER_LOOP_4P_B // Four pixles left?
|
|
|
|
jmp FINISH_REMAINDER4_B
|
|
|
|
// Align start of loop to 0 past the beginning of a cache line.
|
|
ALIGN 16
|
|
nop
|
|
ALIGN 16
|
|
|
|
//
|
|
// Do four pixels at a time.
|
|
//
|
|
// mm0 = packed & masked U1,V1,U2,V2
|
|
// mm7 is stepped once.
|
|
//
|
|
INNER_LOOP_4P_B:
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
movq mm0,mm7 // Copy U1,V1
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
movq mm1,mm7 // Copy U2,V2
|
|
|
|
psrad mm1,16 // Shift for integer U2,V2
|
|
packssdw mm0,mm1 // Pack integer texture values.
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 2
|
|
pand mm0,mm3 // Mask for tiling
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 1
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
shl eax,16 // Shift second pixel up.
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
|
|
or ebx,eax // Combine 2 pixels.
|
|
movd mm4,ebx // Put in MMX register.
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
movq mm0,mm7 // Copy U1,V1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
movq mm1,mm7 // Copy U2,V2
|
|
psrad mm1,16 // Shift for integer U2,V2
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 2
|
|
packssdw mm0,mm1 // Pack integer texture values.
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 1
|
|
pand mm0,mm3 // Mask for tiling
|
|
|
|
shl eax,16 // Shift second pixel up.
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
or ebx,eax // Combine 2 pixels.
|
|
movd mm1,ebx // Put in MMX register.
|
|
|
|
punpckldq mm4,mm1 // Combine all four pixels.
|
|
movq [edx + edi*2 - 8],mm4 // Store 4 pixels
|
|
|
|
add edi,4 // Inrcement index by 4
|
|
jl INNER_LOOP_4P_B // Loop (while >4 pixels)
|
|
|
|
FINISH_REMAINDER4_B:
|
|
//
|
|
// One (edi == 3), two (edi == 2), three (edi == 1) or four (edi == 0) pixels left.
|
|
//
|
|
jnz THREE_OR_LESS_B
|
|
|
|
//
|
|
// Four pixels left, step co-ordinates 3 times.
|
|
//
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
movq mm0,mm7 // Copy U1,V1
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
movq mm1,mm7 // Copy U2,V2
|
|
|
|
psrad mm1,16 // Shift for integer U2,V2
|
|
packssdw mm0,mm1 // Pack integer texture values.
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 2
|
|
pand mm0,mm3 // Mask for tiling
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 1
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
shl eax,16 // Shift second pixel up.
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
|
|
or ebx,eax // Combine 2 pixels.
|
|
movd mm4,ebx // Put in MMX register.
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 2
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 1
|
|
|
|
shl eax,16 // Shift second pixel up.
|
|
|
|
or ebx,eax // Combine 2 pixels.
|
|
movd mm1,ebx // Put in MMX register.
|
|
|
|
punpckldq mm4,mm1 // Combine all four pixels.
|
|
movq [edx - 8],mm4 // Store 4 pixels
|
|
|
|
jmp END_OF_SCANLINE_B
|
|
|
|
THREE_OR_LESS_B:
|
|
sub edi,2
|
|
jge FINISH_REMAINDER2_B
|
|
|
|
//
|
|
// Three pixels left, step co-ordinates twice.
|
|
//
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
movq mm0,mm7 // Copy U1,V1
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
psrad mm0,16 // Shift for integer U1,V1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
movq mm1,mm7 // Copy U2,V2
|
|
|
|
psrad mm1,16 // Shift for integer U2,V2
|
|
packssdw mm0,mm1 // Pack integer texture values.
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 1
|
|
pand mm0,mm3 // Mask for tiling
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 2
|
|
pmaddwd mm0,mm2 // Compute texture indicies.
|
|
|
|
shl eax,16 // Shift pixel 2 up.
|
|
or ebx,eax // Combine pixels.
|
|
|
|
mov [edx - 6],ebx // Store pixels
|
|
|
|
movd ebx,mm0 // Get texture index 1
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
|
|
mov bx,word ptr[ecx + ebx*2 + 4] // Clut lookup for p1
|
|
|
|
mov [edx - 2],bx // Store pixel 1
|
|
|
|
jmp short END_OF_SCANLINE_B
|
|
|
|
FINISH_REMAINDER2_B:
|
|
//
|
|
// One pixel (edi == 1) or two pixels (edi == 0) left.
|
|
//
|
|
jnz ONE_PIXEL_LEFT_B
|
|
|
|
//
|
|
// Two pixels left, only step texture co-ordinates once.
|
|
//
|
|
movq [pdIndexTemp],mm0 // Save texture indicies.
|
|
paddd mm7,mm6 // Step U,V
|
|
|
|
mov eax,dword ptr[pdIndexTemp + 4] // Get texture index 2
|
|
|
|
mov ebx,dword ptr[pdIndexTemp] // Get texture index 1
|
|
|
|
movzx eax,byte ptr[esi + eax + 4] // Lookup texel 2
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
|
|
movzx eax,word ptr[ecx + eax*2 + 4] // Clut lookup for pixel 2
|
|
|
|
movzx ebx,word ptr[ecx + ebx*2 + 4] // Clut lookup for pixel 1
|
|
|
|
shl eax,16 // Shift pixel 2 up.
|
|
or ebx,eax // Combine pixels.
|
|
|
|
mov [edx - 4],ebx // Store pixels
|
|
|
|
jmp short END_OF_SCANLINE_B
|
|
|
|
ONE_PIXEL_LEFT_B:
|
|
//
|
|
// One pixel left, don't step texture co-ordinates.
|
|
//
|
|
movd ebx,mm0 // Get texture index 1
|
|
|
|
movzx ebx,byte ptr[esi + ebx + 4] // Lookup texel 1
|
|
|
|
mov bx,word ptr[ecx + ebx*2 + 4] // Clut lookup for p1
|
|
|
|
mov [edx - 2],bx // Store pixel 1
|
|
|
|
END_OF_SCANLINE_B:
|
|
//
|
|
// Save updated values.
|
|
//
|
|
mov edi,[psv_saved]
|
|
|
|
movq [edi]SaveValues.pd_uv,mm7
|
|
movq [edi]SaveValues.pd_uvstep,mm6
|
|
mov [edi]SaveValues.pu2_dest,edx
|
|
|
|
// psv_saved++;
|
|
// i_line++;
|
|
add edi,SIZE SaveValues
|
|
mov eax,[i_line]
|
|
|
|
mov [psv_saved],edi
|
|
inc eax
|
|
|
|
mov esi,this
|
|
mov [i_line],eax
|
|
|
|
ENTER_BLOCK_LINE_LOOP:
|
|
cmp eax,[i_lines_drawn]
|
|
jl BLOCK_LINE_LOOP
|
|
|
|
mov ebx,[i_pixel]
|
|
|
|
//ENTER_BLOCK_LOOP:
|
|
add ebx,iRENDER_BLOCK_SIZE
|
|
mov [i_pixel],ebx
|
|
|
|
cmp ebx,[esi]myCSkyRender.u4ScreenWidth
|
|
jl BLOCK_LOOP
|
|
|
|
mov eax,[b_done]
|
|
|
|
test eax,eax
|
|
jz SCANLINE_LOOP
|
|
|
|
femms // ensure fast switch.
|
|
}
|
|
|
|
// if the fill flag is set and the screen was not filled by the sky then fill it with the
|
|
// back fog colour.
|
|
if (bFill && u4_lines < u4ScreenHeight)
|
|
{
|
|
FillSky
|
|
(
|
|
pu2Raster,
|
|
u4ScreenWidth,
|
|
((i4Pitch-(int32)u4ScreenWidth)*prasRenderSurface->iPixelBits/8),
|
|
u4ScreenHeight - u4_lines,
|
|
u4Fog
|
|
);
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
//**********************************************************************************************
|
|
//
|
|
void CSkyRender::DrawSkyTexturedLinear()
|
|
//
|
|
//**************************************
|
|
{
|
|
CVector3<> v3_delta_left;
|
|
CVector3<> v3_delta_right;
|
|
CVector3<>* pv3_left;
|
|
CVector3<>* pv3_right;
|
|
float f_clip;
|
|
int32 i4_fog;
|
|
uint32 fp_u;
|
|
uint32 fp_v;
|
|
uint32 u4_lines = 0;
|
|
uint8* pu1_tex;
|
|
uint32 u4_x;
|
|
uint32 u4_adr;
|
|
uint32 fp_delta_u;
|
|
uint32 fp_delta_v;
|
|
|
|
pu1_tex = (uint8*)prasSkyTexture->pSurface;
|
|
|
|
//
|
|
// If the World space Z component of the frustum top left vector is negative then we are
|
|
// drawing from bottom to top of the screen.
|
|
//
|
|
if (av3FrustTran[0].tZ < fSKY_HORIZON_Z)
|
|
{
|
|
// we are drawing from bottom to top
|
|
// calculate the per scan line deltas..
|
|
v3_delta_left = (av3FrustTran[0] - av3FrustTran[2]) * fScreenHeightRep;
|
|
v3_delta_right = (av3FrustTran[1] - av3FrustTran[3]) * fScreenHeightRep;
|
|
|
|
// point to the base vector we are using (bottom in this case)
|
|
pv3_left = &av3FrustTran[2];
|
|
pv3_right = &av3FrustTran[3];
|
|
|
|
// adjust the screen pointer to point to the left edge of the last scanline
|
|
pu2Raster = pu2Raster + (i4Pitch*((int)u4ScreenHeight-1));
|
|
i4Pitch = - i4Pitch;
|
|
}
|
|
else
|
|
{
|
|
// we are drawing from top to bottom
|
|
// calculate the per scan line deltas..
|
|
v3_delta_left = (av3FrustTran[2] - av3FrustTran[0]) * fScreenHeightRep;
|
|
v3_delta_right = (av3FrustTran[3] - av3FrustTran[1]) * fScreenHeightRep;
|
|
|
|
// point to the base vector we are using (bottom in this case)
|
|
pv3_left = &av3FrustTran[0];
|
|
pv3_right = &av3FrustTran[1];
|
|
}
|
|
|
|
// get the parametric clip point for the vector and sky plane, relative to the origin.
|
|
// This is the initial clip point used for the first scan line, the next clip point
|
|
// is calculated while the first scan line is being drawn..
|
|
f_clip = fSkyHeight / pv3_left->tZ;
|
|
|
|
// while not at the horizion and there are scan lines left.
|
|
while ( (pv3_left->tZ>fSKY_HORIZON_Z) && (u4_lines<u4ScreenHeight) )
|
|
{
|
|
// calculate the fog band based on the Z component the ray vectors for this scan line,
|
|
// we need to shift down u4DEFAULT_SKY_FOG_BITS because the linear version does not
|
|
// use the fog fraction.
|
|
i4_fog = (int32) ((1.0f - fabs(pv3_left->tZ) - fFogNear) * fFogScale)>>u4DEFAULT_SKY_FOG_BITS;
|
|
|
|
//
|
|
// clamp the fog bands to the definded range...
|
|
// If we above or equal to the last fog band then we can set the whole scan line to
|
|
// a flat shaded colour.
|
|
//
|
|
if (i4_fog<0)
|
|
{
|
|
i4_fog = 0;
|
|
}
|
|
else if (i4_fog>=iNUM_SKY_FOG_BANDS-1)
|
|
{
|
|
// next ray cast vectors...
|
|
*pv3_left+=v3_delta_left;
|
|
*pv3_right+=v3_delta_right;
|
|
|
|
// fire off the divide
|
|
f_clip = fSkyHeight / (pv3_left->tZ);
|
|
|
|
// fill 1 scan line
|
|
FillSky(pu2Raster,u4ScreenWidth,0,1, u4Fog);
|
|
|
|
// goto the next address
|
|
pu2Raster = pu2Raster + i4Pitch;
|
|
u4_lines++;
|
|
continue;
|
|
}
|
|
|
|
// calculate the intersection points with the sky plane, scale it and convert it to
|
|
// 16.16 fixed point.
|
|
fp_u = (uint32) ( ((v3Camera.tX+(pv3_left->tX*f_clip))*fScale) + fSkyOffsetU);
|
|
fp_v = (uint32) ( ((v3Camera.tY+(pv3_left->tY*f_clip))*fScale) + fSkyOffsetV);
|
|
|
|
|
|
// scale the f_clip by the screen width scale so the U,V deltas come out from below
|
|
// ready scaled.
|
|
// fScreenWidthScaleRep contains a scale of 65536.0 to adjust for the fixed point
|
|
f_clip *= fScreenWidthScaleRep;
|
|
|
|
// vec_right and vec_left contain the intersection points of the frustum vectors for
|
|
// this scan line and the sky plane (in world space, with constant height).
|
|
// The UVs are calculated as the difference between these positions divided by the
|
|
// number of steps/pixels in the screen width.
|
|
// These deltas are then scaled by the pixel/world size and the fixed point constant
|
|
// 65536.0f
|
|
fp_delta_u = (uint32) ( ((pv3_right->tX) - (pv3_left->tX) ) * f_clip);
|
|
fp_delta_v = (uint32) ( ((pv3_right->tY) - (pv3_left->tY) ) * f_clip);
|
|
|
|
// calculate the ray cast vectors for the next scan line
|
|
*pv3_left+=v3_delta_left;
|
|
*pv3_right+=v3_delta_right;
|
|
|
|
//
|
|
// get the parametric clip point for the vector and sky plane, relative to the player.
|
|
// This is for the next scan line, the floating point divide will overlap the drawing
|
|
// code of this scan line which is all fixed point...
|
|
//
|
|
f_clip = fSkyHeight / (pv3_left->tZ);
|
|
|
|
// while the divide is going draw the scan line with all integer code
|
|
for (u4_x = 0; u4_x<u4ScreenWidth; u4_x++)
|
|
{
|
|
u4_adr = (((fp_v>>16) & 0xff)<<9) | ((fp_u>>16) & 0xff);
|
|
|
|
pu2Raster[u4_x] = u2FogTable[ i4_fog ][ pu1_tex[u4_adr] ];
|
|
|
|
fp_u += fp_delta_u;
|
|
fp_v += fp_delta_v;
|
|
}
|
|
|
|
// we have done a scan line so adjust the start pointer to the next
|
|
pu2Raster = pu2Raster + i4Pitch;
|
|
u4_lines++;
|
|
}
|
|
|
|
// if the fill flag is set and the screen was not filled by the sky then fill it with the
|
|
// back fog colour.
|
|
if ((bFill) && (u4_lines<u4ScreenHeight))
|
|
{
|
|
FillSky
|
|
(
|
|
pu2Raster,
|
|
u4ScreenWidth,
|
|
((i4Pitch-(int32)u4ScreenWidth)*prasRenderSurface->iPixelBits/8),
|
|
u4ScreenHeight - u4_lines,
|
|
u4Fog
|
|
);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
//**********************************************************************************************
|
|
// Draws a flat shaded sky which is not horizontal. The edge walking is identical to the textured
|
|
// primitive but no sub-division are made. The fog start and end colour is calculated once per
|
|
// scan line and then interpolated at every pixel.
|
|
//
|
|
void CSkyRender::DrawSkyFlatPerspective()
|
|
//
|
|
//**************************************
|
|
{
|
|
CVector3<> v3_delta_start;
|
|
CVector3<> v3_delta_end;
|
|
CVector3<>* pv3_start;
|
|
CVector3<>* pv3_end;
|
|
|
|
int32 i4_fog_s;
|
|
int32 i4_fog_e;
|
|
int32 i4_fog_inc;
|
|
uint16* pu2_pixel;
|
|
int32 i4_pixels;
|
|
int32 i4_dir;
|
|
float f_pixels;
|
|
uint32 u4_lines = 0;
|
|
|
|
|
|
//
|
|
// fast fill the whole screen if the fill flag is switched on. This is quicker than
|
|
// trying to fill just the pixels that the sky does not cover.
|
|
//
|
|
if (bFill)
|
|
{
|
|
FillSky
|
|
(
|
|
pu2Raster,
|
|
u4ScreenWidth,
|
|
(i4Pitch-(int32)u4ScreenWidth)*2,
|
|
u4ScreenHeight,
|
|
u4Fog
|
|
);
|
|
}
|
|
|
|
|
|
//
|
|
// Determine which of the corners of the screen is closest to the sky. This is done
|
|
// by checking the sign of the up and right vectors. The drawing direction is always
|
|
// away from the closest point.
|
|
//
|
|
|
|
if (av3FrustTran[4].tZ>0.0f)
|
|
{
|
|
//
|
|
// Top vector is facing up (+ve Z) so the screen is the correct way around..
|
|
//
|
|
if (av3FrustTran[5].tZ<=0.0f)
|
|
{
|
|
// Right vector Z is 0 or less so we are drawing in the normal direction
|
|
v3_delta_start = (av3FrustTran[2] - av3FrustTran[0]) * fScreenHeightRep;
|
|
v3_delta_end = (av3FrustTran[3] - av3FrustTran[1]) * fScreenHeightRep;
|
|
|
|
pv3_start = &av3FrustTran[0];
|
|
pv3_end = &av3FrustTran[1];
|
|
|
|
// Draw direction is from left to right. top to bottom
|
|
i4_dir = 1;
|
|
}
|
|
else
|
|
{
|
|
// Right vector X is begative so we draw from the right
|
|
v3_delta_start = (av3FrustTran[3] - av3FrustTran[1]) * fScreenHeightRep;
|
|
v3_delta_end = (av3FrustTran[2] - av3FrustTran[0]) * fScreenHeightRep;
|
|
|
|
pv3_start = &av3FrustTran[1];
|
|
pv3_end = &av3FrustTran[0];
|
|
|
|
// Draw direction is from right to left, top to bottom
|
|
i4_dir = -1;
|
|
pu2Raster = pu2Raster + u4ScreenWidth-1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The top vector is facing down so the screen is upside down
|
|
//
|
|
if (av3FrustTran[5].tZ<=0.0f)
|
|
{
|
|
// Right vector Z is 0 or less so we are drawing in the normal direction
|
|
v3_delta_start = (av3FrustTran[0] - av3FrustTran[2]) * fScreenHeightRep;
|
|
v3_delta_end = (av3FrustTran[1] - av3FrustTran[3]) * fScreenHeightRep;
|
|
|
|
pv3_start = &av3FrustTran[2];
|
|
pv3_end = &av3FrustTran[3];
|
|
|
|
// draw direction is from left to right, bottom to top
|
|
i4_dir = 1;
|
|
pu2Raster = pu2Raster + (i4Pitch*((int32)u4ScreenHeight-1));
|
|
i4Pitch = - i4Pitch;
|
|
}
|
|
else
|
|
{
|
|
// Right vector X is begative so we draw from the right
|
|
v3_delta_start = (av3FrustTran[1] - av3FrustTran[3]) * fScreenHeightRep;
|
|
v3_delta_end = (av3FrustTran[0] - av3FrustTran[2]) * fScreenHeightRep;
|
|
|
|
pv3_start = &av3FrustTran[3];
|
|
pv3_end = &av3FrustTran[2];
|
|
|
|
// draw direction is from right to left, bottom to top
|
|
i4_dir = -1;
|
|
pu2Raster = pu2Raster + (i4Pitch*((int32)u4ScreenHeight-1));
|
|
pu2Raster = pu2Raster + u4ScreenWidth-1;
|
|
i4Pitch = - i4Pitch;
|
|
}
|
|
}
|
|
|
|
//
|
|
// The primitive just calculates the fog colour at the start and end of the scan line. (This
|
|
// is done in an identical method to the perspective function).
|
|
// This function does nothing else, once it has the start and end fog colours it goes into
|
|
// the main loop.
|
|
//
|
|
while ( (pv3_start->tZ>fSKY_HORIZON_Z) && (u4_lines<u4ScreenHeight))
|
|
{
|
|
// calculate the fog colour at the start of the scan line, fog calculations are only
|
|
// done once per scan line.
|
|
// The start vector is definiatly on the screen so we have no need to check, this is
|
|
// assured because we start drawing at the closest point. Leave the fixed point bits
|
|
// in with the fog colour.
|
|
i4_fog_s = ((1.0 - fabs(pv3_start->tZ) - fFogNear) * fFogScale);
|
|
|
|
// clamp the fog bands to the definded range...
|
|
if (i4_fog_s>(iNUM_SKY_FOG_BANDS-1)*(1<<u4DEFAULT_SKY_FOG_BITS))
|
|
i4_fog_s = (iNUM_SKY_FOG_BANDS-1)*(1<<u4DEFAULT_SKY_FOG_BITS);
|
|
if (i4_fog_s<0)
|
|
i4_fog_s = 0;
|
|
|
|
// if the end of the scan line points towards the sky then the fog can be calculated
|
|
// the same as the above the the scan line length can be set to the screen width as we
|
|
// are going to fill the whole line.
|
|
if (pv3_end->tZ>fSKY_HORIZON_Z)
|
|
{
|
|
// end fog colour
|
|
i4_fog_e = (int32)((1.0 - fabs(pv3_end->tZ) - fFogNear) * fFogScale);
|
|
|
|
// clamp to range.
|
|
if (i4_fog_e> (iNUM_SKY_FOG_BANDS-1)*(1<<u4DEFAULT_SKY_FOG_BITS))
|
|
i4_fog_e = (iNUM_SKY_FOG_BANDS-1)*(1<<u4DEFAULT_SKY_FOG_BITS);
|
|
if (i4_fog_e<0)
|
|
i4_fog_e = 0;
|
|
|
|
// calculate the fog band increment per pixel along the scan line
|
|
i4_fog_inc = (int32) ((float)(i4_fog_e - i4_fog_s) * fScreenWidthRep);
|
|
|
|
// number of pixels to draw is the whole scan line
|
|
i4_pixels = (int32)u4ScreenWidth;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If the end of the scan line is not pointing towrds the sky we need to find the horizon.
|
|
// after finding the paramterix horizon we calculate how many pixles are to be drawn and
|
|
// assume the fog colour at this point is maximum.
|
|
f_pixels = (float)u4ScreenWidth * (fSKY_HORIZON_Z-pv3_start->tZ)/(pv3_end->tZ - pv3_start->tZ);
|
|
i4_fog_inc = (int32)(((float)(((iNUM_SKY_FOG_BANDS-1) * (1<<u4DEFAULT_SKY_FOG_BITS)) - i4_fog_s)) / f_pixels);
|
|
i4_pixels = (int32)f_pixels;
|
|
}
|
|
|
|
// make a copy of the scan line address
|
|
pu2_pixel = pu2Raster;
|
|
|
|
|
|
//
|
|
// Main drawing loop
|
|
//
|
|
// draw pixels of this scan line (i4_pixels) in one go.
|
|
//
|
|
while (i4_pixels)
|
|
{
|
|
// The last colour in the map is the flat shaded colour
|
|
*pu2_pixel = u2FogTable[i4_fog_s>>u4DEFAULT_SKY_FOG_BITS][u4FlatColourIndex];
|
|
pu2_pixel+=i4_dir;
|
|
|
|
// new fog colour
|
|
i4_fog_s += i4_fog_inc;
|
|
|
|
i4_pixels -= 1;
|
|
}
|
|
|
|
// calculate the edge vectors for the next scan line
|
|
*pv3_start += v3_delta_start;
|
|
*pv3_end += v3_delta_end;
|
|
|
|
// move to the next scan line
|
|
pu2Raster = pu2Raster + i4Pitch;
|
|
|
|
// we have done a scan line..
|
|
u4_lines++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//**********************************************************************************************
|
|
// Draws a non horizontal sky. To do this perspective correction is requird if we are going to
|
|
// draw a scan line at a time. This will draw a horizontal sky but is not efficient and the above
|
|
// routine should be used.
|
|
// In operation this is similar to the linear routine but instead of casting out 1 ray per scan
|
|
// line it casts out many, 1 every X pixels. This forms a grid when done on every scan line and
|
|
// the perspective is correct at the grid points so accraute UV co-ords can be calculated. Linear
|
|
// Interpolation is used on a per pixel basis between the grid points.
|
|
// An alternate method would be to draw down the lines of constant Z but it is difficult to stop
|
|
// cracking.
|
|
//
|
|
void CSkyRender::DrawSkyTexturedPerspective()
|
|
//
|
|
//**************************************
|
|
{
|
|
CVector3<> v3_delta_start;
|
|
CVector3<> v3_delta_end;
|
|
CVector3<>* pv3_start;
|
|
CVector3<>* pv3_end;
|
|
CVector3<> v3_step_delta;
|
|
CVector3<> v3_step;
|
|
CVector3<> v3_next_step;
|
|
|
|
float f_clipl;
|
|
float f_clipr;
|
|
|
|
int32 i4_fog_e;
|
|
|
|
uint32 fp_u;
|
|
uint32 fp_v;
|
|
|
|
int32 i4_x_limit;
|
|
int32 i4_x_limit1;
|
|
int32 i4_x_limit2;
|
|
int32 i4_pixels;
|
|
float f_pixels;
|
|
|
|
uint32 u4_lines = 0;
|
|
|
|
#if (VER_ASM)
|
|
static void* pvFogPointer;
|
|
static uint8* pu1_tex;
|
|
static uint16* pu2_pixel;
|
|
static int32 i4_fog_s;
|
|
static int32 i4_fog_inc;
|
|
static uint32 fp_delta_u;
|
|
static uint32 fp_delta_v;
|
|
static int32 i4_dir;
|
|
#else
|
|
uint8* pu1_tex;
|
|
uint16* pu2_pixel;
|
|
int32 i4_fog_s;
|
|
int32 i4_fog_inc;
|
|
uint32 fp_delta_u;
|
|
uint32 fp_delta_v;
|
|
int32 i4_dir;
|
|
int32 i4_x;
|
|
uint32 u4_adr;
|
|
#endif
|
|
|
|
pu1_tex = (uint8*)prasSkyTexture->pSurface;
|
|
|
|
//
|
|
// fast fill the whole screen if the fill flag is switched on. This is quicker than
|
|
// trying to fill just the pixels that the sky does not cover.
|
|
//
|
|
if (bFill)
|
|
{
|
|
FillSky
|
|
(
|
|
pu2Raster,
|
|
u4ScreenWidth,
|
|
(i4Pitch-(int32)u4ScreenWidth)*2,
|
|
u4ScreenHeight,
|
|
u4Fog
|
|
);
|
|
}
|
|
|
|
|
|
//
|
|
// Determine which of the corners of the screen is closest to the sky. This is done
|
|
// by checking the sign of the up and right vectors. The drawing direction is always
|
|
// away from the closest point.
|
|
//
|
|
|
|
if (av3FrustTran[4].tZ>0.0f)
|
|
{
|
|
//
|
|
// Top vector is facing up (+ve Z) so the screen is the correct way around..
|
|
//
|
|
if (av3FrustTran[5].tZ<=0.0f)
|
|
{
|
|
// Right vector Z is 0 or less so we are drawing in the normal direction
|
|
v3_delta_start = (av3FrustTran[2] - av3FrustTran[0]) * fScreenHeightRep;
|
|
v3_delta_end = (av3FrustTran[3] - av3FrustTran[1]) * fScreenHeightRep;
|
|
|
|
pv3_start = &av3FrustTran[0];
|
|
pv3_end = &av3FrustTran[1];
|
|
|
|
// Draw direction is from left to right. top to bottom
|
|
i4_dir = 1;
|
|
}
|
|
else
|
|
{
|
|
// Right vector X is begative so we draw from the right
|
|
v3_delta_start = (av3FrustTran[3] - av3FrustTran[1]) * fScreenHeightRep;
|
|
v3_delta_end = (av3FrustTran[2] - av3FrustTran[0]) * fScreenHeightRep;
|
|
|
|
pv3_start = &av3FrustTran[1];
|
|
pv3_end = &av3FrustTran[0];
|
|
|
|
// Draw direction is from right to left, top to bottom
|
|
i4_dir = -1;
|
|
pu2Raster = pu2Raster + u4ScreenWidth-1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The top vector is facing down so the screen is upside down
|
|
//
|
|
if (av3FrustTran[5].tZ<=0.0f)
|
|
{
|
|
// Right vector Z is 0 or less so we are drawing in the normal direction
|
|
v3_delta_start = (av3FrustTran[0] - av3FrustTran[2]) * fScreenHeightRep;
|
|
v3_delta_end = (av3FrustTran[1] - av3FrustTran[3]) * fScreenHeightRep;
|
|
|
|
pv3_start = &av3FrustTran[2];
|
|
pv3_end = &av3FrustTran[3];
|
|
|
|
// draw direction is from left to right, bottom to top
|
|
i4_dir = 1;
|
|
pu2Raster = pu2Raster + (i4Pitch*((int32)u4ScreenHeight-1));
|
|
i4Pitch = - i4Pitch;
|
|
}
|
|
else
|
|
{
|
|
// Right vector X is begative so we draw from the right
|
|
v3_delta_start = (av3FrustTran[1] - av3FrustTran[3]) * fScreenHeightRep;
|
|
v3_delta_end = (av3FrustTran[0] - av3FrustTran[2]) * fScreenHeightRep;
|
|
|
|
pv3_start = &av3FrustTran[3];
|
|
pv3_end = &av3FrustTran[2];
|
|
|
|
// draw direction is from right to left, bottom to top
|
|
i4_dir = -1;
|
|
pu2Raster = pu2Raster + (i4Pitch*((int32)u4ScreenHeight-1));
|
|
pu2Raster = pu2Raster + u4ScreenWidth-1;
|
|
i4Pitch = - i4Pitch;
|
|
}
|
|
}
|
|
|
|
//
|
|
// pv3_start and pv3_end point to the start and end vectors for the scan lines.
|
|
// v3_delta_start and v3_delta_end is what we adjust these vectors by on each scan line.
|
|
//
|
|
// No we have the start,end and delta vectors we are ready to start drawing the scan lines
|
|
//
|
|
while ( (pv3_start->tZ>fSKY_HORIZON_Z) && (u4_lines<u4ScreenHeight))
|
|
{
|
|
//
|
|
// First we need a step delta vector for this scan line, This will step from the start
|
|
// to the end in x increments based on the division length. This vector is applied to
|
|
// the current position at each subdivision.
|
|
//
|
|
v3_step_delta = ((*pv3_end) - (*pv3_start)) * fDivisionsPerScanRep;
|
|
|
|
// v3_step is the current position and originally is the start position.
|
|
v3_step = *pv3_start;
|
|
|
|
// v3_next_step is the next sub division which is were the linear run of pixels is
|
|
// going to head for.
|
|
v3_next_step = *pv3_start + v3_step_delta;
|
|
|
|
// Calculate 2 parametric clip values, 1 for the each of the two current positions.
|
|
// from these the UV co-ords in the sky map will be calculated.
|
|
f_clipl = (fSkyHeight / v3_step.tZ);
|
|
f_clipr = (fSkyHeight / v3_next_step.tZ);
|
|
|
|
// calculate the fog colour at the start of the scan line, fog calculations are only
|
|
// done once per scan line.
|
|
// The start vector is definiatly on the screen so we have no need to check, this is
|
|
// assured because we start drawing at the closest point. Leave the fixed point bits
|
|
// in with the fog colour.
|
|
i4_fog_s = ((1.0 - fabs(pv3_start->tZ) - fFogNear) * fFogScale);
|
|
|
|
// clamp the fog bands to the definded range...
|
|
if (i4_fog_s>(iNUM_SKY_FOG_BANDS-1)*(1<<u4DEFAULT_SKY_FOG_BITS))
|
|
i4_fog_s = (iNUM_SKY_FOG_BANDS-1)*(1<<u4DEFAULT_SKY_FOG_BITS);
|
|
if (i4_fog_s<0)
|
|
i4_fog_s = 0;
|
|
|
|
// if the end of the scan line points towards the sky then the fog can be calculated
|
|
// the same as the above the the scan line length can be set to the screen width as we
|
|
// are going to fill the whole line.
|
|
if (pv3_end->tZ>fSKY_HORIZON_Z)
|
|
{
|
|
// end fog colour
|
|
i4_fog_e = (int32)((1.0 - fabs(pv3_end->tZ) - fFogNear) * fFogScale);
|
|
|
|
// clamp to range.
|
|
if (i4_fog_e> (iNUM_SKY_FOG_BANDS-1)*(1<<u4DEFAULT_SKY_FOG_BITS))
|
|
i4_fog_e = (iNUM_SKY_FOG_BANDS-1)*(1<<u4DEFAULT_SKY_FOG_BITS);
|
|
if (i4_fog_e<0)
|
|
i4_fog_e = 0;
|
|
|
|
// calculate the fog band increment per pixel along the scan line
|
|
i4_fog_inc = (int32) ((float)(i4_fog_e - i4_fog_s) * fScreenWidthRep);
|
|
|
|
// number of pixels to draw is the whole scan line
|
|
i4_pixels = (int32)u4ScreenWidth;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If the end of the scan line is not pointing towrds the sky we need to find the horizon.
|
|
// after finding the paramterix horizon we calculate how many pixles are to be drawn and
|
|
// assume the fog colour at this point is maximum.
|
|
f_pixels = (float)u4ScreenWidth * (fSKY_HORIZON_Z-pv3_start->tZ)/(pv3_end->tZ - pv3_start->tZ);
|
|
i4_fog_inc = (int32)(((float)(((iNUM_SKY_FOG_BANDS-1) * (1<<u4DEFAULT_SKY_FOG_BITS)) - i4_fog_s)) / f_pixels);
|
|
i4_pixels = (int32)f_pixels;
|
|
}
|
|
|
|
// make a copy of the scan line address
|
|
pu2_pixel = pu2Raster;
|
|
|
|
// number of pixels per divide and the half values.
|
|
i4_x_limit = u4DivisionLength;
|
|
i4_x_limit1 = i4_x_limit2 = (i4_x_limit>>1);
|
|
|
|
// while there are pixels left in this division
|
|
while (i4_pixels>=i4_x_limit)
|
|
{
|
|
// calculate the UV co-ord at the start division position
|
|
fp_u = (uint32) ( fSkyOffsetU + ((v3Camera.tX+(v3_step.tX*f_clipl))*fScale) );
|
|
fp_v = (uint32) ( fSkyOffsetV + ((v3Camera.tY+(v3_step.tY*f_clipl))*fScale) );
|
|
|
|
// calculate the UV per pixel delta based on the end division poisiton
|
|
fp_delta_u = (uint32) (( ((v3_next_step.tX*f_clipr) - (v3_step.tX*f_clipl)) ) * fDivisionLengthRepScale);
|
|
fp_delta_v = (uint32) (( ((v3_next_step.tY*f_clipr) - (v3_step.tY*f_clipl)) ) * fDivisionLengthRepScale);
|
|
|
|
// the new start division is the previous end,
|
|
v3_step = v3_next_step;
|
|
|
|
// the next end division is the previous + the delta.
|
|
v3_next_step += v3_step_delta;
|
|
|
|
#if (VER_ASM)
|
|
//Assert(iNUM_SKY_COLOURS == 64);
|
|
|
|
typedef CSkyRender myCSkyRender;
|
|
|
|
__asm
|
|
{
|
|
mov ecx,this // Load object pointer.
|
|
|
|
fld [ecx]myCSkyRender.fSkyHeight // Load sky height.
|
|
fdiv float ptr [v3_step.tZ] // fSkyHeight / (pv3_left->tZ)
|
|
// Overlap division with scanline.
|
|
|
|
//
|
|
// Per 1/2 span loop.
|
|
//
|
|
lea esi,[ecx]myCSkyRender.u2FogTable // Pointer to fog table.
|
|
mov eax,[i4_dir] // Load scan direction.
|
|
|
|
push ebp // Save ebp.
|
|
mov [pvFogPointer],esi // Global fog pointer.
|
|
|
|
mov ecx,[pu2_pixel] // Pointer to destination.
|
|
mov edi,[i4_x_limit1] // Load width of span.
|
|
|
|
cmp eax,0
|
|
jl short NEG_SCAN1
|
|
|
|
// Scanning left to right.
|
|
neg edi // Negate width.
|
|
|
|
NEG_SCAN1:
|
|
sub ecx,edi // Start - negative width.
|
|
mov eax,[fp_u] // Load fixed point U.
|
|
|
|
sub ecx,edi // Start - negative width*2.
|
|
mov ebx,[fp_v] // Load fixed point V.
|
|
|
|
mov edx,[i4_fog_s] // Load fog value.
|
|
mov [pu2_pixel],ecx // Save pixel after last pixel.
|
|
|
|
X_LOOP1:
|
|
mov ebp,eax // get copy of u
|
|
mov ecx,ebx // get copy of v
|
|
|
|
sar ebp,16 // integral u
|
|
mov esi,[pu1_tex] // load base of texture.
|
|
|
|
sar ecx,(16 - 9) // integral v
|
|
and ebp,0xff // mask u for tiling
|
|
|
|
and ecx,(0xff << 9) // mask v for tiling
|
|
add ebp,esi // add texture base to u.
|
|
|
|
add ebp,ecx // Add U and V.
|
|
mov ecx,edx // Copy fog value.
|
|
|
|
sar ecx,u4DEFAULT_SKY_FOG_BITS // Shift off fractional portion.
|
|
|
|
shl ecx,8 // Shift for width of table.
|
|
mov esi,[pvFogPointer] // Load base of fog table.
|
|
|
|
add esi,ecx // Add base of fog table.
|
|
xor ecx,ecx // Zero ecx.
|
|
|
|
mov cl,[ebp] // fetch pixel
|
|
mov ebp,[pu2_pixel] // base of end of line.
|
|
|
|
add eax,[fp_delta_u] // Step U.
|
|
add ebx,[fp_delta_v] // Step V.
|
|
|
|
mov cx,[esi + ecx*2] // Lookup fogged pixel.
|
|
|
|
add edx,[i4_fog_inc] // Step fog value.
|
|
mov esi,[i4_dir] // Load step direction.
|
|
|
|
mov [ebp + edi*2],cx // Store pixel.
|
|
|
|
add edi,esi // Step destination.
|
|
jnz short X_LOOP1
|
|
|
|
mov [i4_fog_s],edx // Save updated fog value.
|
|
pop ebp // Restore ebp.
|
|
|
|
fstp [f_clipl] // Store f_clipl
|
|
|
|
mov ecx,this // Load object pointer.
|
|
|
|
fld [ecx]myCSkyRender.fSkyHeight // Load sky height.
|
|
fdiv float ptr [v3_next_step.tZ] // fSkyHeight / (pv3_left->tZ)
|
|
// Overlap division with scanline.
|
|
|
|
//
|
|
// Per 1/2 span loop.
|
|
//
|
|
// eax = fp_u
|
|
// ebx = fp_v
|
|
// edx = i4_fog_s
|
|
//
|
|
mov esi,[i4_dir] // Load scan direction.
|
|
push ebp // Save ebp.
|
|
|
|
mov ecx,[pu2_pixel] // Pointer to destination.
|
|
mov edi,[i4_x_limit2] // Load width of span.
|
|
|
|
cmp esi,0
|
|
jl short NEG_SCAN2
|
|
|
|
// S canning left to right.
|
|
neg edi // Negate width.
|
|
|
|
NEG_SCAN2:
|
|
sub ecx,edi // Start - negative width.
|
|
|
|
sub ecx,edi // Start - negative width*2.
|
|
mov [pu2_pixel],ecx // Save pixel after last pixel.
|
|
|
|
X_LOOP2:
|
|
mov ebp,eax // get copy of u
|
|
mov ecx,ebx // get copy of v
|
|
|
|
sar ebp,16 // integral u
|
|
mov esi,[pu1_tex] // load base of texture.
|
|
|
|
sar ecx,(16 - 9) // integral v
|
|
and ebp,0xff // mask u for tiling
|
|
|
|
and ecx,(0xff << 9) // mask v for tiling
|
|
add ebp,esi // add texture base to u.
|
|
|
|
add ebp,ecx // Add U and V.
|
|
mov ecx,edx // Copy fog value.
|
|
|
|
sar ecx,u4DEFAULT_SKY_FOG_BITS // Shift off fractional portion.
|
|
|
|
shl ecx,8 // Shift for width of table.
|
|
mov esi,[pvFogPointer] // Load base of fog table.
|
|
|
|
add esi,ecx // Add base of fog table.
|
|
xor ecx,ecx // Zero ecx.
|
|
|
|
mov cl,[ebp] // fetch pixel
|
|
mov ebp,[pu2_pixel] // base of end of line.
|
|
|
|
add eax,[fp_delta_u] // Step U.
|
|
add ebx,[fp_delta_v] // Step V.
|
|
|
|
mov cx,[esi + ecx*2] // Lookup fogged pixel.
|
|
|
|
add edx,[i4_fog_inc] // Step fog value.
|
|
mov esi,[i4_dir] // Load step direction.
|
|
|
|
mov [ebp + edi*2],cx // Store pixel.
|
|
|
|
add edi,esi // Step destination.
|
|
jnz short X_LOOP2
|
|
|
|
pop ebp // Restore ebp.
|
|
mov [i4_fog_s],edx // Save updated fog value.
|
|
|
|
fstp [f_clipr] // Store f_clipr
|
|
}
|
|
#else
|
|
// start the division for the next start division clip point
|
|
f_clipl = fSkyHeight / v3_step.tZ;
|
|
|
|
// draw just half of the pixels of this run while that divide is going.
|
|
for (i4_x = 0; i4_x<i4_x_limit1; i4_x++)
|
|
{
|
|
// linear address from UV
|
|
u4_adr = (((fp_v>>16) & 0xff)<<9) | ((fp_u>>16) & 0xff);
|
|
|
|
// put pixel on screen and adjust screen pointer
|
|
*pu2_pixel = u2FogTable[i4_fog_s>>u4DEFAULT_SKY_FOG_BITS][ pu1_tex[u4_adr] ];
|
|
pu2_pixel+=i4_dir;
|
|
|
|
// new UV
|
|
fp_u += fp_delta_u;
|
|
fp_v += fp_delta_v;
|
|
|
|
// new fog colour
|
|
i4_fog_s += i4_fog_inc;
|
|
}
|
|
|
|
// start the second divide for the end division
|
|
f_clipr = fSkyHeight / v3_next_step.tZ;
|
|
|
|
// do the second half of the pixels, this loop is identical to the above
|
|
for (i4_x = 0; i4_x<i4_x_limit2; i4_x++)
|
|
{
|
|
u4_adr = (((fp_v>>16) & 0xff)<<9) | ((fp_u>>16) & 0xff);
|
|
|
|
*pu2_pixel = u2FogTable[i4_fog_s>>u4DEFAULT_SKY_FOG_BITS][ pu1_tex[u4_adr] ];
|
|
pu2_pixel+=i4_dir;
|
|
|
|
fp_u += fp_delta_u;
|
|
fp_v += fp_delta_v;
|
|
|
|
i4_fog_s += i4_fog_inc;
|
|
}
|
|
#endif
|
|
|
|
// this run is finished, decrement the pixel count and go again.
|
|
i4_pixels -= i4_x_limit;
|
|
}
|
|
|
|
// at this point we have the remainder of the pixels that did not fit into a whole number
|
|
// of divisions, or 0.
|
|
if (i4_pixels>0)
|
|
{
|
|
// This loop is identical to the above loops but no next division is calculated and
|
|
// there is only 1 loop.
|
|
fp_u = (uint32) ( fSkyOffsetU + ((v3Camera.tX+(v3_step.tX*f_clipl))*fScale) );
|
|
fp_v = (uint32) ( fSkyOffsetV + ((v3Camera.tY+(v3_step.tY*f_clipl))*fScale) );
|
|
|
|
fp_delta_u = (uint32) (( ((v3_next_step.tX*f_clipr) - (v3_step.tX*f_clipl)) ) * fDivisionLengthRepScale);
|
|
fp_delta_v = (uint32) (( ((v3_next_step.tY*f_clipr) - (v3_step.tY*f_clipl)) ) * fDivisionLengthRepScale);
|
|
|
|
#if (VER_ASM)
|
|
typedef CSkyRender myCSkyRender;
|
|
|
|
__asm
|
|
{
|
|
mov ecx,this
|
|
|
|
//
|
|
// Span loop.
|
|
//
|
|
lea esi,[ecx]myCSkyRender.u2FogTable // Pointer to fog table.
|
|
mov eax,[i4_dir] // Load scan direction.
|
|
|
|
push ebp // Save ebp.
|
|
mov [pvFogPointer],esi // Global fog pointer.
|
|
|
|
mov ecx,[pu2_pixel] // Pointer to destination.
|
|
mov edi,[i4_pixels] // Load width of span.
|
|
|
|
cmp eax,0
|
|
jl short NEG_SCAN3
|
|
|
|
// Scanning left to right.
|
|
neg edi // Negate width.
|
|
|
|
NEG_SCAN3:
|
|
sub ecx,edi // Start - negative width.
|
|
mov eax,[fp_u] // Load fixed point U.
|
|
|
|
sub ecx,edi // Start - negative width*2.
|
|
mov ebx,[fp_v] // Load fixed point V.
|
|
|
|
mov edx,[i4_fog_s] // Load fog value.
|
|
mov [pu2_pixel],ecx // Save pixel after last pixel.
|
|
|
|
X_LOOP3:
|
|
mov ebp,eax // get copy of u
|
|
mov ecx,ebx // get copy of v
|
|
|
|
sar ebp,16 // integral u
|
|
mov esi,[pu1_tex] // load base of texture.
|
|
|
|
sar ecx,(16 - 9) // integral v
|
|
and ebp,0xff // mask u for tiling
|
|
|
|
and ecx,(0xff << 9) // mask v for tiling
|
|
add ebp,esi // add texture base to u.
|
|
|
|
add ebp,ecx // Add U and V.
|
|
mov ecx,edx // Copy fog value.
|
|
|
|
sar ecx,u4DEFAULT_SKY_FOG_BITS // Shift off fractional portion.
|
|
|
|
shl ecx,8 // Shift for width of table.
|
|
mov esi,[pvFogPointer] // Load base of fog table.
|
|
|
|
add esi,ecx // Add base of fog table.
|
|
xor ecx,ecx // Zero ecx.
|
|
|
|
mov cl,[ebp] // fetch pixel
|
|
mov ebp,[pu2_pixel] // base of end of line.
|
|
|
|
add eax,[fp_delta_u] // Step U.
|
|
add ebx,[fp_delta_v] // Step V.
|
|
|
|
mov cx,[esi + ecx*2] // Lookup fogged pixel.
|
|
|
|
add edx,[i4_fog_inc] // Step fog value.
|
|
mov esi,[i4_dir] // Load step direction.
|
|
|
|
mov [ebp + edi*2],cx // Store pixel.
|
|
|
|
add edi,esi // Step destination.
|
|
jnz short X_LOOP3
|
|
|
|
mov [i4_fog_s],edx // Save updated fog value.
|
|
pop ebp // Restore ebp.
|
|
}
|
|
#else
|
|
for (i4_x = 0; i4_x<i4_pixels; i4_x++)
|
|
{
|
|
u4_adr = (((fp_v>>16) & 0xff)<<9) | ((fp_u>>16) & 0xff);
|
|
|
|
*pu2_pixel = u2FogTable[i4_fog_s>>u4DEFAULT_SKY_FOG_BITS][ pu1_tex[u4_adr] ];
|
|
pu2_pixel += i4_dir;
|
|
|
|
fp_u += fp_delta_u;
|
|
fp_v += fp_delta_v;
|
|
|
|
i4_fog_s += i4_fog_inc;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// calculate the edge vectors for the next scan line
|
|
*pv3_start += v3_delta_start;
|
|
*pv3_end += v3_delta_end;
|
|
|
|
pu2Raster = pu2Raster + i4Pitch;
|
|
|
|
// we have done a scan line..
|
|
u4_lines++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//**********************************************************************************************
|
|
// Fast fill a scan line with the given 32bit value. This code is generally optimal and will
|
|
// function on all processors. No processor specific version is required.
|
|
//
|
|
void CSkyRender::FillSky
|
|
//
|
|
//**************************************
|
|
(
|
|
uint16* pu2_dst, // pointer to the dst surface
|
|
int32 i4_width, // width in pixels to store
|
|
int32 i4_pitch_adj, // value to add to pointer at end of scan line to get tp the next
|
|
uint32 u4_lines, // number of lines to do
|
|
uint32 u4_col // colour packed into a DWORD
|
|
)
|
|
{
|
|
Assert (u4_lines>0);
|
|
Assert (i4_width>0);
|
|
Assert ( (((uint32)pu2_dst) & 1) == 0 ); // address must be 16 bit aligned
|
|
|
|
_asm
|
|
{
|
|
mov edi,pu2_dst
|
|
mov eax,i4_width
|
|
mov ebx,u4_col
|
|
mov esi,eax
|
|
mov ecx,u4_lines
|
|
mov edx,i4_pitch_adj
|
|
|
|
LOOPY:
|
|
// align to a 64 bit boundardry
|
|
ALIGN_64:
|
|
test edi,7 // are we aligned to a 64 bit (8 byte) boundary??
|
|
jz short LOOPX
|
|
mov [edi],bx
|
|
add edi,2
|
|
dec eax
|
|
jnz short ALIGN_64
|
|
jmp short DONE
|
|
|
|
LOOPX:
|
|
sub eax,8 // can we do 8 pixels (16 bytes)
|
|
jl FINISH_X
|
|
|
|
mov [edi],ebx
|
|
mov [edi+4],ebx
|
|
mov [edi+8],ebx
|
|
mov [edi+12],ebx
|
|
add edi,16
|
|
jmp short LOOPX
|
|
|
|
FINISH_X:
|
|
add eax,8
|
|
jz short NEXT_LINE
|
|
LOOP_FINISH_X:
|
|
mov [edi],bx
|
|
add edi,2
|
|
dec eax
|
|
jnz short LOOP_FINISH_X
|
|
|
|
NEXT_LINE:
|
|
add edi,edx
|
|
mov eax,esi
|
|
dec ecx
|
|
jnz short LOOPY
|
|
DONE:
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//**********************************************************************************************
|
|
//
|
|
// Function returns the four corners of the far clipping plane's intersection with the
|
|
// view frustum. These vectors are calculated as direction vectors in the array CSkyRender::av3FrustTran.
|
|
// They are returned as CVector's and not CDir's because operations need to be performed on them,
|
|
//
|
|
// The world position of the camera is returned in 'CSkyRender::v3Camera'
|
|
//
|
|
void CSkyRender::SetTransformedCameraCorners()
|
|
//
|
|
//**************************************
|
|
{
|
|
// Query the world database to get the current active camera.
|
|
CWDbQueryActiveCamera wqcam(wWorld);
|
|
CCamera* pcam = wqcam.tGet();
|
|
Assert(pcam);
|
|
|
|
// Construct an inverse transform for the camera.
|
|
CTransform3<> tf3_invcam = ~pcam->tf3ToNormalisedCamera();
|
|
|
|
// Set the position of the camera.
|
|
v3Camera = pcam->pr3Presence().v3Pos;
|
|
|
|
// Transform these points, base at the origin and normalize..
|
|
for (uint u = 0; u < u4NUM_SKY_TRANSFORM_VERT; ++u)
|
|
{
|
|
av3FrustTran[u] = (av3Frustum[u] * tf3_invcam) - v3Camera;
|
|
av3FrustTran[u].FastNormalise();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//**********************************************************************************************
|
|
//
|
|
// Static helper functions to create and destroy the global sky
|
|
//
|
|
|
|
|
|
//**********************************************************************************************
|
|
//
|
|
void CSkyRender::CreateSky
|
|
(
|
|
const CGroffObjectName* pgon, // Object to load.
|
|
CLoadWorld* pload, // The loader.
|
|
const CHandle& h_object, // handle of object in value table.
|
|
CValueTable* pvtable, // Value Table.
|
|
const CInfo* pinfo // The info to copy. Create a new one if 0.
|
|
)
|
|
//
|
|
//**************************************
|
|
{
|
|
// remove any existing sky.
|
|
RemoveSky();
|
|
|
|
int32 i4_shade_index = iNUM_SKY_COLOURS - 1;
|
|
|
|
IF_SETUP_TEXT_PROCESSING(pvtable, pload)
|
|
SETUP_OBJECT_HANDLE(h_object)
|
|
{
|
|
#if (VER_TEST == TRUE)
|
|
|
|
//
|
|
// The sky must have no mip maps and be packed in the no pageable region of the texture
|
|
// memory.
|
|
//
|
|
bool b_mips = true;
|
|
bFILL_BOOL(b_mips, esMipMap);
|
|
|
|
if (b_mips)
|
|
{
|
|
char str_buffer[1024];
|
|
|
|
sprintf(str_buffer, "Cannot Load: The sky does not have the 'MipMap = false' text property. (%s)", __FILE__);
|
|
|
|
if (bTerminalError(ERROR_ASSERTFAIL, true, str_buffer, __LINE__))
|
|
DebuggerBreak();
|
|
}
|
|
#endif
|
|
bFILL_INT(i4_shade_index, esSkyFlatColour);
|
|
Assert( i4_shade_index <= iNUM_SKY_COLOURS);
|
|
}
|
|
END_OBJECT;
|
|
END_TEXT_PROCESSING;
|
|
|
|
//
|
|
// we must make a permenant reference to the texture before this function goes
|
|
// out of scope and the mesh gets deleted.
|
|
//
|
|
|
|
// Load the mesh as a render type, then cast this to a CShape
|
|
rptr<CRenderType> prdt = CRenderType::prdtFindShared(pgon, pload, h_object, pvtable);
|
|
rptr<CShape> psh = ptCastRenderType<CShape>(prdt);
|
|
|
|
// Make a polygon iterator to go through the polygons of the mesh.
|
|
// OK to use 0 for mesh instance, as it doesn't need the CInstance*.
|
|
aptr<CShape::CPolyIterator> ppi = psh->pPolyIterator(0);
|
|
Verify(ppi->bNext());
|
|
|
|
//get the texture of the first polygon and use it for the sky.
|
|
const CTexture* ptex = ppi->ptexTexture();
|
|
|
|
// Create a new sky renderer class, the destination of which is the Main Screens raster
|
|
gpskyRender = new CSkyRender(ptex->prasGetTexture(), rptr_cast(CRaster,prasMainScreen) );
|
|
|
|
gpskyRender->SetFlatShadeColour(i4_shade_index);
|
|
}
|
|
|
|
|
|
|
|
//**********************************************************************************************
|
|
//
|
|
void CSkyRender::RemoveSky()
|
|
//
|
|
//**************************************
|
|
{
|
|
delete gpskyRender;
|
|
gpskyRender = NULL;
|
|
}
|
|
|
|
//******************************************************************************************
|
|
void CSkyRender::PurgeD3D()
|
|
{
|
|
// Remove the existing D3D sky.
|
|
prasD3DSky = rptr0;
|
|
}
|
|
|
|
//******************************************************************************************
|
|
void CSkyRender::InitializeForD3D()
|
|
{
|
|
// Remove the existing D3D sky.
|
|
PurgeD3D();
|
|
|
|
// Do nothing if the software-only renderer is to be used.
|
|
if (!bUseD3D)
|
|
return;
|
|
Assert (prasSkyTexture->iWidth == 256);
|
|
Assert (prasSkyTexture->iHeight == 256);
|
|
|
|
//
|
|
// Create, copy and upload a sky raster.
|
|
//
|
|
AlwaysAssert(bWithin(prasSkyTexture->iWidth, 2, 256));
|
|
AlwaysAssert(bWithin(prasSkyTexture->iHeight, 2, 256));
|
|
#if bTRACK_D3D_RASTERS
|
|
TrackSystem(etrSky);
|
|
#endif
|
|
prasD3DSky = rptr_cast(CRaster, rptr_new CRasterD3D(CRasterD3D::CInit
|
|
(
|
|
prasSkyTexture->iWidth,
|
|
prasSkyTexture->iHeight,
|
|
ed3dtexSCREEN_OPAQUE,
|
|
true
|
|
)));
|
|
|
|
prasSkyTexture->Lock();
|
|
prasD3DSky->Lock();
|
|
for (int i_x = 0; i_x < prasSkyTexture->iWidth; ++i_x)
|
|
for (int i_y = 0; i_y < prasSkyTexture->iHeight; ++i_y)
|
|
{
|
|
uint32 u4_pix = prasSkyTexture->pixGet(i_x, i_y);
|
|
u4_pix = prasD3DSky->pixFromColour(prasSkyTexture->clrFromPixel(u4_pix));
|
|
prasD3DSky->PutPixel(i_x, i_y, u4_pix);
|
|
}
|
|
prasD3DSky->Unlock();
|
|
prasSkyTexture->Unlock();
|
|
|
|
// Upload the D3D raster.
|
|
Verify(prasD3DSky->bUpload());
|
|
}
|
|
|
|
//******************************************************************************************
|
|
//
|
|
void CSkyRender::FillD3D
|
|
(
|
|
float f_offset_x,
|
|
float f_offset_y
|
|
)
|
|
//
|
|
// Fills the Direct3D version of the sky.
|
|
//
|
|
//**************************************
|
|
{
|
|
// Do nothing if no fill is required.
|
|
if (!bFill)
|
|
return;
|
|
|
|
// Get the screen width and height.
|
|
float f_screen_w = float(u4ScreenWidth);
|
|
float f_screen_h = float(u4ScreenHeight);
|
|
|
|
// Direct3D colour constants.
|
|
D3DCOLOR d3drgb_plain = d3dDriver.d3dcolGetFogColour();
|
|
D3DCOLOR d3drgb_plaina = D3DRGBA(1, 1, 1, 1);
|
|
|
|
// Setup Direct3D for this polygon.
|
|
LPDIRECT3DDEVICE3 pdevice = d3dDriver.pGetDevice(); // Copy of the device pointer.
|
|
Assert(pdevice);
|
|
|
|
d3dDriver.err = pdevice->Begin
|
|
(
|
|
D3DPT_TRIANGLEFAN,
|
|
D3DFVF_TLVERTEX,
|
|
D3DDP_DONOTCLIP | D3DDP_DONOTUPDATEEXTENTS
|
|
);
|
|
|
|
d3dDriver.err = pdevice->Vertex(&D3DTLVERTEX (D3DVECTOR( 0.0f + f_offset_x, 0.0f + f_offset_y, 1.0f), 0.5f, d3drgb_plain, d3drgb_plaina, 0.0f, 0.0f));
|
|
d3dDriver.err = pdevice->Vertex(&D3DTLVERTEX (D3DVECTOR(f_screen_w + f_offset_x, 0.0f + f_offset_y, 1.0f), 0.5f, d3drgb_plain, d3drgb_plaina, 0.0f, 0.0f));
|
|
d3dDriver.err = pdevice->Vertex(&D3DTLVERTEX (D3DVECTOR(f_screen_w + f_offset_x, f_screen_h + f_offset_y, 1.0f), 0.5f, d3drgb_plain, d3drgb_plaina, 0.0f, 0.0f));
|
|
d3dDriver.err = pdevice->Vertex(&D3DTLVERTEX (D3DVECTOR( 0.0f + f_offset_x, f_screen_h + f_offset_y, 1.0f), 0.5f, d3drgb_plain, d3drgb_plaina, 0.0f, 0.0f));
|
|
|
|
d3dDriver.err = pdevice->End(0);
|
|
}
|
|
|
|
//******************************************************************************************
|
|
//
|
|
void CSkyRender::DrawD3D
|
|
(
|
|
)
|
|
//
|
|
// Draws the Direct3D version of the sky.
|
|
//
|
|
//**************************************
|
|
{
|
|
Assert(prasRenderSurface);
|
|
|
|
float f_offset_x = 0.0f;
|
|
float f_offset_y = 0.0f;
|
|
LPDIRECT3DDEVICE3 pdevice = d3dDriver.pGetDevice(); // Copy of the device pointer.
|
|
|
|
//
|
|
// Initialize the sky for Direct3D if it has not already been initialized.
|
|
//
|
|
static bool b_initialized_sky = false;
|
|
if (!b_initialized_sky)
|
|
{
|
|
InitializeForD3D();
|
|
b_initialized_sky = true;
|
|
}
|
|
|
|
// Query the world database to get the current active camera.
|
|
CWDbQueryActiveCamera wqcam(wWorld);
|
|
CCamera* pcam = wqcam.tGet();
|
|
Assert(pcam);
|
|
|
|
// Make sure the screen is a CRasterWin.
|
|
CRasterWin* prasw = dynamic_cast<CRasterWin*>(prasRenderSurface.ptGet());
|
|
if (prasw)
|
|
{
|
|
f_offset_x = float(prasw->iOffsetX) + CScreenRenderAuxD3D::fOffsetXBase;
|
|
f_offset_y = float(prasw->iOffsetY) + CScreenRenderAuxD3D::fOffsetYBase;
|
|
}
|
|
|
|
// Fill the sky with the fog colour if required.
|
|
//FillD3D(f_offset_x, f_offset_y);
|
|
|
|
const float fFarClipPlane = 50000.0f;
|
|
const float fSkySize = 1.0f / 10000.0f;
|
|
float f_screen_w = float(u4ScreenWidth);
|
|
float f_screen_h = float(u4ScreenHeight);
|
|
float f_cam_scale = pcam->campropGetProperties().rFarClipPlaneDist / fFarClipPlane;
|
|
|
|
SSkyClip skc[8];
|
|
CVector3<> av3[u4NUM_SKY_TRANSFORM_VERT];
|
|
uint u;
|
|
|
|
// Create a world view frustum.
|
|
av3[0] = av3FrustTran[u4FRUST_TL] * fFarClipPlane + v3Camera;
|
|
av3[1] = av3FrustTran[u4FRUST_TR] * fFarClipPlane + v3Camera;
|
|
av3[2] = av3FrustTran[u4FRUST_BR] * fFarClipPlane + v3Camera;
|
|
av3[3] = av3FrustTran[u4FRUST_BL] * fFarClipPlane + v3Camera;
|
|
|
|
// Initialize variables.
|
|
skc[0].Set(&v3Camera, &av3[0], 0, 0);
|
|
skc[1].Set(&av3[0], &av3[1], f_screen_w, f_screen_h);
|
|
skc[2].Set(&v3Camera, &av3[1], f_screen_w, 0);
|
|
skc[3].Set(&av3[1], &av3[2], f_screen_w, f_screen_h);
|
|
skc[4].Set(&v3Camera, &av3[2], f_screen_w, f_screen_h);
|
|
skc[5].Set(&av3[2], &av3[3], f_screen_w, f_screen_h);
|
|
skc[6].Set(&v3Camera, &av3[3], 0, f_screen_h);
|
|
skc[7].Set(&av3[3], &av3[0], f_screen_w, f_screen_h);
|
|
|
|
// Generate outcodes.
|
|
for (u = 0; u < 4; ++u)
|
|
skc[u * 2].bValid = av3[u].tZ > fSkyHeight;
|
|
skc[1].SetValid(&skc[0], &skc[2]);
|
|
skc[3].SetValid(&skc[2], &skc[4]);
|
|
skc[5].SetValid(&skc[4], &skc[6]);
|
|
skc[7].SetValid(&skc[6], &skc[0]);
|
|
|
|
// Count the outcodes, and only render if there are three or more.
|
|
{
|
|
int i_num_inview = 0;
|
|
for (u = 0; u < 8; ++u)
|
|
if (skc[u].bValid)
|
|
++i_num_inview;
|
|
if (i_num_inview < 3)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find the worldspace point of intersection for every edge of the frustum that
|
|
// intersects the sky.
|
|
//
|
|
for (u = 0; u < 8; ++u)
|
|
if (skc[u].bValid)
|
|
skc[u].SetIntersection(fSkyHeight, fSkySize);
|
|
|
|
skc[1].SetScreenTop();
|
|
skc[3].SetScreenRight();
|
|
skc[5].SetScreenBottom();
|
|
skc[7].SetScreenLeft();
|
|
|
|
{
|
|
// Construct an inverse transform for the camera.
|
|
CTransform3<> tf3_invcam = pcam->tf3ToNormalisedCamera();
|
|
|
|
// Transform these points, base at the origin and normalize..
|
|
for (u = 0; u < 8; ++u)
|
|
{
|
|
CVector3<> v3 = skc[u].v3IntersectSky * tf3_invcam;
|
|
skc[u].fZ = v3.tY;
|
|
}
|
|
}
|
|
|
|
// Setup Direct3D for this polygon.
|
|
srd3dRenderer.SetD3DMode(ed3drSOFTWARE_LOCK);
|
|
srd3dRenderer.FlushBatch();
|
|
d3dDriver.err = d3dDriver.pGetDevice()->BeginScene();
|
|
d3dstState.SetDefault();
|
|
d3dstState.SetFog(true);
|
|
d3dstState.SetFiltering(true);
|
|
d3dstState.SetTexture(prasD3DSky.ptGet());
|
|
d3dstState.SetShading(true);
|
|
d3dstState.SetAddressing(eamTileUV);
|
|
|
|
// Turn Z buffering off.
|
|
d3dstState.SetAllowZBuffer(false);
|
|
|
|
// Set up the vertices and feed them to DrawPrimitive.
|
|
int i_num_vertices = 0;
|
|
D3DTLVERTEX atlv[8];
|
|
|
|
for (u = 0; u < 8; ++u)
|
|
{
|
|
// Add a vertex.
|
|
if (skc[u].bValid)
|
|
{
|
|
float f_z = skc[u].fZ * f_cam_scale;
|
|
float f_fog = 1.0f - f_z * 1.5f;
|
|
SetMinMax(f_fog, 0.0f, 1.0f);
|
|
D3DTLVERTEX* ptlv = &atlv[i_num_vertices];
|
|
|
|
// Set the fog colour.
|
|
D3DCOLOR d3d_fog = (uint32(f_fog * 255.0f) << 24);
|
|
|
|
// Copy the data to the TLVertex.
|
|
ptlv->sx = skc[u].v2Screen.tX + f_offset_x;
|
|
ptlv->sy = skc[u].v2Screen.tY + f_offset_y;
|
|
ptlv->sz = fInvScale / f_z;
|
|
ptlv->rhw = ptlv->sz;
|
|
ptlv->color = d3drgbPlain;
|
|
ptlv->specular = d3d_fog;
|
|
ptlv->tu = skc[u].v2UVSky.tX + fSkyOffsetU;
|
|
ptlv->tv = skc[u].v2UVSky.tY + fSkyOffsetV;
|
|
|
|
++i_num_vertices;
|
|
}
|
|
}
|
|
|
|
// Call DrawPrimitive.
|
|
d3dDriver.err = pdevice->DrawPrimitive
|
|
(
|
|
D3DPT_TRIANGLEFAN,
|
|
D3DFVF_TLVERTEX,
|
|
(LPVOID)atlv,
|
|
i_num_vertices,
|
|
u4DrawPrimFlags
|
|
);
|
|
|
|
// Render the scene.
|
|
d3dDriver.err = d3dDriver.pGetDevice()->EndScene();
|
|
}
|
|
|
|
//*****************************************************************************************
|
|
//
|
|
char* CSkyRender::pcSave
|
|
(
|
|
char* pc
|
|
) const
|
|
//
|
|
// Saves the sky settings to a buffer.
|
|
//
|
|
//**************************************
|
|
{
|
|
if (this)
|
|
{
|
|
// Save version number.
|
|
pc = pcSaveT(pc, 1);
|
|
|
|
pc = pcSaveT(pc, u4DivisionLength);
|
|
pc = pcSaveT(pc, fPixelsPerMeter);
|
|
pc = pcSaveT(pc, fFogFar);
|
|
pc = pcSaveT(pc, fFogNear);
|
|
pc = pcSaveT(pc, fSkyHeight);
|
|
pc = pcSaveT(pc, fSkyOffsetU);
|
|
pc = pcSaveT(pc, fSkyOffsetV);
|
|
pc = pcSaveT(pc, fSkyOffsetdU);
|
|
pc = pcSaveT(pc, fSkyOffsetdV);
|
|
pc = pcSaveT(pc, true); // No longer used.
|
|
pc = pcSaveT(pc, bFill);
|
|
}
|
|
else
|
|
{
|
|
// No sky to save.
|
|
pc = pcSaveT(pc, 0);
|
|
}
|
|
|
|
return pc;
|
|
}
|
|
|
|
//*****************************************************************************************
|
|
//
|
|
const char* CSkyRender::pcLoad
|
|
(
|
|
const char* pc
|
|
)
|
|
//
|
|
// Loads the sky settings from a buffer.
|
|
//
|
|
//**************************************
|
|
{
|
|
int iVersion;
|
|
|
|
pc = pcLoadT(pc, &iVersion);
|
|
|
|
if (iVersion == 1)
|
|
{
|
|
if (this)
|
|
{
|
|
pc = pcLoadT(pc, &u4DivisionLength);
|
|
pc = pcLoadT(pc, &fPixelsPerMeter);
|
|
pc = pcLoadT(pc, &fFogFar);
|
|
pc = pcLoadT(pc, &fFogNear);
|
|
pc = pcLoadT(pc, &fSkyHeight);
|
|
pc = pcLoadT(pc, &fSkyOffsetU);
|
|
pc = pcLoadT(pc, &fSkyOffsetV);
|
|
pc = pcLoadT(pc, &fSkyOffsetdU);
|
|
pc = pcLoadT(pc, &fSkyOffsetdV);
|
|
|
|
// Ignore this settings, it is set by the global quality slider.
|
|
bool b_textured;
|
|
pc = pcLoadT(pc, &b_textured);
|
|
|
|
pc = pcLoadT(pc, &bFill);
|
|
|
|
// Update dependant values.
|
|
SetWorkingConstants
|
|
(
|
|
fPixelsPerMeter,
|
|
fSkyHeight,
|
|
fFogNear,
|
|
fFogFar,
|
|
u4DivisionLength
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// Skip this data.
|
|
pc += sizeof(uint32) + sizeof(float)* 8 + sizeof(bool) * 2;
|
|
}
|
|
}
|
|
else if (iVersion != 0)
|
|
{
|
|
AlwaysAssert("Unknown version of sky settings");
|
|
}
|
|
|
|
return pc;
|
|
}
|