/////////////////////////////////////////////////////////////////////////////// // File: VBlob.cpp // // Copyright 2001 Pipeworks Software /////////////////////////////////////////////////////////////////////////////// #include "precomp.h" #include "xbs_math.h" #include "xbs_app.h" #include "qrand.h" #include "VBlob.h" #include "tex_gen.h" /////////////////////////////////////////////////////////////////////////////// const float MIN_SPAWN_MAGN = (0.5f); #define BLOBLET_DIM (8) #define BLOB_DIM (32) /////////////////////////////////////////////////////////////////////////////// QRand VBlob::m_QRand; VBlob* gpVBlob; /////////////////////////////////////////////////////////////////////////////// void VBlob::Init() { int i; for (i = 0; i < MAX_BLOBBUMPS; i++) { m_BlobBumps[i].Init(); } for (i = 0; i < MAX_BLOBLETS; i++) { m_Bloblets[i].Init(); } m_QRand.Init(); m_pBlobletVB = m_pBlobVBConst = m_pBlobVBChangingR = m_pBlobVBChangingU = NULL; m_pBlobletIB = m_pBlobIB = NULL; m_pUnitSphereNormals = NULL; m_dwNumBlobletVertices = m_dwNumBlobletIndices = m_NumVertsPerFace = m_dwNumVertices = m_dwNumIndices = 0; m_dwVShaderBlob = m_dwVShaderBloblet = 0; m_dwPShaderBlob = m_dwPShaderBloblet = 0; m_NumBlobBumps = m_NumBloblets = 0; Set(&m_BlobColor, 0.25f, 1.0f, 0.15f, 1.0f); Set(&m_Pos, 0.0f, 0.0f, 0.0f); Set(&m_Scale, 1.0f, 1.0f, 1.0f); m_fRadius = 2.3f; } /////////////////////////////////////////////////////////////////////////////// void VBlob::create() { gpVBlob = this; gpd3dDev->CreateVertexBuffer(4 * sizeof(float)*5, 0, 0, 0, &pHaloQuadVB); //MTS generateUnitSphere(2, &m_pBlobletVB, &m_pBlobletIB, NULL, &m_dwNumBlobletVertices, &m_dwNumBlobletIndices); generateUnitSphere(BLOBLET_DIM, &m_pBlobletVB, &m_pBlobletIB, NULL, &m_dwNumBlobletVertices, &m_dwNumBlobletIndices); generateUnitSphere(BLOB_DIM, &m_pBlobVBConst, &m_pBlobIB, &m_pUnitSphereNormals, &m_dwNumVertices, &m_dwNumIndices); gpd3dDev->CreateVertexBuffer(m_dwNumVertices * sizeof(VBlobChangingVertex), 0, 0, 0, &m_pBlobVBChangingR); gpd3dDev->CreateVertexBuffer(m_dwNumVertices * sizeof(VBlobChangingVertex), 0, 0, 0, &m_pBlobVBChangingU); m_NumVertsPerFace = m_dwNumVertices / 6; restart(); // Initialize the pixel shaders. if( m_dwPShaderBlob ) { gpd3dDev->DeletePixelShader( m_dwPShaderBlob ); m_dwPShaderBlob = 0; } #ifndef BINARY_RESOURCE m_dwPShaderBlob = gApp.loadPixelShader("D:\\Shaders\\VBlob.xpu"); #else // BINARY_RESOURCE m_dwPShaderBlob = gApp.loadPixelShader(g_vblob_xpu); #endif // BINARY_RESOURCE if( m_dwPShaderBloblet ) { gpd3dDev->DeletePixelShader( m_dwPShaderBloblet ); m_dwPShaderBloblet = 0; } #ifndef BINARY_RESOURCE m_dwPShaderBloblet = gApp.loadPixelShader("D:\\Shaders\\VBloblet.xpu"); #else // BINARY_RESOURCE m_dwPShaderBloblet = gApp.loadPixelShader(g_vbloblet_xpu); #endif // BINARY_RESOURCE // Initialize the vertex shaders. DWORD dwBlobShaderVertexDecl[] = { D3DVSD_STREAM( 0 ), D3DVSD_REG( 0, D3DVSDT_FLOAT3 ), // unit sphere normal D3DVSD_STREAM( 1 ), D3DVSD_REG( 1, D3DVSDT_FLOAT4 ), // vertex normal, w is displacement D3DVSD_END() }; if (m_dwVShaderBlob) { gpd3dDev->DeleteVertexShader( m_dwVShaderBlob ); m_dwVShaderBlob = 0; } #ifndef BINARY_RESOURCE m_dwVShaderBlob = gApp.loadVertexShader("D:\\Shaders\\VBlob.xvu", dwBlobShaderVertexDecl); #else // BINARY_RESOURCE m_dwVShaderBlob = gApp.loadVertexShader(g_vblob_xvu, dwBlobShaderVertexDecl); #endif // BINARY_RESOURCE DWORD dwBlobletShaderVertexDecl[] = { D3DVSD_STREAM( 0 ), D3DVSD_REG( 0, D3DVSDT_FLOAT3 ), // unit sphere normal D3DVSD_END() }; if (m_dwVShaderBloblet) { gpd3dDev->DeleteVertexShader( m_dwVShaderBloblet ); m_dwVShaderBloblet = 0; } #ifndef BINARY_RESOURCE m_dwVShaderBloblet = gApp.loadVertexShader("D:\\Shaders\\VBloblet.xvu", dwBlobletShaderVertexDecl); #else // BINARY_RESOURCE m_dwVShaderBloblet = gApp.loadVertexShader(g_vbloblet_xvu, dwBlobletShaderVertexDecl); #endif // BINARY_RESOURCE } /////////////////////////////////////////////////////////////////////////////// void VBlob::destroy() { m_pBlobletVB->Release(); m_pBlobletIB->Release(); m_pBlobVBConst->Release(); m_pBlobVBChangingR->Release(); m_pBlobVBChangingU->Release(); m_pBlobIB->Release(); MemFree(m_pUnitSphereNormals); pHaloQuadVB->Release(); if (m_dwPShaderBlob) gpd3dDev->DeletePixelShader(m_dwPShaderBlob); if (m_dwPShaderBloblet) gpd3dDev->DeletePixelShader(m_dwPShaderBloblet); if (m_dwVShaderBlob) gpd3dDev->DeleteVertexShader(m_dwVShaderBlob); if (m_dwVShaderBloblet) gpd3dDev->DeleteVertexShader(m_dwVShaderBloblet); m_pBlobletVB = NULL; m_pBlobletIB = NULL; m_pBlobVBConst = NULL; m_pBlobVBChangingU = m_pBlobVBChangingR = NULL; m_pBlobIB = NULL; m_pUnitSphereNormals = NULL; } /////////////////////////////////////////////////////////////////////////////// void VBlob::render() { // Set default states gpd3dDev->SetRenderState( D3DRS_LIGHTING, FALSE ); gpd3dDev->SetRenderState( D3DRS_ZENABLE, TRUE ); gpd3dDev->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); gpd3dDev->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); gpd3dDev->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_NONE ); gpd3dDev->SetTextureStageState( 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); gpd3dDev->SetTextureStageState( 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); gpd3dDev->SetTextureStageState( 0, D3DTSS_ADDRESSW, D3DTADDRESS_CLAMP); gpd3dDev->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); gpd3dDev->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); gpd3dDev->SetTextureStageState( 1, D3DTSS_MIPFILTER, D3DTEXF_NONE ); gpd3dDev->SetTextureStageState( 1, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); gpd3dDev->SetTextureStageState( 1, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); gpd3dDev->SetTextureStageState( 1, D3DTSS_ADDRESSW, D3DTADDRESS_CLAMP); gpd3dDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); gpd3dDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); gpd3dDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); // Render halo after blob, but before bloblets. gpd3dDev->SetVertexShader(D3DFVF_XYZ|D3DFVF_TEX1); gpd3dDev->SetPixelShader(NULL); D3DMATRIX id_mat; SetIdentity(&id_mat); gpd3dDev->SetTransform(D3DTS_WORLD,&id_mat); gpd3dDev->SetTransform(D3DTS_VIEW,&gApp.theCamera.matWTC); gpd3dDev->SetTransform(D3DTS_PROJECTION,&gApp.theCamera.matProj); gpd3dDev->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_MODULATE); gpd3dDev->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE); gpd3dDev->SetTextureStageState(0,D3DTSS_COLORARG2,D3DTA_TFACTOR); gpd3dDev->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1); gpd3dDev->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TFACTOR); gpd3dDev->SetTextureStageState(1,D3DTSS_COLOROP,D3DTOP_DISABLE); float cur_rad = m_fRadius * (1.0f + 1.3f * fast_sqrt(gApp.getPulseIntensity())); DWORD dw_alpha; float f_alpha = min(gApp.getBlobIntensity(),1.f) * 255.f; __asm { cvttss2si eax, f_alpha shl eax,24 mov dw_alpha,eax }; DWORD dw_tf = 0x00a0ff40 | dw_alpha; gpd3dDev->SetRenderState( D3DRS_TEXTUREFACTOR,dw_tf); gpd3dDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); gpd3dDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE ); gpd3dDev->SetRenderState( D3DRS_ZWRITEENABLE, FALSE ); gpd3dDev->SetTexture(0,gApp.pGlowMap); struct _decalvert { D3DVECTOR p; float u,v; }; _decalvert * phalo_verts = NULL; pHaloQuadVB->Lock(0,sizeof(_decalvert) * 4, (BYTE **)&phalo_verts,NULL); float f_rad = cur_rad * 5.2f; D3DMATRIX & ctw = gApp.theCamera.matCTW; Sub(*(D3DVECTOR *)&ctw._21,*(D3DVECTOR *)&ctw._11,&phalo_verts[0].p); Scale(&phalo_verts[0].p,f_rad); phalo_verts[0].u = 0.f; phalo_verts[0].v = 1.f; Add(*(D3DVECTOR *)&ctw._21,*(D3DVECTOR *)&ctw._11,&phalo_verts[1].p); Scale(&phalo_verts[1].p,f_rad); phalo_verts[1].u = 1.f; phalo_verts[1].v = 1.f; Sub(*(D3DVECTOR *)&ctw._11,*(D3DVECTOR *)&ctw._21,&phalo_verts[2].p); Scale(&phalo_verts[2].p,f_rad); phalo_verts[2].u = 1.f; phalo_verts[2].v = 0.f; Set(&phalo_verts[3].p,-ctw._11-ctw._21,-ctw._12-ctw._22,-ctw._13-ctw._23); Scale(&phalo_verts[3].p,f_rad); phalo_verts[3].u = 0.f; phalo_verts[3].v = 0.f; pHaloQuadVB->Unlock(); gpd3dDev->SetStreamSource( 0, pHaloQuadVB, sizeof(_decalvert)); gpd3dDev->DrawPrimitive(D3DPT_TRIANGLEFAN,0,2); // Restore state gpd3dDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); gpd3dDev->SetRenderState( D3DRS_ZWRITEENABLE, TRUE ); //MTS gpd3dDev->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME ); gpd3dDev->SetTexture( 0, gApp.pNormalCubeMapLoRes ); gpd3dDev->SetTexture( 1, gApp.pNormalCubeMapLoRes ); gpd3dDev->SetVertexShader( m_dwVShaderBlob ); gpd3dDev->SetPixelShader( m_dwPShaderBlob ); // Note: when passing matrices to a vertex shader, we transpose them, since // matrix multiplies are done with dot product operations on the matrix rows. D3DMATRIX matFinal,matTmp; MulMats(gApp.theCamera.matWTC,gApp.theCamera.matProj,&matTmp); SetTranspose(matTmp,&matFinal); gpd3dDev->SetVertexShaderConstant(4,(CONST void *)&matFinal,4); //; Expected vertex shaders constants //; c0-c3 = Transpose of world matrix //; c4-c7 = Transpose of view*projection matrix //; c8 = some constants, x=0, y=1, z=2, w=0.5 //; c9 = eye location //; c10 = blob scaling //; c11 = 1/ blob scaling //; c12 = blob center D3DVECTOR4 val[5]; // Constants Set(&val[0], 0.0f, 1.0f, 2.0f, 0.5f); // Eye position gApp.theCamera.getCameraPos(&val[1]); // Scaling Set(&val[2], cur_rad*m_Scale.x, cur_rad*m_Scale.y, cur_rad*m_Scale.z, 1.0f); // 1 / blob scaling val[3].x = 1.0f / val[2].x; val[3].y = 1.0f / val[2].y; val[3].z = 1.0f / val[2].z; // Blob center. //MTS float f_jitter_mag = (gApp.getElapsedTime() - BLOB_JITTER_START) * OO_BLOB_JITTER_DELTA; //MTS f_jitter_mag *= f_jitter_mag; //MTS float cOffsets[3] = { 0.2f, 0.7f, 4.2f }; //MTS float cScales[3] = { 20.0f, 28.0f, 44.0f }; D3DVECTOR4 cur_pos; //MTS cur_pos.x = m_Pos.x + f_jitter_mag * sinf((gApp.getElapsedTime() - cOffsets[0])*cScales[0]); //MTS cur_pos.y = m_Pos.y + f_jitter_mag * sinf((gApp.getElapsedTime() - cOffsets[1])*cScales[1]); //MTS cur_pos.z = m_Pos.z + f_jitter_mag * sinf((gApp.getElapsedTime() - cOffsets[2])*cScales[2]); cur_pos.x = m_Pos.x; cur_pos.y = m_Pos.y; cur_pos.z = m_Pos.z; cur_pos.w = 0.0f; Set(&val[4], cur_pos.x, cur_pos.y, cur_pos.z, 0.0f); gpd3dDev->SetVertexShaderConstant( 8, &val, 5 ); // Make the object to World transform. Transpose it. D3DMATRIX matT, mat; SetIdentity( &mat ); mat.m[0][0] = m_Scale.x * cur_rad; mat.m[1][1] = m_Scale.y * cur_rad; mat.m[2][2] = m_Scale.z * cur_rad; mat.m[3][0] = cur_pos.x; mat.m[3][1] = cur_pos.y; mat.m[3][2] = cur_pos.z; SetTranspose( mat, &matT ); gpd3dDev->SetVertexShaderConstant( 0, &matT, 4 ); // Expected pixel shader constants //; c0 = base blob color //; c1 = ambient color // Blob color val[0] = m_BlobColor; float f_color_intensity = BLOB_BASE_INTENSITY + 4.0f * (1.2f * gApp.getBaseBlobIntensity() + 0.8f * gApp.getPulseIntensity() ); //MTS f_color_intensity *= min(1.0f, gApp.getElapsedTime() * OO_BLOB_STATIC_END_TIME); f_color_intensity *= min(1.0f, gApp.getElapsedTime() * 4.0f); Scale(&val[0], f_color_intensity); // Ambient light val[1] = m_BlobColor; Scale(&val[1], 0.0f); gpd3dDev->SetPixelShaderConstant( 0, &val[0], 2 ); gpd3dDev->SetIndices( m_pBlobIB, 0 ); gpd3dDev->SetStreamSource( 0, m_pBlobVBConst, sizeof(VBlobConstantVertex) ); // Get the Update vertex buffer and use it to render. swapChangingVertices(); gpd3dDev->SetStreamSource( 1, m_pBlobVBChangingR, sizeof(VBlobChangingVertex) ); gpd3dDev->DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP, 0, m_dwNumVertices, 0, m_dwNumIndices-2 ); // Render the bloblets. gpd3dDev->SetVertexShader( m_dwVShaderBloblet ); gpd3dDev->SetPixelShader( m_dwPShaderBloblet ); gpd3dDev->SetVertexShaderConstant(4,(CONST void *)&matFinal,4); // Constants Set(&val[0], 0.0f, 1.0f, 2.0f, 0.5f); // Eye position gApp.theCamera.getCameraPos(&val[1]); gpd3dDev->SetVertexShaderConstant( 8, &val, 2 ); // Bloblet color val[0] = m_BlobColor; Scale(&val[0], 0.3f * gApp.getBlobIntensity()); // Ambient light val[1] = m_BlobColor; Scale(&val[1], 0.2f); Set(&val[2], 2.0f, 2.0f, 2.0f, 2.0f); // 1/val is the level of brightness that is full alpha gpd3dDev->SetPixelShaderConstant( 0, &val, 3 ); gpd3dDev->SetIndices( m_pBlobletIB, 0 ); gpd3dDev->SetStreamSource( 0, m_pBlobletVB, sizeof(VBlobConstantVertex) ); for (int i=0; ivPosition.x, p_bloblet->vPosition.y, p_bloblet->vPosition.z, 0.0f); // Direction of scaling. Set(&val[1], p_bloblet->vDirection.x, p_bloblet->vDirection.y, p_bloblet->vDirection.z, 1.0f); // Scaling perpendicular to direction float fval = p_bloblet->fRadius / fast_sqrt(p_bloblet->fWobble); Set(&val[2], fval, fval, fval, 1.0f); // Parallel minus perpendicular scaling multiplied by scaling direction fval = p_bloblet->fRadius * p_bloblet->fWobble - fval; Set(&val[3], fval*p_bloblet->vDirection.x, fval*p_bloblet->vDirection.y, fval*p_bloblet->vDirection.z, 1.0f); gpd3dDev->SetVertexShaderConstant( 10, &val, 4 ); gpd3dDev->DrawIndexedPrimitive( D3DPT_TRIANGLESTRIP, 0, m_dwNumBlobletVertices, 0, m_dwNumBlobletIndices-2 ); } // Restore the state gpd3dDev->SetPixelShader( NULL ); gpd3dDev->SetVertexShader( NULL ); gpd3dDev->SetTexture(0, NULL); gpd3dDev->SetTexture(1, NULL); gpd3dDev->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE ); } /////////////////////////////////////////////////////////////////////////////// void VBlob::zeroChangingVertices() { VBlobChangingVertex* p_verts; const D3DVECTOR* p_us_normals = m_pUnitSphereNormals; m_pBlobVBChangingU->Lock(0, 0, (BYTE**)&p_verts, 0); // D3DLOCK_DISCARD not on XBox! for (int face=0; face<6; face++) { for (int i=0; inormal.x = p_us_normals->x; p_verts->normal.y = p_us_normals->y; p_verts->normal.z = p_us_normals->z; p_verts->normal.w = 1.0f; } } m_pBlobVBChangingU->Unlock(); } /////////////////////////////////////////////////////////////////////////////// void VBlob::prepareChangingVertices() { VBlobChangingVertex* p_verts; const D3DVECTOR* p_us_normals = m_pUnitSphereNormals; m_pBlobVBChangingU->Lock(0, 0, (BYTE**)&p_verts, 0); // D3DLOCK_DISCARD not on XBox! /* // For spiky blobs mark 2. const float cA = 1.0f; const float cB = 0.1f; const float cD = 1.0f / ( (1.0f/cB) - (1.0f / (cA+cB)) ); const float cE = cA / cD; const float cF = cB / cD; const float cG = - cD / (cA+cB); float sd_frac = max(1.0f, gApp.getElapsedTime() / 6.0f); float bd_frac = 1.0f - sd_frac; */ for (int face=0; face<6; face++) { const VBlobBump* vp_blobs_of_interest[MAX_BLOBBUMPS]; int i; int num_boi = 0; for (i=0; inormal; //MTS D3DVECTOR4 accum_normal; Set(&accum_normal, us_normal.x, us_normal.y, us_normal.z, 0.0f); for (int j=num_boi-1; j>=0; j--) { const VBlobBump* p_blob = vp_blobs_of_interest[j]; D3DVECTOR delta; Sub(us_normal, p_blob->vPosition, &delta); //MTS float dist2 = Length2(delta); float dist2 = delta.x*delta.x + delta.y*delta.y + delta.z*delta.z; //MTS float dist2 = Distance2(us_normal, p_blob->vPosition); if (dist2 < p_blob->fRadius2) { //MTS if ((p_blob->facesOfInterest & (1<fOORadius2 - 1.0f; float displacement = m_fRadius*p_blob->fMagnitude * dist2_mo*dist2_mo; /* // Spiky blob bumps mark 2. float bumpy_displacement = m_fRadius*p_blob->fMagnitude * dist2_mo*dist2_mo; float spiky_displacement = m_fRadius * p_blob->fMagnitude * ( 1.0f / (cE*dist2*p_blob->fOORadius2 + cF) + cG ); spiky_displacement *= 1.3f; float displacement = bd_frac*bumpy_displacement + sd_frac*spiky_displacement; */ float perturb_amount = -4.0f * p_blob->fMagnitude * p_blob->fOORadius2 * dist2_mo; // lnorm = us_normal + perturb_amount*(us_normal - p_blob->vPosition) // This should make it faster, but VTune suggests it doesn't. Maybe in Release... //MTS D3DVECTOR lnorm; //MTS float oppa = 1.0f + perturb_amount; //MTS lnorm.x = us_normal.x * oppa - perturb_amount * p_blob->vPosition.x; //MTS lnorm.y = us_normal.y * oppa - perturb_amount * p_blob->vPosition.y; //MTS lnorm.z = us_normal.z * oppa - perturb_amount * p_blob->vPosition.z; D3DVECTOR lnorm = us_normal; //MTS Set(&lnorm, 0.0f, 0.0f, 0.0f); //MTS D3DVECTOR delta; //MTS Sub(us_normal, p_blob->vPosition, &delta); AddScaled(&lnorm, delta, perturb_amount); QuickNormalize(&lnorm); accum_normal.x += lnorm.x; accum_normal.y += lnorm.y; accum_normal.z += lnorm.z; accum_normal.w += displacement; } } p_verts->normal = accum_normal; } } m_pBlobVBChangingU->Unlock(); } /////////////////////////////////////////////////////////////////////////////// void VBlob::advanceTime(float fElapsedTime, float fDt) { if (fElapsedTime < BLOB_STATIC_END_TIME) { if (fElapsedTime - fDt > BLOB_STATIC_END_TIME) { zeroChangingVertices(); swapChangingVertices(); zeroChangingVertices(); } return; } for (int i=0; iBlockUntilNotBusy(); // this causes it to block here, rather than in prepareChangingVertices prepareChangingVertices(); } /////////////////////////////////////////////////////////////////////////////// void VBlob::restart() { m_NumBloblets = 0; m_NumBlobBumps = 0; while (m_NumBlobBumpsCreateVertexBuffer( *num_verts * sizeof(VBlobConstantVertex), 0, 0, 0, pp_vb); gpd3dDev->CreateIndexBuffer( *num_indices * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, pp_ib); if (pp_us) *pp_us = (D3DVECTOR*)MemAlloc(sizeof(D3DVECTOR)*(*num_verts)); VBlobConstantVertex* p_verts; WORD* p_indices; (*pp_vb)->Lock(0, 0, (BYTE**)&p_verts, 0); (*pp_ib)->Lock(0, 0, (BYTE**)&p_indices, 0); D3DVECTOR* p_us = ((pp_us) ? *pp_us : NULL); // Create vertices. VBlobConstantVertex* p_vert = &p_verts[0]; for (int k=0; k<6; k++) { for (int j=0; j<=subdiv; j++) { for (int i=0; i<=subdiv; i++) { D3DVECTOR& pos = p_vert->unit_sphere_normal; float fu = ((i==subdiv) ? +1.0f : (-1.0f + f_division_step * ((float)i))); float fv = ((j==subdiv) ? +1.0f : (-1.0f + f_division_step * ((float)j))); switch(k) { case 0: Set(&pos, -1.0f, -fu, +fv); break; case 1: Set(&pos, +fv, -1.0f, -fu); break; case 2: Set(&pos, -fu, +fv, -1.0f); break; case 3: Set(&pos, +1.0f, +fu, +fv); break; case 4: Set(&pos, +fv, +1.0f, +fu); break; case 5: Set(&pos, +fu, +fv, +1.0f); break; } Normalize(&pos); if (p_us) { *p_us = pos; p_us++; } p_vert++; } } } // Create indices. int j = 0; for (int i=0; i<6; i++) { j += CreateTristripForMesh(&p_indices[j], subdiv, subdiv, (i>0), (i<5), i*(subdiv+1)*(subdiv+1)); } (*pp_ib)->Unlock(); (*pp_vb)->Unlock(); return true; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// void VBlobBump::Init() { pMyBloblet = NULL; } /////////////////////////////////////////////////////////////////////////////// void VBlobBump::UnInit() { } /////////////////////////////////////////////////////////////////////////////// // randomly creates a blob bump bool VBlobBump::create(float cur_time, VBloblet* p_bloblet) { if (cur_time < 0.0f) pMyBloblet = NULL; vDirection.x = VBlob::fRand11(); vDirection.y = VBlob::fRand11(); vDirection.z = VBlob::fRand11(); if (Length2(vDirection) < 0.001f) { vDirection.x = VBlob::fRand11(); vDirection.y = VBlob::fRand11(); vDirection.z = 1.0f; } Set(&vPosition, 0.0f, 0.0f, 0.0f); QuickNormalize(&vDirection); float time_prog = max(0.0f, (cur_time-BLOB_STATIC_END_TIME) * OO_MAX_INTENSITY_DELTA); float rad_mag_rand = VBlob::fRand01(); fRadius = rad_mag_rand * 0.4f + 0.4f; fRadius2 = fRadius*fRadius; fOORadius2 = 1.0f / fRadius2; fMagnitude = 0.0f; recalculateFacesOfInterest(); fStartTime = cur_time + 0.4f * VBlob::fRand01(); fMaxMagnitude = (1.0f - rad_mag_rand) * 0.5f + 0.2f; fMaxMagnitude *= 0.5f + 0.5f * time_prog; if (!pMyBloblet) pMyBloblet = p_bloblet; if (pMyBloblet) { // Paired with a bloblet. float f_main_rad = gpVBlob->getRadius(); pMyBloblet->fRadius = (VBlob::fRand01()+1.0f) * 0.25f * f_main_rad * fRadius; pMyBloblet->vDirection = vDirection; pMyBloblet->fMaxDist = f_main_rad * (5.0f + VBlob::fRand11() * 2.0f); pMyBloblet->fMaxDist *= 0.6f; pMyBloblet->fStartTime = (cur_time<-1.0f) ? -VBlob::fRand01() * 0.3f : cur_time; float period = 0.8f + 0.3f * VBlob::fRand01(); period *= 1.0f / 0.6f; pMyBloblet->fTimeMultiple = 2.0f * Pi / period; pMyBloblet->fWobble = 1.2f; pMyBloblet->fWobbleDirection = 0.0f; bStillAttachedToBloblet = (cur_time-fStartTime < 0.4f*period); // Set my properties from the bloblet. pMyBloblet->update(cur_time, 0.0f); update(cur_time, 0.0f, NULL); } else { // Not paired with a bloblet. float sequence_len = fMaxMagnitude * 0.3f + VBlob::fRand01() * 0.3f; fTimeMul = Pi / sequence_len; fTimeMul *= time_prog*0.2f + 0.8f; if (cur_time < -1.0f) fStartTime = -VBlob::fRand01() * Pi / fTimeMul; } return (pMyBloblet!=NULL); } /////////////////////////////////////////////////////////////////////////////// // returns true if it initialized a new Bloblet bool VBlobBump::update(float elapsed_time, float dt, VBloblet* p_bloblet) { if (pMyBloblet) { float f_b_mag = (fast_fabs(pMyBloblet->fCurDist) + pMyBloblet->fRadius) / gpVBlob->getRadius(); fMagnitude = min( 2.0f, max(0.0f, f_b_mag - 1.0f) ); if (bStillAttachedToBloblet) { if (fMagnitude > 0.8f) { // Lost attachment bStillAttachedToBloblet = false; //MTS fMaxMagnitude = max(0.0f, fMagnitude - 2.0f * pMyBloblet->fRadius / gpVBlob->getRadius()); fMaxMagnitude = fMagnitude; float sequence_len = 0.3f * fMagnitude; fTimeMul = 2.0f * Pi / sequence_len; fStartTime = elapsed_time - 0.25f * sequence_len; pMyBloblet->fWobble = max(0.6f, min(0.8f, fMagnitude-0.5f)); // more wobble when there is less energy pMyBloblet->fWobbleDirection = 0.0f; } else { // Still attached. if ( (Dot(vDirection, pMyBloblet->vDirection) < 0.0f) != pMyBloblet->bFarSide) { // Must reverse direction. Scale(&vDirection, -1.0f); vPosition = vDirection; recalculateFacesOfInterest(); } return false; } } // May have just lost attachment. if (!bStillAttachedToBloblet) { if (f_b_mag < 0.9f) { // Blob is inside sphere, reattach. bStillAttachedToBloblet = true; } } } float t = (elapsed_time - fStartTime) * fTimeMul; if (t>Pi) { if (pMyBloblet==NULL) { return create(elapsed_time, p_bloblet); } fMagnitude = 0.0f; return false; } if (t<0.0f) return false; float sin_val = fast_sin(t); fMagnitude = fMaxMagnitude * sin_val; //MTS vPosition.x = vDirection.x * sin_val; //MTS vPosition.y = vDirection.y * sin_val; //MTS vPosition.z = vDirection.z * sin_val; vPosition = vDirection; recalculateFacesOfInterest(); //MTS if ((bNotYetSpawned) && (t > 0.5f * Pi) && (p_bloblet)) //MTS { //MTS bNotYetSpawned = false; //MTS //MTS float f_main_rad = gpVBlob->getRadius(); //MTS p_bloblet->fRadius = 0.7f * f_main_rad * fRadius; //MTS //MTS float displ = f_main_rad * (1.0f + fMagnitude) - p_bloblet->fRadius; //MTS p_bloblet->vPosition = gpVBlob->getCenter(); //MTS p_bloblet->vPosition.x += vDirection.x * displ; //MTS p_bloblet->vPosition.y += vDirection.y * displ; //MTS p_bloblet->vPosition.z += vDirection.z * displ; //MTS //MTS //MTS //MTS //MTS //MTS float vel = f_main_rad * (fMagnitude-MIN_SPAWN_MAGN) * 100.0f + 20.0f; //MTS p_bloblet->vVelocity.x = vDirection.x * vel; //MTS p_bloblet->vVelocity.y = vDirection.y * vel; //MTS p_bloblet->vVelocity.z = vDirection.z * vel; //MTS //MTS p_bloblet->vAttachedTo = gpVBlob->getCenter(); //MTS //MTS //MTS // Set up a spring as per 2001.05.01 of my notes. //MTS //MTS // Use a spring model for now. Period is 2*Pi/sqrt(k/m), so k/m = (2*Pi/period)^2 //MTS float sequence_time_mul = 5.0f; //MTS p_bloblet->fRestoreForceConstant = 2.0f * Pi / (sequence_time_mul*(elapsed_time - fStartTime)); //MTS p_bloblet->fRestoreForceConstant *= p_bloblet->fRestoreForceConstant; //MTS //MTS p_bloblet->fEndDist2 = f_main_rad - p_bloblet->fRadius; //MTS p_bloblet->fEndDist2 *= p_bloblet->fEndDist2; //MTS //MTS return true; //MTS } return false; } /////////////////////////////////////////////////////////////////////////////// void VBlobBump::recalculateFacesOfInterest() { // Bitfield indicating the faces (0,1,2,4,5) <-> (-x,-y,-z,+x,+y,+z) the blob points most be checked with. facesOfInterest = ((vDirection.x - fRadius < -0.57735f) ? 0x0001 : 0) + ((vDirection.y - fRadius < -0.57735f) ? 0x0002 : 0) + ((vDirection.z - fRadius < -0.57735f) ? 0x0004 : 0) + ((vDirection.x + fRadius > +0.57735f) ? 0x0008 : 0) + ((vDirection.y + fRadius > +0.57735f) ? 0x0010 : 0) + ((vDirection.z + fRadius > +0.57735f) ? 0x0020 : 0) ; } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// const float WOBBLE_ACCEL = (1000.0f); // returns false if it should be deleted bool VBloblet::update(float elapsed_time, float dt) { fWobble = min(2.0f, max(0.5f, fWobble + fWobbleDirection * dt)); if (fWobbleDirection > 0.0f) { if ((fWobble < 0.95f) || (fWobble > 1.0f)) { fWobbleDirection -= (fWobble-1.0f) * dt * WOBBLE_ACCEL; } } else { if ((fWobble < 1.0f) || (fWobble > 1.05f)) { fWobbleDirection -= (fWobble-1.0f) * dt * WOBBLE_ACCEL; } } float time_prog = max(0.0f, (elapsed_time-BLOB_STATIC_END_TIME) * OO_MAX_INTENSITY_DELTA); float t = fTimeMultiple * (elapsed_time - fStartTime); t *= 1.4f * (1.0f + elapsed_time / 10.0f); // speed up over time float s = fast_sin(t); float sm = fast_fabs(s); sm = 1.0f - (1.0f-sm)*fast_sqrt(1.0f-sm); s = (s>0.0f) ? sm : -sm; fCurDist = fMaxDist * s * time_prog; bFarSide = (fCurDist<0.0f); vPosition = gpVBlob->getCenter(); AddScaled(&vPosition, vDirection, fCurDist); return (fast_fabs(fCurDist) + fRadius < gpVBlob->getRadius() * 0.5f); } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////