windows-nt/Source/XPSP1/NT/shell/osshell/control/scrnsave/flyingobjects/genwin2.cpp
2020-09-26 16:20:57 +08:00

482 lines
15 KiB
C++

/******************************Module*Header*******************************\
* Module Name: genwin2.c
*
* The new Windows style of the 3D Flying Objects screen saver.
*
* Texture maps .BMP files onto a simulation of a flag waving in the breeze.
*
* Copyright (c) 2001 Microsoft Corporation
*
\**************************************************************************/
#include <stdlib.h>
#include <windows.h>
#include <string.h>
#include <math.h>
#include <d3dx8.h>
#include "D3DSaver.h"
#include "FlyingObjects.h"
#include "resource.h"
#include "mesh.h"
enum STATE
{
S_FREE,
S_MOVETOORIGIN,
S_FADETOCOLOR,
S_PAUSE,
S_FADEFROMCOLOR
};
#define TIME_FREE 10.0f
#define TIME_FADETOCOLOR 1.0f
#define TIME_PAUSE 5.0f
#define TIME_FADEFROMCOLOR 1.0f
// Note: There's no TIME_MOVETOORIGIN since that takes a variable amt of time.
const FLOAT winTotalwidth = (FLOAT)0.75;
const FLOAT winTotalheight = (FLOAT)0.75;
#define MAX_FRAMES 20
// IPREC is the number of faces in the mesh that models the flag.
#define IPREC 35
static int Frames = 10;
static MESH winMesh[MAX_FRAMES];
static FLOAT sinAngle = (FLOAT)0.0;
static FLOAT xTrans = (FLOAT)0.0;
// Material properties
static RGBA matlBrightSpecular = {1.0f, 1.0f, 1.0f, 1.0f};
// Lighting properties
static FLOAT light0Pos[] = {-15.0f, 0.0f, -10.0f};
/******************************Public*Routine******************************\
* iPtInList
*
* Add a vertex and its normal to the mesh. If the vertex already exists,
* add in the normal to the existing normal (we to accumulate the average
* normal at each vertex). Normalization of the normals is the
* responsibility of the caller.
*
\**************************************************************************/
static int iPtInList(MESH *mesh, int start,
POINT3D *p, POINT3D *norm, BOOL blend)
{
int i;
POINT3D *pts = mesh->pts + start;
if (blend) {
for (i = start; i < mesh->numPoints; i++, pts++) {
if ((pts->x == p->x) && (pts->y == p->y) && (pts->z == p->z)) {
mesh->norms[i].x += norm->x;
mesh->norms[i].y += norm->y;
mesh->norms[i].z += norm->z;
return i;
}
}
} else {
i = mesh->numPoints;
}
mesh->pts[i] = *p;
mesh->norms[i] = *norm;
mesh->numPoints++;
return i;
}
/******************************Public*Routine******************************\
* getZpos
*
* Get the z-position (depth) of the "wavy" flag component at the given x.
*
* The function used to model the wave is:
*
* 1/2
* z = x * sin((2*PI*x + sinAngle) / 8)
*
* The shape of the wave varies from frame to frame by changing the
* phase, sinAngle.
*
\**************************************************************************/
static FLOAT getZpos(FLOAT x)
{
FLOAT xAbs = x - xTrans;
FLOAT angle = sinAngle + ((FLOAT) (2.0 * PI) * (xAbs / winTotalwidth));
xAbs = winTotalwidth - xAbs;
return (FLOAT)(-(sin((double)angle) / 8.0) *
sqrt((double)(xAbs / winTotalwidth )));
}
/******************************Public*Routine******************************\
* genTex
*
* Generate a mesh representing a frame of the flag. The phase, sinAngle,
* is a global variable.
*
\**************************************************************************/
static BOOL genTex(MESH *winMesh)
{
POINT3D pos;
POINT3D pts[4];
FLOAT w, h;
int i;
if( !newMesh(winMesh, IPREC * IPREC, IPREC * IPREC) )
return FALSE;
// Width and height of each face
w = (winTotalwidth) / (FLOAT)(IPREC + 1);
h = winTotalheight;
// Generate the mesh data. At equally spaced intervals along the x-axis,
// we compute the z-position of the flag surface.
pos.y = (FLOAT) 0.0;
pos.z = (FLOAT) 0.0;
for (i = 0, pos.x = xTrans; i < IPREC; i++, pos.x += w) {
int faceCount = winMesh->numFaces;
pts[0].x = (FLOAT)pos.x;
pts[0].y = (FLOAT)(pos.y);
pts[0].z = getZpos(pos.x);
pts[1].x = (FLOAT)pos.x;
pts[1].y = (FLOAT)(pos.y + h);
pts[1].z = getZpos(pos.x);
pts[2].x = (FLOAT)(pos.x + w);
pts[2].y = (FLOAT)(pos.y);
pts[2].z = getZpos(pos.x + w);
pts[3].x = (FLOAT)(pos.x + w);
pts[3].y = (FLOAT)(pos.y + h);
pts[3].z = getZpos(pos.x + w);
// Compute the face normal.
ss_calcNorm(&winMesh->faces[faceCount].norm, pts + 2, pts + 1, pts);
// Add the face to the mesh.
winMesh->faces[faceCount].material = 0;
winMesh->faces[faceCount].p[0] = iPtInList(winMesh, 0, pts,
&winMesh->faces[faceCount].norm, TRUE);
winMesh->faces[faceCount].p[1] = iPtInList(winMesh, 0, pts + 1,
&winMesh->faces[faceCount].norm, TRUE);
winMesh->faces[faceCount].p[2] = iPtInList(winMesh, 0, pts + 2,
&winMesh->faces[faceCount].norm, TRUE);
winMesh->faces[faceCount].p[3] = iPtInList(winMesh, 0, pts + 3,
&winMesh->faces[faceCount].norm, TRUE);
winMesh->numFaces++;
}
// Normalize the vertex normals in the mesh.
ss_normalizeNorms(winMesh->norms, winMesh->numPoints);
return TRUE;
}
/******************************Public*Routine******************************\
* initWin2Scene
*
* Initialize the screen saver.
*
* This function is exported to the main module in ss3dfo.c.
*
\**************************************************************************/
BOOL initWin2Scene()
{
int i;
FLOAT angleDelta;
SetProjectionMatrixInfo( TRUE, 2.0f, 2.0f, 0.0f, 3.0f );
D3DXMATRIX matView;
D3DXMatrixTranslation(&matView, -0.17f, -0.04f, 1.5f);
m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
// Adjust position of light 0
D3DLIGHT8 light;
m_pd3dDevice->GetLight(0, &light);
light.Position.x = light0Pos[0];
light.Position.y = light0Pos[1];
light.Position.z = light0Pos[2];
m_pd3dDevice->SetLight(0, &light);
m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE);
m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_LINEAR );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP );
Frames = MAX_FRAMES;
// Generate the geometry data (stored in the array of mesh structures),
// for each frame of the animation. The shape of the flag is varied by
// changing the global variable sinAngle.
angleDelta = (FLOAT)(2.0 * PI) / (FLOAT)Frames;
sinAngle = (FLOAT) 0.0;
for (i = 0; i < Frames; i++) {
if( !genTex(&winMesh[i]) )
return FALSE;
sinAngle += angleDelta;
}
return TRUE;
}
/******************************Public*Routine******************************\
* delWin2Scene
*
* Cleanup the data associated with this screen saver.
*
* This function is exported to the main module in ss3dfo.c.
*
\**************************************************************************/
void delWin2Scene()
{
int i;
for (i = 0; i < Frames; i++)
delMesh(&winMesh[i]);
}
/******************************Public*Routine******************************\
* updateWin2Scene
*
* Generate a scene by taking one of the meshes and rendering it
*
* This function is exported to the main module in ss3dfo.c.
*
\**************************************************************************/
void updateWin2Scene(int flags, FLOAT fElapsedTime)
{
MESH *pMesh;
static double mxrot = 40.0;
static double myrot = 0;
static double mzrot = -12.0;
static int frameNum = 0;
static FLOAT fFrameNum = (FLOAT)Frames;
FLOAT s = 0.0f;
FLOAT ds;
static FLOAT s_fTime = 0.0f;
static FLOAT s_fTimeLastChange = 0.0f;
static FLOAT s_fTimeNextChange = TIME_FREE;
static STATE s_state = S_FREE;
FLOAT fBeta;
if( fElapsedTime > 0.25f )
fElapsedTime = 0.25f;
FLOAT fTimeFactor = fElapsedTime * 20.0f;
HRESULT hr;
s_fTime += fElapsedTime;
if( s_fTimeNextChange != -1.0f && s_fTime > s_fTimeNextChange )
{
// Handle state transitions
s_fTimeLastChange = s_fTime;
switch( s_state )
{
case S_FREE:
s_state = S_MOVETOORIGIN;
g_bMoveToOrigin = TRUE;
s_fTimeNextChange = -1.0f;
break;
case S_MOVETOORIGIN:
s_state = S_FADETOCOLOR;
s_fTimeNextChange = s_fTime + TIME_FADETOCOLOR;
break;
case S_FADETOCOLOR:
s_state = S_PAUSE;
s_fTimeNextChange = s_fTime + TIME_PAUSE;
break;
case S_PAUSE:
s_state = S_FADEFROMCOLOR;
s_fTimeNextChange = s_fTime + TIME_FADEFROMCOLOR;
break;
case S_FADEFROMCOLOR:
s_state = S_FREE;
s_fTimeNextChange = s_fTime + TIME_FREE;
g_bMoveToOrigin = FALSE;
break;
}
}
fBeta = 0.0f;
// Handle state processing
switch( s_state )
{
case S_MOVETOORIGIN:
if( g_bAtOrigin && frameNum == 0)
s_fTimeNextChange = s_fTime; // provoke state change next time
break;
case S_FADETOCOLOR:
fBeta = (s_fTime - s_fTimeLastChange) / TIME_FADETOCOLOR;
break;
case S_PAUSE:
fBeta = 1.0f;
break;
case S_FADEFROMCOLOR:
fBeta = 1.0f - ( (s_fTime - s_fTimeLastChange) / TIME_FADEFROMCOLOR );
break;
}
if( fBeta != 0.0f )
{
// Render background logo
MYVERTEX3 v[4];
FLOAT fLeft = g_pFloatRect->xMin - g_xScreenOrigin;
FLOAT fRight = fLeft + g_pFloatRect->xSize;
FLOAT fBottom = g_pFloatRect->yMin - g_yScreenOrigin;
FLOAT fTop = g_pFloatRect->yMin + g_pFloatRect->ySize;
DWORD dwColor = D3DXCOLOR( 1.0f, 1.0f, 1.0f, fBeta );
v[0].p = D3DXVECTOR3(fLeft, fBottom, 0.9f); v[0].rhw = 0.1f; v[0].dwDiffuse = dwColor; v[0].tu = 0.0f; v[0].tv = 0.0f;
v[1].p = D3DXVECTOR3(fRight, fBottom, 0.9f); v[1].rhw = 0.1f; v[1].dwDiffuse = dwColor; v[1].tu = 1.0f; v[1].tv = 0.0f;
v[2].p = D3DXVECTOR3(fLeft, fTop, 0.9f); v[2].rhw = 0.1f; v[2].dwDiffuse = dwColor; v[2].tu = 0.0f; v[2].tv = 1.0f;
v[3].p = D3DXVECTOR3(fRight, fTop, 0.9f); v[3].rhw = 0.1f; v[3].dwDiffuse = dwColor; v[3].tu = 1.0f; v[3].tv = 1.0f;
hr = m_pd3dDevice->SetTexture( 0, g_pDeviceObjects->m_pTexture2 );
hr = m_pd3dDevice->SetVertexShader( D3DFVF_MYVERTEX3 );
hr = m_pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, v, sizeof(MYVERTEX3) );
}
m_pd3dDevice->SetTexture( 0, g_pDeviceObjects->m_pTexture );
D3DXMATRIX mat1, mat2, mat3, mat4, matFinal;
D3DXMatrixRotationX(&mat1, D3DXToRadian((FLOAT)mxrot));
D3DXMatrixRotationY(&mat2, D3DXToRadian((FLOAT)myrot));
D3DXMatrixRotationZ(&mat3, D3DXToRadian((FLOAT)mzrot));
D3DXMatrixScaling( &mat4, 0.82f, 0.92f, 0.82f );
matFinal = mat4 * mat3 * mat2 * mat1 ;
m_pd3dDevice->SetTransform( D3DTS_WORLD, &matFinal );
// Divide the texture into IPREC slices. ds is the texture coordinate
// delta we apply as we move along the x-axis.
ds = (FLOAT)1.0 / (FLOAT)IPREC;
// Setup the material property of the flag. The material property, light
// properties, and polygon orientation will interact with the texture.
myglMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (FLOAT *) &matlBrightSpecular);
myglMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, (FLOAT) 40.0);
FLOAT fColor[4];
fColor[0] = 1.0f;
fColor[1] = 1.0f;
fColor[2] = 1.0f;
fColor[3] = 1.0f - fBeta; // Adjust flag alpha so it fades when showing logo
if( fColor[3] != 0.0f )
{
// Render flag
myglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, fColor);
pMesh = &winMesh[frameNum];
INT numPrims = 0;
INT numIndices = 0;
INT numVertices = 0;
WORD iVertexA, iVertexB, iVertexC, iVertexD;
INT a,b,c,d;
MFACE *faces;
WORD* i;
MYVERTEX2* v;
hr = m_pVB2->Lock( 0, 0, (BYTE**)&v, 0 );
hr = m_pIB->Lock( 0, MAX_INDICES, (BYTE**)&i, 0 );
faces = pMesh->faces;
for( int iFace = 0; iFace < pMesh->numFaces; iFace++ )
{
a = faces[iFace].p[0];
b = faces[iFace].p[1];
c = faces[iFace].p[2];
d = faces[iFace].p[3];
v[numVertices].p = pMesh->pts[a];
v[numVertices].n = bSmoothShading ? -pMesh->norms[a] : -faces[iFace].norm;
v[numVertices].tu = s; v[numVertices].tv = 1.0f;
iVertexA = numVertices++;
v[numVertices].p = pMesh->pts[b];
v[numVertices].n = bSmoothShading ? -pMesh->norms[b] : -faces[iFace].norm;
v[numVertices].tu = s; v[numVertices].tv = 0.0f;
iVertexB = numVertices++;
v[numVertices].p = pMesh->pts[c];
v[numVertices].n = bSmoothShading ? -pMesh->norms[c] : -faces[iFace].norm;
v[numVertices].tu = s+ds; v[numVertices].tv = 1.0f;
iVertexC = numVertices++;
v[numVertices].p = pMesh->pts[d];
v[numVertices].n = bSmoothShading ? -pMesh->norms[d] : -faces[iFace].norm;
v[numVertices].tu = s+ds; v[numVertices].tv = 0.0f;
iVertexD = numVertices++;
s += ds;
i[numIndices++] = iVertexA;
i[numIndices++] = iVertexB;
i[numIndices++] = iVertexC;
numPrims++;
i[numIndices++] = iVertexC;
i[numIndices++] = iVertexB;
i[numIndices++] = iVertexD;
numPrims++;
}
hr = m_pVB2->Unlock();
hr = m_pIB->Unlock();
hr = m_pd3dDevice->SetVertexShader( D3DFVF_MYVERTEX2 );
hr = m_pd3dDevice->SetStreamSource( 0, m_pVB2, sizeof(MYVERTEX2) );
hr = m_pd3dDevice->SetIndices( m_pIB, 0 );
hr = m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, numVertices,
0, numPrims );
}
// Don't change frame number if we're in S_FADETOCOLOR, S_PAUSE,
// or S_FADEFROMCOLOR, unless by some chance we're in those states
// but framenum is not at zero (yet).
if( frameNum != 0 ||
s_state != S_FADETOCOLOR &&
s_state != S_PAUSE &&
s_state != S_FADEFROMCOLOR )
{
fFrameNum -= fTimeFactor;
frameNum = (INT)fFrameNum;
if (frameNum < 0)
{
fFrameNum = (FLOAT)(Frames - 1);
frameNum = Frames - 1;
}
}
}