The source code for the physics interaction (Example 11-54 and Example 11-55) and update (Example 11-56) are presented here for you to study. You can download the complete source code from http://www.threadingbuildingblocks.org/book. Look for errata and notes at this web site as well.
For more in-depth reading on this topic, Intel engineers wrote several articles covering the topic of threading games, which you can download at the web site as well.
Example 11-54. Physics interaction code: InteractTask
class InteractTask : public tbb::task { SceneNode* m_node; size_t m_i; D3DBlackHole* m_bh; float m_universeRadius; size_t m_DummyCount; public: // Interact all stars in task InteractTask(SceneNode* node, size_t i, D3DBlackHole* bh, float universeRadius, size_t DummyCount) : m_node(node), m_i(i), m_bh(bh), m_universeRadius(universeRadius), m_DummyCount(DummyCount) {} tbb::task* execute() { if (m_node->getChildCount()) { // High in scene graph, Create parallel domain tasks for the children size_t i; tbb::task_list list; tbb::task& c = *new(allocate_continuation()) tbb::empty_task(); for (i = 0; i < m_node->getChildCount(); ++i) { list.push_back(*new(c.allocate_child()) InteractTask(m_node->getChild(i), i, m_bh, m_universeRadius, m_DummyCount)); } c.set_ref_count((int)i); c.spawn(list); } if (m_node->getUserID() > 0) { // Low-level object tasks, interact each star serially D3DStar* pStar = (D3DStar*)m_node; float elapsedTime = g_elapsedTime - pStar->getTimeStamp(); // TODO: check accuracy of interaction and decide: // 1. Skip interaction for this short period of time // 2. Split this long period of time to parts and // interact for each pStar->setTimeStamp(g_elapsedTime); pStar->setElapsedTime(elapsedTime); if (!pStar->isAlive() && !pStar->isDying()) { pStar->Reset(m_bh, m_universeRadius); pStar->NextState(); } else { // apply attraction to black hole pStar->Interact(elapsedTime, m_bh, m_universeRadius, m_DummyCount); // apply attraction to every other star SceneNode* node = m_node->getParent(); for (size_t j = (m_i + 1); j < node->getChildCount(); ++j) { pStar->Interact(elapsedTime, (D3DStar*)node->getChild(j), m_DummyCount); } } } return NULL; } };
Example 11-55. Physics interaction code: UpdateTask
class UpdateTask : public tbb::task { SceneNode* m_node; public: // Update all star positions based on // interactions in this frame UpdateTask(SceneNode* node) : m_node(node) {} tbb::task* execute() { if (m_node->getChildCount()) { // High in scene graph, Create parallel // domain tasks for the children size_t i; tbb::task_list list; tbb::task& c = *new(allocate_continuation()) tbb::empty_task(); for (i = 0; i < m_node->getChildCount(); ++i) { list.push_back(*new(c.allocate_child()) UpdateTask(m_node->getChild(i))); } c.set_ref_count((int)i); c.spawn(list); } if (m_node->getUserID() > 0) { // Low-level object tasks, update each star serially D3DStar* pStar = (D3DStar*)m_node; // Matrix transformation pStar->Update(pStar->getElapsedTime()); } return NULL; } };
Example 11-56. Update Code
void World::Update(void) { static __itt_event ev = __itt_event_create("update", 6); // Lock out changing k-d tree until interactions // and updates are done. Lock(); __itt_event_start(ev); tbb::tick_count t0 = tbb::tick_count::now(); if (isParallel() && !isChanged()) { InteractTask& task = *new(tbb::task::allocate_root()) InteractTask(m_bh, 0, m_bh, m_universeRadius, m_DummyCount); tbb::task::spawn_root_and_wait(task); } else { // Sequential equivalent to threaded version in InteractTask for (size_t i = 0; i < m_bh->getChildCount(); ++i) { GroupNode* grp = (GroupNode*)m_bh->getChild(i); for (size_t j = 0; j < grp->getChildCount(); ++j) { D3DStar* pStar = (D3DStar*)grp->getChild(j); float elapsedTime = g_elapsedTime - pStar->getTimeStamp(); pStar->setTimeStamp(g_elapsedTime); pStar->setElapsedTime(elapsedTime); if (!pStar->isAlive() && !pStar->isDying()) { pStar->Reset(m_bh, m_universeRadius); pStar->NextState(); continue; } // apply attraction to black hole pStar->Interact(elapsedTime, m_bh, m_universeRadius, m_DummyCount); // apply attraction to every other star in group for (size_t k = (j + 1); k < grp->getChildCount(); ++k) { pStar->Interact(elapsedTime, (D3DStar*)grp->getChild(k), m_DummyCount); } } } } tbb::tick_count t1 = tbb::tick_count::now(); m_UpdateTime = (t1-t0).seconds(); __itt_event_end(ev); t0 = tbb::tick_count::now(); if (isParallel() && !isChanged()) { UpdateTask& task = *new(tbb::task::allocate_root()) UpdateTask(m_bh); tbb::task::spawn_root_and_wait(task); } else { // Sequential equivalent to threaded version in UpdateTask for (size_t i = 0; i < m_bh->getChildCount(); ++i) { GroupNode* grp = (GroupNode*)m_bh->getChild(i); for (size_t j = 0; j < grp->getChildCount(); ++j) { D3DStar* pStar = (D3DStar*)grp->getChild(j); // Matrix transformation pStar->Update(pStar->getElapsedTime()); } } } float elapsedTime = g_elapsedTime - m_bh->getTimeStamp(); m_bh->setTimeStamp(g_elapsedTime); m_bh->setElapsedTime(elapsedTime); // update Black Hole m_bh->Update(elapsedTime); t1 = tbb::tick_count::now(); m_TransformTime = (t1-t0).seconds(); // Balance groups here (every 10 frame) static int balance_counter = 0; if (!(balance_counter % 10)) { for (size_t i = 0; i < m_bh->getChildCount(); ++i) { GroupNode* grp = (GroupNode*)m_bh->getChild(i); for (size_t j = 0; j < grp->getChildCount(); ++j) { D3DStar* pStar = (D3DStar*)grp->getChild(j); if (pStar->isAlive() && !grp->isInGroup(pStar->getLocation(0), pStar->getLocation(1), pStar->getLocation(2))) { for (size_t k = 0; k < m_bh->getChildCount(); ++k) { GroupNode* ngrp = (GroupNode*)m_bh->getChild(k); if (ngrp != grp && ngrp->isInGroup(pStar->getLocation(0), pStar->getLocation(1), pStar->getLocation(2))) { grp->removeChild(pStar); ngrp->addChild(pStar); } } } } } } Unlock(); // Ok, now permit changing the k-d tree. }
18.117.103.5