void CSimulation2::RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling) { PROFILE3("sim submit"); CMessageRenderSubmit msg(collector, frustum, culling); m->m_ComponentManager.BroadcastMessage(msg); }
void ParticleRenderer::PrepareForRendering() { PROFILE3("prepare particles"); // Can't load the shader in the constructor because it's called before the // renderer initialisation is complete, so load it the first time through here if (!m->shader) { typedef std::map<CStr, CStr> Defines; Defines defNull; m->shader = g_Renderer.GetShaderManager().LoadProgram("particle", defNull); m->shaderSolid = g_Renderer.GetShaderManager().LoadProgram("particle_solid", defNull); } { PROFILE("update emitters"); for (size_t i = 0; i < m->emitters.size(); ++i) { CParticleEmitter* emitter = m->emitters[i]; emitter->UpdateArrayData(); } } { // Sort back-to-front by distance from camera PROFILE("sort emitters"); CMatrix3D worldToCam; g_Renderer.GetViewCamera().m_Orientation.GetInverse(worldToCam); std::stable_sort(m->emitters.begin(), m->emitters.end(), SortEmitterDistance(worldToCam)); } // TODO: should batch by texture here when possible, maybe }
/** * Given a grid of passable/impassable navcells (based on some passability mask), * computes a new grid where a navcell is impassable (per that mask) if * it is <=clearance navcells away from an impassable navcell in the original grid. * The results are ORed onto the original grid. * * This is used for adding clearance onto terrain-based navcell passability. * * TODO PATHFINDER: might be nicer to get rounded corners by measuring clearances as * Euclidean distances; currently it effectively does dist=max(dx,dy) instead. * This would only really be a problem for big clearances. */ static void ExpandImpassableCells(Grid<u16>& grid, u16 clearance, pass_class_t mask) { PROFILE3("ExpandImpassableCells"); u16 w = grid.m_W; u16 h = grid.m_H; // First expand impassable cells horizontally into a temporary 1-bit grid Grid<u8> tempGrid(w, h); for (u16 j = 0; j < h; ++j) { // New cell (i,j) is blocked if (i',j) blocked for any i-clearance <= i' <= i+clearance // Count the number of blocked cells around i=0 u16 numBlocked = 0; for (u16 i = 0; i <= clearance && i < w; ++i) if (!IS_PASSABLE(grid.get(i, j), mask)) ++numBlocked; for (u16 i = 0; i < w; ++i) { // Store a flag if blocked by at least one nearby cell if (numBlocked) tempGrid.set(i, j, 1); // Slide the numBlocked window along: // remove the old i-clearance value, add the new (i+1)+clearance // (avoiding overflowing the grid) if (i >= clearance && !IS_PASSABLE(grid.get(i-clearance, j), mask)) --numBlocked; if (i+1+clearance < w && !IS_PASSABLE(grid.get(i+1+clearance, j), mask)) ++numBlocked; } } for (u16 i = 0; i < w; ++i) { // New cell (i,j) is blocked if (i,j') blocked for any j-clearance <= j' <= j+clearance // Count the number of blocked cells around j=0 u16 numBlocked = 0; for (u16 j = 0; j <= clearance && j < h; ++j) if (tempGrid.get(i, j)) ++numBlocked; for (u16 j = 0; j < h; ++j) { // Add the mask if blocked by at least one nearby cell if (numBlocked) grid.set(i, j, grid.get(i, j) | mask); // Slide the numBlocked window along: // remove the old j-clearance value, add the new (j+1)+clearance // (avoiding overflowing the grid) if (j >= clearance && tempGrid.get(i, j-clearance)) --numBlocked; if (j+1+clearance < h && tempGrid.get(i, j+1+clearance)) ++numBlocked; } } }
void CPatchRData::BuildSides() { PROFILE3("build sides"); std::vector<SSideVertex> sideVertices; int sideFlags = m_Patch->GetSideFlags(); // If no sides are enabled, we don't need to do anything if (!sideFlags) return; // For each side, generate a tristrip by adding a vertex at ground/water // level and a vertex underneath at height 0. if (sideFlags & CPATCH_SIDE_NEGX) BuildSide(sideVertices, CPATCH_SIDE_NEGX); if (sideFlags & CPATCH_SIDE_POSX) BuildSide(sideVertices, CPATCH_SIDE_POSX); if (sideFlags & CPATCH_SIDE_NEGZ) BuildSide(sideVertices, CPATCH_SIDE_NEGZ); if (sideFlags & CPATCH_SIDE_POSZ) BuildSide(sideVertices, CPATCH_SIDE_POSZ); if (sideVertices.empty()) return; if (!m_VBSides) m_VBSides = g_VBMan.Allocate(sizeof(SSideVertex), sideVertices.size(), GL_STATIC_DRAW, GL_ARRAY_BUFFER); m_VBSides->m_Owner->UpdateChunkVertices(m_VBSides, &sideVertices[0]); }
/////////////////////////////////////////////////////////// // This callback is part of the Scene interface // Submit all objects visible in the given frustum void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c) { { PROFILE3("submit terrain"); CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain(); float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight + 0.001f; const ssize_t patchesPerSide = pTerrain->GetPatchesPerSide(); // find out which patches will be drawn for (ssize_t j=0; j<patchesPerSide; ++j) { for (ssize_t i=0; i<patchesPerSide; ++i) { CPatch* patch=pTerrain->GetPatch(i,j); // can't fail // If the patch is underwater, calculate a bounding box that also contains the water plane CBoundingBoxAligned bounds = patch->GetWorldBounds(); if(bounds[1].Y < waterHeight) bounds[1].Y = waterHeight; if (!m->Culling || frustum.IsBoxVisible(bounds)) c->Submit(patch); } } } m->Game->GetSimulation2()->RenderSubmit(*c, frustum, m->Culling); }
void CNetClientSession::Poll() { PROFILE3("net client poll"); ENSURE(m_Host && m_Server); m_FileTransferer.Poll(); ENetEvent event; while (enet_host_service(m_Host, &event, 0) > 0) { switch (event.type) { case ENET_EVENT_TYPE_CONNECT: { ENSURE(event.peer == m_Server); // Report the server address char hostname[256] = "(error)"; enet_address_get_host_ip(&event.peer->address, hostname, ARRAY_SIZE(hostname)); LOGMESSAGE("Net client: Connected to %s:%u", hostname, (unsigned int)event.peer->address.port); m_Client.HandleConnect(); break; } case ENET_EVENT_TYPE_DISCONNECT: { ENSURE(event.peer == m_Server); LOGMESSAGE("Net client: Disconnected"); m_Client.HandleDisconnect(event.data); return; } case ENET_EVENT_TYPE_RECEIVE: { CNetMessage* msg = CNetMessageFactory::CreateMessage(event.packet->data, event.packet->dataLength, m_Client.GetScriptInterface()); if (msg) { LOGMESSAGE("Net client: Received message %s of size %lu from server", msg->ToString().c_str(), (unsigned long)msg->GetSerializedLength()); m_Client.HandleMessage(msg); delete msg; } enet_packet_destroy(event.packet); break; } case ENET_EVENT_TYPE_NONE: break; } } }
void CNetClientSession::Flush() { PROFILE3("net client flush"); ENSURE(m_Host && m_Server); enet_host_flush(m_Host); }
void HierarchicalPathfinder::Recompute(Grid<NavcellData>* grid, const std::map<std::string, pass_class_t>& nonPathfindingPassClassMasks, const std::map<std::string, pass_class_t>& pathfindingPassClassMasks) { PROFILE3("Hierarchical Recompute"); m_PassClassMasks = pathfindingPassClassMasks; std::map<std::string, pass_class_t> allPassClasses = m_PassClassMasks; allPassClasses.insert(nonPathfindingPassClassMasks.begin(), nonPathfindingPassClassMasks.end()); m_W = grid->m_W; m_H = grid->m_H; // Divide grid into chunks with round-to-positive-infinity m_ChunksW = (grid->m_W + CHUNK_SIZE - 1) / CHUNK_SIZE; m_ChunksH = (grid->m_H + CHUNK_SIZE - 1) / CHUNK_SIZE; ENSURE(m_ChunksW < 256 && m_ChunksH < 256); // else the u8 Chunk::m_ChunkI will overflow m_Chunks.clear(); m_Edges.clear(); for (auto& passClassMask : allPassClasses) { pass_class_t passClass = passClassMask.second; // Compute the regions within each chunk m_Chunks[passClass].resize(m_ChunksW*m_ChunksH); for (int cj = 0; cj < m_ChunksH; ++cj) { for (int ci = 0; ci < m_ChunksW; ++ci) { m_Chunks[passClass].at(cj*m_ChunksW + ci).InitRegions(ci, cj, grid, passClass); } } // Construct the search graph over the regions EdgesMap& edges = m_Edges[passClass]; for (int cj = 0; cj < m_ChunksH; ++cj) { for (int ci = 0; ci < m_ChunksW; ++ci) { FindEdges(ci, cj, passClass, edges); } } } if (m_DebugOverlay) { PROFILE("debug overlay"); m_DebugOverlayLines.clear(); AddDebugEdges(GetPassabilityClass("default")); } }
virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) { switch (msg.GetType()) { case MT_Interpolate: { PROFILE3("OverlayRenderer::Interpolate"); const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg); Interpolate(msgData.deltaSimTime, msgData.offset); break; } case MT_RenderSubmit: { PROFILE3("OverlayRenderer::RenderSubmit"); const CMessageRenderSubmit& msgData = static_cast<const CMessageRenderSubmit&> (msg); RenderSubmit(msgData.collector); break; } } }
void CNetLocalTurnManager::NotifyFinishedUpdate(u32 UNUSED(turn)) { #if 0 // this hurts performance and is only useful for verifying log replays std::string hash; { PROFILE3("state hash check"); ENSURE(m_Simulation2.ComputeStateHash(hash)); } m_Replay.Hash(hash); #endif }
void CSimulation2Impl::Interpolate(float simFrameLength, float frameOffset, float realFrameLength) { PROFILE3("sim interpolate"); m_LastFrameOffset = frameOffset; CMessageInterpolate msg(simFrameLength, frameOffset, realFrameLength); m_ComponentManager.BroadcastMessage(msg); // Clean up any entities destroyed during interpolate (e.g. local corpses) m_ComponentManager.FlushDestroyedComponents(); }
static void RendererIncrementalLoad() { PROFILE3("renderer incremental load"); const double maxTime = 0.1f; double startTime = timer_Time(); bool more; do { more = g_Renderer.GetTextureManager().MakeProgress(); } while (more && timer_Time() - startTime < maxTime); }
void CCmpPathfinder::ComputeTerrainPassabilityGrid(const Grid<u16>& shoreGrid) { PROFILE3("terrain passability"); CmpPtr<ICmpWaterManager> cmpWaterManager(GetSimContext(), SYSTEM_ENTITY); CTerrain& terrain = GetSimContext().GetTerrain(); // Compute initial terrain-dependent passability for (int j = 0; j < m_MapSize * Pathfinding::NAVCELLS_PER_TILE; ++j) { for (int i = 0; i < m_MapSize * Pathfinding::NAVCELLS_PER_TILE; ++i) { // World-space coordinates for this navcell fixed x, z; Pathfinding::NavcellCenter(i, j, x, z); // Terrain-tile coordinates for this navcell int itile = i / Pathfinding::NAVCELLS_PER_TILE; int jtile = j / Pathfinding::NAVCELLS_PER_TILE; // Gather all the data potentially needed to determine passability: fixed height = terrain.GetExactGroundLevelFixed(x, z); fixed water; if (cmpWaterManager) water = cmpWaterManager->GetWaterLevel(x, z); fixed depth = water - height; //fixed slope = terrain.GetExactSlopeFixed(x, z); // Exact slopes give kind of weird output, so just use rough tile-based slopes fixed slope = terrain.GetSlopeFixed(itile, jtile); // Get world-space coordinates from shoreGrid (which uses terrain tiles) fixed shoredist = fixed::FromInt(shoreGrid.get(itile, jtile)).MultiplyClamp(TERRAIN_TILE_SIZE); // Compute the passability for every class for this cell: NavcellData t = 0; for (PathfinderPassability& passability : m_PassClasses) { if (!passability.IsPassable(depth, slope, shoredist)) t |= passability.m_Mask; } m_Grid->set(i, j, t); } } }
void HierarchicalPathfinder::Update(Grid<NavcellData>* grid, const Grid<u8>& dirtinessGrid) { PROFILE3("Hierarchical Update"); std::vector<std::pair<int, int> > processedChunks; for (int j = 0; j < dirtinessGrid.m_H; ++j) { for (int i = 0; i < dirtinessGrid.m_W; ++i) { if (!dirtinessGrid.get(i, j)) continue; std::pair<int, int> chunkID(i / CHUNK_SIZE, j / CHUNK_SIZE); for (auto& passClassMask : m_PassClassMasks) { pass_class_t passClass = passClassMask.second; Chunk& a = m_Chunks[passClass].at(chunkID.second*m_ChunksW + chunkID.first); if (std::find(processedChunks.begin(), processedChunks.end(), chunkID) == processedChunks.end()) { processedChunks.push_back(chunkID); a.InitRegions(chunkID.first, chunkID.second, grid, passClass); } } } } // TODO: Also be clever with edges m_Edges.clear(); for (auto& passClassMask : m_PassClassMasks) { pass_class_t passClass = passClassMask.second; EdgesMap& edges = m_Edges[passClass]; for (int cj = 0; cj < m_ChunksH; ++cj) { for (int ci = 0; ci < m_ChunksW; ++ci) { FindEdges(ci, cj, passClass, edges); } } } if (m_DebugOverlay) { PROFILE("debug overlay"); m_DebugOverlayLines.clear(); AddDebugEdges(GetPassabilityClass("default")); } }
bool CGame::Update(const double deltaRealTime, bool doInterpolate) { if (m_Paused) return true; if (!m_TurnManager) return true; const double deltaSimTime = deltaRealTime * m_SimRate; bool ok = true; if (deltaSimTime) { // To avoid confusing the profiler, we need to trigger the new turn // while we're not nested inside any PROFILE blocks if (m_TurnManager->WillUpdate(deltaSimTime)) g_Profiler.Turn(); // At the normal sim rate, we currently want to render at least one // frame per simulation turn, so let maxTurns be 1. But for fast-forward // sim rates we want to allow more, so it's not bounded by framerate, // so just use the sim rate itself as the number of turns per frame. size_t maxTurns = (size_t)m_SimRate; if (m_TurnManager->Update(deltaSimTime, maxTurns)) { { PROFILE3("gui sim update"); g_GUI->SendEventToAll("SimulationUpdate"); } GetView()->GetLOSTexture().MakeDirty(); } if (CRenderer::IsInitialised()) g_Renderer.GetTimeManager().Update(deltaSimTime); } if (doInterpolate) { m_TurnManager->Interpolate(deltaSimTime, deltaRealTime); #if CONFIG2_AUDIO if ( g_SoundManager ) g_SoundManager->IdleTask(); #endif } return ok; }
void CPatchRData::BuildVertices() { PROFILE3("build vertices"); // create both vertices and lighting colors // number of vertices in each direction in each patch ssize_t vsize=PATCH_SIZE+1; std::vector<SBaseVertex> vertices; vertices.resize(vsize*vsize); // get index of this patch ssize_t px=m_Patch->m_X; ssize_t pz=m_Patch->m_Z; CTerrain* terrain=m_Patch->m_Parent; const CLightEnv& lightEnv = g_Renderer.GetLightEnv(); bool cpuLighting = (g_Renderer.GetRenderPath() == CRenderer::RP_FIXED); // build vertices for (ssize_t j=0;j<vsize;j++) { for (ssize_t i=0;i<vsize;i++) { ssize_t ix=px*PATCH_SIZE+i; ssize_t iz=pz*PATCH_SIZE+j; ssize_t v=(j*vsize)+i; // calculate vertex data terrain->CalcPosition(ix,iz,vertices[v].m_Position); // Calculate diffuse lighting for this vertex // Ambient is added by the lighting pass (since ambient is the same // for all vertices, it need not be stored in the vertex structure) CVector3D normal; terrain->CalcNormal(ix,iz,normal); vertices[v].m_Normal = normal; vertices[v].m_DiffuseColor = cpuLighting ? lightEnv.EvaluateTerrainDiffuseScaled(normal) : lightEnv.EvaluateTerrainDiffuseFactor(normal); } } // upload to vertex buffer if (!m_VBBase) m_VBBase = g_VBMan.Allocate(sizeof(SBaseVertex), vsize * vsize, GL_STATIC_DRAW, GL_ARRAY_BUFFER); m_VBBase->m_Owner->UpdateChunkVertices(m_VBBase, &vertices[0]); }
void CGUIManager::TickObjects() { PROFILE3("gui tick"); // We share the script runtime with everything else that runs in the same thread. // This call makes sure we trigger GC regularly even if the simulation is not running. m_ScriptInterface->GetRuntime()->MaybeIncrementalGC(1.0f); // Save an immutable copy so iterators aren't invalidated by tick handlers PageStackType pageStack = m_PageStack; for (PageStackType::iterator it = pageStack.begin(); it != pageStack.end(); ++it) { m_CurrentGUI = it->gui; it->gui->TickObjects(); } m_CurrentGUI.reset(); }
static int ProgressiveLoad() { PROFILE3("progressive load"); wchar_t description[100]; int progress_percent; try { Status ret = LDR_ProgressiveLoad(10e-3, description, ARRAY_SIZE(description), &progress_percent); switch(ret) { // no load active => no-op (skip code below) case INFO::OK: return 0; // current task didn't complete. we only care about this insofar as the // load process is therefore not yet finished. case ERR::TIMED_OUT: break; // just finished loading case INFO::ALL_COMPLETE: g_Game->ReallyStartGame(); wcscpy_s(description, ARRAY_SIZE(description), L"Game is starting.."); // LDR_ProgressiveLoad returns L""; set to valid text to // avoid problems in converting to JSString break; // error! default: WARN_RETURN_STATUS_IF_ERR(ret); // can't do this above due to legit ERR::TIMED_OUT break; } } catch (PSERROR_Game_World_MapLoadFailed& e) { // Map loading failed // Call script function to do the actual work // (delete game data, switch GUI page, show error, etc.) CancelLoad(CStr(e.what()).FromUTF8()); } GUI_DisplayLoadProgress(progress_percent, description); return 0; }
void CNetClientTurnManager::NotifyFinishedUpdate(u32 turn) { bool quick = !TurnNeedsFullHash(turn); std::string hash; { PROFILE3("state hash check"); ENSURE(m_Simulation2.ComputeStateHash(hash, quick)); } NETTURN_LOG((L"NotifyFinishedUpdate(%d, %hs)\n", turn, Hexify(hash).c_str())); m_Replay.Hash(hash, quick); // Send message to the server CSyncCheckMessage msg; msg.m_Turn = turn; msg.m_Hash = hash; m_NetClient.SendMessage(&msg); }
// dispatch all pending events to the various receivers. static void PumpEvents() { PROFILE3("dispatch events"); SDL_Event_ ev; while (SDL_PollEvent(&ev.ev)) { PROFILE2("event"); if (g_GUI) { std::string data = g_GUI->GetScriptInterface().StringifyJSON( ScriptInterface::ToJSVal(g_GUI->GetScriptInterface().GetContext(), ev)); PROFILE2_ATTR("%s", data.c_str()); } in_dispatch_event(&ev); } g_TouchInput.Frame(); }
void HierarchicalPathfinder::Update(Grid<NavcellData>* grid, const Grid<u8>& dirtinessGrid) { PROFILE3("Hierarchical Update"); for (int cj = 0; cj < m_ChunksH; ++cj) { for (int ci = 0; ci < m_ChunksW; ++ci) { if (!IsChunkDirty(ci, cj, dirtinessGrid)) continue; for (const std::pair<std::string, pass_class_t>& passClassMask : m_PassClassMasks) { pass_class_t passClass = passClassMask.second; Chunk& a = m_Chunks[passClass].at(ci + cj*m_ChunksW); a.InitRegions(ci, cj, grid, passClass); } } } // TODO: Also be clever with edges m_Edges.clear(); for (const std::pair<std::string, pass_class_t>& passClassMask : m_PassClassMasks) { pass_class_t passClass = passClassMask.second; EdgesMap& edges = m_Edges[passClass]; for (int cj = 0; cj < m_ChunksH; ++cj) { for (int ci = 0; ci < m_ChunksW; ++ci) { FindEdges(ci, cj, passClass, edges); } } } if (m_DebugOverlay) { PROFILE("debug overlay"); m_DebugOverlayLines.clear(); AddDebugEdges(GetPassabilityClass("default")); } }
// dispatch all pending events to the various receivers. static void PumpEvents() { PROFILE3("dispatch events"); SDL_Event_ ev; while (in_poll_event(&ev)) { PROFILE2("event"); if (g_GUI) { JS::Value tmpVal; ScriptInterface::ToJSVal(g_GUI->GetScriptInterface()->GetContext(), tmpVal, ev); std::string data = g_GUI->GetScriptInterface()->StringifyJSON(tmpVal); PROFILE2_ATTR("%s", data.c_str()); } in_dispatch_event(&ev); } g_TouchInput.Frame(); }
void ParticleRenderer::PrepareForRendering(const CShaderDefines& context) { PROFILE3("prepare particles"); // Can't load the shader in the constructor because it's called before the // renderer initialisation is complete, so load it the first time through here if (!m->shader) { // Only construct the shaders when shaders are supported and enabled; otherwise // RenderParticles will never be called so it's safe to leave the shaders as null if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { m->shader = g_Renderer.GetShaderManager().LoadEffect(str_particle, context, CShaderDefines()); m->shaderSolid = g_Renderer.GetShaderManager().LoadEffect(str_particle_solid, context, CShaderDefines()); } } { PROFILE("update emitters"); for (size_t i = 0; i < m->emitters.size(); ++i) { CParticleEmitter* emitter = m->emitters[i]; emitter->UpdateArrayData(); } } { // Sort back-to-front by distance from camera PROFILE("sort emitters"); CMatrix3D worldToCam; g_Renderer.GetViewCamera().m_Orientation.GetInverse(worldToCam); std::stable_sort(m->emitters.begin(), m->emitters.end(), SortEmitterDistance(worldToCam)); } // TODO: should batch by texture here when possible, maybe }
void CMiniMap::Draw() { PROFILE3("render minimap"); // The terrain isn't actually initialized until the map is loaded, which // happens when the game is started, so abort until then. if(!(GetGUI() && g_Game && g_Game->IsGameStarted())) return; CSimulation2* sim = g_Game->GetSimulation2(); CmpPtr<ICmpRangeManager> cmpRangeManager(*sim, SYSTEM_ENTITY); ENSURE(cmpRangeManager); // Set our globals in case they hadn't been set before m_Camera = g_Game->GetView()->GetCamera(); m_Terrain = g_Game->GetWorld()->GetTerrain(); m_Width = (u32)(m_CachedActualSize.right - m_CachedActualSize.left); m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top); m_MapSize = m_Terrain->GetVerticesPerSide(); m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize); m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f); if(!m_TerrainTexture || g_GameRestarted) CreateTextures(); // only update 2x / second // (note: since units only move a few pixels per second on the minimap, // we can get away with infrequent updates; this is slow) static double last_time; const double cur_time = timer_Time(); if(cur_time - last_time > 0.5) { last_time = cur_time; if(m_TerrainDirty) RebuildTerrainTexture(); } glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); CMatrix3D matrix = GetDefaultGuiMatrix(); glLoadMatrixf(&matrix._11); // Disable depth updates to prevent apparent z-fighting-related issues // with some drivers causing units to get drawn behind the texture glDepthMask(0); const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; const float z = GetBufferedZ(); const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize; const float angle = GetAngle(); // Draw the main textured quad g_Renderer.BindTexture(0, m_TerrainTexture); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); DrawTexture(texCoordMax, angle, x, y, x2, y2, z); // Draw territory boundaries CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture(); territoryTexture.BindTexture(0); glEnable(GL_BLEND); glMatrixMode(GL_TEXTURE); glLoadMatrixf(territoryTexture.GetMinimapTextureMatrix()); glMatrixMode(GL_MODELVIEW); DrawTexture(1.0f, angle, x, y, x2, y2, z); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDisable(GL_BLEND); // Draw the LOS quad in black, using alpha values from the LOS texture CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); losTexture.BindTexture(0); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor3f(0.0f, 0.0f, 0.0f); glMatrixMode(GL_TEXTURE); glLoadMatrixf(losTexture.GetMinimapTextureMatrix()); glMatrixMode(GL_MODELVIEW); DrawTexture(1.0f, angle, x, y, x2, y2, z); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDisable(GL_BLEND); // Set up the matrix for drawing points and lines glPushMatrix(); glTranslatef(x, y, z); // Rotate around the center of the map glTranslatef((x2-x)/2.f, (y2-y)/2.f, 0.f); // Scale square maps to fit in circular minimap area float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f); glScalef(unitScale, unitScale, 1.f); glRotatef(angle * 180.f/M_PI, 0.f, 0.f, 1.f); glTranslatef(-(x2-x)/2.f, -(y2-y)/2.f, 0.f); PROFILE_START("minimap units"); // Don't enable GL_POINT_SMOOTH because it's far too slow // (~70msec/frame on a GF4 rendering a thousand points) glPointSize(3.f); float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap); std::vector<MinimapUnitVertex> vertexArray; vertexArray.reserve(ents.size()); for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) { MinimapUnitVertex v; ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second); entity_pos_t posX, posZ; if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ)) { ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID()); if (vis != ICmpRangeManager::VIS_HIDDEN) { v.a = 255; v.x = posX.ToFloat()*sx; v.y = -posZ.ToFloat()*sy; vertexArray.push_back(v); } } } if (!vertexArray.empty()) { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(2, GL_FLOAT, sizeof(MinimapUnitVertex), &vertexArray[0].x); glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(MinimapUnitVertex), &vertexArray[0].r); glDrawArrays(GL_POINTS, 0, (GLsizei)vertexArray.size()); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); } PROFILE_END("minimap units"); DrawViewRect(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); // Reset everything back to normal glPointSize(1.0f); glEnable(GL_TEXTURE_2D); glDepthMask(1); }
bool FractureElasticityVoigt::evalInt (LocalIntegral& elmInt, const FiniteElement& fe, const Vec3& X) const { PROFILE3("FractureEl::evalInt"); ElmMats& elMat = static_cast<ElmMats&>(elmInt); size_t nstrc = (nsd+1)*nsd/2; Matrix Bmat, dSdE(nstrc,nstrc); SymmTensor eps(nsd), sigma(nsd); bool lHaveStrains = false; if (eKm || eKg || iS || m_mode == SIM::RECOVERY) { // Evaluate the symmetric strain tensor if displacements are available if (!this->kinematics(elMat.vec.front(),fe.N,fe.dNdX,0.0,Bmat,eps,eps)) return false; else if (!eps.isZero(1.0e-16)) { lHaveStrains = true; // Scale the shear strain components by 0.5 to convert from engineering // strains gamma_ij = eps_ij + eps_ji to the tensor components eps_ij // which are needed for consistent calculation of principal directions for (unsigned short int i = 1; i <= nsd; i++) for (unsigned short int j = i+1; j <= nsd; j++) eps(i,j) *= 0.5; } #if INT_DEBUG > 3 std::cout <<"\nFractureElasticity::evalInt(X = "<< X <<")\nBmat ="<< Bmat; #endif // Evaluate the material parameters at this point double lambda, mu; if (!material->evaluate(lambda,mu,fe,X)) return false; // Evaluate the stress degradation function double Gc = this->getStressDegradation(fe.N,elmInt.vec); #if INT_DEBUG > 3 std::cout <<"lambda = "<< lambda <<" mu = "<< mu <<" G(c) = "<< Gc <<"\n"; if (lHaveStrains) std::cout <<"eps =\n"<< eps; #endif // Evaluate the stress state at this point if (!this->evalStress(lambda,mu,Gc,eps,&myPhi[fe.iGP],&sigma, eKm ? &dSdE : nullptr)) return false; } if (eKm) { #if INT_DEBUG > 3 std::cout <<"dSdE ="<< dSdE; #endif // Integrate the material stiffness matrix Matrix CB; CB.multiply(dSdE,Bmat).multiply(fe.detJxW); // CB = dSdE*B*|J|*w elMat.A[eKm-1].multiply(Bmat,CB,true,false,true); // EK += B^T * CB } if (eKg && lHaveStrains) // Integrate the geometric stiffness matrix this->formKG(elMat.A[eKg-1],fe.N,fe.dNdX,0.0,sigma,fe.detJxW); if (eM) // Integrate the mass matrix this->formMassMatrix(elMat.A[eM-1],fe.N,X,fe.detJxW); if (iS && lHaveStrains) { // Integrate the internal forces sigma *= -fe.detJxW; if (!Bmat.multiply(sigma,elMat.b[iS-1],true,true)) // ES -= B^T*sigma return false; } if (eS) { // Integrate the load vector due to gravitation and other body forces this->formBodyForce(elMat.b[eS-1],fe.N,X,fe.detJxW); // Integrate the load vector due to internal crack pressure this->formCrackForce(elMat.b[eS-1],elMat.vec,fe,X); } return true; }
// TODO: render the minimap in a framebuffer and just draw the frambuffer texture // most of the time, updating the framebuffer twice a frame. // Here it updates as ping-pong either texture or vertex array each sec to lower gpu stalling // (those operations cause a gpu sync, which slows down the way gpu works) void CMiniMap::Draw() { PROFILE3("render minimap"); // The terrain isn't actually initialized until the map is loaded, which // happens when the game is started, so abort until then. if(!(GetGUI() && g_Game && g_Game->IsGameStarted())) return; CSimulation2* sim = g_Game->GetSimulation2(); CmpPtr<ICmpRangeManager> cmpRangeManager(*sim, SYSTEM_ENTITY); ENSURE(cmpRangeManager); // Set our globals in case they hadn't been set before m_Camera = g_Game->GetView()->GetCamera(); m_Terrain = g_Game->GetWorld()->GetTerrain(); m_Width = (u32)(m_CachedActualSize.right - m_CachedActualSize.left); m_Height = (u32)(m_CachedActualSize.bottom - m_CachedActualSize.top); m_MapSize = m_Terrain->GetVerticesPerSide(); m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize); m_MapScale = (cmpRangeManager->GetLosCircular() ? 1.f : 1.414f); if(!m_TerrainTexture || g_GameRestarted) CreateTextures(); // only update 2x / second // (note: since units only move a few pixels per second on the minimap, // we can get away with infrequent updates; this is slow) // TODO: store frequency in a config file? static double last_time; const double cur_time = timer_Time(); const bool doUpdate = cur_time - last_time > 0.5; if(doUpdate) { last_time = cur_time; if(m_TerrainDirty) RebuildTerrainTexture(); } glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); CMatrix3D matrix = GetDefaultGuiMatrix(); glLoadMatrixf(&matrix._11); // Disable depth updates to prevent apparent z-fighting-related issues // with some drivers causing units to get drawn behind the texture glDepthMask(0); CShaderProgramPtr shader; CShaderTechniquePtr tech; if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { CShaderDefines defines; defines.Add(str_MINIMAP_BASE, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); } const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; const float z = GetBufferedZ(); const float texCoordMax = (float)(m_MapSize - 1) / (float)m_TextureSize; const float angle = GetAngle(); // Draw the main textured quad if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture(str_baseTex, m_TerrainTexture); else g_Renderer.BindTexture(0, m_TerrainTexture); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); DrawTexture(shader, texCoordMax, angle, x, y, x2, y2, z); // Draw territory boundaries CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) shader->BindTexture(str_baseTex, territoryTexture.GetTexture()); else territoryTexture.BindTexture(0); glEnable(GL_BLEND); glMatrixMode(GL_TEXTURE); glLoadMatrixf(territoryTexture.GetMinimapTextureMatrix()); glMatrixMode(GL_MODELVIEW); DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDisable(GL_BLEND); // Draw the LOS quad in black, using alpha values from the LOS texture CLOSTexture& losTexture = g_Game->GetView()->GetLOSTexture(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); CShaderDefines defines; defines.Add(str_MINIMAP_LOS, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); shader->BindTexture(str_baseTex, losTexture.GetTexture()); } else { losTexture.BindTexture(0); } glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor3f(0.0f, 0.0f, 0.0f); glMatrixMode(GL_TEXTURE); glLoadMatrixf(losTexture.GetMinimapTextureMatrix()); glMatrixMode(GL_MODELVIEW); DrawTexture(shader, 1.0f, angle, x, y, x2, y2, z); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glDisable(GL_BLEND); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); CShaderDefines defines; defines.Add(str_MINIMAP_POINT, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); } // Set up the matrix for drawing points and lines glPushMatrix(); glTranslatef(x, y, z); // Rotate around the center of the map glTranslatef((x2-x)/2.f, (y2-y)/2.f, 0.f); // Scale square maps to fit in circular minimap area float unitScale = (cmpRangeManager->GetLosCircular() ? 1.f : m_MapScale/2.f); glScalef(unitScale, unitScale, 1.f); glRotatef(angle * 180.f/M_PI, 0.f, 0.f, 1.f); glTranslatef(-(x2-x)/2.f, -(y2-y)/2.f, 0.f); PROFILE_START("minimap units"); const float sx = (float)m_Width / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); const float sy = (float)m_Height / ((m_MapSize - 1) * TERRAIN_TILE_SIZE); CSimulation2::InterfaceList ents = sim->GetEntitiesWithInterface(IID_Minimap); if (doUpdate) { VertexArrayIterator<float[2]> attrPos = m_AttributePos.GetIterator<float[2]>(); VertexArrayIterator<u8[4]> attrColor = m_AttributeColor.GetIterator<u8[4]>(); m_EntitiesDrawn = 0; MinimapUnitVertex v; std::vector<MinimapUnitVertex> pingingVertices; pingingVertices.reserve(MAX_ENTITIES_DRAWN/2); const double time = timer_Time(); if (time > m_NextBlinkTime) { m_BlinkState = !m_BlinkState; m_NextBlinkTime = time + m_HalfBlinkDuration; } entity_pos_t posX, posZ; for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it) { ICmpMinimap* cmpMinimap = static_cast<ICmpMinimap*>(it->second); if (cmpMinimap->GetRenderData(v.r, v.g, v.b, posX, posZ)) { ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(it->first, g_Game->GetPlayerID()); if (vis != ICmpRangeManager::VIS_HIDDEN) { v.a = 255; v.x = posX.ToFloat()*sx; v.y = -posZ.ToFloat()*sy; // Check minimap pinging to indicate something if (m_BlinkState && cmpMinimap->CheckPing(time, m_PingDuration)) { v.r = 255; // ping color is white v.g = 255; v.b = 255; pingingVertices.push_back(v); } else { addVertex(v, attrColor, attrPos); ++m_EntitiesDrawn; } } } } // Add the pinged vertices at the end, so they are drawn on top for (size_t v = 0; v < pingingVertices.size(); ++v) { addVertex(pingingVertices[v], attrColor, attrPos); ++m_EntitiesDrawn; } ENSURE(m_EntitiesDrawn < MAX_ENTITIES_DRAWN); m_VertexArray.Upload(); } if (m_EntitiesDrawn > 0) { // Don't enable GL_POINT_SMOOTH because it's far too slow // (~70msec/frame on a GF4 rendering a thousand points) glPointSize(3.f); u8* indexBase = m_IndexArray.Bind(); u8* base = m_VertexArray.Bind(); const GLsizei stride = (GLsizei)m_VertexArray.GetStride(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { shader->VertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset); shader->ColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); shader->AssertPointersBound(); } else { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glDisable(GL_TEXTURE_2D); glVertexPointer(2, GL_FLOAT, stride, base + m_AttributePos.offset); glColorPointer(4, GL_UNSIGNED_BYTE, stride, base + m_AttributeColor.offset); } if (!g_Renderer.m_SkipSubmit) { glDrawElements(GL_POINTS, (GLsizei)(m_EntitiesDrawn), GL_UNSIGNED_SHORT, indexBase); } g_Renderer.GetStats().m_DrawCalls++; CVertexBuffer::Unbind(); } PROFILE_END("minimap units"); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); CShaderDefines defines; defines.Add(str_MINIMAP_LINE, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); shader = tech->GetShader(); } else { glEnable(GL_TEXTURE_2D); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); } DrawViewRect(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); if (g_Renderer.GetRenderPath() == CRenderer::RP_SHADER) { tech->EndPass(); } // Reset everything back to normal glPointSize(1.0f); glEnable(GL_TEXTURE_2D); glDepthMask(1); }
void Render() { PROFILE3("render"); if (g_SoundManager) g_SoundManager->IdleTask(); ogl_WarnIfError(); g_Profiler2.RecordGPUFrameStart(); ogl_WarnIfError(); // prepare before starting the renderer frame if (g_Game && g_Game->IsGameStarted()) g_Game->GetView()->BeginFrame(); if (g_Game) g_Renderer.SetSimulation(g_Game->GetSimulation2()); // start new frame g_Renderer.BeginFrame(); ogl_WarnIfError(); if (g_Game && g_Game->IsGameStarted()) g_Game->GetView()->Render(); ogl_WarnIfError(); g_Renderer.RenderTextOverlays(); if (g_DoRenderGui) g_GUI->Draw(); ogl_WarnIfError(); // If we're in Atlas game view, render special overlays (e.g. editor bandbox) if (g_AtlasGameLoop && g_AtlasGameLoop->view) { g_AtlasGameLoop->view->DrawOverlays(); ogl_WarnIfError(); } // Text: glDisable(GL_DEPTH_TEST); g_Console->Render(); ogl_WarnIfError(); if (g_DoRenderLogger) g_Logger->Render(); ogl_WarnIfError(); // Profile information g_ProfileViewer.RenderProfile(); ogl_WarnIfError(); // Draw the cursor (or set the Windows cursor, on Windows) if (g_DoRenderCursor) { PROFILE3_GPU("cursor"); CStrW cursorName = g_CursorName; if (cursorName.empty()) { cursor_draw(g_VFS, NULL, g_mouse_x, g_yres-g_mouse_y, false); } else { bool forceGL = false; CFG_GET_VAL("nohwcursor", forceGL); #if CONFIG2_GLES #warning TODO: implement cursors for GLES #else // set up transform for GL cursor glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); CMatrix3D transform; transform.SetOrtho(0.f, (float)g_xres, 0.f, (float)g_yres, -1.f, 1000.f); glLoadMatrixf(&transform._11); #endif #if OS_ANDROID #warning TODO: cursors for Android #else if (cursor_draw(g_VFS, cursorName.c_str(), g_mouse_x, g_yres-g_mouse_y, forceGL) < 0) LOGWARNING("Failed to draw cursor '%s'", utf8_from_wstring(cursorName)); #endif #if CONFIG2_GLES #warning TODO: implement cursors for GLES #else // restore transform glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); #endif } } glEnable(GL_DEPTH_TEST); g_Renderer.EndFrame(); PROFILE2_ATTR("draw calls: %d", (int)g_Renderer.GetStats().m_DrawCalls); PROFILE2_ATTR("terrain tris: %d", (int)g_Renderer.GetStats().m_TerrainTris); PROFILE2_ATTR("water tris: %d", (int)g_Renderer.GetStats().m_WaterTris); PROFILE2_ATTR("model tris: %d", (int)g_Renderer.GetStats().m_ModelTris); PROFILE2_ATTR("overlay tris: %d", (int)g_Renderer.GetStats().m_OverlayTris); PROFILE2_ATTR("blend splats: %d", (int)g_Renderer.GetStats().m_BlendSplats); PROFILE2_ATTR("particles: %d", (int)g_Renderer.GetStats().m_Particles); ogl_WarnIfError(); g_Profiler2.RecordGPUFrameEnd(); ogl_WarnIfError(); }
bool FractureElasticityVoigt::evalStress (double lambda, double mu, double Gc, const SymmTensor& epsil, double* Phi, SymmTensor* sigma, Matrix* dSdE, bool postProc, bool printElm) const { PROFILE3("FractureEl::evalStress"); unsigned short int a = 0, b = 0; // Define a Lambda-function to set up the isotropic constitutive matrix auto&& setIsotropic = [this,a,b](Matrix& C, double lambda, double mu) mutable { for (a = 1; a <= C.rows(); a++) if (a > nsd) C(a,a) = mu; else { C(a,a) = 2.0*mu; for (b = 1; b <= nsd; b++) C(a,b) += lambda; } }; // Define some material constants double trEps = epsil.trace(); double C0 = trEps >= -epsZ ? Gc*lambda : lambda; double Cp = Gc*mu; if (trEps >= -epsZ && trEps <= epsZ) { // No strains, stress free configuration Phi[0] = 0.0; if (postProc) Phi[1] = Phi[2] = Phi[3] = 0.0; if (sigma) *sigma = 0.0; if (dSdE) setIsotropic(*dSdE,C0,Cp); return true; } // Calculate principal strains and the associated directions Vec3 eps; std::vector<SymmTensor> M(nsd,SymmTensor(nsd)); { PROFILE4("Tensor::principal"); if (!epsil.principal(eps,M.data())) return false; } // Split the strain tensor into positive and negative parts SymmTensor ePos(nsd), eNeg(nsd); for (a = 0; a < nsd; a++) if (eps[a] > 0.0) ePos += eps[a]*M[a]; else if (eps[a] < 0.0) eNeg += eps[a]*M[a]; if (sigma) { // Evaluate the stress tensor *sigma = C0*trEps; *sigma += 2.0*mu*(Gc*ePos + eNeg); } // Evaluate the tensile energy Phi[0] = mu*(ePos*ePos).trace(); if (trEps > 0.0) Phi[0] += 0.5*lambda*trEps*trEps; if (postProc) { // Evaluate the compressive energy Phi[1] = mu*(eNeg*eNeg).trace(); if (trEps < 0.0) Phi[1] += 0.5*lambda*trEps*trEps; // Evaluate the total strain energy Phi[2] = Gc*Phi[0] + Phi[1]; // Evaluate the bulk energy Phi[3] = Gc*(Phi[0] + Phi[1]); } else if (sigmaC > 0.0) // Evaluate the crack driving function Phi[0] = this->MieheCrit56(eps,lambda,mu); #if INT_DEBUG > 4 std::cout <<"eps_p = "<< eps <<"\n"; for (a = 0; a < nsd; a++) std::cout <<"M("<< 1+a <<") =\n"<< M[a]; std::cout <<"ePos =\n"<< ePos <<"eNeg =\n"<< eNeg; if (sigma) std::cout <<"sigma =\n"<< *sigma; std::cout <<"Phi = "<< Phi[0]; if (postProc) std::cout <<" "<< Phi[1] <<" "<< Phi[2] <<" "<< Phi[3]; std::cout << std::endl; #else if (printElm) { std::cout <<"g(c) = "<< Gc <<"\nepsilon =\n"<< epsil <<"eps_p = "<< eps <<"\nePos =\n"<< ePos <<"eNeg =\n"<< eNeg; if (sigma) std::cout <<"sigma =\n"<< *sigma; std::cout <<"Phi = "<< Phi[0]; if (postProc) std::cout <<" "<< Phi[1] <<" "<< Phi[2] <<" "<< Phi[3]; std::cout << std::endl; } #endif if (!dSdE) return true; else if (eps[0] == eps[nsd-1]) { // Hydrostatic pressure setIsotropic(*dSdE, C0, eps.x > 0.0 ? Cp : mu); return true; } typedef unsigned short int s_ind; // Convenience type definition // Define a Lambda-function to calculate (lower triangle of) the matrix Qa auto&& getQ = [this](Matrix& Q, const SymmTensor& Ma, double C) { if (C == 0.0) return; auto&& Mult = [Ma](s_ind i, s_ind j, s_ind k, s_ind l) { return Ma(i,j)*Ma(k,l); }; s_ind i, j, k, l, is, js; // Normal stresses and strains for (i = 1; i <= nsd; i++) for (j = 1; j <= i; j++) Q(i,j) += C*Mult(i,i,j,j); is = nsd+1; for (i = 1; i < nsd; i++) for (j = i+1; j <= nsd; j++, is++) { // Shear stress coupled to normal strain for (k = 1; k <= nsd; k++) Q(is,k) += C*Mult(i,j,k,k); // Shear stress coupled to shear strain js = nsd+1; for (k = 1; k < nsd; k++) for (l = k+1; js <= is; l++, js++) Q(is,js) += C*Mult(i,j,k,l); } }; // Define a Lambda-function to calculate (lower triangle of) the matrix Gab auto&& getG = [this](Matrix& G, const SymmTensor& Ma, const SymmTensor& Mb, double C) { if (C == 0.0) return; auto&& Mult = [Ma,Mb](s_ind i, s_ind j, s_ind k, s_ind l) { return Ma(i,k)*Mb(j,l) + Ma(i,l)*Mb(j,k) + Mb(i,k)*Ma(j,l) + Mb(i,l)*Ma(j,k); }; s_ind i, j, k, l, is, js; // Normal stresses and strains for (i = 1; i <= nsd; i++) for (j = 1; j <= i; j++) G(i,j) += C*Mult(i,i,j,j); is = nsd+1; for (i = 1; i < nsd; i++) for (j = i+1; j <= nsd; j++, is++) { // Shear stress coupled to normal strain for (k = 1; k <= nsd; k++) G(is,k) += C*Mult(i,j,k,k); // Shear stress coupled to shear strain js = nsd+1; for (k = 1; k < nsd; k++) for (l = k+1; js <= is; l++, js++) G(is,js) += C*Mult(i,j,k,l); } }; // Evaluate the stress tangent assuming Voigt notation and symmetry for (a = 1; a <= nsd; a++) for (b = 1; b <= a; b++) (*dSdE)(a,b) = C0; for (a = 0; a < nsd; a++) { double C1 = eps[a] >= 0.0 ? Cp : mu; getQ(*dSdE, M[a], 2.0*C1); if (eps[a] != 0.0) for (b = 0; b < nsd; b++) if (a != b && eps[a] != eps[b]) getG(*dSdE,M[a],M[b],C1/(1.0-eps[b]/eps[a])); } // Account for symmetry for (b = 2; b <= dSdE->rows(); b++) for (a = 1; a < b; a++) (*dSdE)(a,b) = (*dSdE)(b,a); return true; }
virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) { switch (msg.GetType()) { case MT_Interpolate: { PROFILE3("Position::Interpolate"); const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg); float rotY = m_RotY.ToFloat(); if (rotY != m_InterpolatedRotY) { float delta = rotY - m_InterpolatedRotY; // Wrap delta to -M_PI..M_PI delta = fmodf(delta + (float)M_PI, 2*(float)M_PI); // range -2PI..2PI if (delta < 0) delta += 2*(float)M_PI; // range 0..2PI delta -= (float)M_PI; // range -M_PI..M_PI // Clamp to max rate float deltaClamped = clamp(delta, -m_RotYSpeed*msgData.deltaSimTime, +m_RotYSpeed*msgData.deltaSimTime); // Calculate new orientation, in a peculiar way in order to make sure the // result gets close to m_orientation (rather than being n*2*M_PI out) m_InterpolatedRotY = rotY + deltaClamped - delta; // update the visual XZ rotation if (m_InWorld) { m_LastInterpolatedRotX = m_InterpolatedRotX; m_LastInterpolatedRotZ = m_InterpolatedRotZ; UpdateXZRotation(); } UpdateMessageSubscriptions(); } break; } case MT_TurnStart: { m_LastInterpolatedRotX = m_InterpolatedRotX; m_LastInterpolatedRotZ = m_InterpolatedRotZ; if (m_InWorld && (m_LastX != m_X || m_LastZ != m_Z)) UpdateXZRotation(); // Store the positions from the turn before m_PrevX = m_LastX; m_PrevZ = m_LastZ; m_LastX = m_X; m_LastZ = m_Z; m_LastYDifference = entity_pos_t::Zero(); // warn when a position change also causes a territory change under the entity if (m_InWorld) { player_id_t newTerritory; CmpPtr<ICmpTerritoryManager> cmpTerritoryManager(GetSystemEntity()); if (cmpTerritoryManager) newTerritory = cmpTerritoryManager->GetOwner(m_X, m_Z); else newTerritory = INVALID_PLAYER; if (newTerritory != m_Territory) { m_Territory = newTerritory; CMessageTerritoryPositionChanged msg(GetEntityId(), m_Territory); GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); } } else if (m_Territory != INVALID_PLAYER) { CMessageTerritoryPositionChanged msg(GetEntityId(), m_Territory); GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); } break; } case MT_TerrainChanged: case MT_WaterChanged: { AdvertiseInterpolatedPositionChanges(); break; } case MT_Deserialized: { Deserialized(); break; } } }
/////////////////////////////////////////////////////////// // This callback is part of the Scene interface // Submit all objects visible in the given frustum void CGameView::EnumerateObjects(const CFrustum& frustum, SceneCollector* c) { { PROFILE3("submit terrain"); CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain(); const ssize_t patchesPerSide = pTerrain->GetPatchesPerSide(); // find out which patches will be drawn for (ssize_t j=0; j<patchesPerSide; j++) { for (ssize_t i=0; i<patchesPerSide; i++) { CPatch* patch=pTerrain->GetPatch(i,j); // can't fail // If the patch is underwater, calculate a bounding box that also contains the water plane CBoundingBoxAligned bounds = patch->GetWorldBounds(); float waterHeight = g_Renderer.GetWaterManager()->m_WaterHeight + 0.001f; if(bounds[1].Y < waterHeight) { bounds[1].Y = waterHeight; } if (!m->Culling || frustum.IsBoxVisible (CVector3D(0,0,0), bounds)) { //c->Submit(patch); // set the renderstate for this patch patch->setDrawState(true); // set the renderstate for the neighbors CPatch *nPatch; nPatch = pTerrain->GetPatch(i-1,j-1); if(nPatch) nPatch->setDrawState(true); nPatch = pTerrain->GetPatch(i,j-1); if(nPatch) nPatch->setDrawState(true); nPatch = pTerrain->GetPatch(i+1,j-1); if(nPatch) nPatch->setDrawState(true); nPatch = pTerrain->GetPatch(i-1,j); if(nPatch) nPatch->setDrawState(true); nPatch = pTerrain->GetPatch(i+1,j); if(nPatch) nPatch->setDrawState(true); nPatch = pTerrain->GetPatch(i-1,j+1); if(nPatch) nPatch->setDrawState(true); nPatch = pTerrain->GetPatch(i,j+1); if(nPatch) nPatch->setDrawState(true); nPatch = pTerrain->GetPatch(i+1,j+1); if(nPatch) nPatch->setDrawState(true); } } } // draw the patches for (ssize_t j=0; j<patchesPerSide; j++) { for (ssize_t i=0; i<patchesPerSide; i++) { CPatch* patch=pTerrain->GetPatch(i,j); // can't fail if(patch->getDrawState() == true) { c->Submit(patch); patch->setDrawState(false); } } } } m->Game->GetSimulation2()->RenderSubmit(*c, frustum, m->Culling); }