//////////////////////////////////////////////////////////////////////////// // // Crytek Engine Source File. // Copyright (C), Crytek Studios, 2002. // ------------------------------------------------------------------------- // File name: terrain_sector_beach.cpp // Version: v1.00 // Created: 28/5/2001 by Vladimir Kajalin // Compilers: Visual Studio.NET // Description: shore siluet calculations // ------------------------------------------------------------------------- // History: // //////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "terrain_sector.h" //min size of water area with beaches #define MIN_UNITS_IN_WATER_AREA 8 /* bool CBeachGenerator::ProcessPoint(short x, short y, int nAreaID) { if(x<0 || y<0 || x>=CTerrain::GetTerrainSize()/CTerrain::GetHeightMapUnitSize() || y>=CTerrain::GetTerrainSize()/CTerrain::GetHeightMapUnitSize()) return false; if(m_arrAlreadyProcessed[x][y])// || m_WaterAreaMap[x][y]==nAreaID) return false; m_arrAlreadyProcessed[x][y] = true; bool in_water = m_pTerrain->GetZSafe(x*CTerrain::GetHeightMapUnitSize(),y*CTerrain::GetHeightMapUnitSize()) < m_pTerrain->GetWaterLevel(); if(!in_water) return false; m_WaterAreaMap[x][y] = nAreaID; return true; }*/ struct TerPoint { TerPoint (short _x, short _y) { x=_x; y=_y; } short x,y; }; void CBeachGenerator::RenameWaterArea( int nOld, int nNew ) { /* int nSize = CTerrain::GetTerrainSize()/CTerrain::GetHeightMapUnitSize(); for(int x=0; xGetZSafe(x*CTerrain::GetHeightMapUnitSize(),y*CTerrain::GetHeightMapUnitSize()) < m_pTerrain->GetWaterLevel(); m_WaterAreaMap[x][y] = in_water ? 1 : 0; } } m_lstWaterAreaSizeTable.Reset(); for(int x=0; x lstAreaPtrTable; lstAreaPtrTable.Add(0); lstAreaPtrTable[0] = new int; *lstAreaPtrTable[0] = ++nMaxAreaId; list2 lstRenameTable; for(int x=0; xGetZSafe(x*CTerrain::GetHeightMapUnitSize(),y*CTerrain::GetHeightMapUnitSize()) < m_pTerrain->GetWaterLevel(); if(!in_water) { m_WaterAreaMap[x][y] = 0; continue; } int * nLeftAreaId = y>0 ? m_WaterAreaMap[x][y-1] : lstAreaPtrTable[0]; int * nTopAreaId = x>0 ? m_WaterAreaMap[x-1][y] : lstAreaPtrTable[0]; if(nLeftAreaId && !nTopAreaId) { // only left valid m_WaterAreaMap[x][y] = nLeftAreaId; } else if(nTopAreaId && !nLeftAreaId) { // only top valid m_WaterAreaMap[x][y] = nTopAreaId; } else if(nTopAreaId && nTopAreaId == nLeftAreaId) { // both are the same and valid m_WaterAreaMap[x][y] = nLeftAreaId; } else if(nTopAreaId && nLeftAreaId && (nTopAreaId != nLeftAreaId)) { // both valid and different, // todo: rename top units RenameInfo ri; ri.nTop = *nTopAreaId; ri.nLeft = *nLeftAreaId; lstRenameTable.Add(ri); // *nTopAreaId = *nLeftAreaId; m_WaterAreaMap[x][y] = nTopAreaId; } else if(!nTopAreaId && !nLeftAreaId) { // both zero - new area m_WaterAreaMap[x][y] = new int; *m_WaterAreaMap[x][y] = ++nMaxAreaId; lstAreaPtrTable.Add(m_WaterAreaMap[x][y]); } else { assert(0); } } } // rename units for(int i=lstRenameTable.Count()-1; i>0; i--) { RenameInfo * pRi = &lstRenameTable[i]; if(pRi->nLeftnTop) { for(int n=0; nnTop) *lstAreaPtrTable[n] = pRi->nLeft; } else { for(int n=0; nnLeft) *lstAreaPtrTable[n] = pRi->nTop; } } m_lstWaterAreaSizeTable.Reset(); for(int x=0; x Stack; Stack.PreAllocate(8000000/sizeof(TerPoint)); m_lstWaterAreaSizeTable.Reset(); ushort nAreaID = 1, nStep = MIN_UNITS_IN_WATER_AREA*4; for(int X=nStep; X0 && CurPoint.y>0 && !m_arrAlreadyProcessed[CurPoint.x][CurPoint.y+1]) Stack.Add(TerPoint(CurPoint.x ,CurPoint.y+1)); if(CurPoint.x0 && CurPoint.y>0 && !m_arrAlreadyProcessed[CurPoint.x][CurPoint.y-1]) Stack.Add(TerPoint(CurPoint.x ,CurPoint.y-1)); if(CurPoint.x0 && CurPoint.y>0 && !m_arrAlreadyProcessed[CurPoint.x-1][CurPoint.y]) Stack.Add(TerPoint(CurPoint.x-1,CurPoint.y )); if(CurPoint.x0 && CurPoint.y>0 && !m_arrAlreadyProcessed[CurPoint.x+1][CurPoint.y]) Stack.Add(TerPoint(CurPoint.x+1,CurPoint.y )); } else if(Stack.Count()) { CurPoint = Stack.Last(); Stack.DeleteLast(); } else break; } while(m_lstWaterAreaSizeTable.Count()<=nAreaID) m_lstWaterAreaSizeTable.Add(int(0)); m_lstWaterAreaSizeTable[nAreaID] = nCounter; if(nCounter>m_nMaxAreaSize) m_nMaxAreaSize = nCounter; if(nCounter) nAreaID++; break; // only out water } return 0; }*/ void CSectorInfo::MakeBeachStage1() { if(!m_pTerrain->m_pBeachGenerator->m_lstWaterAreaSizeTable.Count()) return; m_bBeachPresent = false; for(int x=m_nOriginX; x<=m_nOriginX+CTerrain::GetSectorSize(); x+=CTerrain::GetHeightMapUnitSize()) for(int y=m_nOriginY; y<=m_nOriginY+CTerrain::GetSectorSize(); y+=CTerrain::GetHeightMapUnitSize()) { bool in_water = m_pTerrain->GetZSafe(x,y) < m_pTerrain->GetWaterLevel(); bool beach = 0; for(int _x=x-CTerrain::GetHeightMapUnitSize(); _x<=x+CTerrain::GetHeightMapUnitSize(); _x+=CTerrain::GetHeightMapUnitSize()) for(int _y=y-CTerrain::GetHeightMapUnitSize(); _y<=y+CTerrain::GetHeightMapUnitSize(); _y+=CTerrain::GetHeightMapUnitSize()) { bool _in_water = (m_pTerrain->GetZSafe(_x,_y) < m_pTerrain->GetWaterLevel()) && (_x>0 && _y>0 && _xm_pBeachGenerator->m_lstWaterAreaSizeTable [ (m_pTerrain->m_pBeachGenerator->m_WaterAreaMap[_x/CTerrain::GetHeightMapUnitSize()][_y/CTerrain::GetHeightMapUnitSize()]) ] >MIN_UNITS_IN_WATER_AREA); if(in_water != _in_water && (x==_x || y==_y)) { beach = true; m_bBeachPresent = true; break; } } m_pTerrain->m_pBeachGenerator->m_arrBeachMap[x/CTerrain::GetHeightMapUnitSize()][y/CTerrain::GetHeightMapUnitSize()].beach = beach; m_pTerrain->m_pBeachGenerator->m_arrBeachMap[x/CTerrain::GetHeightMapUnitSize()][y/CTerrain::GetHeightMapUnitSize()].in_water = in_water; } } void CSectorInfo::MakeBeachStage2(FILE * hFileToSave) { struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * m_pVertBufferBeach=0; int m_nVertNumBeach=0; if(!m_bBeachPresent) { if(hFileToSave) GetSystem()->GetIPak()->FPrintf(hFileToSave, "BeachInfo(%8d)",GetSecIndex()); // m_nVertNumBeach is zero = no beach here if(hFileToSave) GetSystem()->GetIPak()->FWrite(&m_nVertNumBeach,1,sizeof(m_nVertNumBeach),hFileToSave); return; } int group; for(group=0; groupm_pBeachGenerator->m_arrBeachMap[x/CTerrain::GetHeightMapUnitSize()][y/CTerrain::GetHeightMapUnitSize()].beach && !m_pTerrain->m_pBeachGenerator->m_arrBeachMap[x/CTerrain::GetHeightMapUnitSize()][y/CTerrain::GetHeightMapUnitSize()].in_water) { Vec3d water_dir(0,0,0); for(int _x=x-CTerrain::GetHeightMapUnitSize(); _x<=x+CTerrain::GetHeightMapUnitSize(); _x+=CTerrain::GetHeightMapUnitSize()) for(int _y=y-CTerrain::GetHeightMapUnitSize(); _y<=y+CTerrain::GetHeightMapUnitSize(); _y+=CTerrain::GetHeightMapUnitSize()) if(_x>=0 && _y>=0 && _xm_pBeachGenerator->m_arrBeachMap[_x/CTerrain::GetHeightMapUnitSize()][_y/CTerrain::GetHeightMapUnitSize()].in_water) water_dir += Vec3d(float(_x-x),float(_y-y),0); water_dir.Normalize(); Vec3d border_pos((float)x,(float)y,m_pTerrain->GetWaterLevel()); BeachPairStruct pair; pair.water_dir = water_dir; water_dir/=100; int t=0; while(m_pTerrain->GetZApr(border_pos.x,border_pos.y)>m_pTerrain->GetWaterLevel() && t<100) { border_pos += water_dir; t++; } // assert(t<100); /* if( border_pos.x>=m_nOriginX && border_pos.y>=m_nOriginY && border_pos.x<(m_nOriginX+CTerrain::GetSectorSize()) && border_pos.y<(m_nOriginY+CTerrain::GetSectorSize()) )*/ { pair.pos = border_pos ;//+ Vec3d(0,0,0.01f); m_lstUnsortedBeachVerts.Add(pair); } /* else { if(GetSectorFromPoint(border_pos.x,border_pos.y) == this }*/ } } if(!m_lstUnsortedBeachVerts.Count()) { if(hFileToSave) GetSystem()->GetIPak()->FPrintf(hFileToSave, "BeachInfo(%8d)",GetSecIndex()); // m_nVertNumBeach is zero = no beach here if(hFileToSave) GetSystem()->GetIPak()->FWrite(&m_nVertNumBeach,1,sizeof(m_nVertNumBeach),hFileToSave); return; } for(group=0; group=m_lstUnsortedBeachVerts.Count()) break; // no more free points m_arrlistBeachVerts[group].Add(m_lstUnsortedBeachVerts[first]); m_lstUnsortedBeachVerts[first].busy ++; for(int pass=0; pass=0) { // if found add into current group if(prev_closest_id>=0) m_lstUnsortedBeachVerts[prev_closest_id].busy++; prev_closest_id = closest_id; m_arrlistBeachVerts[group].Add(m_lstUnsortedBeachVerts[closest_id]); m_lstUnsortedBeachVerts[closest_id].busy ++; } else { if(prev_closest_id>=0) m_lstUnsortedBeachVerts[prev_closest_id].busy++; prev_closest_id = closest_id; closest_id = -1; { // try to find semi free point as last float closest_dist = 100000; for(int j=0; j=0) { // if found add into current group m_arrlistBeachVerts[group].Add(m_lstUnsortedBeachVerts[closest_id]); m_lstUnsortedBeachVerts[closest_id].busy ++; } if(m_arrlistBeachVerts[group].Count()==1) m_arrlistBeachVerts[group].Clear(); break; } } } // for(int u=0; uDrawLabel(UnsortedBeachVerts[u].pos,1,"%d",UnsortedBeachVerts[u].busy); // smooth for(group=0; group-0.99f) dir = dir1 + dir2; else dir = dir1.Cross(Vec3d(0,0,1)); dir.Normalize(); if(dir.Dot(m_arrlistBeachVerts[group][i ].water_dir)<0) dir = -dir; m_arrlistBeachVerts[group][i ].water_dir = dir; } } for( group=0; grouppos + p1->water_dir*2).x); int _y = int((p1->pos + p1->water_dir*2).y); // int nAreaID = m_pTerrain->m_pBeachGenerator->m_WaterAreaMap[_x/CTerrain::GetHeightMapUnitSize()][_y/CTerrain::GetHeightMapUnitSize()]; float fBeachSize = (float)m_pTerrain->m_fShoreSize;//1.f+8.f*((float)m_lstWaterAreaSizeTable[nAreaID]/(float)m_nMaxAreaSize); // left p1->pos1 = p1->pos; int l=0; while(p1->pos1.zGetWaterLevel()+0.1f*fBeachSize && l<70) { p1->pos1 = p1->pos1 - m_arrlistBeachVerts[group][i].water_dir*0.05f; p1->pos1.z = m_pTerrain->GetZApr(p1->pos1.x,p1->pos1.y); l++; } p1->pos2 = p1->pos + p1->water_dir*fBeachSize; p1->posm = p1->pos + Vec3d(0,0,0.2f*fBeachSize/4); // right p2->pos1 = p2->pos; l=0; while(p2->pos1.zGetWaterLevel()+0.1f*fBeachSize && l<70) { p2->pos1 = p2->pos1 - p2->water_dir*0.05f; p2->pos1.z = m_pTerrain->GetZApr(p2->pos1.x,p2->pos1.y); l++; } p2->pos2 = p2->pos + p2->water_dir*fBeachSize; p2->posm = p2->pos + Vec3d(0,0,0.2f*fBeachSize/4); } } m_lstUnsortedBeachVerts.Reset(); ///////////////////////////////////////////////////////////////////////////////////////////// // stage 3 ///////////////////////////////////////////////////////////////////////////////////////////// if(!m_bBeachPresent) { if(hFileToSave) GetSystem()->GetIPak()->FPrintf(hFileToSave, "BeachInfo(%8d)",GetSecIndex()); // m_nVertNumBeach is zero = no beach here if(hFileToSave) GetSystem()->GetIPak()->FWrite(&m_nVertNumBeach,1,sizeof(m_nVertNumBeach),hFileToSave); return; } // count elements int nElements = 0; for( group=0; groupGetIPak()->FPrintf(hFileToSave, "BeachInfo(%8d)",GetSecIndex()); // m_nVertNumBeach is zero = no beach here if(hFileToSave) GetSystem()->GetIPak()->FWrite(&m_nVertNumBeach,1,sizeof(m_nVertNumBeach),hFileToSave); return; } } // make buffer m_nVertNumBeach = 6*nElements; m_pVertBufferBeach = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F[m_nVertNumBeach]; list2 lstBeachIndices; // tmp buff struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F verts[6]; // color Vec3d vTerrainColor = GetSystem()->GetI3DEngine()->GetWorldColor();//*GetSystem()->GetI3DEngine()->GetWorldBrightnes(); for(int i=0; i<6; i++) { verts[i].color.bcolor[0]=(byte)min(255,vTerrainColor[0]*512.0f); verts[i].color.bcolor[1]=(byte)min(255,vTerrainColor[1]*512.0f); verts[i].color.bcolor[2]=(byte)min(255,vTerrainColor[2]*512.0f); verts[i].color.bcolor[3]=0; } verts[2].color.bcolor[3]=255; verts[3].color.bcolor[3]=255; // tex coord verts[0].st[0]=0; verts[0].st[1]=1.0f; verts[1].st[0]=1; verts[1].st[1]=1.0f; verts[2].st[0]=0; verts[2].st[1]=0.5f; verts[3].st[0]=1; verts[3].st[1]=0.5f; verts[4].st[0]=0; verts[4].st[1]=0.0f; verts[5].st[0]=1; verts[5].st[1]=0.0f; // make final buffer int nPos=0; int nIndex=0; for( group=0; grouppos1.z = min(p1->pos1.z, m_pTerrain->GetWaterLevel()+fMaxShoreHeight); p1->pos2.z = min(p1->pos2.z, m_pTerrain->GetWaterLevel()+fMaxShoreHeight); p1->posm.z = min(p1->posm.z, m_pTerrain->GetWaterLevel()+fMaxShoreHeight); p2->pos1.z = min(p2->pos1.z, m_pTerrain->GetWaterLevel()+fMaxShoreHeight); p2->pos2.z = min(p2->pos2.z, m_pTerrain->GetWaterLevel()+fMaxShoreHeight); p2->posm.z = min(p2->posm.z, m_pTerrain->GetWaterLevel()+fMaxShoreHeight); float fShoreHeightOffset = 0.05f; Vec3d vTerrainColor = GetSystem()->GetI3DEngine()->GetWorldColor(); Vec3d vAmbColor = GetSystem()->GetI3DEngine()->GetOutdoorAmbientColor(); vAmbColor.x *= (vTerrainColor.x*0.7f); vAmbColor.y *= (vTerrainColor.y*0.7f); vAmbColor.z *= (vTerrainColor.z*0.7f); float fBrR = vAmbColor.x + (1.f-vAmbColor.x)*m_pTerrain->IsOnTheLight((int)p1->posm.x,(int)p1->posm.y); float fBrG = vAmbColor.y + (1.f-vAmbColor.y)*m_pTerrain->IsOnTheLight((int)p1->posm.x,(int)p1->posm.y); float fBrB = vAmbColor.z + (1.f-vAmbColor.z)*m_pTerrain->IsOnTheLight((int)p1->posm.x,(int)p1->posm.y); uchar r1 = (byte)(min(255,vTerrainColor[0]*512.0f)*fBrR); uchar g1 = (byte)(min(255,vTerrainColor[1]*512.0f)*fBrG); uchar b1 = (byte)(min(255,vTerrainColor[2]*512.0f)*fBrB); fBrR = vAmbColor.x + (1.f-vAmbColor.x)*m_pTerrain->IsOnTheLight((int)p2->posm.x,(int)p2->posm.y); fBrG = vAmbColor.y + (1.f-vAmbColor.y)*m_pTerrain->IsOnTheLight((int)p2->posm.x,(int)p2->posm.y); fBrB = vAmbColor.z + (1.f-vAmbColor.z)*m_pTerrain->IsOnTheLight((int)p2->posm.x,(int)p2->posm.y); uchar r2 = (byte)(min(255,vTerrainColor[0]*512.0f)*fBrR); uchar g2 = (byte)(min(255,vTerrainColor[1]*512.0f)*fBrG); uchar b2 = (byte)(min(255,vTerrainColor[2]*512.0f)*fBrB); // pos verts[0].xyz.x = p1->pos1.x; verts[0].xyz.y = p1->pos1.y; verts[0].xyz.z = p1->pos1.z+fShoreHeightOffset; verts[0].color.bcolor[0] = r1; verts[0].color.bcolor[1] = g1; verts[0].color.bcolor[2] = b1; verts[1].xyz.x = p2->pos1.x; verts[1].xyz.y = p2->pos1.y; verts[1].xyz.z = p2->pos1.z+fShoreHeightOffset; verts[1].color.bcolor[0] = r2; verts[1].color.bcolor[1] = g2; verts[1].color.bcolor[2] = b2; verts[2].xyz.x = p1->posm.x; verts[2].xyz.y = p1->posm.y; verts[2].xyz.z = p1->posm.z+fShoreHeightOffset; verts[2].color.bcolor[0] = r1; verts[2].color.bcolor[1] = g1; verts[2].color.bcolor[2] = b1; verts[3].xyz.x = p2->posm.x; verts[3].xyz.y = p2->posm.y; verts[3].xyz.z = p2->posm.z+fShoreHeightOffset; verts[3].color.bcolor[0] = r2; verts[3].color.bcolor[1] = g2; verts[3].color.bcolor[2] = b2; verts[4].xyz.x = p1->pos2.x; verts[4].xyz.y = p1->pos2.y; verts[4].xyz.z = p1->pos2.z+fShoreHeightOffset; verts[4].color.bcolor[0] = r1; verts[4].color.bcolor[1] = g1; verts[4].color.bcolor[2] = b1; verts[5].xyz.x = p2->pos2.x; verts[5].xyz.y = p2->pos2.y; verts[5].xyz.z = p2->pos2.z+fShoreHeightOffset; verts[5].color.bcolor[0] = r2; verts[5].color.bcolor[1] = g2; verts[5].color.bcolor[2] = b2; // draw memcpy(&m_pVertBufferBeach[nPos],verts,sizeof(verts)); nPos+=6; lstBeachIndices.Add(nIndex+0); lstBeachIndices.Add(nIndex+1); lstBeachIndices.Add(nIndex+2); lstBeachIndices.Add(nIndex+3); lstBeachIndices.Add(nIndex+2); lstBeachIndices.Add(nIndex+1); lstBeachIndices.Add(nIndex+2); lstBeachIndices.Add(nIndex+3); lstBeachIndices.Add(nIndex+4); lstBeachIndices.Add(nIndex+5); lstBeachIndices.Add(nIndex+4); lstBeachIndices.Add(nIndex+3); nIndex+=6; } // save calculated data into file if(hFileToSave) { // header GetSystem()->GetIPak()->FPrintf(hFileToSave, "BeachInfo(%8d)",GetSecIndex()); // verts GetSystem()->GetIPak()->FWrite(&m_nVertNumBeach,1,sizeof(m_nVertNumBeach),hFileToSave); GetSystem()->GetIPak()->FWrite(m_pVertBufferBeach,m_nVertNumBeach,sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F),hFileToSave); // indices int nIndCount = lstBeachIndices.Count(); GetSystem()->GetIPak()->FWrite(&nIndCount,1,sizeof(nIndCount),hFileToSave); GetSystem()->GetIPak()->FWrite(&lstBeachIndices[0],nIndCount,sizeof(ushort),hFileToSave); } // make vertex buffer if(m_pLeafBufferBeach) GetRenderer()->DeleteLeafBuffer(m_pLeafBufferBeach); m_pLeafBufferBeach = GetRenderer()->CreateLeafBufferInitialized( m_pVertBufferBeach, m_nVertNumBeach, VERTEX_FORMAT_P3F_COL4UB_TEX2F, lstBeachIndices.GetElements(), lstBeachIndices.Count(), R_PRIMV_TRIANGLES, "WaterBeach"); m_pLeafBufferBeach->SetChunk( m_pTerrain->m_pSHShore, 0, m_nVertNumBeach, 0, lstBeachIndices.Count()); assert(m_pLeafBufferBeach); delete [] m_pVertBufferBeach; m_pVertBufferBeach=0; } // load precalculated data from file void CSectorInfo::LoadBeach(FILE * hFileToLoad) { if(!hFileToLoad) return; // header int nReadedIndex=-1; char szHeader[32]=""; GetSystem()->GetIPak()->FRead(szHeader, 1, 19, hFileToLoad); szHeader[19]=0; sscanf(szHeader, "BeachInfo(%8d)", &nReadedIndex); if(nReadedIndex!=GetSecIndex()) { GetConsole()->Exit("CSectorInfo::LoadBeach: File beach.tmp is corrupted, try to delete this file (or all *.tmp files) and run again"); assert(0); // Exit should do exit } m_bBeachPresent = true; struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * m_pVertBufferBeach=0; int m_nVertNumBeach=0; // verts GetSystem()->GetIPak()->FRead(&m_nVertNumBeach,1,sizeof(m_nVertNumBeach),hFileToLoad); if(!m_nVertNumBeach) return; // no beach here assert(m_nVertNumBeach<=2048); if(m_nVertNumBeach>2048) return; // no beach here m_pVertBufferBeach = new struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F[m_nVertNumBeach]; GetSystem()->GetIPak()->FRead(m_pVertBufferBeach,m_nVertNumBeach,sizeof(struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F),hFileToLoad); // flip colors for DX if(!(GetRenderer()->GetFeatures() & RFT_RGBA)) { struct_VERTEX_FORMAT_P3F_COL4UB_TEX2F * pVert = m_pVertBufferBeach; for(int i=0; icolor.bcolor[0], pVert->color.bcolor[2]); pVert++; } } // indices int nIndCount = -1; GetSystem()->GetIPak()->FRead(&nIndCount,1,sizeof(nIndCount),hFileToLoad); list2 lstBeachIndices; lstBeachIndices.PreAllocate(nIndCount,nIndCount); GetSystem()->GetIPak()->FRead(&lstBeachIndices[0],nIndCount,sizeof(ushort),hFileToLoad); // make vertex buffer if(m_pLeafBufferBeach) GetRenderer()->DeleteLeafBuffer(m_pLeafBufferBeach); m_pLeafBufferBeach = GetRenderer()->CreateLeafBufferInitialized( m_pVertBufferBeach, m_nVertNumBeach, VERTEX_FORMAT_P3F_COL4UB_TEX2F, lstBeachIndices.GetElements(), lstBeachIndices.Count(), R_PRIMV_TRIANGLES, "WaterBeach"); if(m_pTerrain->m_pSHShore) m_pLeafBufferBeach->SetChunk( m_pTerrain->m_pSHShore, 0, m_nVertNumBeach, 0, lstBeachIndices.Count()); assert(m_pLeafBufferBeach); delete [] m_pVertBufferBeach; m_pVertBufferBeach=0; } void CSectorInfo::RenderBeach(IShader * pShader, float fZoomFactor, float fCamZ) { if(m_pLeafBufferBeach && m_bBeachPresent) if(m_fDistance*fZoomFactor < 128 + (fCamZ - m_fMinZ)*0.5f) { CCObject * pObject = GetRenderer()->EF_GetObject(true); m_pLeafBufferBeach->SetShader(pShader); pObject->m_Matrix.SetIdentity(); m_pLeafBufferBeach->AddRE( pObject, 0, (fCamZ>m_pTerrain->GetWaterLevel()) ? eS_Banner : eS_WaterBeach ); pObject->m_SortId = -1; // render water beaches after water // let distance sorter think that object is in camera position if(m_pLeafBufferBeach->m_pMats->Count() && m_pLeafBufferBeach->m_pMats->Get(0)->pRE) m_pLeafBufferBeach->m_vBoxMin = m_pLeafBufferBeach->m_vBoxMax = GetViewCamera().GetPos(); } } const void * CSectorInfo::GetShoreGeometry(int & nPosStride, int & nVertCount) { if(!m_pLeafBufferBeach || !m_pLeafBufferBeach->m_SecVertCount) return 0; nVertCount = m_pLeafBufferBeach->m_SecVertCount; return m_pLeafBufferBeach->GetPosPtr(nPosStride,0,true); }