Пример #1
0
// Support function for finding collided nodes using a subset of nodes in the scene
// recursive method for going through all scene nodes
void getNodeRayBB(ISceneNode* root,
               const core::line3df& ray,
               s32 bits,
               bool recurse,
               f32& outbestdistance,
               ISceneNode*& outbestnode)
{
    core::vector3df edges[8];

    const core::list<ISceneNode*>& children = root->getChildren();

    core::list<ISceneNode*>::ConstIterator it = children.begin();
    for (; it != children.end(); ++it)
    {
        ISceneNode* current = *it;

        if (current->isVisible() &&
//        (bNoDebugObjects ? !current->isDebugObject() : true) &&
        (bits==0 || (bits != 0 && (current->getID() & bits))))
        {
            // get world to object space transform
            core::matrix4 mat;
            if (!current->getAbsoluteTransformation().getInverse(mat))
                continue;

            // transform vector from world space to object space
            core::line3df line(ray);
            mat.transformVect(line.start);
            mat.transformVect(line.end);

            const core::aabbox3df& box = current->getBoundingBox();

            // do intersection test in object space
            if (box.intersectsWithLine(line))
            {
                box.getEdges(edges);
                f32 distance = 0.0f;

                for (s32 e=0; e<8; ++e)
                {
                    f32 t = edges[e].getDistanceFromSQ(line.start);
                    if (t > distance)
                        distance = t;
                }

                if (distance < outbestdistance)
                {
                    outbestnode = current;
                    outbestdistance = distance;
                }
            }
        }

        if ( recurse )
            getNodeRayBB(current, ray, bits, recurse, outbestdistance, outbestnode);
    }
}
Пример #2
0
// Support function for finding collided nodes using a subset of nodes in the scene
// recursive method for going through all scene nodes and testing them against a point
bool getNodePointBB(ISceneNode* root,
                    vector3df point,
                    s32 bits,
                    bool recurse,
                    ISceneNode*& outbestnode)
{
    core::vector3df edges[8];

    const core::list<ISceneNode*>& children = root->getChildren();

    core::list<ISceneNode*>::ConstIterator it = children.begin();
    for (; it != children.end(); ++it)
    {
        ISceneNode* current = *it;

        if (current->isVisible() &&
        //          (bNoDebugObjects ? !current->isDebugObject() : true) &&
        (bits==0 || (bits != 0 && (current->getID() & bits))))
        {
            // get world to object space transform
            core::matrix4 mat;
            if (!current->getAbsoluteTransformation().getInverse(mat))
                continue;

            // transform vector from world space to object space
            vector3df currentPoint( point );
            mat.transformVect(currentPoint);

            const core::aabbox3df& box = current->getBoundingBox();

            // do intersection test in object space
            if (box.isPointInside( currentPoint ))
            {
                outbestnode = current;
                return true;
            }
        }
        if ( recurse )
            if ( getNodePointBB(current, point, bits, recurse, outbestnode))
                return true;
    }
    return false;
}
Пример #3
0
// ----------------------------------------------------------------------------
void Track::exportElements(std::ofstream& stream, bool obj)
{
    ISceneManager* sm = Editor::getEditor()->getSceneManager();
    ISceneNode* node;
    stringc name;
    int i = 1;
    while ((node = sm->getSceneNodeFromId(MAGIC_NUMBER + i)))
    {
        name = node->getName();
        vector3df pos, rot, sca;
        if (node->isVisible() && name != "banana" && name != "item"
            && name != "small-nitro" && name != "big-nitro"
            && (name.equalsn("obj/", 4) == obj))
        {
            pos = node->getPosition();
            rot = node->getRotation();
            sca = node->getScale();
            if (name.equalsn("obj/", 4))
            {
                stream << "    <static-object model=\"" << Editor::toRelative(name).c_str();
                copyObj(name);

                ITexture* tex;
                for (int j = 0; (tex = node->getMaterial(0).getTexture(j)); j++)
                    copyObj(stringc("obj/") + Editor::toRelative(tex->getName()));
            } // export as static-object
            else
            {
                stream << "  <library name=\"" << Editor::getLib(node->getName()).c_str();
            } // export as library
            stream << "\" xyz=\"";
            stream << pos.X << " " << pos.Y << " " << pos.Z << "\" hpr=\"";
            stream << rot.X << " " << rot.Y << " " << rot.Z << "\" scale=\"";
            stream << sca.X << " " << sca.Y << " " << sca.Z << "\"/>\n";
        }
        i++;
    }
} // exportElements
Пример #4
0
// ----------------------------------------------------------------------------
void Track::build()
{
    IrrlichtDevice* device = Editor::getEditor()->getDevice();

    PHYSFS_setWriteDir(Editor::getEditor()->getTrackDir().c_str());
    PHYSFS_mkdir(m_file_name.c_str());

    path p = Editor::getEditor()->getTrackDir() + m_file_name;

    CMeshBuffer<S3DVertex2TCoords>* mb = m_terrain->build(p);
    SMesh smesh;
    smesh.addMeshBuffer(mb);

    for (u32 i = 1; i < m_roads.size(); i++)
    {
        IRoad* r = m_roads[i];
        if (r->getSpline()->getPointNum()>1)
            smesh.addMeshBuffer(((Road*)r)->getMeshBuffer());
    }

    B3DMeshWriter* writer = new B3DMeshWriter(device->getFileSystem());
    IWriteFile *file;
    file = device->getFileSystem()->createAndWriteFile((p + "/track.b3d").c_str());
    writer->writeMesh(file, &smesh);
    file->drop();
    delete writer;

    m_driveline->build(p);

    std::ofstream mat;
    mat.open((p + "/materials.xml").c_str());
    mat << "<materials>\n";
    mat << "  <material name=\"splatt.png\" graphical-effect=\"splatting\"";
    SMaterial m = m_terrain->getMaterial(0);
    for (int i = 1; i < 5; i++)
    {
        mat << " splatting-texture-" << i << "=\"";
        mat << Editor::toRelative(m.getTexture(i+1)->getName()).c_str();
        mat << "\"";
    }
    mat << "/>\n";

    if (m_gravity_road)
    {
        for (u32 i = 1; i < m_roads.size(); i++)
        {
            stringc tex = m_roads[i]->getTexName();
            if (tex.size()>0)
            {
                mat << "  <material name=\"";
                mat << tex.c_str();
                mat << "\" has-gravity=\"yes\" />\n";
            }
        } // roads
    } // gravity road mode

    mat <<"</materials>\n";
    mat.close();

    stringw track;
    track += "<track  name           = \"";
    track += m_track_name + L"\"\n";
    track += "        version        = \"5\"\n";
    track += "        groups         = \"made-by-STK-TE\"\n";
    track += "        designer       = \"";
    track += m_designer + "\"\n";
    track += "        music          = \"";
    track += m_music.c_str();
    track += "\"\n";
    track += "        screenshot     = \"screenshot.jpg\"\n";
    track += "        smooth-normals = \"true\"\n";
    track += "        reverse        = \"Y\"\n>\n";
    track += "</track>\n";

    PHYSFS_uint64 len = 4 * track.size();
    char*         dst = new char[len];
#ifdef _WIN32
    PHYSFS_utf8FromUcs2((PHYSFS_uint16*)track.c_str(),dst,len);
#else
    PHYSFS_utf8FromUcs4((PHYSFS_uint32*)track.c_str(), dst, len);
#endif

    FILE* f;
    f = fopen((p + "/track.xml").c_str(), "wb");
    fwrite(dst, sizeof(char), strlen(dst), f);
    fclose(f);
    delete[] dst;


    std::ofstream scene;
    scene.open((p + "/scene.xml").c_str());
    scene << "<scene>\n";
    scene << "  <track model=\"track.b3d\" x=\"0\" y=\"0\" z=\"0\">\n";

    exportElements(scene, true);
    scene << "  </track>\n";
    exportElements(scene, false);


    ISceneManager* sm = Editor::getEditor()->getSceneManager();
    ISceneNode* node;
    int i = 1;
    stringc name;
    while ((node = sm->getSceneNodeFromId(MAGIC_NUMBER + i)))
    {
        name = node->getName();
        vector3df pos;
        if (node->isVisible() && (name == "banana" || name == "item"
            || name == "small-nitro" || name == "big-nitro"))
        {
            pos = node->getPosition();
            scene << "  <" << name.c_str() << " x=\"" << pos.X << "\" y=\"" << pos.Y
                  << "\" z=\"" << pos.Z << "\" />\n";
        }
        i++;
    }

    scene << Viewport::get()->getSky()->getXmlString().c_str();

    Viewport::get()->printCheckLine(&scene);

    scene << "  <default-start   karts-per-row = \"3\"\n";
    scene << "                   forwards-distance =\"1.50\"\n";
    scene << "                   sidewards-distance=\"3.00\"\n";
    scene << "                   upwards-distance  =\"0.10\"/>\n";

    scene << "</scene>\n";
    scene.close();

    MsgWndw::get()->showMsg(_("Track exported!"));

} // build
Пример #5
0
// ----------------------------------------------------------------------------
void Track::save()
{
  FILE* pFile = 0;

  path p = Editor::getEditor()->getMapsPath() + "/" + m_file_name.c_str();
  pFile = fopen(p.c_str(), "wb");

  if (!pFile)
  {
      MsgWndw::get()->showMsg(_("Save failed: file could not be created!\n"));
      return;
  }

  // SIGN
  u64 sign = TOP_SECRET_SIGNATURE_NUMBER;
  fwrite(&sign, sizeof(u64), 1, pFile);

  // TRACK NAME
  u8 size = m_track_name.size() + 1;
  fwrite(&size, sizeof(u8), 1, pFile);
  fwrite(m_track_name.c_str(), sizeof(wchar_t), size, pFile);

  // DESIGNER NAME
  size = m_designer.size() + 1;
  fwrite(&size, sizeof(u8), 1, pFile);
  fwrite(m_designer.c_str(), sizeof(wchar_t), size, pFile);

  // FILE NAME
  size = m_file_name.size() + 1;
  fwrite(&size, sizeof(u8), 1, pFile);
  fwrite(m_file_name.c_str(), sizeof(c8), size, pFile);

  // MUSIC
  size = m_music.size() + 1;
  fwrite(&size, sizeof(u8), 1, pFile);
  fwrite(m_music.c_str(), sizeof(c8), size, pFile);

  // TERRAIN
  m_terrain->save(pFile);

  // SKY
  Viewport::get()->getSky()->save(pFile);

  // GRAVITY ROAD FLAG
  fwrite(&m_gravity_road, sizeof(bool), 1, pFile);

  // ROADS
  size = m_roads.size();
  fwrite(&size, sizeof(u8), 1, pFile);
  IRoad* r;
  for (u8 i = 0; i < size; i++)
  {
      r = m_roads[i];
      r->save(pFile);
  }

  //CHECKLINES

  Viewport::get()->saveCheckLines(pFile);

  // OBJECTS
  ISceneManager* sm = Editor::getEditor()->getSceneManager();
  ISceneNode* node;
  u32 num = Viewport::getLastEntityID() - MAGIC_NUMBER;
  u32 vnum = 0;
  for (u32 i = 0; i < num; i++)
  {
      node = sm->getSceneNodeFromId(MAGIC_NUMBER + i + 1);
      if (node && node->isVisible()) vnum++;
  }

  fwrite(&vnum, sizeof(u32), 1, pFile);

  for (u32 i = 0; i < num; i++)
  {
      node = sm->getSceneNodeFromId(MAGIC_NUMBER + i + 1);
      assert(node);
      if (node->isVisible())
      {
          fwrite(&node->getPosition(), sizeof(vector3df), 1, pFile);
          fwrite(&node->getRotation(), sizeof(vector3df), 1, pFile);
          fwrite(&node->getScale(),    sizeof(vector3df), 1, pFile);
          u8 size = strlen(node->getName()) + 1;
          fwrite(&size, sizeof(u8), 1, pFile);
          fwrite(node->getName(), sizeof(c8), size, pFile);
      }
  }
  fclose(pFile);
  Editor::getEditor()->addToRecentlyOpenedList(m_file_name);

  MsgWndw::get()->showMsg(_("Track saved!\n"));

} // save
Пример #6
0
/******************************************************************************
 * Apply explosion damage to all objects within the radius of the given
 * gameObject, scaled based on distance from the explosion, up to a maximum
 * damage as dictated by the given object's damage value. Explosions
 * affect vehicles, buildings, enemies, and Borbie.
 *****************************************************************************/
void GameInstance::applyExplosionDamage(GameObject *explodingObject) {
  // get the exploding object's variables
  GameObjectType explodingType = explodingObject->getObjectType();
  ISceneNode *explodingNode = explodingObject->getNode();
  float explosionRadius = explodingObject->getExplosionRadius();
  float explosionDamage = explodingObject->getExplosionDamage();
  vector3df explodePos = explodingNode->getPosition();

  // calculate damage to enemies
  int numEnemies = enemies->objList.size();
  for(int i=0; i<numEnemies; i++){
    ISceneNode *curNode = enemies->objList[i]->getNode();
    // if current node is the exploding node, ignore it
    if(curNode == explodingNode)
      continue;
    // if current node is NOT visible or if it already blew up, ignore it
    else if(!curNode->isVisible() || enemies->objList[i]->hasExploded())
      continue;
    float distance = curNode->getPosition().getDistanceFrom(explodePos);
    if(distance <= explosionRadius){
      int damage = explosionDamage; // max damage
      if(distance > 400){ // if more than 400 away, scale down damage
        float scale = (distance-400) / (explosionRadius-400);
        damage = int(explosionDamage * scale);
      }
      enemies->objList[i]->applyDamage(damage);
    }
  }

  // calculate damage for buildings
  int numBuild = buildings->objList.size();
  for(int i=0; i<numBuild; i++){
    ISceneNode *curNode = buildings->objList[i]->getNode();
    // if current node is the exploding node, ignore it
    if(curNode == explodingNode)
      continue;
    // if current node is NOT visible, ignore it
    else if(!curNode->isVisible() || buildings->objList[i]->hasExploded())
      continue;
    // otherwise, check if the distance is close enough, and apply damage
    //  based on the distance to the explosion center. Offset position by 200
    //  since the buildings are not positioned relative to their center.
    float distance = curNode->getPosition().getDistanceFrom(explodePos);
    if(distance <= explosionRadius){
      int damage = explosionDamage; // max damage
      if(distance > 400){ // if more than 400 away, scale down damage
        float scale = (distance-400) / (explosionRadius-400);
        damage = int(explosionDamage * scale);
      }
      // if the exploding object is a building, reduce splash damage
      //  to prevent instant-killing an entire city. That would suck.
      if(explodingType == TYPE_BUILDING)
        damage = damage / 20;
      buildings->objList[i]->applyDamage(damage);
    }
  }

  // calculate damage for vehicles
  int numVehicles = vehicles->objList.size();
  for(int i = 0 ; i < numVehicles ; i++){
    ISceneNode *curNode = vehicles->objList[i]->getNode();
    // if current node is the exploding node, ignore it
    if(curNode == explodingNode)
      continue;
    // if current node is NOT visible, ignore it
    else if(!curNode->isVisible() || vehicles->objList[i]->hasExploded())
      continue;
    // otherwise, check if the distance is close enough, and apply damage
    //  based on the distance to the explosion center
    float distance = curNode->getPosition().getDistanceFrom(explodePos);
    if(distance <= explosionRadius){
      int damage = explosionDamage; // max damage
      if(distance > 400){ // if more than 400 away, scale down damage
        float scale = (distance-400) / (explosionRadius-400);
        damage = int(explosionDamage * scale);
      }
      vehicles->objList[i]->applyDamage(damage);
    } 
  } 

  // if Borbie is already dead, don't kill her again :(
  if(player->hasExploded())
    return;

  // apply damage to borbie herself (the player)
  float distance = player->getNode()->getPosition().getDistanceFrom(explodePos);
  // if a vehicle, lower the explosion radius that applies to borbie
  if(explodingType == TYPE_VEHICLE)
    explosionRadius = 600;
  if(distance <= explosionRadius){
    int damage = explosionDamage; // max damage
    if(distance > 400){ // if more than 400 away, scale down damage
      float scale = (distance-400) / (explosionRadius-400);
      damage = int(explosionDamage * scale);
    }
    player->applyDamage(damage/2); // reduce damage by half
  }
}
Пример #7
0
void CImpostorSceneNode::OnRegisterSceneNode()
{
	if (!IsVisible)
		return;

	RenderCount++;

	// in here we:
	// decide which nodes need updates, add them to the queue
	// process the render queue
	//  allocate textures and mesh buffers if required
	// perform clean up tasks:
	//  garbage collection- free up spaces
	//  reorganise


	// get collision manager
	ISceneCollisionManager* colmgr = SceneManager->getSceneCollisionManager();

	// and the active camera
	ICameraSceneNode* cam = SceneManager->getActiveCamera();
	core::aabbox3df camBB = cam->getViewFrustum()->getBoundingBox();
	u32 now = Timer->getRealTime();

	// loop through all impostor nodes
	u32 i;
	for (i=0; i < Impostors.size(); ++i)
	{
		SNodeLink &Imp = Impostors[i];
		ISceneNode *n = Imp.Node;

		// skip invisible and culled nodes
		if (!n->isVisible() || !camBB.intersectsWithBox(n->getTransformedBoundingBox()))
		{
			//Culled++;
			Imp.IsActive = false;
			continue;
		}

		updatePosAndVector(Imp);

		// now we have the screen position...
		core::rect<s32> r = SceneManager->getVideoDriver()->getViewPort();

		if (!Imp.NewPos.isValid() || !r.isRectCollided(Imp.NewPos) )
		{
			// culled
			// Culled++;
			continue;
		}

		core::dimension2di newSize = Imp.NewPos.getSize();

		// Change in rotation: a.length >= a.dotProduct(b) <= -a.length
		f32 diff = 0;

		// far plane = never update, near plane = always update
		f32 far = cam->getFarValue();
		far *= far;
		f32 dist = Imp.Node->getAbsolutePosition().getDistanceFromSQ(cam->getAbsolutePosition());
		dist = 1.0 - (far/dist); // value between 0 and 1
		diff = dist;
		Imp.Score = dist;

		//s32 a = core::max_<s32>(Imp.NewPos.getWidth(), Imp.NewPos.getHeight());
		//diff *= f32(a);

		bool reRender = diff > Threshold;
		//reRender =true;

		reRender = reRender ||
			( !Imp.IsQueued && Imp.BufferID != -1 &&
			Buffers[Imp.BufferID].SlotSize < getTextureSizeFromSurfaceSize(core::max_<s32>(newSize.Width, newSize.Height)));

		// so small that we don't care about it
		if (newSize.Width < 4 || newSize.Height < 4)
		{
			Imp.IsActive = false;
			// object was culled
			//Culled++;
			continue;
		}

		// too large to fit in a texture slot
		if (newSize.Width > MaxSize || newSize.Height > MaxSize)
		{
			// get rid
			releaseSlot(Imp);
			Imp.IsActive = false;
		}
		else
		{
			Imp.IsActive = true;
		}

		if (Imp.IsActive && Imp.BufferID == -1 && !Imp.IsQueued )
			reRender = true;

		if (Imp.IsActive)
		{
			// impostor replaces the node
			if (reRender && now > Imp.Time + MinTime)
			{

				if (!Imp.IsQueued)
				{
					CacheMisses++;

					Imp.IsQueued = true;

					SRenderQueueItem q;
					q.Node = &Imp;
					//q.Value = val;

					RenderQueue.push_back(q);
				}
				else
				{
					//QueueHits++;
				}
			}
			else
			{
				// don't re-render the impostor texture, only draw it
				CacheHits++;
			}
		}
		if (!Imp.IsActive) // || ( Imp.BufferID == -1 && Imp.IsQueued))
		{
			// original node is visible
			n->OnRegisterSceneNode();
			// cache miss
			CacheMisses++;
		}
	}

	SceneManager->registerNodeForRendering(this, ESNRP_TRANSPARENT);
}