void GasCellPort::cellDraw( const coordInt2d_t& coord ) const { // Создаём образ // Содержимое ячейки представим в виде меша const int i = helper::ic( coord.get<0>(), coord.get<1>(), N, M ); assert( (i != -1) && "Получена координата за пределами матрицы порта." ); const GasFD c = content[i]; if (c.uid == 0) { // Вакуум не показываем return; } #if 0 // - Медленно. Переписано через биллборды. /* const std::string name = "smoke-pressure-" + Ogre::StringConverter::toString( (int)c.pressure ); */ const std::string meshName = "sphere.mesh"; /* - @todo Так ли каждый раз нужна новая сущность? const std::string entityName = meshName + ".entity"; const bool has = sm->hasEntity( entityName ); Ogre::Entity* image = has ? sm->getEntity( entityName ) : sm->createEntity( entityName, meshName ); */ Ogre::Entity* image = sm->createEntity( meshName ); auto childScene = sn->createChildSceneNode(); childScene->attachObject( image ); // Координаты образа кратны масштабу childScene->setPosition( (float)coord.get<0>() * scale, 0.0f, (float)coord.get<1>() * scale ); // Образ заполняет ячейку целиком //const Ogre::Vector3 fillScale( scale / image->getBoundingRadius() ); //childScene->setScale( fillScale ); #endif // Работаем через биллборды // @source http://89.151.96.106/forums/viewtopic.php?f=10&t=60455 const float S = scale * visualScale; // Готовим биллборды при первом обращении к ним // @todo Визаулизировать в зависимости от характеристики ячейки и соседей. std::string bsName = "GasCellPort-bs"; Ogre::BillboardSet* bs = nullptr; if ( sm->hasBillboardSet( bsName ) ) { bs = sm->getBillboardSet( bsName ); } else { // Дым - один образ на всю ячейку bs = sm->createBillboardSet( bsName, count() ); bs->setAutoextend( false ); const std::string prefixMaterial = "smokeport2d/smoke-"; const std::string nameMaterial = prefixMaterial + "0"; bs->setMaterialName( nameMaterial ); bs->setBillboardType( Ogre::BBT_PERPENDICULAR_COMMON ); bs->setCommonUpVector( Ogre::Vector3::UNIT_Z ); bs->setCommonDirection( -Ogre::Vector3::UNIT_Y ); bs->setBillboardsInWorldSpace( true ); bs->setBillboardOrigin( Ogre::BBO_CENTER ); bs->setDefaultDimensions( S, S ); sn->attachObject( bs ); } // Позиционируем биллборд Ogre::Billboard* b = bs->createBillboard( (float)coord.get<0>() * S, 0.0f, (float)coord.get<1>() * S ); //b->setRotation( Ogre::Degree( (float)rand() ) ); }
void CellDrawActor< C >::allDraw( const AllDrawMessage< C >& m ) { // Рисуем только если ещё не было нарисовано // или по просьбе "обновлять постоянно" const std::string sceneName = "CellDrawActor::allDraw::Scene"; const std::string bsName = "CellDrawActor::allDraw::BillboardSet"; // @test /* try { m.sm->getRootSceneNode()->removeAndDestroyChild( sceneName ); } catch ( ... ) { } try { m.sm->destroyBillboardSet( bsName ); } catch ( ... ) { } */ if ( m.update || !m.sm->hasSceneNode( sceneName ) ) { // Каждому образу - свой холст (общая сцена) auto scene = m.sm->hasSceneNode( sceneName ) ? m.sm->getSceneNode( sceneName ) : m.sm->getRootSceneNode()->createChildSceneNode( sceneName ); // Определяем общее кол-во элементов const size_t NM = m.N * m.M; // Готовим биллборды // Обращаются за отрисовкой первый раз? const bool virgin = m.sm->hasBillboardSet( bsName ); Ogre::BillboardSet* bs = nullptr; if ( virgin ) { bs = m.sm->getBillboardSet( bsName ); } else { // Один образ для всех ячеек // @todo Расширить кол-во образов. bs = m.sm->createBillboardSet( bsName, NM ); bs->setAutoextend( true ); const std::string nameMaterial = m.prefixMaterial + "0"; bs->setMaterialName( nameMaterial ); bs->setBillboardType( Ogre::BBT_PERPENDICULAR_COMMON ); bs->setCommonUpVector( Ogre::Vector3::UNIT_Z ); bs->setCommonDirection( -Ogre::Vector3::UNIT_Y ); bs->setBillboardsInWorldSpace( true ); bs->setBillboardOrigin( Ogre::BBO_CENTER ); bs->setDefaultDimensions( m.scale, m.scale ); bs->setUseAccurateFacing( false ); scene->attachObject( bs ); } // Визуализируем каждую ячейку /* - @todo Можно ускорить отрисовку > http://www.ogre3d.org/forums/viewtopic.php?f=2&t=11134&start=0 Ogre::Billboard b = Ogre::Billboard( Ogre::Vector3::ZERO, bs ); b.setColour( Ogre::ColourValue::White ); b.setRotation( Ogre::Degree( (float)rand() ) ); */ //bs->beginBillboards(); for (size_t z = 0; z < m.M; ++z) { for (size_t x = 0; x < m.N; ++x) { const coordInt2d_t coord( (int)x, (int)z ); // Создадим образ ячейки с указанной координатой const int i = helper::ic( coord.get<0>(), coord.get<1>(), m.N, m.M ); assert( (i != -1) && "Получена координата за пределами матрицы порта." ); const C c = m.content[i]; // Биллборд уже мог быть создан ранее const auto bi = helper::index( *bs, coord, m.scale ); if (bi != -1) { bs->removeBillboard( bi ); } if (c.uid == 0) { // Вакуум - отсутствие образа continue; } #if 0 // - Медленно. Переписано через биллборды. /* const std::string name = "smoke-pressure-" + Ogre::StringConverter::toString( (int)c.pressure ); */ const std::string meshName = "sphere.mesh"; /* - @todo Так ли каждый раз нужна новая сущность? const std::string entityName = meshName + ".entity"; const bool has = sm->hasEntity( entityName ); Ogre::Entity* image = has ? sm->getEntity( entityName ) : sm->createEntity( entityName, meshName ); */ Ogre::Entity* image = sm->createEntity( meshName ); auto childScene = sn->createChildSceneNode(); childScene->attachObject( image ); // Координаты образа кратны масштабу childScene->setPosition( (float)coord.get<0>() * scale, 0.0f, (float)coord.get<1>() * scale ); // Образ заполняет ячейку целиком //const Ogre::Vector3 fillScale( scale / image->getBoundingRadius() ); //childScene->setScale( fillScale ); #endif // Работаем через биллборды // @source http://89.151.96.106/forums/viewtopic.php?f=10&t=60455 // @todo Визаулизировать в зависимости от характеристики ячейки и соседей. // Позиционируем биллборд Ogre::Billboard* b = bs->createBillboard( (float)coord.get<0>() * m.scale, 0.0f, (float)coord.get<1>() * m.scale ); b->setRotation( Ogre::Degree( (float)rand() ) ); /* b.setPosition( (float)coord.get<0>() * m.scale, 0.0f, (float)coord.get<1>() * m.scale ); bs->injectBillboard( b ); */ // @test //break; } // for (size_t x = 0; x < m.N; ++x) } // for (size_t z = 0; z < m.M; ++z) //bs->endBillboards(); } // if ( m.update || !m.sm->hasSceneNode( sceneName ) ) }