482 lines
15 KiB
C++
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;
|
|
}
|
|
}
|
|
}
|