/////////////////////////////////////////////////////////////////////////////// // File: Blobs.cpp // // Copyright 2001 Pipeworks Software /////////////////////////////////////////////////////////////////////////////// #include #include "xbs_math.h" #include "xbs_app.h" #include "qrand.h" #include "Blobs.h" const LavaLampInterior* LLBlob::spLL = NULL; QRand LavaLampInterior::m_QRand; void LavaLampInterior::destroy() { //MTS m_BlobRenderer.destroy(); for (int i=0; iDeletePixelShader( m_dwPixelShader ); m_dwPixelShader = 0; } if ( m_dwVertexShader ) { gpd3dDev->DeleteVertexShader( m_dwVertexShader ); m_dwVertexShader = 0; } } LLBlob::LLBlob() { m_pBlobVB = NULL; m_pBlobIB = NULL; m_Temperature = 0.5f; Set(&m_Accel, 0.0f, 0.0f, 0.0f); Set(&m_Velocity, 0.0f, 0.0f, 0.0f); m_DeformationInertia = 0.3f; } void LLBlob::destroy() { if (m_pBlobVB) { m_pBlobVB->Release(); m_pBlobVB = NULL; } if (m_pBlobIB) { m_pBlobIB->Release(); m_pBlobIB = NULL; } } void LavaLampInterior::InitPixelShader() { if( m_dwPixelShader ) { gpd3dDev->DeletePixelShader( m_dwPixelShader ); m_dwPixelShader = 0; } m_dwPixelShader = gApp.loadPixelShader("D:\\Shaders\\blob.xpu"); } void LavaLampInterior::create() { LLBlob::spLL = this; m_ConicSectionCenterX = +0.04f; m_ConicSectionCenterY = -0.082f; m_NumConicSections = 2; m_ConicSectionBotZ[0] = -0.47f; m_ConicSectionBotZ[1] = -0.25f; m_ConicSectionBotZ[2] = +0.35f; m_ConicSectionRadius[0] = 0.11f; m_ConicSectionRadius[1] = 0.25f; m_ConicSectionRadius[2] = 0.12f; int i; for (i=0; i>1] ); Set(&color, (i&0x04) ? 0.0f : 1.0f, (i&0x02) ? 0.0f : 1.0f, (i&0x01) ? 0.0f : 1.0f, 1.0f); Set(&base_color, 0.724f, 0.732f, 0.556f, 1.0f); //MTS m_Blobs[i].create(pos, color*0.1f + base_color*0.9f); m_Blobs[i].create(pos, base_color); m_Blobs[i].setSpecies(i); } //MTS m_BlobRenderer.create(); //MTS m_BlobRenderer.init(this, &m_Blobs[0], NUM_LLBLOBS, 0.01f, 0.01f, m_ConicSectionCenterX, m_ConicSectionCenterY); return; }; void LLBlob::calcFacePoint(D3DVECTOR* ppos, int face, int u, int v) { float fu = (u==m_Subdivisions) ? +1.0f : -1.0f + m_fDivisionStep * ((float)u); float fv = (v==m_Subdivisions) ? +1.0f : -1.0f + m_fDivisionStep * ((float)v); switch(face) { case 0: Set(ppos, -1.0f, -fu, +fv); break; case 1: Set(ppos, +fv, -1.0f, -fu); break; case 2: Set(ppos, -fu, +fv, -1.0f); break; case 3: Set(ppos, +1.0f, +fu, +fv); break; case 4: Set(ppos, +fv, +1.0f, +fu); break; case 5: Set(ppos, +fu, +fv, +1.0f); break; } } void LLBlob::create(D3DVECTOR pos, D3DVECTOR4 color) { // A blob is modeled as a subdivided cube. m_BlobColor = color; m_Pos = pos; Set(&m_Scale, 0.9f, 0.9f, 0.9f); m_DeformationInertia = spLL->fRand11() * 0.1f; m_fRadius = LavaLampInterior::fRand01(); m_fRadius = 0.5f * (m_fRadius*m_fRadius + LavaLampInterior::fRand01()); m_fRadius = 0.03f + 0.05f * m_fRadius; m_TemperatureAbsorbance = 0.05f / m_fRadius; // is just representational m_Temperature = 0.5f + 0.2f * LavaLampInterior::fRand11(); m_Subdivisions = 4; // face is a grid of sd+1 quads square m_fDivisionStep = 2.0f / m_Subdivisions; //MTS m_dwNumVertices = 2*(subdivisions+2)*(subdivisions+2) + 4*subdivisions*(subdivisions+1); // number of unique vertices m_dwNumVertices = 6*(m_Subdivisions+1)*(m_Subdivisions+1); m_dwNumIndices = 6*(m_Subdivisions)*(m_Subdivisions)*2*3; gpd3dDev->CreateVertexBuffer( m_dwNumVertices * sizeof(BlobVertex), 0, 0, 0, &m_pBlobVB); gpd3dDev->CreateIndexBuffer( m_dwNumIndices * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &m_pBlobIB); BlobVertex* p_verts; WORD* p_indices; m_pBlobVB->Lock(0, 0, (BYTE**)&p_verts, 0); m_pBlobIB->Lock(0, 0, (BYTE**)&p_indices, 0); // Create vertices. BlobVertex* p_vert = &p_verts[0]; for (int k=0; k<6; k++) { for (int j=0; j<=m_Subdivisions; j++) { for (int i=0; i<=m_Subdivisions; i++) { calcFacePoint(&p_vert->pos, k, i, j); float oo_dist = 1.0f / sqrtf(p_vert->pos.x*p_vert->pos.x + p_vert->pos.y*p_vert->pos.y + p_vert->pos.z*p_vert->pos.z); p_vert->pos.x *= oo_dist; p_vert->pos.y *= oo_dist; p_vert->pos.z *= oo_dist; p_vert++; } } } // Create indices. WORD* p_index = &p_indices[0]; for (int k=0; k<6; k++) { int face_start = k*(m_Subdivisions+1)*(m_Subdivisions+1); for (int j=0; jUnlock(); m_pBlobIB->Unlock(); } void LavaLampInterior::advanceTime(float fElapsedTime, float fDt) { if (fDt < 0.0f) fDt = 0.0f; if (fDt > 0.1f) fDt = 0.1f; //MTS m_BlobRenderer.advanceTime(fElapsedTime, fDt); for (int i=0; igetTemperature(m_Pos.z); float scale = 0.002f * m_TemperatureAbsorbance*m_TemperatureAbsorbance * fDt; m_Temperature += scale * (ambient_temp - m_Temperature); // For purposes of the simulation, water stays at a constant density. // A blob's density is equal to water at temperature 0.5f. For each unit // of temperature difference, an acceleration of 1.0 m/s/s is applied. m_Velocity.z += fDt * 1.0f * (m_Temperature-0.5f); m_Accel.x += LavaLampInterior::fRand11() * fDt; m_Accel.y += LavaLampInterior::fRand11() * fDt; m_Accel.z += LavaLampInterior::fRand11() * fDt; //MTS m_Velocity.x += LavaLampInterior::fRand11() * fDt * fDt; //MTS m_Velocity.y += LavaLampInterior::fRand11() * fDt * fDt; //MTS m_Velocity.z += LavaLampInterior::fRand11() * fDt * fDt; m_Accel.x = min(+0.05f, max(-0.05f, m_Accel.x)); m_Accel.y = min(+0.05f, max(-0.05f, m_Accel.y)); m_Accel.z = min(+0.05f, max(-0.05f, m_Accel.z)); if (Length2(m_Accel) > 1.0f) Scale(&m_Accel, 0.96f); // Friction moving through water. AddScaled(&m_Velocity, m_Accel, fDt); float vel2 = Length2(m_Velocity); Scale(&m_Velocity, 1.0f - fDt * 120.0f * vel2); AddScaled(&m_Pos, m_Velocity, fDt); // Do collisions. spLL->collide(this, m_Pos.x, m_Pos.y, m_Pos.z, m_fRadius, fDt); // Adjust render wobble. m_Scale.x += m_DeformationInertia * fDt * m_TemperatureAbsorbance; m_Scale.y += m_DeformationInertia * fDt * m_TemperatureAbsorbance; m_Scale.z = 0.9f - (m_Scale.x - 0.9f) * (0.9f+0.9f)*0.9f / (0.9f*0.9f); float accel; if (m_DeformationInertia > 0.0f) { accel = 0.91f - m_Scale.x; } else { accel = 0.89f - m_Scale.x; } m_DeformationInertia += 20.0f * accel * fDt; m_DeformationInertia = max(-0.3f, min(+0.3f, m_DeformationInertia)); } float LavaLampInterior::getTemperature(float z) const { float dz = -0.5f + (z - m_ConicSectionBotZ[0]) / (m_ConicSectionBotZ[m_NumConicSections] - m_ConicSectionBotZ[0]); dz *= 2.6f; dz *= dz*dz; return max(0.0f, min(1.0f, 0.5f - dz)); } bool LavaLampInterior::collideWithCaps(LLBlob* pllb, float x, float y, float z, float radius) const { if (z - radius < m_ConicSectionBotZ[0]) { D3DVECTOR pos, norm; Set(&pos, x, y, m_ConicSectionBotZ[0] + radius + 0.001f); Set(&norm, 0.0f, 0.0f, +1.0f); pllb->collided(pos, norm); return true; } if (z + radius > m_ConicSectionBotZ[m_NumConicSections]) { D3DVECTOR pos, norm; Set(&pos, x, y, m_ConicSectionBotZ[m_NumConicSections] - radius - 0.001f); Set(&norm, 0.0f, 0.0f, -1.0f); pllb->collided(pos, norm); return true; } return false; } void LavaLampInterior::collide(LLBlob* pllb, float x, float y, float z, float radius, float dt) const { // Bounce off the caps. if (collideWithCaps(pllb, x, y, z, radius)) { z = pllb->getPos().z; } x -= m_ConicSectionCenterX; y -= m_ConicSectionCenterY; float r = sqrtf( x*x + y*y ); // Check the conic sections. Check the surfaces first, the corners will be checked afterwards. int i; bool b_hit_wall = false; for (i=0; i z + radius) break; // Sphere overlaps the section at least somewhat. Find the nearest // point on the cone surface and see if that is within the range. float dz = z - m_ConicSectionBotZ[i]; float dr = r - m_ConicSectionRadius[i]; float overlap = radius - (dr*m_ConicSectionNormalR[i] + dz*m_ConicSectionNormalZ[i]); if (overlap < 0.0f) continue; // Calculate distance along surface to the nearest point of collision. float s = dr*m_ConicSectionNormalZ[i] - dz*m_ConicSectionNormalR[i]; if (s<0.0f) continue; float height = m_ConicSectionBotZ[i+1]-m_ConicSectionBotZ[i]; if (s*s > height*height * (1.0f + m_ConicSectionSlope[i]*m_ConicSectionSlope[i])) continue; // Collision. float nz = m_ConicSectionNormalZ[i]; float oo_r = 1.0f / max(0.001f, r); float nx = x * oo_r * m_ConicSectionNormalR[i]; float ny = y * oo_r * m_ConicSectionNormalR[i]; D3DVECTOR pos, norm; x += nx*overlap; y += ny*overlap; z += nz*overlap; r = sqrtf( x*x + y*y ); // recompute radius Set(&pos, m_ConicSectionCenterX + x, m_ConicSectionCenterY + y, z); Set(&norm, nx, ny, nz); pllb->collided(pos, norm); b_hit_wall = true; } // Check the corners. if (!b_hit_wall) for (i=0; i z + radius) break; float dz = z - m_ConicSectionBotZ[i]; float dr = r - m_ConicSectionRadius[i]; if (dz*dz + dr*dr > radius*radius) continue; float dist = sqrtf(dz*dz + dr*dr); float overlap = radius - dist; float f_norm = 1.0f / max(0.001f, dist); float nz = -dz * f_norm; float nr = -dr * f_norm; float oo_r = 1.0f / max(0.001f, r); float nx = x * oo_r * nr; float ny = y * oo_r * nr; D3DVECTOR pos, norm; x += nx*overlap; y += ny*overlap; z += nz*overlap; r = sqrtf( x*x + y*y ); // recompute radius Set(&pos, m_ConicSectionCenterX + x, m_ConicSectionCenterY + y, z); Set(&norm, nx, ny, nz); pllb->collided(pos, norm); b_hit_wall = true; } // Check other blobs. for (i=0; igetPos(), &delta); float rad = (m_Blobs[i].getRadius() + pllb->getRadius()); if (Length2(delta) > rad*rad) continue; pllb->interactWithBlob(&m_Blobs[i], dt); } if (collideWithCaps(pllb, x + m_ConicSectionCenterX, y + m_ConicSectionCenterY, z, radius)) { // Should never happen with convex hull. z = pllb->getPos().z; } } void LLBlob::collided(D3DVECTOR pos, D3DVECTOR normal) { D3DVECTOR diff; Sub(pos, m_Pos, &diff); if (Length2(diff) > 0.5f * m_fRadius * m_fRadius) { int a = 0; } float dot; dot = Dot(normal, m_Accel); if (dot<0.0f) AddScaled(&m_Accel, normal, -dot); dot = Dot(normal, m_Velocity); if (dot<0.0f) AddScaled(&m_Velocity, normal, -dot); m_Pos = pos; } void LLBlob::interactWithBlob(const LLBlob* pllb, float dt) { // Attract at range, repel when close. float mass_b = pllb->m_fRadius; mass_b *= mass_b*mass_b; D3DVECTOR delta; Sub(pllb->getPos(), getPos(), &delta); float dist2 = Length2(delta); if (dist2 < 0.000001f) return; D3DVECTOR delta_v; Sub(pllb->m_Velocity, m_Velocity, &delta_v); float f_part_mag = Dot(delta_v, delta); if (getSpecies() == pllb->getSpecies()) { // Same species. float extreme_rad = (m_fRadius + pllb->m_fRadius); float attract = mass_b * dt * 10000.0f * ((f_part_mag > 0.0f) ? 1.0f : 0.5f); AddScaled(&m_Velocity, delta, attract); //MTS float attract = ((1.0f / dist2) - (1.0f / (extreme_rad*extreme_rad))) * mass_b * dt * 5.0f; //MTS AddScaled(&m_Accel, delta, attract); // Should try adding to the velocity directly... extreme_rad *= 0.6f; float extreme_rad2 = extreme_rad*extreme_rad; float repel = ((1.0f / min(extreme_rad2*0.04f, dist2)) - (1.0f / extreme_rad2)) * mass_b * dt * 5.0f; repel *= ((f_part_mag > 0.0f) ? 0.3f : 1.0f); if (repel > 0.0f) AddScaled(&m_Velocity, delta, -repel); //MTS float repel = ((1.0f / min(extreme_rad2*0.04f, dist2)) - (1.0f / extreme_rad2)) * mass_b * dt * 500.0f; //MTS if (repel > 0.0f) AddScaled(&m_Accel, delta, -repel); } else { // Different specie. float extreme_rad2 = (m_fRadius + pllb->m_fRadius); extreme_rad2 *= extreme_rad2; float repel = ((1.0f / min(extreme_rad2*0.04f, dist2)) - (1.0f / extreme_rad2)) * mass_b * dt * 1.0f; repel *= ((f_part_mag > 0.0f) ? 0.3f : 1.0f); AddScaled(&m_Velocity, delta, -repel); //MTS float repel = ((1.0f / min(extreme_rad2*0.04f, dist2)) - (1.0f / extreme_rad2)) * mass_b * dt * 50.0f; //MTS AddScaled(&m_Accel, delta, -repel); } } void LavaLampInterior::recomputeSpecie() { int prev_species[NUM_LLBLOBS]; int i; for (i=0; iSetRenderState( 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_LINEAR ); gpd3dDev->SetTextureStageState( 0, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP ); gpd3dDev->SetTextureStageState( 0, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP ); gpd3dDev->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE ); gpd3dDev->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL ); gpd3dDev->SetRenderState( D3DRS_ALPHAREF, 0x00000001 ); gpd3dDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); gpd3dDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); gpd3dDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); //MTS gpd3dDev->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME ); gpd3dDev->SetTexture( 0, gApp.pNormalCubeMap ); gpd3dDev->SetVertexShader( m_dwVertexShader ); gpd3dDev->SetPixelShader( m_dwPixelShader ); // 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 D3DVECTOR4 val; // Constants Set(&val, 0.0f, 1.0f, 2.0f, 0.5f); gpd3dDev->SetVertexShaderConstant( 8, &val, 1 ); //MTS m_BlobRenderer.render(); for (int i=0; iSetPixelShader( NULL ); gpd3dDev->SetVertexShader( NULL ); gpd3dDev->SetTexture(0, NULL); } void LLBlob::render() { // Make the object to World transform. Transpose it. D3DMATRIX matT, mat; SetIdentity( &mat ); mat.m[0][0] = m_Scale.x * m_fRadius; mat.m[1][1] = m_Scale.y * m_fRadius; mat.m[2][2] = m_Scale.z * m_fRadius; mat.m[3][0] = m_Pos.x; mat.m[3][1] = m_Pos.y; mat.m[3][2] = m_Pos.z; SetTranspose( mat, &matT ); gpd3dDev->SetVertexShaderConstant( 0, &matT, 4 ); // Expected pixel shader constants //; c0 = light 1 direction //; c1 = light 2 direction //; c2 = base blob color //; c3 = ambient color D3DVECTOR4 val; Set(&val, 0.5f, 0.6f, 0.5f, 1.0f ); gpd3dDev->SetPixelShaderConstant( 0, &val, 1 ); Set(&val, 0.5f, 0.4f, 0.5f, 1.0f ); gpd3dDev->SetPixelShaderConstant( 1, &val, 1 ); // Blob color gpd3dDev->SetPixelShaderConstant( 2, &m_BlobColor, 1 ); // Ambient light val = m_BlobColor; val.x *= 0.6f; val.y *= 0.6f; val.z *= 0.6f; gpd3dDev->SetPixelShaderConstant( 3, &val, 1 ); // This could be set in the lava lamp, but we might have blobs with different numbers of vertices. gpd3dDev->SetIndices( m_pBlobIB, 0 ); gpd3dDev->SetStreamSource( 0, m_pBlobVB, sizeof(BlobVertex) ); gpd3dDev->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, m_dwNumVertices, 0, m_dwNumIndices/3 ); }