├── .gitignore ├── Agent.cpp ├── Agent.h ├── CMakeLists.txt ├── GLView.cpp ├── GLView.h ├── MLPBrain.cpp ├── MLPBrain.h ├── README ├── README.txt ├── ReadWrite.cpp ├── ReadWrite.h ├── View.cpp ├── View.h ├── World.cpp ├── World.h ├── config.h ├── config.h.in ├── glui.h ├── glui32.lib ├── glui32d.lib ├── glut.dll ├── glut.h ├── glut.lib ├── glut32.dll ├── glut32.lib ├── helpers.h ├── main.cpp ├── settings.h ├── versionhistory.txt ├── vmath.cpp └── vmath.h /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp* 3 | *.kdev4 4 | Debug/ 5 | Release/ 6 | build/ 7 | *.SCB 8 | *.dll 9 | *.vcproj 10 | report.txt 11 | -------------------------------------------------------------------------------- /Agent.cpp: -------------------------------------------------------------------------------- 1 | #include "Agent.h" 2 | 3 | #include "settings.h" 4 | #include "helpers.h" 5 | #include 6 | //#include 7 | #include 8 | #include "MLPBrain.h" 9 | 10 | using namespace std; 11 | Agent::Agent() 12 | { 13 | //basics 14 | id= 0; 15 | pos= Vector2f(randf(0,conf::WIDTH),randf(0,conf::HEIGHT)); 16 | angle= randf(-M_PI,M_PI); 17 | health= 1+randf(0.5,0.75); 18 | age= 0; 19 | MUTRATE1= randf(0.1, 0.15); //0.08; //chance of mutations occuring 20 | MUTRATE2= 0.007; //randf(0.001, 0.01); //severity of mutations 21 | radius= randf(conf::MEANRADIUS*0.2,conf::MEANRADIUS*2.2); 22 | 23 | //triggers, counters, and layer interaction 24 | freshkill= 0; 25 | species= randi(-conf::NUMBOTS*200,conf::NUMBOTS*200); //related to numbots because it's a good relationship 26 | gencount= 0; 27 | repcounter= conf::REPRATE; 28 | numbabies= randi(1,4); 29 | temperature_preference= cap(randn(2.0*abs(pos.y/conf::HEIGHT - 0.5),0.05)); 30 | lungs= randf(0,1); 31 | metabolism= 1.0;//randf(0.5,2); 32 | 33 | float herb,carn,frui; 34 | int overtype= randi(0,Stomach::FOOD_TYPES-1); 35 | herb= randf(0,1); 36 | carn= randf(0,1); 37 | frui= randf(0,1); 38 | stomach[Stomach::PLANT]= herb; 39 | stomach[Stomach::MEAT]= carn; 40 | stomach[Stomach::FRUIT]= frui; 41 | if (herb+carn+frui < 1){ 42 | stomach[overtype]+= 1-herb-carn-frui; 43 | cap(stomach[overtype]); 44 | } 45 | 46 | //senses and sense-ability 47 | //eyes 48 | eye_see_agent_mod= randf(0.1, 3); 49 | eyefov.resize(NUMEYES, 0); 50 | eyedir.resize(NUMEYES, 0); 51 | for(int i=0;itemp2){ 66 | hearlow[i]= temp2; 67 | hearhigh[i]= temp1; 68 | } else { 69 | hearlow[i]= temp1; 70 | hearhigh[i]= temp2; 71 | } 72 | } 73 | clockf1= randf(5,100); 74 | clockf2= randf(5,100); 75 | clockf3= 2; 76 | blood_mod= randf(0.1, 3); 77 | smell_mod= randf(0.1, 3); 78 | 79 | //brain matters 80 | in.resize(Input::INPUT_SIZE, 0); 81 | out.resize(Output::OUTPUT_SIZE, 0); 82 | brainact= 0; 83 | 84 | //output mechanical values 85 | w1= 0; 86 | w2= 0; 87 | boost= false; 88 | jump= 0; 89 | red= 0.5; 90 | gre= 0.5; 91 | blu= 0.5; 92 | volume= 1; 93 | tone= 0.5; 94 | give= 0; 95 | spikeLength= 0; 96 | jawPosition= 0; 97 | jawOldPos= 0; 98 | grabID= -1; 99 | grabbing= 0; 100 | sexproject= false; 101 | 102 | //stats 103 | hybrid= false; 104 | death= "Killed by Unknown Factor!"; //default death message, just in case 105 | children= 0; 106 | killed= 0; 107 | hits= 0; 108 | indicator= 0; 109 | ir= 0; 110 | ig= 0; 111 | ib= 0; 112 | jawrend= 0; 113 | dfood= 0; 114 | } 115 | 116 | void Agent::printSelf() 117 | { 118 | printf("\n~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 119 | printf("AGENT, ID: %i\n", id); 120 | printf("Species # = %i\n", species); 121 | printf("Metabolism = %f\n", metabolism); 122 | printf("Lungs = %f\n", lungs); 123 | printf("MUTRATE1 = %f, MUTRATE2 = %f\n", MUTRATE1, MUTRATE2); 124 | printf("children= %i\n", children); 125 | printf("killed= %i\n", killed); 126 | if (isHerbivore()) printf("Herbivore\n"); 127 | if (isCarnivore()) printf("Carnivore\n"); 128 | if (isFrugivore()) printf("Frugivore\n"); 129 | for (int i=0; i<(int)mutations.size(); i++) { 130 | cout << mutations[i]; 131 | } 132 | printf("~~~~~~~~~~~~~~~~~~~~~~~~~\n"); 133 | } 134 | 135 | void Agent::initEvent(float size, float r, float g, float b) 136 | { 137 | indicator=size; 138 | ir=r; 139 | ig=g; 140 | ib=b; 141 | } 142 | 143 | void Agent::setActivity() 144 | { 145 | brainact= brain.getActivity(); 146 | } 147 | 148 | void Agent::tick() 149 | { 150 | brain.tick(in, out); 151 | } 152 | Agent Agent::reproduce(Agent that, float MR, float MR2) 153 | { 154 | //create baby. Note that if the bot selects itself to mate with, this function acts also as assexual reproduction 155 | //NOTES: Agent "this" is mother, Agent "that" is father, Agent "a2" is daughter 156 | //if a single parent's trait is required, use the mother's (this->) 157 | Agent a2; 158 | 159 | //spawn the baby somewhere closeby behind the mother 160 | //we want to spawn behind so that agents dont accidentally kill their young right away 161 | //note that this relies on bots actally driving forward, not backward. Well let natural selection choose who lives and who dies 162 | Vector2f fb(this->radius*2.5,0); 163 | fb.rotate(this->angle+M_PI+this->numbabies*randf(-0.4,0.4)); 164 | a2.pos= this->pos + fb; 165 | a2.borderRectify(); 166 | 167 | //basic trait inheritance 168 | a2.gencount= max(this->gencount+1,that.gencount+1); 169 | a2.numbabies= randf(0,1)<0.5 ? this->numbabies : that.numbabies; 170 | a2.metabolism= randf(0,1)<0.5 ? this->metabolism : that.metabolism; 171 | a2.stomach[Stomach::PLANT]= randf(0,1)<0.5 ? this->stomach[Stomach::PLANT]: that.stomach[Stomach::PLANT]; 172 | a2.stomach[Stomach::MEAT]= randf(0,1)<0.5 ? this->stomach[Stomach::MEAT]: that.stomach[Stomach::MEAT]; 173 | a2.stomach[Stomach::FRUIT]= randf(0,1)<0.5 ? this->stomach[Stomach::FRUIT]: that.stomach[Stomach::FRUIT]; 174 | a2.species= randf(0,1)<0.5 ? this->species : that.species; 175 | a2.radius= randf(0,1)<0.5 ? this->radius : that.radius; 176 | 177 | a2.MUTRATE1= randf(0,1)<0.5 ? this->MUTRATE1 : that.MUTRATE1; 178 | a2.MUTRATE2= randf(0,1)<0.5 ? this->MUTRATE2 : that.MUTRATE2; 179 | a2.clockf1= randf(0,1)<0.5 ? this->clockf1 : that.clockf1; 180 | a2.clockf2= randf(0,1)<0.5 ? this->clockf2 : that.clockf2; 181 | 182 | a2.smell_mod= randf(0,1)<0.5 ? this->smell_mod : that.smell_mod; 183 | a2.hear_mod= randf(0,1)<0.5 ? this->hear_mod : that.hear_mod; 184 | a2.eye_see_agent_mod= randf(0,1)<0.5 ? this->eye_see_agent_mod : that.eye_see_agent_mod; 185 | // a2.eye_see_cell_mod= randf(0,1)<0.5 ? this->eye_see_cell_mod : that.eye_see_cell_mod; 186 | a2.blood_mod= randf(0,1)<0.5 ? this->blood_mod : that.blood_mod; 187 | 188 | a2.temperature_preference= randf(0,1)<0.5 ? this->temperature_preference : that.temperature_preference; 189 | a2.lungs= randf(0,1)<0.5 ? this->lungs : that.lungs; 190 | 191 | a2.eardir= randf(0,1)<0.5 ? this->eardir : that.eardir; 192 | a2.hearlow= randf(0,1)<0.5 ? this->hearlow : that.hearlow; 193 | a2.hearhigh= randf(0,1)<0.5 ? this->hearhigh : that.hearhigh; 194 | 195 | a2.eyefov= randf(0,1)<0.5 ? this->eyefov : that.eyefov; 196 | a2.eyedir= randf(0,1)<0.5 ? this->eyedir : that.eyedir; 197 | 198 | //mutations 199 | if (randf(0,1)conf::MAXMETABOLISM) a2.metabolism= conf::MAXMETABOLISM; 203 | if (randf(0,1)2*M_PI) a2.eardir[i] = 2*M_PI; 232 | if(randf(0,1)a2.hearhigh[i]) { 235 | float temp= a2.hearlow[i]; 236 | a2.hearlow[i]= a2.hearhigh[i]; 237 | a2.hearhigh[i]= temp; 238 | } 239 | } 240 | 241 | // #pragma omp parallel for 242 | for(int i=0;iM_PI) a2.eyefov[i] = M_PI; //eyes cannot wrap around bot 246 | 247 | if(randf(0,1)2*M_PI) a2.eyedir[i] = 2*M_PI; 250 | //not going to loop coordinates; 0,2pi is bots front, so it provides a good point to "bounce" off of 251 | } 252 | 253 | //create brain here 254 | a2.brain= this->brain.crossover(that.brain); 255 | a2.brain.initMutate(MR,MR2); 256 | 257 | a2.initEvent(20,0.8,0.8,0.8); //grey event means we were just born! Welcome! 258 | 259 | return a2; 260 | 261 | } 262 | 263 | void Agent::setHerbivore() 264 | { 265 | this->stomach[Stomach::PLANT]= randf(0.7, 1); 266 | this->stomach[Stomach::MEAT]= randf(0, 0.3); 267 | this->stomach[Stomach::FRUIT]= randf(0, 0.3); 268 | } 269 | 270 | void Agent::setCarnivore() 271 | { 272 | this->stomach[Stomach::PLANT]= randf(0, 0.3); 273 | this->stomach[Stomach::MEAT]= randf(0.7, 1); 274 | this->stomach[Stomach::FRUIT]= randf(0, 0.3); 275 | } 276 | 277 | void Agent::setFrugivore() 278 | { 279 | this->stomach[Stomach::PLANT]= randf(0, 0.3); 280 | this->stomach[Stomach::MEAT]= randf(0, 0.3); 281 | this->stomach[Stomach::FRUIT]= randf(0.7, 1); 282 | } 283 | 284 | void Agent::setPos(float x, float y) 285 | { 286 | this->pos.x= x; 287 | this->pos.y= y; 288 | this->borderRectify(); 289 | } 290 | 291 | void Agent::borderRectify() 292 | { 293 | //if this agent has fallen outside of the world borders, rectify and wrap him to the other side 294 | if (this->pos.x<0) this->pos.x= this->pos.x + conf::WIDTH*((int)((0-this->pos.x)/conf::WIDTH)+1); 295 | if (this->pos.x>=conf::WIDTH) this->pos.x= this->pos.x - conf::WIDTH*((int)((this->pos.x-conf::WIDTH)/conf::WIDTH)+1); 296 | if (this->pos.y<0) this->pos.y= this->pos.y + conf::HEIGHT*((int)((0-this->pos.y)/conf::HEIGHT)+1); 297 | if (this->pos.y>=conf::HEIGHT) this->pos.y= this->pos.y - conf::HEIGHT*((int)((this->pos.y-conf::HEIGHT)/conf::HEIGHT)+1); 298 | } 299 | 300 | bool Agent::isHerbivore() 301 | { 302 | if (stomach[Stomach::PLANT]>=stomach[Stomach::MEAT] && stomach[Stomach::PLANT]>=stomach[Stomach::FRUIT]) return true; 303 | return false; 304 | } 305 | 306 | bool Agent::isCarnivore() 307 | { 308 | if (stomach[Stomach::MEAT]>=stomach[Stomach::PLANT] && stomach[Stomach::MEAT]>=stomach[Stomach::FRUIT]) return true; 309 | return false; 310 | } 311 | 312 | bool Agent::isFrugivore() 313 | { 314 | if (stomach[Stomach::FRUIT]>=stomach[Stomach::PLANT] && stomach[Stomach::FRUIT]>=stomach[Stomach::MEAT]) return true; 315 | return false; 316 | } 317 | 318 | void Agent::writeIfKilled(const char * cause) 319 | /*======LIST OF CURRENT DEATH CAUSES=======// 320 | "Killed by Unknown Factor! Agent.cpp ~ln 87 Note: if no other message is applied, this will pop up 321 | "Killed by Something ?" World.cpp ~ln 210 Note: the space is for easy interpretation by Excel with text->data delimitation via spaces 322 | "Killed by Spike Raising" World.cpp ~ln 515 323 | "Killed by a Hazard" World.cpp ~ln 620 324 | "Killed by Suffocation ." World.cpp ~ln 632 Note: the space is for easy interpretation by Excel with text->data delimitation via spaces 325 | "Killed by Excessive Generosity" World.cpp ~ln 658 326 | "Killed by a Collision" World.cpp ~ln 687-9 327 | "Killed by a Murder" World.cpp ~ln 754 Note: death by both spike and jaws 328 | "Killed by Natural Causes" World.cpp ~ln 808 Note: contains wheel loss, aging, metabolism, boost penalty, and brain use 329 | "Killed by Temp Discomfort" World.cpp ~ln 816 330 | "Killed by LackOf Oxygen" World.cpp ~ln 821 331 | "Killed by God (you)" World.cpp ~ln 927 332 | "Killed by Child Birth" World.cpp ~ln 1069 333 | */ 334 | { 335 | if(this->health<0){ 336 | this->death= cause; 337 | this->health= 0; 338 | } 339 | } -------------------------------------------------------------------------------- /Agent.h: -------------------------------------------------------------------------------- 1 | #ifndef AGENT_H 2 | #define AGENT_H 3 | 4 | #include "MLPBrain.h" 5 | #include "vmath.h" 6 | 7 | #include 8 | #include 9 | 10 | class Agent 11 | { 12 | //IMPORTANT: if ANY variables are added/removed, you MUST check ReadWrite.cpp to see how loading and saving will be effected!!! 13 | public: 14 | Agent(); 15 | 16 | void printSelf(); 17 | //for drawing purposes 18 | void initEvent(float size, float r, float g, float b); 19 | 20 | void tick(); 21 | void setActivity(); 22 | void writeIfKilled(const char * cause); 23 | 24 | Agent reproduce(Agent that, float MR, float MR2); 25 | 26 | //random agent creation tweakers 27 | void setHerbivore(); 28 | void setCarnivore(); 29 | void setFrugivore(); 30 | void setPos(float x, float y); 31 | void borderRectify(); 32 | 33 | bool isHerbivore(); 34 | bool isCarnivore(); 35 | bool isFrugivore(); 36 | 37 | //Variables 38 | //bot basics 39 | int id; 40 | Vector2f pos; 41 | float angle; //of the bot 42 | float health; //in range [0,2]. I cant remember why. 43 | int age; //how old is the agent 44 | float MUTRATE1; //how often do mutations occur? 45 | float MUTRATE2; //how significant are they? 46 | float radius; //radius of bot 47 | 48 | //triggers, counters, and layer interaction 49 | int freshkill; //were you just stabbed/collided with? how long ago? 50 | int species; //if two bots are of significantly different species, then they can't crossover 51 | int gencount; //generation counter 52 | float repcounter; //when repcounter gets to 0, this bot reproduces 53 | int numbabies; //number of children this bot creates with every reproduction event 54 | float temperature_preference; //what temperature does this agent like? [0 to 1] 55 | float lungs; //what type of environment does this agent need? [0 for "water", 1 for "land"] 56 | float metabolism; //rate modifier for food to repcounter conversion, also, a factor of max bot speed 57 | float stomach[Stomach::FOOD_TYPES]; //stomach: #0 is herbivore, #1 is carnivore, #2 is frugivore 58 | 59 | //senses 60 | // int numeyes; 61 | float eye_see_agent_mod; 62 | std::vector eyefov; //field of view for each eye 63 | std::vector eyedir; //direction of each eye 64 | // int numears; 65 | float hear_mod; 66 | std::vector eardir; //position of ears 67 | std::vector hearlow; //low values of hearing ranges 68 | std::vector hearhigh; //high values of hearing ranges 69 | float clockf1, clockf2, clockf3; //the frequencies of the three clocks of this bot 70 | float blood_mod; 71 | float smell_mod; 72 | 73 | //the brain 74 | // int numinputs; //number of inputs and brain boxes. UNUSED 75 | // int numboxes; 76 | MLPBrain brain; 77 | std::vector in; //see Input in settings.h 78 | std::vector out; //see Output in settings.h 79 | float brainact; //records the activity of the brain 80 | 81 | //outputs 82 | float w1; //wheel speeds. in range [-1,1] 83 | float w2; 84 | bool boost; //is this agent boosting? 85 | float jump; //what "height" this bot is at after jumping 86 | float red, gre, blu; 87 | float volume; //sound volume of this bot. It can scream, or be very sneaky. 88 | float tone; //sound tone of this bot. it can be low pitched (<0.5) or high (>0.5), where only bots with hearing in range of tone will hear 89 | float give; //is this agent attempting to give food to other agent? 90 | float spikeLength; //"my, what a long spike you have!" 91 | float jawPosition; //what "position" the jaw is in. 0 for open, 1 for closed 92 | float jawOldPos; //the previous "position" of the jaw 93 | int grabID; //id of agent this agent is "glued" to. ==-1 if none selected 94 | float grabbing; //is this agent attempting to grab another? If already grabbed, how far are we willing to let them go? 95 | bool sexproject; //is this bot trying to give out its genetic data? 96 | 97 | //stats 98 | bool hybrid; //is this agent result of crossover? 99 | const char * death; //the cause of death of this agent 100 | int children; //how many kids did you say you had again? 101 | int killed; //how many bots have you murdered??? 102 | int hits; //how much fighting have you done? 103 | float indicator; 104 | float ir, ig, ib; //indicator colors 105 | float dfood; //what is change in health of this agent due to giving/receiving? 106 | float dfoodx; //x and y location of other bot 107 | float dfoody; 108 | float grabx; //x and y location of the grab target 109 | float graby; 110 | int jawrend; //render counter for jaw. Past ~10 ticks of no jaw action, it is "retracted" visually 111 | std::vector mutations; 112 | }; 113 | 114 | #endif // AGENT_H 115 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(scriptbots) 2 | cmake_minimum_required(VERSION 2.8) 3 | find_package(OpenGL REQUIRED) 4 | find_package(GLUT REQUIRED) 5 | 6 | if (WIN32 AND NOT GLUT_FOUND) 7 | find_library(GLUT_LIBRARY NAMES glut PATHS ${CMAKE_CURRENT_SOURCE_DIR}) 8 | find_library(GLUT32_LIBRARY NAMES glut32 PATHS ${CMAKE_CURRENT_SOURCE_DIR}) 9 | SET (LOCAL_GLUT32 1) 10 | endif() 11 | 12 | find_package(OpenMP) 13 | 14 | if (OPENMP_FOUND) 15 | SET (HAVE_OPENMP 1) 16 | SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 17 | SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 18 | endif() 19 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) 20 | 21 | include_directories(${CMAKE_CURRENT_BINARY_DIR} ${OPENGL_INCLUDE_DIRS} ${GLUT_INCLUDE_DIR}) 22 | 23 | set( SB_SRCS ReadWrite.cpp 24 | View.cpp 25 | GLView.cpp 26 | main.cpp 27 | DWRAONBrain.cpp 28 | MLPBrain.cpp 29 | AssemblyBrain.cpp 30 | Agent.cpp 31 | World.cpp 32 | vmath.cpp ) 33 | 34 | add_executable(scriptbots ${SB_SRCS}) 35 | 36 | if (WIN32 AND NOT GLUT_FOUND) 37 | target_link_libraries(scriptbots ${OPENGL32_LIBRARIES} ${GLUT_LIBRARY} ${GLUT32_LIBRARY}) 38 | else() 39 | target_link_libraries(scriptbots ${OPENGL32_LIBRARIES} ${GLUT_LIBRARY}) 40 | endif() 41 | -------------------------------------------------------------------------------- /GLView.cpp: -------------------------------------------------------------------------------- 1 | #include "GLView.h" 2 | 3 | #include 4 | 5 | #include "config.h" 6 | #ifdef LOCAL_GLUT32 7 | #include "glut.h" 8 | #else 9 | #include 10 | #endif 11 | 12 | #ifdef WIN32 13 | #define _CRT_SECURE_NO_WARNINGS 14 | #endif 15 | #include 16 | 17 | void gl_processNormalKeys(unsigned char key, int x, int y) 18 | { 19 | GLVIEW->processNormalKeys(key, x, y); 20 | } 21 | void gl_processSpecialKeys(int key, int x, int y) 22 | { 23 | GLVIEW->processSpecialKeys(key, x, y); 24 | } 25 | void gl_processReleasedKeys(unsigned char key, int x, int y) 26 | { 27 | GLVIEW->processReleasedKeys(key, x, y); 28 | } 29 | void gl_menu(int key) 30 | { 31 | GLVIEW->menu(key); 32 | } 33 | void gl_changeSize(int w, int h) 34 | { 35 | GLVIEW->changeSize(w,h); 36 | } 37 | void gl_handleIdle() 38 | { 39 | GLVIEW->handleIdle(); 40 | } 41 | void gl_processMouse(int button, int state, int x, int y) 42 | { 43 | GLVIEW->processMouse(button, state, x, y); 44 | } 45 | void gl_processMouseActiveMotion(int x, int y) 46 | { 47 | GLVIEW->processMouseActiveMotion(x,y); 48 | } 49 | void gl_processMousePassiveMotion(int x, int y) 50 | { 51 | GLVIEW->processMousePassiveMotion(x,y); 52 | } 53 | void gl_renderScene() 54 | { 55 | GLVIEW->renderScene(); 56 | } 57 | void glui_handleRW(int action) 58 | { 59 | GLVIEW->handleRW(action); 60 | } 61 | void glui_handleCloses(int action) 62 | { 63 | GLVIEW->handleCloses(action); 64 | } 65 | 66 | 67 | void RenderString(float x, float y, void *font, const char* string, float r, float g, float b) 68 | { 69 | glColor3f(r,g,b); 70 | glRasterPos2f(x, y); 71 | int len = (int) strlen(string); 72 | for (int i = 0; i < len; i++) 73 | glutBitmapCharacter(font, string[i]); 74 | } 75 | 76 | void drawCircle(float x, float y, float r) { 77 | float n; 78 | for (int k=0;k<17;k++) { 79 | n = k*(M_PI/8); 80 | glVertex3f(x+r*sin(n),y+r*cos(n),0); 81 | } 82 | } 83 | 84 | void drawQuadrant(float x, float y, float r, float a, float b) { 85 | glVertex3f(x,y,0); 86 | float n; 87 | for (int k=0;k<(int)((b-a)*8/M_PI+1);k++) { 88 | n = k*(M_PI/8)+a; 89 | glVertex3f(x+r*sin(n),y+r*cos(n),0); 90 | } 91 | glVertex3f(x+r*sin(b),y+r*cos(b),0); 92 | glVertex3f(x,y,0); 93 | } 94 | 95 | GLView::GLView(World *s) : 96 | world(world), 97 | modcounter(0), 98 | frames(0), 99 | lastUpdate(0), 100 | mousedrag(false) 101 | { 102 | 103 | xtranslate= 0.0; 104 | ytranslate= 0.0; 105 | scalemult= 0.2; 106 | downb[0]=0;downb[1]=0;downb[2]=0; 107 | mousex=0;mousey=0; 108 | 109 | } 110 | 111 | GLView::~GLView() 112 | { 113 | 114 | } 115 | void GLView::changeSize(int w, int h) 116 | { 117 | //Tell GLUT that were changing the projection, not the actual view 118 | glMatrixMode(GL_PROJECTION); 119 | //Reset the coordinate system 120 | glLoadIdentity(); 121 | //resize viewport to new size 122 | glViewport(0, 0, w, h); 123 | //reconcile projection (required to keep everything that's visible, visible 124 | glOrtho(0,w,h,0,0,1); 125 | //revert to normal view opperations 126 | glMatrixMode(GL_MODELVIEW); 127 | } 128 | 129 | void GLView::processMouse(int button, int state, int x, int y) 130 | { 131 | if(world->isDebug()) printf("MOUSE EVENT: button=%i state=%i x=%i y=%i, scale=%f, mousedrag=%i\n", button, state, x, y, scalemult, mousedrag); 132 | 133 | if(!mousedrag && state==1){ //dont let mouse click do anything if drag flag is raised 134 | //have world deal with it. First translate to world coordinates though 135 | int wx= (int) ((x-glutGet(GLUT_WINDOW_WIDTH)/2)/scalemult-xtranslate); 136 | int wy= (int) ((y-glutGet(GLUT_WINDOW_HEIGHT)/2)/scalemult-ytranslate); 137 | 138 | if(world->processMouse(button, state, wx, wy, scalemult)) live_selection = Select::MANUAL; 139 | } 140 | 141 | mousex=x; mousey=y; 142 | mousedrag= false; 143 | 144 | downb[button]=1-state; //state is backwards, ah well 145 | } 146 | 147 | void GLView::processMouseActiveMotion(int x, int y) 148 | { 149 | if(world->isDebug()) printf("MOUSE MOTION x=%i y=%i, %i %i %i\n", x, y, downb[0], downb[1], downb[2]); 150 | if (downb[0]==1) { 151 | //left mouse button drag: pan around 152 | xtranslate += (x-mousex)/scalemult; 153 | ytranslate += (y-mousey)/scalemult; 154 | if (abs(x-mousex)>6 || abs(x-mousex)>6) live_follow= 0; 155 | //for releasing follow if the mouse is used to drag screen, but there's a threshold 156 | } 157 | if (downb[1]==1) { 158 | //mouse wheel. Change scale 159 | scalemult -= conf::ZOOM_SPEED*(y-mousey); 160 | if(scalemult<0.01) scalemult=0.01; 161 | } 162 | /* if(downb[2]==1){ //disabled 163 | //right mouse button. 164 | }*/ 165 | if(abs(mousex-x)>4 || abs(mousey-y)>4) mousedrag= true; //mouse was clearly dragged, don't select agents after 166 | mousex=x; mousey=y; 167 | } 168 | 169 | void GLView::processMousePassiveMotion(int x, int y) 170 | { 171 | //for mouse scrolling. [DISABLED] 172 | /* if(y<=30) ytranslate += 2*(30-y); 173 | if(y>=glutGet(GLUT_WINDOW_HEIGHT)-30) ytranslate -= 2*(y-(glutGet(GLUT_WINDOW_HEIGHT)-30)); 174 | if(x<=30) xtranslate += 2*(30-x); 175 | if(x>=glutGet(GLUT_WINDOW_WIDTH)-30) xtranslate -= 2*(x-(glutGet(GLUT_WINDOW_WIDTH)-30));*/ 176 | } 177 | 178 | void GLView::processNormalKeys(unsigned char key, int x, int y) 179 | { 180 | menu(key); 181 | } 182 | 183 | void GLView::processSpecialKeys(int key, int x, int y) 184 | { 185 | menuS(key); 186 | } 187 | 188 | void GLView::processReleasedKeys(unsigned char key, int x, int y) 189 | { 190 | if (key==32) {//spacebar input [released] 191 | world->pinput1= 0; 192 | } 193 | } 194 | 195 | void GLView::menu(int key) 196 | { 197 | ReadWrite* savehelper= new ReadWrite(); //for loading/saving 198 | if (key == 27) //[esc] quit 199 | exit(0); 200 | else if (key=='p') { 201 | //pause 202 | live_paused= !live_paused; 203 | } else if (key=='m') { //drawing 204 | live_fastmode= !live_fastmode; 205 | } else if (key==43) { //+ 206 | live_skipdraw++; 207 | } else if (key==45) { //- 208 | live_skipdraw--; 209 | } else if (key=='l' || key=='k') { //layer switch; l= "next", k= "previous" 210 | if (key=='l') live_layersvis++; 211 | else live_layersvis--; 212 | if (live_layersvis>Layer::LAYERS) live_layersvis= 0; 213 | if (live_layersvis<0) live_layersvis= Layer::LAYERS; 214 | } else if (key=='z' || key=='x') { //change agent visual scheme; x= "next", z= "previous" 215 | if (key=='x') live_agentsvis++; 216 | else live_agentsvis--; 217 | if (live_agentsvis>Visual::VISUALS-1) live_agentsvis= Visual::NONE; 218 | if (live_agentsvisaddAgents(5); 221 | } else if (key==1002) { //add Herbivore agents 222 | world->addAgents(5, Stomach::PLANT); 223 | } else if (key==1003) { //add Carnivore agents 224 | world->addAgents(5, Stomach::MEAT); 225 | } else if (key==1004) { //add Frugivore agents 226 | world->addAgents(5, Stomach::FRUIT); 227 | } else if (key=='c') { 228 | world->setClosed( !world->isClosed() ); 229 | live_worldclosed= (int) world->isClosed(); 230 | /* glutGet(GLUT_MENU_NUM_ITEMS); 231 | if (world->isClosed()) glutChangeToMenuEntry(4, "Open World", 'c'); 232 | else glutChangeToMenuEntry(4, "Close World", 'c'); 233 | glutSetMenu(m_id);*/ 234 | } else if (key=='f') { 235 | live_follow= !live_follow; //toggle follow selected agent 236 | } else if(key=='o') { 237 | if(live_selection!=Select::OLDEST) live_selection= Select::OLDEST; //follow oldest agent 238 | else live_selection= Select::NONE; 239 | } else if(key=='q') { 240 | //zoom and translocate to instantly see the whole world 241 | float scaleA= (float)glutGet(GLUT_WINDOW_WIDTH)/(conf::WIDTH+2200); 242 | float scaleB= (float)glutGet(GLUT_WINDOW_HEIGHT)/(conf::HEIGHT+150); 243 | if(scaleA>scaleB) scalemult= scaleB; 244 | else scalemult= scaleA; 245 | xtranslate= -(conf::WIDTH-2020)/2; 246 | ytranslate= -(conf::HEIGHT-80)/2; 247 | live_follow= 0; 248 | } else if(key=='g') { 249 | if(live_selection!=Select::BEST_GEN) live_selection= Select::BEST_GEN; //follow most advanced generation agent 250 | else live_selection= Select::NONE; 251 | } else if(key=='h') { 252 | if(live_selection!=Select::HEALTHY) live_selection= Select::HEALTHY; //follow healthiest 253 | else live_selection= Select::NONE; 254 | }else if (key==127) { //delete 255 | world->selectedKill(); 256 | }else if (key==62) { //zoom+ > 257 | scalemult += 10*conf::ZOOM_SPEED; 258 | }else if (key==60) { //zoom- < 259 | scalemult -= 10*conf::ZOOM_SPEED; 260 | if(scalemult<0.01) scalemult=0.01; 261 | }else if (key==32) { //spacebar input [pressed] 262 | world->pinput1= 1; 263 | }else if (key=='/') { // / heal selected 264 | world->selectedHeal(); 265 | }else if (key=='|') { // | reproduce selected 266 | world->selectedBabys(); 267 | }else if (key==119) { //w (move faster) 268 | world->pcontrol= true; 269 | world->pleft= capm(world->pleft + 0.08, -1, 1); 270 | world->pright= capm(world->pright + 0.08, -1, 1); 271 | }else if (key==97) { //a (turn left) 272 | world->pcontrol= true; 273 | world->pleft= capm(world->pleft - 0.05 + (world->pright-world->pleft)*0.05, -1, 1); //this extra code helps with turning out of tight circles 274 | world->pright= capm(world->pright + 0.05 + (world->pleft-world->pright)*0.05, -1, 1); 275 | }else if (key==115) { //s (move slower) 276 | world->pcontrol= true; 277 | world->pleft= capm(world->pleft - 0.08, -1, 1); 278 | world->pright= capm(world->pright - 0.08, -1, 1); 279 | }else if (key==100) { //d (turn right) 280 | world->pcontrol= true; 281 | world->pleft= capm(world->pleft + 0.05 + (world->pright-world->pleft)*0.05, -1, 1); 282 | world->pright= capm(world->pright - 0.05 + (world->pleft-world->pright)*0.05, -1, 1); 283 | } else if (key==999) { //player control 284 | world->setControl(!world->pcontrol); 285 | glutGet(GLUT_MENU_NUM_ITEMS); 286 | if (world->pcontrol) glutChangeToMenuEntry(1, "Release Agent", 999); 287 | else glutChangeToMenuEntry(1, "Control Selected (w,a,s,d)", 999); 288 | glutSetMenu(m_id); 289 | }else if (key==1005) { //menu only, debug mode 290 | world->setDebug( !world->isDebug() ); 291 | live_debug= (int) world->isDebug(); 292 | /* glutGet(GLUT_MENU_NUM_ITEMS); 293 | if (world->isDebug()){ 294 | glutChangeToMenuEntry(18, "Exit Debug Mode", 1005); 295 | printf("Entered Debug Mode\n"); 296 | } else glutChangeToMenuEntry(18, "Enter Debug Mode", 1005); 297 | glutSetMenu(m_id);*/ 298 | }else if (key==1006) { //force-reset config 299 | world->writeConfig(); 300 | }else if (key==1007) { // reset 301 | world->reset(); 302 | world->spawn(); 303 | printf("WORLD RESET!\n"); 304 | } else if (key==1008) { //save world 305 | handleRW(2); 306 | } else if (key==1009) { //load world 307 | handleRW(1); 308 | } else if (world->isDebug()) { 309 | printf("Unknown key pressed: %i\n", key); 310 | } 311 | //other keys: '1':49, '2':50, ..., '0':48 312 | } 313 | 314 | void GLView::menuS(int key) // movement control 315 | { 316 | if (key == GLUT_KEY_UP) { 317 | ytranslate += 20/scalemult; 318 | } else if (key == GLUT_KEY_LEFT) { 319 | xtranslate += 20/scalemult; 320 | } else if (key == GLUT_KEY_DOWN) { 321 | ytranslate -= 20/scalemult; 322 | } else if (key == GLUT_KEY_RIGHT) { 323 | xtranslate -= 20/scalemult; 324 | } 325 | } 326 | 327 | void GLView::glCreateMenu() 328 | { 329 | m_id = glutCreateMenu(gl_menu); //right-click context menu 330 | glutAddMenuEntry("Control Selected (w,a,s,d)", 999); //line contains mode-specific text, see menu function above 331 | glutAddMenuEntry("Heal Agent (/)", '/'); 332 | glutAddMenuEntry("Delete Agent (del)", 127); 333 | glutAddMenuEntry("-------------------",-1); 334 | glutAddMenuEntry("Spawn Agents", 1001); 335 | glutAddMenuEntry("Spawn Herbivores", 1002); 336 | glutAddMenuEntry("Spawn Carnivores", 1003); 337 | glutAddMenuEntry("Spawn Frugivores", 1004); 338 | glutAddMenuEntry("Toggle Closed", 'c'); 339 | glutAddMenuEntry("Save World",1008); 340 | glutAddMenuEntry("-------------------",-1); 341 | glutAddMenuEntry("Load World",1009); 342 | glutAddMenuEntry("Enter Debug Mode", 1005); 343 | glutAddMenuEntry("Reset Agents", 1007); 344 | glutAddMenuEntry("Reset Config", 1006); 345 | glutAddMenuEntry("Exit (esc)", 27); 346 | glutAttachMenu(GLUT_RIGHT_BUTTON); 347 | } 348 | 349 | void GLView::gluiCreateMenu() 350 | { 351 | //GLUI menu. Slimy, yet satisfying. 352 | //must set our live vars to something. Might as well do it here 353 | live_worldclosed= 0; 354 | live_paused= 0; 355 | live_fastmode= 0; 356 | live_skipdraw= 1; 357 | live_agentsvis= Visual::RGB; 358 | live_layersvis= Layer::LAND+1; 359 | live_selection= Select::MANUAL; 360 | live_follow= 0; 361 | live_autosave= 1; 362 | live_debug= 0; 363 | 364 | //create GLUI and add the options, be sure to connect them all to their real vals later 365 | Menu = GLUI_Master.create_glui("Menu",0,20,20); 366 | Menu->add_checkbox("Closed world",&live_worldclosed); 367 | Menu->add_checkbox("Pause",&live_paused); 368 | Menu->add_checkbox("Allow Autosaves",&live_autosave); 369 | 370 | new GLUI_Button(Menu,"Load World",1, glui_handleRW); 371 | new GLUI_Button(Menu,"Save World",2, glui_handleRW); 372 | new GLUI_Button(Menu,"New World",3, glui_handleRW); 373 | 374 | GLUI_Panel *panel_speed= new GLUI_Panel(Menu,"Speed Control"); 375 | Menu->add_checkbox_to_panel(panel_speed,"Fast Mode",&live_fastmode); 376 | Menu->add_spinner_to_panel(panel_speed,"Speed",GLUI_SPINNER_INT,&live_skipdraw); 377 | 378 | GLUI_Rollout *rollout_vis= new GLUI_Rollout(Menu,"Visuals"); 379 | GLUI_RadioGroup *group_layers= new GLUI_RadioGroup(rollout_vis,&live_layersvis); 380 | new GLUI_StaticText(rollout_vis,"Layer"); 381 | new GLUI_RadioButton(group_layers,"off"); 382 | for(int i=0; iadd_column_to_panel(rollout_vis,true); 395 | GLUI_RadioGroup *group_agents= new GLUI_RadioGroup(rollout_vis,&live_agentsvis); 396 | new GLUI_StaticText(rollout_vis,"Agents"); 397 | for(int i=0; iadd_checkbox_to_panel(rollout_xyl, "Follow Selected", &live_follow); 427 | Menu->add_button_to_panel(rollout_xyl, "Save Selected", 4, glui_handleRW); 428 | 429 | Menu->add_checkbox("DEBUG",&live_debug); 430 | 431 | //set to main graphics window 432 | Menu->set_main_gfx_window(win1); 433 | } 434 | 435 | void GLView::handleRW(int action) //glui callback for saving/loading worlds 436 | { 437 | live_paused= 1; 438 | 439 | //action= 1: loading, action= 2: saving, action= 3: new (reset) world 440 | if (action==1){ //load option selected 441 | Loader = GLUI_Master.create_glui("Load World",0,50,50); 442 | 443 | Filename= new GLUI_EditText(Loader,"File Name (e.g, 'WORLD.SCB'):"); 444 | Filename->set_w(300); 445 | new GLUI_Button(Loader,"Load",1, glui_handleCloses); 446 | 447 | Loader->set_main_gfx_window(win1); 448 | 449 | } else if (action==2){ //save option 450 | Saver = GLUI_Master.create_glui("Save World",0,50,50); 451 | 452 | Filename= new GLUI_EditText(Saver,"File Name (e.g, 'WORLD.SCB'):"); 453 | Filename->set_w(300); 454 | new GLUI_Button(Saver,"Save",2, glui_handleCloses); 455 | 456 | Saver->set_main_gfx_window(win1); 457 | } else if (action==3){ //new world (old reset) 458 | Alert = GLUI_Master.create_glui("Alert",0,50,50); 459 | Alert->show(); 460 | new GLUI_StaticText(Alert,"Are you sure? This will"); 461 | new GLUI_StaticText(Alert,"erase the current world."); 462 | new GLUI_Button(Alert,"Okay",3, glui_handleCloses); 463 | new GLUI_Button(Alert,"Cancel",4, glui_handleCloses); 464 | 465 | Alert->set_main_gfx_window(win1); 466 | } else if (action==4){ //save selected agent 467 | Saver = GLUI_Master.create_glui("Save Agent",0,50,50); 468 | 469 | Filename= new GLUI_EditText(Saver,"File Name (e.g, 'AGENT.BOT'):"); 470 | Filename->set_w(300); 471 | new GLUI_Button(Saver,"Save",6, glui_handleCloses); 472 | } 473 | } 474 | 475 | void GLView::handleCloses(int action) //GLUI callback for handling window closing 476 | { 477 | live_paused= 0; 478 | 479 | ReadWrite* savehelper= new ReadWrite(); //for loading/saving 480 | 481 | if (action==1){ //loading 482 | strcpy(filename,Filename->get_text()); 483 | if (debug) printf("File: '\\saves\\%s'\n",filename); 484 | if (!filename || filename=="" || filename==NULL || filename[0]=='\0'){ 485 | printf("ERROR: empty filename; returning to program.\n"); 486 | 487 | Alert = GLUI_Master.create_glui("Alert",0,50,50); 488 | Alert->show(); 489 | new GLUI_StaticText(Alert,"No file name given."); 490 | new GLUI_StaticText(Alert,"Returning to main program."); 491 | new GLUI_Button(Alert,"Okay",4, glui_handleCloses); 492 | 493 | } else { 494 | savehelper->loadWorld(world, xtranslate, ytranslate, filename); 495 | } 496 | Loader->hide(); 497 | 498 | } else if (action==2){ //saving 499 | trySaveWorld(); 500 | Saver->hide(); 501 | 502 | } else if (action==3){ //resetting 503 | world->reset(); 504 | world->spawn(); 505 | printf("WORLD RESET!\n"); 506 | Alert->hide(); 507 | } else if (action==4){ //Alert cancel/continue 508 | Alert->hide(); 509 | } else if (action==5){ //Alert from above saving 510 | savehelper->saveWorld(world, xtranslate, ytranslate, filename); 511 | Alert->hide(); 512 | } else if (action==6){ //saving agents 513 | const char *tempname= Filename->get_text(); 514 | strcpy(filename, tempname); 515 | if (debug) printf("File: '\\saved_agents\\%s'",filename); 516 | if (!filename || filename==""){ 517 | printf("ERROR: empty filename; returning to program.\n"); 518 | 519 | Alert = GLUI_Master.create_glui("Alert",0,50,50); 520 | Alert->show(); 521 | new GLUI_StaticText(Alert, "No file name given." ); 522 | new GLUI_StaticText(Alert, "Returning to main program." ); 523 | new GLUI_Button(Alert,"Okay"); 524 | 525 | } else { 526 | //check the filename given to see if it exists yet 527 | char address[32]; 528 | strcpy(address,"saved_agents\\"); 529 | strcat(address,tempname); 530 | 531 | // FILE* ck = fopen(address, "r"); 532 | // if(ck){ 533 | // if (debug) printf("WARNING: %s already exists!\n", filename); 534 | // 535 | // Alert = GLUI_Master.create_glui("Alert",0,50,50); 536 | // Alert->show(); 537 | // new GLUI_StaticText(Alert, "The file name given already exists." ); 538 | // new GLUI_StaticText(Alert, "Would you like to overwrite?" ); 539 | // new GLUI_Button(Alert,"Okay",7, glui_handleCloses); 540 | // new GLUI_Button(Alert,"Cancel",4, glui_handleCloses); 541 | // live_paused= 1; 542 | // fclose(ck); 543 | // } else { 544 | // fclose(ck); 545 | FILE* sa = fopen(address, "w"); 546 | int sidx= world->getSelectedAgent(); 547 | if (sidx>=0){ 548 | Agent *a= &world->agents[sidx]; 549 | savehelper->saveAgent(a, sa); 550 | } 551 | fclose(sa); 552 | // } 553 | } 554 | Saver->hide(); 555 | // } else if (action==7){ //overwrite agent save 556 | // FILE* sa = fopen(address, "w"); 557 | // int sidx= world->getSelectedAgent(); 558 | // if (sidx>=0){ 559 | // savehelper->saveAgent(world->agents[sidx], sa); 560 | // } 561 | // fclose(sa); 562 | } 563 | } 564 | 565 | void GLView::trySaveWorld(bool autosave) 566 | { 567 | const char *tempname; 568 | if(autosave) tempname= "AUTOSAVE.SCB"; 569 | else tempname= Filename->get_text(); 570 | strcpy(filename, tempname); 571 | if (debug) printf("File: '\\saves\\%s'\n",filename); 572 | if (!filename || filename=="" || filename==NULL || filename[0]=='\0'){ 573 | printf("ERROR: empty filename; returning to program.\n"); 574 | 575 | Alert = GLUI_Master.create_glui("Alert",0,50,50); 576 | Alert->show(); 577 | new GLUI_StaticText(Alert, "No file name given." ); 578 | new GLUI_StaticText(Alert, "Returning to main program." ); 579 | new GLUI_Button(Alert,"Okay"); 580 | 581 | } else { 582 | char address[32]; 583 | strcpy(address,"saves\\"); 584 | strcat(address,tempname); 585 | 586 | if(autosave){ //autosave overwrites 587 | ReadWrite* savehelper= new ReadWrite(); 588 | savehelper->saveWorld(world, xtranslate, ytranslate, filename); 589 | } else { 590 | //check the filename given to see if it exists yet 591 | FILE* ck = fopen(address, "r"); 592 | if(ck){ 593 | if (debug) printf("WARNING: %s already exists!\n", filename); 594 | 595 | Alert = GLUI_Master.create_glui("Alert",0,50,50); 596 | Alert->show(); 597 | new GLUI_StaticText(Alert, "The file name given already exists." ); 598 | new GLUI_StaticText(Alert, "Would you like to overwrite?" ); 599 | new GLUI_Button(Alert,"Okay",5, glui_handleCloses); 600 | new GLUI_Button(Alert,"Cancel",4, glui_handleCloses); 601 | live_paused= 1; 602 | 603 | fclose(ck); 604 | } else { 605 | ReadWrite* savehelper= new ReadWrite(); 606 | savehelper->saveWorld(world, xtranslate, ytranslate, filename); 607 | } 608 | } 609 | } 610 | } 611 | 612 | void GLView::handleIdle() 613 | { 614 | //set proper window (we don't want to draw on nothing, now do we?!) 615 | if (glutGetWindow() != win1) glutSetWindow(win1); 616 | 617 | GLUI_Master.sync_live_all(); 618 | 619 | //after syncing all the live vars with GLUI_Master, set the vars they represent to their proper values. 620 | world->setClosed(live_worldclosed); 621 | world->setDebug((bool) live_debug); 622 | 623 | modcounter++; 624 | if (!live_paused) world->update(); 625 | 626 | //autosave world periodically, based on world time 627 | if (live_autosave==1 && world->modcounter%(world->FRAMES_PER_EPOCH)==0) trySaveWorld(true); 628 | 629 | //show FPS and other stuff 630 | int currentTime = glutGet( GLUT_ELAPSED_TIME ); 631 | frames++; 632 | if ((currentTime - lastUpdate) >= 1000) { 633 | sprintf( buf, "FPS: %d speed: %d Total Agents: %d Herbivores: %d Carnivores: %d Frugivores: %d Epoch: %d", 634 | frames, live_skipdraw, world->getAgents(), world->getHerbivores(), world->getCarnivores(), world->getFrugivores(), world->epoch() ); 635 | glutSetWindowTitle( buf ); 636 | frames = 0; 637 | lastUpdate = currentTime; 638 | } 639 | 640 | if (!live_fastmode) { 641 | if (live_skipdraw>0) { 642 | if (modcounter%live_skipdraw==0) renderScene(); //increase fps by skipping drawing 643 | } 644 | else { //we will decrease fps by waiting using clocks 645 | clock_t endwait; 646 | float mult=-0.005*(live_skipdraw-1); //ugly, ah well 647 | endwait = clock () + mult * CLOCKS_PER_SEC ; 648 | while (clock() < endwait) {} 649 | renderScene(); 650 | } 651 | } 652 | } 653 | 654 | void GLView::renderScene() 655 | { 656 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 657 | glPushMatrix(); 658 | 659 | glTranslatef(glutGet(GLUT_WINDOW_WIDTH)/2, glutGet(GLUT_WINDOW_HEIGHT)/2, 0.0f); 660 | glScalef(scalemult, scalemult, 1.0f); 661 | 662 | //handle world agent selection interface 663 | world->setSelection(live_selection); 664 | if (world->getSelection()==-1 && live_selection!=Select::MANUAL && modcounter%5==0) live_selection= Select::NONE; 665 | 666 | if(live_follow==1){ //if we're following, 667 | float xi=0, yi=0; 668 | world->getFollowLocation(xi, yi); //get the follow location from the world (location of selected agent) 669 | 670 | if(xi!=0 && yi!=0){ 671 | // if we got to move the screen completly accross the world, jump instead 672 | if(abs(-xi-xtranslate)>0.95*conf::WIDTH || abs(-yi-ytranslate)>0.95*conf::HEIGHT){ 673 | xtranslate= -xi; ytranslate= -yi; 674 | } else { 675 | float speed= conf::SNAP_SPEED; 676 | if(scalemult>0.5) speed= cap(speed*pow(scalemult + 0.5,3)); 677 | xtranslate+= speed*(-xi-xtranslate); ytranslate+= speed*(-yi-ytranslate); 678 | } 679 | } 680 | } 681 | 682 | glTranslatef(xtranslate, ytranslate, 0.0f); 683 | 684 | world->draw(this, live_layersvis); 685 | 686 | glPopMatrix(); 687 | glutSwapBuffers(); 688 | } 689 | 690 | void GLView::drawAgent(const Agent& agent, float x, float y, bool ghost) 691 | { 692 | float n; 693 | float r= agent.radius; 694 | float rp= agent.radius+2.5; 695 | 696 | if (live_agentsvis!=Visual::NONE) { 697 | 698 | //color assignment 699 | float red= 0,gre= 0,blu= 0; 700 | float discomfort= 0; 701 | 702 | //first, calculate colors which also have indicator boxes 703 | float dd= 2.0*abs(agent.pos.y/conf::HEIGHT - 0.5); 704 | discomfort= cap(sqrt(abs(dd-agent.temperature_preference))); 705 | if (discomfort<0.08) discomfort=0; 706 | 707 | float stomach_red= cap(pow(agent.stomach[Stomach::MEAT],2)+pow(agent.stomach[Stomach::FRUIT],2)-pow(agent.stomach[Stomach::PLANT],2)); 708 | float stomach_gre= cap(pow(agent.stomach[Stomach::PLANT],2)/2+pow(agent.stomach[Stomach::FRUIT],2)-pow(agent.stomach[Stomach::MEAT],2)); 709 | 710 | //now colorize agents and other things 711 | if (live_agentsvis==Visual::RGB){ //real rgb values 712 | red= agent.red; gre= agent.gre; blu= agent.blu; 713 | 714 | } else if (live_agentsvis==Visual::STOMACH){ //stomach 715 | red= stomach_red; 716 | gre= stomach_gre; 717 | 718 | } else if (live_agentsvis==Visual::DISCOMFORT){ //temp discomfort 719 | red= discomfort; gre= (2-discomfort)/2; blu= 1-discomfort; 720 | 721 | } else if (live_agentsvis==Visual::VOLUME) { //volume 722 | red= agent.volume; 723 | gre= agent.volume; 724 | blu= agent.volume; 725 | 726 | } else if (live_agentsvis==Visual::SPECIES){ //species 727 | red= (cos((float)agent.species/330*M_PI)+1.0)/2.0; 728 | gre= (sin((float)agent.species/100*M_PI)+1.0)/2.0; 729 | blu= (cos((float)agent.species/43*M_PI)+1.0)/2.0; 730 | 731 | } else if (live_agentsvis==Visual::CROSSABLE){ //crossover-compatable to selection 732 | //all other agents look grey if unrelated or if none is selected, b/c then we don't have a reference 733 | red= 0.8; 734 | gre= 0.8; 735 | blu= 0.8; 736 | 737 | if(world->getSelectedAgent()>=0){ 738 | float deviation= abs(agent.species - world->agents[world->getSelectedAgent()].species); //species deviation check 739 | if (deviation==0) { //exact copies 740 | red= 0.2; 741 | } else if (deviation<=world->MAXDEVIATION) { 742 | //reproducable relatives 743 | red= 0; 744 | gre= 0; 745 | } else if (deviation<=3*world->MAXDEVIATION) { 746 | //un-reproducable relatives 747 | red= 0.6; 748 | gre= 0.4; 749 | } 750 | } 751 | 752 | } else if (live_agentsvis==Visual::HEALTH) { //volume 753 | gre= powf(agent.health/2,0.5); 754 | red= ((int)(agent.health*1000)%2==0) ? (1.0-agent.health/2)*gre : (1.0-agent.health/2); 755 | } 756 | 757 | 758 | //handle selected agent 759 | if (agent.id==world->getSelection() && !ghost) { 760 | //draw selection 761 | glBegin(GL_POLYGON); 762 | glColor3f(1,1,1); 763 | drawCircle(x, y, agent.radius+3/scalemult); 764 | glEnd(); 765 | 766 | if(scalemult > .2){ 767 | glPushMatrix(); 768 | glTranslatef(x-80,y+20,0); 769 | //draw inputs, outputs 770 | float col; 771 | float yy=15; 772 | float xx=15; 773 | float ss=16; 774 | glBegin(GL_QUADS); 775 | for (int j=0;j .7){ 784 | glEnd(); 785 | if(j==Input::CLOCK1 || j==Input::CLOCK2 || j==Input::CLOCK3){ 786 | RenderString(xx/3+ss*j, yy*2/3, GLUT_BITMAP_HELVETICA_12, "Q", 0.0f, 0.0f, 0.0f); 787 | } else if(j==Input::TEMP){ 788 | RenderString(xx/3+ss*j, yy*2/3, GLUT_BITMAP_HELVETICA_12, "H", 0.8f, 0.5f, 0.0f); 789 | } else if(j==Input::HEARING1 || j==Input::HEARING2){ 790 | RenderString(xx/3+ss*j, yy*2/3, GLUT_BITMAP_HELVETICA_12, "E", 1.0f, 1.0f, 1.0f); 791 | } 792 | glBegin(GL_QUADS); 793 | } 794 | } 795 | yy+=5; 796 | for (int j=0;j .7){ 810 | glEnd(); 811 | if(j==Output::LEFT_WHEEL_B || j==Output::LEFT_WHEEL_F || j==Output::RIGHT_WHEEL_B || j==Output::RIGHT_WHEEL_F){ 812 | RenderString(xx/3+ss*j, yy+ss*2/3, GLUT_BITMAP_HELVETICA_12, "!", 0.0f, 1.0f, 0.0f); 813 | } else if(j==Output::VOLUME){ 814 | RenderString(xx/3+ss*j, yy+ss*2/3, GLUT_BITMAP_HELVETICA_12, "V", 1.0f, 1.0f, 1.0f); 815 | } else if(j==Output::CLOCKF3){ 816 | RenderString(xx/3+ss*j, yy+ss*2/3, GLUT_BITMAP_HELVETICA_12, "Q", 0.0f, 0.0f, 0.0f); 817 | } else if(j==Output::SPIKE){ 818 | RenderString(xx/3+ss*j, yy+ss*2/3, GLUT_BITMAP_HELVETICA_12, "S", 1.0f, 0.0f, 0.0f); 819 | } else if(j==Output::PROJECT){ 820 | RenderString(xx/3+ss*j, yy+ss*2/3, GLUT_BITMAP_HELVETICA_12, "P", 0.5f, 0.0f, 0.5f); 821 | } 822 | glBegin(GL_QUADS); 823 | } 824 | 825 | } 826 | yy+=ss*2; 827 | glEnd(); 828 | 829 | if(world->isDebug()){ 830 | //draw brain in debug mode 831 | glBegin(GL_QUADS); 832 | float offx=0; 833 | ss=8; 834 | xx=ss; 835 | for (int j=0;jDIST*sin(n),y+world->DIST*cos(n),0); 859 | n = (k+1)*(M_PI/8); 860 | glVertex3f(x+world->DIST*sin(n),y+world->DIST*cos(n),0); 861 | } 862 | glEnd(); 863 | 864 | //now spike, share, and grab effective zones 865 | glBegin(GL_POLYGON); 866 | glColor4f(1,0,0,0.35); 867 | glVertex3f(x,y,0); 868 | glVertex3f(x+(r+agent.spikeLength*world->SPIKELENGTH)*cos(agent.angle+M_PI/8), 869 | y+(r+agent.spikeLength*world->SPIKELENGTH)*sin(agent.angle+M_PI/8),0); 870 | glVertex3f(x+(r+agent.spikeLength*world->SPIKELENGTH)*cos(agent.angle), 871 | y+(r+agent.spikeLength*world->SPIKELENGTH)*sin(agent.angle),0); 872 | glVertex3f(x+(r+agent.spikeLength*world->SPIKELENGTH)*cos(agent.angle-M_PI/8), 873 | y+(r+agent.spikeLength*world->SPIKELENGTH)*sin(agent.angle-M_PI/8),0); 874 | glVertex3f(x,y,0); 875 | glEnd(); 876 | 877 | //grab is currently a range-only thing, change? 878 | glBegin(GL_POLYGON); 879 | glColor4f(0,1,1,0.15); 880 | drawCircle(x,y,r+world->GRABBING_DISTANCE); 881 | glEnd(); 882 | 883 | //health-sharing 884 | glBegin(GL_POLYGON); 885 | glColor4f(0,0.5,0,0.25); 886 | drawCircle(x,y,r+world->FOOD_SHARING_DISTANCE); 887 | glEnd(); 888 | 889 | } else glPopMatrix(); 890 | } 891 | 892 | /* 893 | //draw lines connecting connected brain boxes, but only in debug mode (NEEDS SIMPLIFICATION) 894 | if(world->isDebug()){ 895 | glEnd(); 896 | glBegin(GL_LINES); 897 | float offx=0; 898 | ss=30; 899 | xx=ss; 900 | for (int j=0;j0) { 934 | glBegin(GL_POLYGON); 935 | glColor4f(agent.ir,agent.ig,agent.ib,0.75); 936 | drawCircle(x, y, r+((int)agent.indicator)); 937 | glEnd(); 938 | } 939 | 940 | //draw giving/receiving 941 | if(agent.dfood!=0){ 942 | glBegin(GL_POLYGON); 943 | float mag=cap(abs(agent.dfood)/world->FOODTRANSFER/3); 944 | if(agent.dfood>0) glColor3f(0,mag,0); 945 | else glColor3f(mag,0,0); //draw sharing as a thick green or red outline 946 | for (int k=0;k<17;k++){ 947 | n = k*(M_PI/8); 948 | glVertex3f(x+rp*sin(n),y+rp*cos(n),0); 949 | n = (k+1)*(M_PI/8); 950 | glVertex3f(x+rp*sin(n),y+rp*cos(n),0); 951 | } 952 | glEnd(); 953 | } 954 | 955 | if (scalemult > .1 || ghost) { //dont render eyes, ears, or boost if zoomed too far out, but always render them on ghosts 956 | //draw eyes 957 | for(int q=0;q .3 || ghost) && agent.grabbing>0.5){ 990 | glLineWidth(2); 991 | glBegin(GL_LINES); 992 | 993 | glColor4f(0.0,0.7,0.7,0.75); 994 | glVertex3f(x,y,0); 995 | float mult= agent.grabID==-1 ? 1 : 0; 996 | float aa= agent.angle+M_PI/8*mult; 997 | float ab= agent.angle-M_PI/8*mult; 998 | glVertex3f(x+(world->GRABBING_DISTANCE+r)*cos(aa), y+(world->GRABBING_DISTANCE+r)*sin(aa), 0); 999 | glVertex3f(x,y,0); 1000 | glVertex3f(x+(world->GRABBING_DISTANCE+r)*cos(ab), y+(world->GRABBING_DISTANCE+r)*sin(ab), 0); 1001 | glEnd(); 1002 | glLineWidth(1); 1003 | 1004 | /* agent-agent directed grab vis code. Works but coords are wrong from World.cpp 1005 | glLineWidth(2); 1006 | glBegin(GL_LINES); 1007 | 1008 | glColor4f(0.0,0.7,0.7,0.75); 1009 | glVertex3f(x,y,0); 1010 | 1011 | if(agent.grabID!=-1) glVertex3f(agent.grabx, agent.graby, 0); 1012 | else { 1013 | float aa= agent.angle+M_PI/8; 1014 | float ab= agent.angle-M_PI/8; 1015 | glVertex3f(x+(world->GRABBING_DISTANCE+r)*cos(aa), y+(world->GRABBING_DISTANCE+r)*sin(aa), 0); 1016 | glVertex3f(x,y,0); 1017 | glVertex3f(x+(world->GRABBING_DISTANCE+r)*cos(ab), y+(world->GRABBING_DISTANCE+r)*sin(ab), 0); 1018 | } 1019 | glEnd(); 1020 | glLineWidth(1); 1021 | */ 1022 | } 1023 | 1024 | } 1025 | 1026 | glBegin(GL_POLYGON); 1027 | //body 1028 | glColor3f(red,gre,blu); 1029 | drawCircle(x, y, r); 1030 | glEnd(); 1031 | 1032 | glBegin(GL_LINES); 1033 | 1034 | //outline and spikes are effected by the zoom magnitude 1035 | float blur= cap(4.5*scalemult-0.5); 1036 | if (ghost) blur= 1; //disable effect for static rendering 1037 | 1038 | //jaws 1039 | if ((scalemult > .08 || ghost) && agent.jawrend>0) { 1040 | //dont render jaws if zoomed too far out, but always render them on ghosts, and only if they've been active within the last few ticks 1041 | glColor4f(0.9,0.9,0,blur); 1042 | float mult= 1-powf(abs(agent.jawPosition),0.5); 1043 | glVertex3f(x+r*cos(agent.angle),y+r*sin(agent.angle),0); 1044 | glVertex3f(x+(10+r)*cos(agent.angle+M_PI/8*mult), y+(10+r)*sin(agent.angle+M_PI/8*mult), 0); 1045 | glVertex3f(x+r*cos(agent.angle),y+r*sin(agent.angle),0); 1046 | glVertex3f(x+(10+r)*cos(agent.angle-M_PI/8*mult), y+(10+r)*sin(agent.angle-M_PI/8*mult), 0); 1047 | } 1048 | 1049 | //outline 1050 | float out_red= 0,out_gre= 0,out_blu= 0; 1051 | if (agent.jump>0) { //draw jumping as yellow outline 1052 | out_red= 0.8; 1053 | out_gre= 0.8; 1054 | } 1055 | 1056 | glColor3f(cap(out_red*blur + (1-blur)*red), cap(out_gre*blur + (1-blur)*gre), cap(out_blu*blur + (1-blur)*blu)); 1057 | 1058 | for (int k=0;k<17;k++) 1059 | { 1060 | n = k*(M_PI/8); 1061 | glVertex3f(x+r*sin(n),y+r*cos(n),0); 1062 | n = (k+1)*(M_PI/8); 1063 | glVertex3f(x+r*sin(n),y+r*cos(n),0); 1064 | } 1065 | 1066 | //sound waves! 1067 | if(live_agentsvis==Visual::VOLUME && !ghost && agent.volume>0){ 1068 | float volume= agent.volume; 1069 | float count= agent.tone*11+1; 1070 | for (int l=0; l<=(int)count; l++){ 1071 | float dist= world->DIST*(l/count)+4*(world->modcounter%(int)((world->DIST)/4)); 1072 | if (dist>world->DIST) dist-= world->DIST; 1073 | glColor4f((1-agent.tone)*(1-agent.tone), 1-fabs(agent.tone-0.5)*2, agent.tone*agent.tone, cap((1-dist/world->DIST)*sqrtf(volume))); 1074 | 1075 | for (int k=0;k<32;k++) 1076 | { 1077 | n = k*(M_PI/16); 1078 | glVertex3f(x+dist*sin(n),y+dist*cos(n),0); 1079 | n = (k+1)*(M_PI/16); 1080 | glVertex3f(x+dist*sin(n),y+dist*cos(n),0); 1081 | } 1082 | } 1083 | } 1084 | 1085 | //and spike, if harmful 1086 | if ((scalemult > .08 || ghost) && agent.spikeLength*world->SPIKELENGTH>r) { 1087 | //dont render spike if zoomed too far out, but always render it on ghosts, and only if it's capable of hurting 1088 | glColor4f(0.7,0,0,blur); 1089 | glVertex3f(x,y,0); 1090 | glVertex3f(x+(world->SPIKELENGTH*agent.spikeLength)*cos(agent.angle), 1091 | y+(world->SPIKELENGTH*agent.spikeLength)*sin(agent.angle), 1092 | 0); 1093 | } 1094 | glEnd(); 1095 | 1096 | //some final debug stuff that is shown even on ghosts: 1097 | if(world->isDebug() || ghost){ 1098 | //wheels and wheel speeds 1099 | float wheelangle= agent.angle+ M_PI/2; 1100 | glBegin(GL_LINES); 1101 | glColor3f(0,1,0); 1102 | glVertex3f(x+agent.radius/2*cos(wheelangle),y+agent.radius/2*sin(wheelangle),0); 1103 | glVertex3f(x+agent.radius/2*cos(wheelangle)+20*agent.w1*cos(agent.angle), y+agent.radius/2*sin(wheelangle)+20*agent.w1*sin(agent.angle), 0); 1104 | wheelangle-= M_PI; 1105 | glVertex3f(x+agent.radius/2*cos(wheelangle),y+agent.radius/2*sin(wheelangle),0); 1106 | glVertex3f(x+agent.radius/2*cos(wheelangle)+20*agent.w2*cos(agent.angle), y+agent.radius/2*sin(wheelangle)+20*agent.w2*sin(agent.angle), 0); 1107 | glEnd(); 1108 | 1109 | glBegin(GL_POLYGON); 1110 | glColor3f(0,1,0); 1111 | drawCircle(x+agent.radius/2*cos(wheelangle), y+agent.radius/2*sin(wheelangle), 1); 1112 | glEnd(); 1113 | wheelangle+= M_PI; 1114 | glBegin(GL_POLYGON); 1115 | drawCircle(x+agent.radius/2*cos(wheelangle), y+agent.radius/2*sin(wheelangle), 1); 1116 | glEnd(); 1117 | } 1118 | 1119 | if(!ghost){ //only draw extra infos if not a ghost 1120 | 1121 | if(scalemult > .3) {//hide extra visual data if really far away 1122 | 1123 | //debug stuff 1124 | if(world->isDebug()) { 1125 | //debug sight lines: connect to anything selected agent sees 1126 | glBegin(GL_LINES); 1127 | for (int i=0;i<(int)world->linesA.size();i++) { 1128 | glColor3f(1,1,1); 1129 | glVertex3f(world->linesA[i].x,world->linesA[i].y,0); 1130 | glVertex3f(world->linesB[i].x,world->linesB[i].y,0); 1131 | } 1132 | world->linesA.resize(0); 1133 | world->linesB.resize(0); 1134 | glEnd(); 1135 | 1136 | //debug cell smell box: outlines all cells the selected agent is "smelling" 1137 | if(agent.id==world->getSelection()){ 1138 | int minx, maxx, miny, maxy; 1139 | int scx= (int) (agent.pos.x/conf::CZ); 1140 | int scy= (int) (agent.pos.y/conf::CZ); 1141 | 1142 | minx= (scx-world->DIST/conf::CZ/2) > 0 ? (scx-world->DIST/conf::CZ/2)*conf::CZ : 0; 1143 | maxx= (scx+1+world->DIST/conf::CZ/2) < conf::WIDTH/conf::CZ ? (scx+1+world->DIST/conf::CZ/2)*conf::CZ : conf::WIDTH; 1144 | miny= (scy-world->DIST/conf::CZ/2) > 0 ? (scy-world->DIST/conf::CZ/2)*conf::CZ : 0; 1145 | maxy= (scy+1+world->DIST/conf::CZ/2) < conf::HEIGHT/conf::CZ ? (scy+1+world->DIST/conf::CZ/2)*conf::CZ : conf::HEIGHT; 1146 | 1147 | glBegin(GL_LINES); 1148 | glColor3f(0,1,0); 1149 | glVertex3f(minx,miny,0); 1150 | glVertex3f(minx,maxy,0); 1151 | glVertex3f(minx,maxy,0); 1152 | glVertex3f(maxx,maxy,0); 1153 | glVertex3f(maxx,maxy,0); 1154 | glVertex3f(maxx,miny,0); 1155 | glVertex3f(maxx,miny,0); 1156 | glVertex3f(minx,miny,0); 1157 | glEnd(); 1158 | } 1159 | } 1160 | 1161 | //health 1162 | int xo=18; 1163 | int yo=-15; 1164 | glBegin(GL_QUADS); 1165 | glColor3f(0,0,0); 1166 | glVertex3f(x+xo,y+yo,0); 1167 | glVertex3f(x+xo+5,y+yo,0); 1168 | glVertex3f(x+xo+5,y+yo+40,0); 1169 | glVertex3f(x+xo,y+yo+40,0); 1170 | 1171 | glColor3f(0,0.8,0); 1172 | glVertex3f(x+xo,y+yo+20*(2-agent.health),0); 1173 | glVertex3f(x+xo+5,y+yo+20*(2-agent.health),0); 1174 | glVertex3f(x+xo+5,y+yo+40,0); 1175 | glVertex3f(x+xo,y+yo+40,0); 1176 | 1177 | //hybrid marker 1178 | if (agent.hybrid) { 1179 | glColor3f(0,0,0.8); 1180 | glVertex3f(x+xo+6,y+yo,0); 1181 | glVertex3f(x+xo+12,y+yo,0); 1182 | glVertex3f(x+xo+12,y+yo+10,0); 1183 | glVertex3f(x+xo+6,y+yo+10,0); 1184 | } 1185 | 1186 | //stomach type indicator 1187 | glColor3f(stomach_red,stomach_gre,0); 1188 | glVertex3f(x+xo+6,y+yo+12,0); 1189 | glVertex3f(x+xo+12,y+yo+12,0); 1190 | glVertex3f(x+xo+12,y+yo+22,0); 1191 | glVertex3f(x+xo+6,y+yo+22,0); 1192 | 1193 | //sound volume indicator 1194 | glColor3f(agent.volume,agent.volume,agent.volume); 1195 | glVertex3f(x+xo+6,y+yo+24,0); 1196 | glVertex3f(x+xo+12,y+yo+24,0); 1197 | glVertex3f(x+xo+12,y+yo+34,0); 1198 | glVertex3f(x+xo+6,y+yo+34,0); 1199 | 1200 | //temp discomfort indicator 1201 | glColor3f(discomfort,(2-discomfort)/2,(1-discomfort)); 1202 | glVertex3f(x+xo+6,y+yo+36,0); 1203 | glVertex3f(x+xo+12,y+yo+36,0); 1204 | glVertex3f(x+xo+12,y+yo+46,0); 1205 | glVertex3f(x+xo+6,y+yo+46,0); 1206 | 1207 | //land/water lungs requirement indicator 1208 | glColor3f(0.2,0.4*agent.lungs+0.3,0.6*(1-agent.lungs)+0.2); //land (0.2,0.7,0.2), amph (0.2,0.5,0.5), water (0.2,0.3,0.8) 1209 | glVertex3f(x+xo+14,y+yo,0); 1210 | glVertex3f(x+xo+20,y+yo,0); 1211 | glVertex3f(x+xo+20,y+yo+10,0); 1212 | glVertex3f(x+xo+14,y+yo+10,0); 1213 | } 1214 | 1215 | glEnd(); 1216 | 1217 | //print stats 1218 | if(scalemult > .7) { // hide the number stats when zoomed out 1219 | //generation count 1220 | sprintf(buf2, "%i", agent.gencount); 1221 | RenderString(x-rp*1.414, y+rp*1.414, GLUT_BITMAP_HELVETICA_12, buf2, 0.8f, 1.0f, 1.0f); 1222 | 1223 | //age 1224 | sprintf(buf2, "%i", agent.age); 1225 | float red = cap((float) agent.age/world->MAXAGE); //will be redder the closer it is to MAXAGE 1226 | RenderString(x-rp*1.414, y+rp*1.414+12, GLUT_BITMAP_HELVETICA_12, buf2, 0.8f, 1.0-red, 1.0-red); 1227 | 1228 | //health 1229 | sprintf(buf2, "%.2f", agent.health); 1230 | RenderString(x-rp*1.414, y+rp*1.414+24, GLUT_BITMAP_HELVETICA_12, buf2, 0.8f, 1.0f, 1.0f); 1231 | 1232 | //repcounter 1233 | float dr = agent.metabolism/conf::MAXMETABOLISM; //red if high metabolism, blue if low 1234 | sprintf(buf2, "%.2f", agent.repcounter); 1235 | RenderString(x-rp*1.414, y+rp*1.414+36, GLUT_BITMAP_HELVETICA_12, buf2, dr/2+0.5, dr/2+0.5, (1.0-dr)/2+0.5); 1236 | } 1237 | } 1238 | } 1239 | } 1240 | 1241 | 1242 | void GLView::drawData() 1243 | { 1244 | float mm = 3; 1245 | //draw misc info 1246 | glBegin(GL_LINES); 1247 | glColor3f(0,0,0); //border around graphs and feedback 1248 | 1249 | glVertex3f(conf::WIDTH,0,0); 1250 | glVertex3f(-2020,0,0); 1251 | 1252 | glVertex3f(-2020,0,0); 1253 | glVertex3f(-2020,conf::HEIGHT,0); 1254 | 1255 | glVertex3f(0,0,0); 1256 | glVertex3f(0,conf::HEIGHT,0); 1257 | 1258 | glVertex3f(-2020,conf::HEIGHT,0); 1259 | glVertex3f(conf::WIDTH,conf::HEIGHT,0); 1260 | 1261 | glVertex3f(conf::WIDTH,conf::HEIGHT,0); 1262 | glVertex3f(conf::WIDTH,0,0); 1263 | 1264 | glColor3f(0,0,0.8); //hybrid count 1265 | for(int q=0;qptr-1) continue; 1267 | glVertex3f(-2020 + q*10, conf::HEIGHT - mm*world->numHybrid[q],0); 1268 | glVertex3f(-2020 +(q+1)*10, conf::HEIGHT - mm*world->numHybrid[q+1],0); 1269 | } 1270 | glColor3f(0,1,0); //herbivore count 1271 | for(int q=0;qptr-1) continue; 1273 | glVertex3f(-2020 + q*10,conf::HEIGHT -mm*world->numHerbivore[q],0); 1274 | glVertex3f(-2020 +(q+1)*10,conf::HEIGHT -mm*world->numHerbivore[q+1],0); 1275 | } 1276 | glColor3f(1,0,0); //carnivore count 1277 | for(int q=0;qptr-1) continue; 1279 | glVertex3f(-2020 + q*10,conf::HEIGHT -mm*world->numCarnivore[q],0); 1280 | glVertex3f(-2020 +(q+1)*10,conf::HEIGHT -mm*world->numCarnivore[q+1],0); 1281 | } 1282 | glColor3f(0.7,0.7,0); //frugivore count 1283 | for(int q=0;qptr-1) continue; 1285 | glVertex3f(-2020 + q*10,conf::HEIGHT -mm*world->numFrugivore[q],0); 1286 | glVertex3f(-2020 +(q+1)*10,conf::HEIGHT -mm*world->numFrugivore[q+1],0); 1287 | } 1288 | glColor3f(0,0,0); //total count 1289 | for(int q=0;qptr-1) continue; 1291 | glVertex3f(-2020 + q*10,conf::HEIGHT -mm*world->numTotal[q],0); 1292 | glVertex3f(-2020 +(q+1)*10,conf::HEIGHT -mm*world->numTotal[q+1],0); 1293 | } 1294 | glVertex3f(-2020 + world->ptr*10,conf::HEIGHT,0); 1295 | glVertex3f(-2020 + world->ptr*10,conf::HEIGHT -mm*world->getAgents(),0); 1296 | glEnd(); 1297 | sprintf(buf2, "%i agents", world->getAgents()); 1298 | RenderString(-2016 + world->ptr*10,conf::HEIGHT -mm*world->getAgents(), GLUT_BITMAP_HELVETICA_12, buf2, 0.0f, 0.0f, 0.0f); 1299 | 1300 | RenderString(-2020, -80, GLUT_BITMAP_HELVETICA_12, "Useful Keybindings: 'm' disables drawing, 'p' pauses the sim, 'l' & 'k' switch layer view, and 'z' & 'x' switch agent view. 'f' follows the selected bot.", 0.0f, 0.0f, 0.0f); 1301 | RenderString(-2020, -20, GLUT_BITMAP_HELVETICA_12, "Try clicking on a bot. Use 'w,a,s,d' to control it. '/' heals it, 'delete' kills it. 'spacebar' triggers a special input.", 0.0f, 0.0f, 0.0f); 1302 | } 1303 | 1304 | void GLView::drawStatic() 1305 | { 1306 | /*start setup*/ 1307 | glMatrixMode(GL_PROJECTION); 1308 | // save previous matrix which contains the 1309 | //settings for the perspective projection 1310 | glPushMatrix(); 1311 | glLoadIdentity(); 1312 | 1313 | // set a 2D orthographic projection 1314 | gluOrtho2D(0, glutGet(GLUT_WINDOW_WIDTH), 0, glutGet(GLUT_WINDOW_HEIGHT)); 1315 | // invert the y axis, down is positive 1316 | glScalef(1, -1, 1); 1317 | // move the origin from the bottom left corner 1318 | // to the upper left corner 1319 | glTranslatef(0, -glutGet(GLUT_WINDOW_HEIGHT), 0); 1320 | glMatrixMode(GL_MODELVIEW); 1321 | glPushMatrix(); 1322 | glLoadIdentity(); 1323 | /*end setup*/ 1324 | 1325 | //begin things that we actually want to draw staticly 1326 | if(live_paused) RenderString(10, 20, GLUT_BITMAP_HELVETICA_12, "Paused", 0.5f, 0.5f, 0.5f); 1327 | if(live_follow!=0) { 1328 | if(world->getSelectedAgent()>=0) RenderString(10, 40, GLUT_BITMAP_HELVETICA_12, "Following", 0.5f, 0.5f, 0.5f); 1329 | else RenderString(10, 40, GLUT_BITMAP_HELVETICA_12, "No Follow Target", 1.0f, 0.5f, 0.5f); 1330 | } 1331 | if(world->isClosed()) RenderString(10, 60, GLUT_BITMAP_HELVETICA_12, "Closed World", 0.5f, 0.5f, 0.5f); 1332 | if(world->isDebug()) { 1333 | sprintf(buf, "75%% Plant: %i", world->getFood()); 1334 | RenderString(5, 80, GLUT_BITMAP_HELVETICA_12, buf, 0.5f, 0.5f, 1.0f); 1335 | sprintf(buf, "50%% Fruit: %i", world->getFruit()); 1336 | RenderString(5, 100, GLUT_BITMAP_HELVETICA_12, buf, 0.5f, 0.5f, 1.0f); 1337 | sprintf(buf, "50%% Meat: %i", world->getMeat()); 1338 | RenderString(5, 120, GLUT_BITMAP_HELVETICA_12, buf, 0.5f, 0.5f, 1.0f); 1339 | sprintf(buf, "50%% Hazard: %i", world->getHazards()); 1340 | RenderString(5, 140, GLUT_BITMAP_HELVETICA_12, buf, 0.5f, 0.5f, 1.0f); 1341 | sprintf(buf, "modcounter: %i", world->modcounter); 1342 | RenderString(5, 160, GLUT_BITMAP_HELVETICA_12, buf, 0.5f, 0.5f, 1.0f); 1343 | sprintf(buf, "GL modcounter: %i", modcounter); 1344 | RenderString(5, 180, GLUT_BITMAP_HELVETICA_12, buf, 0.5f, 0.5f, 1.0f); 1345 | } 1346 | 1347 | //center axis markers 1348 | glBegin(GL_LINES); 1349 | glColor4f(0,1,0,0.3); //green y-axis 1350 | glVertex3f(glutGet(GLUT_WINDOW_WIDTH)/2,glutGet(GLUT_WINDOW_HEIGHT)/2,0); 1351 | glVertex3f(glutGet(GLUT_WINDOW_WIDTH)/2,glutGet(GLUT_WINDOW_HEIGHT)/2+15,0); 1352 | 1353 | glColor4f(1,0,0,0.3); //red x-axis 1354 | glVertex3f(glutGet(GLUT_WINDOW_WIDTH)/2,glutGet(GLUT_WINDOW_HEIGHT)/2,0); 1355 | glVertex3f(glutGet(GLUT_WINDOW_WIDTH)/2+15,glutGet(GLUT_WINDOW_HEIGHT)/2,0); 1356 | glEnd(); 1357 | 1358 | //selected agent overlay 1359 | if(world->getSelectedAgent()>=0){ 1360 | //get agent 1361 | Agent selected= world->agents[world->getSelectedAgent()]; 1362 | //slightly transparent background 1363 | glBegin(GL_QUADS); 1364 | glColor4f(0,0.4,0.5,0.6); 1365 | glVertex3f(glutGet(GLUT_WINDOW_WIDTH)-10,10,0); 1366 | glVertex3f(glutGet(GLUT_WINDOW_WIDTH)-10,150,0); 1367 | glVertex3f(glutGet(GLUT_WINDOW_WIDTH)-400,150,0); 1368 | glVertex3f(glutGet(GLUT_WINDOW_WIDTH)-400,10,0); 1369 | glEnd(); 1370 | 1371 | //draw Ghost Agent 1372 | drawAgent(selected, glutGet(GLUT_WINDOW_WIDTH)-350, 80, true); 1373 | 1374 | //write text and values 1375 | //Agent ID 1376 | sprintf(buf, "ID: %d", selected.id); 1377 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-380, 1378 | 25, GLUT_BITMAP_HELVETICA_12, 1379 | buf, 0.8f, 1.0f, 1.0f); 1380 | 1381 | //Health 1382 | sprintf(buf, "Health: %.2f/2", selected.health); 1383 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-300, 1384 | 25, GLUT_BITMAP_HELVETICA_12, 1385 | buf, 0.8f, 1.0f, 1.0f); 1386 | 1387 | //Repcounter 1388 | sprintf(buf, "Child: %.2f/%.0f", selected.repcounter, conf::REPRATE); 1389 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-200, 1390 | 25, GLUT_BITMAP_HELVETICA_12, 1391 | buf, 0.8f, 1.0f, 1.0f); 1392 | 1393 | //Stomach 1394 | sprintf(buf, "H%.1f F%.1f C%.1f", selected.stomach[Stomach::PLANT], selected.stomach[Stomach::FRUIT], 1395 | selected.stomach[Stomach::MEAT]); 1396 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-100, 1397 | 25, GLUT_BITMAP_HELVETICA_12, 1398 | buf, 0.8f, 1.0f, 1.0f); 1399 | 1400 | if(selected.isHerbivore()) sprintf(buf, "\"Herbivore\""); 1401 | else if(selected.isFrugivore()) sprintf(buf, "\"Frugivore\""); 1402 | else if(selected.isCarnivore()) sprintf(buf, "\"Carnivore\""); 1403 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-100, 1404 | 40, GLUT_BITMAP_HELVETICA_12, 1405 | buf, 0.8f, 1.0f, 1.0f); 1406 | 1407 | //age 1408 | sprintf(buf, "Age: %d", selected.age); 1409 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-300, 1410 | 40, GLUT_BITMAP_HELVETICA_12, 1411 | buf, 0.8f, 1.0f, 1.0f); 1412 | 1413 | //Generation 1414 | sprintf(buf, "Gen: %d", selected.gencount); 1415 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-200, 1416 | 40, GLUT_BITMAP_HELVETICA_12, 1417 | buf, 0.8f, 1.0f, 1.0f); 1418 | 1419 | //Temperature Preference 1420 | if(selected.temperature_preference<0.3) sprintf(buf, "Heat-loving(%.3f)", selected.temperature_preference); 1421 | else if (selected.temperature_preference>0.7) sprintf(buf, "Cold-loving(%.3f)", selected.temperature_preference); 1422 | else sprintf(buf, "Temperate(%.3f)", selected.temperature_preference); 1423 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-300, 1424 | 55, GLUT_BITMAP_HELVETICA_12, 1425 | buf, 0.8f, 1.0f, 1.0f); 1426 | 1427 | //Lung-type 1428 | if(selected.lungs<0.3) sprintf(buf, "Aquatic(%.3f)", selected.lungs); 1429 | else if (selected.lungs>0.7) sprintf(buf, "Terrestrial(%.3f)", selected.lungs); 1430 | else sprintf(buf, "Amphibious(%.3f)", selected.lungs); 1431 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-200, 1432 | 55, GLUT_BITMAP_HELVETICA_12, 1433 | buf, 0.8f, 1.0f, 1.0f); 1434 | 1435 | //Radius 1436 | sprintf(buf, "Radius: %.2f", selected.radius); 1437 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-100, 1438 | 55, GLUT_BITMAP_HELVETICA_12, 1439 | buf, 0.8f, 1.0f, 1.0f); 1440 | 1441 | 1442 | //Mutrates 1443 | sprintf(buf, "Mutrate1: %.3f", selected.MUTRATE1); 1444 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-300, 1445 | 70, GLUT_BITMAP_HELVETICA_12, 1446 | buf, 0.8f, 1.0f, 1.0f); 1447 | 1448 | sprintf(buf, "Mutrate2: %.3f", selected.MUTRATE2); 1449 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-200, 1450 | 70, GLUT_BITMAP_HELVETICA_12, 1451 | buf, 0.8f, 1.0f, 1.0f); 1452 | 1453 | //Metabolism 1454 | sprintf(buf, "Metab: %.2f", selected.metabolism); 1455 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-100, 1456 | 70, GLUT_BITMAP_HELVETICA_12, 1457 | buf, 0.8f, 1.0f, 1.0f); 1458 | 1459 | //Hybrid 1460 | if(selected.hybrid) sprintf(buf, "Hybrid"); 1461 | else sprintf(buf, "Budded"); 1462 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-300, 1463 | 85, GLUT_BITMAP_HELVETICA_12, 1464 | buf, 0.8f, 1.0f, 1.0f); 1465 | 1466 | //Giving 1467 | if(selected.out[Output::GIVE]>0.5) sprintf(buf, "Generous"); 1468 | else sprintf(buf, "Selfish"); 1469 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-200, 1470 | 85, GLUT_BITMAP_HELVETICA_12, 1471 | buf, 0.8f, 1.0f, 1.0f); 1472 | 1473 | //Spike 1474 | if(selected.spikeLength*world->SPIKELENGTH>=selected.radius){ 1475 | float mw= fabs(selected.w1)>fabs(selected.w2) ? fabs(selected.w1) : fabs(selected.w2); 1476 | float val= world->SPIKEMULT*selected.spikeLength*mw; 1477 | sprintf(buf, "Spikey(DMG%.2f)", val); 1478 | } else sprintf(buf, "Not Spikey"); 1479 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-100, 1480 | 85, GLUT_BITMAP_HELVETICA_12, 1481 | buf, 0.8f, 1.0f, 1.0f); 1482 | 1483 | //Stats: Children 1484 | sprintf(buf, "Children: %d", selected.children); 1485 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-300, 1486 | 100, GLUT_BITMAP_HELVETICA_12, 1487 | buf, 0.8f, 1.0f, 1.0f); 1488 | 1489 | //Stats: Stimulated 1490 | if(selected.out[Output::STIMULANT]>0.5) sprintf(buf, "Stim?"); 1491 | else sprintf(buf, "No Stim?"); 1492 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-200, 1493 | 100, GLUT_BITMAP_HELVETICA_12, 1494 | buf, 0.8f, 1.0f, 1.0f); 1495 | 1496 | //Stats: Killed 1497 | sprintf(buf, "Killed: %d", selected.killed); 1498 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-100, 1499 | 100, GLUT_BITMAP_HELVETICA_12, 1500 | buf, 0.8f, 1.0f, 1.0f); 1501 | 1502 | //Trait: Num Babies 1503 | sprintf(buf, "Num Babies: %d", selected.numbabies); 1504 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-300, 1505 | 115, GLUT_BITMAP_HELVETICA_12, 1506 | buf, 0.8f, 1.0f, 1.0f); 1507 | 1508 | //Output: Sexual projection 1509 | if(selected.sexproject) sprintf(buf, "Sexting"); 1510 | else sprintf(buf, "Not Sexting"); 1511 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-200, 1512 | 115, GLUT_BITMAP_HELVETICA_12, 1513 | buf, 0.8f, 1.0f, 1.0f); 1514 | 1515 | //Species ID (Genome) 1516 | sprintf(buf, "Genome: %d", selected.species); 1517 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-100, 1518 | 115, GLUT_BITMAP_HELVETICA_12, 1519 | buf, 0.8f, 1.0f, 1.0f); 1520 | 1521 | //Jumping status 1522 | if(selected.jump<=0) sprintf(buf, "Grounded"); 1523 | else sprintf(buf, "Airborne!"); 1524 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-300, 1525 | 130, GLUT_BITMAP_HELVETICA_12, 1526 | buf, 0.8f, 1.0f, 1.0f); 1527 | 1528 | //Grab status 1529 | if(selected.grabbing>0.5){ 1530 | if(selected.grabID==-1) sprintf(buf, "Seeking"); 1531 | else sprintf(buf, "Hold: %d", selected.grabID); 1532 | } else sprintf(buf, "Isolated"); 1533 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-200, 1534 | 130, GLUT_BITMAP_HELVETICA_12, 1535 | buf, 0.8f, 1.0f, 1.0f); 1536 | 1537 | //Stats: Biting 1538 | if(selected.jawPosition!=0) sprintf(buf, "Biting %.2f", selected.jawPosition); 1539 | else sprintf(buf, "Not Biting"); 1540 | RenderString(glutGet(GLUT_WINDOW_WIDTH)-100, 1541 | 130, GLUT_BITMAP_HELVETICA_12, 1542 | buf, 0.8f, 1.0f, 1.0f); 1543 | 1544 | } 1545 | 1546 | /*start clean up*/ 1547 | glPopMatrix(); 1548 | glMatrixMode(GL_PROJECTION); 1549 | // restore previous projection matrix 1550 | glPopMatrix(); 1551 | 1552 | // get back to modelview mode 1553 | glMatrixMode(GL_MODELVIEW); 1554 | /*end clean up*/ 1555 | } 1556 | 1557 | 1558 | void GLView::drawCell(int x, int y, float quantity) 1559 | { 1560 | if (live_layersvis!=0) { //0: white 1561 | glBegin(GL_QUADS); 1562 | if (live_layersvis==Layer::PLANTS+1) { //plant food: green w/ navy blue background 1563 | glColor4f(0.0,quantity,0.1,1); 1564 | } else if (live_layersvis==Layer::MEATS+1) { //meat food: red/burgundy w/ navy blue bg 1565 | glColor4f(quantity,0.0,0.1,1); 1566 | } else if (live_layersvis==Layer::HAZARDS+1) { //hazards: purple/magenta w/ navy blue bg 1567 | glColor4f(quantity,0.0,quantity*0.9+0.1,1); 1568 | } else if (live_layersvis==Layer::FRUITS+1) { //fruit: yellow w/ navy blue bg 1569 | glColor4f(quantity*0.8,quantity*0.8,0.1,1); 1570 | } else if (live_layersvis==Layer::LAND+1) { //land: green if 1, blue if 0, black otherwise (debug) 1571 | if (quantity==1) glColor4f(0.3,0.7,0.3,1); 1572 | else if (quantity==0) glColor4f(0.3,0.3,0.9,1); 1573 | else glColor4f(0,0,0,1); 1574 | } else if (live_layersvis==Layer::LIGHT+1) { //light: bright white/yellow w/ navy blue bg 1575 | glColor4f(quantity,quantity,quantity*0.7+0.1,1); 1576 | } 1577 | glVertex3f(x*conf::CZ,y*conf::CZ,0); 1578 | glVertex3f(x*conf::CZ+conf::CZ,y*conf::CZ,0); 1579 | glVertex3f(x*conf::CZ+conf::CZ,y*conf::CZ+conf::CZ,0); 1580 | glVertex3f(x*conf::CZ,y*conf::CZ+conf::CZ,0); 1581 | glEnd(); 1582 | } 1583 | } 1584 | 1585 | void GLView::setWorld(World* w) 1586 | { 1587 | world = w; 1588 | } 1589 | -------------------------------------------------------------------------------- /GLView.h: -------------------------------------------------------------------------------- 1 | #ifndef GLVIEW_H 2 | #define GLVIEW_H 3 | 4 | 5 | #include "View.h" 6 | #include "World.h" 7 | #include "ReadWrite.h" 8 | #include "glui.h" 9 | 10 | class GLView; 11 | 12 | extern GLView* GLVIEW; 13 | 14 | void gl_processNormalKeys(unsigned char key, int x, int y); 15 | void gl_processSpecialKeys(int key, int x, int y); 16 | void gl_processReleasedKeys(unsigned char key, int x, int y); 17 | void gl_menu(int key); 18 | void gl_processMouse(int button, int state, int x, int y); 19 | void gl_processMouseActiveMotion(int x, int y); 20 | void gl_processMousePassiveMotion(int x, int y); 21 | void gl_changeSize(int w, int h); 22 | void gl_handleIdle(); 23 | void gl_renderScene(); 24 | void glui_handleRW(int action); 25 | void glui_handleCloses(int action); 26 | 27 | class GLView : public View 28 | { 29 | 30 | public: 31 | GLView(World* w); 32 | virtual ~GLView(); 33 | 34 | virtual void drawAgent(const Agent &a, float x, float y, bool ghost= 0); 35 | virtual void drawCell(int x, int y, float quantity); //draws the background boxes 36 | virtual void drawData(); //draws info in the left side of the sim 37 | virtual void drawStatic(); //draws viewer-static objects 38 | 39 | virtual void trySaveWorld(bool autosave= false); //called by world, starts GLView working on saving the world 40 | // virtual void trySaveAgent(); //starts GLView working on saving selected agent 41 | // virtual void tryLoadAgent(); //loads up an agent from a file 42 | 43 | void setWorld(World* w); 44 | 45 | //GLUT functions 46 | void processNormalKeys(unsigned char key, int x, int y); 47 | void processSpecialKeys(int key, int x, int y); 48 | void processReleasedKeys(unsigned char key, int x, int y); 49 | void processMouse(int button, int state, int x, int y); 50 | void processMouseActiveMotion(int x, int y); 51 | void processMousePassiveMotion(int x, int y); 52 | void menu(int key); 53 | void menuS(int key); 54 | void changeSize(int w, int h); 55 | void handleIdle(); 56 | void renderScene(); 57 | void handleRW(int action); //callback function for glui loading/saving 58 | void handleCloses(int action); //callback function for closing glui's 59 | 60 | void glCreateMenu(); 61 | int m_id; //main right-click context menu 62 | int win1; 63 | void gluiCreateMenu(); 64 | 65 | private: 66 | 67 | World *world; //the WORLD 68 | int live_worldclosed; //live variable support via glui 69 | int live_paused; //are we paused? 70 | int live_fastmode; //are we drawing? 71 | int live_skipdraw; //are we skipping some frames? 72 | int live_agentsvis; //are we drawing agents? If so, what's the scheme? see namespace "Visuals" in settings.h for details 73 | int live_layersvis; //what cell layer is currently active? see namespace "Layers" in settings.h 74 | int live_selection; //what bot catagory are we currently trying to autoselect? see namespace "Select" in settings.h 75 | int live_follow; //are we following the selected agent? 76 | int live_autosave; //are we allowing autosaves? 77 | 78 | int live_debug; //are we debugging? 79 | bool debug; 80 | GLUI * Menu; 81 | GLUI_FileBrowser * Browser; 82 | GLUI * Loader; 83 | GLUI * Saver; 84 | GLUI * Alert; 85 | GLUI_EditText * Filename; 86 | char filename[30]; 87 | 88 | char buf[100]; 89 | char buf2[10]; //text buffers 90 | int modcounter; //tick counter 91 | int lastUpdate; 92 | int frames; 93 | 94 | float scalemult; //the viewer's scale factor (larger values are closer zoom) 95 | float xtranslate, ytranslate; //the viewer's x and y position 96 | int downb[3]; //the three buttons and their states 97 | int mousex, mousey; 98 | bool mousedrag; //was the mouse dragged? used to disable button click activity when click-moving 99 | }; 100 | 101 | #endif // GLVIEW_H 102 | -------------------------------------------------------------------------------- /MLPBrain.cpp: -------------------------------------------------------------------------------- 1 | #include "MLPBrain.h" 2 | using namespace std; 3 | 4 | 5 | MLPBox::MLPBox() 6 | { 7 | 8 | w.resize(CONNS,0); 9 | id.resize(CONNS,0); 10 | type.resize(CONNS,0); 11 | 12 | //constructor 13 | for (int i=0;i& in, vector< float >& out) 67 | { 68 | //do a single tick of the brain 69 | for (int j=0; j<(int)boxes.size(); j++){ 70 | MLPBox* abox= &boxes[j]; 71 | 72 | if (jout= in[j]; 74 | } else { //then do a dynamics tick and set all targets 75 | float acc=abox->bias; 76 | 77 | for (int k=0;kid[k]; 79 | int type = abox->type[k]; 80 | float val= boxes[idx].out; 81 | 82 | if(type==2){ //switch conn 83 | if(val>0.5){ 84 | break; 85 | continue; 86 | } 87 | continue; 88 | } 89 | 90 | if(type==1){ //change sensitive conn 91 | val-= boxes[idx].oldout; 92 | val*=10; 93 | } 94 | 95 | acc+= val*abox->w[k]; 96 | } 97 | 98 | acc*= abox->gw; 99 | 100 | //put through sigmoid 101 | acc= 1.0/(1.0+exp(-acc)); 102 | 103 | abox->target= cap(acc); 104 | } 105 | } 106 | 107 | 108 | for (int j=0; j<(int)boxes.size(); j++){ 109 | MLPBox* abox= &boxes[j]; 110 | 111 | //back up current out for each box 112 | abox->oldout = abox->out; 113 | 114 | //make all boxes go a bit toward target 115 | if (j>=Input::INPUT_SIZE) abox->out+= (abox->target-abox->out)*abox->kp; 116 | } 117 | 118 | //finally set out[] to the last few boxes output 119 | for (int j=0;jout - abox->oldout); 132 | } 133 | return sum/BRAINSIZE; 134 | } 135 | 136 | void MLPBrain::initMutate(float MR, float MR2) 137 | { 138 | //for mutations which may occur at conception 139 | for (int j=0; j<(int)boxes.size(); j++){ 140 | MLPBox* abox= &boxes[j]; 141 | if (randf(0,1)type[rc] = randi(0,2); 145 | // a2.mutations.push_back("synapse type randomized\n"); 146 | abox->seed= 0; 147 | } 148 | 149 | if (randf(0,1)type= boxes[k].type; 154 | abox->id= boxes[k].id; 155 | abox->bias= boxes[k].bias; 156 | abox->kp= boxes[k].kp; 157 | abox->type= boxes[k].type; 158 | abox->w= boxes[k].w; 159 | // a2.mutations.push_back("box coppied\n"); 160 | abox->seed= 0; 161 | } 162 | } 163 | 164 | if (randf(0,1)id[rc]= ri; 169 | // a2.mutations.push_back("connection randomized\n"); 170 | abox->seed= 0; 171 | } 172 | 173 | if (randf(0,1)id[rc1]; 178 | abox->id[rc1]= abox->id[rc2]; 179 | abox->id[rc2]= temp; 180 | // a2.mutations.push_back("inputs swapped\n"); 181 | abox->seed= 0; 182 | } 183 | 184 | // more likely changes here 185 | if (randf(0,1)gw+= randn(0, MR2); 188 | if (abox->gw<0) abox->gw=0; 189 | // a2.mutations.push_back("global weight jiggled\n"); 190 | // abox->seed= 0; 191 | } 192 | 193 | if (randf(0,1)bias+= randn(0, MR2); 196 | // a2.mutations.push_back("bias jiggled\n"); 197 | // abox->seed= 0; 198 | } 199 | 200 | if (randf(0,1)kp+= randn(0, MR2); 203 | if (abox->kp<0.01) abox->kp=0.01; 204 | if (abox->kp>1) abox->kp=1; 205 | // a2.mutations.push_back("kp jiggled\n"); 206 | // abox->seed= 0; 207 | } 208 | 209 | if (randf(0,1)w[rc]+= randn(0, MR2); 213 | // a2.mutations.push_back("weight jiggled\n"); 214 | // abox->seed= 0; 215 | } 216 | } 217 | } 218 | 219 | void MLPBrain::liveMutate(float MR, float MR2, vector& out) 220 | { 221 | //for mutations which may occur while the bot is live 222 | int j= randi(0,BRAINSIZE); 223 | MLPBox* abox= &boxes[j]; 224 | 225 | if (randf(0,1)out)<=0.01) b= rb; 233 | if (b<=-100) break; 234 | } 235 | if (b>=0){ 236 | abox->id[rc]= b; 237 | // a2.mutations.push_back("connection Hebb'ed\n"); 238 | abox->seed= 0; 239 | } 240 | } 241 | 242 | if (randf(0,1)0.5){ 246 | for (int k=0;kid[k]].out; 249 | abox->w[k]+= conf::LEARNRATE*stim*(abox->oldout-(1-val)); 250 | } 251 | } 252 | // a2.mutations.push_back("weight stimulated\n"); 253 | // abox->seed= 0; 254 | } 255 | 256 | if (randf(0,1)bias+= randn(0, MR2); 259 | // a2.mutations.push_back("bias jiggled\n"); 260 | // abox->seed= 0; 261 | } 262 | 263 | if (randf(0,1)kp+= randn(0, MR2); 266 | if (abox->kp<0.01) abox->kp=0.01; 267 | if (abox->kp>1) abox->kp=1; 268 | // a2.mutations.push_back("kp jiggled\n"); 269 | // abox->seed= 0; 270 | } 271 | } 272 | 273 | MLPBrain MLPBrain::crossover(const MLPBrain& other) 274 | { 275 | MLPBrain newbrain(*this); 276 | 277 | #pragma omp parallel for 278 | for (int i=0; i<(int)newbrain.boxes.size(); i++){ 279 | int s1= this->boxes[i].seed; 280 | int s2= other.boxes[i].seed; 281 | //function which offers pobability of which parent to use, based on relative seed counters 282 | float threshold= ((s1-s2)/(1+abs(s1-s2))+1)/2; 283 | 284 | if(randf(0,1)boxes[i].bias; 286 | newbrain.boxes[i].gw= this->boxes[i].gw; 287 | newbrain.boxes[i].kp= this->boxes[i].kp; 288 | newbrain.boxes[i].seed= this->boxes[i].seed + 1; 289 | // this->boxes[i].seed += 1; //reward the copied box 290 | for (int j=0; jboxes[i].id[j]; 292 | newbrain.boxes[i].w[j] = this->boxes[i].w[j]; 293 | newbrain.boxes[i].type[j] = this->boxes[i].type[j]; 294 | } 295 | 296 | } else { 297 | newbrain.boxes[i].bias= other.boxes[i].bias; 298 | newbrain.boxes[i].gw= other.boxes[i].gw; 299 | newbrain.boxes[i].kp= other.boxes[i].kp; 300 | newbrain.boxes[i].seed= other.boxes[i].seed + 1; 301 | // other.boxes[i].seed += 1; 302 | for (int j=0; j 8 | #include 9 | 10 | class MLPBox { 11 | public: 12 | 13 | MLPBox(); 14 | 15 | std::vector w; //weight of each connecting box 16 | std::vector id; //id in boxes[] of the connecting box 17 | std::vector type; //0: regular synapse. 1: change-sensitive synapse. 2: memory trigger synapse 18 | 19 | int seed; //number of successes (reproduction events) this box has experienced whilst unmodified 20 | float kp; //damper 21 | float gw; //global w 22 | float bias; //base number 23 | 24 | //state variables 25 | float target; //target value this node is going toward 26 | float out; //current output 27 | float oldout; //output a tick ago 28 | }; 29 | 30 | /** 31 | * Damped Weighted Recurrent AND/OR Network 32 | */ 33 | class MLPBrain 34 | { 35 | public: 36 | 37 | std::vector boxes; 38 | 39 | MLPBrain(); 40 | MLPBrain(const MLPBrain &other); 41 | virtual MLPBrain& operator=(const MLPBrain& other); 42 | 43 | void tick(std::vector& in, std::vector& out); 44 | float getActivity(); 45 | void initMutate(float MR, float MR2); 46 | void liveMutate(float MR, float MR2, std::vector& out); 47 | MLPBrain crossover( const MLPBrain &other ); 48 | private: 49 | void init(); 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | #### ALERT! ####: My branch of this project has outgrown the parent and is being split off so it can grow on its own! 2 | 3 | Please redirect your attention to https://github.com/GhengopelALPHA/Evagents 4 | 5 | ############################################################################################################################# 6 | 7 | 8 | This is a Windows version of Scriptbots, originally by Andrej Karpathy, continued by Julian Hershey 9 | 10 | Project Home: https://sites.google.com/site/scriptbotsevo/home 11 | 12 | To compile scriptbots you will need: 13 | * CMake >= 2.8 (http://www.cmake.org/cmake/resources/software.html) 14 | * OpenGL, GLUT (http://www.opengl.org/resources/libraries/glut/) 15 | 16 | For windows: 17 | Extracting the .zip file with the version number inside the download will give the executable and its parts. Tested on a 18 | Windows XP, Windows 7, and Windows 10 machines. 19 | If you wish to edit the source code, you will need to run CMake first on the source code. If you use VC++, there are several 20 | other steps you might need to take, including setting several flags and ignoring certain libraries. I can't tell what steps 21 | you should take because honestly, I don't know what they are (I only do this as a hobby, my skills are limited) 22 | Once running, the program will generate two folders, "saves" and "saved agents", and a "settings.cfg" file. 23 | 24 | QUESTIONS COMMENTS are best posted at the google group, available on project site 25 | or contact either andrej.karpathy@gmail.com or julian.hershey@gmail.com 26 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | SCRIPTBOTS 2 | Author: Andrej Karpathy 3 | Contributors: Casey Link, Julian Hershey 4 | Licence: BSD 5 | 6 | Project website and attached forum: 7 | https://sites.google.com/site/scriptbotsevo/home 8 | 9 | ------------------------------------------------------ 10 | 11 | BUILDING: 12 | To compile scriptbots you will need: 13 | 14 | CMake >= 2.8 (http://www.cmake.org/cmake/resources/software.html) 15 | OpenGL and GLUT (http://www.opengl.org/resources/libraries/glut/) 16 | * Linux: freeglut (http://freeglut.sourceforge.net/) 17 | It will use OpenMP to speed up everything, in case you have multicore cpu. 18 | 19 | If you are on Ubuntu (or debian) you can install all the dependencies with: 20 | $ apt-get install cmake build-essential libopenmpi-dev libglut32-dev libxi-dev libxmu-dev 21 | 22 | To build ScriptBots on Linux: 23 | $ cd path/to/source 24 | $ mkdir build 25 | $ cd build 26 | $ cmake ../ # this is the equiv of ./configure 27 | $ make 28 | 29 | To execute ScriptBots simply type the following in the build directory: 30 | $ ./scriptbots 31 | 32 | For Windows: 33 | Follow basically the same steps, but after running cmake (with default options) open up the 34 | VS solution (.sln) file it generates and compile the project from VS. 35 | 36 | USAGE: 37 | 38 | Compile and run. Hit 'm' to make it go MUCH FASTER (and not draw). Speed can 39 | also be controlled with + and -. Use mouse to pan and zoom, or the 'w,a,s,d' 40 | and '<,>' keys respectively. Right-click the world for more options. 41 | 42 | 43 | QUESTIONS COMMENTS are best posted at the google group, available on project site 44 | or contact me at andrej.karpathy@gmail.com 45 | 46 | -------------------------------------------------------------------------------- /ReadWrite.cpp: -------------------------------------------------------------------------------- 1 | //Read/Write module. Built by Julian Hershey, 2012. Use as you wish. Beware of human-made errors! 2 | 3 | //The way this works is it includes agent.h, world.h, and glview.h, and is included by glview.cpp. 4 | //I was unable to have this between world.h and glview.h. If you can find a better way to use this, 5 | //please do so and let me know @ julian.hershey@gmail.com 6 | 7 | //Currently, GLView has to create an instance of this class whenever saving or loading is needed (see GLView::menu) 8 | //once that is done, the world and other data must be fed to the functions of ReadWrite in order to fully save all data 9 | //It's not pretty, but it works 10 | 11 | //Data can be saved in any file format, as the data is put into text form. I tried to emulate XML, but I did not 12 | //strictly follow those rules. There must be a space between the equals sign and the data being loaded, or there 13 | //will be failures. I've made use of a mode var to better control when certain objects and data should be expected. 14 | 15 | //For loading agents: I've used and tags to outline individual agents. Upon loading, a fake agent 16 | //is created, all attributes which have data to be retrieved are set, and the tag signals the copy of the 17 | //fake agent's variables into a real agent placed in the world array. 18 | 19 | //IN THE FILES: Order does not matter, as each line is read individually from the others. HOWEVER, cell data MUST 20 | //be contained inside , and agent data MUST be included in its own . If something goes wrong and 21 | //two lines modify the same attribute, the latter one will be used. 22 | 23 | //VERSION CHECKING: As of now, the system seems to deal with missing data quite harmlessly; 24 | //in the case of agent vars missing, random init data values are assigned; in the case of 25 | //world data, nothing can break down because those values are set by the program. Cells may break since it's more 26 | //complex, so beware. Even too much data (eg some old data that is no longer used by the program) isn't a 27 | //big issue; simply remove the already removed variable and the line check for it. 28 | 29 | #include "ReadWrite.h" 30 | 31 | #include "settings.h" 32 | #include "helpers.h" 33 | #include 34 | #include 35 | 36 | using namespace std; 37 | 38 | ReadWrite::ReadWrite() 39 | { 40 | ourfile= "WORLD.SCB"; 41 | } 42 | 43 | void ReadWrite::loadSettings(const char *filename) 44 | { 45 | char line[64], *pos; 46 | char var[16]; 47 | char dataval[16]; 48 | 49 | //if no filename given, use default 50 | if(filename=="" || filename==0){ 51 | filename= "settings.txt"; 52 | printf("No filename given. Loading default settings.txt instead.\n"); 53 | } 54 | 55 | //open the file 56 | FILE* sf = fopen(filename, "r"); 57 | 58 | if(sf){ 59 | printf("file exists! loading"); 60 | while(!feof(sf)){ 61 | fgets(line, sizeof(line), sf); 62 | pos= strtok(line,"\n"); 63 | sscanf(line, "%s%s", var, dataval); 64 | 65 | } 66 | } 67 | } 68 | 69 | 70 | void ReadWrite::saveAgent(Agent *a, FILE *file) 71 | { 72 | //NOTE: this method REQUIRES "file" to be opened and closed outside 73 | fprintf(file, "\n"); //signals the writing of a new agent 74 | // fprintf(file, "id= %i\n", a->id); //id not loaded 75 | fprintf(file, "posx= %f\nposy= %f\n", a->pos.x, a->pos.y); 76 | fprintf(file, "angle= %f\n", a->angle); 77 | fprintf(file, "health= %f\n", a->health); 78 | // fprintf(file, "red= %f\ngre= %f\nblu= %f\n", a->red, a->gre, a->blu); 79 | // fprintf(file, "w1= %f\nw2= %f\n", w1, w2); 80 | // fprintf(file, "boost= %i\n", (int) a->boost); 81 | fprintf(file, "herbivore= %f\n", a->stomach[Stomach::PLANT]); 82 | fprintf(file, "carnivore= %f\n", a->stomach[Stomach::MEAT]); 83 | fprintf(file, "frugivore= %f\n", a->stomach[Stomach::FRUIT]); 84 | fprintf(file, "species= %i\n", a->species); 85 | fprintf(file, "radius= %f\n", a->radius); 86 | fprintf(file, "spike= %f\n", a->spikeLength); 87 | fprintf(file, "jump= %f\n", a->jump); //version 6 addition 88 | fprintf(file, "dfood= %f\n", a->dfood); 89 | fprintf(file, "age= %i\n", a->age); 90 | fprintf(file, "gen= %i\n", a->gencount); 91 | fprintf(file, "hybrid= %i\n", (int) a->hybrid); 92 | fprintf(file, "cl1= %f\ncl2= %f\n", a->clockf1, a->clockf2); 93 | fprintf(file, "smellmod= %f\n", a->smell_mod); 94 | fprintf(file, "hearmod= %f\n", a->hear_mod); 95 | fprintf(file, "bloodmod= %f\n", a->blood_mod); 96 | fprintf(file, "eyesensemod= %f\n", a->eye_see_agent_mod); 97 | // fprintf(file, "eyecellmod= %f\n", a->eye_see_cell_mod); 98 | for(int q=0;q\n"); 100 | fprintf(file, "eye#= %i\n", q); 101 | fprintf(file, "eyedir= %f\n", a->eyedir[q]); 102 | fprintf(file, "eyefov= %f\n", a->eyefov[q]); 103 | fprintf(file, "\n"); 104 | } 105 | for(int q=0;q\n"); 107 | fprintf(file, "ear#= %i\n", q); 108 | fprintf(file, "eardir= %f\n", a->eardir[q]); 109 | fprintf(file, "hearlow= %f\n", a->hearlow[q]); 110 | fprintf(file, "hearhigh= %f\n", a->hearhigh[q]); 111 | fprintf(file, "\n"); 112 | } 113 | fprintf(file, "numbabies= %i\n", a->numbabies); 114 | fprintf(file, "metabolism= %f\n", a->metabolism); 115 | fprintf(file, "repcounter= %f\n", a->repcounter); 116 | fprintf(file, "temppref= %f\n", a->temperature_preference); 117 | fprintf(file, "lungs= %f\n", a->lungs); 118 | // fprintf(file, "indicator= %f\n", a->indicator); 119 | // fprintf(file, "ir= %f\nig= %f\nib= %f\n", a->ir, a->ig, a->ib); 120 | // fprintf(file, "give= %f\n", a->give); 121 | fprintf(file, "mutrate1= %f\nmutrate2= %f\n", a->MUTRATE1, a->MUTRATE2); 122 | fprintf(file, "freshkill= %i\n", a->freshkill); 123 | fprintf(file, "\n"); //signals the writing of the brain (more for organization than proper loading) 124 | 125 | for(int b=0;b\n"); //signals the writing of a specific numbered box 127 | fprintf(file, "box#= %i\n", b); 128 | fprintf(file, "kp= %f\n", a->brain.boxes[b].kp); 129 | fprintf(file, "bias= %f\n", a->brain.boxes[b].bias); 130 | fprintf(file, "seed= %i\n", a->brain.boxes[b].seed); 131 | fprintf(file, "globalw= %f\n", a->brain.boxes[b].gw); 132 | fprintf(file, "target= %f\n", a->brain.boxes[b].target); 133 | fprintf(file, "out= %f\n", a->brain.boxes[b].out); 134 | fprintf(file, "oldout= %f\n", a->brain.boxes[b].oldout); 135 | for(int c=0;c\n"); //signals the writing of a specific connection for a specific box 137 | fprintf(file, "conn#= %i\n", c); 138 | fprintf(file, "type= %i\n", a->brain.boxes[b].type[c]); 139 | fprintf(file, "w= %f\n", a->brain.boxes[b].w[c]); 140 | fprintf(file, "cid= %i\n", a->brain.boxes[b].id[c]); 141 | fprintf(file, "\n"); //end of connection 142 | } 143 | fprintf(file, "\n"); //end of box 144 | } 145 | fprintf(file, "\n"); //end of brain 146 | fprintf(file, "\n"); //end of agent 147 | } 148 | 149 | 150 | void ReadWrite::saveWorld(World *world, float xpos, float ypos, const char *filename) 151 | { 152 | //Some Notes: When this method is called, it's assumed that filename is not blank or null 153 | char address[32]; 154 | printf("Filename %s given. Saving...\n", filename); 155 | 156 | strcpy(address,"saves\\"); 157 | strcat(address,filename); 158 | 159 | //checking for the presence of the file has been relocated to GLView.cpp 160 | 161 | //open save file, write over any previous 162 | FILE* fs = fopen(address, "w"); 163 | 164 | //start with saving world vars and food layer 165 | fprintf(fs,"\n"); 166 | /* fprintf(fs,"inputs= %i\n", Input::INPUT_SIZE); 167 | fprintf(fs,"outputs= %i\n", Output::OUTPUT_SIZE); 168 | fprintf(fs,"brainsize= %i\n", BRAINSIZE); 169 | fprintf(fs,"connections= %i\n", CONNS); 170 | fprintf(fs,"width= %i\n", conf::WIDTH); 171 | fprintf(fs,"height= %i\n", conf::HEIGHT); 172 | fprintf(fs,"cellsize= %i\n", conf::CZ);*/ 173 | fprintf(fs,"epoch= %i\n", world->current_epoch); 174 | fprintf(fs,"mod= %i\n", world->modcounter); 175 | fprintf(fs,"is_closed= %i\n", world->isClosed()); 176 | fprintf(fs,"xpos= %f\n", xpos); 177 | fprintf(fs,"ypos= %f\n", ypos); //GLView xtranslate and ytranslate 178 | for(int cx=0;cxCW;cx++){ //start with the layers 179 | for(int cy=0;cyCH;cy++){ 180 | float food= world->cells[Layer::PLANTS][cx][cy]; 181 | float meat= world->cells[Layer::MEATS][cx][cy]; 182 | float hazard= world->cells[Layer::HAZARDS][cx][cy]; 183 | float fruit= world->cells[Layer::FRUITS][cx][cy]; 184 | int land= world->cells[Layer::LAND][cx][cy]; 185 | fprintf(fs, "\n"); //signals the writting of a cell 186 | fprintf(fs, "cx= %i\n", cx); 187 | fprintf(fs, "cy= %i\n", cy); 188 | if (food>0) fprintf(fs, "food= %f\n", food); //to further save space, we needn't report a value of a layer for the cell if it's zero 189 | if (meat>0) fprintf(fs, "meat= %f\n", meat); 190 | if (hazard>0) fprintf(fs, "hazard= %f\n", hazard); 191 | if (fruit>0) fprintf(fs, "fruit= %f\n", fruit); 192 | if (land>0) fprintf(fs, "land= %i\n", land); 193 | fprintf(fs,"\n"); 194 | } 195 | } 196 | 197 | for(int i=0; i<(int)world->agents.size(); i++){ 198 | // here we save all agents. All simulation-significant data must be stored, from the pos and angle, to the change in food the bot was experiencing 199 | Agent* a= &world->agents[i]; 200 | 201 | saveAgent(a, fs); 202 | } 203 | fprintf(fs,""); 204 | fclose(fs); 205 | 206 | 207 | //now copy over report.txt logs 208 | strcat(address,"_report.txt"); 209 | 210 | char line[1028], *pos; 211 | 212 | //first, check if the last epoch in the saved report matches or is one less than the first one in the current report 213 | FILE* fr = fopen("report.txt", "r"); 214 | FILE* ft = fopen(address, "r"); 215 | bool append= false; 216 | char text[8]; //for checking 217 | int epoch= 0; 218 | int maxepoch= 0; 219 | 220 | if(ft){ 221 | while(!feof(ft)){ 222 | fgets(line, sizeof(line), ft); 223 | pos= strtok(line,"\n"); 224 | sscanf(line, "%s%i%*s", &text, &epoch); 225 | if (strcmp(text, "Epoch:")==0) { 226 | if (epoch>maxepoch) maxepoch= epoch; 227 | } 228 | } 229 | fclose(ft); 230 | 231 | if(world->isDebug()) printf("Old report.txt found, and its last epoch was %i.\n", maxepoch); 232 | 233 | //now compare the max epoch from original with the first entry of the new 234 | if(fr){ 235 | fgets(line, sizeof(line), fr); 236 | pos= strtok(line,"\n"); 237 | sscanf(line, "%s%i%*s", &text, &epoch); 238 | if (strcmp(text, "Epoch:")==0) { 239 | //if it is, we append, because this is (very likely) a continuation of that save 240 | if(world->isDebug())printf("Our report.txt starts at epoch %i. ", epoch); 241 | if (epoch==maxepoch || epoch==maxepoch+1){ 242 | append= true; 243 | printf("Old report.txt exists. Continuing it.\n"); 244 | } else printf("Old report.txt found. Replacing it.\n"); 245 | } 246 | rewind(fr); 247 | } 248 | //otherwise, we overwrite! 249 | } else { 250 | printf("No old report.txt found. Continuing\n"); 251 | } 252 | 253 | ft = append ? fopen(address, "a") : fopen(address, "w"); 254 | if(fr){ 255 | printf("Copying report.txt to save file\n"); //report status 256 | while(!feof(fr)){ 257 | fgets(line, sizeof(line), fr); 258 | fprintf(ft, line); 259 | } 260 | } else { 261 | printf("report.txt didn\'t exist. That\'s... odd...\n"); 262 | } 263 | fclose(fr); fclose(ft); 264 | 265 | printf("World Saved!\n"); 266 | } 267 | 268 | void ReadWrite::loadWorld(World *world, float &xtranslate, float &ytranslate, const char *filename) 269 | { 270 | //Some Notes: When this method is called, it's assumed that filename is not blank or null 271 | char address[32]; 272 | char line[64], *pos; 273 | char var[16]; 274 | char dataval[16]; 275 | int cxl= 0; 276 | int cyl= 0; 277 | int mode= -1;//loading mode: -1= off, 0= world, 1= cell, 2= agent, 3= box, 4= connection, 5= eyes, 6= ears 278 | 279 | Agent xa; //mock agent. gets moved and deleted after loading 280 | bool t1= false, t2= false; 281 | 282 | int eyenum= -1; //counters 283 | int earnum= -1; 284 | int boxnum= -1; 285 | int connnum= -1; 286 | int i; //integer buffer 287 | float f; //float buffer 288 | 289 | strcpy(address,"saves\\"); 290 | strcat(address,filename); 291 | 292 | FILE *fl; 293 | fl= fopen(address, "r"); 294 | if(fl){ 295 | printf("file exists! loading.\n"); 296 | while(!feof(fl)){ 297 | fgets(line, sizeof(line), fl); 298 | pos= strtok(line,"\n"); 299 | sscanf(line, "%s%s", var, dataval); 300 | 301 | if(mode==-1){ //mode @ -1 = off 302 | if(strcmp(var, "")==0){ //strcmp= 0 when the arguements equal 303 | //if we find a tag, enable world loading and reset. simple 304 | mode= 0; 305 | world->reset(); 306 | printf("discovered world.\n"); //report status 307 | }else if(strcmp(var, "")==0 || strcmp(var, "")==0){ 308 | //if we find an tag, jump right to agent loading (for spawning saved agents) 309 | mode= 2; 310 | } 311 | }else if(mode==0){ //mode @ 0 = world 312 | // }else if(strcmp(var, "inputs=")==0){ 313 | //inputs count; NOT CURRENTLY USED 314 | // }else if(strcmp(var, "outputs=")==0){ 315 | //outputs count; NOT CURRENTLY USED 316 | // }else if(strcmp(var, "brainsize=")==0){ 317 | //brainsize count; NOT CURRENTLY USED 318 | // }else if(strcmp(var, "connections=")==0){ 319 | //conns count; NOT CURRENTLY USED 320 | // }else if(strcmp(var, "width=")==0){ 321 | //world width; NOT CURRENTLY USED 322 | // sscanf(dataval, "%i", &i); 323 | // conf::WIDTH= i; 324 | // }else if(strcmp(var, "height=")==0){ 325 | //world height; NOT CURRENTLY USED 326 | // sscanf(dataval, "%i", &i); 327 | // conf::HEIGHT= i; 328 | // }else if(strcmp(var, "cellsize=")==0){ 329 | //CZ; NOT CURRENTLY USED 330 | // sscanf(dataval, "%i", &i); 331 | // conf::CZ= i; 332 | if(strcmp(var, "epoch=")==0){ 333 | //epoch 334 | sscanf(dataval, "%i", &i); 335 | world->current_epoch= i; 336 | }else if(strcmp(var, "mod=")==0){ 337 | //mod count 338 | sscanf(dataval, "%i", &i); 339 | world->modcounter= i; 340 | }else if(strcmp(var, "is_closed=")==0){ 341 | //closed state 342 | sscanf(dataval, "%i", &i); 343 | if (i==1) world->setClosed(true); 344 | else world->setClosed(false); 345 | }else if(strcmp(var, "xpos=")==0){ 346 | //veiw screen location x 347 | sscanf(dataval, "%f", &f); 348 | xtranslate= f; 349 | }else if(strcmp(var, "ypos=")==0){ 350 | //veiw screen location y 351 | sscanf(dataval, "%f", &f); 352 | ytranslate= f; 353 | }else if(strcmp(var, "")==0 || strcmp(var, "")==0){ 354 | //version 5 (9/2012) has changed cell loading to follow the same pattern as that of agents 355 | //cells tag activates cell reading mode 356 | mode= 1; 357 | }else if(strcmp(var, "")==0 || strcmp(var, "")==0){ 358 | //agent tag activates agent reading mode 359 | mode= 2; 360 | if (!t1) printf("loaded cells.\n"); //report status 361 | t1= true; 362 | } 363 | }else if(mode==1){ //mode @ 1 = cell 364 | if(strcmp(var, "")==0 || strcmp(var, "")==0){ 365 | //end_cell tag is checked for first, because of else condition 366 | mode= 0; 367 | }else if(strcmp(var, "cx=")==0){ 368 | sscanf(dataval, "%i", &i); 369 | cxl= i; 370 | }else if(strcmp(var, "cy=")==0){ 371 | sscanf(dataval, "%i", &i); 372 | cyl= i; 373 | }else if(strcmp(var, "food=")==0){ 374 | sscanf(dataval, "%f", &f); 375 | world->cells[Layer::PLANTS][cxl][cyl]= f; 376 | }else if(strcmp(var, "meat=")==0){ 377 | sscanf(dataval, "%f", &f); 378 | world->cells[Layer::MEATS][cxl][cyl]= f; 379 | }else if(strcmp(var, "hazard=")==0){ 380 | sscanf(dataval, "%f", &f); 381 | world->cells[Layer::HAZARDS][cxl][cyl]= f; 382 | }else if(strcmp(var, "fruit=")==0){ 383 | sscanf(dataval, "%f", &f); 384 | world->cells[Layer::FRUITS][cxl][cyl]= f; 385 | }else if(strcmp(var, "land=")==0){ 386 | sscanf(dataval, "%i", &i); 387 | world->cells[Layer::LAND][cxl][cyl]= i; 388 | } 389 | }else if(mode==2){ //mode @ 2 = agent 390 | if(strcmp(var, "")==0 || strcmp(var, "")==0){ 391 | //end_agent tag is checked for, and when found, copies agent xa 392 | mode= 0; 393 | Agent loadee= xa; 394 | loadee.id= world->idcounter; 395 | world->idcounter++; 396 | world->agents.push_back(loadee); 397 | if(!t2 && randf(0,1)>world->NUMBOTS/world->agents.size()){ 398 | printf("halfway there.\n"); 399 | t2= true; 400 | } 401 | }else if(strcmp(var, "posx=")==0){ 402 | sscanf(dataval, "%f", &f); 403 | xa.pos.x= f; 404 | }else if(strcmp(var, "posy=")==0){ 405 | sscanf(dataval, "%f", &f); 406 | xa.pos.y= f; 407 | }else if(strcmp(var, "angle=")==0){ 408 | sscanf(dataval, "%f", &f); 409 | xa.angle= f; 410 | }else if(strcmp(var, "health=")==0){ 411 | sscanf(dataval, "%f", &f); 412 | xa.health= f; 413 | }else if(strcmp(var, "herbivore=")==0){ 414 | sscanf(dataval, "%f", &f); 415 | xa.stomach[Stomach::PLANT]= f; 416 | }else if(strcmp(var, "carnivore=")==0){ 417 | sscanf(dataval, "%f", &f); 418 | xa.stomach[Stomach::MEAT]= f; 419 | }else if(strcmp(var, "frugivore=")==0){ 420 | sscanf(dataval, "%f", &f); 421 | xa.stomach[Stomach::FRUIT]= f; 422 | }else if(strcmp(var, "species=")==0){ 423 | sscanf(dataval, "%i", &i); 424 | xa.species= i; 425 | }else if(strcmp(var, "radius=")==0){ 426 | sscanf(dataval, "%f", &f); 427 | xa.radius= f; 428 | }else if(strcmp(var, "spike=")==0){ 429 | sscanf(dataval, "%f", &f); 430 | xa.spikeLength= f; 431 | }else if(strcmp(var, "jump=")==0){ 432 | sscanf(dataval, "%f", &f); 433 | xa.jump= f; 434 | }else if(strcmp(var, "dfood=")==0){ 435 | sscanf(dataval, "%f", &f); 436 | xa.dfood= f; 437 | }else if(strcmp(var, "age=")==0){ 438 | sscanf(dataval, "%i", &i); 439 | xa.age= i; 440 | }else if(strcmp(var, "gen=")==0){ 441 | sscanf(dataval, "%i", &i); 442 | xa.gencount= i; 443 | }else if(strcmp(var, "hybrid=")==0){ 444 | sscanf(dataval, "%i", &i); 445 | if(i==1) xa.hybrid= true; 446 | else xa.hybrid= false; 447 | }else if(strcmp(var, "cl1=")==0){ 448 | sscanf(dataval, "%f", &f); 449 | xa.clockf1= f; 450 | }else if(strcmp(var, "cl2=")==0){ 451 | sscanf(dataval, "%f", &f); 452 | xa.clockf2= f; 453 | }else if(strcmp(var, "smellmod=")==0){ 454 | sscanf(dataval, "%f", &f); 455 | xa.smell_mod= f; 456 | }else if(strcmp(var, "hearmod=")==0){ 457 | sscanf(dataval, "%f", &f); 458 | xa.hear_mod= f; 459 | }else if(strcmp(var, "bloodmod=")==0){ 460 | sscanf(dataval, "%f", &f); 461 | xa.blood_mod= f; 462 | }else if(strcmp(var, "eyesensemod=")==0){ 463 | sscanf(dataval, "%f", &f); 464 | xa.eye_see_agent_mod= f; 465 | // }else if(strcmp(var, "eyecellmod=")==0){ 466 | // sscanf(dataval, "%f", &f); 467 | // xa.eye_see_cell_mod= f; 468 | }else if(strcmp(var, "numbabies=")==0){ 469 | sscanf(dataval, "%i", &i); 470 | xa.numbabies= i; 471 | }else if(strcmp(var, "metabolism=")==0){ 472 | sscanf(dataval, "%f", &f); 473 | xa.metabolism= f; 474 | }else if(strcmp(var, "repcounter=")==0){ 475 | sscanf(dataval, "%f", &f); 476 | xa.repcounter= f; 477 | }else if(strcmp(var, "temppref=")==0){ 478 | sscanf(dataval, "%f", &f); 479 | xa.temperature_preference= f; 480 | }else if(strcmp(var, "lungs=")==0){ 481 | sscanf(dataval, "%f", &f); 482 | xa.lungs= f; 483 | }else if(strcmp(var, "mutrate1=")==0){ 484 | sscanf(dataval, "%f", &f); 485 | xa.MUTRATE1= f; 486 | }else if(strcmp(var, "mutrate2=")==0){ 487 | sscanf(dataval, "%f", &f); 488 | xa.MUTRATE2= f; 489 | }else if(strcmp(var, "freshkill=")==0){ 490 | sscanf(dataval, "%i", &i); 491 | xa.freshkill= i; 492 | }else if(strcmp(var, "")==0 || strcmp(var, "")==0){ 493 | mode= 5; 494 | }else if(strcmp(var, "")==0 || strcmp(var, "")==0){ 495 | mode= 3; 496 | }else if(strcmp(var, "")==0 || strcmp(var, "")==0){ 497 | mode= 6; 498 | } 499 | }else if(mode==5){ //mode @ 5 = eye (of agent) 500 | if(strcmp(var, "")==0 || strcmp(var, "")==0){ 501 | mode= 2; 502 | }else if(strcmp(var, "eye#=")==0){ 503 | sscanf(dataval, "%i", &i); 504 | eyenum= i; 505 | }else if(strcmp(var, "eyedir=")==0){ 506 | sscanf(dataval, "%f", &f); 507 | xa.eyedir[eyenum]= f; 508 | }else if(strcmp(var, "eyefov=")==0){ 509 | sscanf(dataval, "%f", &f); 510 | xa.eyefov[eyenum]= f; 511 | } 512 | }else if(mode==6){ //mode @ 6 = ear (of agent) 513 | if(strcmp(var, "")==0 || strcmp(var, "")==0){ 514 | mode= 2; 515 | }else if(strcmp(var, "ear#=")==0){ 516 | sscanf(dataval, "%i", &i); 517 | earnum= i; 518 | }else if(strcmp(var, "eardir=")==0){ 519 | sscanf(dataval, "%f", &f); 520 | xa.eardir[earnum]= f; 521 | }else if(strcmp(var, "hearlow=")==0){ 522 | sscanf(dataval, "%f", &f); 523 | xa.hearlow[earnum]= f; 524 | }else if(strcmp(var, "hearhigh=")==0){ 525 | sscanf(dataval, "%f", &f); 526 | xa.hearhigh[earnum]= f; 527 | } 528 | }else if(mode==3){ //mode @ 3 = brain box (of agent) 529 | if(strcmp(var, "")==0 || strcmp(var, "")==0){ 530 | mode= 2; 531 | }else if(strcmp(var, "box#=")==0){ 532 | sscanf(dataval, "%i", &i); 533 | boxnum= i; 534 | }else if(strcmp(var, "seed=")==0){ 535 | sscanf(dataval, "%i", &i); 536 | xa.brain.boxes[boxnum].seed= i; 537 | }else if(strcmp(var, "kp=")==0){ 538 | sscanf(dataval, "%f", &f); 539 | xa.brain.boxes[boxnum].kp= f; 540 | }else if(strcmp(var, "bias=")==0){ 541 | sscanf(dataval, "%f", &f); 542 | xa.brain.boxes[boxnum].bias= f; 543 | }else if(strcmp(var, "globalw=")==0){ 544 | sscanf(dataval, "%f", &f); 545 | xa.brain.boxes[boxnum].gw= f; 546 | }else if(strcmp(var, "target=")==0){ 547 | sscanf(dataval, "%f", &f); 548 | xa.brain.boxes[boxnum].target= f; 549 | }else if(strcmp(var, "out=")==0){ 550 | sscanf(dataval, "%f", &f); 551 | xa.brain.boxes[boxnum].out= f; 552 | }else if(strcmp(var, "oldout=")==0){ 553 | sscanf(dataval, "%f", &f); 554 | xa.brain.boxes[boxnum].oldout= f; 555 | }else if(strcmp(var, "")==0 || strcmp(var, "")==0){ 556 | mode= 4; 557 | } 558 | }else if(mode==4){ //mode @ 4 = connection (of brain box of agent) 559 | if(strcmp(var, "")==0 || strcmp(var, "")==0){ 560 | mode= 3; 561 | }else if(strcmp(var, "conn#=")==0){ 562 | sscanf(dataval, "%i", &i); 563 | connnum= i; 564 | }else if(strcmp(var, "type=")==0){ 565 | sscanf(dataval, "%i", &i); 566 | xa.brain.boxes[boxnum].type[connnum]= i; 567 | }else if(strcmp(var, "w=")==0){ 568 | sscanf(dataval, "%f", &f); 569 | xa.brain.boxes[boxnum].w[connnum]= f; 570 | }else if(strcmp(var, "cid=")==0){ 571 | sscanf(dataval, "%f", &f); 572 | xa.brain.boxes[boxnum].id[connnum]= f; 573 | } 574 | } 575 | } 576 | printf("loaded agents.\n"); //report status 577 | fclose(fl); 578 | 579 | printf("WORLD LOADED!\n"); 580 | 581 | world->setInputs(); 582 | world->brainsTick(); 583 | 584 | } else { //DOH! the file doesn't exist! 585 | printf("ERROR: Save file specified (%s) doesn't exist!\n", filename); 586 | } 587 | } 588 | -------------------------------------------------------------------------------- /ReadWrite.h: -------------------------------------------------------------------------------- 1 | #ifndef READWRITE_H 2 | #define READWRITE_H 3 | 4 | #include "Agent.h" 5 | #include "World.h" 6 | #include 7 | #include "settings.h" 8 | 9 | class ReadWrite 10 | { 11 | 12 | public: 13 | ReadWrite(); 14 | 15 | void loadSettings(const char *filename); //load text settings file 16 | 17 | void saveAgent(Agent *a, FILE *file); //save a single agent 18 | void loadAgent(const char *filename); 19 | 20 | void saveWorld(World *world, float xpos, float ypos, const char *filename); //save world to text 21 | void loadWorld(World *world, float &xtranslate, float &ytranslate, const char *filename); //load world from text 22 | 23 | const char *ourfile; 24 | const char *lastfile; 25 | }; 26 | 27 | #endif // READWRITE_H -------------------------------------------------------------------------------- /View.cpp: -------------------------------------------------------------------------------- 1 | #include "View.h" 2 | 3 | -------------------------------------------------------------------------------- /View.h: -------------------------------------------------------------------------------- 1 | #ifndef VIEW_H 2 | #define VIEW_H 3 | 4 | #include "Agent.h" 5 | class View 6 | { 7 | public: 8 | virtual void drawAgent(const Agent &a, float x, float y, bool ghost = 0) = 0; 9 | virtual void drawCell(int x, int y, float quantity) = 0; 10 | virtual void drawData() = 0; 11 | virtual void drawStatic() = 0; 12 | 13 | virtual void trySaveWorld(bool autosave = false) = 0; 14 | // virtual void trySaveAgent() = 0; 15 | // virtual void tryLoadAgent() = 0; 16 | }; 17 | 18 | #endif // VIEW_H 19 | -------------------------------------------------------------------------------- /World.h: -------------------------------------------------------------------------------- 1 | #ifndef WORLD_H 2 | #define WORLD_H 3 | 4 | #include "View.h" 5 | #include "Agent.h" 6 | #include "settings.h" 7 | //#include "ReadWrite.h" 8 | #include 9 | class World 10 | { 11 | public: 12 | World(); 13 | ~World(); 14 | 15 | void update(); 16 | void reset(); 17 | void spawn(); 18 | void readConfig(); 19 | void writeConfig(); 20 | 21 | void draw(View* view, int layer); 22 | 23 | bool isClosed() const; 24 | void setClosed(bool close); 25 | 26 | //debug stuff 27 | bool isDebug() const; 28 | void setDebug(bool state); 29 | std::vector linesA; 30 | std::vector linesB; 31 | 32 | //following and selected agent stuff 33 | void positionOfInterest(int type, float &xi, float &yi); 34 | 35 | int getSelection() const; 36 | 37 | int pinput1; 38 | float pleft; 39 | float pright; 40 | bool pcontrol; 41 | void setControl(bool state); 42 | 43 | void setSelection(int type); 44 | void setSelectedAgent(int id = -1); 45 | int getSelectedAgent() const; 46 | void selectedHeal(); 47 | void selectedKill(); 48 | void selectedBabys(); 49 | void getFollowLocation(float &xi, float &yi); 50 | 51 | bool isAutoselecting() const; 52 | void setAutoselect(bool state); 53 | 54 | int epoch() const; 55 | 56 | //mouse interaction 57 | bool processMouse(int button, int state, int x, int y, float scale); 58 | 59 | void addAgents(int num, int set_stomach=-1, float nx=-1, float ny=-1, bool set_lungs=true); 60 | 61 | //graph stuff 62 | int numHerbivore[conf::RECORD_SIZE]; 63 | int numCarnivore[conf::RECORD_SIZE]; 64 | int numFrugivore[conf::RECORD_SIZE]; 65 | int numHybrid[conf::RECORD_SIZE]; 66 | int numTotal[conf::RECORD_SIZE]; 67 | int ptr; 68 | 69 | //counters 70 | int modcounter; 71 | int current_epoch; 72 | int idcounter; 73 | 74 | //the agents! 75 | std::vector agents; 76 | 77 | void setInputs(); 78 | void brainsTick(); //takes in[] to out[] for every agent 79 | void processOutputs(); 80 | 81 | void healthTick(); 82 | 83 | std::vector deaths; //record of all the causes of death this epoch 84 | 85 | //helper functions to give us counts of agents and cells 86 | int getHerbivores() const; 87 | int getCarnivores() const; 88 | int getFrugivores() const; 89 | int getLungLand() const; 90 | int getLungWater() const; 91 | int getAgents() const; 92 | int getHybrids() const; 93 | int getSpiked() const; 94 | int getFood() const; 95 | int getFruit() const; 96 | int getMeat() const; 97 | int getHazards() const; 98 | 99 | //cells; replaces food layer, can be expanded (4 layers currently) 100 | //[LAYER] represents current layer, see settings.h for ordering 101 | int CW; 102 | int CH; 103 | float cells[Layer::LAYERS][conf::WIDTH/conf::CZ][conf::HEIGHT/conf::CZ]; //[LAYER][CELL_X][CELL_Y] 104 | 105 | //reloadable "constants" 106 | int MINFOOD; 107 | float INITFOODDENSITY; 108 | int INITFOOD; 109 | float INITFRUITDENSITY; 110 | int INITFRUIT; 111 | 112 | int NUMBOTS; 113 | int ENOUGHBOTS; 114 | int TOOMANYBOTS; 115 | 116 | int REPORTS_PER_EPOCH; 117 | int FRAMES_PER_EPOCH; 118 | int FRAMES_PER_DAY; 119 | 120 | int CONTINENTS; 121 | float OCEANPERCENT; 122 | float GRAVITYACCEL; 123 | float REACTPOWER; 124 | float SPIKEMULT; 125 | float BOTSPEED; 126 | float BOOSTSIZEMULT; 127 | float SOUNDPITCHRANGE; 128 | float FOODTRANSFER; 129 | // float MEANRADIUS; 130 | float SPIKESPEED; 131 | int FRESHKILLTIME; 132 | int TENDERAGE; 133 | float MINMOMHEALTH; 134 | // float REPRATE; 135 | // float LEARNRATE; 136 | float MAXDEVIATION; 137 | int MAXAGE; 138 | 139 | float DIST; 140 | float SPIKELENGTH; 141 | float TOOCLOSE; 142 | float FOOD_SHARING_DISTANCE; 143 | float SEXTING_DISTANCE; 144 | float GRABBING_DISTANCE; 145 | 146 | float HEALTHLOSS_WHEELS; 147 | float HEALTHLOSS_BOOSTMULT; 148 | float HEALTHLOSS_BADTEMP; 149 | float HEALTHLOSS_AGING; 150 | float HEALTHLOSS_BRAINUSE; 151 | float HEALTHLOSS_BUMP; 152 | float HEALTHLOSS_SPIKE_EXT; 153 | float HEALTHLOSS_BADAIR; 154 | float HEALTHLOSS_NOOXYGEN; 155 | float HEALTHLOSS_ASSEX; 156 | float HEALTHLOSS_JAWSNAP; 157 | 158 | float FOODINTAKE; 159 | float FOODDECAY; 160 | float FOODGROWTH; 161 | float FOODWASTE; 162 | int FOODADDFREQ; 163 | float FOODSPREAD; 164 | int FOODRANGE; 165 | 166 | float FRUITINTAKE; 167 | float FRUITDECAY; 168 | float FRUITWASTE; 169 | int FRUITADDFREQ; 170 | float FRUITREQUIRE; 171 | 172 | float MEATINTAKE; 173 | float MEATDECAY; 174 | float MEATWASTE; 175 | float MEATVALUE; 176 | 177 | int HAZARDFREQ; 178 | float HAZARDDECAY; 179 | float HAZARDDEPOSIT; 180 | float HAZARDDAMAGE; 181 | 182 | private: 183 | void writeReport(); 184 | 185 | void reproduce(int ai, int bi); 186 | 187 | void cellsRandomFill(int layer, float amount, int number); 188 | void cellsLandMasses(); 189 | 190 | bool CLOSED; //if environment is closed, then no random bots or food are added per time interval 191 | bool DEBUG; //if debugging, collect additional data, print more feedback, and draw extra info 192 | bool AUTOSELECT; //if autoselecting, the agent which we are newly following gets selected 193 | int SELECTION; //id of selected agent 194 | }; 195 | 196 | #endif // WORLD_H 197 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #define HAVE_OPENMP 2 | #define LOCAL_GLUT32 3 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | #cmakedefine HAVE_OPENMP 2 | #cmakedefine LOCAL_GLUT32 3 | -------------------------------------------------------------------------------- /glui32.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GhengopelALPHA/scriptbots/b7e1a05584297880c970cd8cccdef78a6fc1a475/glui32.lib -------------------------------------------------------------------------------- /glui32d.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GhengopelALPHA/scriptbots/b7e1a05584297880c970cd8cccdef78a6fc1a475/glui32d.lib -------------------------------------------------------------------------------- /glut.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GhengopelALPHA/scriptbots/b7e1a05584297880c970cd8cccdef78a6fc1a475/glut.dll -------------------------------------------------------------------------------- /glut.h: -------------------------------------------------------------------------------- 1 | #ifndef __glut_h__ 2 | #define __glut_h__ 3 | 4 | /* Copyright (c) Mark J. Kilgard, 1994, 1995, 1996, 1998. */ 5 | 6 | /* This program is freely distributable without licensing fees and is 7 | provided without guarantee or warrantee expressed or implied. This 8 | program is -not- in the public domain. */ 9 | 10 | #if defined(_WIN32) 11 | 12 | /* GLUT 3.7 now tries to avoid including 13 | to avoid name space pollution, but Win32's 14 | needs APIENTRY and WINGDIAPI defined properly. */ 15 | # if 0 16 | # define WIN32_LEAN_AND_MEAN 17 | # include 18 | # else 19 | /* XXX This is from Win32's */ 20 | # ifndef APIENTRY 21 | # define GLUT_APIENTRY_DEFINED 22 | # if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) 23 | # define APIENTRY __stdcall 24 | # else 25 | # define APIENTRY 26 | # endif 27 | # endif 28 | /* XXX This is from Win32's */ 29 | # ifndef CALLBACK 30 | # if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) 31 | # define CALLBACK __stdcall 32 | # else 33 | # define CALLBACK 34 | # endif 35 | # endif 36 | /* XXX This is from Win32's and */ 37 | # ifndef WINGDIAPI 38 | # define GLUT_WINGDIAPI_DEFINED 39 | # define WINGDIAPI __declspec(dllimport) 40 | # endif 41 | /* XXX This is from Win32's */ 42 | # ifndef _WCHAR_T_DEFINED 43 | typedef unsigned short wchar_t; 44 | # define _WCHAR_T_DEFINED 45 | # endif 46 | # endif 47 | 48 | #pragma comment (lib, "winmm.lib") /* link with Windows MultiMedia lib */ 49 | #pragma comment (lib, "opengl32.lib") /* link with Microsoft OpenGL lib */ 50 | #pragma comment (lib, "glu32.lib") /* link with OpenGL Utility lib */ 51 | #pragma comment (lib, "glut32.lib") /* link with Win32 GLUT lib */ 52 | 53 | #pragma warning (disable:4244) /* Disable bogus conversion warnings. */ 54 | #pragma warning (disable:4305) /* VC++ 5.0 version of above warning. */ 55 | 56 | #endif 57 | 58 | #include 59 | #include 60 | 61 | /* define APIENTRY and CALLBACK to null string if we aren't on Win32 */ 62 | #if !defined(_WIN32) 63 | #define APIENTRY 64 | #define GLUT_APIENTRY_DEFINED 65 | #define CALLBACK 66 | #endif 67 | 68 | #ifdef __cplusplus 69 | extern "C" { 70 | #endif 71 | 72 | /** 73 | GLUT API revision history: 74 | 75 | GLUT_API_VERSION is updated to reflect incompatible GLUT 76 | API changes (interface changes, semantic changes, deletions, 77 | or additions). 78 | 79 | GLUT_API_VERSION=1 First public release of GLUT. 11/29/94 80 | 81 | GLUT_API_VERSION=2 Added support for OpenGL/GLX multisampling, 82 | extension. Supports new input devices like tablet, dial and button 83 | box, and Spaceball. Easy to query OpenGL extensions. 84 | 85 | GLUT_API_VERSION=3 glutMenuStatus added. 86 | 87 | GLUT_API_VERSION=4 glutInitDisplayString, glutWarpPointer, 88 | glutBitmapLength, glutStrokeLength, glutWindowStatusFunc, dynamic 89 | video resize subAPI, glutPostWindowRedisplay, glutKeyboardUpFunc, 90 | glutSpecialUpFunc, glutIgnoreKeyRepeat, glutSetKeyRepeat, 91 | glutJoystickFunc, glutForceJoystickFunc (NOT FINALIZED!). 92 | **/ 93 | #ifndef GLUT_API_VERSION /* allow this to be overriden */ 94 | #define GLUT_API_VERSION 3 95 | #endif 96 | 97 | /** 98 | GLUT implementation revision history: 99 | 100 | GLUT_XLIB_IMPLEMENTATION is updated to reflect both GLUT 101 | API revisions and implementation revisions (ie, bug fixes). 102 | 103 | GLUT_XLIB_IMPLEMENTATION=1 mjk's first public release of 104 | GLUT Xlib-based implementation. 11/29/94 105 | 106 | GLUT_XLIB_IMPLEMENTATION=2 mjk's second public release of 107 | GLUT Xlib-based implementation providing GLUT version 2 108 | interfaces. 109 | 110 | GLUT_XLIB_IMPLEMENTATION=3 mjk's GLUT 2.2 images. 4/17/95 111 | 112 | GLUT_XLIB_IMPLEMENTATION=4 mjk's GLUT 2.3 images. 6/?/95 113 | 114 | GLUT_XLIB_IMPLEMENTATION=5 mjk's GLUT 3.0 images. 10/?/95 115 | 116 | GLUT_XLIB_IMPLEMENTATION=7 mjk's GLUT 3.1+ with glutWarpPoitner. 7/24/96 117 | 118 | GLUT_XLIB_IMPLEMENTATION=8 mjk's GLUT 3.1+ with glutWarpPoitner 119 | and video resize. 1/3/97 120 | 121 | GLUT_XLIB_IMPLEMENTATION=9 mjk's GLUT 3.4 release with early GLUT 4 routines. 122 | 123 | GLUT_XLIB_IMPLEMENTATION=11 Mesa 2.5's GLUT 3.6 release. 124 | 125 | GLUT_XLIB_IMPLEMENTATION=12 mjk's GLUT 3.6 release with early GLUT 4 routines + signal handling. 126 | 127 | GLUT_XLIB_IMPLEMENTATION=13 mjk's GLUT 3.7 release with GameGLUT support. 128 | **/ 129 | #ifndef GLUT_XLIB_IMPLEMENTATION /* Allow this to be overriden. */ 130 | #define GLUT_XLIB_IMPLEMENTATION 13 131 | #endif 132 | 133 | /* Display mode bit masks. */ 134 | #define GLUT_RGB 0 135 | #define GLUT_RGBA GLUT_RGB 136 | #define GLUT_INDEX 1 137 | #define GLUT_SINGLE 0 138 | #define GLUT_DOUBLE 2 139 | #define GLUT_ACCUM 4 140 | #define GLUT_ALPHA 8 141 | #define GLUT_DEPTH 16 142 | #define GLUT_STENCIL 32 143 | #if (GLUT_API_VERSION >= 2) 144 | #define GLUT_MULTISAMPLE 128 145 | #define GLUT_STEREO 256 146 | #endif 147 | #if (GLUT_API_VERSION >= 3) 148 | #define GLUT_LUMINANCE 512 149 | #endif 150 | 151 | /* Mouse buttons. */ 152 | #define GLUT_LEFT_BUTTON 0 153 | #define GLUT_MIDDLE_BUTTON 1 154 | #define GLUT_RIGHT_BUTTON 2 155 | 156 | /* Mouse button state. */ 157 | #define GLUT_DOWN 0 158 | #define GLUT_UP 1 159 | 160 | #if (GLUT_API_VERSION >= 2) 161 | /* function keys */ 162 | #define GLUT_KEY_F1 1 163 | #define GLUT_KEY_F2 2 164 | #define GLUT_KEY_F3 3 165 | #define GLUT_KEY_F4 4 166 | #define GLUT_KEY_F5 5 167 | #define GLUT_KEY_F6 6 168 | #define GLUT_KEY_F7 7 169 | #define GLUT_KEY_F8 8 170 | #define GLUT_KEY_F9 9 171 | #define GLUT_KEY_F10 10 172 | #define GLUT_KEY_F11 11 173 | #define GLUT_KEY_F12 12 174 | /* directional keys */ 175 | #define GLUT_KEY_LEFT 100 176 | #define GLUT_KEY_UP 101 177 | #define GLUT_KEY_RIGHT 102 178 | #define GLUT_KEY_DOWN 103 179 | #define GLUT_KEY_PAGE_UP 104 180 | #define GLUT_KEY_PAGE_DOWN 105 181 | #define GLUT_KEY_HOME 106 182 | #define GLUT_KEY_END 107 183 | #define GLUT_KEY_INSERT 108 184 | #endif 185 | 186 | /* Entry/exit state. */ 187 | #define GLUT_LEFT 0 188 | #define GLUT_ENTERED 1 189 | 190 | /* Menu usage state. */ 191 | #define GLUT_MENU_NOT_IN_USE 0 192 | #define GLUT_MENU_IN_USE 1 193 | 194 | /* Visibility state. */ 195 | #define GLUT_NOT_VISIBLE 0 196 | #define GLUT_VISIBLE 1 197 | 198 | /* Window status state. */ 199 | #define GLUT_HIDDEN 0 200 | #define GLUT_FULLY_RETAINED 1 201 | #define GLUT_PARTIALLY_RETAINED 2 202 | #define GLUT_FULLY_COVERED 3 203 | 204 | /* Color index component selection values. */ 205 | #define GLUT_RED 0 206 | #define GLUT_GREEN 1 207 | #define GLUT_BLUE 2 208 | 209 | /* Layers for use. */ 210 | #define GLUT_NORMAL 0 211 | #define GLUT_OVERLAY 1 212 | 213 | #if defined(_WIN32) 214 | /* Stroke font constants (use these in GLUT program). */ 215 | #define GLUT_STROKE_ROMAN ((void*)0) 216 | #define GLUT_STROKE_MONO_ROMAN ((void*)1) 217 | 218 | /* Bitmap font constants (use these in GLUT program). */ 219 | #define GLUT_BITMAP_9_BY_15 ((void*)2) 220 | #define GLUT_BITMAP_8_BY_13 ((void*)3) 221 | #define GLUT_BITMAP_TIMES_ROMAN_10 ((void*)4) 222 | #define GLUT_BITMAP_TIMES_ROMAN_24 ((void*)5) 223 | #if (GLUT_API_VERSION >= 3) 224 | #define GLUT_BITMAP_HELVETICA_10 ((void*)6) 225 | #define GLUT_BITMAP_HELVETICA_12 ((void*)7) 226 | #define GLUT_BITMAP_HELVETICA_18 ((void*)8) 227 | #endif 228 | #else 229 | /* Stroke font opaque addresses (use constants instead in source code). */ 230 | extern void *glutStrokeRoman; 231 | extern void *glutStrokeMonoRoman; 232 | 233 | /* Stroke font constants (use these in GLUT program). */ 234 | #define GLUT_STROKE_ROMAN (&glutStrokeRoman) 235 | #define GLUT_STROKE_MONO_ROMAN (&glutStrokeMonoRoman) 236 | 237 | /* Bitmap font opaque addresses (use constants instead in source code). */ 238 | extern void *glutBitmap9By15; 239 | extern void *glutBitmap8By13; 240 | extern void *glutBitmapTimesRoman10; 241 | extern void *glutBitmapTimesRoman24; 242 | extern void *glutBitmapHelvetica10; 243 | extern void *glutBitmapHelvetica12; 244 | extern void *glutBitmapHelvetica18; 245 | 246 | /* Bitmap font constants (use these in GLUT program). */ 247 | #define GLUT_BITMAP_9_BY_15 (&glutBitmap9By15) 248 | #define GLUT_BITMAP_8_BY_13 (&glutBitmap8By13) 249 | #define GLUT_BITMAP_TIMES_ROMAN_10 (&glutBitmapTimesRoman10) 250 | #define GLUT_BITMAP_TIMES_ROMAN_24 (&glutBitmapTimesRoman24) 251 | #if (GLUT_API_VERSION >= 3) 252 | #define GLUT_BITMAP_HELVETICA_10 (&glutBitmapHelvetica10) 253 | #define GLUT_BITMAP_HELVETICA_12 (&glutBitmapHelvetica12) 254 | #define GLUT_BITMAP_HELVETICA_18 (&glutBitmapHelvetica18) 255 | #endif 256 | #endif 257 | 258 | /* glutGet parameters. */ 259 | #define GLUT_WINDOW_X 100 260 | #define GLUT_WINDOW_Y 101 261 | #define GLUT_WINDOW_WIDTH 102 262 | #define GLUT_WINDOW_HEIGHT 103 263 | #define GLUT_WINDOW_BUFFER_SIZE 104 264 | #define GLUT_WINDOW_STENCIL_SIZE 105 265 | #define GLUT_WINDOW_DEPTH_SIZE 106 266 | #define GLUT_WINDOW_RED_SIZE 107 267 | #define GLUT_WINDOW_GREEN_SIZE 108 268 | #define GLUT_WINDOW_BLUE_SIZE 109 269 | #define GLUT_WINDOW_ALPHA_SIZE 110 270 | #define GLUT_WINDOW_ACCUM_RED_SIZE 111 271 | #define GLUT_WINDOW_ACCUM_GREEN_SIZE 112 272 | #define GLUT_WINDOW_ACCUM_BLUE_SIZE 113 273 | #define GLUT_WINDOW_ACCUM_ALPHA_SIZE 114 274 | #define GLUT_WINDOW_DOUBLEBUFFER 115 275 | #define GLUT_WINDOW_RGBA 116 276 | #define GLUT_WINDOW_PARENT 117 277 | #define GLUT_WINDOW_NUM_CHILDREN 118 278 | #define GLUT_WINDOW_COLORMAP_SIZE 119 279 | #if (GLUT_API_VERSION >= 2) 280 | #define GLUT_WINDOW_NUM_SAMPLES 120 281 | #define GLUT_WINDOW_STEREO 121 282 | #endif 283 | #if (GLUT_API_VERSION >= 3) 284 | #define GLUT_WINDOW_CURSOR 122 285 | #endif 286 | #define GLUT_SCREEN_WIDTH 200 287 | #define GLUT_SCREEN_HEIGHT 201 288 | #define GLUT_SCREEN_WIDTH_MM 202 289 | #define GLUT_SCREEN_HEIGHT_MM 203 290 | #define GLUT_MENU_NUM_ITEMS 300 291 | #define GLUT_DISPLAY_MODE_POSSIBLE 400 292 | #define GLUT_INIT_WINDOW_X 500 293 | #define GLUT_INIT_WINDOW_Y 501 294 | #define GLUT_INIT_WINDOW_WIDTH 502 295 | #define GLUT_INIT_WINDOW_HEIGHT 503 296 | #define GLUT_INIT_DISPLAY_MODE 504 297 | #if (GLUT_API_VERSION >= 2) 298 | #define GLUT_ELAPSED_TIME 700 299 | #endif 300 | #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) 301 | #define GLUT_WINDOW_FORMAT_ID 123 302 | #endif 303 | 304 | #if (GLUT_API_VERSION >= 2) 305 | /* glutDeviceGet parameters. */ 306 | #define GLUT_HAS_KEYBOARD 600 307 | #define GLUT_HAS_MOUSE 601 308 | #define GLUT_HAS_SPACEBALL 602 309 | #define GLUT_HAS_DIAL_AND_BUTTON_BOX 603 310 | #define GLUT_HAS_TABLET 604 311 | #define GLUT_NUM_MOUSE_BUTTONS 605 312 | #define GLUT_NUM_SPACEBALL_BUTTONS 606 313 | #define GLUT_NUM_BUTTON_BOX_BUTTONS 607 314 | #define GLUT_NUM_DIALS 608 315 | #define GLUT_NUM_TABLET_BUTTONS 609 316 | #endif 317 | #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) 318 | #define GLUT_DEVICE_IGNORE_KEY_REPEAT 610 319 | #define GLUT_DEVICE_KEY_REPEAT 611 320 | #define GLUT_HAS_JOYSTICK 612 321 | #define GLUT_OWNS_JOYSTICK 613 322 | #define GLUT_JOYSTICK_BUTTONS 614 323 | #define GLUT_JOYSTICK_AXES 615 324 | #define GLUT_JOYSTICK_POLL_RATE 616 325 | #endif 326 | 327 | #if (GLUT_API_VERSION >= 3) 328 | /* glutLayerGet parameters. */ 329 | #define GLUT_OVERLAY_POSSIBLE 800 330 | #define GLUT_LAYER_IN_USE 801 331 | #define GLUT_HAS_OVERLAY 802 332 | #define GLUT_TRANSPARENT_INDEX 803 333 | #define GLUT_NORMAL_DAMAGED 804 334 | #define GLUT_OVERLAY_DAMAGED 805 335 | 336 | #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) 337 | /* glutVideoResizeGet parameters. */ 338 | #define GLUT_VIDEO_RESIZE_POSSIBLE 900 339 | #define GLUT_VIDEO_RESIZE_IN_USE 901 340 | #define GLUT_VIDEO_RESIZE_X_DELTA 902 341 | #define GLUT_VIDEO_RESIZE_Y_DELTA 903 342 | #define GLUT_VIDEO_RESIZE_WIDTH_DELTA 904 343 | #define GLUT_VIDEO_RESIZE_HEIGHT_DELTA 905 344 | #define GLUT_VIDEO_RESIZE_X 906 345 | #define GLUT_VIDEO_RESIZE_Y 907 346 | #define GLUT_VIDEO_RESIZE_WIDTH 908 347 | #define GLUT_VIDEO_RESIZE_HEIGHT 909 348 | #endif 349 | 350 | /* glutUseLayer parameters. */ 351 | #define GLUT_NORMAL 0 352 | #define GLUT_OVERLAY 1 353 | 354 | /* glutGetModifiers return mask. */ 355 | #define GLUT_ACTIVE_SHIFT 1 356 | #define GLUT_ACTIVE_CTRL 2 357 | #define GLUT_ACTIVE_ALT 4 358 | 359 | /* glutSetCursor parameters. */ 360 | /* Basic arrows. */ 361 | #define GLUT_CURSOR_RIGHT_ARROW 0 362 | #define GLUT_CURSOR_LEFT_ARROW 1 363 | /* Symbolic cursor shapes. */ 364 | #define GLUT_CURSOR_INFO 2 365 | #define GLUT_CURSOR_DESTROY 3 366 | #define GLUT_CURSOR_HELP 4 367 | #define GLUT_CURSOR_CYCLE 5 368 | #define GLUT_CURSOR_SPRAY 6 369 | #define GLUT_CURSOR_WAIT 7 370 | #define GLUT_CURSOR_TEXT 8 371 | #define GLUT_CURSOR_CROSSHAIR 9 372 | /* Directional cursors. */ 373 | #define GLUT_CURSOR_UP_DOWN 10 374 | #define GLUT_CURSOR_LEFT_RIGHT 11 375 | /* Sizing cursors. */ 376 | #define GLUT_CURSOR_TOP_SIDE 12 377 | #define GLUT_CURSOR_BOTTOM_SIDE 13 378 | #define GLUT_CURSOR_LEFT_SIDE 14 379 | #define GLUT_CURSOR_RIGHT_SIDE 15 380 | #define GLUT_CURSOR_TOP_LEFT_CORNER 16 381 | #define GLUT_CURSOR_TOP_RIGHT_CORNER 17 382 | #define GLUT_CURSOR_BOTTOM_RIGHT_CORNER 18 383 | #define GLUT_CURSOR_BOTTOM_LEFT_CORNER 19 384 | /* Inherit from parent window. */ 385 | #define GLUT_CURSOR_INHERIT 100 386 | /* Blank cursor. */ 387 | #define GLUT_CURSOR_NONE 101 388 | /* Fullscreen crosshair (if available). */ 389 | #define GLUT_CURSOR_FULL_CROSSHAIR 102 390 | #endif 391 | 392 | /* GLUT initialization sub-API. */ 393 | extern void APIENTRY glutInit(int *argcp, char **argv); 394 | extern void APIENTRY glutInitDisplayMode(unsigned int mode); 395 | #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) 396 | extern void APIENTRY glutInitDisplayString(const char *string); 397 | #endif 398 | extern void APIENTRY glutInitWindowPosition(int x, int y); 399 | extern void APIENTRY glutInitWindowSize(int width, int height); 400 | extern void APIENTRY glutMainLoop(void); 401 | 402 | /* GLUT window sub-API. */ 403 | extern int APIENTRY glutCreateWindow(const char *title); 404 | extern int APIENTRY glutCreateSubWindow(int win, int x, int y, int width, int height); 405 | extern void APIENTRY glutDestroyWindow(int win); 406 | extern void APIENTRY glutPostRedisplay(void); 407 | #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 11) 408 | extern void APIENTRY glutPostWindowRedisplay(int win); 409 | #endif 410 | extern void APIENTRY glutSwapBuffers(void); 411 | extern int APIENTRY glutGetWindow(void); 412 | extern void APIENTRY glutSetWindow(int win); 413 | extern void APIENTRY glutSetWindowTitle(const char *title); 414 | extern void APIENTRY glutSetIconTitle(const char *title); 415 | extern void APIENTRY glutPositionWindow(int x, int y); 416 | extern void APIENTRY glutReshapeWindow(int width, int height); 417 | extern void APIENTRY glutPopWindow(void); 418 | extern void APIENTRY glutPushWindow(void); 419 | extern void APIENTRY glutIconifyWindow(void); 420 | extern void APIENTRY glutShowWindow(void); 421 | extern void APIENTRY glutHideWindow(void); 422 | #if (GLUT_API_VERSION >= 3) 423 | extern void APIENTRY glutFullScreen(void); 424 | extern void APIENTRY glutSetCursor(int cursor); 425 | #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) 426 | extern void APIENTRY glutWarpPointer(int x, int y); 427 | #endif 428 | 429 | /* GLUT overlay sub-API. */ 430 | extern void APIENTRY glutEstablishOverlay(void); 431 | extern void APIENTRY glutRemoveOverlay(void); 432 | extern void APIENTRY glutUseLayer(GLenum layer); 433 | extern void APIENTRY glutPostOverlayRedisplay(void); 434 | #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 11) 435 | extern void APIENTRY glutPostWindowOverlayRedisplay(int win); 436 | #endif 437 | extern void APIENTRY glutShowOverlay(void); 438 | extern void APIENTRY glutHideOverlay(void); 439 | #endif 440 | 441 | /* GLUT menu sub-API. */ 442 | extern int APIENTRY glutCreateMenu(void (*)(int)); 443 | extern void APIENTRY glutDestroyMenu(int menu); 444 | extern int APIENTRY glutGetMenu(void); 445 | extern void APIENTRY glutSetMenu(int menu); 446 | extern void APIENTRY glutAddMenuEntry(const char *label, int value); 447 | extern void APIENTRY glutAddSubMenu(const char *label, int submenu); 448 | extern void APIENTRY glutChangeToMenuEntry(int item, const char *label, int value); 449 | extern void APIENTRY glutChangeToSubMenu(int item, const char *label, int submenu); 450 | extern void APIENTRY glutRemoveMenuItem(int item); 451 | extern void APIENTRY glutAttachMenu(int button); 452 | extern void APIENTRY glutDetachMenu(int button); 453 | 454 | /* GLUT window callback sub-API. */ 455 | extern void APIENTRY glutDisplayFunc(void (*func)(void)); 456 | extern void APIENTRY glutReshapeFunc(void (*func)(int width, int height)); 457 | extern void APIENTRY glutKeyboardFunc(void (*func)(unsigned char key, int x, int y)); 458 | extern void APIENTRY glutMouseFunc(void (*func)(int button, int state, int x, int y)); 459 | extern void APIENTRY glutMotionFunc(void (*func)(int x, int y)); 460 | extern void APIENTRY glutPassiveMotionFunc(void (*func)(int x, int y)); 461 | extern void APIENTRY glutEntryFunc(void (*func)(int state)); 462 | extern void APIENTRY glutVisibilityFunc(void (*func)(int state)); 463 | extern void APIENTRY glutIdleFunc(void (*func)(void)); 464 | extern void APIENTRY glutTimerFunc(unsigned int millis, void (*func)(int value), int value); 465 | extern void APIENTRY glutMenuStateFunc(void (*func)(int state)); 466 | #if (GLUT_API_VERSION >= 2) 467 | extern void APIENTRY glutSpecialFunc(void (*func)(int key, int x, int y)); 468 | extern void APIENTRY glutSpaceballMotionFunc(void (*func)(int x, int y, int z)); 469 | extern void APIENTRY glutSpaceballRotateFunc(void (*func)(int x, int y, int z)); 470 | extern void APIENTRY glutSpaceballButtonFunc(void (*func)(int button, int state)); 471 | extern void APIENTRY glutButtonBoxFunc(void (*func)(int button, int state)); 472 | extern void APIENTRY glutDialsFunc(void (*func)(int dial, int value)); 473 | extern void APIENTRY glutTabletMotionFunc(void (*func)(int x, int y)); 474 | extern void APIENTRY glutTabletButtonFunc(void (*func)(int button, int state, int x, int y)); 475 | #if (GLUT_API_VERSION >= 3) 476 | extern void APIENTRY glutMenuStatusFunc(void (*func)(int status, int x, int y)); 477 | extern void APIENTRY glutOverlayDisplayFunc(void (*func)(void)); 478 | #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) 479 | extern void APIENTRY glutWindowStatusFunc(void (*func)(int state)); 480 | #endif 481 | #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) 482 | extern void APIENTRY glutKeyboardUpFunc(void (*func)(unsigned char key, int x, int y)); 483 | extern void APIENTRY glutSpecialUpFunc(void (*func)(int key, int x, int y)); 484 | extern void APIENTRY glutJoystickFunc(void (*func)(unsigned int buttonMask, int x, int y, int z), int pollInterval); 485 | #endif 486 | #endif 487 | #endif 488 | 489 | /* GLUT color index sub-API. */ 490 | extern void APIENTRY glutSetColor(int, GLfloat red, GLfloat green, GLfloat blue); 491 | extern GLfloat APIENTRY glutGetColor(int ndx, int component); 492 | extern void APIENTRY glutCopyColormap(int win); 493 | 494 | /* GLUT state retrieval sub-API. */ 495 | extern int APIENTRY glutGet(GLenum type); 496 | extern int APIENTRY glutDeviceGet(GLenum type); 497 | #if (GLUT_API_VERSION >= 2) 498 | /* GLUT extension support sub-API */ 499 | extern int APIENTRY glutExtensionSupported(const char *name); 500 | #endif 501 | #if (GLUT_API_VERSION >= 3) 502 | extern int APIENTRY glutGetModifiers(void); 503 | extern int APIENTRY glutLayerGet(GLenum type); 504 | #endif 505 | 506 | /* GLUT font sub-API */ 507 | extern void APIENTRY glutBitmapCharacter(void *font, int character); 508 | extern int APIENTRY glutBitmapWidth(void *font, int character); 509 | extern void APIENTRY glutStrokeCharacter(void *font, int character); 510 | extern int APIENTRY glutStrokeWidth(void *font, int character); 511 | #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) 512 | extern int APIENTRY glutBitmapLength(void *font, const unsigned char *string); 513 | extern int APIENTRY glutStrokeLength(void *font, const unsigned char *string); 514 | #endif 515 | 516 | /* GLUT pre-built models sub-API */ 517 | extern void APIENTRY glutWireSphere(GLdouble radius, GLint slices, GLint stacks); 518 | extern void APIENTRY glutSolidSphere(GLdouble radius, GLint slices, GLint stacks); 519 | extern void APIENTRY glutWireCone(GLdouble base, GLdouble height, GLint slices, GLint stacks); 520 | extern void APIENTRY glutSolidCone(GLdouble base, GLdouble height, GLint slices, GLint stacks); 521 | extern void APIENTRY glutWireCube(GLdouble size); 522 | extern void APIENTRY glutSolidCube(GLdouble size); 523 | extern void APIENTRY glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings); 524 | extern void APIENTRY glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings); 525 | extern void APIENTRY glutWireDodecahedron(void); 526 | extern void APIENTRY glutSolidDodecahedron(void); 527 | extern void APIENTRY glutWireTeapot(GLdouble size); 528 | extern void APIENTRY glutSolidTeapot(GLdouble size); 529 | extern void APIENTRY glutWireOctahedron(void); 530 | extern void APIENTRY glutSolidOctahedron(void); 531 | extern void APIENTRY glutWireTetrahedron(void); 532 | extern void APIENTRY glutSolidTetrahedron(void); 533 | extern void APIENTRY glutWireIcosahedron(void); 534 | extern void APIENTRY glutSolidIcosahedron(void); 535 | 536 | #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) 537 | /* GLUT video resize sub-API. */ 538 | extern int APIENTRY glutVideoResizeGet(GLenum param); 539 | extern void APIENTRY glutSetupVideoResizing(void); 540 | extern void APIENTRY glutStopVideoResizing(void); 541 | extern void APIENTRY glutVideoResize(int x, int y, int width, int height); 542 | extern void APIENTRY glutVideoPan(int x, int y, int width, int height); 543 | 544 | /* GLUT debugging sub-API. */ 545 | extern void APIENTRY glutReportErrors(void); 546 | #endif 547 | 548 | #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) 549 | /* GLUT device control sub-API. */ 550 | /* glutSetKeyRepeat modes. */ 551 | #define GLUT_KEY_REPEAT_OFF 0 552 | #define GLUT_KEY_REPEAT_ON 1 553 | #define GLUT_KEY_REPEAT_DEFAULT 2 554 | 555 | /* Joystick button masks. */ 556 | #define GLUT_JOYSTICK_BUTTON_A 1 557 | #define GLUT_JOYSTICK_BUTTON_B 2 558 | #define GLUT_JOYSTICK_BUTTON_C 4 559 | #define GLUT_JOYSTICK_BUTTON_D 8 560 | 561 | extern void APIENTRY glutIgnoreKeyRepeat(int ignore); 562 | extern void APIENTRY glutSetKeyRepeat(int repeatMode); 563 | extern void APIENTRY glutForceJoystickFunc(void); 564 | 565 | /* GLUT game mode sub-API. */ 566 | /* glutGameModeGet. */ 567 | #define GLUT_GAME_MODE_ACTIVE 0 568 | #define GLUT_GAME_MODE_POSSIBLE 1 569 | #define GLUT_GAME_MODE_WIDTH 2 570 | #define GLUT_GAME_MODE_HEIGHT 3 571 | #define GLUT_GAME_MODE_PIXEL_DEPTH 4 572 | #define GLUT_GAME_MODE_REFRESH_RATE 5 573 | #define GLUT_GAME_MODE_DISPLAY_CHANGED 6 574 | 575 | extern void APIENTRY glutGameModeString(const char *string); 576 | extern int APIENTRY glutEnterGameMode(void); 577 | extern void APIENTRY glutLeaveGameMode(void); 578 | extern int APIENTRY glutGameModeGet(GLenum mode); 579 | #endif 580 | 581 | #ifdef __cplusplus 582 | } 583 | 584 | #endif 585 | 586 | #ifdef GLUT_APIENTRY_DEFINED 587 | # undef GLUT_APIENTRY_DEFINED 588 | # undef APIENTRY 589 | #endif 590 | 591 | #ifdef GLUT_WINGDIAPI_DEFINED 592 | # undef GLUT_WINGDIAPI_DEFINED 593 | # undef WINGDIAPI 594 | #endif 595 | 596 | #endif /* __glut_h__ */ 597 | -------------------------------------------------------------------------------- /glut.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GhengopelALPHA/scriptbots/b7e1a05584297880c970cd8cccdef78a6fc1a475/glut.lib -------------------------------------------------------------------------------- /glut32.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GhengopelALPHA/scriptbots/b7e1a05584297880c970cd8cccdef78a6fc1a475/glut32.dll -------------------------------------------------------------------------------- /glut32.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GhengopelALPHA/scriptbots/b7e1a05584297880c970cd8cccdef78a6fc1a475/glut32.lib -------------------------------------------------------------------------------- /helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef HELPERS_H 2 | #define HELPERS_H 3 | #include 4 | #include 5 | #include "vmath.h" 6 | 7 | //uniform random in [a,b) 8 | inline float randf(float a, float b){return ((b-a)*((float)rand()/RAND_MAX))+a;} 9 | 10 | //uniform random int in [a,b) 11 | inline int randi(int a, int b){return (rand()%(b-a))+a;} 12 | 13 | //normalvariate random N(mu, sigma) 14 | inline double randn(double mu, double sigma) { 15 | static bool deviateAvailable=false; // flag 16 | static float storedDeviate; // deviate from previous calculation 17 | double polar, rsquared, var1, var2; 18 | if (!deviateAvailable) { 19 | do { 20 | var1=2.0*( double(rand())/double(RAND_MAX) ) - 1.0; 21 | var2=2.0*( double(rand())/double(RAND_MAX) ) - 1.0; 22 | rsquared=var1*var1+var2*var2; 23 | } while ( rsquared>=1.0 || rsquared == 0.0); 24 | polar=sqrt(-2.0*log(rsquared)/rsquared); 25 | storedDeviate=var1*polar; 26 | deviateAvailable=true; 27 | return var2*polar*sigma + mu; 28 | } 29 | else { 30 | deviateAvailable=false; 31 | return storedDeviate*sigma + mu; 32 | } 33 | } 34 | 35 | //cap value between 0 and 1 36 | inline float cap(float a){ 37 | if (a<0) return 0; 38 | if (a>1) return 1; 39 | return a; 40 | } 41 | 42 | inline float capm(float a, float low, float hi){ 43 | if (ahi) return hi; 45 | return a; 46 | } 47 | 48 | inline int fround(float a){ 49 | if(a - ((int) (abs(a)))>=0.5) return (int) (a) + 1; 50 | else return (int) (a); 51 | } 52 | 53 | //distance between point and a line connecting two other points 54 | inline float pointline(Vector2f posA, Vector2f posB, Vector2f posC){ 55 | //points A & B are of line; point C is other 56 | float normalLength=(posA-posB).length(); 57 | return fabs((posC.x-posA.x)*(posB.y-posA.y) - (posC.y-posA.y)*(posB.x-posA.x))/normalLength; 58 | } 59 | #endif -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "GLView.h" 2 | #include "World.h" 3 | 4 | #include 5 | 6 | #include "config.h" 7 | 8 | #ifdef LOCAL_GLUT32 9 | #include "glut.h" 10 | #else 11 | #include 12 | #endif 13 | 14 | #include "glui.h" 15 | 16 | #ifdef WIN32 17 | #include 18 | #endif 19 | 20 | #include 21 | 22 | 23 | GLView* GLVIEW = new GLView(0); 24 | int main(int argc, char **argv) { 25 | srand(time(0)); 26 | 27 | //load settings. This will be different... 28 | //import readwrite for this? 29 | // int window; 30 | // GLUI *menu; 31 | 32 | if (conf::WIDTH%conf::CZ!=0 || conf::HEIGHT%conf::CZ!=0) printf("CAREFUL! The cell size variable conf::CZ should divide evenly into both conf::WIDTH and conf::HEIGHT! It doesn't right now!"); 33 | 34 | printf("Controls:\n p= pause\n m= toggle drawing (for faster computation)\n += faster, -= slower\n delete= delete selected agent\n tab= reset world\n"); 35 | printf("Pan around by dragging with left mouse button or the arrow keys, zoom by dragging middle mouse button or the '<' and '>' keys. Right-click on the world for options\n"); 36 | printf( "GLUI version: %3.2f\n", GLUI_Master.get_version() ); 37 | 38 | World* world = new World(); 39 | GLVIEW->setWorld(world); 40 | 41 | //GLUT SETUP 42 | glutInit(&argc, argv); 43 | glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); 44 | glutInitWindowPosition(250,20); 45 | glutInitWindowSize(conf::WWIDTH,conf::WHEIGHT); 46 | GLVIEW->win1= glutCreateWindow("Scriptbots"); 47 | 48 | glEnable(GL_BLEND); 49 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 50 | glShadeModel(GL_FLAT); 51 | glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 52 | 53 | GLUI_Master.set_glutDisplayFunc(gl_renderScene); 54 | GLUI_Master.set_glutIdleFunc(gl_handleIdle); 55 | GLUI_Master.set_glutReshapeFunc(gl_changeSize); 56 | 57 | glutKeyboardFunc(gl_processNormalKeys); 58 | glutSpecialFunc(gl_processSpecialKeys); 59 | glutKeyboardUpFunc(gl_processReleasedKeys); 60 | glutMouseFunc(gl_processMouse); 61 | glutMotionFunc(gl_processMouseActiveMotion); 62 | glutPassiveMotionFunc(gl_processMousePassiveMotion); 63 | 64 | //menu window. 65 | GLVIEW->gluiCreateMenu(); 66 | 67 | //create right click context menu 68 | GLVIEW->glCreateMenu(); 69 | 70 | if (CreateDirectory("saves", NULL)) printf("\"saves\" directory did not exist. Does now!"); 71 | if (CreateDirectory("saved_agents", NULL)) printf("\"saved_agents\" directory did not exist. Does now!"); 72 | 73 | try{ 74 | glutMainLoop(); 75 | } catch( std::bad_alloc &){ 76 | printf("Out of memory!\n"); 77 | } catch( std::bad_exception &){ 78 | printf("Severe error!\n"); 79 | } 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NUMEYES 6 4 | #define NUMEARS 2 5 | #define BRAINSIZE 150 6 | #define CONNS 5 7 | 8 | #ifndef SETTINGS_H 9 | #define SETTINGS_H 10 | 11 | 12 | //defines for layer code. Changing order here changes cycle order and menu-listing order 13 | namespace Layer{ 14 | enum { 15 | //NOTE that GLVeiw's use of these must be incremented by 1 because 0 is used for disable draw 16 | LAND= 0, 17 | PLANTS, 18 | FRUITS, 19 | MEATS, 20 | HAZARDS, 21 | //TEMP, 22 | LIGHT, 23 | 24 | //Don't add beyond this entry! 25 | LAYERS 26 | };}; 27 | 28 | namespace Visual{ 29 | enum { 30 | NONE= 0, 31 | RGB, 32 | STOMACH, 33 | DISCOMFORT, 34 | VOLUME, 35 | SPECIES, 36 | CROSSABLE, 37 | HEALTH, 38 | 39 | //Don't add beyond this entry! 40 | VISUALS 41 | };}; 42 | 43 | //defines for selection code. Changing order here changes cycle order and menu-listing order 44 | namespace Select { 45 | enum { 46 | NONE= 0, 47 | MANUAL, 48 | OLDEST, 49 | BEST_GEN, 50 | HEALTHY, 51 | PRODUCTIVE, 52 | AGGRESSIVE, 53 | SOCIAL, 54 | 55 | //Don't add beyond this entry! 56 | SELECT_TYPES 57 | };}; 58 | 59 | //defines for brain input code. Changing order here changes input-to-brain order and and visualization order 60 | namespace Input { 61 | enum { 62 | // R1 G1 B1 R2 G2 B2 R3 G3 B3 R4 G4 B4 HEALTH CLOCK1 CLOCK2 SOUND HEARING SMELL BLOOD TEMP_DISCOMFORT PLAYER_INPUT1 63 | // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15,16 17,18 19 20 21 22 64 | // FOOD_SMELL MEAT_SMELL HAZARD_SMELL WATER_SMELL 65 | // 23 24 25 26 66 | 67 | RED1= 0, 68 | GRE1, 69 | BLU1, 70 | RED2, 71 | GRE2, 72 | BLU2, 73 | RED3, 74 | GRE3, 75 | BLU3, 76 | RED4, 77 | GRE4, 78 | BLU4, 79 | HEALTH, 80 | RANDOM, 81 | CLOCK1, 82 | CLOCK2, 83 | CLOCK3, 84 | HEARING1, 85 | HEARING2, 86 | BOT_SMELL, 87 | BLOOD, 88 | TEMP, 89 | PLAYER, 90 | FRUIT_SMELL, 91 | MEAT_SMELL, 92 | HAZARD_SMELL, 93 | WATER_SMELL, 94 | 95 | //Don't add beyond this entry! 96 | INPUT_SIZE 97 | };}; 98 | 99 | //defines for brain output code. Changing order here changes brain-to-output order and visualization order 100 | namespace Output { 101 | enum { 102 | //LEFT RIGHT BOOST JUMP R G B VOLUME GIVING SPIKE CHOICE STIMULANT 103 | // 0 1 2 3 4 5 6 7 8 9 10 11 104 | LEFT_WHEEL_F= 0, 105 | RIGHT_WHEEL_F, 106 | LEFT_WHEEL_B, 107 | RIGHT_WHEEL_B, 108 | BOOST, 109 | JUMP, 110 | RED, 111 | GRE, 112 | BLU, 113 | VOLUME, 114 | TONE, 115 | GIVE, 116 | SPIKE, 117 | JAW, 118 | GRAB, 119 | PROJECT, 120 | STIMULANT, 121 | CLOCKF3, 122 | 123 | //don't add beyond this entry! 124 | OUTPUT_SIZE 125 | };}; 126 | 127 | namespace Stomach { 128 | enum { 129 | PLANT= 0, 130 | MEAT, 131 | FRUIT, 132 | 133 | //don't add beyond this entry! 134 | FOOD_TYPES 135 | };}; 136 | 137 | namespace conf { 138 | 139 | //DEFAULTS: All of what follows are defaults, and if settings.cfg exists, are subsituted with that file's values 140 | //SIM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SIM 141 | const int WIDTH = 10000; //width and height of simulation 142 | const int HEIGHT = 8000; 143 | const int WWIDTH = 1100; //initial window width and height 144 | const int WHEIGHT = 700; 145 | 146 | const float SNAP_SPEED = 0.2; //how fast snapping to an object of interest is; 1 is instant, 0.1 is smooth, 0 is pointless 147 | const float ZOOM_SPEED = 0.002; //how fast zoom actions change the magnification 148 | 149 | const int CZ= 50; //cell size in pixels, for food squares. Should divide well into Width, Height 150 | const int MINFOOD= 2000; //(.cfg) 151 | const float INITFOODDENSITY= 0.00012; //(.cfg) 152 | const float INITFRUITDENSITY= 0.00008; //(.cfg) 153 | const int NUMBOTS= 30; //(.cfg) 154 | const int ENOUGHBOTS= 500; //(.cfg) 155 | const int TOOMANYBOTS= 1800; //(.cfg) 156 | 157 | const int REPORTS_PER_EPOCH = 10; //(.cfg) 158 | const int FRAMES_PER_EPOCH = 10000; //(.cfg) 159 | const int FRAMES_PER_DAY= 2500; //(.cfg) 160 | const int RECORD_SIZE = 200; // number of data points stored for the graph. Units is in reports, the frequency of which are defined above 161 | 162 | const int CONTINENTS= 2; //(.cfg) 163 | const float OCEANPERCENT= 0.65; //(.cfg) 164 | const float GRAVITYACCEL= 0.01; //(.cfg) 165 | const float REACTPOWER= 0.13; //(.cfg) 166 | const float SPIKEMULT= 2; //(.cfg) 167 | 168 | //BOTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BOTS 169 | const float BOTSPEED= 0.3; //(.cfg) 170 | const float BOOSTSIZEMULT=2; //(.cfg) 171 | const float SOUNDPITCHRANGE= 0.1; //(.cfg) 172 | const float FOODTRANSFER= 0.01; //(.cfg) 173 | const float MEANRADIUS=10; //average agent radius (only applies to random agents) 174 | const float SPIKESPEED= 0.01; //(.cfg) 175 | const int FRESHKILLTIME= 10; //(.cfg) 176 | const int TENDERAGE= 10; //(.cfg) 177 | const float MINMOMHEALTH=0.15; //(.cfg) 178 | const float MAXMETABOLISM=1.5; //agent metabolism is limited to [0,this] 179 | const float REPRATE=20; //amount of food required to be consumed for an agent to reproduce 180 | const float LEARNRATE= 0.001; // 0.02 (high-gen feedback) //how quickly a conn weight can change from use 181 | const float MAXDEVIATION=10; //(.cfg) 182 | const float METAMUTRATE1= 0.002; //what is the change in MUTRATE1 and 2 on reproduction? lol 183 | const float METAMUTRATE2= 0.0001; 184 | const int MAXAGE=1000; //(.cfg) 185 | 186 | //distances 187 | const float DIST= 400; //(.cfg) 188 | const float SPIKELENGTH=30; //(.cfg) 189 | const float TOOCLOSE=14; //(.cfg) 190 | const float FOOD_SHARING_DISTANCE= 60; //(.cfg) 191 | const float SEXTING_DISTANCE= 60; //(.cfg) 192 | const float GRABBING_DISTANCE= 40; //(.cfg) 193 | 194 | const float HEALTHLOSS_WHEELS = 0.00005; //(.cfg) 195 | const float HEALTHLOSS_BOOSTMULT=4; //(.cfg) 196 | const float HEALTHLOSS_BADTEMP = 0.003; //(.cfg) 197 | const float HEALTHLOSS_AGING = 0.0001; //(.cfg) 198 | const float HEALTHLOSS_BRAINUSE= 0.001; //(.cfg) 199 | const float HEALTHLOSS_BUMP= 0.005; //(.cfg) 200 | const float HEALTHLOSS_SPIKE_EXT= 0; //(.cfg) 201 | const float HEALTHLOSS_BADAIR= 0.01; //(.cfg) 202 | const float HEALTHLOSS_NOOXYGEN= 0.0003; //(.cfg) 203 | const float HEALTHLOSS_ASSEX= 0.325; //(.cfg) 204 | const float HEALTHLOSS_JAWSNAP= 0.6; //(.cfg) 205 | 206 | const float BRAIN_DIRECTINPUT= 0.3; //probability of random brain conns on average which will connect directly to inputs 207 | const float BRAIN_DEADCONNS= 0.3; //probability of random brain conns which are "dead" (that is, weight = 0) 208 | const float BRAIN_CHANGECONNS= 0.15; //probablility of random brain conns which are change sensitive 209 | const float BRAIN_MEMCONN= 0.01; //probablility of random brain conns which are memory type 210 | 211 | //LAYERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LAYERS 212 | const float FOODINTAKE= 0.008; //(.cfg) 213 | const float FOODDECAY = 0.000005; //(.cfg) 214 | const float FOODGROWTH= 0.0000051; //(.cfg) 215 | const float FOODWASTE= 0.0004; //(.cfg) 216 | const float FOODMAX= 0.5; //how much food per cell can there be at max? 217 | const int FOODADDFREQ= 250; //(.cfg) 218 | const float FOODSPREAD= 0.0001; //(.cfg) 219 | const int FOODRANGE= 2; //(.cfg) 220 | //Plant food is the simplest and most plentiful form of nutrition, but it takes a long time to consume enough 221 | 222 | const float FRUITINTAKE = 0.013; //(.cfg) 223 | const float FRUITDECAY = 0.0005; //(.cfg) 224 | const float FRUITWASTE = 0.0005; //(.cfg) 225 | const float FRUITMAX = 0.5; 226 | const int FRUITADDFREQ = 5; //(.cfg) 227 | const float FRUITREQUIRE= 0.0; //(.cfg) 228 | //Fruit is a quick and easy alternative to plants. Also randomly populated, harkening back to ScriptBots origins 229 | 230 | const float MEATINTAKE= 0.08; //(.cfg) 231 | const float MEATDECAY= 0.000001; //(.cfg) 232 | const float MEATWASTE= 0.002; //(.cfg) 233 | const float MEATMAX= 0.5; //how much meat per cell can there be at max? 234 | const float MEATVALUE= 1; //(.cfg) 235 | //Meat currently has these stats: 236 | //0.5 full meat / 0.0015 meat eaten = 333 ticks to consume full meat 237 | //333 ticks * 0.04 meat intake = 13 real intake from 1 full meat cell (for perfect carnivore) 238 | //13 real intake / 30 reprate = 4/9ths of reproduction (very roughly) 239 | //Meat comes from dead bots, and is the fastest form of nutrition, IF bots can learn to find it... 240 | 241 | const int HAZARDFREQ= 20; //(.cfg) 242 | const float HAZARDDECAY= 0.000002; //(.cfg) 243 | const float HAZARDDEPOSIT= 0.0015; //(.cfg) 244 | const float HAZARDDAMAGE= 0.015; //(.cfg) 245 | const float HAZARDMAX= 0.5; //how much hazard per cell can there be at max? more than 9/10 of this qualifies as an instant hazard 246 | } 247 | 248 | #endif 249 | -------------------------------------------------------------------------------- /versionhistory.txt: -------------------------------------------------------------------------------- 1 | 7/15/2016: 2 | Version 1.2-ALPHA 3 | + SETTINGS.CFG! Finally, .exe users can modify some core constants of the sim! Currently limited to world constants. 4 | *Does ~NOT~ include agent, brain, or box constants, like MEANRADIUS, BRAIN_DEADCONNS, or CONNS. 5 | *If missing, will be generated at world creation (launch, reset, or loading), using settings.h values 6 | *Works like ReadWrite and doesn't need every entry to work. Instead scans the .cfg, and if it finds a flag, changes it. 7 | Make your .cfg's as small and efficient as you like! Please note that deleted flags won't be regenerated unless the whole file is missing. 8 | *Every run, all constants are first loaded from settings.h, and then settings.cfg resets ones it has flags for. 9 | *Syntax is similar to saveworlds: eg, "NUMBOTS= 30". Any spaces and content after are ignored. Any text lines that aren't a flag are ignored. 10 | *Only the last value is used for duplicate flags. Most flags are float format, but some are integers. Respect the obvious differences and no 11 | errors should occur 12 | -Doesn't use ReadWrite module. For those who are like me and appreciate a place for these kind of things, this will bother you. I'll work on it 13 | *To other programmers: please use care when making .cfg settings. First a new world variable must be declared. Then initialized with a 14 | settings.h value, which should get printed to the .cfg when writeConfig() is called (order doesn't matter), and finally you must add code 15 | to readConfig() to get any changes pushed to the world variables. IT IS EASY TO FORGET ONE OF THESE STEPS AND THE ERROR CAN GO UNNOTICED 16 | *All future changes to constants in versionhistory.txt will be to the default values. if you keep your old config files when updating to 17 | newer versions, your values will persist, and any new constants added will use defaults. 18 | * For details, search ".cfg" in the project 19 | 20 | = Range of cell smell inputs reduced to DIST/2 21 | = Meat cell decay now inversely proportional to the remaining meat as a RATIO of MEATMAX, rather than the raw value 22 | = FRUITREQUIRE default set to 0; trying to sepparate herbivores and frugivores, prevent them from effecting each other 23 | = Hazard damage decreased: Too high a value seems to prevent other species from starting. 24 | = Meat-eaters only give 25% of meat value, down from 50% 25 | = Changed stim to only activate at values over 0.5 26 | = Right-click menu has new options: 27 | *Reset Config: forces config file to be rewritten with default values 28 | *Spawn Frugivores: added obvious missing function 29 | *Toggle Closed: not sure why I removed it in the first place... 30 | =Load and Save world now use GUI from context menu! 31 | = Selected agent highlighting is now visible at further zooms (gets bigger with scale) 32 | = Prettied up cout text when starting, resetting, and loading worlds 33 | = FIXED: Stim report on selected agent display was instead reporting spikiness 34 | = FIXED: Pressing 'q' to center world while following agents wouldn't stop following agent 35 | = FIXED: Pressing "tab" no longer resets agents, having a physical button for such an action no longer makes sense 36 | 37 | * Graphical glitch with "current population" bar on the graph after the world has been loaded. 38 | 39 | 40 | 41 | 5/25/2016: 42 | + Added a sun. New layer: light. Sinusoid function over time and x axis, recreates day and night. 43 | * Bots in night cannot see and see a base 0.5 input in day. 44 | * New display and settings.h var, FRAMES_PER_DAY, to control the speed. 45 | + New output and input: Clock 3. Works like other clocks, except its frequency is determined by an output, in range [0,1] -> [100,2] 46 | changes to clock 3's frequency are not instant. 47 | + Vocalization broadened: new "tone" output used with volume to produce sounds. Hearing rebuilt to include ranges for each ear 48 | * Tone from other agents are only "heard" fully when they fall within the range defined by "hearlow" and "hearhigh" 49 | * Tones falling just inside of hearing ranges (to a tone difference set by settings.h) will be heard, but at reduced volume 50 | * All sounds heard are merged into one input. Resolution and tone differentiation can come with ear pairs, or later, more ear structures 51 | + Added new Visual: Agent Health. Will display agents with full health as green, half-health as blinking orange, and almost dead 52 | as blinking black and red. Slower blinking means slower health loss/gain 53 | + Added Autosaving. At the end of every epoch, the world is saved in AUTOSAVE.SCB. Disableable while program is running with UI 54 | + Added several DEBUG features: 55 | * Selected agents show DIST circle - the range of most senses, cell smell zone - area within cells are counted for the cell smell 56 | input, food sharing distance, grabbing distance, and spike zone of effect 57 | * All bots display wheel speeds via green bars showing the output speed of each wheel originating at the real position of the wheels 58 | = The brain box display has been moved to be a DEBUG feature only 59 | = Some saving and loading printf's changed to debug only 60 | 61 | - Sound sensor removed. All agents emit a "low-pitched" sound picked up by bots with hearing at a tone of 0.25 62 | - Removed Choice: bot output that effects every box through their last connection has been eliminated. Reason being it's just 63 | so influential on every output that I can't imagine a proper use for it, and every use of it seen so far has been seizuring agents. 64 | 65 | = Increased DIST 66 | = Agent eyes increased from 4 to 6 67 | = Brain mutation chances adjusted. Goal is to get more chance of species improvement by letting inputs and connections get jostled more 68 | = Changed the population size of bots where random spawns stop occuring from 100 to 500 69 | = Bots now see 0.5 light minimum during "day", are blind during "night" and must rely on other senses 70 | = Init mutation rates increased. From studies on the origins of our own life, if an RNA world was the start, mutations were rampant 71 | = Changed stomach multipliers for having high values of two or more food types: max intake available to an agent with two high values is .25 72 | = Jaws aren't rendered if a timeout period has passed and they haven't triggered. Spikes aren't rendered if incapable of harming other 73 | agents 74 | = Visualization of "volume" changed: bots are colored according to volume, sound wave color and count according to tone 75 | * Tone when expressed as color: red is low frequency, green is middle, blue is high 76 | = Visualization of bot inputs and outputs labeled at close zooms: 77 | * Clocks have a black "Q", temp discomfort has orange "H", hearing have white "E"s 78 | * red,gre,blu bot color outputs colored respectively, jump is yellow, tone as above, Wheels have green "!", clock3 has black "Q", 79 | sexual projection has purple "P", volume has white "V", and spike has red "S" 80 | * Eventually all outputs will have other graphical representations, and the input and out vis will be a debug feature 81 | = Optimizations 82 | = Changed agent constructor to simplify in cases of babies, so that time is not wasted trying to make random values that are then replaced 83 | = FIXED Agents being saved would not properly record "freshkill" in integer format 84 | = FIXED center scene 'q' feature not zooming and centering properly on window sizes other than default 85 | = FIXED lag issues when new agents would be created. Add agents, world init and resets, and birth events no longer stall program 86 | =? FIXED very rare issue where, upon processing an agent that happened to be at exactly WIDTH or HEIGHT in x or y, the code would try to get 87 | the cell values of the N+1th cell, which doesn't exist 88 | 89 | Old Saves: 90 | BROKEN! On account of loss of sound sensors and the addition of new inputs and outputs, old saves will not work as intended. 91 | New eyesight and hearing code, and lack of choice, will make all previous agent systems that relied on these features break compleately. 92 | 93 | 94 | 95 | 3/30/2016 b: 96 | Features: 97 | = Fixed typos in death log key in Agents.cpp 98 | = Fixed Release version bugs. This version is now fully released into the wild! 99 | 100 | 101 | 102 | 3/30/2016: 103 | Features: 104 | + Added grabbing: new output, if over 0.5, activates and pulls together a nearby target bot. If pulled too far, the 105 | target can break free. Only one target at the moment 106 | * Should be saved and loaded, but isn't currently. Would require the saving of agent ID's, and that's Pandora's box at the moment, 107 | as no id is ever saved 108 | + Added jaws: new output, when changed rapidly from low to high, activates and "chomps" on agents immediately in front. 109 | NOTE: deathcause is same as spike deaths, "Killed by a Murder" 110 | + Healthloss of a parent through assexual reproduction is related to (parent radius)/(mean radius). A settings.h var exists to 111 | change the impact, currently a bot with a radius of 10 will lose 0.325 health with assexual reproduction 112 | + Bots will suffer damage when populations are large via "Oxygen", simple size()/TOOMANYBOTS factor. Death cause: "LackOf Oxygen" 113 | + New Input: Random. Value with randn applied on every tick 114 | - Bots now will give health to any bot they want, not just lower-health bots 115 | - Brains when being mutated will no longer skip any more mutations if a major mutation occurs. Let natural selection have options 116 | - Removed spike startle. Not really relevant any longer since agents have physical bodies now and can't pass through each other 117 | 118 | = Hazard dropped by bots faster (rate of 0.001->0.0015) 119 | = Meat is much shorter lived but much more fulfilling 120 | = Meat dropped by slow-kill deaths reduced to 25%. Counter added to give grace period for fresh-kill deaths after spikings, 121 | durration set by FRESHKILLTIME 122 | = In effort to bring variety locally, collision reaction force increased. The way I see it, weak collisions allow agents to overlap, 123 | too far and they kill each other. We need to let them bump into each other and mingle more. 124 | = Fixed ZeroHealth bug. Bots would be kept afloat just above 0 health because fruit intake occured after hazard loss, keeping 125 | bots killed by hazard (health forced = 0) alive, barely. 126 | = Fixed bug where newborn bots were not using parent's angles to correctly place them behind parents. Note, this will not apply 127 | to agents driving backwards. Babies will ALWAYS be spawned on the side opposite the parent's spike 128 | = Fixed long-standing bug with agent movement. At top speed, wheels would not drive agents straight, but rather at an oblique angle 129 | 130 | Simulation: 131 | + Added selected agent display reports of jumping and grabbing status 132 | + following is now related to scalemult, so at closer zooms the follow target will be closer to the middle of the window 133 | + Added a key, 'q', that instantly zooms and centers the world so that everything can be seen. 134 | + Added new visualization: Crossable. Will highlight bots that can perform sexual reproduction with selected agent, by making 135 | all perfect relatives light blue, other relatives blue, all cousins purple, and all non-relatives grey 136 | + Newborn babies will show a small grey event 137 | + Report now contains RandomSeed: picks a random bot, and a random brain box, and reports its seed counter. 138 | + Toppled report.txt fprintf function into multiple. Easier to navigate code 139 | 140 | Old Saves: 141 | BROKEN! On account of new features for bots - grabbing and jaws,new input - random, and changed physical constants - REACTPOWER and 142 | FRESHKILLTIME, old saves will not preserve the situation. With regard to freshkill, old saves are not compatable 143 | 144 | 145 | 146 | 12/31/15 147 | Bots: 148 | + New sensors: A cell variation of smell. Counts values of cells nearby and reports the ratio to total cells sensed. 149 | Four "scents" available to bots: Fruit, Meat, Hazard, and Water 150 | + New brain box feature: seed. Counts the number of sucesses (reproduction events) a single box has experienced. Only 151 | effects sexual reproduction, where comparing the seed counts of the same box in the two parents will change the 152 | probability of which parent's box is coppied. Gives massive value to sexual reproduction, as brain boxes which have 153 | suffered a detrimental mutation are much more quickly weeded out 154 | + New output: Sexual Projection. A bot with this output will be more likely to take part in sexual reproduction with others 155 | + Num Babies trait finally introduced. Now, the number of children produced from reproduction events is under the control 156 | of the agents. An inheritable and mutable integer that is never allowed to go below 1 157 | + Agents now keep track of how they died. Strings are stored that describe their death cause, which are collected by the 158 | world and reported both in the report.txt and, if the agent was selected, to the output window. 159 | + New selected bot outputs: Bots will report to the output window when they give birth and how many children they had, 160 | and their cause of death 161 | + Agents with large radii have purpose: larger agents move less in collisions, and take less damage if over-pressured 162 | + Two-way wheels enabled once more: Now agents have four wheel outputs, left backwards and forwards, and right backwards 163 | and forwards. NOTE: IMEDITATELY after enabling these, tribes were spotted once more! DO NOT REMOVE THIS FEATURE!!! 164 | + Newborn bots are born grey, to guarentee vision activation by parents, neighbors 165 | + Newborn bots and their mothers will be given extra health according to mother's -repcounter/reprate. Mothers take MINMOMHEALTH damage 166 | 167 | - Eyes sensing cells feature removed. Final judgement: the effects of eyes being over-saturated are too damaging for 168 | too little of an evolutionary factor. Code still present, but must be re-worked in if desired. May later make a 169 | setting to determine if it's used. 170 | - "selected" tag removed. Selected agent now handled by world. 171 | 172 | = Code for producing random agents improved. Lungs will be adapted for terrain spawned in, temp_pref will reflect 173 | spawned y-axis location, and custom positions are now available (preparation for point-click agent adding functionality). 174 | = Jump code: Output now forced to be a change-sensitive output, making jump a less common, and more challenging solution. 175 | Change requires min age for bot jump capability: only agents older than 0 can jump. (init 0->val change sensitive bug) 176 | = Reproduction re-written: now the mother's health will always be split amongst the mother and children 177 | = Sexual reproduction separated from health sharing. Instead uses new output, Sexual Projection 178 | = Give change: now agents with give can specify the range, according to (output-0.5)*2 of FOOD_SHARE-DISTANCE 179 | = Agent brains changed: Global Weight range decreased, Weight range increased, code for reprodction changed 180 | = Stomach changes: Worst any stomach type can do to other intakes is 50% reduction, instead of 100%. Omnivores should 181 | be more plentiful 182 | = Collision changes: agents that collided and died will now output full meat value 183 | = Reworked metabolism slightly: now effects the max speed bots can travel at, and should never be mutated to zero 184 | 185 | Sim: 186 | + Plant food now grows when hazard exists on same cell, settings.h variable can fine tune the rate 187 | + New stats on bots: killed, hits, and death cause. Records number of kills and number of attacks this bot has commited, 188 | and death cause is collected by the world and stored in report.txt, resets every epoch 189 | + New select options: 190 | Follow most aggressive: targets bot with greatest cumulative of its kills + 1/4 its attacks 191 | Follow most social: targets bot with highest "give" output + 1/4 its sexual projection 192 | + Report updates: 193 | + Added tracking fruit numbers (counts those cells with >50% fruit) 194 | + Added tracking of Terrestrial and Aquatic bot counts and top generations of those 195 | + Added death count 196 | + Added death causes, along with counts of each. Has such stucture that some extra work is needed to sort and graph the 197 | data, but a simple Excel function(s) can do the trick. Has provided VERY valuable data 198 | + Introduced Random Generation: Picks a random agent and reports its gencount. Actually very useful in figuring out 199 | generation paths of different species, also the approximate generations of the dominant species 200 | = Cleaned up report code, including a bug where fruigvores and carnivores top gens were mixed up 201 | + "Closed" state of world now persists with saving and loading 202 | + Pressing the "/" key will now insta-heal selected agent 203 | 204 | = New code optimizations (performance of 300 fps again on an i3 processor) 205 | = Follow & agent selection code altered and updated majorly: 206 | + Agents can be automatically selected via the old "following" types, and a toggle option deterimines if it's followed 207 | + Internal changes: the world now keeps an agent ID value stored (or -1 if no agent selected) 208 | + Adjusted code to take zoom scale into account, minor selection distance limit increase at far zooms 209 | + Changes to manual selection / automatic selection interaction. Any manually selected agent will overide any auto 210 | selection chosen. Likewise, any re-activated autoselection will override the manual selection 211 | = Fixed deletion of first selected agent bug 212 | = Mouse click-and-drag no longer counts as a mouse click. Click actions now only performed at button release 213 | = Fixed bug with agents children counters only counting reproduction events, now reports physical children 214 | = Fixed long standing bug with init fruit decaying b/c it wasn't spawned on plant-filled cells 215 | = Modified terrain generation code for accuracy of settings.h vars (OCEANPERCENT now actually generates that % of water) 216 | = New enums make Layers, Select, Visual, Input, Output, and Stomach code easier to understand and make changes to 217 | = Hazard damage greatly increased, now poses a significant threat to established species (and circle drivers) 218 | = Other food balancing changes. I'm probably starting to repeat old values now... 219 | = Meta-mutation rates adjusted: more likely for chance-of-mutations to change, much less change in strength-of-mutations 220 | = Fixed messy code structure with ReadWrite.cpp 221 | = Cleaned up using new helpers.h capm instead of capCell. capm takes 3 arguments, a, low, and high, and returns value 222 | between low and high if "a" is not between them, "a" otherwise. 223 | 224 | * GLview's modcounter gets stuck after loading. Will investigate 225 | 226 | Graphics: 227 | + New Static display: renders things in a fixed frame with respect to the window. Now includes the following: 228 | + New Selected Agent Overlay: displays stats and values of selected agent, including health, lung type, giving, 229 | # children, mutrates, radius, # kills, stomach type, temp preference, land preference, and MORE 230 | + New debug infos: counts of reported food and hazard cells, current world and GLview modcounters. Room for expansion 231 | + Added visual crosshair indicating the center of the window and directional axises 232 | = Text informers (relating "closed", "Following", and "Paused" statuses) have been moved to static display 233 | + New volume indicators: when "Volume" agent visual mode is active, expanding "pings" indicating the volume (and future 234 | frequency) of the agent's voice are displayed. Are entirely graphical, no extra sim processing time used on fast mode. 235 | 236 | = Transparency functionality added. Agent events, eye lines of sight, outlines, spikes and boost now utilize blur effects 237 | = Altered rendering of bot outlines: now always renders at close zoom, but blurs to the bot visualization color at wide 238 | zoom. Makes visual data from agents more meaningful and easy to see globally. 239 | = Agent spikes, eyes, and ears now blur away when zoomed out 240 | = Fixed window resizing and mouse-world interactions being incorrect. Now fully supports any kind of window resizing! 241 | = Fixed Species display color coding to actually display possibly meaningful colors. Now, almost every randomly generated 242 | species can be seen to be visually distinct, and major deviations between subspecies will be visualized. 243 | = Improved code of drawing agents for more utility. Now supports custom positional rendering, instead of strictly bot x&y. 244 | = Prettied up the agent report display: shows more stats and values. Mostly meaningless now with the Agent Overlay. 245 | = Fixed bug with text printing where a different font specified in the method arguement wasn't used (perhaps code was 246 | intended to be written to handle exceptions where incorrect fonts were passed?) 247 | 248 | Saves: 249 | + IMPORTANT: All saves will be placed in and loaded from a "saves" folder, which if does not exist will be made by the 250 | program. When loading and saving it is NOT required that the folder/directory be specified. Again, NOT required. 251 | + Report.txt will be saved with the world to a new text file in the "saves" folder. If a saved report already exists by 252 | the same name, checking is done to see if it is a continuation of the saved world. If it is, any new report.txt data 253 | generated will be appended. Otherwise, the report file is replaced entirely. 254 | + "numbabies" agent tag, backwards compatable (old saves can be loaded), but uniqueness-breaking (random values upon load) 255 | + "seed" brain box tag, backwards compatable and uniqueness-preserving (constant, non-sim-breaking values upon load) 256 | + "closed" world tag, backwards compatable and uniqueness-breaking (always FALSE from old saves) 257 | 258 | - "selected" tag removed. Old selections will not be preserved from old saves, and will no longer be loaded or saved 259 | - "killed" tag removed. The flag is always set to FALSE before writing, so it's pointless to store 260 | 261 | = Old saves are still compatable, but may not work as intended (numbabies, closed world) 262 | 263 | * NOTE FOR NON-WINDOWS USERS: you are going to have to implement some other form of folder generation and checking than 264 | that which is implimented currently in main.cpp. 265 | 266 | 267 | 12/25/13 changes 268 | + Added menu window via GLUI; gui integration achieved. Many options and live variables migrated there. 269 | Current list of all live variables: 270 | * Fast Mode (disable draw) and speed 271 | * Pausing and close/open world toggling 272 | * Layer drawing mode selection 273 | * Agent drawing mode selection 274 | * Following mode selection 275 | * Debug toggle 276 | All live variables are still togglable via key commands and right-click context menu (some) 277 | Loading, saving, and starting new worlds are available as well, along with input and alert windows 278 | + Terrian generator implemented. Creates land masses and oceans. Mapped and displayed via cell layers. (oceans: 0, 279 | land: 1. May add other value possibilities for heightmaps). Settings.h vars control number of continents and 280 | percent of world which is water. 281 | + Lungs: inheritable, mutable bot constant, determines what environment (land, water, or both) the bot can 282 | survive in. New indicator next to bot visualizes this variable. 283 | + New brain mutation: Input Swap: two inputs for one brain box are switched. Moderate chance. 284 | + Now tracking number of children from each bot 285 | + New Follow type: Most Productive: the bot which has had the most number of children over its lifetime will be followed 286 | * Known bug: this is not working fully yet and only follows oldest agents. Will fix in next update 287 | 288 | = Plant spread now directly related to fruit presence, which now requires 1/4 plant instead of 1/10 289 | = Adjustments to agent's initial species and radius values (wider ranges for both) 290 | = Giving birth no longer takes health for sexual reproduction, and 0.4 for assexual 291 | = Give function of bots now activates only if target bot has less health than self 292 | = Collisions are now softer and take the relative bot's radii into account (smaller bots get pushed more) 293 | = Changes to brain (fewer weights will be -1 or 1 at init, dampening more likely to be seen, a lot less injury 294 | by activity, and increased percent of inputs set to actual sence inputs to 40%) 295 | = Max generation following will no longer select zero generation agents, meaning if there are only zero gen 296 | agents, the focus will not change 297 | = Meat decays again 298 | = Fixes to order of operations in loading world, specifically the extra initial tick and success message 299 | = Tweeks to mutation rates, boost, hazard layer mechanics 300 | = Poison/hazard hurts bots more (several runs were observed with localized specitation after this change!!!) 301 | = Food balancing 302 | = Moved graph and infos to better fit 1366x768 res screens 303 | 304 | 305 | 7/22/13 changes 306 | + Hearing and Sound sensors split, now each bot has NUMEARS of these sensor pairs (called ears), 307 | and each has a variable angle location on each bot. Ears drawn on bots as small tan circles 308 | + Health lost for having lots of actively changing boxes in the brain 309 | + Health lost if physics corrects for less than a TOOCLOSE (settings const) distance 310 | + New brain synapse type: memory; causes box to skip changing if conn value > 0.5, effectively 311 | nulifying any changes to the box's value 312 | + Added constants for modifying simulation interface (zoom and snap speeds) 313 | + Added liveMutate function to brain; allows changes to brains after bot conception 314 | + Added variable bot radius: is inheritable, ranges between 2.5 and 17.5 for random agents (mean= 10, configurable) 315 | + Agents are no longer able to countdown repcounter while health is below mothering health theshold (default 0.65, configurable) 316 | + Count of agents with spikes now reported (no graph as yet) 317 | + Agents now gain repcounter bonus if at full health 318 | + Agents have sepparate "eyesensecellmod" and "eyesensebotsmod" vars for eyes 319 | + Aesthetics: 320 | Added Agent visual toggle; can hide agents, or color them according to stomach type, temperature discomfort, or sound volume 321 | Agents get white event when they are selected. 322 | Changes regarding spike, eye, and ear rendering related to bot radius, to allow for better looking custom radii bots. 323 | other color scheme changes 324 | 325 | - Removed species count reporting (code still present) 326 | - Version number checking for loading/saving discontinued 327 | - Collisions no longer flag agents as spiked. Was creating too many sitting colonies. 328 | 329 | = Temperature layer changed into fruit layer. Fruit will be a new source of food which populates randomly like old food, but is only 330 | available on cells with plant present. Code for consumption by bots not yet implemented. 331 | = Bot's clock inputs fixed; was suddenly snapping to zero at modcounter reset, so current epoch is now 332 | taken into account as well. 333 | = Reduced health loss from reproduction 334 | = Edited jump code to force bots to have a grace period between jumps. Fixed jumping jump landing bug 335 | = Extended spike length now based on settings var 336 | = Meat no longer decays 337 | = Carnivores now get same bonus as herbivores for moving slowly over their food 338 | = Omnivores now should have a harder time eating 339 | = Agent speed factor for food consumption switched from average to max of the speeds of the two wheels 340 | = Metabolism instead only effects rate of repcounter countdown and healthloss. REPRATE setting adjusted appropriately. 341 | = Daughter bots should now spawn behind their mothers more. 342 | = Plant food can only spread from 3/4 or more full cells (was 1/2) 343 | = Agents which run at full speed will not get any food from any source. 344 | = Code opimization 345 | = Balancing: 346 | Food rates. Trying to get balance between not enough bots and explosive colonies. 347 | Mutation chances and magnitudes of brain boxes and agent traits tweaked 348 | 349 | 350 | 11/7/12 changes 351 | + Added Hazard layer: instant hazards which last a random number of ticks before disapearing, slowly increases under live bots and damages them. 352 | + Added Jump: output that sets a counter for "height" that slowly decreases over time. Jumping bots cannot be attacked, cannot change direction 353 | or angle, and cannot interact with cells (plants, meat, or hazards). Automatically locks in boost if active when jump is activated. 354 | Jumping bots do not interact physically with other bots, but can still attack others 355 | + Added saving and loading of hazard layer, and of jump "height" of bots 356 | + Added meat count, hazard count, and hybrid bots, omnivore bots, and max omnivore generation count to report 357 | + Code for blood sensor detecting meat in layer form added, but currently unused 358 | + Added stomach type multiplier for dead bot to meat conversion. Carnivores will give only half of what an otherwise identical herbivore 359 | would give. Prevents self-sufficient carnivores 360 | + Added Debug Mode: reports mouse events, visually displays what the selected agent can see with all eyes. Can be toggled via menu 361 | - Eye FOV are limited to 180 degrees; anything greater doesn't make sense and starts giving bots unfair advantages 362 | - Age counts removed from reports 363 | - Metabolism no longer effects health loss 364 | = Cell saving and loading changed; no longer requires more reading variables, but now takes up to 3x the number of lines from previous versions. 365 | Old saves are incompatable 366 | = Adjusted init health of spawned bots to increase turnover rate and give more of a challenge to species 367 | = Reduced "jumpiness" of "follow healthiest agent" function 368 | = Changed weight adjusting code (again). Hopefully this time the bots will exhibit some learning behavior 369 | = Fixed incorrect save data bug, -1 selected agent id bug, and other tune ups to ReadWrite module 370 | = Fixed species reporting. A species is counted in reporting only when there are 3 or more members 371 | = Fixed food overpopulation of edges bug 372 | = Continued plant, meat, and hazard balancing 373 | * Notable bug: bots turn instantly when jump= 0, making the action look ugly. Needs work 374 | * FPS has been reduced to less than 200 at program init, settings as is, on an intel i3, 2.1GHz Windows machine. This is annoying 375 | 376 | 377 | 6/26/12 changes 378 | + Added player control of agents: use "w,a,s,d" keys to control the selected agent. Is toggleable ("w,a,s,d" keys can activate, 379 | menu option can toggle to either state) 380 | w: increase speed; s: decrease speed; a: increase right, decrease left (turn left); d: increase left, decrease right (turn right) 381 | + Agent color now changes a fraction of the difference between its current color and the respective output; makes for smoother color changes 382 | + Added new output: Stimulus - if greater than 0.5, will allow decay and strengthening of brain box weights 383 | + New cell layers: plants, meat, temp are constructed, agents intereact only with plant and meat layers. More can be easily programed 384 | + Added meat layer. Feeds carnivores, with high yield, exponential decay 385 | + Added temperature layer: calculated at world init, shows where "heat" is 386 | + Closed world setting also disables FOODADDFREQ from adding food; only FOODMIN can add food if triggered 387 | + Added species agent variable, to reduce intermixing of species. All random bots have ids between -10 and 388 | 10, to induce beneficial crossovers. 389 | + Agent selection now toggleable by clicking on the selected agent to deselect it (toggling selection will also disable player control) 390 | + defined LAYERS: will effect the construct of cells array and the layer toggle 391 | + Eyes now can see meat and plant food in the world 392 | + Follow healthiest agent now an option, most useful when no established species exist yet. 393 | + Added smooth tracking of agents when follow is enabled, meaning quick screen snaps are a thing of the past 394 | + Saving/loading additions: save-over existing file check and saving & loading of screen location and selected agent 395 | 396 | - Removed carnivore kill-sharing. Dead agents are now directly converted to the meat layer 397 | - Removed food sensor input 398 | - Removed add agents keystrokes. Adding agents now can only be triggered by right-click menu 399 | - Removed edge-based scroll 400 | 401 | = Loading/saving now completely modularized. 402 | = Changed drawfood toggle to layer integer, allowing different cell layers to be displayed. Can be changed with the 'k' and 'l' keys 403 | = Fixed temperature sensor to correctly involve agents' y-axis, rather than their x-axis, locations 404 | = Modified proximity formulas 405 | = Increased DIST 406 | = Changed interface: must left-click nearer to bots to select them, left-click-drag moves the scene, and resets follow to zero if moved quickly enough 407 | = Changes as required for new layer system to loading and saving code 408 | = Fixed loading agents "inheriting" traits from previously loaded agents bug 409 | = Fixed spacebar input (and direction inputs) bugs 410 | = Fixed negative weights being set to 0 bug 411 | = Nearly half of all boxes have weights that have a decent chance of being at -1 or 1, to better facititate equal value and 412 | difference connections 413 | = Agent age report on selection changed to report its species id 414 | = Some code opimizations 415 | 416 | 5/23/12 changes 417 | + More graph features: total count (black) and hybrid count (blue) plots, erases on world reset & load. 418 | + Fixed the crossover function. Re-introduced sexual reproduction; works off same code for asexual reproduction 419 | + Camera pan keystrokes now arrow keys, instead of "w,a,s,d" keys, which I plan to change into selected bot control 420 | + Food spread (seeding) range now settings.h variable 421 | + Improved and expandable cells array: replaces food layer, boasts a possible 3 additional layers (can be expanded) 422 | cells[LAYER][CELL_X][CELL_Y]; for [LAYER]: 0= plant food (meat, poison, water/land, light, temperature layers also possible with very little coding) 423 | - Removed reprate agent variable. All agents must eat REPRATE amount of food in order to reproduce. 424 | = Brain adjustments. Reactivated box gb - global weights (were disabled in some previous version) 425 | = Metabolism now has primary control over agent's reproduction rate. Also, now effects rate of health loss (higher metabolism -> faster health loss) 426 | = Changes to save-load function: remove reprate val, improved version checking (old versions may not behave as expected) 427 | = Relocation of menu creating; look for glCreateMenu() function in GLView.cpp 428 | = "Toggle closed world" menu option now represents correct open or closed state in-menu 429 | = Rewrote player input code to something much more professional... 430 | = Even more food balancing changes (including allowing any non-zero food cell to seed) 431 | 432 | 4/15/12 changes 433 | + Physics collision correction incorperated 434 | + Added metabolism agent variable, effects rate of food to repcounter, and meat to repcounter. Range: 0 -> 4 435 | + Added basic world save function 436 | + Added basic world load function 437 | + Last OUTPUTSIZE boxes are no longer forced to have connections with zero weights 438 | + Increased chance of change-sensitive conns (5% -> 10%) 439 | + Food spread now has a range of three cells (not yet adjustable via settings.h) 440 | - Removed eye proximity inputs, merged with the colors 441 | = Changes to mutation chances 442 | = Changes to MLP Brain inner workings and variable ranges 443 | = Fixed follow selected agent feature so that death of selected agent does not result in snaping to origin 444 | = Adjusted world reset to better work with loading saved worlds. 445 | = Further adjustment to food constants 446 | 447 | 2/15/12 changes 448 | + added spacebar input to bots, makes interesting yet unlikely useful behaviour changes 449 | + New brain output: Choice. Replaces the weight of the last connection of each box with a value in the range 0-2 based on this output. It is hoped 450 | that this will lead to more complex behaviours than ever before. 451 | + added "follow highest generation" function, follows bot with highest gen count. NOTE: this and "follow oldest" follow the same bot in the most 452 | random batches of agents. 453 | + food spread introduced 454 | + food sharing indicator changed to temperature discomfort indicator: more orange means more health being lost 455 | = Temperature preference now more likely to match the location where a random agent is placed, to help start populations 456 | = experimentation with a recursive weight system, where when a conn's val is above 0.6, its weight is increased. Conversely, when it's below 0.3, its 457 | weight is decreased, by about 0.000001 both ways 458 | = balancing adjustments to plant food 459 | = optimizing of code and agent loops; mostly just experimentation. 460 | 461 | 1/13/12 changes 462 | + added MINFOOD constant; number of food cells with 50% MAXFOOD will never fall below this number. 463 | + added speed (skipdraw) report to window title 464 | + added new type of mutation: box copy. All attributes are copied from one box to another. 465 | + added David Coleman's code for hiding stats when zoomed out and custom epoch report frequency, added Anaal Nathrakh's code for closed state reporting, 466 | = changed/added display of total population on graph by using the cursor-line. Added a numerical display also. Shows possible change in population as well. 467 | = Fixed follow agent and follow oldest so that the screen stays at its location when either is toggled off (no nasty jumping back to previous location) 468 | = Fixed selecting of agents while following. Now you can select the oldest agent while following him, or select others of interest nearby! 469 | = Fixed bugs with reporting (not clearing the file on reload, incorrect values to some fields) 470 | 471 | 1/3/12 (GhengopelALPHA) changes 472 | - changed process keys to allow right-click context menu. Added scroll for mouse movement near window edge. Removed right-click-move scroll ability (interference with context menu) 473 | + Added "delete" function: press the delete key when a bot is selected and it will be removed. 474 | - Changed color scheme (don't like the white and gray background) 475 | - Fixed agent selection to get correct world x&y when following 476 | + Added new reprate variable for bots, and is the number repcounter is reset to, with the fastest possible reprate defined by MINREPRATE. Is inherited. 477 | 478 | 1/1/2012 changes 479 | - made many more variables per agent customizable and inheritable (such as eye sensitivity etc) 480 | - added two more keys: 's' follows the selected agent around. 'o' follows the oldest agent around. 481 | - number of carnivores and herbivores are now visualized on top of the world 482 | - added a new type of brain: assembly brain, but it needs much more work. i.e. don't use 483 | 484 | v1.3 485 | - Fixed compilation issues on Linux 486 | - Ported to CMake build system 487 | 488 | v1.2 changes (released 19 January 2011): 489 | 490 | - New Brain: DWRAON (Damped Weighted Recurrent AND/OR Network). This is better due to more continuous behavior than the old, discrete, rule based system. 491 | - No dichotomy of herbivore/carnivore. There is a stomach specialization variable between 0,1. At 0, specialized to process plants, at 1, meat. This trait is inherited and undergoes mutation. This also supports emergence of omnivores, which can process both, to a lesser degree. 492 | - Meat food is now only allocated when a creature dies, as opposed to when it is injured. It is distributed evenly to all nearby creatures when the kill occurs. This leads more clearly to emergence of hunting packs. 493 | - Ability to judge health of an organism in front was added. I think of it something as a blood sensor. Essentially, it fires if something wounded is ahead. This can make agents become selective when hunting. 494 | - More sensors were added: Two clock neurons that have time-varying activity at a some frequency that can be inherited. This is useful for introducing base activity into the brain, and also for giving agents a simple way to keep track of time, and do something at regular intervals. 495 | - Also, a hearing sensor was added that directly simulates sound. Agents can now shout at each other, but probably lack the capacity to temporally parse a shouting stream and create anything that resembles a non-trivial language. 496 | - Sound generator actuator was added, which simulates creating sound and corresponds to shouting. 497 | - Ability to share food was added. An agent can choose to give up its food to organisms around it. This potentially enables emergence of altruism: When a bot is too high in health, it may sense that there is one of its kind ahead that needs food, and choose to give it up. 498 | -------------------------------------------------------------------------------- /vmath.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * vmath, set of classes for computer graphics mathemtics. 3 | * Copyright (c) 2005-2006, Jan Bartipan < barzto at gmail dot com > 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * - Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * - Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * - Neither the names of its contributors may be used to endorse or 17 | * promote products derived from this software without specific 18 | * prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 30 | * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | * POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | #include "vmath.h" 35 | 36 | #ifdef VMATH_NAMESPACE 37 | namespace VMATH_NAMESPACE 38 | { 39 | #endif 40 | 41 | template class Vector2; 42 | template class Vector2; 43 | template class Vector3; 44 | template class Vector3; 45 | template class Vector4; 46 | template class Vector4; 47 | template class Matrix3; 48 | template class Matrix3; 49 | template class Matrix4; 50 | template class Matrix4; 51 | template class Quaternion; 52 | template class Quaternion; 53 | 54 | #ifdef VMATH_NAMESPACE 55 | } 56 | #endif 57 | --------------------------------------------------------------------------------