challenge.cpp
Go to the documentation of this file.
00001 /*
00002         Challenge - Virtual Robot Challenge System
00003         Copyright (C) 1999--2008:
00004                 Stephane Magnenat <stephane at magnenat dot net>
00005                 (http://stephane.magnenat.net)
00006         3D models
00007         Copyright (C) 2008:
00008                 Basilio Noris
00009         Aseba - an event-based framework for distributed robot control
00010         Copyright (C) 2007--2012:
00011                 Stephane Magnenat <stephane at magnenat dot net>
00012                 (http://stephane.magnenat.net)
00013                 and other contributors, see authors.txt for details
00014         
00015         This program is free software: you can redistribute it and/or modify
00016         it under the terms of the GNU Lesser General Public License as published
00017         by the Free Software Foundation, version 3 of the License.
00018         
00019         This program is distributed in the hope that it will be useful,
00020         but WITHOUT ANY WARRANTY; without even the implied warranty of
00021         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022         GNU Lesser General Public License for more details.
00023         
00024         You should have received a copy of the GNU Lesser General Public License
00025         along with this program. If not, see <http://www.gnu.org/licenses/>.
00026 */
00027 
00028 #ifndef ASEBA_ASSERT
00029 #define ASEBA_ASSERT
00030 #endif
00031 
00032 #include "../../vm/vm.h"
00033 #include "../../vm/natives.h"
00034 #include "../../common/productids.h"
00035 #include "../../common/consts.h"
00036 #include "../../transport/buffer/vm-buffer.h"
00037 #include <dashel/dashel.h>
00038 #include <enki/PhysicalEngine.h>
00039 #include <enki/robots/e-puck/EPuck.h>
00040 #include <iostream>
00041 #include <QtGui>
00042 #include <QtDebug>
00043 #include "challenge.h"
00044 #include <challenge.moc>
00045 #include <string.h>
00046 
00047 #define SIMPLIFIED_EPUCK
00048 
00049 static void initTexturesResources()
00050 {
00051         Q_INIT_RESOURCE(challenge_textures);
00052 }
00053 
00055 template<typename Derived, typename Base>
00056 inline Derived polymorphic_downcast(Base base)
00057 {
00058         Derived derived = dynamic_cast<Derived>(base);
00059         assert(derived);
00060         return derived;
00061 }
00062 
00063 // Definition of the aseba glue
00064 
00065 namespace Enki
00066 {
00067         class AsebaFeedableEPuck;
00068 }
00069 
00070 // map for aseba glue code
00071 typedef QMap<AsebaVMState*, Enki::AsebaFeedableEPuck*>  VmEPuckMap;
00072 static VmEPuckMap asebaEPuckMap;
00073 
00074 static AsebaNativeFunctionPointer nativeFunctions[] =
00075 {
00076         ASEBA_NATIVES_STD_FUNCTIONS,
00077 };
00078 
00079 static const AsebaNativeFunctionDescription* nativeFunctionsDescriptions[] =
00080 {
00081         ASEBA_NATIVES_STD_DESCRIPTIONS,
00082         0
00083 };
00084 
00085 // changed by selection dialog
00086 static QString localName;
00087 
00088 extern "C" AsebaVMDescription vmDescription_en;
00089 extern "C" AsebaVMDescription vmDescription_fr;
00090 
00091 namespace Enki
00092 {
00093         #define EPUCK_FEEDER_INITIAL_ENERGY             10
00094         #define EPUCK_FEEDER_THRESHOLD_HIDE             2
00095         #define EPUCK_FEEDER_THRESHOLD_SHOW             4
00096         #define EPUCK_FEEDER_RADIUS                             5
00097         #define EPUCK_FEEDER_RADIUS_DEAD                6
00098         #define EPUCK_FEEDER_RANGE                              10
00099         
00100         #define EPUCK_FEEDER_COLOR_ACTIVE               Color::blue
00101         #define EPUCK_FEEDER_COLOR_INACTIVE             Color::red
00102         #define EPUCK_FEEDER_COLOR_DEAD                 Color::gray
00103         
00104         #define EPUCK_FEEDER_D_ENERGY                   4
00105         #define EPUCK_FEEDER_RECHARGE_RATE              0.5
00106         #define EPUCK_FEEDER_MAX_ENERGY                 100
00107         
00108         #define EPUCK_FEEDER_LIFE_SPAN                  60
00109         #define EPUCK_FEEDER_DEATH_SPAN                 10
00110         
00111         #define EPUCK_INITIAL_ENERGY                    10
00112         #define EPUCK_ENERGY_CONSUMPTION_RATE   1
00113         
00114         #define DEATH_ANIMATION_STEPS                   30
00115         #define PORT_BASE                                               ASEBA_DEFAULT_PORT
00116         
00117         extern GLint GenFeederBase();
00118         extern GLint GenFeederCharge0();
00119         extern GLint GenFeederCharge1();
00120         extern GLint GenFeederCharge2();
00121         extern GLint GenFeederCharge3();
00122         extern GLint GenFeederRing();
00123         
00124         class FeedableEPuck: public EPuck
00125         {
00126         public:
00127                 double energy;
00128                 double score;
00129                 QString name;
00130                 int diedAnimation;
00131         
00132         public:
00133                 FeedableEPuck() : EPuck(CAPABILITY_BASIC_SENSORS | CAPABILITY_CAMERA), energy(EPUCK_INITIAL_ENERGY), score(0), diedAnimation(-1) { }
00134                 
00135                 virtual void controlStep(double dt)
00136                 {
00137                         EPuck::controlStep(dt);
00138                         
00139                         energy -= dt * EPUCK_ENERGY_CONSUMPTION_RATE;
00140                         score += dt;
00141                         if (energy < 0)
00142                         {
00143                                 score /= 2;
00144                                 energy = EPUCK_INITIAL_ENERGY;
00145                                 diedAnimation = DEATH_ANIMATION_STEPS;
00146                         }
00147                         else if (diedAnimation >= 0)
00148                                 diedAnimation--;
00149                 }
00150         };
00151         
00152         class AsebaFeedableEPuck : public FeedableEPuck, public Dashel::Hub
00153         {
00154         public:
00155                 Dashel::Stream* stream;
00156                 AsebaVMState vm;
00157                 std::valarray<unsigned short> bytecode;
00158                 std::valarray<signed short> stack;
00159                 struct Variables
00160                 {
00161                         sint16 productId; // product id
00162                         sint16 speedL; // left motor speed
00163                         sint16 speedR; // right motor speed
00164                         sint16 colorR; // body red [0..100] %
00165                         sint16 colorG; // body green [0..100] %
00166                         sint16 colorB; // body blue [0..100] %
00167                         #ifdef SIMPLIFIED_EPUCK
00168                         sint16 dist_A[8];       // proximity sensors in dist [cm] as variables, normal e-puck order
00169                         sint16 dist_B[8];       // proximity sensors in dist [cm] as array, normal e-puck order
00170                         #else
00171                         sint16 prox[8];         // proximity sensors, normal e-puck order
00172                         #endif
00173                         #ifdef SIMPLIFIED_EPUCK
00174                         sint16 camR_A[3]; // camera red as variables (left, middle, right) [0..100] %
00175                         sint16 camR_B[3]; // camera red as array (left, middle, right) [0..100] %
00176                         sint16 camG_A[3]; // camera green as variables (left, middle, right) [0..100] %
00177                         sint16 camG_B[3]; // camera green as array (left, middle, right) [0..100] %
00178                         sint16 camB_A[3]; // camera blue as variables (left, middle, right) [0..100] %
00179                         sint16 camB_B[3]; // camera blue as array (left, middle, right) [0..100] %
00180                         #else
00181                         sint16 camR[60]; // camera red (left, middle, right) [0..100] %
00182                         sint16 camG[60]; // camera green (left, middle, right) [0..100] %
00183                         sint16 camB[60]; // camera blue (left, middle, right) [0..100] %
00184                         #endif
00185                         sint16 energy;
00186                         sint16 user[1024];
00187                 } variables;
00188                 int port;
00189                 
00190                 uint16 lastMessageSource;
00191                 std::valarray<uint8> lastMessageData;
00192                 
00193         public:
00194                 AsebaFeedableEPuck(int id) :
00195                         stream(0)
00196                 {
00197                         asebaEPuckMap[&vm] = this;
00198                         
00199                         vm.nodeId = 1;
00200                         
00201                         bytecode.resize(512);
00202                         vm.bytecode = &bytecode[0];
00203                         vm.bytecodeSize = bytecode.size();
00204                         
00205                         stack.resize(64);
00206                         vm.stack = &stack[0];
00207                         vm.stackSize = stack.size();
00208                         
00209                         vm.variables = reinterpret_cast<sint16 *>(&variables);
00210                         vm.variablesSize = sizeof(variables) / sizeof(sint16);
00211                         
00212                         port = PORT_BASE+id;
00213                         try
00214                         {
00215                                 Dashel::Hub::connect(QString("tcpin:port=%1").arg(port).toStdString());
00216                         }
00217                         catch (Dashel::DashelException e)
00218                         {
00219                                 QMessageBox::critical(0, QApplication::tr("Aseba Challenge"), QApplication::tr("Cannot create listening port %0: %1").arg(port).arg(e.what()));
00220                                 abort();
00221                         }
00222                         
00223                         AsebaVMInit(&vm);
00224                         
00225                         variables.productId = ASEBA_PID_CHALLENGE;
00226                         variables.colorG = 100;
00227                 }
00228                 
00229                 virtual ~AsebaFeedableEPuck()
00230                 {
00231                         asebaEPuckMap.remove(&vm);
00232                 }
00233                 
00234         public:
00235                 void connectionCreated(Dashel::Stream *stream)
00236                 {
00237                         std::string targetName = stream->getTargetName();
00238                         if (targetName.substr(0, targetName.find_first_of(':')) == "tcp")
00239                         {
00240                                 qDebug() << this << " : New client connected.";
00241                                 if (this->stream)
00242                                 {
00243                                         closeStream(this->stream);
00244                                         qDebug() << this << " : Disconnected old client.";
00245                                 }
00246                                 this->stream = stream;
00247                         }
00248                 }
00249                 
00250                 void incomingData(Dashel::Stream *stream)
00251                 {
00252                         uint16 temp;
00253                         uint16 len;
00254                         
00255                         stream->read(&temp, 2);
00256                         len = bswap16(temp);
00257                         stream->read(&temp, 2);
00258                         lastMessageSource = bswap16(temp);
00259                         lastMessageData.resize(len+2);
00260                         stream->read(&lastMessageData[0], lastMessageData.size());
00261                         
00262                         if (bswap16(*(uint16*)&lastMessageData[0]) >= 0xA000)
00263                                 AsebaProcessIncomingEvents(&vm);
00264                         else
00265                                 qDebug() << this << " : Non debug event dropped.";
00266                 }
00267                 
00268                 void connectionClosed(Dashel::Stream *stream, bool abnormal)
00269                 {
00270                         if (stream == this->stream)
00271                         {
00272                                 this->stream = 0;
00273                                 // clear breakpoints
00274                                 vm.breakpointsCount = 0;
00275                         }
00276                         if (abnormal)
00277                                 qDebug() << this << " : Client has disconnected unexpectedly.";
00278                         else
00279                                 qDebug() << this << " : Client has disconnected properly.";
00280                 }
00281                 
00282                 double toDoubleClamp(sint16 val, double mul, double min, double max)
00283                 {
00284                         double v = static_cast<double>(val) * mul;
00285                         if (v > max)
00286                                 v = max;
00287                         else if (v < min)
00288                                 v = min;
00289                         return v;
00290                 }
00291                 
00292                 void controlStep(double dt)
00293                 {
00294                         // set physical variables
00295                         leftSpeed = toDoubleClamp(variables.speedL, 1, -13, 13);
00296                         rightSpeed = toDoubleClamp(variables.speedR, 1, -13, 13);
00297                         Color c;
00298                         c.setR(toDoubleClamp(variables.colorR, 0.01, 0, 1));
00299                         c.setG(toDoubleClamp(variables.colorG, 0.01, 0, 1));
00300                         c.setB(toDoubleClamp(variables.colorB, 0.01, 0, 1));
00301                         setColor(c);
00302                         
00303                         // do motion
00304                         FeedableEPuck::controlStep(dt);
00305                         
00306                         // get physical variables
00307                         #ifdef SIMPLIFIED_EPUCK
00308                         variables.dist_A[0] = static_cast<sint16>(infraredSensor0.getDist());
00309                         variables.dist_A[1] = static_cast<sint16>(infraredSensor1.getDist());
00310                         variables.dist_A[2] = static_cast<sint16>(infraredSensor2.getDist());
00311                         variables.dist_A[3] = static_cast<sint16>(infraredSensor3.getDist());
00312                         variables.dist_A[4] = static_cast<sint16>(infraredSensor4.getDist());
00313                         variables.dist_A[5] = static_cast<sint16>(infraredSensor5.getDist());
00314                         variables.dist_A[6] = static_cast<sint16>(infraredSensor6.getDist());
00315                         variables.dist_A[7] = static_cast<sint16>(infraredSensor7.getDist());
00316                         for (size_t i = 0; i < 8; ++i)
00317                                 variables.dist_B[i] = variables.dist_A[i];
00318                         #else
00319                         variables.prox[0] = static_cast<sint16>(infraredSensor0.finalValue);
00320                         variables.prox[1] = static_cast<sint16>(infraredSensor1.finalValue);
00321                         variables.prox[2] = static_cast<sint16>(infraredSensor2.finalValue);
00322                         variables.prox[3] = static_cast<sint16>(infraredSensor3.finalValue);
00323                         variables.prox[4] = static_cast<sint16>(infraredSensor4.finalValue);
00324                         variables.prox[5] = static_cast<sint16>(infraredSensor5.finalValue);
00325                         variables.prox[6] = static_cast<sint16>(infraredSensor6.finalValue);
00326                         variables.prox[7] = static_cast<sint16>(infraredSensor7.finalValue);
00327                         #endif
00328                         
00329                         #ifdef SIMPLIFIED_EPUCK
00330                         for (size_t i = 0; i < 3; i++)
00331                         {
00332                                 double sumR = 0;
00333                                 double sumG = 0;
00334                                 double sumB = 0;
00335                                 for (size_t j = 0; j < 20; j++)
00336                                 {
00337                                         size_t index = 59 - (i * 20 + j);
00338                                         sumR += camera.image[index].r();
00339                                         sumG += camera.image[index].g();
00340                                         sumB += camera.image[index].b();
00341                                 }
00342                                 variables.camR_A[i] = variables.camR_B[i] = static_cast<sint16>(sumR * 100. / 20.);
00343                                 variables.camG_A[i] = variables.camG_B[i] = static_cast<sint16>(sumG * 100. / 20.);
00344                                 variables.camB_A[i] = variables.camB_B[i] = static_cast<sint16>(sumB * 100. / 20.);
00345                         }
00346                         #else
00347                         for (size_t i = 0; i < 60; i++)
00348                         {
00349                                 variables.camR[i] = static_cast<sint16>(camera.image[i].r() * 100.);
00350                                 variables.camG[i] = static_cast<sint16>(camera.image[i].g() * 100.);
00351                                 variables.camB[i] = static_cast<sint16>(camera.image[i].b() * 100.);
00352                         }
00353                         #endif
00354                         
00355                         variables.energy = static_cast<sint16>(energy);
00356                         
00357                         // do a network step
00358                         Hub::step();
00359                         
00360                         // run VM
00361                         AsebaVMRun(&vm, 65535);
00362                         
00363                         // reschedule a periodic event if we are not in step by step
00364                         if (AsebaMaskIsClear(vm.flags, ASEBA_VM_STEP_BY_STEP_MASK) || AsebaMaskIsClear(vm.flags, ASEBA_VM_EVENT_ACTIVE_MASK))
00365                                 AsebaVMSetupEvent(&vm, ASEBA_EVENT_LOCAL_EVENTS_START);
00366                 }
00367         };
00368         
00369         class EPuckFeeding : public LocalInteraction
00370         {
00371         public:
00372                 double energy;
00373                 double age;
00374                 bool alive;
00375 
00376         public :
00377                 EPuckFeeding(Robot *owner, double age) : energy(EPUCK_FEEDER_INITIAL_ENERGY), age(age)
00378                 {
00379                         r = EPUCK_FEEDER_RANGE;
00380                         this->owner = owner;
00381                         alive = true;
00382                 }
00383                 
00384                 void objectStep(double dt, World *w, PhysicalObject *po)
00385                 {
00386                         if (alive)
00387                         {
00388                                 FeedableEPuck *epuck = dynamic_cast<FeedableEPuck *>(po);
00389                                 if (epuck && energy > 0)
00390                                 {
00391                                         double dEnergy = dt * EPUCK_FEEDER_D_ENERGY;
00392                                         epuck->energy += dEnergy;
00393                                         energy -= dEnergy;
00394                                         if (energy < EPUCK_FEEDER_THRESHOLD_HIDE)
00395                                                 owner->setColor(EPUCK_FEEDER_COLOR_INACTIVE);
00396                                 }
00397                         }
00398                 }
00399                 
00400                 void finalize(double dt, World *w)
00401                 {
00402                         age += dt;
00403                         if (alive)
00404                         {
00405                                 if ((energy < EPUCK_FEEDER_THRESHOLD_SHOW) && (energy+dt >= EPUCK_FEEDER_THRESHOLD_SHOW))
00406                                         owner->setColor(EPUCK_FEEDER_COLOR_ACTIVE);
00407                                 energy += EPUCK_FEEDER_RECHARGE_RATE * dt;
00408                                 if (energy > EPUCK_FEEDER_MAX_ENERGY)
00409                                         energy = EPUCK_FEEDER_MAX_ENERGY;
00410                                 
00411                                 if (age > EPUCK_FEEDER_LIFE_SPAN)
00412                                 {
00413                                         alive = false;
00414                                         age = 0;
00415                                         owner->setColor(EPUCK_FEEDER_COLOR_DEAD);
00416                                         owner->setCylindric(EPUCK_FEEDER_RADIUS_DEAD, owner->getHeight(), owner->getMass());
00417                                 }
00418                         }
00419                         else
00420                         {
00421                                 if (age > EPUCK_FEEDER_DEATH_SPAN)
00422                                 {
00423                                         alive = true;
00424                                         age = 0;
00425                                         owner->setColor(EPUCK_FEEDER_COLOR_ACTIVE);
00426                                         owner->setCylindric(EPUCK_FEEDER_RADIUS, owner->getHeight(), owner->getMass());
00427                                 }
00428                         }
00429                 }
00430         };
00431         
00432         class EPuckFeeder : public Robot
00433         {
00434         public:
00435                 EPuckFeeding feeding;
00436         
00437         public:
00438                 EPuckFeeder(double age) : feeding(this, age)
00439                 {
00440                         setCylindric(EPUCK_FEEDER_RADIUS, 5, -1);
00441                         addLocalInteraction(&feeding);
00442                         setColor(EPUCK_FEEDER_COLOR_ACTIVE);
00443                 }
00444         };
00445         
00446         class FeederModel : public ViewerWidget::CustomRobotModel
00447         {
00448         public:
00449                 FeederModel(ViewerWidget* viewer)
00450                 {
00451                         textures.resize(2);
00452                         textures[0] = viewer->bindTexture(QPixmap(QString(":/textures/feeder.png")), GL_TEXTURE_2D);
00453                         textures[1] = viewer->bindTexture(QPixmap(QString(":/textures/feederr.png")), GL_TEXTURE_2D, GL_LUMINANCE8);
00454                         lists.resize(6);
00455                         lists[0] = GenFeederBase();
00456                         lists[1] = GenFeederCharge0();
00457                         lists[2] = GenFeederCharge1();
00458                         lists[3] = GenFeederCharge2();
00459                         lists[4] = GenFeederCharge3();
00460                         lists[5] = GenFeederRing();
00461                 }
00462                 
00463                 void cleanup(ViewerWidget* viewer)
00464                 {
00465                         for (int i = 0; i < textures.size(); i++)
00466                                 viewer->deleteTexture(textures[i]);
00467                         for (int i = 0; i < lists.size(); i++)
00468                                 glDeleteLists(lists[i], 1);
00469                 }
00470                 
00471                 virtual void draw(PhysicalObject* object) const
00472                 {
00473                         EPuckFeeder* feeder = polymorphic_downcast<EPuckFeeder*>(object);
00474                         double age = feeder->feeding.age;
00475                         bool alive = feeder->feeding.alive;
00476                         
00477                         glEnable(GL_TEXTURE_2D);
00478                         glBindTexture(GL_TEXTURE_2D, textures[0]);
00479                         
00480                         glPushMatrix();
00481                         double disp;
00482                         if (age < M_PI/2)
00483                         {
00484                                 //glTranslated(0, 0, -0.2);
00485                                 if (alive)
00486                                         disp = -1 + sin(age);
00487                                 else
00488                                         disp = -sin(age);
00489                         }
00490                         else
00491                         {
00492                                 if (alive)
00493                                         disp = 0;
00494                                 else
00495                                         disp = -1;
00496                         }
00497                         
00498                         glTranslated(0, 0, 4.3*disp-0.2);
00499                         
00500                         // body
00501                         glColor3d(1, 1, 1);
00502                         glCallList(lists[0]);
00503                         
00504                         // ring
00505                         glColor3d(0.6+object->getColor().components[0]-0.3*object->getColor().components[1]-0.3*object->getColor().components[2], 0.6+object->getColor().components[1]-0.3*object->getColor().components[0]-0.3*object->getColor().components[2], 0.6+object->getColor().components[2]-0.3*object->getColor().components[0]-0.3*object->getColor().components[1]);
00506                         glCallList(lists[5]);
00507                         
00508                         // food
00509                         glColor3d(0.3, 0.3, 1);
00510                         int foodAmount = (int)((feeder->feeding.energy * 5) / (EPUCK_FEEDER_MAX_ENERGY + 0.001));
00511                         assert(foodAmount <= 4);
00512                         for (int i = 0; i < foodAmount; i++)
00513                                 glCallList(lists[1+i]);
00514                         
00515                         glPopMatrix();
00516                         
00517                         // shadow
00518                         glColor3d(1, 1, 1);
00519                         glBindTexture(GL_TEXTURE_2D, textures[1]);
00520                         glDisable(GL_LIGHTING);
00521                         glEnable(GL_BLEND);
00522                         glBlendFunc(GL_ZERO, GL_SRC_COLOR);
00523                         
00524                         // bottom shadow
00525                         glPushMatrix();
00526                         // disable writing of z-buffer
00527                         glDepthMask( GL_FALSE );
00528                         glEnable(GL_POLYGON_OFFSET_FILL);
00529                         //glScaled(1-disp*0.1, 1-disp*0.1, 1);
00530                         glBegin(GL_QUADS);
00531                         glTexCoord2f(1.f, 0.f);
00532                         glVertex2f(-7.5f, -7.5f);
00533                         glTexCoord2f(1.f, 1.f);
00534                         glVertex2f(7.5f, -7.5f);
00535                         glTexCoord2f(0.f, 1.f);
00536                         glVertex2f(7.5f, 7.5f);
00537                         glTexCoord2f(0.f, 0.f);
00538                         glVertex2f(-7.5f, 7.5f);
00539                         glEnd();
00540                         glDisable(GL_POLYGON_OFFSET_FILL);
00541                         glDepthMask( GL_TRUE );
00542                         glPopMatrix();
00543                         
00544                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00545                         glDisable(GL_BLEND);
00546                         glEnable(GL_LIGHTING);
00547                         
00548                         glDisable(GL_TEXTURE_2D);
00549                 }
00550                 
00551                 virtual void drawSpecial(PhysicalObject* object, int param) const
00552                 {
00553                         /*glEnable(GL_BLEND);
00554                         glBlendFunc(GL_ONE, GL_ONE);
00555                         glDisable(GL_TEXTURE_2D);
00556                         glCallList(lists[0]);
00557                         glDisable(GL_BLEND);*/
00558                 }
00559         };
00560 
00561         // Challenge Viewer
00562         
00563         ChallengeViewer::ChallengeViewer(World* world, int ePuckCount) : ViewerWidget(world), ePuckCount(ePuckCount)
00564         {
00565                 savingVideo = false;
00566                 autoCamera = false;
00567                 initTexturesResources();
00568                 
00569                 int res = QFontDatabase::addApplicationFont(":/fonts/SF Old Republic SC.ttf");
00570                 Q_ASSERT(res != -1);
00571                 Q_UNUSED(res);
00572                 //qDebug() << QFontDatabase::applicationFontFamilies(res);
00573                 titleFont = QFont("SF Old Republic SC", 20);
00574                 entryFont = QFont("SF Old Republic SC", 23);
00575                 labelFont = QFont("SF Old Republic SC", 16);
00576                 
00577                 setMouseTracking(true);
00578                 setAttribute(Qt::WA_OpaquePaintEvent);
00579                 setAttribute(Qt::WA_NoSystemBackground);
00580                 setAutoFillBackground(false);
00581                 //resize(780, 560);
00582         }
00583         
00584         void ChallengeViewer::addNewRobot()
00585         {
00586                 bool ok;
00587                 QString eventName = QInputDialog::getText(this, tr("Add a new robot"), tr("Robot name:"), QLineEdit::Normal, "", &ok);
00588                 if (ok && !eventName.isEmpty())
00589                 {
00590                         // TODO change ePuckCount to port
00591                         Enki::AsebaFeedableEPuck* epuck = new Enki::AsebaFeedableEPuck(ePuckCount++);
00592                         epuck->pos.x = Enki::random.getRange(120)+10;
00593                         epuck->pos.y = Enki::random.getRange(120)+10;
00594                         epuck->name = eventName;
00595                         world->addObject(epuck);
00596                 }
00597         }
00598         
00599         void ChallengeViewer::removeRobot()
00600         {
00601                 std::set<AsebaFeedableEPuck *> toFree;
00602                 // TODO: for now, remove all robots; later, show a gui box to choose which robot to remove
00603                 for (World::ObjectsIterator it = world->objects.begin(); it != world->objects.end(); ++it)
00604                 {
00605                         AsebaFeedableEPuck *epuck = dynamic_cast<AsebaFeedableEPuck*>(*it);
00606                         if (epuck)
00607                                 toFree.insert(epuck);
00608                 }
00609                 
00610                 for (std::set<AsebaFeedableEPuck *>::iterator it = toFree.begin(); it != toFree.end(); ++it)
00611                 {
00612                         world->removeObject(*it);
00613                         delete *it;
00614                 }
00615                 ePuckCount = 0;
00616         }
00617 
00618         void ChallengeViewer::autoCameraStateChanged(bool state)
00619         {
00620                 autoCamera = state;
00621         }
00622         
00623         void ChallengeViewer::timerEvent(QTimerEvent * event)
00624         {
00625                 if (autoCamera)
00626                 {
00627                         altitude = 70;
00628                         yaw += 0.002;
00629                         pos = QPointF(-world->w/2 + 120*sin(yaw+M_PI/2), -world->h/2 + 120*cos(yaw+M_PI/2));
00630                         if (yaw > 2*M_PI)
00631                                 yaw -= 2*M_PI;
00632                         pitch = M_PI/7  ;
00633                 }
00634                 ViewerWidget::timerEvent(event);
00635         }
00636 /*
00637         void ChallengeViewer::mouseMoveEvent ( QMouseEvent * event )
00638         {
00639                 #ifndef Q_WS_MAC
00640 
00641                 bool isInButtonArea = event->y() < addRobotButton->y() + addRobotButton->height() + 10;
00642                 if (hideButtons->isChecked())
00643                 {
00644                         if (isInButtonArea && !addRobotButton->isVisible())
00645                         {
00646                                 menuFrame->show();
00647                         }
00648                         if (!isInButtonArea && addRobotButton->isVisible())
00649                         {
00650                                 menuFrame->hide();
00651                         }
00652                 }
00653 
00654                 #endif // Q_WS_MAC
00655                 
00656                 ViewerWidget::mouseMoveEvent(event);
00657         }
00658 */
00659         void ChallengeViewer::keyPressEvent ( QKeyEvent * event )
00660         {
00661                 if (event->key() == Qt::Key_V)
00662                         savingVideo = true;
00663                 else
00664                         ViewerWidget::keyPressEvent(event);
00665         }
00666         
00667         void ChallengeViewer::keyReleaseEvent ( QKeyEvent * event )
00668         {
00669                 if (event->key() == Qt::Key_V)
00670                         savingVideo = false;
00671                 else
00672                         ViewerWidget::keyReleaseEvent (event);
00673         }
00674         
00675         void ChallengeViewer::drawQuad2D(double x, double y, double w, double ar)
00676         {
00677                 double thisAr = (double)width() / (double)height();
00678                 double h = (w * thisAr) / ar;
00679                 glBegin(GL_QUADS);
00680                 glTexCoord2d(0, 1);
00681                 glVertex2d(x, y);
00682                 glTexCoord2d(1, 1);
00683                 glVertex2d(x+w, y);
00684                 glTexCoord2d(1, 0);
00685                 glVertex2d(x+w, y+h);
00686                 glTexCoord2d(0, 0);
00687                 glVertex2d(x, y+h);
00688                 glEnd();
00689         }
00690         
00691         void ChallengeViewer::initializeGL()
00692         {
00693                 ViewerWidget::initializeGL();
00694         }
00695         
00696         void ChallengeViewer::renderObjectsTypesHook()
00697         {
00698                 // render vrcs specific static types
00699                 managedObjects[&typeid(EPuckFeeder)] = new FeederModel(this);
00700                 managedObjectsAliases[&typeid(AsebaFeedableEPuck)] = &typeid(EPuck);
00701         }
00702         
00703         void ChallengeViewer::displayObjectHook(PhysicalObject *object)
00704         {
00705                 FeedableEPuck *epuck = dynamic_cast<FeedableEPuck*>(object);
00706                 if ((epuck) && (epuck->diedAnimation >= 0))
00707                 {
00708                         ViewerUserData *userData = dynamic_cast<ViewerUserData *>(epuck->userData);
00709                         assert(userData);
00710                         
00711                         double dist = (double)(DEATH_ANIMATION_STEPS - epuck->diedAnimation);
00712                         double coeff =  (double)(epuck->diedAnimation) / DEATH_ANIMATION_STEPS;
00713                         glColor3d(0.2*coeff, 0.2*coeff, 0.2*coeff);
00714                         glTranslated(0, 0, 2. * dist);
00715                         userData->drawSpecial(object);
00716                 }
00717                 /*FeedableEPuck *epuck = dynamic_cast<FeedableEPuck*>(object);
00718                 {
00719                 }*/
00720         }
00721         
00722         void ChallengeViewer::sceneCompletedHook()
00723         {
00724                 // create a map with names and scores
00725                 qglColor(Qt::black);
00726                 QMultiMap<int, QStringList> scores;
00727                 for (World::ObjectsIterator it = world->objects.begin(); it != world->objects.end(); ++it)
00728                 {
00729                         AsebaFeedableEPuck *epuck = dynamic_cast<AsebaFeedableEPuck*>(*it);
00730                         if (epuck)
00731                         {
00732                                 QStringList entry;
00733                                 entry << epuck->name << QString::number(epuck->port) << QString::number((int)epuck->energy) << QString::number((int)epuck->score);
00734                                 scores.insert((int)epuck->score, entry);
00735                                 renderText(epuck->pos.x, epuck->pos.y, 10, epuck->name, labelFont);
00736                         }
00737                 }
00738                 
00739                 // build score texture
00740                 QImage scoreBoard(512, 256, QImage::Format_ARGB32);
00741                 scoreBoard.setDotsPerMeterX(2350);
00742                 scoreBoard.setDotsPerMeterY(2350);
00743                 QPainter painter(&scoreBoard);
00744                 //painter.fillRect(scoreBoard.rect(), QColor(224,224,255,196));
00745                 painter.fillRect(scoreBoard.rect(), QColor(224,255,224,196));
00746                 
00747                 // draw lines
00748                 painter.setBrush(Qt::NoBrush);
00749                 QPen pen(Qt::black);
00750                 pen.setWidth(2);
00751                 painter.setPen(pen);
00752                 painter.drawRect(scoreBoard.rect());
00753                 pen.setWidth(1);
00754                 painter.setPen(pen);
00755                 painter.drawLine(22, 34, 504, 34);
00756                 painter.drawLine(312, 12, 312, 247);
00757                 painter.drawLine(312, 240, 504, 240);
00758                 
00759                 // draw title
00760                 painter.setFont(titleFont);
00761                 painter.drawText(35, 28, "name");
00762                 painter.drawText(200, 28, "port");
00763                 painter.drawText(324, 28, "energy");
00764                 painter.drawText(430, 28, "points");
00765                 
00766                 // display entries
00767                 QMapIterator<int, QStringList> it(scores);
00768                 
00769                 it.toBack();
00770                 int pos = 61;
00771                 while (it.hasPrevious())
00772                 {
00773                         it.previous();
00774                         painter.drawText(200, pos, it.value().at(1));
00775                         pos += 24;
00776                 }
00777                 
00778                 it.toBack();
00779                 painter.setFont(entryFont);
00780                 pos = 61;
00781                 while (it.hasPrevious())
00782                 {
00783                         it.previous();
00784                         painter.drawText(35, pos, it.value().at(0));
00785                         painter.drawText(335, pos, it.value().at(2));
00786                         painter.drawText(445, pos, it.value().at(3));
00787                         pos += 24;
00788                 }
00789                 
00790                 glDisable(GL_LIGHTING);
00791                 glEnable(GL_TEXTURE_2D);
00792                 GLuint tex = bindTexture(scoreBoard, GL_TEXTURE_2D);
00793                 glEnable(GL_BLEND);
00794                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00795                 
00796                 glCullFace(GL_FRONT);
00797                 glColor4d(1, 1, 1, 0.75);
00798                 for (int i = 0; i < 4; i++)
00799                 {
00800                         glPushMatrix();
00801                         glTranslated(world->w/2, world->h/2, 50);
00802                         glRotated(90*i, 0, 0, 1);
00803                         glBegin(GL_QUADS);
00804                         glTexCoord2d(0, 0);
00805                         glVertex3d(-20, -20, 0);
00806                         glTexCoord2d(1, 0);
00807                         glVertex3d(20, -20, 0);
00808                         glTexCoord2d(1, 1);
00809                         glVertex3d(20, -20, 20);
00810                         glTexCoord2d(0, 1);
00811                         glVertex3d(-20, -20, 20);
00812                         glEnd();
00813                         glPopMatrix();
00814                 }
00815                 
00816                 glCullFace(GL_BACK);
00817                 glColor3d(1, 1, 1);
00818                 for (int i = 0; i < 4; i++)
00819                 {
00820                         glPushMatrix();
00821                         glTranslated(world->w/2, world->h/2, 50);
00822                         glRotated(90*i, 0, 0, 1);
00823                         glBegin(GL_QUADS);
00824                         glTexCoord2d(0, 0);
00825                         glVertex3d(-20, -20, 0);
00826                         glTexCoord2d(1, 0);
00827                         glVertex3d(20, -20, 0);
00828                         glTexCoord2d(1, 1);
00829                         glVertex3d(20, -20, 20);
00830                         glTexCoord2d(0, 1);
00831                         glVertex3d(-20, -20, 20);
00832                         glEnd();
00833                         glPopMatrix();
00834                 }
00835                 
00836                 deleteTexture(tex);
00837                 
00838                 glDisable(GL_TEXTURE_2D);
00839                 glColor4d(7./8.,7./8.,1,0.75);
00840                 glPushMatrix();
00841                 glTranslated(world->w/2, world->h/2, 50);
00842                 glBegin(GL_QUADS);
00843                 glVertex3d(-20,-20,20);
00844                 glVertex3d(20,-20,20);
00845                 glVertex3d(20,20,20);
00846                 glVertex3d(-20,20,20);
00847                 
00848                 glVertex3d(-20,20,0);
00849                 glVertex3d(20,20,0);
00850                 glVertex3d(20,-20,0);
00851                 glVertex3d(-20,-20,0);
00852                 glEnd();
00853                 glPopMatrix();
00854                 
00855                 // save image
00856                 static int imageCounter = 0;
00857                 if (savingVideo)
00858                         grabFrameBuffer().save(QString("frame%0.bmp").arg(imageCounter++), "BMP");
00859         }
00860 
00861 
00862         ChallengeApplication::ChallengeApplication(World* world, int ePuckCount) :
00863                 viewer(world, ePuckCount)
00864         {
00865                 // help viewer
00866                 helpViewer = new QTextBrowser();
00867                 helpViewer->setReadOnly(true);
00868                 helpViewer->resize(600, 500);
00869                 // help files generated by txt2tags, xhtml mode, with TOC
00870                 if (localName.left(2) == "fr")
00871                         helpViewer->setSource(QString("qrc:/doc/challenge.fr.html"));
00872                 else if (localName.left(2) == "es")
00873                         helpViewer->setSource(QString("qrc:/doc/challenge.es.html"));
00874                 else
00875                         helpViewer->setSource(QString("qrc:/doc/challenge.en.html"));
00876                 helpViewer->moveCursor(QTextCursor::Start);
00877                 helpViewer->setWindowTitle(tr("Aseba Challenge Help"));
00878 
00879                 connect(this, SIGNAL(windowClosed()), helpViewer, SLOT(close()));
00880 
00881                 // main windows layout
00882                 QVBoxLayout *vLayout = new QVBoxLayout;
00883                 QHBoxLayout *hLayout = new QHBoxLayout;
00884 
00885                 hLayout->addStretch();
00886 
00887                 // construction of menu frame
00888                 QFrame* menuFrame = new QFrame();
00889                 //menuFrame->setFrameStyle(QFrame::Box | QFrame::Plain);
00890                 menuFrame->setFrameStyle(QFrame::NoFrame | QFrame::Plain);
00891                 QHBoxLayout *frameLayout = new QHBoxLayout;
00892                 QPushButton* addRobotButton = new QPushButton(tr("Add a new robot"));
00893                 frameLayout->addWidget(addRobotButton);
00894                 QPushButton* delRobotButton = new QPushButton(tr("Remove all robots"));
00895                 frameLayout->addWidget(delRobotButton);
00896                 QCheckBox* autoCamera = new QCheckBox(tr("Auto camera"));
00897                 frameLayout->addWidget(autoCamera);
00898                 QCheckBox* fullScreen = new QCheckBox(tr("Full screen"));
00899                 frameLayout->addWidget(fullScreen);
00900                 //hideButtons = new QCheckBox(tr("Auto hide"));
00901                 //frameLayout->addWidget(hideButtons);
00902                 QPushButton* helpButton = new QPushButton(tr("Help"));
00903                 frameLayout->addWidget(helpButton);
00904                 QPushButton* quitButton = new QPushButton(tr("Quit"));
00905                 frameLayout->addWidget(quitButton);
00906                 menuFrame->setLayout(frameLayout);
00907 
00908 //              menuFrame->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
00909                 viewer.setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
00910                 resize(780, 560);
00911 
00912                 // construction of the screen layout
00913                 hLayout->addWidget(menuFrame);
00914                 hLayout->addStretch();
00915 
00916                 vLayout->addLayout(hLayout);
00917                 vLayout->addWidget(&viewer);
00918                 vLayout->setContentsMargins(0,4,0,0);
00919                 setLayout(vLayout);
00920 
00921                 connect(addRobotButton, SIGNAL(clicked()), &viewer, SLOT(addNewRobot()));
00922                 connect(delRobotButton, SIGNAL(clicked()), &viewer, SLOT(removeRobot()));
00923                 connect(autoCamera, SIGNAL(toggled(bool)), &viewer, SLOT(autoCameraStateChanged(bool)));
00924                 connect(fullScreen, SIGNAL(toggled(bool)), SLOT(fullScreenStateChanged(bool)));
00925                 connect(helpButton, SIGNAL(clicked()), helpViewer, SLOT(show()));
00926                 connect(quitButton, SIGNAL(clicked()), SLOT(close()));
00927                 
00928                 autoCamera->setCheckState(Qt::Checked);
00929 
00930                 /*
00931                 #else // Q_WS_MAC
00932 
00933                 QMenuBar *menuBar = new QMenuBar(0);
00934                 QMenu *menu = menuBar->addMenu(tr("Simulator control"));
00935                 menu->addAction(tr("Add a new robot"), this, SLOT(addNewRobot()));
00936                 menu->addAction(tr("Remove all robots"), this, SLOT(removeRobot()));
00937                 menu->addSeparator();
00938                 autoCamera = new QAction(tr("Auto camera"), 0);
00939                 autoCamera->setCheckable(true);
00940                 menu->addAction(autoCamera);
00941                 menu->addSeparator();
00942                 menu->addAction(tr("Help"), helpViewer, SLOT(show()));
00943                 
00944                 #endif // Q_WS_MAC
00945                 */
00946         }
00947         
00948         void ChallengeApplication::fullScreenStateChanged(bool fullScreen)
00949         {
00950                 if (fullScreen)
00951                         showFullScreen();
00952                 else
00953                         showNormal();
00954         }
00955 
00956         void ChallengeApplication::closeEvent ( QCloseEvent * event )
00957         {
00958                 if (event->isAccepted())
00959                         emit windowClosed();
00960         }
00961 }
00962 
00963 // Implementation of aseba glue code
00964 
00965 extern "C" void AsebaPutVmToSleep(AsebaVMState *vm) 
00966 {
00967 }
00968 
00969 extern "C" void AsebaSendBuffer(AsebaVMState *vm, const uint8* data, uint16 length)
00970 {
00971         Dashel::Stream* stream = asebaEPuckMap[vm]->stream;
00972         assert(stream);
00973 
00974         try
00975         {
00976                 uint16 temp;
00977                 temp = bswap16(length - 2);
00978                 stream->write(&temp, 2);
00979                 temp = bswap16(vm->nodeId);
00980                 stream->write(&temp, 2);
00981                 stream->write(data, length);
00982                 stream->flush();
00983         }
00984         catch (Dashel::DashelException e)
00985         {
00986                 std::cerr << "Cannot write to socket: " << stream->getFailReason() << std::endl;
00987         }
00988 }
00989 
00990 extern "C" uint16 AsebaGetBuffer(AsebaVMState *vm, uint8* data, uint16 maxLength, uint16* source)
00991 {
00992         if (asebaEPuckMap[vm]->lastMessageData.size())
00993         {
00994                 *source = asebaEPuckMap[vm]->lastMessageSource;
00995                 memcpy(data, &asebaEPuckMap[vm]->lastMessageData[0], asebaEPuckMap[vm]->lastMessageData.size());
00996         }
00997         return asebaEPuckMap[vm]->lastMessageData.size();
00998 }
00999 
01000 extern "C" const AsebaVMDescription* AsebaGetVMDescription(AsebaVMState *vm)
01001 {
01002         if (localName == "fr")
01003                 return &vmDescription_fr;
01004         else
01005                 return &vmDescription_en;
01006 }
01007 
01008 static const AsebaLocalEventDescription localEvents[] = { { "timer", "periodic timer at 50 Hz" }, { NULL, NULL }};
01009 
01010 extern "C" const AsebaLocalEventDescription * AsebaGetLocalEventsDescriptions(AsebaVMState *vm)
01011 {
01012         return localEvents;
01013 }
01014 
01015 extern "C" const AsebaNativeFunctionDescription * const * AsebaGetNativeFunctionsDescriptions(AsebaVMState *vm)
01016 {
01017         return nativeFunctionsDescriptions;
01018 }
01019 
01020 extern "C" void AsebaNativeFunction(AsebaVMState *vm, uint16 id)
01021 {
01022         nativeFunctions[id](vm);
01023 }
01024 
01025 extern "C" void AsebaWriteBytecode(AsebaVMState *vm)
01026 {
01027 }
01028 
01029 extern "C" void AsebaResetIntoBootloader(AsebaVMState *vm)
01030 {
01031 }
01032 
01033 extern "C" void AsebaAssert(AsebaVMState *vm, AsebaAssertReason reason)
01034 {
01035         std::cerr << "\nFatal error: ";
01036         switch (vm->nodeId)
01037         {
01038                 case 1: std::cerr << "left motor module"; break;
01039                 case 2: std::cerr << "right motor module"; break;
01040                 case 3: std::cerr << "proximity sensors module"; break;
01041                 case 4: std::cerr << "distance sensors module"; break;
01042                 default: std::cerr << "unknown module"; break;
01043         }
01044         std::cerr << " has produced exception: ";
01045         switch (reason)
01046         {
01047                 case ASEBA_ASSERT_UNKNOWN: std::cerr << "undefined"; break;
01048                 case ASEBA_ASSERT_UNKNOWN_UNARY_OPERATOR: std::cerr << "unknown unary operator"; break;
01049                 case ASEBA_ASSERT_UNKNOWN_BINARY_OPERATOR: std::cerr << "unknown binary operator"; break;
01050                 case ASEBA_ASSERT_UNKNOWN_BYTECODE: std::cerr << "unknown bytecode"; break;
01051                 case ASEBA_ASSERT_STACK_OVERFLOW: std::cerr << "stack overflow"; break;
01052                 case ASEBA_ASSERT_STACK_UNDERFLOW: std::cerr << "stack underflow"; break;
01053                 case ASEBA_ASSERT_OUT_OF_VARIABLES_BOUNDS: std::cerr << "out of variables bounds"; break;
01054                 case ASEBA_ASSERT_OUT_OF_BYTECODE_BOUNDS: std::cerr << "out of bytecode bounds"; break;
01055                 case ASEBA_ASSERT_STEP_OUT_OF_RUN: std::cerr << "step out of run"; break;
01056                 case ASEBA_ASSERT_BREAKPOINT_OUT_OF_BYTECODE_BOUNDS: std::cerr << "breakpoint out of bytecode bounds"; break;
01057                 case ASEBA_ASSERT_EMIT_BUFFER_TOO_LONG: std::cerr << "tried to emit a buffer too long"; break;
01058                 default: std::cerr << "unknown exception"; break;
01059         }
01060         std::cerr << ".\npc = " << vm->pc << ", sp = " << vm->sp;
01061         std::cerr << "\nResetting VM" << std::endl;
01062         assert(false);
01063         AsebaVMInit(vm);
01064 }
01065 
01066 
01067 LanguageSelectionDialog::LanguageSelectionDialog()
01068 {
01069         QVBoxLayout* layout = new QVBoxLayout(this);
01070         
01071         QLabel* text = new QLabel(tr("Please choose your language"));
01072         layout->addWidget(text);
01073         
01074         languageSelectionBox = new QComboBox(this);
01075         languageSelectionBox->addItem(QString::fromUtf8("English"), "en");
01076         languageSelectionBox->addItem(QString::fromUtf8("Français"), "fr");
01077         languageSelectionBox->addItem(QString::fromUtf8("German"), "de");
01078         languageSelectionBox->addItem(QString::fromUtf8("Español"), "es");
01079         //qDebug() << "locale is " << QLocale::system().name();
01080         for (int i = 0; i < languageSelectionBox->count(); ++i)
01081         {
01082                 if (QLocale::system().name().startsWith(languageSelectionBox->itemData(i).toString()))
01083                 {
01084                         languageSelectionBox->setCurrentIndex(i);
01085                         break;
01086                 }
01087         }
01088         layout->addWidget(languageSelectionBox);
01089         
01090         QPushButton* okButton = new QPushButton(QIcon(":/images/ok.png"), tr("Ok"));
01091         connect(okButton, SIGNAL(clicked(bool)), SLOT(accept()));
01092         layout->addWidget(okButton);
01093         
01094         setWindowTitle(tr("Language selection"));
01095 }
01096 
01097 
01098 int main(int argc, char *argv[])
01099 {
01100         QApplication app(argc, argv);
01101         
01102         // Translation support
01103         QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
01104         
01105         QTranslator qtTranslator;
01106         qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
01107         app.installTranslator(&qtTranslator);
01108         
01109         //qDebug() << QLocale::system().name();
01110         QTranslator translator;
01111         translator.load(QString(":/asebachallenge_") + QLocale::system().name());
01112         app.installTranslator(&translator);
01113         
01114         // choose the language
01115         {
01116                 LanguageSelectionDialog languageSelectionDialog;
01117                 languageSelectionDialog.show();
01118                 languageSelectionDialog.exec();
01119                 
01120                 localName = languageSelectionDialog.languageSelectionBox->itemData(languageSelectionDialog.languageSelectionBox->currentIndex()).toString();
01121                 qtTranslator.load(QString("qt_") + localName, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
01122                 translator.load(QString(":/asebachallenge_") + localName);
01123         }
01124         
01125         // Create the world
01126         Enki::World world(140, 140, Enki::Color(0.4, 0.4, 0.4));
01127         
01128         // Add feeders
01129         Enki::EPuckFeeder* feeders[4];
01130         
01131         feeders[0] = new Enki::EPuckFeeder(0);
01132         feeders[0]->pos.x = 40;
01133         feeders[0]->pos.y = 40;
01134         world.addObject(feeders[0]);
01135         
01136         feeders[1] = new Enki::EPuckFeeder(15);
01137         feeders[1]->pos.x = 100;
01138         feeders[1]->pos.y = 40;
01139         world.addObject(feeders[1]);
01140         
01141         feeders[2] = new Enki::EPuckFeeder(45);
01142         feeders[2]->pos.x = 40;
01143         feeders[2]->pos.y = 100;
01144         world.addObject(feeders[2]);
01145         
01146         feeders[3] = new Enki::EPuckFeeder(30);
01147         feeders[3]->pos.x = 100;
01148         feeders[3]->pos.y = 100;
01149         world.addObject(feeders[3]);
01150         
01151         // Add e-puck
01152         int ePuckCount = 0;
01153         for (int i = 1; i < argc; i++)
01154         {
01155                 Enki::AsebaFeedableEPuck* epuck = new Enki::AsebaFeedableEPuck(i-1);
01156                 epuck->pos.x = Enki::random.getRange(120)+10;
01157                 epuck->pos.y = Enki::random.getRange(120)+10;
01158                 epuck->name = argv[i];
01159                 world.addObject(epuck);
01160                 ePuckCount++;
01161         }
01162         
01163         // Create viewer
01164         Enki::ChallengeApplication viewer(&world, ePuckCount);
01165         
01166         // Show and run
01167         viewer.setWindowTitle("ASEBA Challenge - Stephane Magnenat (code) - Basilio Noris (gfx)");
01168         viewer.show();
01169         
01170         return app.exec();
01171 }


aseba
Author(s): Stéphane Magnenat
autogenerated on Sun Oct 5 2014 23:46:38