diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.cpp | 26 | ||||
-rw-r--r-- | src/ui.cpp | 163 | ||||
-rw-r--r-- | src/world.cpp | 85 |
3 files changed, 182 insertions, 92 deletions
diff --git a/src/main.cpp b/src/main.cpp index a5bee95..327bd66 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -140,9 +140,21 @@ void render(){ **** RENDER STUFF HERE **** **************************/ - currentWorld->draw(&player->loc); - player->draw(); - ui::putString(0,0,"Hello"); + currentWorld->draw(&player->loc); // Draw the world around the player + player->draw(); // Draw the player + + if(ui::debug){ + static unsigned int debugDiv=0; + static int fps,d; + if(++debugDiv==20){ + fps=1000/deltaTime; + d=deltaTime; + debugDiv=0; + } + ui::putText(player->loc.x-SCREEN_WIDTH/2,SCREEN_HEIGHT-ui::fontSize,"FPS: %d\nD: %d\nRes: %ux%u",fps,d,SCREEN_WIDTH,SCREEN_HEIGHT); + } + + ui::draw(); // Draw any UI elements if they need to be for(int i=0;i<=entity.size();i++){ entity[i]->draw(); @@ -160,12 +172,10 @@ void render(){ void logic(){ ui::handleEvents(); - currentWorld->detect(&player->loc,&player->vel,player->width); + currentWorld->detect(player); for(int i=0;i<=entity.size();i++){ - currentWorld->detect(&entity[i]->loc,&entity[i]->vel,entity[i]->width); - if(entity[i]->alive==true&&entity[i]->type == 1){ + if(entity[i]->alive&&entity[i]->type == 1){ entity[i]->wander(90, &entity[i]->vel); } } - -} +} @@ -1,24 +1,32 @@ #include <ui.h> -#include <world.h> -#include <ft2build.h> +#include <world.h> // World-switching stuff +#include <ft2build.h> // FreeType stuff #include FT_FREETYPE_H -#define SDL_KEY e.key.keysym.sym +#define SDL_KEY e.key.keysym.sym // Keeps the code neater :) -extern Player *player; -extern World *currentWorld; +extern Player *player; // 'player' should be (must be) defined in main.cpp +extern World *currentWorld; // should/must also be defined in main.cpp -static FT_Library ftl; +static FT_Library ftl; // Variables for the FreeType library and stuff static FT_Face ftf; static GLuint ftex; -static unsigned int fontSize; + +static bool dialogBoxExists=false; +static const char *dialogBoxText=NULL; namespace ui { + bool debug=false; + unsigned int fontSize; + /* + * initFonts(), setFontFace(), and setFontSize() are pretty self-explanatory + */ void initFonts(void){ if(FT_Init_FreeType(&ftl)){ std::cout<<"Error! Couldn't initialize freetype."<<std::endl; abort(); } + fontSize=12; // to be safe } void setFontFace(const char *ttf){ if(FT_New_Face(ftl,ttf,0,&ftf)){ @@ -30,51 +38,75 @@ namespace ui { fontSize=size; FT_Set_Pixel_Sizes(ftf,0,fontSize); } + float putChar(float x,float y,char c){ + unsigned int j; + char *buf; + float w,h; + // Load the first/next character (if possible) + if(FT_Load_Char(ftf,c,FT_LOAD_RENDER)){ + std::cout<<"Error! Unsupported character "<<c<<" ("<<(int)c<<")."<<std::endl; + abort(); + } + // Load the bitmap with OpenGL + glActiveTexture(GL_TEXTURE0); + glGenTextures(1,&ftex); + glBindTexture(GL_TEXTURE_2D,ftex); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + glPixelStorei(GL_UNPACK_ALIGNMENT,1); + /* + * ftf->glyph->bitmap.buffer simply stores a bitmap of the character, + * and if OpenGL tries to load it directly it'll mistake it as a simple + * red on black texture. Here we allocate enough space to convert this + * bitmap to an RGBA-type buffer, also making the text white on black. + * + * TODO: allow different colors + */ + buf=(char *)malloc(ftf->glyph->bitmap.width*ftf->glyph->bitmap.rows*4); + for(j=0;j<ftf->glyph->bitmap.width*ftf->glyph->bitmap.rows;j++){ + buf[j*4]=255; + buf[j*4+1]=255; + buf[j*4+2]=255; + buf[j*4+3]=ftf->glyph->bitmap.buffer[j]?255:0; + } + glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,ftf->glyph->bitmap.width,ftf->glyph->bitmap.rows,0,GL_RGBA,GL_UNSIGNED_BYTE,buf); + // Draw the texture and move the cursor + w=ftf->glyph->bitmap.width; + h=ftf->glyph->bitmap.rows; + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D,ftex); + glBegin(GL_QUADS); + glColor3ub(255,255,255); + glTexCoord2f(0,1);glVertex2f(x,y); + glTexCoord2f(1,1);glVertex2f(x+w,y); + glTexCoord2f(1,0);glVertex2f(x+w,y+h); + glTexCoord2f(0,0);glVertex2f(x,y+h); + glEnd(); + glDisable(GL_TEXTURE_2D); + // Free the RGBA buffer and the OpenGL texture + free(buf); + glDeleteTextures(1,&ftex); + return w; + } void putString(const float x,const float y,const char *s){ unsigned int i=0,j; - float xo=x,yo=y,w,h; - char *buf; + float xo=x,yo=y; do{ - if(FT_Load_Char(ftf,s[i],FT_LOAD_RENDER)){ - std::cout<<"Error! Unsupported character "<<s[i]<<" ("<<(int)s[i]<<")."<<std::endl; - return; - } - glActiveTexture(GL_TEXTURE0); - glGenTextures(1,&ftex); - glBindTexture(GL_TEXTURE_2D,ftex); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); - glPixelStorei(GL_UNPACK_ALIGNMENT,1); - buf=(char *)malloc(ftf->glyph->bitmap.width*ftf->glyph->bitmap.rows*4); - for(j=0;j<ftf->glyph->bitmap.width*ftf->glyph->bitmap.rows;j++){ - buf[j*4]=255; - buf[j*4+1]=255; - buf[j*4+2]=255; - buf[j*4+3]=ftf->glyph->bitmap.buffer[j]?255:0; + if(s[i]=='\n'){ + yo-=fontSize*1.15; + xo=x; + }else if(s[i]==' '){ + xo+=fontSize/2; + }else{ + xo+=putChar(xo,yo,s[i])+fontSize*.1; } - glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,ftf->glyph->bitmap.width,ftf->glyph->bitmap.rows,0,GL_RGBA,GL_UNSIGNED_BYTE,buf); - w=ftf->glyph->bitmap.width; - h=ftf->glyph->bitmap.rows; - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D,ftex); - glBegin(GL_QUADS); - glColor3ub(255,255,255); - glTexCoord2f(0,1);glVertex2f(xo,yo); - glTexCoord2f(1,1);glVertex2f(xo+w,yo); - glTexCoord2f(1,0);glVertex2f(xo+w,yo+h); - glTexCoord2f(0,0);glVertex2f(xo,yo+h); - glEnd(); - glDisable(GL_TEXTURE_2D); - xo+=w; - free(buf); - glDeleteTextures(1,&ftex); }while(s[i++]); } - void putText(const float x,const float y,const char *str,...){ - va_list args; - char *buf; + void putText(const float x,const float y,const char *str,...){ // putText() simply runs 'str' and the extra arguments though + va_list args; // vsnprintf(), which'll store the complete string to a buffer + char *buf; // that's then passed to putString() buf=(char *)calloc(128,sizeof(char)); va_start(args,str); vsnprintf(buf,128,str,args); @@ -82,6 +114,17 @@ namespace ui { putString(x,y,buf); free(buf); } + void dialogBox(const char *text){ + dialogBoxExists=true; + dialogBoxText=text; + } + void draw(void){ + if(dialogBoxExists){ + glColor3ub(0,0,0); + glRectf(player->loc.x-SCREEN_WIDTH/2,SCREEN_HEIGHT,player->loc.x+SCREEN_WIDTH/2,SCREEN_HEIGHT-SCREEN_HEIGHT/4); + putString(player->loc.x-SCREEN_WIDTH/2,SCREEN_HEIGHT-fontSize,dialogBoxText); + } + } void handleEvents(void){ SDL_Event e; while(SDL_PollEvent(&e)){ @@ -90,21 +133,31 @@ namespace ui { gameRunning=false; break; case SDL_KEYDOWN: - if(SDL_KEY==SDLK_ESCAPE)gameRunning=false; - if(SDL_KEY==SDLK_a){ + if(SDL_KEY==SDLK_ESCAPE)gameRunning=false; // Exit the game with ESC + if(SDL_KEY==SDLK_a){ // Move left player->vel.x=-.15; - currentWorld=currentWorld->goWorldLeft(&player->loc,player->width); + currentWorld=currentWorld->goWorldLeft(player); } - if(SDL_KEY==SDLK_d){ + if(SDL_KEY==SDLK_d){ // Move right player->vel.x=.15; - currentWorld=currentWorld->goWorldRight(&player->loc,player->width); + currentWorld=currentWorld->goWorldRight(player); + } + if(SDL_KEY==SDLK_SPACE)player->vel.y=.25; // Jump + if(SDL_KEY==SDLK_i)currentWorld=currentWorld->goWorldBack(player); // Go back a layer if possible + if(SDL_KEY==SDLK_k)currentWorld=currentWorld->goWorldFront(player); // Go forward a layer if possible + if(SDL_KEY==SDLK_F3)debug^=true; + + // TEMPORARY UNTIL MOUSE + if(SDL_KEY==SDLK_t){ + if(dialogBoxExists){ + dialogBoxExists=false; + dialogBoxText=NULL; + }else dialogBox("Hello"); } - if(SDL_KEY==SDLK_SPACE)player->vel.y=.25; - if(SDL_KEY==SDLK_i)currentWorld=currentWorld->goWorldBack(&player->loc,player->width); - if(SDL_KEY==SDLK_k)currentWorld=currentWorld->goWorldFront(&player->loc,player->width); + break; case SDL_KEYUP: - if(SDL_KEY==SDLK_a)player->vel.x=0; + if(SDL_KEY==SDLK_a)player->vel.x=0; // Stop the player if movement keys are released if(SDL_KEY==SDLK_d)player->vel.x=0; break; default: diff --git a/src/world.cpp b/src/world.cpp index 891c8cd..b279f2f 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -12,6 +12,8 @@ #define DRAW_Y_OFFSET 50 // Defines how many pixels each layer should be offset from each other on the y axis when drawn. #define DRAW_SHADE 40 // Defines a shade increment for draw() +extern std::vector<Entity *>entity; + void safeSetColor(int r,int g,int b){ // safeSetColor() is an alternative to directly using glColor3ub() to set if(r>255)r=255; // the color for OpenGL drawing. safeSetColor() checks for values that are if(g>255)g=255; // outside the range of an unsigned character and sets them to a safer value. @@ -24,7 +26,7 @@ void safeSetColor(int r,int g,int b){ // safeSetColor() is an alternative to dir World::World(unsigned int width){ // Generates the world and sets all variables contained in the World class. unsigned int i; // Used for 'for' loops - float inc; // See line 37 + float inc; // See line 40 lineCount=width+GEN_INC; // Sets line count to the desired width plus GEN_INC to remove incorrect line calculations. line=(struct line_t *)calloc(lineCount,sizeof(struct line_t)); // Allocate memory for the array 'line' @@ -46,12 +48,15 @@ World::World(unsigned int width){ // Generates the world and sets all variables // in the form (where n represents the color) glColor3ub(n,n-50,n-100) } x_start=0-getWidth(this)/2+GEN_INC/2*HLINE; // Calculate x_start (explained in world.h) - behind=infront=NULL; // Set pointers to other worlds to NULL - toLeft=toRight=NULL; // to avoid accidental calls to goWorld... functions + behind=infront=NULL; // Set pointers to other worlds to NULL + toLeft=toRight=NULL; // to avoid accidental calls to goWorld... functions + //peeps=(Entity **)calloc(WORLD_ENTITY_MAX+1,sizeof(Entity *)); // peeps[0] is reserved for the player when detect() is called + //peepCount=0; } World::~World(void){ free(line); // Free (de-allocate) the array 'line' + //free(peeps); // same for the entity array } void World::draw(vec2 *vec){ @@ -78,7 +83,7 @@ LOOP2: // Draw each world cline=current->line; // 'cline' and 'cx_start' only exist to make the for loop clear (and maybe make it faster) cx_start=current->x_start; glBegin(GL_QUADS); - for(i=i;i<ie;i++){ // For lines in array 'line' from 'i' to 'ie' + for(i=i;i<ie-GEN_INC;i++){ // For lines in array 'line' from 'i' to 'ie' cline[i].y+=(yoff-DRAW_Y_OFFSET); // 'yoff' is always one incrementation ahead of what it should be safeSetColor(shade,200+shade,shade); // Safely set the grass color glVertex2i(cx_start+i*HLINE ,cline[i].y); // Draw the grass area of the line @@ -101,24 +106,38 @@ LOOP2: // Draw each world }else{ // Otherwise reset static values and return yoff=DRAW_Y_OFFSET; shade=0; + /*if(peepCount){ + for(i=1;i<peepCount;i++){ + peeps[i]->draw(); + } + }*/ } } -void World::detect(vec2 *v,vec2 *vel,const float width){ +void World::singleDetect(Entity *e){ unsigned int i; - i=(v->x+width/2-x_start)/HLINE; // Calculate what line the player is currently on - if(v->y<=line[i].y){ // Snap the player to the top of that line if the player is inside it - vel->y=0; - v->y=line[i].y+HLINE/2; - }else{ // If the player is above the ground do some gravity stuff - vel->y-=.01; + if(e->alive){ + i=(e->loc.x+e->width/2-x_start)/HLINE; // Calculate what line the player is currently on + if(e->loc.y<=line[i].y){ // Snap the player to the top of that line if the player is inside it + e->vel.y=0; + e->loc.y=line[i].y+HLINE/2; + }else{ // If the player is above the ground do some gravity stuff + e->vel.y-=.01; + } + if(e->loc.x<x_start){ // Keep the player inside world bounds (ui.cpp handles world jumping) + e->vel.x=0; + e->loc.x=x_start+HLINE/2; + }else if(e->loc.x+e->width+HLINE>x_start+getWidth(this)){ + e->vel.x=0; + e->loc.x=x_start+getWidth(this)-e->width-HLINE; + } } - if(v->x<x_start){ // Keep the player inside world bounds (ui.cpp handles world jumping) - vel->x=0; - v->x=x_start+HLINE/2; - }else if(v->x+width+HLINE>x_start+getWidth(this)){ - vel->x=0; - v->x=x_start+getWidth(this)-width-HLINE; +} +void World::detect(Player *p){ + unsigned int i; + singleDetect(p); + for(i=0;i<=entity.size();i++){ + singleDetect(entity[i]); } } @@ -135,34 +154,42 @@ void World::addLayer(unsigned int width){ behind->infront=this; } -World *World::goWorldLeft(vec2 *loc,const float width){ - if(toLeft&&loc->x<x_start+HLINE*10){ - loc->x=toLeft->x_start+getWidth(toLeft)-HLINE*10; - loc->y=toLeft->line[0].y; +World *World::goWorldLeft(Player *p){ + if(toLeft&&p->loc.x<x_start+HLINE*10){ + p->loc.x=toLeft->x_start+getWidth(toLeft)-HLINE*10; + p->loc.y=toLeft->line[0].y; return toLeft; } return this; } -World *World::goWorldRight(vec2 *loc,const float width){ - if(toRight&&loc->x+width>x_start+getWidth(this)-HLINE*10){ - loc->x=toRight->x_start+HLINE*10; - loc->y=toRight->line[toRight->lineCount-GEN_INC-1].y; +World *World::goWorldRight(Player *p){ + if(toRight&&p->loc.x+p->width>x_start+getWidth(this)-HLINE*10){ + p->loc.x=toRight->x_start+HLINE*10; + p->loc.y=toRight->line[toRight->lineCount-GEN_INC-1].y; return toRight; } return this; } -World *World::goWorldBack(vec2 *loc,const float width){ - if(behind&&loc->x>(int)(0-getWidth(behind)/2)&&loc->x<getWidth(behind)/2){ +World *World::goWorldBack(Player *p){ + if(behind&&p->loc.x>(int)(0-getWidth(behind)/2)&&p->loc.x<getWidth(behind)/2){ return behind; } return this; } -World *World::goWorldFront(vec2 *loc,const float width){ - if(infront&&loc->x>(int)(0-getWidth(infront)/2)&&loc->x<getWidth(infront)/2){ +World *World::goWorldFront(Player *p){ + if(infront&&p->loc.x>(int)(0-getWidth(infront)/2)&&p->loc.x<getWidth(infront)/2){ return infront; } return this; } + +/*void World::addEntity(Entity *e){ + if(peepCount!=WORLD_ENTITY_MAX){ + peeps[1+peepCount++]=e; // See peeps's allocation in World() for explanation of the 1+... + }else{ + std::cout<<"Warning: can't add any more entities"<<std::endl; + } +}*/ |