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

648 lines
20 KiB
C++

//-----------------------------------------------------------------------------
// File: Dolphin.cpp
//
// Desc: Sample of swimming dolphin
//
// Note: This code uses the D3D Framework helper library.
//
// Copyright (c) 1998-1999 Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#include "stdafx.h"
#define D3D_OVERLOADS
#include "StdAfx.h"
#include <ddraw.h>
#include <d3d.h>
#include "D3DApp.h"
#include "D3DUtil.h"
#include "D3DMath.h"
#include "D3DTextr.h"
#include "D3DFile.h"
#include <math.h>
#include <time.h>
//#include <mmsystem.h>
#include "dxsvr.h"
#include "sealife.h"
float rnd(void)
{
return float(rand())/RAND_MAX;
}
//-----------------------------------------------------------------------------
// Name: CSeaLife()
// Desc: Constructor
//-----------------------------------------------------------------------------
/*
*/
CSeaLife::CSeaLife()
{
// Initialize member variables
m_pDolphinGroupObject = NULL;
m_pDolphinObject = NULL;
m_pFloorObject = NULL;
m_pFish1Object = NULL;
m_pd3dDevice = NULL;
m_pDeviceInfo = NULL;
}
//-----------------------------------------------------------------------------
// Name: OneTimeSceneInit()
// Desc: Called during initial app startup, this function performs all the
// permanent initialization.
//-----------------------------------------------------------------------------
HRESULT CSeaLife::OneTimeSceneInit()
{
HRESULT hr;
m_pDolphinGroupObject = NULL;
m_pDolphinObject = NULL;
m_pFloorObject = NULL;
m_pFish1Object = NULL;
m_pd3dDevice = NULL;
m_pDeviceInfo = NULL;
m_pDolphinGroupObject = new CD3DFile();
m_pDolphinObject = new CD3DFile();
m_pFloorObject = new CD3DFile();
m_pFish1Object = new CD3DFile();
hr = m_pDolphinGroupObject->Load(TEXT("dolphin_group.x"));
hr |= m_pDolphinGroupObject->GetMeshVertices(TEXT("Dolph01"), &m_pDolphin1Vertices, &m_dwNumDolphinVertices);
hr |= m_pDolphinGroupObject->GetMeshVertices(TEXT("Dolph02"), &m_pDolphin2Vertices, &m_dwNumDolphinVertices);
hr |= m_pDolphinGroupObject->GetMeshVertices(TEXT("Dolph03"), &m_pDolphin3Vertices, &m_dwNumDolphinVertices);
if (FAILED(hr))
{
MessageBox(NULL, TEXT("Error loading DOLPHIN_GROUP.X file"),
TEXT("Dolphins"), MB_OK|MB_ICONERROR);
return E_FAIL;
}
hr = m_pDolphinObject->Load(TEXT("dolphin.x"));
hr |= m_pDolphinObject->GetMeshVertices(TEXT("Dolph02"), &m_pDolphinVertices, &m_dwNumDolphinVertices);
if (FAILED(hr))
{
MessageBox(NULL, TEXT("Error loading DOLPHIN.X file"),
TEXT("Dolphins"), MB_OK|MB_ICONERROR);
return E_FAIL;
}
hr = m_pFloorObject->Load(TEXT("seafloor.x"));
hr |= m_pFloorObject->GetMeshVertices(TEXT("SeaFloor"), &m_pFloorVertices, &m_dwNumFloorVertices);
if (FAILED(hr))
{
MessageBox(NULL, TEXT("Error loading SEAFLOOR.X file"),
TEXT("Dolphins"), MB_OK|MB_ICONERROR);
return E_FAIL;
}
hr = m_pFish1Object->Load(TEXT("clownfish2.x"));
D3DTextr_CreateTextureFromFile(TEXT("seafloor.bmp"));
D3DTextr_CreateTextureFromFile(TEXT("dolphin.bmp"));
srand(5);
// Scale the sea floor vertices, and add some bumpiness
for(DWORD i=0; i<m_dwNumFloorVertices; i++)
{
m_pFloorVertices[i].y += (rand()/(FLOAT)RAND_MAX);
m_pFloorVertices[i].y += (rand()/(FLOAT)RAND_MAX);
m_pFloorVertices[i].y += (rand()/(FLOAT)RAND_MAX);
m_pFloorVertices[i].tu *= 10;
m_pFloorVertices[i].tv *= 10;
}
// Scale the dolphin vertices (the model file is too big)
for(i=0; i<m_dwNumDolphinVertices; i++)
{
D3DVECTOR vScale(0.01f, 0.01f, 0.01f);
*((D3DVECTOR*)(&m_pDolphin1Vertices[i])) *= vScale;
*((D3DVECTOR*)(&m_pDolphin2Vertices[i])) *= vScale;
*((D3DVECTOR*)(&m_pDolphin3Vertices[i])) *= vScale;
}
for (i=0; i<NUM_FISH;i++)
{
ZeroMemory(&m_FishState[i],sizeof(FISHSTRUCT));
m_FishState[i].type=FISHTYPE_DOLPHIN;
m_FishState[i].dir=D3DVECTOR(0,0,1);
m_FishState[i].goal=D3DVECTOR(XEXTENT,YEXTENT,ZEXTENT);
m_FishState[i].loc=D3DVECTOR(XEXTENT,0,ZEXTENT);
m_FishState[i].speed = DOLPHINSPEED;
m_FishState[i].angle_tweak =TWEAK;
m_FishState[i].pitch=INITPITCH;
m_FishState[i].turndelta=(float)TURNDELTADOLPHIN;
m_FishState[i].pitchchange= (float)PITCHCHANGE;
m_FishState[i].pitchdelta= PITCHDELTA;
if ((i > NUM_DOLPHINS))
{
m_FishState[i].type=FISHTYPE_FISH1;
m_FishState[i].pitchchange= (float)PITCHCHANGEFISH;
m_FishState[i].pitchdelta= PITCHDELTAFISH;
m_FishState[i].turndelta=(float)TURNDELTAFISH;
m_FishState[i].angle_tweak =TWEAKFISH;
m_FishState[i].speed = FISHSPEED;
;
}
}
m_FishState[0].type=FISHTYPE_CAMERA;
m_FishState[0].turndelta=(float)TURNDELTADOLPHIN;
m_FishState[0].angle_tweak =TWEAK;
srand (time (0));
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: FinalCleanup()
// Desc: Called before the app exits, this function gives the app the chance
// to cleanup after itself.
//-----------------------------------------------------------------------------
HRESULT CSeaLife::FinalCleanup()
{
SAFE_DELETE(m_pDolphinGroupObject);
SAFE_DELETE(m_pDolphinObject);
SAFE_DELETE(m_pFloorObject);
//dont cleanup device object..
D3DTextr_InvalidateAllTextures();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: BlendMeshes()
// Desc: Does a linear interpolation between all vertex positions and normals
// in two source meshes and outputs the result to the destination mesh.
// This function assumes that all strided vertices have the same stride,
// and that each mesh contains the same number of vertices
//-----------------------------------------------------------------------------
VOID BlendMeshes(D3DVERTEX* pDstMesh, D3DVERTEX* pSrcMesh1,
D3DVERTEX* pSrcMesh2, DWORD dwNumVertices, FLOAT fWeight)
{
FLOAT fInvWeight = 1.0f - fWeight;
// LERP positions and normals
for(DWORD i=0; i<dwNumVertices; i++)
{
pDstMesh->x = fWeight*pSrcMesh1->x + fInvWeight*pSrcMesh2->x;
pDstMesh->y = fWeight*pSrcMesh1->y + fInvWeight*pSrcMesh2->y;
pDstMesh->z = fWeight*pSrcMesh1->z + fInvWeight*pSrcMesh2->z;
pDstMesh->nx = fWeight*pSrcMesh1->nx + fInvWeight*pSrcMesh2->nx;
pDstMesh->ny = fWeight*pSrcMesh1->ny + fInvWeight*pSrcMesh2->ny;
pDstMesh->nz = fWeight*pSrcMesh1->nz + fInvWeight*pSrcMesh2->nz;
pDstMesh++;
pSrcMesh1++;
pSrcMesh2++;
}
}
//-----------------------------------------------------------------------------
// Name: Render()
// Desc: Called once per frame, the call is the entry point for 3d
// rendering. This function sets up render states, clears the
// viewport, and renders the scene.
//-----------------------------------------------------------------------------
HRESULT CSeaLife::Render(LPDIRECT3DDEVICE7 lpDev)
{
float fWeight;
D3DMATRIX* pmatDest=NULL;
D3DUtil_SetIdentityMatrix(m_matFloor);
if (lpDev!=m_pd3dDevice)
{
D3DTextr_RestoreAllTextures(lpDev);
}
m_pd3dDevice=lpDev;
// Clear the viewport
m_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
WATER_COLOR, 1.0f, 0L);
// Begin the scene
if (SUCCEEDED(m_pd3dDevice->BeginScene()))
{
m_pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matFloor);
m_pFloorObject->Render(m_pd3dDevice);
// Move the dolphin in a circle
CD3DFileObject* pDolphinObject = m_pDolphinObject->FindObject(TEXT("x3ds_Dolph02"));
CD3DFileObject* pFish1Object = m_pFish1Object->FindObject(TEXT("clownfish_root"));
for (int i =0;i<NUM_FISH;i++)
{
switch (m_FishState[i].type)
{
case FISHTYPE_DOLPHIN:
fWeight=-m_FishState[i].weight;
if(fWeight < 0.0f)
{
BlendMeshes(m_pDolphinVertices, m_pDolphin3Vertices,
m_pDolphin2Vertices, m_dwNumDolphinVertices, -fWeight);
}
else
{
BlendMeshes(m_pDolphinVertices, m_pDolphin1Vertices,
m_pDolphin2Vertices, m_dwNumDolphinVertices, fWeight);
}
if (pDolphinObject)
{
m_pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matFloor);
pmatDest = pDolphinObject->GetMatrix();
*pmatDest=m_FishState[i].matrix;
m_pDolphinObject->Render(m_pd3dDevice);
}
break;
case FISHTYPE_FISH1:
if (pFish1Object)
{
m_pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &m_matFloor);
pmatDest = pFish1Object->GetMatrix();
*pmatDest=m_FishState[i].matrix;
m_pFish1Object->Render(m_pd3dDevice);
}
break;
}
}
// End the scene.
m_pd3dDevice->EndScene();
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: InitDeviceObjects()
// Desc: Initialize scene objects.
//-----------------------------------------------------------------------------
HRESULT CSeaLife::InitDeviceObjects(LPDIRECT3DDEVICE7 pDev ,D3DEnum_DeviceInfo* pInfo)
{
if (!pDev) return E_FAIL;
m_pd3dDevice=pDev;
m_pDeviceInfo=pInfo;
// Set up the lighting states
// if (m_pDeviceInfo->ddDeviceDesc.dwVertexProcessingCaps &
// D3DVTXPCAPS_DIRECTIONALLIGHTS)
{
D3DLIGHT7 light;
D3DUtil_InitLight(light, D3DLIGHT_DIRECTIONAL, 0.0f, -1.0f, 0.0f);
m_pd3dDevice->SetLight(0, &light);
m_pd3dDevice->LightEnable(0, TRUE);
m_pd3dDevice->SetRenderState(D3DRENDERSTATE_LIGHTING, TRUE);
}
m_pd3dDevice->SetRenderState(D3DRENDERSTATE_AMBIENT, 0x33333333);
// Set the transform matrices
D3DVIEWPORT7 vp;
m_pd3dDevice->GetViewport(&vp);
FLOAT fAspect = ((FLOAT)vp.dwHeight) / vp.dwWidth;
D3DVECTOR vEyePt = D3DVECTOR(0.0f, 0.0f, -10.0f);
D3DVECTOR vLookatPt = D3DVECTOR(0.0f, 0.0f, 0.0f);
D3DVECTOR vUpVec = D3DVECTOR(0.0f, 1.0f, 0.0f);
D3DMATRIX matWorld, matProj;
D3DUtil_SetIdentityMatrix(matWorld);
m_pd3dDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &matWorld);
D3DMATRIX matView;
D3DUtil_SetViewMatrix(matView,vEyePt, vLookatPt, vUpVec);
m_pd3dDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &matView);
D3DUtil_SetProjectionMatrix(matProj, g_PI/3, fAspect, 1.0f, 1000.0f);
m_pd3dDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &matProj);
// Set up textures
D3DTextr_RestoreAllTextures(m_pd3dDevice);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_LINEAR);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR);
// Set default render states
m_pd3dDevice->SetRenderState(D3DRENDERSTATE_DITHERENABLE, TRUE);
m_pd3dDevice->SetRenderState(D3DRENDERSTATE_SPECULARENABLE, FALSE);
m_pd3dDevice->SetRenderState(D3DRENDERSTATE_ZENABLE, TRUE);
// Turn on fog
FLOAT fFogStart = 1.0f;
FLOAT fFogEnd = 50.0f;
FLOAT fDense = 0.5f;
//note turn off fog for RGB
//m_pd3dDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
m_pd3dDevice->SetRenderState(D3DRENDERSTATE_FOGENABLE, TRUE);
m_pd3dDevice->SetRenderState(D3DRENDERSTATE_FOGCOLOR, WATER_COLOR);
m_pd3dDevice->SetRenderState(D3DRENDERSTATE_FOGTABLEMODE, D3DFOG_NONE);
m_pd3dDevice->SetRenderState(D3DRENDERSTATE_FOGDENSITY, *(DWORD*)(&fDense));
m_pd3dDevice->SetRenderState(D3DRENDERSTATE_FOGVERTEXMODE, D3DFOG_LINEAR);
m_pd3dDevice->SetRenderState(D3DRENDERSTATE_FOGSTART, *((DWORD *)(&fFogStart)));
m_pd3dDevice->SetRenderState(D3DRENDERSTATE_FOGEND, *((DWORD *)(&fFogEnd)));
D3DTextr_Restore(TEXT("seafloor.bmp") ,m_pd3dDevice);
D3DTextr_Restore(TEXT("dolphin.bmp"), m_pd3dDevice);
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DeleteDeviceObjects()
// Desc: Called when the app is exitting, or the device is being changed,
// this function deletes any device dependant objects.
//-----------------------------------------------------------------------------
HRESULT CSeaLife::DeleteDeviceObjects()
{
D3DTextr_InvalidateAllTextures();
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: FrameMove()
// Desc: Called once per frame, the call is the entry point for animating
// the scene.
//-----------------------------------------------------------------------------
HRESULT CSeaLife::FrameMove(FLOAT fTimeKeyIn)
{
D3DVECTOR vDirXZ;
D3DVECTOR vDeltaXZ;
float dotProd;
static DWORD dwLastTime=0;
float deltaspeed=.002f;
DWORD dwThisTime=timeGetTime();
if (dwLastTime != 0)
{
deltaspeed=((float)(dwThisTime-dwLastTime))/10000.0f;
}
dwLastTime=dwThisTime;
float fT,fT2,fT3 ;
D3DMATRIX matFish;
D3DMATRIX matYRotate,matZRotate,matXRotate;
D3DMATRIX matTrans1, matScale;
D3DMATRIX matRotate1, matRotate2;
D3DMATRIX matTemp,matTemp2;
FLOAT fPhase;
FLOAT fKickFreq;
FLOAT fTimeKey;
FLOAT fJiggleFreq;
for (int i=0; i< NUM_FISH;i++)
{
//time based numbers
fTimeKey=fTimeKeyIn+i*2;
fKickFreq = 3*fTimeKey;
fJiggleFreq = fTimeKey;
fT=-(DOLPHINUPDOWN(fKickFreq));
fT2=-fT/2;
fT3=(float) ((3.1415/32)*sin(fTimeKeyIn/10));
fPhase = (fTimeKey)/3;
m_FishState[i].weight= - (float)sin(fKickFreq);
//get the vector from current location to the goal
vDeltaXZ=m_FishState[i].goal -m_FishState[i].loc ;
vDeltaXZ.y=0;
//transpose x and z coordinates to find normal to direction
//only for the dolphin though
vDirXZ.x =-m_FishState[i].dir.z;
vDirXZ.z = m_FishState[i].dir.x;
vDirXZ.y =0;
//take dot product to determine what side to turn to
dotProd=DotProduct(vDeltaXZ,vDirXZ);
// turn by adding yaw
if (dotProd < -m_FishState[i].turndelta)
m_FishState[i].yaw +=m_FishState[i].angle_tweak;
if (dotProd > m_FishState[i].turndelta)
m_FishState[i].yaw -=m_FishState[i].angle_tweak;
// now see how far we have to go up and down.
float deltaY=m_FishState[i].goal.y - m_FishState[i].loc.y;
if (deltaY < -m_FishState[i].pitchdelta)
{
m_FishState[i].pitch+=m_FishState[i].pitchchange;
if (m_FishState[i].pitch > 0.8f) m_FishState[i].pitch=0.8f;
}
else if (deltaY > PITCHDELTA)
{
m_FishState[i].pitch-=m_FishState[i].pitchchange;
if (m_FishState[i].pitch < -0.8f) m_FishState[i].pitch=-0.8f;
}
else
{
m_FishState[i].pitch *= .95f;
}
if (m_FishState[i].type==FISHTYPE_FISH1)
{
//note for the dolphin we will modulate the pitch
D3DUtil_SetRotateYMatrix(matYRotate, (float) (m_FishState[i].yaw+FISHWIGGLE));
D3DUtil_SetRotateXMatrix(matXRotate,-m_FishState[i].pitch);
D3DMath_MatrixMultiply(matTemp, matXRotate, matYRotate); //ak
}
else if (m_FishState[i].type==FISHTYPE_CAMERA)
{
D3DUtil_SetRotateYMatrix(matYRotate,m_FishState[i].yaw);
D3DUtil_SetRotateXMatrix(matXRotate,-m_FishState[i].pitch);
D3DMath_MatrixMultiply(matTemp, matXRotate, matYRotate); //ak
}
else
{
//note for the dolphin we will modulate the pitch
D3DUtil_SetRotateYMatrix(matYRotate,m_FishState[i].yaw);
D3DUtil_SetRotateXMatrix(matXRotate,-m_FishState[i].pitch+fT);
D3DMath_MatrixMultiply(matTemp, matXRotate, matYRotate); //ak
}
//extract a new direction vector
m_FishState[i].dir[0] = -matTemp(2, 0);
m_FishState[i].dir[1] = -matTemp(2, 1);
m_FishState[i].dir[2] = -matTemp(2, 2);
//normalize direction
m_FishState[i].dir = Normalize(m_FishState[i].dir);
if (m_FishState[i].type ==FISHTYPE_CAMERA)
{
D3DVECTOR local_up;
D3DVECTOR from;
D3DVECTOR at;
D3DVECTOR loc = m_FishState[i].loc;
D3DVECTOR dir = m_FishState[i].dir;
D3DMATRIX view;
local_up.x =matTemp(1, 0);
local_up.y =matTemp(1, 1);
local_up.z =matTemp(1, 2);
from=loc; // - 20 * dir + 3* local_up;
at= loc+dir;
//SetViewParams(&from,&at,&local_up,1.0f);
}
//update the location
//TODO make time based
m_FishState[i].loc += m_FishState[i].speed *deltaspeed* m_FishState[i].dir;
//if we near our goal choose another one
D3DVECTOR vRes = (m_FishState[i].goal - m_FishState[i].loc);
if ((((int)abs(vRes.x)) < 1) && (((int)abs(vRes.z)) < 1))
{
m_FishState[i].goal=D3DVECTOR(XEXTENT,YEXTENT,ZEXTENT);
}
if (m_FishState[i].type==FISHTYPE_FISH1)
{
D3DUtil_SetRotateXMatrix(matRotate2,-m_FishState[i].pitch);
D3DUtil_SetScaleMatrix(matScale,10,10,10);
D3DUtil_SetRotateYMatrix(matRotate1,m_FishState[i].yaw+FISHWIGGLE);
if (rnd()<.01)
{
m_FishState[i].goal=D3DVECTOR(XEXTENT,YEXTENT,ZEXTENT);
}
}
else if (m_FishState[i].type==FISHTYPE_CAMERA)
{
D3DUtil_SetRotateXMatrix(matRotate2,-m_FishState[i].pitch);
D3DUtil_SetScaleMatrix(matScale,10,10,10);
D3DUtil_SetRotateYMatrix(matRotate1,m_FishState[i].yaw);
if (rnd()<.01)
{
m_FishState[i].goal=D3DVECTOR(XEXTENT,YEXTENT,ZEXTENT);
}
}
else
{
D3DUtil_SetScaleMatrix(matScale,1,1,1);
D3DUtil_SetRotateZMatrix(matRotate2,m_FishState[i].pitch +fT2);
D3DUtil_SetRotateYMatrix(matRotate1,m_FishState[i].yaw-3.1415/2);
}
D3DUtil_SetTranslateMatrix(matTrans1,
m_FishState[i].loc.x,
m_FishState[i].loc.y,
m_FishState[i].loc.z);
D3DMath_MatrixMultiply(matTemp, matRotate2, matRotate1);
D3DMath_MatrixMultiply(matTemp2, matTemp, matScale);
D3DMath_MatrixMultiply(matFish, matTemp2, matTrans1);
m_FishState[i].matrix = matFish;
}
return S_OK;
}
#if 0
float dot = DotProduct (offset, FISH[i].delta);
offset = CrossProduct (offset, FISH[i].delta);
dot = (1.0f-dot)/2.0f * angle_tweak * 10.0f;
if (offset.y > 0.01) {
FISH[i].dyaw = (FISH[i].dyaw*9.0f + dot) * 0.1f;
} else if (offset.y < 0.01) {
FISH[i].dyaw = (FISH[i].dyaw*9.0f - dot) * 0.1f;
}
FISH[i].yaw += FISH[i].dyaw;
FISH[i].roll = -FISH[i].dyaw * 9.0f;
#endif