Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation2/src/orxonox/overlays/Map.cc @ 6427

Last change on this file since 6427 was 6394, checked in by rgrieder, 15 years ago

std::string tweaks:

  • Declared BLANKSTRING in UtilPrereqs.h as well (removed obsolete StringUtils.h includes to avoid dependencies)
  • Using BLANKSTRING if const std::string& return type is possible
  • Replaced a few (const) std::string arguments with const std::string&
  • if (str == "") —> if (str.empty())
  • std::string msg = name + "adsf"; —> const std::string& msg = name + "asdf";
  • std::string asdf = object→getFooBar(); —> const std::string& asdf = object→getFooBar();
  • std::string asdf = "asdf"; —> std::string asdf("asdf");
  • ostream << "."; and name + "." —> ostream << '.'; and name + '.'
  • str = ""; —> str.clear()
  • std::string asdf = ""; —> std::string asdf;
  • asdf_ = ""; (in c'tor) —> delete line
  • Property svn:eol-style set to native
File size: 18.6 KB
RevLine 
[2837]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Si Sun
24 *
25 */
[3196]26
[2837]27#include "Map.h"
[3089]28
[2837]29#include <string>
[3196]30
31#include <OgreBorderPanelOverlayElement.h>
32#include <OgreCamera.h>
33#include <OgreEntity.h>
34#include <OgreHardwarePixelBuffer.h>
35#include <OgreMaterialManager.h>
36#include <OgreMovablePlane.h>
37#include <OgreOverlay.h>
38#include <OgreOverlayContainer.h>
39#include <OgreOverlayManager.h>
40#include <OgrePass.h>
41#include <OgreRenderTexture.h>
42#include <OgreResourceGroupManager.h>
43#include <OgreRoot.h>
[2856]44#include <OgreSceneManager.h>
45#include <OgreSceneNode.h>
[3196]46#include <OgreTechnique.h>
[2913]47#include <OgreTexture.h>
[3196]48#include <OgreTextureManager.h>
[2913]49#include <OgreViewport.h>
[2942]50
[6394]51#include "util/StringUtils.h"
[3196]52#include "core/ConsoleCommand.h"
[2837]53#include "core/CoreIncludes.h"
[3196]54#include "core/XMLPort.h"
55#include "interfaces/RadarViewable.h"
[5735]56#include "Scene.h"
57#include "controllers/HumanController.h"
58#include "worldentities/CameraPosition.h"
59#include "worldentities/ControllableEntity.h"
[3089]60
[2837]61 namespace orxonox
62 {
63    CreateFactory(Map);
[2942]64    SetConsoleCommand(Map, openMap, true);
[2956]65    //SetConsoleCommand(Map, rotateYaw, true).setAsInputCommand();
66    //SetConsoleCommand(Map, rotatePitch, true).setAsInputCommand();
67    SetConsoleCommand(Map, Zoom, true).setAsInputCommand();
[2942]68
[3082]69
[2942]70    Map* Map::singletonMap_s = 0;
[2956]71    Ogre::SceneManager* Map::mapSceneM_s = 0;
[3101]72    Ogre::Camera* Map::Cam_ = 0;
73    Ogre::SceneNode* Map::CamNode_ = 0;
74    Ogre::MaterialPtr Map::OverlayMaterial_;// = init();
75    Ogre::Overlay* Map::overlay_ = 0;
76/*
77Ogre::MaterialPtr Map::init()
78{
79    Ogre::MaterialPtr tmp;
80    tmp.setNull();
81    return tmp;
82}
83*/
84
[2956]85    //int Map::mouseLookSpeed_ = 200;
86    //Ogre::SceneNode* Map::playerShipNode_ = 0;
87
88    const int PITCH=-30;
89    const int DISTANCE=200;
90
[2837]91    Map::Map(BaseObject* creator) : OrxonoxOverlay(creator)
92    {
93        RegisterObject(Map);
[2942]94        Map::singletonMap_s=this;
[3089]95
[2856]96        //Getting Scene Manager (Hack)
[6218]97        ObjectList<Scene>::iterator it = ObjectList<Scene>::begin();
98        this->sManager_ = it->getSceneManager();
[2956]99        if( !Map::getMapSceneManager() )
100        {
101            Map::setMapSceneManager( Ogre::Root::getSingletonPtr()->createSceneManager( Ogre::ST_GENERIC,"MapScene" ) );
102        }
[3089]103
[2956]104        this->playerShipNode_ = 0;
[2913]105        //this->sNode_ = new Ogre::SceneNode(sManager_);
106        //oManager_ = Ogre::OverlayManager::getSingletonPtr();
107        //overlay_ = oManager_->create("Map");
[2856]108        //overlay_ is member of OrxonoxOverlay
[3089]109
[2856]110        //Not Showing the map as default
[2913]111        //this->isVisible_=false;
112        //overlay_->hide();
[2956]113        this->mouseLookSpeed_ = 200;
[2913]114
[2856]115        //TestEntity
[2956]116        //Ogre::Entity * ent = mapSceneM_s->createEntity("ent", "drone.mesh");
[3089]117
[2956]118        //Map::getMapSceneManager()->getRootSceneNode()->attachObject( ent );
[2913]119        /*sNode_->setPosition(0,0,-50);
[2856]120        overlay_->add3D(sNode_);
[2913]121        */
122
[3089]123
124
125
126
[2913]127        // Alter the camera aspect ratio to match the viewport
128        //mCamera->setAspectRatio(Real(vp->getActualWidth()) / Real(vp->getActualHeight()));
[3101]129        if(!Map::Cam_)
130            Cam_ = Map::getMapSceneManager()->createCamera("ReflectCam");
[2956]131        //Cam_->setPosition(200,170, -160);
132        //Cam_->lookAt(0,0,0);
133        Cam_->setAspectRatio(1);
134        //Cam_->setRenderingDistance(0);
[3101]135        if(!Map::CamNode_)
136            CamNode_ = Map::getMapSceneManager()->getRootSceneNode()->createChildSceneNode();
[2913]137
[3089]138
[2942]139        //Create overlay material
[3101]140        if(Map::OverlayMaterial_.isNull())
141            Map::OverlayMaterial_ = this->createRenderCamera(Cam_, "RttMat");
[2913]142/*
143        Ogre::TexturePtr rttTex = Ogre::TextureManager::getSingleton().createManual("RttTex", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
144
145        Ogre::RenderTexture *renderTexture = rttTex->getBuffer()->getRenderTarget();
146
[2956]147        renderTexture->addViewport(Cam_);
[2913]148        renderTexture->getViewport(0)->setClearEveryFrame(true);
149        renderTexture->getViewport(0)->setBackgroundColour(ColourValue::Black);
150        renderTexture->getViewport(0)->setOverlaysEnabled(false);
151
152        Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create("RttMat", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
153        Ogre::Technique *technique = material->createTechnique();
154        technique->createPass();
155        material->getTechnique(0)->getPass(0)->setLightingEnabled(false);
156        material->getTechnique(0)->getPass(0)->createTextureUnitState("RttTex");
157*/
158
159
160        // create overlay
161/*
162        Ogre::Overlay* pOverlay = Ogre::OverlayManager::getSingleton().create("Overlay1");
[3089]163
[2913]164        // Create a panel with RenderToTexture texture
165        Ogre::OverlayContainer* m_pOverlayPanel = static_cast<Ogre::OverlayContainer*>(Ogre::OverlayManager::getSingleton().createOverlayElement("Panel","OverlayPanelName%d"));
166        m_pOverlayPanel->setMetricsMode(Ogre::GMM_PIXELS);
167        m_pOverlayPanel->setPosition(10, 10);
168        m_pOverlayPanel->setDimensions(500, 300);
169        // Give overlay a texture
[3089]170        m_pOverlayPanel->setMaterialName(camMat_id);
[2913]171        pOverlay->add2D(m_pOverlayPanel);
172        pOverlay->show();
173*/
[3101]174        if(!this->overlay_)
175        {
176            this->overlay_ = Ogre::OverlayManager::getSingletonPtr()->create("MapOverlay");
177            Ogre::OverlayContainer* m_pOverlayPanel = static_cast<Ogre::OverlayContainer*>(Ogre::OverlayManager::getSingleton().createOverlayElement("Panel","OverlayPanelName%d"));
178            //m_pOverlayPanel->setMetricsMode(Ogre::GMM_PIXELS);
179            //m_pOverlayPanel->setPosition(10, 10);
180            //m_pOverlayPanel->setDimensions(600, 400);
181            m_pOverlayPanel->setPosition(0.01, 0.003);
182            m_pOverlayPanel->setDimensions(0.5, 0.4);
183            // Give overlay a texture
184            m_pOverlayPanel->setMaterialName("RttMat");
185            overlay_->add2D(m_pOverlayPanel);
[3082]186
[3101]187            //Add Borders
188            Ogre::BorderPanelOverlayElement* oBorder = static_cast<Ogre::BorderPanelOverlayElement*>(Ogre::OverlayManager::getSingletonPtr()->createOverlayElement("BorderPanel", "MapBorderPanel" + getUniqueNumberString()));
189            oBorder->setBorderSize( 0.003, 0.003 );
190            oBorder->setDimensions(0.5, 0.4);
191            oBorder->setBorderMaterialName("StatsBorder");
192            oBorder->setTopBorderUV(0.49, 0.0, 0.51, 0.5);
193            oBorder->setTopLeftBorderUV(0.0, 0.0, 0.5, 0.5);
194            oBorder->setTopRightBorderUV(0.5, 0.0, 1.0, 0.5);
195            oBorder->setLeftBorderUV(0.0, 0.49, 0.5, 0.51);
196            oBorder->setRightBorderUV(0.5, 0.49, 1.0, 0.5);
197            oBorder->setBottomBorderUV(0.49, 0.5, 0.51, 1.0);
198            oBorder->setBottomLeftBorderUV(0.0, 0.5, 0.5, 1.0);
199            oBorder->setBottomRightBorderUV(0.5, 0.5, 1.0, 1.0);
200            //overlay_->add2D(oBorder);
201            m_pOverlayPanel->addChild(oBorder);
202        }
[3082]203
[3101]204
[2913]205        //Not Showing the map as default
206        this->isVisible_=false;
207        overlay_->hide();
208
[3101]209        //Create plane to show gridTypeError: blimport() takes no keyword arguments
210/*        Ogre::Entity* plane_ent;
211        if(Map::getMapSceneManager()->hasEntity("MapPlane"))
212            plane_ent = Map::getMapSceneManager()->getEntity("MapPlane");
213        else
214            plane_ent = Map::getMapSceneManager()->createEntity( "MapPlane", "plane.mesh");
215*/
216        this->movablePlane_ = new Ogre::MovablePlane( Vector3::UNIT_Y, 0 );
217        this->movablePlane_->normalise();
218
219        if(!Map::getMapSceneManager()->hasEntity("MapPlane"))
220        {
221            Ogre::Entity* plane_ent = Map::getMapSceneManager()->createEntity( "MapPlane", "plane.mesh");
222            planeNode_ = Map::getMapSceneManager()->createSceneNode();
[2977]223        //Create plane for calculations
224
[3101]225
[2942]226        //Ogre::MaterialPtr plane_mat = Ogre::MaterialManager::getSingleton().create("mapgrid", "General");
227        //plane_mat->getTechnique(0)->getPass(0)->createTextureUnitState("mapgrid.tga");
228        //plane_ent->setMaterialName("mapgrid");
[3101]229            plane_ent->setMaterialName("Map/Grid");
230            planeNode_->attachObject(plane_ent);
[3089]231
[3101]232            planeNode_->scale(160,1,160);
[3082]233//        planeNode_->attachObject(movablePlane_);
[2942]234        //Ogre::Material plane_mat = Ogre::MaterialManager::getSingletonPtr()->getByName("rock");
235
[3089]236
[2942]237        //ToDo create material script
[3101]238            Ogre::MaterialPtr myManualObjectMaterial = Ogre::MaterialManager::getSingleton().create("Map/Line","General");
239            myManualObjectMaterial->setReceiveShadows(false);
240            myManualObjectMaterial->getTechnique(0)->setLightingEnabled(true);
241            myManualObjectMaterial->getTechnique(0)->getPass(0)->setDiffuse(1,1,0,0);
242            myManualObjectMaterial->getTechnique(0)->getPass(0)->setAmbient(1,1,0);
243            myManualObjectMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1,1,0);
244        }
[2837]245    }
[2942]246
247    Map::~Map()
248    {
[2956]249        this->singletonMap_s = 0;
[3101]250        //delete this->overlay_;
[2956]251        /*if (this->isInitialized())
252        {
[2942]253        //delete sManager_;
[2956]254        //delete Map::getMapSceneManager()->getRootSceneNode();
[2942]255        //delete oManager_;
[2956]256        //delete CamNode_;
257        //delete Cam_;
258        //delete mapSceneM_s;
259        //Map::getMapSceneManager()->destroyAllEntities();
260        //Map::getMapSceneManager()->destroyAllCameras();
261        delete Map::getMapSceneManager();
262        }*/
[2942]263    }
264
[3196]265    Ogre::MaterialPtr Map::createRenderCamera(Ogre::Camera * cam, const std::string& matName)
[2913]266    {
267        Ogre::TexturePtr rttTex = Ogre::TextureManager::getSingleton().createManual(matName+"_tex", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
268
269        Ogre::RenderTexture *renderTexture = rttTex->getBuffer()->getRenderTarget();
270
271        renderTexture->addViewport(cam);
272        renderTexture->getViewport(0)->setClearEveryFrame(true);
273        renderTexture->getViewport(0)->setBackgroundColour(ColourValue::Black);
274        renderTexture->getViewport(0)->setOverlaysEnabled(false);
275
276        Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create(matName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
277        Ogre::Technique *technique = material->createTechnique();
278        technique->createPass();
279        material->getTechnique(0)->getPass(0)->setLightingEnabled(false);
280        material->getTechnique(0)->getPass(0)->createTextureUnitState(matName+"_tex");
281        return material;
282    }
283
284    void Map::updatePositions()
285    {
[2942]286
[2956]287//Ogre::Entity * ent;// = mapSceneM_s->createEntity("ent1", "drone.mesh");
[2913]288       for(ObjectList<orxonox::RadarViewable>::iterator it = ObjectList<orxonox::RadarViewable>::begin();
289            it!=ObjectList<orxonox::RadarViewable>::end();
[5929]290            ++it)
[2913]291        {
292            //COUT(0) << "Radar_Position: " << it->getRVWorldPosition() << std::endl;
293            //Ogre::SceneNode node = it->getMapNode();
294            //Ogre::Entity ent = it->getMapEntity();
295            if( !(it->MapNode_) )
296            {
[2956]297                it->MapNode_ = Map::getMapSceneManager()->getRootSceneNode()->createChildSceneNode( it->getRVWorldPosition() );
[2913]298                //it->MapNode_->translate( it->getRVOrientedVelocity(), Ogre::TS_WORLD );
[2942]299                /*if(it->getRadarObjectShape() == RadarViewable::Dot)
300                {
301                    //if( !(it->MapEntity_) )//check wether the entity is already attached
302                    //{
[2956]303                        //it->MapEntity_ = Map::getMapSceneManager()->createEntity( getUniqueNumberString(), "drone.mesh");
[2942]304                        //it->addEntity();
305                        //it->MapNode_->attachObject( it->MapEntity_ );
306                        //it->MapNode_->attachObject( it->line_ );
307                   // }
308                }*/
309                it->addMapEntity();
[2913]310            }
[3082]311            if(it->isHumanShip_)
312            {
313                this->movablePlane_->redefine(it->MapNode_->getLocalAxes().GetColumn(1) , it->MapNode_->getPosition());
314                if(it->isHumanShip_ && it->MapNode_ != this->playerShipNode_)
315                {
316                    this->playerShipNode_ = it->MapNode_;
[3101]317                    if(planeNode_ && this->planeNode_->getParent())
318                        this->planeNode_->getParent()->removeChild(this->planeNode_);
[3082]319                    this->playerShipNode_->addChild(this->planeNode_);
320                //Movable Plane needs to be attached direcly for calculations
321                //this->movablePlane_->detatchFromParent();
322                //this->movablePlane_->getParentSceneNode()->detachObject(this->movablePlane_);
323                //this->movablePlane_->redefine(it->MapNode_->getLocalAxes().GetColumn(1) , it->MapNode_->getPosition());
324                //it->MapNode_->attachObject(this->movablePlane_);
[3101]325                    if(planeNode_ && this->CamNode_->getParent())
326                        this->CamNode_->getParent()->removeChild(this->CamNode_);
[3082]327                    this->playerShipNode_->addChild(this->CamNode_);
328                    this->CamNode_->attachObject(this->Cam_);
[2956]329                //this->CamNodeHelper_ = this->CamNode_->createChildSceneNode();
330                //this->CamNodeHelper_->attachObject(this->Cam_);
[3082]331                    this->Cam_->setPosition(0, 0, DISTANCE);
[3300]332                    this->Cam_->pitch( static_cast<Degree>(PITCH) );
[3334]333                    this->Cam_->lookAt(this->playerShipNode_->getPosition());
[2977]334                //this->Cam_->setAutoTracking(true, this->playerShipNode_);
[3082]335                }
[2956]336            }
[3082]337            it->updateMapPosition();
338
339
340
[3089]341
342
343
[2913]344        }
345    }
346
[3089]347
348
[2837]349    void Map::XMLPort(Element& xmlElement, XMLPort::Mode mode)
350    {
351        SUPER(Map, XMLPort, xmlElement, mode);
[3089]352    }
[2913]353
354    void Map::changedOwner()
355    {
[3089]356        SUPER(Map, changedOwner);
[2913]357        //COUT(0) << "shipptr" << this->getOwner()->getReverseCamera() << std::endl;
[3089]358
[3325]359        ControllableEntity* entity = orxonox_cast<ControllableEntity*>(this->getOwner());
[3089]360        if(entity && entity->getReverseCamera())
[2913]361        {
362            //COUT(0) << "foo";
[3089]363            entity->getReverseCamera()->attachCamera(this->Cam_);
[2913]364        }
[2837]365    }
[2856]366
[2913]367
[2856]368    void Map::toggleVisibility()
369    {
370        if (!(this->isVisible_))
371        {
372            this->overlay_->show();
373            this->isVisible_=1;
[2942]374            //set mouselook when showing map
375            if (HumanController::localController_s && HumanController::localController_s->controllableEntity_ && !HumanController::localController_s->controllableEntity_->isInMouseLook())
376            HumanController::localController_s->controllableEntity_->mouseLook();
[2856]377        }
378        else
379        {
380            this->overlay_->hide();
381            this->isVisible_=0;
[2942]382            if (HumanController::localController_s && HumanController::localController_s->controllableEntity_ && HumanController::localController_s->controllableEntity_->isInMouseLook())
383            HumanController::localController_s->controllableEntity_->mouseLook();
[2856]384        }
385    }
[3089]386
[2856]387    //Static function to toggle visibility of the map
388    void Map::openMap()
[2837]389    {
[2856]390        for(ObjectList<orxonox::Map>::iterator it = ObjectList<orxonox::Map>::begin();
391            it!=ObjectList<orxonox::Map>::end();
[5929]392            ++it)
[2856]393        {
394        //Map * m = it->getMap();
[2942]395        //COUT(0) << it->isVisible_ << std::endl;
[2856]396        it->toggleVisibility();
[2913]397        //it->updatePositions();
[2856]398        }
[2837]399    }
[3089]400
[3196]401    // HACK!
402    void Map::hackDestroyMap()
403    {
404        Map::OverlayMaterial_.setNull();
405    }
406
[2837]407    void Map::tick(float dt)
408    {
[3082]409        //Debug
410        //COUT(0) << "MovablePlane Position: " << this->movablePlane_->getParentSceneNode()->getName() << this->movablePlane_->getParentSceneNode()->getPosition() << std::endl;
411        //COUT(0) << "planeNode_ Position: " << this->planeNode_ ->getName() << this->planeNode_->getPosition() << std::endl;
412        //COUT(0) <<  "planeNode_ Parrent Position" << this->planeNode_->getParent()->getName() << this->planeNode_->getParent()->getPosition() << std::endl;
[2942]413        if( this->isVisible_ )
414            updatePositions();
[2956]415        //Cam_->roll(Degree(1));
[3089]416
[2837]417    }
[2942]418
419    void Map::rotateYaw(const Vector2& value)
420    {
[2956]421        if(!( Map::singletonMap_s && Map::singletonMap_s->CamNode_ ))
422            return;
423
424/*
[3300]425        singletonMap_s->CamNode_->setOrientation(singletonMap_s->CamNode_->getOrientation() * Quaternion( static_cast<Degree>(-value.y * singletonMap_s->mouseLookSpeed_) , singletonMap_s->playerShipNode_->getLocalAxes().GetColumn(1) ));
[2956]426
427        Map::singletonMap_s->CamNodeHelper_->setDirection(Vector3::UNIT_Y, Ogre::Node::TS_PARENT, Vector3::UNIT_Y);
428        Map::singletonMap_s->CamNodeHelper_->lookAt(Vector3(0,0,0), Ogre::Node::TS_PARENT);
429*/
[3300]430        singletonMap_s->CamNode_->yaw( static_cast<Degree>(-value.y * singletonMap_s->mouseLookSpeed_), Ogre::Node::TS_PARENT);
[2942]431    }
432
433    void Map::rotatePitch(const Vector2& value)
434    {
[2956]435        if(!( Map::singletonMap_s && Map::singletonMap_s->CamNode_ ))
436            return;
[3300]437            //singletonMap_s->Cam_->setOrientation(singletonMap_s->Cam_->getOrientation() * Quaternion( static_cast<Degree>(-value.y * singletonMap_s->mouseLookSpeed_) , Vector3::UNIT_X));
438/*        singletonMap_s->CamNode_->setOrientation(singletonMap_s->CamNode_->getOrientation() * Quaternion( static_cast<Degree>(-value.y * singletonMap_s->mouseLookSpeed_) , singletonMap_s->playerShipNode_->getLocalAxes().GetColumn(0) ));
[2956]439
440        Map::singletonMap_s->CamNodeHelper_->setDirection(Vector3::UNIT_Y, Ogre::Node::TS_PARENT, Vector3::UNIT_Y);
441        Map::singletonMap_s->CamNodeHelper_->lookAt(Vector3(0,0,0), Ogre::Node::TS_PARENT);
442*/
[3300]443        singletonMap_s->CamNode_->pitch( static_cast<Degree>(value.y * singletonMap_s->mouseLookSpeed_), Ogre::Node::TS_LOCAL);
[3089]444
[2942]445    }
[3089]446
[2956]447    void Map::Zoom(const Vector2& value)
448    {
449        if(!( Map::singletonMap_s && Map::singletonMap_s->CamNode_ ))
450            return;
451        //COUT(0) << value.y << std::endl;
452        Map::singletonMap_s->Cam_->setPosition(0,0, Map::singletonMap_s->Cam_->getPosition().z + value.y * Map::singletonMap_s->mouseLookSpeed_ );
453    }
[2837]454 }
Note: See TracBrowser for help on using the repository browser.