Example #1
0
void Parser::object_streams(RootNode *root_node)
{
    int size = root_node->size();
    int i;

    for (i = 0; i < size; i++) {
        ObjNode *root_object = dynamic_cast<ObjNode *> (root_node->get(i));
        if (root_object) {
            MapNode *map = dynamic_cast<MapNode *> (root_object->value());
            if (map) {
                NameNode *type = dynamic_cast<NameNode *> (map->get("/Type"));
                if (type && type->name() == "/ObjStm") {
                    int qtd = 0;
                    int length = 0;
                    NumberNode *number = dynamic_cast<NumberNode *> (map->get("/N"));
                    if (number) {
                        qtd = number->value();
                    }
                    NumberNode *length_node = dynamic_cast<NumberNode *> (map->get("/Length"));
                    if (number) {
                        length = length_node->value();
                    }
                    char *uncompressed = NULL;

                    m_scanner->to_pos(root_object->stream_pos());
                    char *stream = (char *)m_scanner->get_stream(length);

                    int total = length;
                    NameNode *filter = dynamic_cast<NameNode *> (map->get("/Filter"));
                    if (filter && filter->name() == "/FlateDecode") {
                        uncompressed = flat_decode(stream, length, total);
                        delete [] stream;
                    } else if (!filter) {
                        uncompressed = stream;
                    } else {
                        error_message(string("compression not supported: ") + filter->name());
                        return;
                    }
                    stringstream stream_value;
                    stream_value.write(uncompressed, total);
                    stream_value.seekg(0);
                    delete [] uncompressed;

                    Scanner scanner;
                    Scanner *temp = m_scanner;
                    m_scanner = &scanner;
                    scanner.set_istream(&stream_value);

                    vector<int> ids;
                    int loop;
                    for (loop = 0; loop < qtd; loop++) {
                        next_token();
                        ids.push_back(m_token->to_number());
                        next_token();
                    }
                    next_token();
                    vector<int>::iterator id;
                    for (id = ids.begin(); id < ids.end(); id++) {
                        ObjNode *new_obj = new ObjNode(*id, 0);
                        new_obj->set_value(value_sequence());
                        root_node->add_child(new_obj);
                    }
                    m_scanner = temp;
                }
            }
        }
    }
}
MapNode*
EarthFileSerializer2::deserialize( const Config& conf, const std::string& referenceURI ) const
{
    MapOptions mapOptions( conf.child( "options" ) );

    // legacy: check for name/type in top-level attrs:
    if ( conf.hasValue( "name" ) || conf.hasValue( "type" ) )
    {
        Config legacy;
        if ( conf.hasValue("name") ) legacy.add( "name", conf.value("name") );
        if ( conf.hasValue("type") ) legacy.add( "type", conf.value("type") );
        mapOptions.mergeConfig( legacy );
    }

    Map* map = new Map( mapOptions );

    // Yes, MapOptions and MapNodeOptions share the same Config node. Weird but true.
    MapNodeOptions mapNodeOptions( conf.child( "options" ) );

    // Read the layers in LAST (otherwise they will not benefit from the cache/profile configuration)

    // Image layers:
    ConfigSet images = conf.children( "image" );
    for( ConfigSet::const_iterator i = images.begin(); i != images.end(); i++ )
    {
        Config layerDriverConf = *i;        

        ImageLayerOptions layerOpt( layerDriverConf );
        layerOpt.name() = layerDriverConf.value("name");
        //layerOpt.driver() = TileSourceOptions( layerDriverConf );

        map->addImageLayer( new ImageLayer(layerOpt) );
    }

    // Elevation layers:
    for( int k=0; k<2; ++k )
    {
        std::string tagName = k == 0 ? "elevation" : "heightfield"; // support both :)

        ConfigSet heightfields = conf.children( tagName );
        for( ConfigSet::const_iterator i = heightfields.begin(); i != heightfields.end(); i++ )
        {
            Config layerDriverConf = *i;            

            ElevationLayerOptions layerOpt( layerDriverConf );
            layerOpt.name() = layerDriverConf.value( "name" );

            map->addElevationLayer( new ElevationLayer(layerOpt) );
        }
    }

    // Model layers:
    ConfigSet models = conf.children( "model" );
    for( ConfigSet::const_iterator i = models.begin(); i != models.end(); i++ )
    {
        const Config& layerDriverConf = *i;

        ModelLayerOptions layerOpt( layerDriverConf );
        layerOpt.name() = layerDriverConf.value( "name" );
        layerOpt.driver() = ModelSourceOptions( layerDriverConf );

        map->addModelLayer( new ModelLayer(layerOpt) );
    }

    // Mask layer:
    ConfigSet masks = conf.children( "mask" );
    for( ConfigSet::const_iterator i = masks.begin(); i != masks.end(); i++ )
    {
        Config maskLayerConf = *i;

        MaskLayerOptions options(maskLayerConf);
        options.name() = maskLayerConf.value( "name" );
        options.driver() = MaskSourceOptions(options);

        map->addTerrainMaskLayer( new MaskLayer(options) );
    }

    
    //Add any addition paths specified in the options/osg_file_paths element to the file path.  Useful for pointing osgEarth at resource folders.
    Config osg_file_paths = conf.child( "options" ).child("osg_file_paths");
    ConfigSet urls = osg_file_paths.children("url");
    for (ConfigSet::const_iterator i = urls.begin(); i != urls.end(); i++) 
    {
        std::string path = osgEarth::getFullPath( referenceURI, (*i).value());
        OE_DEBUG << "Adding OSG file path " << path << std::endl;
        osgDB::Registry::instance()->getDataFilePathList().push_back( path );
    }

    MapNode* mapNode = new MapNode( map, mapNodeOptions );

    // External configs:
    Config ext = conf.child( "external" );
    if ( !ext.empty() )
    {
        mapNode->externalConfig() = ext;
    }

    return mapNode;
}
Example #3
0
void MapgenV6::placeTreesAndJungleGrass() {
	//TimeTaker t("placeTrees");
	
	PseudoRandom grassrandom(blockseed + 53);

	content_t c_sand            = ndef->getId("mapgen_sand");

	content_t c_junglegrass = ndef->getId("mapgen_junglegrass");
	// if we don't have junglegrass, don't place cignore... that's bad
	if (c_junglegrass == CONTENT_IGNORE)
		c_junglegrass = CONTENT_AIR;
	MapNode n_junglegrass(c_junglegrass);
	v3s16 em = vm->m_area.getExtent();
	
	// Divide area into parts
	s16 div = 8;
	s16 sidelen = central_area_size.X / div;
	double area = sidelen * sidelen;
	
	// N.B.  We must add jungle grass first, since tree leaves will
	// obstruct the ground, giving us a false ground level
	for (s16 z0 = 0; z0 < div; z0++)
	for (s16 x0 = 0; x0 < div; x0++) {
		// Center position of part of division
		v2s16 p2d_center(
			node_min.X + sidelen / 2 + sidelen * x0,
			node_min.Z + sidelen / 2 + sidelen * z0
		);
		// Minimum edge of part of division
		v2s16 p2d_min(
			node_min.X + sidelen * x0,
			node_min.Z + sidelen * z0
		);
		// Maximum edge of part of division
		v2s16 p2d_max(
			node_min.X + sidelen + sidelen * x0 - 1,
			node_min.Z + sidelen + sidelen * z0 - 1
		);
		
		// Amount of trees, jungle area
		u32 tree_count = area * getTreeAmount(p2d_center);
		
		float humidity = 0;
		bool is_jungle = false;
		if (flags & MGV6_JUNGLES) {
			humidity = getHumidity(p2d_center);
			if (humidity > 0.75) {
				is_jungle = true;
				tree_count *= 4;
			}
		}

		if (node_max.Y < water_level)
			tree_count /= 2;

		// Add jungle grass
		if (is_jungle) {			
			u32 grass_count = 5 * humidity * tree_count;
			for (u32 i = 0; i < grass_count; i++) {
				s16 x = grassrandom.range(p2d_min.X, p2d_max.X);
				s16 z = grassrandom.range(p2d_min.Y, p2d_max.Y);
				
				s16 y = findGroundLevelFull(v2s16(x, z)); ////////////////optimize this!
				if (y < water_level || y < node_min.Y || y > node_max.Y)
					continue;
				
				u32 vi = vm->m_area.index(x, y, z);
				// place on dirt_with_grass, since we know it is exposed to sunlight
				if (vm->m_data[vi].getContent() == c_dirt_with_grass) {
					vm->m_area.add_y(em, vi, 1);
					vm->m_data[vi] = n_junglegrass;
				}
			}
		}
		
		// Put trees in random places on part of division
		for (u32 i = 0; i < tree_count; i++) {
			s16 x = myrand_range(p2d_min.X, p2d_max.X);
			s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
			s16 y = findGroundLevelFull(v2s16(x, z)); ////////////////////optimize this!
			// Don't make a tree under water level
			// Don't make a tree so high that it doesn't fit
			if(y > node_max.Y - 6)
				continue;
			
			v3s16 p(x,y,z);
			// Trees grow only on mud and grass
			{
				u32 i = vm->m_area.index(p);
				MapNode *n = &vm->m_data[i];
				if (n->getContent() != c_dirt &&
					n->getContent() != c_dirt_with_grass &&
					(y >= water_level || n->getContent() != c_sand))
					continue;
			}
			p.Y++;
			
			// Make a tree
			if (y < water_level) {
				if (y < water_level - 20) // do not spawn trees in lakes
					treegen::make_cavetree(*vm, p, is_jungle, ndef, myrand());
			}
			else if (is_jungle) {
				treegen::make_jungletree(*vm, p, ndef, myrand());
			} else {
				bool is_apple_tree = (myrand_range(0, 3) == 0) &&
										getHaveAppleTree(v2s16(x, z));
				treegen::make_tree(*vm, p, is_apple_tree, ndef, myrand());
			}
		}
	}
	//printf("placeTreesAndJungleGrass: %dms\n", t.stop());
}
Example #4
0
/*
	Calculate smooth lighting at the XYZ- corner of p.
	Single light bank.
*/
static u8 getSmoothLight(enum LightBank bank, v3s16 p, MeshMakeData *data)
{
	static v3s16 dirs8[8] = {
		v3s16(0,0,0),
		v3s16(0,0,1),
		v3s16(0,1,0),
		v3s16(0,1,1),
		v3s16(1,0,0),
		v3s16(1,1,0),
		v3s16(1,0,1),
		v3s16(1,1,1),
	};

	INodeDefManager *ndef = data->m_gamedef->ndef();

	u16 ambient_occlusion = 0;
	u16 light = 0;
	u16 light_count = 0;
	u8 light_source_max = 0;
	for(u32 i=0; i<8; i++)
	{
		MapNode n = data->m_vmanip.getNodeNoEx(p - dirs8[i]);
		const ContentFeatures &f = ndef->get(n);
		if(f.light_source > light_source_max)
			light_source_max = f.light_source;
		// Check f.solidness because fast-style leaves look
		// better this way
		if(f.param_type == CPT_LIGHT && f.solidness != 2)
		{
			light += decode_light(n.getLight(bank, ndef));
			light_count++;
		}
		else if(n.getContent() != CONTENT_IGNORE)
		{
			ambient_occlusion++;
		}
	}

	if(light_count == 0)
		return 255;
	
	light /= light_count;

	// Boost brightness around light sources
	if(decode_light(light_source_max) >= light)
		//return decode_light(undiminish_light(light_source_max));
		return decode_light(light_source_max);

	if(ambient_occlusion > 4)
	{
		//ambient_occlusion -= 4;
		//light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
		float light_amount = (8 - ambient_occlusion) / 4.0;
		float light_f = (float)light / 255.0;
		light_f = pow(light_f, 2.2f); // gamma -> linear space
		light_f = light_f * light_amount;
		light_f = pow(light_f, 1.0f/2.2f); // linear -> gamma space
		if(light_f > 1.0)
			light_f = 1.0;
		light = 255.0 * light_f + 0.5;
	}

	return light;
}
Example #5
0
void ClientEnvironment::step(float dtime)
{
	DSTACK(__FUNCTION_NAME);

	// Get some settings
	bool free_move = g_settings.getBool("free_move");
	bool footprints = g_settings.getBool("footprints");

	// Get local player
	LocalPlayer *lplayer = getLocalPlayer();
	assert(lplayer);
	// collision info queue
	core::list<CollisionInfo> player_collisions;
	
	/*
		Get the speed the player is going
	*/
	bool is_climbing = lplayer->is_climbing;

	f32 player_speed = 0.001; // just some small value
	player_speed = lplayer->getSpeed().getLength();
	
	/*
		Maximum position increment
	*/
	//f32 position_max_increment = 0.05*BS;
	f32 position_max_increment = 0.1*BS;

	// Maximum time increment (for collision detection etc)
	// time = distance / speed
	f32 dtime_max_increment = position_max_increment / player_speed;
	
	// Maximum time increment is 10ms or lower
	if(dtime_max_increment > 0.01)
		dtime_max_increment = 0.01;
	
	// Don't allow overly huge dtime
	if(dtime > 0.5)
		dtime = 0.5;
	
	f32 dtime_downcount = dtime;

	/*
		Stuff that has a maximum time increment
	*/

	u32 loopcount = 0;
	do
	{
		loopcount++;

		f32 dtime_part;
		if(dtime_downcount > dtime_max_increment)
		{
			dtime_part = dtime_max_increment;
			dtime_downcount -= dtime_part;
		}
		else
		{
			dtime_part = dtime_downcount;
			/*
				Setting this to 0 (no -=dtime_part) disables an infinite loop
				when dtime_part is so small that dtime_downcount -= dtime_part
				does nothing
			*/
			dtime_downcount = 0;
		}
		
		/*
			Handle local player
		*/
		
		{
			v3f lplayerpos = lplayer->getPosition();
			
			// Apply physics
			if(free_move == false && is_climbing == false)
			{
				// Gravity
				v3f speed = lplayer->getSpeed();
				if(lplayer->swimming_up == false)
					speed.Y -= 9.81 * BS * dtime_part * 2;

				// Water resistance
				if(lplayer->in_water_stable || lplayer->in_water)
				{
					f32 max_down = 2.0*BS;
					if(speed.Y < -max_down) speed.Y = -max_down;

					f32 max = 2.5*BS;
					if(speed.getLength() > max)
					{
						speed = speed / speed.getLength() * max;
					}
				}

				lplayer->setSpeed(speed);
			}

			/*
				Move the lplayer.
				This also does collision detection.
			*/
			lplayer->move(dtime_part, *m_map, position_max_increment,
					&player_collisions);
		}
	}
	while(dtime_downcount > 0.001);
		
	//std::cout<<"Looped "<<loopcount<<" times."<<std::endl;

	for(core::list<CollisionInfo>::Iterator
			i = player_collisions.begin();
			i != player_collisions.end(); i++)
	{
		CollisionInfo &info = *i;
		if(info.t == COLLISION_FALL)
		{
			//f32 tolerance = BS*10; // 2 without damage
			f32 tolerance = BS*12; // 3 without damage
			f32 factor = 1;
			if(info.speed > tolerance)
			{
				f32 damage_f = (info.speed - tolerance)/BS*factor;
				u16 damage = (u16)(damage_f+0.5);
				if(lplayer->hp > damage)
					lplayer->hp -= damage;
				else
					lplayer->hp = 0;

				ClientEnvEvent event;
				event.type = CEE_PLAYER_DAMAGE;
				event.player_damage.amount = damage;
				m_client_event_queue.push_back(event);
			}
		}
	}
	
	/*
		Stuff that can be done in an arbitarily large dtime
	*/
	for(core::list<Player*>::Iterator i = m_players.begin();
			i != m_players.end(); i++)
	{
		Player *player = *i;
		v3f playerpos = player->getPosition();
		
		/*
			Handle non-local players
		*/
		if(player->isLocal() == false)
		{
			// Move
			player->move(dtime, *m_map, 100*BS);

			// Update lighting on remote players on client
			u8 light = LIGHT_MAX;
			try{
				// Get node at head
				v3s16 p = player->getLightPosition();
				MapNode n = m_map->getNode(p);
				light = n.getLightBlend(getDayNightRatio());
			}
			catch(InvalidPositionException &e) {}
			player->updateLight(light);
		}
		
		/*
			Add footsteps to grass
		*/
		if(footprints)
		{
			// Get node that is at BS/4 under player
			v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
			try{
				MapNode n = m_map->getNode(bottompos);
				if(n.getContent() == CONTENT_GRASS)
				{
					n.setContent(CONTENT_GRASS_FOOTSTEPS);
					m_map->setNode(bottompos, n);
					// Update mesh on client
					if(m_map->mapType() == MAPTYPE_CLIENT)
					{
						v3s16 p_blocks = getNodeBlockPos(bottompos);
						MapBlock *b = m_map->getBlockNoCreate(p_blocks);
						//b->updateMesh(getDayNightRatio());
						b->setMeshExpired(true);
					}
				}
			}
			catch(InvalidPositionException &e)
			{
			}
		}
	}
	
	/*
		Step active objects and update lighting of them
	*/
	
	for(core::map<u16, ClientActiveObject*>::Iterator
			i = m_active_objects.getIterator();
			i.atEnd()==false; i++)
	{
		ClientActiveObject* obj = i.getNode()->getValue();
		// Step object
		obj->step(dtime, this);

		if(m_active_object_light_update_interval.step(dtime, 0.21))
		{
			// Update lighting
			//u8 light = LIGHT_MAX;
			u8 light = 0;
			try{
				// Get node at head
				v3s16 p = obj->getLightPosition();
				MapNode n = m_map->getNode(p);
				light = n.getLightBlend(getDayNightRatio());
			}
			catch(InvalidPositionException &e) {}
			obj->updateLight(light);
		}
	}
}
Example #6
0
void ParticleManager::addNodeParticle(IGameDef* gamedef,
	LocalPlayer *player, v3s16 pos, const MapNode &n, const ContentFeatures &f)
{
	// No particles for "airlike" nodes
	if (f.drawtype == NDT_AIRLIKE)
		return;

	// Texture
	u8 texid = myrand_range(0, 5);
	const TileLayer &tile = f.tiles[texid].layers[0];
	video::ITexture *texture;
	struct TileAnimationParams anim;
	anim.type = TAT_NONE;

	// Only use first frame of animated texture
	if (tile.material_flags & MATERIAL_FLAG_ANIMATION)
		texture = (*tile.frames)[0].texture;
	else
		texture = tile.texture;

	float size = (rand() % 8) / 64.0f;
	float visual_size = BS * size;
	if (tile.scale)
		size /= tile.scale;
	v2f texsize(size * 2.0f, size * 2.0f);
	v2f texpos;
	texpos.X = (rand() % 64) / 64.0f - texsize.X;
	texpos.Y = (rand() % 64) / 64.0f - texsize.Y;

	// Physics
	v3f velocity(
		(rand() % 150) / 50.0f - 1.5f,
		(rand() % 150) / 50.0f,
		(rand() % 150) / 50.0f - 1.5f
	);
	v3f acceleration(
		0.0f,
		-player->movement_gravity * player->physics_override_gravity / BS,
		0.0f
	);
	v3f particlepos = v3f(
		(f32)pos.X + (rand() % 100) / 200.0f - 0.25f,
		(f32)pos.Y + (rand() % 100) / 200.0f - 0.25f,
		(f32)pos.Z + (rand() % 100) / 200.0f - 0.25f
	);

	video::SColor color;
	if (tile.has_color)
		color = tile.color;
	else
		n.getColor(f, &color);

	Particle* toadd = new Particle(
		gamedef,
		player,
		m_env,
		particlepos,
		velocity,
		acceleration,
		(rand() % 100) / 100.0f, // expiration time
		visual_size,
		true,
		false,
		false,
		false,
		texture,
		texpos,
		texsize,
		anim,
		0,
		color);

	addParticle(toadd);
}
int
seed( osg::ArgumentParser& args )
{    
    osgDB::Registry::instance()->getReaderWriterForExtension("png");
    osgDB::Registry::instance()->getReaderWriterForExtension("jpg");
    osgDB::Registry::instance()->getReaderWriterForExtension("tiff");

    //Read the min level
    int minLevel = -1;
    while (args.read("--min-level", minLevel));

    //Read the max level
    int maxLevel = -1;
    while (args.read("--max-level", maxLevel));

    bool estimate = args.read("--estimate");        
    

    std::vector< Bounds > bounds;
    // restrict packaging to user-specified bounds.    
    double xmin=DBL_MAX, ymin=DBL_MAX, xmax=DBL_MIN, ymax=DBL_MIN;
    while (args.read("--bounds", xmin, ymin, xmax, ymax ))
    {        
        Bounds b;
        b.xMin() = xmin, b.yMin() = ymin, b.xMax() = xmax, b.yMax() = ymax;
        bounds.push_back( b );
    }    

    std::string tileList;
    while (args.read( "--tiles", tileList ) );

    bool verbose = args.read("--verbose");

    unsigned int batchSize = 0;
    args.read("--batchsize", batchSize);

    // Read the concurrency level
    unsigned int concurrency = 0;
    args.read("-c", concurrency);
    args.read("--concurrency", concurrency);

    int imageLayerIndex = -1;
    args.read("--image", imageLayerIndex);

    int elevationLayerIndex = -1;
    args.read("--elevation", elevationLayerIndex);


    //Read in the earth file.
    osg::ref_ptr<osg::Node> node = osgDB::readNodeFiles( args );
    if ( !node.valid() )
        return usage( "Failed to read .earth file." );

    MapNode* mapNode = MapNode::findMapNode( node.get() );
    if ( !mapNode )
        return usage( "Input file was not a .earth file" );

    // Read in an index shapefile
    std::string index;
    while (args.read("--index", index))
    {        
        //Open the feature source
        OGRFeatureOptions featureOpt;
        featureOpt.url() = index;        

        osg::ref_ptr< FeatureSource > features = FeatureSourceFactory::create( featureOpt );
        Status status = features->open();

        if (status.isOK())
        {
            osg::ref_ptr< FeatureCursor > cursor = features->createFeatureCursor(0L);
            while (cursor.valid() && cursor->hasMore())
            {
                osg::ref_ptr< Feature > feature = cursor->nextFeature();
                osgEarth::Bounds featureBounds = feature->getGeometry()->getBounds();
                GeoExtent ext( feature->getSRS(), featureBounds );
                ext = ext.transform( mapNode->getMapSRS() );
                bounds.push_back( ext.bounds() );            
            }
        }
        else
        {
            OE_WARN << status.message() << "\n";
        }
    }

    // If they requested to do an estimate then don't do the seed, just print out the estimated values.
    if (estimate)
    {        
        CacheEstimator est;
        if ( minLevel >= 0 )
            est.setMinLevel( minLevel );
        if ( maxLevel >= 0 )
            est.setMaxLevel( maxLevel );
        est.setProfile( mapNode->getMap()->getProfile() );

        for (unsigned int i = 0; i < bounds.size(); i++)
        {
            GeoExtent extent(mapNode->getMapSRS(), bounds[i]);
            OE_DEBUG << "Adding extent " << extent.toString() << std::endl;
            est.addExtent( extent );
        } 

        unsigned int numTiles = est.getNumTiles();
        double size = est.getSizeInMB();
        double time = est.getTotalTimeInSeconds();
        std::cout << "Cache Estimation " << std::endl
            << "---------------- " << std::endl
            << "Total number of tiles: " << numTiles << std::endl
            << "Size on disk:          " << osgEarth::prettyPrintSize( size ) << std::endl
            << "Total time:            " << osgEarth::prettyPrintTime( time ) << std::endl;

        return 0;
    }
    
    osg::ref_ptr< TileVisitor > visitor;


    // If we are given a task file, load it up and create a new TileKeyListVisitor
    if (!tileList.empty())
    {        
        TaskList tasks( mapNode->getMap()->getProfile() );
        tasks.load( tileList );

        TileKeyListVisitor* v = new TileKeyListVisitor();
        v->setKeys( tasks.getKeys() );
        visitor = v;        
        OE_DEBUG << "Read task list with " << tasks.getKeys().size() << " tasks" << std::endl;
    }
  

    // If we dont' have a visitor create one.
    if (!visitor.valid())
    {
        if (args.read("--mt"))
        {
            // Create a multithreaded visitor
            MultithreadedTileVisitor* v = new MultithreadedTileVisitor();
            if (concurrency > 0)
            {
                v->setNumThreads(concurrency);
            }
            visitor = v;            
        }
        else if (args.read("--mp"))
        {
            // Create a multiprocess visitor
            MultiprocessTileVisitor* v = new MultiprocessTileVisitor();
            if (concurrency > 0)
            {
                v->setNumProcesses(concurrency);
            }

            if (batchSize > 0)
            {                
                v->setBatchSize(batchSize);
            }

            // Try to find the earth file
            std::string earthFile;
            for(int pos=1;pos<args.argc();++pos)
            {
                if (!args.isOption(pos))
                {
                    earthFile  = args[ pos ];
                    break;
                }
            }
            v->setEarthFile( earthFile );            
            visitor = v;            
        }
        else
        {
            // Create a single thread visitor
            visitor = new TileVisitor();            
        }        
    }

    osg::ref_ptr< ProgressCallback > progress = new ConsoleProgressCallback();
    
    if (verbose)
    {
        visitor->setProgressCallback( progress.get() );
    }

    if ( minLevel >= 0 )
        visitor->setMinLevel( minLevel );
    if ( maxLevel >= 0 )
        visitor->setMaxLevel( maxLevel );        


    for (unsigned int i = 0; i < bounds.size(); i++)
    {
        GeoExtent extent(mapNode->getMapSRS(), bounds[i]);
        OE_DEBUG << "Adding extent " << extent.toString() << std::endl;                
        visitor->addExtent( extent );
    }    
    

    // Initialize the seeder
    CacheSeed seeder;
    seeder.setVisitor(visitor.get());

    osgEarth::Map* map = mapNode->getMap();

    // They want to seed an image layer
    if (imageLayerIndex >= 0)
    {
        osg::ref_ptr< ImageLayer > layer = map->getLayerAt<ImageLayer>( imageLayerIndex );
        if (layer)
        {
            OE_NOTICE << "Seeding single layer " << layer->getName() << std::endl;
            osg::Timer_t start = osg::Timer::instance()->tick();        
            seeder.run(layer.get(), map);
            osg::Timer_t end = osg::Timer::instance()->tick();
            if (verbose)
            {
                OE_NOTICE << "Completed seeding layer " << layer->getName() << " in " << prettyPrintTime( osg::Timer::instance()->delta_s( start, end ) ) << std::endl;
            }    
        }
        else
        {
            std::cout << "Failed to find an image layer at index " << imageLayerIndex << std::endl;
            return 1;
        }

    }
    // They want to seed an elevation layer
    else if (elevationLayerIndex >= 0)
    {
        osg::ref_ptr< ElevationLayer > layer = map->getLayerAt<ElevationLayer>( elevationLayerIndex );
        if (layer)
        {
            OE_NOTICE << "Seeding single layer " << layer->getName() << std::endl;
            osg::Timer_t start = osg::Timer::instance()->tick();        
            seeder.run(layer.get(), map);
            osg::Timer_t end = osg::Timer::instance()->tick();
            if (verbose)
            {
                OE_NOTICE << "Completed seeding layer " << layer->getName() << " in " << prettyPrintTime( osg::Timer::instance()->delta_s( start, end ) ) << std::endl;
            }    
        }
        else
        {
            std::cout << "Failed to find an elevation layer at index " << elevationLayerIndex << std::endl;
            return 1;
        }
    }
    // They want to seed the entire map
    else
    {
        TerrainLayerVector terrainLayers;
        map->getLayers(terrainLayers);

        // Seed all the map layers
        for (unsigned int i = 0; i < terrainLayers.size(); ++i)
        {            
            osg::ref_ptr< TerrainLayer > layer = terrainLayers[i].get();
            OE_NOTICE << "Seeding layer" << layer->getName() << std::endl;            
            osg::Timer_t start = osg::Timer::instance()->tick();
            seeder.run(layer.get(), map);            
            osg::Timer_t end = osg::Timer::instance()->tick();
            if (verbose)
            {
                OE_NOTICE << "Completed seeding layer " << layer->getName() << " in " << prettyPrintTime( osg::Timer::instance()->delta_s( start, end ) ) << std::endl;
            }                
        }

        //for (unsigned int i = 0; i < map->getNumElevationLayers(); ++i)
        //{
        //    osg::ref_ptr< ElevationLayer > layer = map->getElevationLayerAt(i);
        //    OE_NOTICE << "Seeding layer" << layer->getName() << std::endl;
        //    osg::Timer_t start = osg::Timer::instance()->tick();
        //    seeder.run(layer.get(), map);            
        //    osg::Timer_t end = osg::Timer::instance()->tick();
        //    if (verbose)
        //    {
        //        OE_NOTICE << "Completed seeding layer " << layer->getName() << " in " << prettyPrintTime( osg::Timer::instance()->delta_s( start, end ) ) << std::endl;
        //    }                
        //}        
    }    

    return 0;
}
Example #8
0
void ClientMap::updateDrawList(video::IVideoDriver* driver)
{
	ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
	g_profiler->add("CM::updateDrawList() count", 1);

	INodeDefManager *nodemgr = m_gamedef->ndef();

	for (std::map<v3s16, MapBlock*>::iterator i = m_drawlist.begin();
			i != m_drawlist.end(); ++i) {
		MapBlock *block = i->second;
		block->refDrop();
	}
	m_drawlist.clear();

	v3f camera_position = m_camera_position;
	v3f camera_direction = m_camera_direction;
	f32 camera_fov = m_camera_fov;

	// Use a higher fov to accomodate faster camera movements.
	// Blocks are cropped better when they are drawn.
	// Or maybe they aren't? Well whatever.
	camera_fov *= 1.2;

	v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
	v3s16 p_blocks_min;
	v3s16 p_blocks_max;
	getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);

	// Number of blocks in rendering range
	u32 blocks_in_range = 0;
	// Number of blocks occlusion culled
	u32 blocks_occlusion_culled = 0;
	// Number of blocks in rendering range but don't have a mesh
	u32 blocks_in_range_without_mesh = 0;
	// Blocks that had mesh that would have been drawn according to
	// rendering range (if max blocks limit didn't kick in)
	u32 blocks_would_have_drawn = 0;
	// Blocks that were drawn and had a mesh
	u32 blocks_drawn = 0;
	// Blocks which had a corresponding meshbuffer for this pass
	//u32 blocks_had_pass_meshbuf = 0;
	// Blocks from which stuff was actually drawn
	//u32 blocks_without_stuff = 0;
	// Distance to farthest drawn block
	float farthest_drawn = 0;

	for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
			si != m_sectors.end(); ++si) {
		MapSector *sector = si->second;
		v2s16 sp = sector->getPos();

		if (m_control.range_all == false) {
			if (sp.X < p_blocks_min.X || sp.X > p_blocks_max.X ||
					sp.Y < p_blocks_min.Z || sp.Y > p_blocks_max.Z)
				continue;
		}

		MapBlockVect sectorblocks;
		sector->getBlocks(sectorblocks);

		/*
			Loop through blocks in sector
		*/

		u32 sector_blocks_drawn = 0;

		for (MapBlockVect::iterator i = sectorblocks.begin();
				i != sectorblocks.end(); ++i) {
			MapBlock *block = *i;

			/*
				Compare block position to camera position, skip
				if not seen on display
			*/

			if (block->mesh != NULL)
				block->mesh->updateCameraOffset(m_camera_offset);

			float range = 100000 * BS;
			if (m_control.range_all == false)
				range = m_control.wanted_range * BS;

			float d = 0.0;
			if (!isBlockInSight(block->getPos(), camera_position,
					camera_direction, camera_fov, range, &d))
				continue;

			// This is ugly (spherical distance limit?)
			/*if(m_control.range_all == false &&
					d - 0.5*BS*MAP_BLOCKSIZE > range)
				continue;*/

			blocks_in_range++;

			/*
				Ignore if mesh doesn't exist
			*/
			{
				//MutexAutoLock lock(block->mesh_mutex);

				if (block->mesh == NULL) {
					blocks_in_range_without_mesh++;
					continue;
				}
			}

			/*
				Occlusion culling
			*/

			// No occlusion culling when free_move is on and camera is
			// inside ground
			bool occlusion_culling_enabled = true;
			if (g_settings->getBool("free_move")) {
				MapNode n = getNodeNoEx(cam_pos_nodes);
				if (n.getContent() == CONTENT_IGNORE ||
						nodemgr->get(n).solidness == 2)
					occlusion_culling_enabled = false;
			}

			v3s16 cpn = block->getPos() * MAP_BLOCKSIZE;
			cpn += v3s16(MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2);
			float step = BS * 1;
			float stepfac = 1.1;
			float startoff = BS * 1;
			// The occlusion search of 'isOccluded()' must stop short of the target
			// point by distance 'endoff' (end offset) to not enter the target mapblock.
			// For the 8 mapblock corners 'endoff' must therefore be the maximum diagonal
			// of a mapblock, because we must consider all view angles.
			// sqrt(1^2 + 1^2 + 1^2) = 1.732
			float endoff = -BS * MAP_BLOCKSIZE * 1.732050807569;
			v3s16 spn = cam_pos_nodes;
			s16 bs2 = MAP_BLOCKSIZE / 2 + 1;
			// to reduce the likelihood of falsely occluded blocks
			// require at least two solid blocks
			// this is a HACK, we should think of a more precise algorithm
			u32 needed_count = 2;
			if (occlusion_culling_enabled &&
					// For the central point of the mapblock 'endoff' can be halved
					isOccluded(this, spn, cpn,
						step, stepfac, startoff, endoff / 2.0f, needed_count, nodemgr) &&
					isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2),
						step, stepfac, startoff, endoff, needed_count, nodemgr) &&
					isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2),
						step, stepfac, startoff, endoff, needed_count, nodemgr) &&
					isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2),
						step, stepfac, startoff, endoff, needed_count, nodemgr) &&
					isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2),
						step, stepfac, startoff, endoff, needed_count, nodemgr) &&
					isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2),
						step, stepfac, startoff, endoff, needed_count, nodemgr) &&
					isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2),
						step, stepfac, startoff, endoff, needed_count, nodemgr) &&
					isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2),
						step, stepfac, startoff, endoff, needed_count, nodemgr) &&
					isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2),
						step, stepfac, startoff, endoff, needed_count, nodemgr)) {
				blocks_occlusion_culled++;
				continue;
			}

			// This block is in range. Reset usage timer.
			block->resetUsageTimer();

			// Limit block count in case of a sudden increase
			blocks_would_have_drawn++;
			if (blocks_drawn >= m_control.wanted_max_blocks &&
					!m_control.range_all &&
					d > m_control.wanted_range * BS)
				continue;

			// Add to set
			block->refGrab();
			m_drawlist[block->getPos()] = block;

			sector_blocks_drawn++;
			blocks_drawn++;
			if (d / BS > farthest_drawn)
				farthest_drawn = d / BS;

		} // foreach sectorblocks

		if (sector_blocks_drawn != 0)
			m_last_drawn_sectors.insert(sp);
	}

	m_control.blocks_would_have_drawn = blocks_would_have_drawn;
	m_control.blocks_drawn = blocks_drawn;
	m_control.farthest_drawn = farthest_drawn;

	g_profiler->avg("CM: blocks in range", blocks_in_range);
	g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
	if (blocks_in_range != 0)
		g_profiler->avg("CM: blocks in range without mesh (frac)",
				(float)blocks_in_range_without_mesh / blocks_in_range);
	g_profiler->avg("CM: blocks drawn", blocks_drawn);
	g_profiler->avg("CM: farthest drawn", farthest_drawn);
	g_profiler->avg("CM: wanted max blocks", m_control.wanted_max_blocks);
}
Example #9
0
void ClientMap::updateDrawList(video::IVideoDriver* driver)
{
	ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
	g_profiler->add("CM::updateDrawList() count", 1);

	INodeDefManager *nodemgr = m_gamedef->ndef();

	for(std::map<v3s16, MapBlock*>::iterator
			i = m_drawlist.begin();
			i != m_drawlist.end(); ++i)
	{
		MapBlock *block = i->second;
		block->refDrop();
	}
	m_drawlist.clear();

	m_camera_mutex.Lock();
	v3f camera_position = m_camera_position;
	v3f camera_direction = m_camera_direction;
	f32 camera_fov = m_camera_fov;
	v3s16 camera_offset = m_camera_offset;
	m_camera_mutex.Unlock();

	// Use a higher fov to accomodate faster camera movements.
	// Blocks are cropped better when they are drawn.
	// Or maybe they aren't? Well whatever.
	camera_fov *= 1.2;

	v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
	v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
	v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
	v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
	// Take a fair amount as we will be dropping more out later
	// Umm... these additions are a bit strange but they are needed.
	v3s16 p_blocks_min(
			p_nodes_min.X / MAP_BLOCKSIZE - 3,
			p_nodes_min.Y / MAP_BLOCKSIZE - 3,
			p_nodes_min.Z / MAP_BLOCKSIZE - 3);
	v3s16 p_blocks_max(
			p_nodes_max.X / MAP_BLOCKSIZE + 1,
			p_nodes_max.Y / MAP_BLOCKSIZE + 1,
			p_nodes_max.Z / MAP_BLOCKSIZE + 1);

	// Number of blocks in rendering range
	u32 blocks_in_range = 0;
	// Number of blocks occlusion culled
	u32 blocks_occlusion_culled = 0;
	// Number of blocks in rendering range but don't have a mesh
	u32 blocks_in_range_without_mesh = 0;
	// Blocks that had mesh that would have been drawn according to
	// rendering range (if max blocks limit didn't kick in)
	u32 blocks_would_have_drawn = 0;
	// Blocks that were drawn and had a mesh
	u32 blocks_drawn = 0;
	// Blocks which had a corresponding meshbuffer for this pass
	//u32 blocks_had_pass_meshbuf = 0;
	// Blocks from which stuff was actually drawn
	//u32 blocks_without_stuff = 0;
	// Distance to farthest drawn block
	float farthest_drawn = 0;

	for(std::map<v2s16, MapSector*>::iterator
			si = m_sectors.begin();
			si != m_sectors.end(); ++si)
	{
		MapSector *sector = si->second;
		v2s16 sp = sector->getPos();

		if(m_control.range_all == false)
		{
			if(sp.X < p_blocks_min.X
			|| sp.X > p_blocks_max.X
			|| sp.Y < p_blocks_min.Z
			|| sp.Y > p_blocks_max.Z)
				continue;
		}

		std::list< MapBlock * > sectorblocks;
		sector->getBlocks(sectorblocks);

		/*
			Loop through blocks in sector
		*/

		u32 sector_blocks_drawn = 0;

		std::list< MapBlock * >::iterator i;
		for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
		{
			MapBlock *block = *i;

			/*
				Compare block position to camera position, skip
				if not seen on display
			*/

			if (block->mesh != NULL)
				block->mesh->updateCameraOffset(m_camera_offset);

			float range = 100000 * BS;
			if(m_control.range_all == false)
				range = m_control.wanted_range * BS;

			float d = 0.0;
			if(isBlockInSight(block->getPos(), camera_position,
					camera_direction, camera_fov,
					range, &d) == false)
			{
				continue;
			}

			// This is ugly (spherical distance limit?)
			/*if(m_control.range_all == false &&
					d - 0.5*BS*MAP_BLOCKSIZE > range)
				continue;*/

			blocks_in_range++;

			/*
				Ignore if mesh doesn't exist
			*/
			{
				//JMutexAutoLock lock(block->mesh_mutex);

				if(block->mesh == NULL){
					blocks_in_range_without_mesh++;
					continue;
				}
			}

			/*
				Occlusion culling
			*/

			// No occlusion culling when free_move is on and camera is
			// inside ground
			bool occlusion_culling_enabled = true;
			if(g_settings->getBool("free_move")){
				MapNode n = getNodeNoEx(cam_pos_nodes);
				if(n.getContent() == CONTENT_IGNORE ||
						nodemgr->get(n).solidness == 2)
					occlusion_culling_enabled = false;
			}

			v3s16 cpn = block->getPos() * MAP_BLOCKSIZE;
			cpn += v3s16(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2);
			float step = BS*1;
			float stepfac = 1.1;
			float startoff = BS*1;
			float endoff = -BS*MAP_BLOCKSIZE*1.42*1.42;
			v3s16 spn = cam_pos_nodes + v3s16(0,0,0);
			s16 bs2 = MAP_BLOCKSIZE/2 + 1;
			u32 needed_count = 1;
			if(
				occlusion_culling_enabled &&
				isOccluded(this, spn, cpn + v3s16(0,0,0),
					step, stepfac, startoff, endoff, needed_count, nodemgr) &&
				isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr) &&
				isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr) &&
				isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr) &&
				isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr) &&
				isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr) &&
				isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr) &&
				isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr) &&
				isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr)
			)
			{
				blocks_occlusion_culled++;
				continue;
			}

			// This block is in range. Reset usage timer.
			block->resetUsageTimer();

			// Limit block count in case of a sudden increase
			blocks_would_have_drawn++;
			if(blocks_drawn >= m_control.wanted_max_blocks
					&& m_control.range_all == false
					&& d > m_control.wanted_min_range * BS)
				continue;

			// Add to set
			block->refGrab();
			m_drawlist[block->getPos()] = block;

			sector_blocks_drawn++;
			blocks_drawn++;
			if(d/BS > farthest_drawn)
				farthest_drawn = d/BS;

		} // foreach sectorblocks

		if(sector_blocks_drawn != 0)
			m_last_drawn_sectors.insert(sp);
	}

	m_control.blocks_would_have_drawn = blocks_would_have_drawn;
	m_control.blocks_drawn = blocks_drawn;
	m_control.farthest_drawn = farthest_drawn;

	g_profiler->avg("CM: blocks in range", blocks_in_range);
	g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
	if(blocks_in_range != 0)
		g_profiler->avg("CM: blocks in range without mesh (frac)",
				(float)blocks_in_range_without_mesh/blocks_in_range);
	g_profiler->avg("CM: blocks drawn", blocks_drawn);
	g_profiler->avg("CM: farthest drawn", farthest_drawn);
	g_profiler->avg("CM: wanted max blocks", m_control.wanted_max_blocks);
}
Example #10
0
collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef,
		f32 pos_max_d, const aabb3f &box_0,
		f32 stepheight, f32 dtime,
		v3f *pos_f, v3f *speed_f,
		v3f accel_f, ActiveObject *self,
		bool collideWithObjects)
{
	static bool time_notification_done = false;
	Map *map = &env->getMap();
	//TimeTaker tt("collisionMoveSimple");
	ScopeProfiler sp(g_profiler, "collisionMoveSimple avg", SPT_AVG);

	collisionMoveResult result;

	/*
		Calculate new velocity
	*/
	if (dtime > 0.5) {
		if (!time_notification_done) {
			time_notification_done = true;
			infostream << "collisionMoveSimple: maximum step interval exceeded,"
					" lost movement details!"<<std::endl;
		}
		dtime = 0.5;
	} else {
		time_notification_done = false;
	}
	*speed_f += accel_f * dtime;

	// If there is no speed, there are no collisions
	if (speed_f->getLength() == 0)
		return result;

	// Limit speed for avoiding hangs
	speed_f->Y = rangelim(speed_f->Y, -5000, 5000);
	speed_f->X = rangelim(speed_f->X, -5000, 5000);
	speed_f->Z = rangelim(speed_f->Z, -5000, 5000);

	/*
		Collect node boxes in movement range
	*/
	std::vector<aabb3f> cboxes;
	std::vector<bool> is_unloaded;
	std::vector<bool> is_step_up;
	std::vector<bool> is_object;
	std::vector<int> bouncy_values;
	std::vector<v3s16> node_positions;
	{
	//TimeTaker tt2("collisionMoveSimple collect boxes");
    ScopeProfiler sp(g_profiler, "collisionMoveSimple collect boxes avg", SPT_AVG);

	v3s16 oldpos_i = floatToInt(*pos_f, BS);
	v3s16 newpos_i = floatToInt(*pos_f + *speed_f * dtime, BS);
	s16 min_x = MYMIN(oldpos_i.X, newpos_i.X) + (box_0.MinEdge.X / BS) - 1;
	s16 min_y = MYMIN(oldpos_i.Y, newpos_i.Y) + (box_0.MinEdge.Y / BS) - 1;
	s16 min_z = MYMIN(oldpos_i.Z, newpos_i.Z) + (box_0.MinEdge.Z / BS) - 1;
	s16 max_x = MYMAX(oldpos_i.X, newpos_i.X) + (box_0.MaxEdge.X / BS) + 1;
	s16 max_y = MYMAX(oldpos_i.Y, newpos_i.Y) + (box_0.MaxEdge.Y / BS) + 1;
	s16 max_z = MYMAX(oldpos_i.Z, newpos_i.Z) + (box_0.MaxEdge.Z / BS) + 1;

	bool any_position_valid = false;

	for(s16 x = min_x; x <= max_x; x++)
	for(s16 y = min_y; y <= max_y; y++)
	for(s16 z = min_z; z <= max_z; z++)
	{
		v3s16 p(x,y,z);

		bool is_position_valid;
		MapNode n = map->getNodeNoEx(p, &is_position_valid);

		if (is_position_valid) {
			// Object collides into walkable nodes

			any_position_valid = true;
			const ContentFeatures &f = gamedef->getNodeDefManager()->get(n);
			if(f.walkable == false)
				continue;
			int n_bouncy_value = itemgroup_get(f.groups, "bouncy");

			std::vector<aabb3f> nodeboxes = n.getCollisionBoxes(gamedef->ndef());
			for(std::vector<aabb3f>::iterator
					i = nodeboxes.begin();
					i != nodeboxes.end(); ++i)
			{
				aabb3f box = *i;
				box.MinEdge += v3f(x, y, z)*BS;
				box.MaxEdge += v3f(x, y, z)*BS;
				cboxes.push_back(box);
				is_unloaded.push_back(false);
				is_step_up.push_back(false);
				bouncy_values.push_back(n_bouncy_value);
				node_positions.push_back(p);
				is_object.push_back(false);
			}
		}
		else {
			// Collide with unloaded nodes
			aabb3f box = getNodeBox(p, BS);
			cboxes.push_back(box);
			is_unloaded.push_back(true);
			is_step_up.push_back(false);
			bouncy_values.push_back(0);
			node_positions.push_back(p);
			is_object.push_back(false);
		}
	}

	// Do not move if world has not loaded yet, since custom node boxes
	// are not available for collision detection.
	if (!any_position_valid)
		return result;

	} // tt2

	if(collideWithObjects)
	{
		ScopeProfiler sp(g_profiler, "collisionMoveSimple objects avg", SPT_AVG);
		//TimeTaker tt3("collisionMoveSimple collect object boxes");

		/* add object boxes to cboxes */

		std::vector<ActiveObject*> objects;
#ifndef SERVER
		ClientEnvironment *c_env = dynamic_cast<ClientEnvironment*>(env);
		if (c_env != 0) {
			f32 distance = speed_f->getLength();
			std::vector<DistanceSortedActiveObject> clientobjects;
			c_env->getActiveObjects(*pos_f, distance * 1.5, clientobjects);
			for (size_t i=0; i < clientobjects.size(); i++) {
				if ((self == 0) || (self != clientobjects[i].obj)) {
					objects.push_back((ActiveObject*)clientobjects[i].obj);
				}
			}
		}
		else
#endif
		{
			ServerEnvironment *s_env = dynamic_cast<ServerEnvironment*>(env);
			if (s_env != 0) {
				f32 distance = speed_f->getLength();
				std::vector<u16> s_objects;
				s_env->getObjectsInsideRadius(s_objects, *pos_f, distance * 1.5);
				for (std::vector<u16>::iterator iter = s_objects.begin(); iter != s_objects.end(); ++iter) {
					ServerActiveObject *current = s_env->getActiveObject(*iter);
					if ((self == 0) || (self != current)) {
						objects.push_back((ActiveObject*)current);
					}
				}
			}
		}

		for (std::vector<ActiveObject*>::const_iterator iter = objects.begin();
				iter != objects.end(); ++iter) {
			ActiveObject *object = *iter;

			if (object != NULL) {
				aabb3f object_collisionbox;
				if (object->getCollisionBox(&object_collisionbox) &&
						object->collideWithObjects()) {
					cboxes.push_back(object_collisionbox);
					is_unloaded.push_back(false);
					is_step_up.push_back(false);
					bouncy_values.push_back(0);
					node_positions.push_back(v3s16(0,0,0));
					is_object.push_back(true);
				}
			}
		}
	} //tt3

	assert(cboxes.size() == is_unloaded.size());    // post-condition
	assert(cboxes.size() == is_step_up.size());     // post-condition
	assert(cboxes.size() == bouncy_values.size());  // post-condition
	assert(cboxes.size() == node_positions.size()); // post-condition
	assert(cboxes.size() == is_object.size());      // post-condition

	/*
		Collision detection
	*/

	/*
		Collision uncertainty radius
		Make it a bit larger than the maximum distance of movement
	*/
	f32 d = pos_max_d * 1.1;
	// A fairly large value in here makes moving smoother
	//f32 d = 0.15*BS;

	// This should always apply, otherwise there are glitches
	assert(d > pos_max_d);	// invariant

	int loopcount = 0;

	while(dtime > BS * 1e-10) {
		//TimeTaker tt3("collisionMoveSimple dtime loop");
        ScopeProfiler sp(g_profiler, "collisionMoveSimple dtime loop avg", SPT_AVG);

		// Avoid infinite loop
		loopcount++;
		if (loopcount >= 100) {
			warningstream << "collisionMoveSimple: Loop count exceeded, aborting to avoid infiniite loop" << std::endl;
			dtime = 0;
			break;
		}

		aabb3f movingbox = box_0;
		movingbox.MinEdge += *pos_f;
		movingbox.MaxEdge += *pos_f;

		int nearest_collided = -1;
		f32 nearest_dtime = dtime;
		u32 nearest_boxindex = -1;

		/*
			Go through every nodebox, find nearest collision
		*/
		for (u32 boxindex = 0; boxindex < cboxes.size(); boxindex++) {
			// Ignore if already stepped up this nodebox.
			if(is_step_up[boxindex])
				continue;

			// Find nearest collision of the two boxes (raytracing-like)
			f32 dtime_tmp;
			int collided = axisAlignedCollision(
					cboxes[boxindex], movingbox, *speed_f, d, &dtime_tmp);

			if (collided == -1 || dtime_tmp >= nearest_dtime)
				continue;

			nearest_dtime = dtime_tmp;
			nearest_collided = collided;
			nearest_boxindex = boxindex;
		}

		if (nearest_collided == -1) {
			// No collision with any collision box.
			*pos_f += *speed_f * dtime;
			dtime = 0;  // Set to 0 to avoid "infinite" loop due to small FP numbers
		} else {
			// Otherwise, a collision occurred.

			const aabb3f& cbox = cboxes[nearest_boxindex];
			// Check for stairs.
			bool step_up = (nearest_collided != 1) && // must not be Y direction
					(movingbox.MinEdge.Y < cbox.MaxEdge.Y) &&
					(movingbox.MinEdge.Y + stepheight > cbox.MaxEdge.Y) &&
					(!wouldCollideWithCeiling(cboxes, movingbox,
							cbox.MaxEdge.Y - movingbox.MinEdge.Y,
							d));

			// Get bounce multiplier
			bool bouncy = (bouncy_values[nearest_boxindex] >= 1);
			float bounce = -(float)bouncy_values[nearest_boxindex] / 100.0;

			// Move to the point of collision and reduce dtime by nearest_dtime
			if (nearest_dtime < 0) {
				// Handle negative nearest_dtime (can be caused by the d allowance)
				if (!step_up) {
					if (nearest_collided == 0)
						pos_f->X += speed_f->X * nearest_dtime;
					if (nearest_collided == 1)
						pos_f->Y += speed_f->Y * nearest_dtime;
					if (nearest_collided == 2)
						pos_f->Z += speed_f->Z * nearest_dtime;
				}
			} else {
				*pos_f += *speed_f * nearest_dtime;
				dtime -= nearest_dtime;
			}

			bool is_collision = true;
			if (is_unloaded[nearest_boxindex])
				is_collision = false;

			CollisionInfo info;
			if (is_object[nearest_boxindex])
				info.type = COLLISION_OBJECT;
			else
				info.type = COLLISION_NODE;

			info.node_p = node_positions[nearest_boxindex];
			info.bouncy = bouncy;
			info.old_speed = *speed_f;

			// Set the speed component that caused the collision to zero
			if (step_up) {
				// Special case: Handle stairs
				is_step_up[nearest_boxindex] = true;
				is_collision = false;
			} else if(nearest_collided == 0) { // X
				if (fabs(speed_f->X) > BS * 3)
					speed_f->X *= bounce;
				else
					speed_f->X = 0;
				result.collides = true;
				result.collides_xz = true;
			}
			else if(nearest_collided == 1) { // Y
				if (fabs(speed_f->Y) > BS * 3)
					speed_f->Y *= bounce;
				else
					speed_f->Y = 0;
				result.collides = true;
			} else if(nearest_collided == 2) { // Z
				if (fabs(speed_f->Z) > BS * 3)
					speed_f->Z *= bounce;
				else
					speed_f->Z = 0;
				result.collides = true;
				result.collides_xz = true;
			}

			info.new_speed = *speed_f;
			if (info.new_speed.getDistanceFrom(info.old_speed) < 0.1 * BS)
				is_collision = false;

			if (is_collision) {
				result.collisions.push_back(info);
			}
		}
	}

	/*
		Final touches: Check if standing on ground, step up stairs.
	*/
	aabb3f box = box_0;
	box.MinEdge += *pos_f;
	box.MaxEdge += *pos_f;
	for (u32 boxindex = 0; boxindex < cboxes.size(); boxindex++) {
		const aabb3f& cbox = cboxes[boxindex];

		/*
			See if the object is touching ground.

			Object touches ground if object's minimum Y is near node's
			maximum Y and object's X-Z-area overlaps with the node's
			X-Z-area.

			Use 0.15*BS so that it is easier to get on a node.
		*/
		if (cbox.MaxEdge.X - d > box.MinEdge.X && cbox.MinEdge.X + d < box.MaxEdge.X &&
				cbox.MaxEdge.Z - d > box.MinEdge.Z &&
				cbox.MinEdge.Z + d < box.MaxEdge.Z) {
			if (is_step_up[boxindex]) {
				pos_f->Y += (cbox.MaxEdge.Y - box.MinEdge.Y);
				box = box_0;
				box.MinEdge += *pos_f;
				box.MaxEdge += *pos_f;
			}
			if (fabs(cbox.MaxEdge.Y - box.MinEdge.Y) < 0.15 * BS) {
				result.touching_ground = true;

				if (is_object[boxindex])
					result.standing_on_object = true;
				if (is_unloaded[boxindex])
					result.standing_on_unloaded = true;
			}
		}
	}

	return result;
}
Example #11
0
void mapblock_mesh_generate_special(MeshMakeData *data,
		MeshCollector &collector, IGameDef *gamedef)
{
	INodeDefManager *nodedef = gamedef->ndef();

	// 0ms
	//TimeTaker timer("mapblock_mesh_generate_special()");

	/*
		Some settings
	*/
	bool new_style_water = g_settings->getBool("new_style_water");
	
	float node_liquid_level = 1.0;
	if(new_style_water)
		node_liquid_level = 0.85;
	
	v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE;

	/*// General ground material for special output
	// Texture is modified just before usage
	video::SMaterial material_general;
	material_general.setFlag(video::EMF_LIGHTING, false);
	material_general.setFlag(video::EMF_BILINEAR_FILTER, false);
	material_general.setFlag(video::EMF_FOG_ENABLE, true);
	material_general.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;*/

	for(s16 z=0; z<MAP_BLOCKSIZE; z++)
	for(s16 y=0; y<MAP_BLOCKSIZE; y++)
	for(s16 x=0; x<MAP_BLOCKSIZE; x++)
	{
		v3s16 p(x,y,z);

		MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p);
		const ContentFeatures &f = nodedef->get(n);

		// Only solidness=0 stuff is drawn here
		if(f.solidness != 0)
			continue;
		
		switch(f.drawtype){
		default:
			infostream<<"Got "<<f.drawtype<<std::endl;
			assert(0);
			break;
		case NDT_AIRLIKE:
			break;
		case NDT_LIQUID:
		{
			/*
				Add water sources to mesh if using new style
			*/
			assert(nodedef->get(n).special_materials[0]);
			//assert(nodedef->get(n).special_materials[1]);
			assert(nodedef->get(n).special_aps[0]);

			video::SMaterial &liquid_material =
					*nodedef->get(n).special_materials[0];
			/*video::SMaterial &liquid_material_bfculled =
					*nodedef->get(n).special_materials[1];*/
			AtlasPointer &pa_liquid1 =
					*nodedef->get(n).special_aps[0];

			bool top_is_air = false;
			MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
			if(n.getContent() == CONTENT_AIR)
				top_is_air = true;
			
			if(top_is_air == false)
				continue;

			u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
			video::SColor c = MapBlock_LightColor(
					nodedef->get(n).alpha, l);
			
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
						pa_liquid1.x0(), pa_liquid1.y1()),
				video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
						pa_liquid1.x1(), pa_liquid1.y1()),
				video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
						pa_liquid1.x1(), pa_liquid1.y0()),
				video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
						pa_liquid1.x0(), pa_liquid1.y0()),
			};

			for(s32 i=0; i<4; i++)
			{
				vertices[i].Pos.Y += (-0.5+node_liquid_level)*BS;
				vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
			}

			u16 indices[] = {0,1,2,2,3,0};
			// Add to mesh collector
			collector.append(liquid_material, vertices, 4, indices, 6);
		break;}
		case NDT_FLOWINGLIQUID:
		{
			/*
				Add flowing liquid to mesh
			*/
			assert(nodedef->get(n).special_materials[0]);
			assert(nodedef->get(n).special_materials[1]);
			assert(nodedef->get(n).special_aps[0]);

			video::SMaterial &liquid_material =
					*nodedef->get(n).special_materials[0];
			video::SMaterial &liquid_material_bfculled =
					*nodedef->get(n).special_materials[1];
			AtlasPointer &pa_liquid1 =
					*nodedef->get(n).special_aps[0];

			bool top_is_same_liquid = false;
			MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
			content_t c_flowing = nodedef->getId(nodedef->get(n).liquid_alternative_flowing);
			content_t c_source = nodedef->getId(nodedef->get(n).liquid_alternative_source);
			if(ntop.getContent() == c_flowing || ntop.getContent() == c_source)
				top_is_same_liquid = true;
			
			u8 l = 0;
			// Use the light of the node on top if possible
			if(nodedef->get(ntop).param_type == CPT_LIGHT)
				l = decode_light(ntop.getLightBlend(data->m_daynight_ratio, nodedef));
			// Otherwise use the light of this node (the liquid)
			else
				l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
			video::SColor c = MapBlock_LightColor(
					nodedef->get(n).alpha, l);
			
			// Neighbor liquid levels (key = relative position)
			// Includes current node
			core::map<v3s16, f32> neighbor_levels;
			core::map<v3s16, content_t> neighbor_contents;
			core::map<v3s16, u8> neighbor_flags;
			const u8 neighborflag_top_is_same_liquid = 0x01;
			v3s16 neighbor_dirs[9] = {
				v3s16(0,0,0),
				v3s16(0,0,1),
				v3s16(0,0,-1),
				v3s16(1,0,0),
				v3s16(-1,0,0),
				v3s16(1,0,1),
				v3s16(-1,0,-1),
				v3s16(1,0,-1),
				v3s16(-1,0,1),
			};
			for(u32 i=0; i<9; i++)
			{
				content_t content = CONTENT_AIR;
				float level = -0.5 * BS;
				u8 flags = 0;
				// Check neighbor
				v3s16 p2 = p + neighbor_dirs[i];
				MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
				if(n2.getContent() != CONTENT_IGNORE)
				{
					content = n2.getContent();

					if(n2.getContent() == c_source)
						level = (-0.5+node_liquid_level) * BS;
					else if(n2.getContent() == c_flowing)
						level = (-0.5 + ((float)(n2.param2&LIQUID_LEVEL_MASK)
								+ 0.5) / 8.0 * node_liquid_level) * BS;

					// Check node above neighbor.
					// NOTE: This doesn't get executed if neighbor
					//       doesn't exist
					p2.Y += 1;
					n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
					if(n2.getContent() == c_source ||
							n2.getContent() == c_flowing)
						flags |= neighborflag_top_is_same_liquid;
				}
				
				neighbor_levels.insert(neighbor_dirs[i], level);
				neighbor_contents.insert(neighbor_dirs[i], content);
				neighbor_flags.insert(neighbor_dirs[i], flags);
			}

			// Corner heights (average between four liquids)
			f32 corner_levels[4];
			
			v3s16 halfdirs[4] = {
				v3s16(0,0,0),
				v3s16(1,0,0),
				v3s16(1,0,1),
				v3s16(0,0,1),
			};
			for(u32 i=0; i<4; i++)
			{
				v3s16 cornerdir = halfdirs[i];
				float cornerlevel = 0;
				u32 valid_count = 0;
				u32 air_count = 0;
				for(u32 j=0; j<4; j++)
				{
					v3s16 neighbordir = cornerdir - halfdirs[j];
					content_t content = neighbor_contents[neighbordir];
					// If top is liquid, draw starting from top of node
					if(neighbor_flags[neighbordir] &
							neighborflag_top_is_same_liquid)
					{
						cornerlevel = 0.5*BS;
						valid_count = 1;
						break;
					}
					// Source is always the same height
					else if(content == c_source)
					{
						cornerlevel = (-0.5+node_liquid_level)*BS;
						valid_count = 1;
						break;
					}
					// Flowing liquid has level information
					else if(content == c_flowing)
					{
						cornerlevel += neighbor_levels[neighbordir];
						valid_count++;
					}
					else if(content == CONTENT_AIR)
					{
						air_count++;
					}
				}
				if(air_count >= 2)
					cornerlevel = -0.5*BS;
				else if(valid_count > 0)
					cornerlevel /= valid_count;
				corner_levels[i] = cornerlevel;
			}

			/*
				Generate sides
			*/

			v3s16 side_dirs[4] = {
				v3s16(1,0,0),
				v3s16(-1,0,0),
				v3s16(0,0,1),
				v3s16(0,0,-1),
			};
			s16 side_corners[4][2] = {
				{1, 2},
				{3, 0},
				{2, 3},
				{0, 1},
			};
			for(u32 i=0; i<4; i++)
			{
				v3s16 dir = side_dirs[i];

				/*
					If our topside is liquid and neighbor's topside
					is liquid, don't draw side face
				*/
				if(top_is_same_liquid &&
						neighbor_flags[dir] & neighborflag_top_is_same_liquid)
					continue;

				content_t neighbor_content = neighbor_contents[dir];
				const ContentFeatures &n_feat = nodedef->get(neighbor_content);
				
				// Don't draw face if neighbor is blocking the view
				if(n_feat.solidness == 2)
					continue;
				
				bool neighbor_is_same_liquid = (neighbor_content == c_source
						|| neighbor_content == c_flowing);
				
				// Don't draw any faces if neighbor same is liquid and top is
				// same liquid
				if(neighbor_is_same_liquid == true
						&& top_is_same_liquid == false)
					continue;

				// Use backface culled material if neighbor doesn't have a
				// solidness of 0
				video::SMaterial *current_material = &liquid_material;
				if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
					current_material = &liquid_material_bfculled;
				
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
							pa_liquid1.x0(), pa_liquid1.y1()),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
							pa_liquid1.x1(), pa_liquid1.y1()),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
							pa_liquid1.x1(), pa_liquid1.y0()),
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
							pa_liquid1.x0(), pa_liquid1.y0()),
				};
				
				/*
					If our topside is liquid, set upper border of face
					at upper border of node
				*/
				if(top_is_same_liquid)
				{
					vertices[2].Pos.Y = 0.5*BS;
					vertices[3].Pos.Y = 0.5*BS;
				}
				/*
					Otherwise upper position of face is corner levels
				*/
				else
				{
					vertices[2].Pos.Y = corner_levels[side_corners[i][0]];
					vertices[3].Pos.Y = corner_levels[side_corners[i][1]];
				}
				
				/*
					If neighbor is liquid, lower border of face is corner
					liquid levels
				*/
				if(neighbor_is_same_liquid)
				{
					vertices[0].Pos.Y = corner_levels[side_corners[i][1]];
					vertices[1].Pos.Y = corner_levels[side_corners[i][0]];
				}
				/*
					If neighbor is not liquid, lower border of face is
					lower border of node
				*/
				else
				{
					vertices[0].Pos.Y = -0.5*BS;
					vertices[1].Pos.Y = -0.5*BS;
				}
				
				for(s32 j=0; j<4; j++)
				{
					if(dir == v3s16(0,0,1))
						vertices[j].Pos.rotateXZBy(0);
					if(dir == v3s16(0,0,-1))
						vertices[j].Pos.rotateXZBy(180);
					if(dir == v3s16(-1,0,0))
						vertices[j].Pos.rotateXZBy(90);
					if(dir == v3s16(1,0,-0))
						vertices[j].Pos.rotateXZBy(-90);
						
					// Do this to not cause glitches when two liquids are
					// side-by-side
					/*if(neighbor_is_same_liquid == false){
						vertices[j].Pos.X *= 0.98;
						vertices[j].Pos.Z *= 0.98;
					}*/

					vertices[j].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(*current_material, vertices, 4, indices, 6);
			}
			
			/*
				Generate top side, if appropriate
			*/
			
			if(top_is_same_liquid == false)
			{
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c,
							pa_liquid1.x0(), pa_liquid1.y1()),
					video::S3DVertex(BS/2,0,BS/2, 0,0,0, c,
							pa_liquid1.x1(), pa_liquid1.y1()),
					video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c,
							pa_liquid1.x1(), pa_liquid1.y0()),
					video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c,
							pa_liquid1.x0(), pa_liquid1.y0()),
				};
				
				// This fixes a strange bug
				s32 corner_resolve[4] = {3,2,1,0};

				for(s32 i=0; i<4; i++)
				{
					//vertices[i].Pos.Y += liquid_level;
					//vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)];
					s32 j = corner_resolve[i];
					vertices[i].Pos.Y += corner_levels[j];
					vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(liquid_material, vertices, 4, indices, 6);
			}
		break;}
		case NDT_GLASSLIKE:
		{
			video::SMaterial material_glass;
			material_glass.setFlag(video::EMF_LIGHTING, false);
			material_glass.setFlag(video::EMF_BILINEAR_FILTER, false);
			material_glass.setFlag(video::EMF_FOG_ENABLE, true);
			material_glass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			AtlasPointer pa_glass = f.tiles[0].texture;
			material_glass.setTexture(0, pa_glass.atlas);

			u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
			video::SColor c = MapBlock_LightColor(255, l);

			for(u32 j=0; j<6; j++)
			{
				// Check this neighbor
				v3s16 n2p = blockpos_nodes + p + g_6dirs[j];
				MapNode n2 = data->m_vmanip.getNodeNoEx(n2p);
				// Don't make face if neighbor is of same type
				if(n2.getContent() == n.getContent())
					continue;

				// The face at Z+
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
						pa_glass.x0(), pa_glass.y1()),
					video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
						pa_glass.x1(), pa_glass.y1()),
					video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
						pa_glass.x1(), pa_glass.y0()),
					video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
						pa_glass.x0(), pa_glass.y0()),
				};
				
				// Rotations in the g_6dirs format
				if(j == 0) // Z+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(0);
				else if(j == 1) // Y+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(-90);
				else if(j == 2) // X+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-90);
				else if(j == 3) // Z-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(180);
				else if(j == 4) // Y-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(90);
				else if(j == 5) // X-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(90);

				for(u16 i=0; i<4; i++){
					vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(material_glass, vertices, 4, indices, 6);
			}
		break;}
		case NDT_ALLFACES:
		{
			video::SMaterial material_leaves1;
			material_leaves1.setFlag(video::EMF_LIGHTING, false);
			material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false);
			material_leaves1.setFlag(video::EMF_FOG_ENABLE, true);
			material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			AtlasPointer pa_leaves1 = f.tiles[0].texture;
			material_leaves1.setTexture(0, pa_leaves1.atlas);

			u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
			video::SColor c = MapBlock_LightColor(255, l);

			for(u32 j=0; j<6; j++)
			{
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c,
						pa_leaves1.x0(), pa_leaves1.y1()),
					video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c,
						pa_leaves1.x1(), pa_leaves1.y1()),
					video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c,
						pa_leaves1.x1(), pa_leaves1.y0()),
					video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c,
						pa_leaves1.x0(), pa_leaves1.y0()),
				};

				// Rotations in the g_6dirs format
				if(j == 0) // Z+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(0);
				else if(j == 1) // Y+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(-90);
				else if(j == 2) // X+
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-90);
				else if(j == 3) // Z-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(180);
				else if(j == 4) // Y-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateYZBy(90);
				else if(j == 5) // X-
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(90);

				for(u16 i=0; i<4; i++){
					vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(material_leaves1, vertices, 4, indices, 6);
			}
		break;}
		case NDT_ALLFACES_OPTIONAL:
			// This is always pre-converted to something else
			assert(0);
			break;
		case NDT_TORCHLIKE:
		{
			v3s16 dir = unpackDir(n.param2);
			
			AtlasPointer ap(0);
			if(dir == v3s16(0,-1,0)){
				ap = f.tiles[0].texture; // floor
			} else if(dir == v3s16(0,1,0)){
				ap = f.tiles[1].texture; // ceiling
			// For backwards compatibility
			} else if(dir == v3s16(0,0,0)){
				ap = f.tiles[0].texture; // floor
			} else {
				ap = f.tiles[2].texture; // side
			}

			// Set material
			video::SMaterial material;
			material.setFlag(video::EMF_LIGHTING, false);
			material.setFlag(video::EMF_BACK_FACE_CULLING, false);
			material.setFlag(video::EMF_BILINEAR_FILTER, false);
			material.setFlag(video::EMF_FOG_ENABLE, true);
			//material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
			material.MaterialType
					= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			material.setTexture(0, ap.atlas);

			video::SColor c(255,255,255,255);

			// Wall at X+ of node
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c,
						ap.x0(), ap.y1()),
				video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c,
						ap.x1(), ap.y1()),
				video::S3DVertex(BS/2,BS/2,0, 0,0,0, c,
						ap.x1(), ap.y0()),
				video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c,
						ap.x0(), ap.y0()),
			};

			for(s32 i=0; i<4; i++)
			{
				if(dir == v3s16(1,0,0))
					vertices[i].Pos.rotateXZBy(0);
				if(dir == v3s16(-1,0,0))
					vertices[i].Pos.rotateXZBy(180);
				if(dir == v3s16(0,0,1))
					vertices[i].Pos.rotateXZBy(90);
				if(dir == v3s16(0,0,-1))
					vertices[i].Pos.rotateXZBy(-90);
				if(dir == v3s16(0,-1,0))
					vertices[i].Pos.rotateXZBy(45);
				if(dir == v3s16(0,1,0))
					vertices[i].Pos.rotateXZBy(-45);

				vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
			}

			u16 indices[] = {0,1,2,2,3,0};
			// Add to mesh collector
			collector.append(material, vertices, 4, indices, 6);
		break;}
		case NDT_SIGNLIKE:
		{
			// Set material
			video::SMaterial material;
			material.setFlag(video::EMF_LIGHTING, false);
			material.setFlag(video::EMF_BACK_FACE_CULLING, false);
			material.setFlag(video::EMF_BILINEAR_FILTER, false);
			material.setFlag(video::EMF_FOG_ENABLE, true);
			material.MaterialType
					= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			AtlasPointer ap = f.tiles[0].texture;
			material.setTexture(0, ap.atlas);

			u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
			video::SColor c = MapBlock_LightColor(255, l);
				
			float d = (float)BS/16;
			// Wall at X+ of node
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c,
						ap.x0(), ap.y1()),
				video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c,
						ap.x1(), ap.y1()),
				video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c,
						ap.x1(), ap.y0()),
				video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c,
						ap.x0(), ap.y0()),
			};

			v3s16 dir = unpackDir(n.param2);

			for(s32 i=0; i<4; i++)
			{
				if(dir == v3s16(1,0,0))
					vertices[i].Pos.rotateXZBy(0);
				if(dir == v3s16(-1,0,0))
					vertices[i].Pos.rotateXZBy(180);
				if(dir == v3s16(0,0,1))
					vertices[i].Pos.rotateXZBy(90);
				if(dir == v3s16(0,0,-1))
					vertices[i].Pos.rotateXZBy(-90);
				if(dir == v3s16(0,-1,0))
					vertices[i].Pos.rotateXYBy(-90);
				if(dir == v3s16(0,1,0))
					vertices[i].Pos.rotateXYBy(90);

				vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
			}

			u16 indices[] = {0,1,2,2,3,0};
			// Add to mesh collector
			collector.append(material, vertices, 4, indices, 6);
		break;}
		case NDT_PLANTLIKE:
		{
			video::SMaterial material_papyrus;
			material_papyrus.setFlag(video::EMF_LIGHTING, false);
			material_papyrus.setFlag(video::EMF_BILINEAR_FILTER, false);
			material_papyrus.setFlag(video::EMF_FOG_ENABLE, true);
			material_papyrus.MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			AtlasPointer pa_papyrus = f.tiles[0].texture;
			material_papyrus.setTexture(0, pa_papyrus.atlas);
			
			u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
			video::SColor c = MapBlock_LightColor(255, l);

			for(u32 j=0; j<4; j++)
			{
				video::S3DVertex vertices[4] =
				{
					video::S3DVertex(-BS/2*f.visual_scale,-BS/2,0, 0,0,0, c,
						pa_papyrus.x0(), pa_papyrus.y1()),
					video::S3DVertex( BS/2*f.visual_scale,-BS/2,0, 0,0,0, c,
						pa_papyrus.x1(), pa_papyrus.y1()),
					video::S3DVertex( BS/2*f.visual_scale,
						-BS/2 + f.visual_scale*BS,0, 0,0,0, c,
						pa_papyrus.x1(), pa_papyrus.y0()),
					video::S3DVertex(-BS/2*f.visual_scale,
						-BS/2 + f.visual_scale*BS,0, 0,0,0, c,
						pa_papyrus.x0(), pa_papyrus.y0()),
				};

				if(j == 0)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(45);
				}
				else if(j == 1)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-45);
				}
				else if(j == 2)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(135);
				}
				else if(j == 3)
				{
					for(u16 i=0; i<4; i++)
						vertices[i].Pos.rotateXZBy(-135);
				}

				for(u16 i=0; i<4; i++)
				{
					vertices[i].Pos *= f.visual_scale;
					vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
				}

				u16 indices[] = {0,1,2,2,3,0};
				// Add to mesh collector
				collector.append(material_papyrus, vertices, 4, indices, 6);
			}
		break;}
		case NDT_FENCELIKE:
		{
			video::SMaterial material_wood;
			material_wood.setFlag(video::EMF_LIGHTING, false);
			material_wood.setFlag(video::EMF_BILINEAR_FILTER, false);
			material_wood.setFlag(video::EMF_FOG_ENABLE, true);
			material_wood.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			AtlasPointer pa_wood = f.tiles[0].texture;
			material_wood.setTexture(0, pa_wood.atlas);

			u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef)));
			video::SColor c = MapBlock_LightColor(255, l);

			const f32 post_rad=(f32)BS/10;
			const f32 bar_rad=(f32)BS/20;
			const f32 bar_len=(f32)(BS/2)-post_rad;

			// The post - always present
			v3f pos = intToFloat(p+blockpos_nodes, BS);
			f32 postuv[24]={
					0.4,0.4,0.6,0.6,
					0.35,0,0.65,1,
					0.35,0,0.65,1,
					0.35,0,0.65,1,
					0.35,0,0.65,1,
					0.4,0.4,0.6,0.6};
			makeCuboid(material_wood, &collector,
				&pa_wood, c, pos,
				post_rad,BS/2,post_rad, postuv);

			// Now a section of fence, +X, if there's a post there
			v3s16 p2 = p;
			p2.X++;
			MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
			const ContentFeatures *f2 = &nodedef->get(n2);
			if(f2->drawtype == NDT_FENCELIKE)
			{
				pos = intToFloat(p+blockpos_nodes, BS);
				pos.X += BS/2;
				pos.Y += BS/4;
				f32 xrailuv[24]={
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6};
				makeCuboid(material_wood, &collector,
					&pa_wood, c, pos,
					bar_len,bar_rad,bar_rad, xrailuv);

				pos.Y -= BS/2;
				makeCuboid(material_wood, &collector,
					&pa_wood, c, pos,
					bar_len,bar_rad,bar_rad, xrailuv);
			}

			// Now a section of fence, +Z, if there's a post there
			p2 = p;
			p2.Z++;
			n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
			f2 = &nodedef->get(n2);
			if(f2->drawtype == NDT_FENCELIKE)
			{
				pos = intToFloat(p+blockpos_nodes, BS);
				pos.Z += BS/2;
				pos.Y += BS/4;
				f32 zrailuv[24]={
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6,
					0,0.4,1,0.6};
				makeCuboid(material_wood, &collector,
					&pa_wood, c, pos,
					bar_rad,bar_rad,bar_len, zrailuv);
				pos.Y -= BS/2;
				makeCuboid(material_wood, &collector,
					&pa_wood, c, pos,
					bar_rad,bar_rad,bar_len, zrailuv);

			}
		break;}
		case NDT_RAILLIKE:
		{
			bool is_rail_x [] = { false, false };  /* x-1, x+1 */
			bool is_rail_z [] = { false, false };  /* z-1, z+1 */

			MapNode n_minus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1,y,z));
			MapNode n_plus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1,y,z));
			MapNode n_minus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z-1));
			MapNode n_plus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z+1));
			
			content_t thiscontent = n.getContent();
			if(n_minus_x.getContent() == thiscontent)
				is_rail_x[0] = true;
			if(n_plus_x.getContent() == thiscontent)
				is_rail_x[1] = true;
			if(n_minus_z.getContent() == thiscontent)
				is_rail_z[0] = true;
			if(n_plus_z.getContent() == thiscontent)
				is_rail_z[1] = true;

			int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1];

			// Assign textures
			AtlasPointer ap = f.tiles[0].texture; // straight
			if(adjacencies < 2)
				ap = f.tiles[0].texture; // straight
			else if(adjacencies == 2)
			{
				if((is_rail_x[0] && is_rail_x[1]) || (is_rail_z[0] && is_rail_z[1]))
					ap = f.tiles[0].texture; // straight
				else
					ap = f.tiles[1].texture; // curved
			}
			else if(adjacencies == 3)
				ap = f.tiles[2].texture; // t-junction
			else if(adjacencies == 4)
				ap = f.tiles[3].texture; // crossing
			
			video::SMaterial material_rail;
			material_rail.setFlag(video::EMF_LIGHTING, false);
			material_rail.setFlag(video::EMF_BACK_FACE_CULLING, false);
			material_rail.setFlag(video::EMF_BILINEAR_FILTER, false);
			material_rail.setFlag(video::EMF_FOG_ENABLE, true);
			material_rail.MaterialType
					= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
			material_rail.setTexture(0, ap.atlas);

			u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef));
			video::SColor c = MapBlock_LightColor(255, l);

			float d = (float)BS/16;
			video::S3DVertex vertices[4] =
			{
				video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c,
						ap.x0(), ap.y1()),
				video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c,
						ap.x1(), ap.y1()),
				video::S3DVertex(BS/2,-BS/2+d,BS/2, 0,0,0, c,
						ap.x1(), ap.y0()),
				video::S3DVertex(-BS/2,-BS/2+d,BS/2, 0,0,0, c,
						ap.x0(), ap.y0()),
			};

			// Rotate textures
			int angle = 0;

			if(adjacencies == 1)
			{
				if(is_rail_x[0] || is_rail_x[1])
					angle = 90;
			}
			else if(adjacencies == 2)
			{
				if(is_rail_x[0] && is_rail_x[1])
					angle = 90;
				else if(is_rail_x[0] && is_rail_z[0])
					angle = 270;
				else if(is_rail_x[0] && is_rail_z[1])
					angle = 180;
				else if(is_rail_x[1] && is_rail_z[1])
					angle = 90;
			}
			else if(adjacencies == 3)
			{
				if(!is_rail_x[0])
					angle=0;
				if(!is_rail_x[1])
					angle=180;
				if(!is_rail_z[0])
					angle=90;
				if(!is_rail_z[1])
					angle=270;
			}

			if(angle != 0) {
				for(u16 i=0; i<4; i++)
					vertices[i].Pos.rotateXZBy(angle);
			}

			for(s32 i=0; i<4; i++)
			{
				vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
			}

			u16 indices[] = {0,1,2,2,3,0};
			collector.append(material_rail, vertices, 4, indices, 6);
		break;}
		}
	}
}
Example #12
0
int
seed( osg::ArgumentParser& args )
{

    //Read the min level
    unsigned int minLevel = 0;
    while (args.read("--min-level", minLevel));

    //Read the max level
    unsigned int maxLevel = 5;
    while (args.read("--max-level", maxLevel));


    std::vector< Bounds > bounds;
    // restrict packaging to user-specified bounds.
    double xmin=DBL_MAX, ymin=DBL_MAX, xmax=DBL_MIN, ymax=DBL_MIN;
    while (args.read("--bounds", xmin, ymin, xmax, ymax ))
    {
        Bounds b;
        b.xMin() = xmin, b.yMin() = ymin, b.xMax() = xmax, b.yMax() = ymax;
        bounds.push_back( b );
    }

    //Read the cache override directory
    std::string cachePath;
    while (args.read("--cache-path", cachePath));

    //Read the cache type
    std::string cacheType;
    while (args.read("--cache-type", cacheType));

    bool verbose = args.read("--verbose");

    //Read in the earth file.
    osg::ref_ptr<osg::Node> node = osgDB::readNodeFiles( args );
    if ( !node.valid() )
        return usage( "Failed to read .earth file." );

    MapNode* mapNode = MapNode::findMapNode( node.get() );
    if ( !mapNode )
        return usage( "Input file was not a .earth file" );

    CacheSeed seeder;
    seeder.setMinLevel( minLevel );
    seeder.setMaxLevel( maxLevel );

    // Read in an index shapefile
    std::string index;
    while (args.read("--index", index))
    {
        //Open the feature source
        OGRFeatureOptions featureOpt;
        featureOpt.url() = index;

        osg::ref_ptr< FeatureSource > features = FeatureSourceFactory::create( featureOpt );
        features->initialize();
        features->getFeatureProfile();

        osg::ref_ptr< FeatureCursor > cursor = features->createFeatureCursor();
        while (cursor.valid() && cursor->hasMore())
        {
            osg::ref_ptr< Feature > feature = cursor->nextFeature();
            osgEarth::Bounds featureBounds = feature->getGeometry()->getBounds();
            GeoExtent ext( feature->getSRS(), featureBounds );
            ext = ext.transform( mapNode->getMapSRS() );
            bounds.push_back( ext.bounds() );
        }
    }

    for (unsigned int i = 0; i < bounds.size(); i++)
    {
        GeoExtent extent(mapNode->getMapSRS(), bounds[i]);
        OE_DEBUG << "Adding extent " << extent.toString() << std::endl;
        seeder.addExtent( extent );
    }
    if (verbose)
    {
        seeder.setProgressCallback(new ConsoleProgressCallback);
    }


    osg::Timer_t start = osg::Timer::instance()->tick();

    seeder.seed( mapNode->getMap() );

    osg::Timer_t end = osg::Timer::instance()->tick();

    OE_NOTICE << "Completed seeding in " << prettyPrintTime( osg::Timer::instance()->delta_s( start, end ) ) << std::endl;

    return 0;
}
Example #13
0
bool AstarMap::findPath(std::vector<MapNode*>& path, int sx, int sy, int tx, int ty)
{
	std::vector<MapNode*> open_stack;

	MapNode* start = getNodeAt(sy,sx);
	MapNode* target = getNodeAt(ty,tx);

	if(start == NULL || target == NULL)
		return false;
	
	start->setOpen(true);
	open_stack.push_back(start);

	while(open_stack.size() > 0){

		std::sort(open_stack.begin(), open_stack.end(), lesser);

		MapNode* node = open_stack.back();

		if(node == target)
			return buildPath(path,target);

		open_stack.pop_back();

		node->setOpen(false);
		node->setClosed(true);

		std::vector<MapNode*> adjacents;

		if(!listAdjacent(adjacents,node))
			continue;

		for(int i = 0; i < adjacents.size(); ++i){

			MapNode* adjacent = adjacents[i];

			if(adjacent->isClosed())
				continue;

			if(adjacent->isLocked())
				continue;

			int check_cost = adjacent->getCostG() + adjacent->isDiagonal(node) ?
				DIAGONAL_MOVE_COST : STRAIGHT_MOVE_COST;

			if(adjacent->isOpen()){

				adjacent->setParent(node);
				adjacent->setCostG(check_cost);

			}else{

				adjacent->setParent(node);
				adjacent->setCostH(adjacent->countHCost(target));
				adjacent->setCostG(check_cost);
				adjacent->setOpen(true);
				open_stack.push_back(adjacent);

			}

		}

	}

	return false;
}
        virtual ReadResult readNode(std::istream& in, const osgDB::Options* readOptions) const
        {
            // pull the URI context from the options structure (since we're reading
            // from an "anonymous" stream here)
            URIContext uriContext( readOptions ); 

            osg::ref_ptr<XmlDocument> doc = XmlDocument::load( in, uriContext );
            if ( !doc.valid() )
                return ReadResult::ERROR_IN_READING_FILE;

            Config docConf = doc->getConfig();

            // support both "map" and "earth" tag names at the top level
            Config conf;
            if ( docConf.hasChild( "map" ) )
                conf = docConf.child( "map" );
            else if ( docConf.hasChild( "earth" ) )
                conf = docConf.child( "earth" );

            osg::ref_ptr<osg::Node> node;

            if ( !conf.empty() )
            {
                // see if we were given a reference URI to use:
                std::string refURI = uriContext.referrer();

                if ( conf.value("version") == "1" )
                {
                    OE_INFO << LC << "Detected a version 1.x earth file" << std::endl;
                    EarthFileSerializer1 ser;
                    node = ser.deserialize( conf, refURI );
                }

                else
                {
                    if ( conf.value("version") != "2" )
                        OE_DEBUG << LC << "No valid earth file version; assuming version='2'" << std::endl;

                    // attempt to parse a "default options" JSON string:
                    std::string defaultConfStr;
                    if ( readOptions )
                    {
                        defaultConfStr = readOptions->getPluginStringData("osgEarth.defaultOptions");
                        if ( !defaultConfStr.empty() )
                        {
                            Config optionsConf("options");
                            if (optionsConf.fromJSON(defaultConfStr))
                            {
                                //OE_NOTICE << "\n\nOriginal = \n" << conf.toJSON(true) << "\n";
                                Config* original = conf.mutable_child("options");
                                if ( original )
                                {
                                    recursiveUniqueKeyMerge(optionsConf, *original);
                                }
                                if ( !optionsConf.empty() )
                                {
                                    conf.set("options", optionsConf);
                                }
                                //OE_NOTICE << "\n\nMerged = \n" << conf.toJSON(true) << "\n";
                            }
                        }
                    }

                    EarthFileSerializer2 ser;
                    node = ser.deserialize( conf, refURI );
                }
            }

            MapNode* mapNode = MapNode::get(node.get());
            if (mapNode)
            {
                // If the user passed in a cache object, apply it to the map now
                CacheSettings* cacheSettings = CacheSettings::get(readOptions);
                if (cacheSettings && cacheSettings->getCache())
                {
                    mapNode->getMap()->setCache( cacheSettings->getCache() );
                    OE_INFO << LC << "Applied user-supplied cache to the Map\n";
                }
            }

            return ReadResult(node.get());
        }
Example #15
0
void MapBlockObjectList::update(std::istream &is, u8 version,
		scene::ISceneManager *smgr, u32 daynight_ratio)
{
	JMutexAutoLock lock(m_mutex);

	/*
		Collect all existing ids to a set.

		As things are updated, they are removed from this.

		All remaining ones are deleted.
	*/
	core::map<s16, bool> ids_to_delete;
	for(core::map<s16, MapBlockObject*>::Iterator
			i = m_objects.getIterator();
			i.atEnd() == false; i++)
	{
		ids_to_delete.insert(i.getNode()->getKey(), true);
	}
	
	u8 buf[6];
	
	is.read((char*)buf, 2);
	u16 count = readU16(buf);

	for(u16 i=0; i<count; i++)
	{
		// Read id
		is.read((char*)buf, 2);
		s16 id = readS16(buf);
		
		// Read position
		// stored as x1000/BS v3s16
		is.read((char*)buf, 6);
		v3s16 pos_i = readV3S16(buf);
		v3f pos((f32)pos_i.X/1000*BS,
				(f32)pos_i.Y/1000*BS,
				(f32)pos_i.Z/1000*BS);

		// Read typeId
		is.read((char*)buf, 2);
		u16 type_id = readU16(buf);
		
		bool create_new = false;

		// Find an object with the id
		core::map<s16, MapBlockObject*>::Node *n;
		n = m_objects.find(id);
		// If no entry is found for id
		if(n == NULL)
		{
			// Insert dummy pointer node
			m_objects.insert(id, NULL);
			// Get node
			n = m_objects.find(id);
			// A new object will be created at this node
			create_new = true;
		}
		// If type_id differs
		else if(n->getValue()->getTypeId() != type_id)
		{
			// Delete old object
			delete n->getValue();
			// A new object will be created at this node
			create_new = true;
		}

		MapBlockObject *obj = NULL;

		if(create_new)
		{
			/*dstream<<"MapBlockObjectList adding new object"
					" id="<<id
					<<std::endl;*/

			if(type_id == MAPBLOCKOBJECT_TYPE_SIGN)
			{
				obj = new SignObject(m_block, id, pos);
			}
			else if(type_id == MAPBLOCKOBJECT_TYPE_RAT)
			{
				obj = new RatObject(m_block, id, pos);
			}
			else if(type_id == MAPBLOCKOBJECT_TYPE_ITEM)
			{
				obj = new ItemObject(m_block, id, pos);
			}
			else
			{
				// This is fatal because we cannot know the length
				// of the object's data
				throw SerializationError
				("MapBlockObjectList::update(): Unknown MapBlockObject type");
			}

			if(smgr != NULL)
				//obj->addToScene(smgr, daynight_ratio);
				obj->addToScene(smgr);

			n->setValue(obj);
		}
		else
		{
			obj = n->getValue();
			obj->updatePos(pos);
			/*if(daynight_ratio != m_last_update_daynight_ratio)
			{
				obj->removeFromScene();
				obj->addToScene(smgr, daynight_ratio);
			}*/
		}

		// Now there is an object in obj.
		// Update it.
		
		obj->update(is, version);
		obj->setBlockChanged();

		/*
			Update light on client
		*/
		if(smgr != NULL)
		{
			u8 light = LIGHT_MAX;
			try{
				v3s16 relpos_i = floatToInt(obj->m_pos, BS);
				MapNode n = m_block->getNodeParent(relpos_i);
				light = n.getLightBlend(daynight_ratio);
			}
			catch(InvalidPositionException &e) {}
			obj->updateLight(light);
		}
		
		// Remove from deletion list
		if(ids_to_delete.find(id) != NULL)
			ids_to_delete.remove(id);
	}

	// Delete all objects whose ids_to_delete remain in ids_to_delete
	for(core::map<s16, bool>::Iterator
			i = ids_to_delete.getIterator();
			i.atEnd() == false; i++)
	{
		s16 id = i.getNode()->getKey();

		/*dstream<<"MapBlockObjectList deleting object"
				" id="<<id
				<<std::endl;*/

		MapBlockObject *obj = m_objects[id];
		obj->removeFromScene();
		delete obj;
		m_objects.remove(id);
	}

	m_last_update_daynight_ratio = daynight_ratio;
}
Example #16
0
/*
	Propagates sunlight down through the block.
	Doesn't modify nodes that are not affected by sunlight.
	
	Returns false if sunlight at bottom block is invalid.
	Returns true if sunlight at bottom block is valid.
	Returns true if bottom block doesn't exist.

	If there is a block above, continues from it.
	If there is no block above, assumes there is sunlight, unless
	is_underground is set or highest node is water.

	All sunlighted nodes are added to light_sources.

	if remove_light==true, sets non-sunlighted nodes black.

	if black_air_left!=NULL, it is set to true if non-sunlighted
	air is left in block.
*/
bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
		bool remove_light, bool *black_air_left)
{
	INodeDefManager *nodemgr = m_gamedef->ndef();

	// Whether the sunlight at the top of the bottom block is valid
	bool block_below_is_valid = true;
	
	v3s16 pos_relative = getPosRelative();
	
	for(s16 x=0; x<MAP_BLOCKSIZE; x++)
	{
		for(s16 z=0; z<MAP_BLOCKSIZE; z++)
		{
#if 1
			bool no_sunlight = false;
			bool no_top_block = false;
			// Check if node above block has sunlight
			try{
				MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
				if(n.getContent() == CONTENT_IGNORE)
				{
					// Trust heuristics
					no_sunlight = is_underground;
				}
				else if(n.getLight(LIGHTBANK_DAY, m_gamedef->ndef()) != LIGHT_SUN)
				{
					no_sunlight = true;
				}
			}
			catch(InvalidPositionException &e)
			{
				no_top_block = true;
				
				// NOTE: This makes over-ground roofed places sunlighted
				// Assume sunlight, unless is_underground==true
				if(is_underground)
				{
					no_sunlight = true;
				}
				else
				{
					MapNode n = getNode(v3s16(x, MAP_BLOCKSIZE-1, z));
					if(m_gamedef->ndef()->get(n).sunlight_propagates == false)
					{
						no_sunlight = true;
					}
				}
				// NOTE: As of now, this just would make everything dark.
				// No sunlight here
				//no_sunlight = true;
			}
#endif
#if 0 // Doesn't work; nothing gets light.
			bool no_sunlight = true;
			bool no_top_block = false;
			// Check if node above block has sunlight
			try{
				MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
				if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
				{
					no_sunlight = false;
				}
			}
			catch(InvalidPositionException &e)
			{
				no_top_block = true;
			}
#endif

			/*std::cout<<"("<<x<<","<<z<<"): "
					<<"no_top_block="<<no_top_block
					<<", is_underground="<<is_underground
					<<", no_sunlight="<<no_sunlight
					<<std::endl;*/
		
			s16 y = MAP_BLOCKSIZE-1;
			
			// This makes difference to diminishing in water.
			bool stopped_to_solid_object = false;
			
			u8 current_light = no_sunlight ? 0 : LIGHT_SUN;

			for(; y >= 0; y--)
			{
				v3s16 pos(x, y, z);
				MapNode &n = getNodeRef(pos);
				
				if(current_light == 0)
				{
					// Do nothing
				}
				else if(current_light == LIGHT_SUN && nodemgr->get(n).sunlight_propagates)
				{
					// Do nothing: Sunlight is continued
				}
				else if(nodemgr->get(n).light_propagates == false)
				{
					// A solid object is on the way.
					stopped_to_solid_object = true;
					
					// Light stops.
					current_light = 0;
				}
				else
				{
					// Diminish light
					current_light = diminish_light(current_light);
				}

				u8 old_light = n.getLight(LIGHTBANK_DAY, nodemgr);

				if(current_light > old_light || remove_light)
				{
					n.setLight(LIGHTBANK_DAY, current_light, nodemgr);
				}
				
				if(diminish_light(current_light) != 0)
				{
					light_sources.insert(pos_relative + pos, true);
				}

				if(current_light == 0 && stopped_to_solid_object)
				{
					if(black_air_left)
					{
						*black_air_left = true;
					}
				}
			}

			// Whether or not the block below should see LIGHT_SUN
			bool sunlight_should_go_down = (current_light == LIGHT_SUN);

			/*
				If the block below hasn't already been marked invalid:

				Check if the node below the block has proper sunlight at top.
				If not, the block below is invalid.
				
				Ignore non-transparent nodes as they always have no light
			*/
			try
			{
			if(block_below_is_valid)
			{
				MapNode n = getNodeParent(v3s16(x, -1, z));
				if(nodemgr->get(n).light_propagates)
				{
					if(n.getLight(LIGHTBANK_DAY, nodemgr) == LIGHT_SUN
							&& sunlight_should_go_down == false)
						block_below_is_valid = false;
					else if(n.getLight(LIGHTBANK_DAY, nodemgr) != LIGHT_SUN
							&& sunlight_should_go_down == true)
						block_below_is_valid = false;
				}
			}//if
			}//try
			catch(InvalidPositionException &e)
			{
				/*std::cout<<"InvalidBlockException for bottom block node"
						<<std::endl;*/
				// Just no block below, no need to panic.
			}
		}
	}

	return block_below_is_valid;
}
Example #17
0
void MapBlockObjectList::step(float dtime, bool server, u32 daynight_ratio)
{
	DSTACK(__FUNCTION_NAME);
	
	JMutexAutoLock lock(m_mutex);

	if(m_objects.empty())
		return;

	core::map<s16, bool> ids_to_delete;

	{
		DSTACKF("%s: stepping objects", __FUNCTION_NAME);

		for(core::map<s16, MapBlockObject*>::Iterator
				i = m_objects.getIterator();
				i.atEnd() == false; i++)
		{
			MapBlockObject *obj = i.getNode()->getValue();
			
			DSTACKF("%s: stepping object type %i", __FUNCTION_NAME,
					obj->getTypeId());

			obj->setBlockChanged();

			if(server)
			{
				// Update light
				u8 light = LIGHT_MAX;
				try{
					v3s16 relpos_i = floatToInt(obj->m_pos, BS);
					MapNode n = m_block->getNodeParent(relpos_i);
					light = n.getLightBlend(daynight_ratio);
				}
				catch(InvalidPositionException &e) {}
				obj->updateLight(light);
				
				bool to_delete = obj->serverStep(dtime, daynight_ratio);

				if(to_delete)
					ids_to_delete.insert(obj->m_id, true);
			}
			else
			{
				obj->clientStep(dtime);
			}
		}
	}

	{
		DSTACKF("%s: deleting objects", __FUNCTION_NAME);

		// Delete objects in delete queue
		for(core::map<s16, bool>::Iterator
				i = ids_to_delete.getIterator();
				i.atEnd() == false; i++)
		{
			s16 id = i.getNode()->getKey();

			MapBlockObject *obj = m_objects[id];
			obj->setBlockChanged();
			obj->removeFromScene();
			delete obj;
			m_objects.remove(id);
		}
	}
	
	/*
		Wrap objects on server
	*/

	if(server == false)
		return;
	
	{
		DSTACKF("%s: object wrap loop", __FUNCTION_NAME);

		for(core::map<s16, MapBlockObject*>::Iterator
				i = m_objects.getIterator();
				i.atEnd() == false; i++)
		{
			MapBlockObject *obj = i.getNode()->getValue();

			v3s16 pos_i = floatToInt(obj->m_pos, BS);

			if(m_block->isValidPosition(pos_i))
			{
				// No wrap
				continue;
			}

			bool impossible = wrapObject(obj);

			if(impossible)
			{
				// No wrap
				continue;
			}

			obj->setBlockChanged();

			// Restart find
			i = m_objects.getIterator();
		}
	}
}
Example #18
0
/*
	Get a quick string to describe what a block actually contains
*/
std::string analyze_block(MapBlock *block)
{
	if(block == NULL)
		return "NULL";

	std::ostringstream desc;
	
	v3s16 p = block->getPos();
	char spos[20];
	snprintf(spos, 20, "(%2d,%2d,%2d), ", p.X, p.Y, p.Z);
	desc<<spos;
	
	switch(block->getModified())
	{
	case MOD_STATE_CLEAN:
		desc<<"CLEAN,           ";
		break;
	case MOD_STATE_WRITE_AT_UNLOAD:
		desc<<"WRITE_AT_UNLOAD, ";
		break;
	case MOD_STATE_WRITE_NEEDED:
		desc<<"WRITE_NEEDED,    ";
		break;
	default:
		desc<<"unknown getModified()="+itos(block->getModified())+", ";
	}

	if(block->isGenerated())
		desc<<"is_gen [X], ";
	else
		desc<<"is_gen [ ], ";

	if(block->getIsUnderground())
		desc<<"is_ug [X], ";
	else
		desc<<"is_ug [ ], ";

#ifndef SERVER
	if(block->getMeshExpired())
		desc<<"mesh_exp [X], ";
	else
		desc<<"mesh_exp [ ], ";
#endif

	if(block->getLightingExpired())
		desc<<"lighting_exp [X], ";
	else
		desc<<"lighting_exp [ ], ";

	if(block->isDummy())
	{
		desc<<"Dummy, ";
	}
	else
	{
		bool full_ignore = true;
		bool some_ignore = false;
		bool full_air = true;
		bool some_air = false;
		for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
		for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
		for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
		{
			v3s16 p(x0,y0,z0);
			MapNode n = block->getNode(p);
			content_t c = n.getContent();
			if(c == CONTENT_IGNORE)
				some_ignore = true;
			else
				full_ignore = false;
			if(c == CONTENT_AIR)
				some_air = true;
			else
				full_air = false;
		}
		
		desc<<"content {";
		
		std::ostringstream ss;
		
		if(full_ignore)
			ss<<"IGNORE (full), ";
		else if(some_ignore)
			ss<<"IGNORE, ";
		
		if(full_air)
			ss<<"AIR (full), ";
		else if(some_air)
			ss<<"AIR, ";
		
		if(ss.str().size()>=2)
			desc<<ss.str().substr(0, ss.str().size()-2);

		desc<<"}, ";
	}

	return desc.str().substr(0, desc.str().size()-2);
}
/** This function can be optimized*/
void ManifoldVoronoiExtractor::process(Serializable* s)
{
    put(s);
    NewKeyNodeMessage* km = dynamic_cast<NewKeyNodeMessage*>(s);
    int cx = _xSize * 0.5;
    int cy = _ySize * 0.5;
    float ires = 1./_resolution;
    if(km)
    {
        PwnCloudCache::HandleType h = _cache->get((SyncSensorDataNode*) km->keyNode);
        cacheHandles.push_back(h);
        while(cacheHandles.size() > _dequeSize)
        {
            cacheHandles.pop_front();
        }
        MapNode* n = km->keyNode;
        Isometry3d inT = n->transform().inverse();

        ManifoldVoronoiData* vdata = new ManifoldVoronoiData();
        vdata->resolution = _resolution;
        boss_map::ImageBLOB* imageBlob = new boss_map::ImageBLOB();
        imageBlob->cvImage().create(_xSize,_ySize, CV_16UC1);
        imageBlob->cvImage().setTo(30000);
        imageBlob->adjustFormat();
        vdata->setTimestamp(0);
        uint16_t obstacle = 65535;
        for(list<PwnCloudCache::HandleType>::iterator it = cacheHandles.begin(); it != cacheHandles.end(); it++)
        {
            PwnCloudCache::HandleType& h = *it;
            CloudWithImageSize* cloud_ = h.get();
            MapNode* cn = h.key();
            Isometry3d currentTransform=inT * cn->transform();
            pwn::Cloud cloud = *cloud_;
            Isometry3f  currentTransformf;
            convertScalar(currentTransformf, currentTransform);
            cloud.transformInPlace( currentTransformf);

            for(size_t i = 0; i < cloud.points().size(); i++)
            {
                pwn::Normal& n = cloud.normals()[i];
                pwn::Point& p = cloud.points()[i];
                int x = cx + p.x()*ires;
                int y = cy + p.y()*ires;
                if ( (x<0) ||
                     (x>=_xSize) ||
                     (y < 0) ||
                     (y>=_ySize) ){
                    continue;
                }
                uint16_t& imZ = imageBlob->cvImage().at<uint16_t>(x,y);
                int pz =  10000 - 1000 * p.z();
                if(imZ == obstacle)
                {
                    continue;
                }
                if(imZ < pz)
                {
                    continue;
                }
                if(n.squaredNorm() < 0.1)
                {
                    continue;
                }
                if(n.z() < _normalThreshold)
                {
                    imZ = obstacle;
                }
                else
                {
                    imZ = pz;
                }
            }
        }
        vdata->imageBlob().set(imageBlob);
        vdata->node = n;
        put(vdata);
    }
}
Example #20
0
/*
	Calculate smooth lighting at the XYZ- corner of p.
	Both light banks
*/
static u16 getSmoothLightCombined(v3s16 p, MeshMakeData *data)
{
	static const v3s16 dirs8[8] = {
		v3s16(0,0,0),
		v3s16(0,0,1),
		v3s16(0,1,0),
		v3s16(0,1,1),
		v3s16(1,0,0),
		v3s16(1,1,0),
		v3s16(1,0,1),
		v3s16(1,1,1),
	};

	INodeDefManager *ndef = data->m_gamedef->ndef();

	u16 ambient_occlusion = 0;
	u16 light_count = 0;
	u8 light_source_max = 0;
	u16 light_day = 0;
	u16 light_night = 0;

	for (u32 i = 0; i < 8; i++)
	{
		MapNode n = data->m_vmanip.getNodeNoEx(p - dirs8[i]);

		// if it's CONTENT_IGNORE we can't do any light calculations
		if (n.getContent() == CONTENT_IGNORE) {
			continue;
		}

		const ContentFeatures &f = ndef->get(n);
		if (f.light_source > light_source_max)
			light_source_max = f.light_source;
		// Check f.solidness because fast-style leaves look better this way
		if (f.param_type == CPT_LIGHT && f.solidness != 2) {
			light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
			light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
			light_count++;
		} else {
			ambient_occlusion++;
		}
	}

	if(light_count == 0)
		return 0xffff;

	light_day /= light_count;
	light_night /= light_count;

	// Boost brightness around light sources
	bool skip_ambient_occlusion_day = false;
	if(decode_light(light_source_max) >= light_day) {
		light_day = decode_light(light_source_max);
		skip_ambient_occlusion_day = true;
	}

	bool skip_ambient_occlusion_night = false;
	if(decode_light(light_source_max) >= light_night) {
		light_night = decode_light(light_source_max);
		skip_ambient_occlusion_night = true;
	}

	if (ambient_occlusion > 4)
	{
		//table of precalculated gamma space multiply factors
		//light^2.2 * factor (0.75, 0.5, 0.25, 0.0), so table holds factor ^ (1 / 2.2)
		static const float light_amount[4] = { 0.877424315, 0.729740053, 0.532520545, 0.0 };

		//calculate table index for gamma space multiplier
		ambient_occlusion -= 5;

		if (!skip_ambient_occlusion_day)
			light_day = rangelim(core::round32(light_day*light_amount[ambient_occlusion]), 0, 255);
		if (!skip_ambient_occlusion_night)
			light_night = rangelim(core::round32(light_night*light_amount[ambient_occlusion]), 0, 255);
	}

	return light_day | (light_night << 8);
}
int
purge( osg::ArgumentParser& args )
{
    osg::ref_ptr<osg::Node> node = osgDB::readNodeFiles( args );
    if ( !node.valid() )
        return usage( "Failed to read .earth file." );

    MapNode* mapNode = MapNode::findMapNode( node.get() );
    if ( !mapNode )
        return usage( "Input file was not a .earth file" );

    Map* map = mapNode->getMap();

    if ( !map->getCache() )
        return message( "Earth file does not contain a cache." );

    std::vector<Entry> entries;


    ImageLayerVector imageLayers;
    map->getLayers( imageLayers );
    for( ImageLayerVector::const_iterator i = imageLayers.begin(); i != imageLayers.end(); ++i )
    {
        ImageLayer* layer = i->get();

        bool useMFP =
            layer->getProfile() &&
            layer->getProfile()->getSRS()->isSphericalMercator() &&
            mapNode->getMapNodeOptions().getTerrainOptions().enableMercatorFastPath() == true;

        const Profile* cacheProfile = useMFP ? layer->getProfile() : map->getProfile();

        CacheSettings* cacheSettings = layer->getCacheSettings();
        if (cacheSettings)
        {
            CacheBin* bin = cacheSettings->getCacheBin();
            if ( bin )
            {
                entries.push_back(Entry());
                entries.back()._isImage = true;
                entries.back()._name = i->get()->getName();
                entries.back()._bin = bin;
            }
        }
    }

    ElevationLayerVector elevationLayers;
    map->getLayers( elevationLayers );
    for( ElevationLayerVector::const_iterator i = elevationLayers.begin(); i != elevationLayers.end(); ++i )
    {
        ElevationLayer* layer = i->get();

        bool useMFP =
            layer->getProfile() &&
            layer->getProfile()->getSRS()->isSphericalMercator() &&
            mapNode->getMapNodeOptions().getTerrainOptions().enableMercatorFastPath() == true;

        const Profile* cacheProfile = useMFP ? layer->getProfile() : map->getProfile();
        
        CacheSettings* cacheSettings = layer->getCacheSettings();
        if (cacheSettings)
        {
            CacheBin* bin = cacheSettings->getCacheBin();
            if (bin)
            {
                entries.push_back(Entry());
                entries.back()._isImage = false;
                entries.back()._name = i->get()->getName();
                entries.back()._bin = bin;
            }
        }
    }

    if ( entries.size() > 0 )
    {
        std::cout << std::endl;

        for( unsigned i=0; i<entries.size(); ++i )
        {
            std::cout << (i+1) << ") " << entries[i]._name << " (" << (entries[i]._isImage? "image" : "elevation" ) << ")" << std::endl;
        }

        std::cout 
            << std::endl
            << "Enter number of cache to purge, or <enter> to quit: "
            << std::flush;

        std::string input;
        std::getline( std::cin, input );

        if ( !input.empty() )
        {
            unsigned k = as<unsigned>(input, 0L);
            if ( k > 0 && k <= entries.size() )
            {
                Config meta = entries[k-1]._bin->readMetadata();
                if ( !meta.empty() )
                {
                    std::cout
                        << std::endl
                        << "Cache METADATA:" << std::endl
                        << meta.toJSON() 
                        << std::endl << std::endl;
                }

                std::cout
                    << "Are you sure (y/N)? "
                    << std::flush;

                std::getline( std::cin, input );
                if ( input == "y" || input == "Y" )
                {
                    std::cout << "Purging.." << std::flush;
                    entries[k-1]._bin->clear();
                }
                else
                {
                    std::cout << "No action taken." << std::endl;
                }
            }
            else
            {
                std::cout << "Invalid choice." << std::endl;
            }
        }
        else
        {
            std::cout << "No action taken." << std::endl;
        }
    }

    return 0;
}
void SwarmGame::initialiseSwarm (EntityType type, int numEntities)
{
   CCTextureCache* textureCache = CCTextureCache::sharedTextureCache();
   CCSize size( float(m_map.width()), float(m_map.height()) );
   EntityFactory& factory = EntityFactory::instance();
   MobileEntity* entity = NULL, *mapEntity = NULL;
   MapNode* node = NULL;
   int x, y;
   int mapHeight = m_map.height() * c_blockSize;

   for ( int i = 0; i < numEntities; i++ )
   {
      if ( (entity = static_cast<MobileEntity*>(factory.createEntity (type))) )
      {
         // random position
         x = rand() % static_cast<int>(size.width);
         y = rand() % static_cast<int>(size.height);

         if ( (node = m_map.nodeAt(x, y)) )
         {
            if ( node->isBlocking() )
            {
                  // if we chose a spot that already has an entity, try again...
                  i--;
                  delete entity;
                  continue;
            }
         }

         // if we get here, we can place the new entity
         m_map.placeEntity<MobileEntity>(entity, x, y);
                  
         // add it to the swarm
         CCTexture2D* entityTexture = NULL;
         if (entity->isHuman())
            m_HumanSwarm.addEntity(entity);
         else
         {
            m_ZombieSwarm.addEntity(entity);
            m_HumanSwarm.addTarget(entity);
         }
         
         // create an entity sprite structure for the visualisation
         EntitySprite es;
         
         entityTexture = textureCache->textureForKey(xmlDataManager::instance().getEntitySprite (entity->type()));
         
         es.m_entity = dynamic_cast<MobileEntity*>(entity);         
         es.m_sprite = SpriteEntity::spriteWithEntity(entity);
         es.m_sprite->setAnchorPoint( ccp(0.5, 0.5) );
         es.m_sprite->setScaleX( c_blockSize/es.m_sprite->getContentSize().width );
         es.m_sprite->setScaleY( c_blockSize/es.m_sprite->getContentSize().height );
         es.m_sprite->setPosition( ccp(es.m_entity->x() * c_blockSize + c_blockSize/2, mapHeight - ((es.m_entity->y()+1) * c_blockSize + c_blockSize/2)) );

         es.m_sprite->setMaxHealth( entity->hitPoints() );

         m_mapLayer->addChild(es.m_sprite);
         m_entitySprites.push_back(es);
      }
   }
}
Example #23
0
/*
	Gets node tile given a face direction.
*/
TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
{
	INodeDefManager *ndef = data->m_gamedef->ndef();

	// Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
	// (0,0,1), (0,0,-1) or (0,0,0)
	assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);

	// Convert direction to single integer for table lookup
	//  0 = (0,0,0)
	//  1 = (1,0,0)
	//  2 = (0,1,0)
	//  3 = (0,0,1)
	//  4 = invalid, treat as (0,0,0)
	//  5 = (0,0,-1)
	//  6 = (0,-1,0)
	//  7 = (-1,0,0)
	u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7)*2;

	// Get rotation for things like chests
	u8 facedir = mn.getFaceDir(ndef);
	if (facedir > 23)
		facedir = 0;
	static const u16 dir_to_tile[24 * 16] =
	{
		// 0     +X    +Y    +Z           -Z    -Y    -X   ->   value=tile,rotation  
		   0,0,  2,0 , 0,0 , 4,0 ,  0,0,  5,0 , 1,0 , 3,0 ,  // rotate around y+ 0 - 3
		   0,0,  4,0 , 0,3 , 3,0 ,  0,0,  2,0 , 1,1 , 5,0 ,
		   0,0,  3,0 , 0,2 , 5,0 ,  0,0,  4,0 , 1,2 , 2,0 ,
		   0,0,  5,0 , 0,1 , 2,0 ,  0,0,  3,0 , 1,3 , 4,0 ,

		   0,0,  2,3 , 5,0 , 0,2 ,  0,0,  1,0 , 4,2 , 3,1 ,  // rotate around z+ 4 - 7
		   0,0,  4,3 , 2,0 , 0,3 ,  0,0,  1,1 , 3,2 , 5,1 ,
		   0,0,  3,3 , 4,0 , 0,0 ,  0,0,  1,2 , 5,2 , 2,1 ,
		   0,0,  5,3 , 3,0 , 0,1 ,  0,0,  1,3 , 2,2 , 4,1 ,

		   0,0,  2,1 , 4,2 , 1,2 ,  0,0,  0,0 , 5,0 , 3,3 ,  // rotate around z- 8 - 11
		   0,0,  4,1 , 3,2 , 1,3 ,  0,0,  0,3 , 2,0 , 5,3 ,
		   0,0,  3,1 , 5,2 , 1,0 ,  0,0,  0,2 , 4,0 , 2,3 ,
		   0,0,  5,1 , 2,2 , 1,1 ,  0,0,  0,1 , 3,0 , 4,3 ,

		   0,0,  0,3 , 3,3 , 4,1 ,  0,0,  5,3 , 2,3 , 1,3 ,  // rotate around x+ 12 - 15
		   0,0,  0,2 , 5,3 , 3,1 ,  0,0,  2,3 , 4,3 , 1,0 ,
		   0,0,  0,1 , 2,3 , 5,1 ,  0,0,  4,3 , 3,3 , 1,1 ,
		   0,0,  0,0 , 4,3 , 2,1 ,  0,0,  3,3 , 5,3 , 1,2 ,

		   0,0,  1,1 , 2,1 , 4,3 ,  0,0,  5,1 , 3,1 , 0,1 ,  // rotate around x- 16 - 19  
		   0,0,  1,2 , 4,1 , 3,3 ,  0,0,  2,1 , 5,1 , 0,0 ,
		   0,0,  1,3 , 3,1 , 5,3 ,  0,0,  4,1 , 2,1 , 0,3 ,  
		   0,0,  1,0 , 5,1 , 2,3 ,  0,0,  3,1 , 4,1 , 0,2 ,  

		   0,0,  3,2 , 1,2 , 4,2 ,  0,0,  5,2 , 0,2 , 2,2 ,  // rotate around y- 20 - 23
		   0,0,  5,2 , 1,3 , 3,2 ,  0,0,  2,2 , 0,1 , 4,2 ,  
		   0,0,  2,2 , 1,0 , 5,2 ,  0,0,  4,2 , 0,0 , 3,2 ,  
		   0,0,  4,2 , 1,1 , 2,2 ,  0,0,  3,2 , 0,3 , 5,2   

	};
	u16 tile_index=facedir*16 + dir_i;
	TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
	spec.rotation=dir_to_tile[tile_index + 1];
	spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture_id);
	return spec;
}
Example #24
0
void ClientMap::updateDrawList(video::IVideoDriver* driver, float dtime, unsigned int max_cycle_ms)
{
    ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
    //g_profiler->add("CM::updateDrawList() count", 1);
    TimeTaker timer_step("ClientMap::updateDrawList");

    INodeDefManager *nodemgr = m_gamedef->ndef();

    if (!m_drawlist_last)
        m_drawlist_current = !m_drawlist_current;
    auto & drawlist = m_drawlist_current ? m_drawlist_1 : m_drawlist_0;

    if (!max_cycle_ms)
        max_cycle_ms = 300/getControl().fps_wanted;

    m_camera_mutex.Lock();
    v3f camera_position = m_camera_position;
    f32 camera_fov = m_camera_fov;
    //v3s16 camera_offset = m_camera_offset;
    m_camera_mutex.Unlock();

    // Use a higher fov to accomodate faster camera movements.
    // Blocks are cropped better when they are drawn.
    // Or maybe they aren't? Well whatever.
    camera_fov *= 1.2;

    v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
    v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
    v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
    v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
    // Take a fair amount as we will be dropping more out later
    // Umm... these additions are a bit strange but they are needed.
    v3s16 p_blocks_min(
        p_nodes_min.X / MAP_BLOCKSIZE - 3,
        p_nodes_min.Y / MAP_BLOCKSIZE - 3,
        p_nodes_min.Z / MAP_BLOCKSIZE - 3);
    v3s16 p_blocks_max(
        p_nodes_max.X / MAP_BLOCKSIZE + 1,
        p_nodes_max.Y / MAP_BLOCKSIZE + 1,
        p_nodes_max.Z / MAP_BLOCKSIZE + 1);

    // Number of blocks in rendering range
    u32 blocks_in_range = 0;
    // Number of blocks occlusion culled
    u32 blocks_occlusion_culled = 0;
    // Number of blocks in rendering range but don't have a mesh
    u32 blocks_in_range_without_mesh = 0;
    // Blocks that had mesh that would have been drawn according to
    // rendering range (if max blocks limit didn't kick in)
    u32 blocks_would_have_drawn = 0;
    // Blocks that were drawn and had a mesh
    u32 blocks_drawn = 0;
    // Blocks which had a corresponding meshbuffer for this pass
    //u32 blocks_had_pass_meshbuf = 0;
    // Blocks from which stuff was actually drawn
    //u32 blocks_without_stuff = 0;
    // Distance to farthest drawn block
    float farthest_drawn = 0;
    int m_mesh_queued = 0;

    bool free_move = g_settings->getBool("free_move");

    float range_max = 100000 * BS;
    if(m_control.range_all == false)
        range_max = m_control.wanted_range * BS;

    if (draw_nearest.empty()) {
        //ScopeProfiler sp(g_profiler, "CM::updateDrawList() make list", SPT_AVG);
        TimeTaker timer_step("ClientMap::updateDrawList make list");

        auto lock = m_blocks.try_lock_shared_rec();
        if (!lock->owns_lock())
            return;

        draw_nearest.clear();

        for(auto & ir : m_blocks) {
            auto bp = ir.first;

            if(m_control.range_all == false)
            {
                if(bp.X < p_blocks_min.X
                        || bp.X > p_blocks_max.X
                        || bp.Z > p_blocks_max.Z
                        || bp.Z < p_blocks_min.Z
                        || bp.Y < p_blocks_min.Y
                        || bp.Y > p_blocks_max.Y)
                    continue;
            }

            v3s16 blockpos_nodes = bp * MAP_BLOCKSIZE;
            // Block center position
            v3f blockpos(
                ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
                ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
                ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
            );

            f32 d = radius_box(blockpos, camera_position); //blockpos_relative.getLength();
            if (d> range_max)
                continue;
            int range = d / (MAP_BLOCKSIZE * BS);
            draw_nearest.emplace_back(std::make_pair(bp, range));
        }
    }

    const int maxq = 1000;

    // No occlusion culling when free_move is on and camera is
    // inside ground
    bool occlusion_culling_enabled = true;
    if(free_move) {
        MapNode n = getNodeNoEx(cam_pos_nodes);
        if(n.getContent() == CONTENT_IGNORE ||
                nodemgr->get(n).solidness == 2)
            occlusion_culling_enabled = false;
    }

    u32 calls = 0, end_ms = porting::getTimeMs() + u32(max_cycle_ms);

    std::unordered_map<v3POS, bool, v3POSHash, v3POSEqual> occlude_cache;

    while (!draw_nearest.empty()) {
        auto ir = draw_nearest.back();

        auto bp = ir.first;
        int range = ir.second;
        draw_nearest.pop_back();
        ++calls;

        //auto block = getBlockNoCreateNoEx(bp);
        auto block = m_blocks.get(bp);
        if (!block)
            continue;

        int mesh_step = getFarmeshStep(m_control, getNodeBlockPos(cam_pos_nodes), bp);
        /*
        	Compare block position to camera position, skip
        	if not seen on display
        */

        auto mesh = block->getMesh(mesh_step);
        if (mesh)
            mesh->updateCameraOffset(m_camera_offset);

        blocks_in_range++;

        auto smesh_size = block->mesh_size;
        /*
        	Ignore if mesh doesn't exist
        */
        {
            if(!mesh) {
                blocks_in_range_without_mesh++;
                if (m_mesh_queued < maxq || range <= 2) {
                    m_client->addUpdateMeshTask(bp, false);
                    ++m_mesh_queued;
                }
                continue;
            }
            if(mesh_step == mesh->step && block->getTimestamp() <= mesh->timestamp && !smesh_size) {
                blocks_in_range_without_mesh++;
                continue;
            }
        }

        /*
        	Occlusion culling
        */

        v3s16 cpn = bp * MAP_BLOCKSIZE;
        cpn += v3s16(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2);

        float step = BS*1;
        float stepfac = 1.2;
        float startoff = BS*1;
        float endoff = -BS*MAP_BLOCKSIZE; //*1.42; //*1.42;
        v3s16 spn = cam_pos_nodes + v3s16(0,0,0);
        s16 bs2 = MAP_BLOCKSIZE/2 + 1;
        u32 needed_count = 1;
        if( range > 1 && smesh_size &&
                occlusion_culling_enabled &&
                isOccluded(this, spn, cpn + v3s16(0,0,0),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache)
          )
        {
            blocks_occlusion_culled++;
            continue;
        }

        // This block is in range. Reset usage timer.
        block->resetUsageTimer();

        // Limit block count in case of a sudden increase
        blocks_would_have_drawn++;
        /*
        			if(blocks_drawn >= m_control.wanted_max_blocks
        					&& m_control.range_all == false
        					&& d > m_control.wanted_min_range * BS)
        				continue;
        */

        if (mesh_step != mesh->step && (m_mesh_queued < maxq*1.2 || range <= 2)) {
            m_client->addUpdateMeshTask(bp);
            ++m_mesh_queued;
        }
        if (block->getTimestamp() > mesh->timestamp + (smesh_size ? 0 : range >= 1 ? 60 : 5) && (m_mesh_queued < maxq*1.5 || range <= 2)) {
            m_client->addUpdateMeshTaskWithEdge(bp);
            ++m_mesh_queued;
        }

        if(!smesh_size)
            continue;

        mesh->incrementUsageTimer(dtime);

        // Add to set
        //block->refGrab();
        block->resetUsageTimer();
        drawlist.set(bp, block);

        blocks_drawn++;

        if(range * MAP_BLOCKSIZE > farthest_drawn)
            farthest_drawn = range * MAP_BLOCKSIZE;

        if (farthest_drawn > m_control.farthest_drawn)
            m_control.farthest_drawn = farthest_drawn;

        if (porting::getTimeMs() > end_ms) {
            break;
        }

    }
    m_drawlist_last = draw_nearest.size();

    //if (m_drawlist_last) infostream<<"breaked UDL "<<m_drawlist_last<<" collected="<<drawlist.size()<<" calls="<<calls<<" s="<<m_blocks.size()<<" maxms="<<max_cycle_ms<<" fw="<<getControl().fps_wanted<<" morems="<<porting::getTimeMs() - end_ms<< " meshq="<<m_mesh_queued<<" occache="<<occlude_cache.size()<<std::endl;

    if (m_drawlist_last)
        return;

    //for (auto & ir : *m_drawlist)
    //	ir.second->refDrop();

    auto m_drawlist_old = !m_drawlist_current ? &m_drawlist_1 : &m_drawlist_0;
    m_drawlist = m_drawlist_current ? &m_drawlist_1 : &m_drawlist_0;
    m_drawlist_old->clear();

    m_control.blocks_would_have_drawn = blocks_would_have_drawn;
    m_control.blocks_drawn = blocks_drawn;
    m_control.farthest_drawn = farthest_drawn;

    g_profiler->avg("CM: blocks total", m_blocks.size());
    g_profiler->avg("CM: blocks in range", blocks_in_range);
    g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
    if(blocks_in_range != 0)
        g_profiler->avg("CM: blocks in range without mesh (frac)",
                        (float)blocks_in_range_without_mesh/blocks_in_range);
    g_profiler->avg("CM: blocks drawn", blocks_drawn);
    g_profiler->avg("CM: farthest drawn", farthest_drawn);
    g_profiler->avg("CM: wanted max blocks", m_control.wanted_max_blocks);
}
Example #25
0
void ServerEnvironment::step(float dtime)
{
	DSTACK(__FUNCTION_NAME);
	
	//TimeTaker timer("ServerEnv step");

	// Get some settings
	bool footprints = g_settings.getBool("footprints");

	/*
		Increment game time
	*/
	{
		m_game_time_fraction_counter += dtime;
		u32 inc_i = (u32)m_game_time_fraction_counter;
		m_game_time += inc_i;
		m_game_time_fraction_counter -= (float)inc_i;
	}
	
	/*
		Handle players
	*/
	for(core::list<Player*>::Iterator i = m_players.begin();
			i != m_players.end(); i++)
	{
		Player *player = *i;
		
		// Ignore disconnected players
		if(player->peer_id == 0)
			continue;

		v3f playerpos = player->getPosition();
		
		// Move
		player->move(dtime, *m_map, 100*BS);
		
		/*
			Add footsteps to grass
		*/
		if(footprints)
		{
			// Get node that is at BS/4 under player
			v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
			try{
				MapNode n = m_map->getNode(bottompos);
				if(n.getContent() == CONTENT_GRASS)
				{
					n.setContent(CONTENT_GRASS_FOOTSTEPS);
					m_map->setNode(bottompos, n);
				}
			}
			catch(InvalidPositionException &e)
			{
			}
		}
	}

	/*
		Manage active block list
	*/
	if(m_active_blocks_management_interval.step(dtime, 2.0))
	{
		/*
			Get player block positions
		*/
		core::list<v3s16> players_blockpos;
		for(core::list<Player*>::Iterator
				i = m_players.begin();
				i != m_players.end(); i++)
		{
			Player *player = *i;
			// Ignore disconnected players
			if(player->peer_id == 0)
				continue;
			v3s16 blockpos = getNodeBlockPos(
					floatToInt(player->getPosition(), BS));
			players_blockpos.push_back(blockpos);
		}
		
		/*
			Update list of active blocks, collecting changes
		*/
		const s16 active_block_range = 5;
		core::map<v3s16, bool> blocks_removed;
		core::map<v3s16, bool> blocks_added;
		m_active_blocks.update(players_blockpos, active_block_range,
				blocks_removed, blocks_added);

		/*
			Handle removed blocks
		*/

		// Convert active objects that are no more in active blocks to static
		deactivateFarObjects(false);
		
		for(core::map<v3s16, bool>::Iterator
				i = blocks_removed.getIterator();
				i.atEnd()==false; i++)
		{
			v3s16 p = i.getNode()->getKey();

			/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
					<<") became inactive"<<std::endl;*/
			
			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if(block==NULL)
				continue;
			
			// Set current time as timestamp (and let it set ChangedFlag)
			block->setTimestamp(m_game_time);
		}

		/*
			Handle added blocks
		*/

		for(core::map<v3s16, bool>::Iterator
				i = blocks_added.getIterator();
				i.atEnd()==false; i++)
		{
			v3s16 p = i.getNode()->getKey();
			
			/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
					<<") became active"<<std::endl;*/

			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if(block==NULL)
				continue;

			activateBlock(block);
		}
	}

	/*
		Mess around in active blocks
	*/
	if(m_active_blocks_nodemetadata_interval.step(dtime, 1.0))
	{
		float dtime = 1.0;

		for(core::map<v3s16, bool>::Iterator
				i = m_active_blocks.m_list.getIterator();
				i.atEnd()==false; i++)
		{
			v3s16 p = i.getNode()->getKey();
			
			/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
					<<") being handled"<<std::endl;*/

			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if(block==NULL)
				continue;

			// Reset block usage timer
			block->resetUsageTimer();
			
			// Set current time as timestamp
			block->setTimestampNoChangedFlag(m_game_time);

			// Run node metadata
			bool changed = block->m_node_metadata.step(dtime);
			if(changed)
			{
				MapEditEvent event;
				event.type = MEET_BLOCK_NODE_METADATA_CHANGED;
				event.p = p;
				m_map->dispatchEvent(&event);

				block->setChangedFlag();
			}
		}
	}
	if(m_active_blocks_test_interval.step(dtime, 10.0))
	{
		//float dtime = 10.0;
		
		for(core::map<v3s16, bool>::Iterator
				i = m_active_blocks.m_list.getIterator();
				i.atEnd()==false; i++)
		{
			v3s16 p = i.getNode()->getKey();
			
			/*dstream<<"Server: Block ("<<p.X<<","<<p.Y<<","<<p.Z
					<<") being handled"<<std::endl;*/

			MapBlock *block = m_map->getBlockNoCreateNoEx(p);
			if(block==NULL)
				continue;
			
			// Set current time as timestamp
			block->setTimestampNoChangedFlag(m_game_time);

			/*
				Do stuff!

				Note that map modifications should be done using the event-
				making map methods so that the server gets information
				about them.

				Reading can be done quickly directly from the block.

				Everything should bind to inside this single content
				searching loop to keep things fast.
			*/
			// TODO: Implement usage of ActiveBlockModifier
			
			// Find out how many objects the block contains
			u32 active_object_count = block->m_static_objects.m_active.size();
			// Find out how many objects this and all the neighbors contain
			u32 active_object_count_wider = 0;
			for(s16 x=-1; x<=1; x++)
			for(s16 y=-1; y<=1; y++)
			for(s16 z=-1; z<=1; z++)
			{
				MapBlock *block = m_map->getBlockNoCreateNoEx(p+v3s16(x,y,z));
				if(block==NULL)
					continue;
				active_object_count_wider +=
						block->m_static_objects.m_active.size();
			}

			v3s16 p0;
			for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
			for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
			for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
			{
				v3s16 p = p0 + block->getPosRelative();
				MapNode n = block->getNodeNoEx(p0);

				/*
					Test something:
					Convert mud under proper lighting to grass
				*/
				if(n.getContent() == CONTENT_MUD)
				{
					if(myrand()%20 == 0)
					{
						MapNode n_top = m_map->getNodeNoEx(p+v3s16(0,1,0));
						if(content_features(n_top).air_equivalent &&
								n_top.getLightBlend(getDayNightRatio()) >= 13)
						{
							n.setContent(CONTENT_GRASS);
							m_map->addNodeWithEvent(p, n);
						}
					}
				}
				/*
					Convert grass into mud if under something else than air
				*/
				if(n.getContent() == CONTENT_GRASS)
				{
					//if(myrand()%20 == 0)
					{
						MapNode n_top = m_map->getNodeNoEx(p+v3s16(0,1,0));
						if(content_features(n_top).air_equivalent == false)
						{
							n.setContent(CONTENT_MUD);
							m_map->addNodeWithEvent(p, n);
						}
					}
				}
				/*
					Rats spawn around regular trees
				*/
				if(n.getContent() == CONTENT_TREE ||
						n.getContent() == CONTENT_JUNGLETREE)
				{
   					if(myrand()%200 == 0 && active_object_count_wider == 0)
					{
						v3s16 p1 = p + v3s16(myrand_range(-2, 2),
								0, myrand_range(-2, 2));
						MapNode n1 = m_map->getNodeNoEx(p1);
						MapNode n1b = m_map->getNodeNoEx(p1+v3s16(0,-1,0));
						if(n1b.getContent() == CONTENT_GRASS &&
								n1.getContent() == CONTENT_AIR)
						{
							v3f pos = intToFloat(p1, BS);
							ServerActiveObject *obj = new RatSAO(this, 0, pos);
							addActiveObject(obj);
						}
					}
			 }
			}
		}
	}
	
	/*
		Step active objects
	*/
	{
		//TimeTaker timer("Step active objects");
		
		// This helps the objects to send data at the same time
		bool send_recommended = false;
		m_send_recommended_timer += dtime;
		if(m_send_recommended_timer > 0.15)
		{
			m_send_recommended_timer = 0;
			send_recommended = true;
		}

		for(core::map<u16, ServerActiveObject*>::Iterator
				i = m_active_objects.getIterator();
				i.atEnd()==false; i++)
		{
			ServerActiveObject* obj = i.getNode()->getValue();
			// Don't step if is to be removed or stored statically
			if(obj->m_removed || obj->m_pending_deactivation)
				continue;
			// Step object
			obj->step(dtime, send_recommended);
			// Read messages from object
			while(obj->m_messages_out.size() > 0)
			{
				m_active_object_messages.push_back(
						obj->m_messages_out.pop_front());
			}
		}
	}
	
	/*
		Manage active objects
	*/
	if(m_object_management_interval.step(dtime, 0.5))
	{
		/*
			Remove objects that satisfy (m_removed && m_known_by_count==0)
		*/
		removeRemovedObjects();
	}

	if(g_settings.getBool("enable_experimental"))
	{

	/*
		TEST CODE
	*/
#if 1
	m_random_spawn_timer -= dtime;
	if(m_random_spawn_timer < 0)
	{
		//m_random_spawn_timer += myrand_range(2.0, 20.0);
		//m_random_spawn_timer += 2.0;
		m_random_spawn_timer += 200.0;

		/*
			Find some position
		*/

		/*v2s16 p2d(myrand_range(-5,5), myrand_range(-5,5));
		s16 y = 1 + getServerMap().findGroundLevel(p2d);
		v3f pos(p2d.X*BS,y*BS,p2d.Y*BS);*/
		
		Player *player = getRandomConnectedPlayer();
		v3f pos(0,0,0);
		if(player)
			pos = player->getPosition();
		pos += v3f(
			myrand_range(-3,3)*BS,
			0,
			myrand_range(-3,3)*BS
		);

		/*
			Create a ServerActiveObject
		*/

		//TestSAO *obj = new TestSAO(this, 0, pos);
		//ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
		//ServerActiveObject *obj = new RatSAO(this, 0, pos);
		//ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
		ServerActiveObject *obj = new FireflySAO(this, 0, pos);
		addActiveObject(obj);
	}
#endif

	} // enable_experimental
}
Example #26
0
static bool getVisibleBrightness(Map *map, v3f p0, v3f dir, float step,
                                 float step_multiplier, float start_distance, float end_distance,
                                 INodeDefManager *ndef, u32 daylight_factor, float sunlight_min_d,
                                 int *result, bool *sunlight_seen)
{
    int brightness_sum = 0;
    int brightness_count = 0;
    float distance = start_distance;
    dir.normalize();
    v3f pf = p0;
    pf += dir * distance;
    int noncount = 0;
    bool nonlight_seen = false;
    bool allow_allowing_non_sunlight_propagates = false;
    bool allow_non_sunlight_propagates = false;
    // Check content nearly at camera position
    {
        v3s16 p = floatToInt(p0 /*+ dir * 3*BS*/, BS);
        MapNode n = map->getNodeNoEx(p);
        if(ndef->get(n).param_type == CPT_LIGHT &&
                !ndef->get(n).sunlight_propagates)
            allow_allowing_non_sunlight_propagates = true;
    }
    // If would start at CONTENT_IGNORE, start closer
    {
        v3s16 p = floatToInt(pf, BS);
        MapNode n = map->getNodeNoEx(p);
        if(n.getContent() == CONTENT_IGNORE) {
            float newd = 2*BS;
            pf = p0 + dir * 2*newd;
            distance = newd;
            sunlight_min_d = 0;
        }
    }
    for(int i=0; distance < end_distance; i++) {
        pf += dir * step;
        distance += step;
        step *= step_multiplier;

        v3s16 p = floatToInt(pf, BS);
        MapNode n = map->getNodeNoEx(p);
        if(allow_allowing_non_sunlight_propagates && i == 0 &&
                ndef->get(n).param_type == CPT_LIGHT &&
                !ndef->get(n).sunlight_propagates) {
            allow_non_sunlight_propagates = true;
        }
        if(ndef->get(n).param_type != CPT_LIGHT ||
                (!ndef->get(n).sunlight_propagates &&
                 !allow_non_sunlight_propagates)) {
            nonlight_seen = true;
            noncount++;
            if(noncount >= 4)
                break;
            continue;
        }
        if(distance >= sunlight_min_d && *sunlight_seen == false
                && nonlight_seen == false)
            if(n.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN)
                *sunlight_seen = true;
        noncount = 0;
        brightness_sum += decode_light(n.getLightBlend(daylight_factor, ndef));
        brightness_count++;
    }
    *result = 0;
    if(brightness_count == 0)
        return false;
    *result = brightness_sum / brightness_count;
    /*std::cerr<<"Sampled "<<brightness_count<<" points; result="
    		<<(*result)<<std::endl;*/
    return true;
}
Example #27
0
void MapgenV6::flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos) {
	// 340ms @cs=8
	TimeTaker timer1("flow mud");

	// Iterate a few times
	for(s16 k = 0; k < 3; k++) {
		for (s16 z = mudflow_minpos; z <= mudflow_maxpos; z++)
		for (s16 x = mudflow_minpos; x <= mudflow_maxpos; x++) {
			// Invert coordinates every 2nd iteration
			if (k % 2 == 0) {
				x = mudflow_maxpos - (x - mudflow_minpos);
				z = mudflow_maxpos - (z - mudflow_minpos);
			}

			// Node position in 2d
			v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x, z);

			v3s16 em = vm->m_area.getExtent();
			u32 i = vm->m_area.index(p2d.X, node_max.Y, p2d.Y);
			s16 y = node_max.Y;

			while(y >= node_min.Y)
			{

			for(;; y--)
			{
				MapNode *n = NULL;
				// Find mud
				for(; y >= node_min.Y; y--) {
					n = &vm->m_data[i];
					if (n->getContent() == c_dirt ||
						n->getContent() == c_dirt_with_grass ||
						n->getContent() == c_gravel)
						break;

					vm->m_area.add_y(em, i, -1);
				}

				// Stop if out of area
				//if(vmanip.m_area.contains(i) == false)
				if (y < node_min.Y)
					break;

				if (n->getContent() == c_dirt ||
					n->getContent() == c_dirt_with_grass)
				{
					// Make it exactly mud
					n->setContent(c_dirt);

					// Don't flow it if the stuff under it is not mud
					{
						u32 i2 = i;
						vm->m_area.add_y(em, i2, -1);
						// Cancel if out of area
						if(vm->m_area.contains(i2) == false)
							continue;
						MapNode *n2 = &vm->m_data[i2];
						if (n2->getContent() != c_dirt &&
							n2->getContent() != c_dirt_with_grass)
							continue;
					}
				}

				v3s16 dirs4[4] = {
					v3s16(0,0,1), // back
					v3s16(1,0,0), // right
					v3s16(0,0,-1), // front
					v3s16(-1,0,0), // left
				};

				// Check that upper is air or doesn't exist.
				// Cancel dropping if upper keeps it in place
				u32 i3 = i;
				vm->m_area.add_y(em, i3, 1);
				if (vm->m_area.contains(i3) == true &&
					ndef->get(vm->m_data[i3]).walkable)
					continue;

				// Drop mud on side
				for(u32 di=0; di<4; di++) {
					v3s16 dirp = dirs4[di];
					u32 i2 = i;
					// Move to side
					vm->m_area.add_p(em, i2, dirp);
					// Fail if out of area
					if (vm->m_area.contains(i2) == false)
						continue;
					// Check that side is air
					MapNode *n2 = &vm->m_data[i2];
					if (ndef->get(*n2).walkable)
						continue;
					// Check that under side is air
					vm->m_area.add_y(em, i2, -1);
					if (vm->m_area.contains(i2) == false)
						continue;
					n2 = &vm->m_data[i2];
					if (ndef->get(*n2).walkable)
						continue;
					// Loop further down until not air
					bool dropped_to_unknown = false;
					do {
						vm->m_area.add_y(em, i2, -1);
						n2 = &vm->m_data[i2];
						// if out of known area
						if(vm->m_area.contains(i2) == false ||
							n2->getContent() == CONTENT_IGNORE) {
							dropped_to_unknown = true;
							break;
						}
					} while (ndef->get(*n2).walkable == false);
					// Loop one up so that we're in air
					vm->m_area.add_y(em, i2, 1);
					n2 = &vm->m_data[i2];

					bool old_is_water = (n->getContent() == c_water_source);
					// Move mud to new place
					if (!dropped_to_unknown) {
						*n2 = *n;
						// Set old place to be air (or water)
						if(old_is_water)
							*n = MapNode(c_water_source);
						else
							*n = MapNode(CONTENT_AIR);
					}

					// Done
					break;
				}
			}
			}
		}
	}
}
Example #28
0
int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
                                       int oldvalue, bool *sunlight_seen_result)
{
    const bool debugprint = false;
    INodeDefManager *ndef = m_gamedef->ndef();
    static v3f z_directions[50] = {
        v3f(-100, 0, 0)
    };
    static f32 z_offsets[sizeof(z_directions)/sizeof(*z_directions)] = {
        -1000,
    };
    if(z_directions[0].X < -99) {
        for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++) {
            z_directions[i] = v3f(
                                  0.01 * myrand_range(-100, 100),
                                  1.0,
                                  0.01 * myrand_range(-100, 100)
                              );
            z_offsets[i] = 0.01 * myrand_range(0,100);
        }
    }
    if(debugprint)
        std::cerr<<"In goes "<<PP(m_camera_direction)<<", out comes ";
    int sunlight_seen_count = 0;
    float sunlight_min_d = max_d*0.8;
    if(sunlight_min_d > 35*BS)
        sunlight_min_d = 35*BS;
    std::vector<int> values;
    for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++) {
        v3f z_dir = z_directions[i];
        z_dir.normalize();
        core::CMatrix4<f32> a;
        a.buildRotateFromTo(v3f(0,1,0), z_dir);
        v3f dir = m_camera_direction;
        a.rotateVect(dir);
        int br = 0;
        float step = BS*1.5;
        if(max_d > 35*BS)
            step = max_d / 35 * 1.5;
        float off = step * z_offsets[i];
        bool sunlight_seen_now = false;
        bool ok = getVisibleBrightness(this, m_camera_position, dir,
                                       step, 1.0, max_d*0.6+off, max_d, ndef, daylight_factor,
                                       sunlight_min_d,
                                       &br, &sunlight_seen_now);
        if(sunlight_seen_now)
            sunlight_seen_count++;
        if(!ok)
            continue;
        values.push_back(br);
        // Don't try too much if being in the sun is clear
        if(sunlight_seen_count >= 20)
            break;
    }
    int brightness_sum = 0;
    int brightness_count = 0;
    std::sort(values.begin(), values.end());
    u32 num_values_to_use = values.size();
    if(num_values_to_use >= 10)
        num_values_to_use -= num_values_to_use/2;
    else if(num_values_to_use >= 7)
        num_values_to_use -= num_values_to_use/3;
    u32 first_value_i = (values.size() - num_values_to_use) / 2;
    if(debugprint) {
        for(u32 i=0; i < first_value_i; i++)
            std::cerr<<values[i]<<" ";
        std::cerr<<"[";
    }
    for(u32 i=first_value_i; i < first_value_i+num_values_to_use; i++) {
        if(debugprint)
            std::cerr<<values[i]<<" ";
        brightness_sum += values[i];
        brightness_count++;
    }
    if(debugprint) {
        std::cerr<<"]";
        for(u32 i=first_value_i+num_values_to_use; i < values.size(); i++)
            std::cerr<<values[i]<<" ";
    }
    int ret = 0;
    if(brightness_count == 0) {
        MapNode n = getNodeNoEx(floatToInt(m_camera_position, BS));
        if(ndef->get(n).param_type == CPT_LIGHT) {
            ret = decode_light(n.getLightBlend(daylight_factor, ndef));
        } else {
            ret = oldvalue;
        }
    } else {
        /*float pre = (float)brightness_sum / (float)brightness_count;
        float tmp = pre;
        const float d = 0.2;
        pre *= 1.0 + d*2;
        pre -= tmp * d;
        int preint = pre;
        ret = MYMAX(0, MYMIN(255, preint));*/
        ret = brightness_sum / brightness_count;
    }
    if(debugprint)
        std::cerr<<"Result: "<<ret<<" sunlight_seen_count="
                 <<sunlight_seen_count<<std::endl;
    *sunlight_seen_result = (sunlight_seen_count > 0);
    return ret;
}
Example #29
0
void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
		core::list<CollisionInfo> *collision_info)
{
	INodeDefManager *nodemgr = m_gamedef->ndef();

	v3f position = getPosition();

	v3f old_speed = m_speed;

	// Copy parent position if local player is attached
	if(isAttached)
	{
		setPosition(overridePosition);
		return;
	}

	// Skip collision detection if noclip mode is used
	bool fly_allowed = m_gamedef->checkLocalPrivilege("fly");
	bool noclip = m_gamedef->checkLocalPrivilege("noclip") &&
		g_settings->getBool("noclip");
	bool free_move = noclip && fly_allowed && g_settings->getBool("free_move");
	if(free_move)
	{
        position += m_speed * dtime;
		setPosition(position);
		return;
	}

	/*
		Collision detection
	*/
	
	/*
		Check if player is in water (the oscillating value)
	*/
	try{
		// If in water, the threshold of coming out is at higher y
		if(in_water)
		{
			v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0),BS);
			in_water = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
			in_water_speed = nodemgr->get(map.getNode(pp).getContent()).nodeMovingSpeed();
		}
		// If not in water, the threshold of going in is at lower y
		else
		{
			v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0),BS);
			in_water = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
		}
	}
	catch(InvalidPositionException &e)
	{
		in_water = false;
	}

	/*
		Check if player is in water (the stable value)
	*/
	try{
		v3s16 pp = floatToInt(position + v3f(0,0,0), BS);
		in_water_stable = nodemgr->get(map.getNode(pp).getContent()).isLiquid();
		in_water_speed = nodemgr->get(map.getNode(pp).getContent()).nodeMovingSpeed();
	}
	catch(InvalidPositionException &e)
	{
		in_water_stable = false;
	}

	/*
	        Check if player is climbing
	*/

	try {
		v3s16 pp = floatToInt(position + v3f(0,0.5*BS,0), BS);
		v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS);
		is_climbing = ((nodemgr->get(map.getNode(pp).getContent()).climbable ||
		nodemgr->get(map.getNode(pp2).getContent()).climbable) && !free_move);
	}
	catch(InvalidPositionException &e)
	{
		is_climbing = false;
	}

	/*
		Collision uncertainty radius
		Make it a bit larger than the maximum distance of movement
	*/
	//f32 d = pos_max_d * 1.1;
	// A fairly large value in here makes moving smoother
	f32 d = 0.15*BS;

	// This should always apply, otherwise there are glitches
	assert(d > pos_max_d);

	float player_radius = BS*0.30;
	float player_height = BS*1.55;
	
	// Maximum distance over border for sneaking
	f32 sneak_max = BS*0.4;

	/*
		If sneaking, keep in range from the last walked node and don't
		fall off from it
	*/
	if(control.sneak && m_sneak_node_exists && !g_settings->getBool("free_move"))
	{
		f32 maxd = 0.5*BS + sneak_max;
		v3f lwn_f = intToFloat(m_sneak_node, BS);
		position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd);
		position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd);
		
		if(!is_climbing)
		{
			f32 min_y = lwn_f.Y + 0.5*BS;
			if(position.Y < min_y)
			{
				position.Y = min_y;

				if(m_speed.Y < 0)
					m_speed.Y = 0;
			}
		}
	}

	/*
		Calculate player collision box (new and old)
	*/
	core::aabbox3d<f32> playerbox(
		-player_radius,
		0.0,
		-player_radius,
		player_radius,
		player_height,
		player_radius
	);

	float player_stepheight = touching_ground ? (BS*0.6) : (BS*0.2);

	v3f accel_f = v3f(0,0,0);

	collisionMoveResult result = collisionMoveSimple(&map, m_gamedef,
			pos_max_d, playerbox, player_stepheight, dtime,
			position, m_speed, accel_f);

	/*
		If the player's feet touch the topside of any node, this is
		set to true.

		Player is allowed to jump when this is true.
	*/
	bool touching_ground_was = touching_ground;
	touching_ground = result.touching_ground;
    
    //bool standing_on_unloaded = result.standing_on_unloaded;

	/*
		Check the nodes under the player to see from which node the
		player is sneaking from, if any.  If the node from under
		the player has been removed, the player falls.
	*/
	v3s16 current_node = floatToInt(position - v3f(0,BS/2,0), BS);
	if(m_sneak_node_exists &&
	   nodemgr->get(map.getNodeNoEx(m_old_node_below)).name == "air" &&
	   m_old_node_below_type != "air")
	{
		// Old node appears to have been removed; that is,
		// it wasn't air before but now it is
		m_need_to_get_new_sneak_node = false;
		m_sneak_node_exists = false;
	}
	else if(nodemgr->get(map.getNodeNoEx(current_node)).name != "air")
	{
		// We are on something, so make sure to recalculate the sneak
		// node.
		m_need_to_get_new_sneak_node = true;
	}
	if(m_need_to_get_new_sneak_node)
	{
		v3s16 pos_i_bottom = floatToInt(position - v3f(0,BS/2,0), BS);
		v2f player_p2df(position.X, position.Z);
		f32 min_distance_f = 100000.0*BS;
		// If already seeking from some node, compare to it.
		/*if(m_sneak_node_exists)
		{
			v3f sneaknode_pf = intToFloat(m_sneak_node, BS);
			v2f sneaknode_p2df(sneaknode_pf.X, sneaknode_pf.Z);
			f32 d_horiz_f = player_p2df.getDistanceFrom(sneaknode_p2df);
			f32 d_vert_f = fabs(sneaknode_pf.Y + BS*0.5 - position.Y);
			// Ignore if player is not on the same level (likely dropped)
			if(d_vert_f < 0.15*BS)
				min_distance_f = d_horiz_f;
		}*/
		v3s16 new_sneak_node = m_sneak_node;
		for(s16 x=-1; x<=1; x++)
		for(s16 z=-1; z<=1; z++)
		{
			v3s16 p = pos_i_bottom + v3s16(x,0,z);
			v3f pf = intToFloat(p, BS);
			v2f node_p2df(pf.X, pf.Z);
			f32 distance_f = player_p2df.getDistanceFrom(node_p2df);
			f32 max_axis_distance_f = MYMAX(
					fabs(player_p2df.X-node_p2df.X),
					fabs(player_p2df.Y-node_p2df.Y));
					
			if(distance_f > min_distance_f ||
					max_axis_distance_f > 0.5*BS + sneak_max + 0.1*BS)
				continue;

			try{
				// The node to be sneaked on has to be walkable
				if(nodemgr->get(map.getNode(p)).walkable == false)
					continue;
				// And the node above it has to be nonwalkable
				if(nodemgr->get(map.getNode(p+v3s16(0,1,0))).walkable == true)
					continue;
			}
			catch(InvalidPositionException &e)
			{
				continue;
			}

			min_distance_f = distance_f;
			new_sneak_node = p;
		}
		
		bool sneak_node_found = (min_distance_f < 100000.0*BS*0.9);

		m_sneak_node = new_sneak_node;
		m_sneak_node_exists = sneak_node_found;

		/*
			If sneaking, the player's collision box can be in air, so
			this has to be set explicitly
		*/
		if(sneak_node_found && control.sneak)
			touching_ground = true;
	}
	
	/*
		Set new position
	*/
	setPosition(position);
	
	/*
		Report collisions
	*/
	bool bouncy_jump = false;
	// Dont report if flying
	if(collision_info && !(g_settings->getBool("free_move") && fly_allowed))
	{
		for(size_t i=0; i<result.collisions.size(); i++){
			const CollisionInfo &info = result.collisions[i];
			collision_info->push_back(info);
			if(info.new_speed.Y - info.old_speed.Y > 0.1*BS &&
					info.bouncy)
				bouncy_jump = true;
		}
	}

	if(bouncy_jump && control.jump){
		m_speed.Y += 6.5*BS;
		touching_ground = false;
		MtEvent *e = new SimpleTriggerEvent("PlayerJump");
		m_gamedef->event()->put(e);
	}

	if(!touching_ground_was && touching_ground){
		MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround");
		m_gamedef->event()->put(e);
	}

	{
		camera_barely_in_ceiling = false;
		v3s16 camera_np = floatToInt(getEyePosition(), BS);
		MapNode n = map.getNodeNoEx(camera_np);
		if(n.getContent() != CONTENT_IGNORE){
			if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){
				camera_barely_in_ceiling = true;
			}
		}
	}

	/*
		Update the node last under the player
	*/
	m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS);
	m_old_node_below_type = nodemgr->get(map.getNodeNoEx(m_old_node_below)).name;
	
	/*
		Check properties of the node on which the player is standing
	*/
	const ContentFeatures &f = nodemgr->get(map.getNodeNoEx(getStandingNodePos()));
	// Determine if jumping is possible
	m_can_jump = touching_ground;
	if(itemgroup_get(f.groups, "disable_jump"))
		m_can_jump = false;
}
Example #30
0
void VoxelManipulator::print(std::ostream &o, INodeDefManager *ndef,
		VoxelPrintMode mode)
{
	v3s16 em = m_area.getExtent();
	v3s16 of = m_area.MinEdge;
	o<<"size: "<<em.X<<"x"<<em.Y<<"x"<<em.Z
	 <<" offset: ("<<of.X<<","<<of.Y<<","<<of.Z<<")"<<std::endl;
	
	for(s32 y=m_area.MaxEdge.Y; y>=m_area.MinEdge.Y; y--)
	{
		if(em.X >= 3 && em.Y >= 3)
		{
			if     (y==m_area.MinEdge.Y+2) o<<"^     ";
			else if(y==m_area.MinEdge.Y+1) o<<"|     ";
			else if(y==m_area.MinEdge.Y+0) o<<"y x-> ";
			else                           o<<"      ";
		}

		for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
		{
			for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
			{
				u8 f = m_flags[m_area.index(x,y,z)];
				char c;
				if(f & VOXELFLAG_NOT_LOADED)
					c = 'N';
				else if(f & VOXELFLAG_INEXISTENT)
					c = 'I';
				else
				{
					c = 'X';
					MapNode n = m_data[m_area.index(x,y,z)];
					content_t m = n.getContent();
					u8 pr = n.param2;
					if(mode == VOXELPRINT_MATERIAL)
					{
						if(m <= 9)
							c = m + '0';
					}
					else if(mode == VOXELPRINT_WATERPRESSURE)
					{
						if(ndef->get(m).isLiquid())
						{
							c = 'w';
							if(pr <= 9)
								c = pr + '0';
						}
						else if(m == CONTENT_AIR)
						{
							c = ' ';
						}
						else
						{
							c = '#';
						}
					}
					else if(mode == VOXELPRINT_LIGHT_DAY)
					{
						if(ndef->get(m).light_source != 0)
							c = 'S';
						else if(ndef->get(m).light_propagates == false)
							c = 'X';
						else
						{
							u8 light = n.getLight(LIGHTBANK_DAY, ndef);
							if(light < 10)
								c = '0' + light;
							else
								c = 'a' + (light-10);
						}
					}
				}
				o<<c;
			}
			o<<' ';
		}
		o<<std::endl;
	}
}