Optimizing Draw Functions
Gatleos

So. My ascii library's draw functions are EVIL CPU-SUCKERS. There are two parts: a Draw_Char function that doesn't draw anything to the screen but updates the symbol at a certain location, and Win_Draw, which updates the given Window by redrawing every character in it. Obviously running them every time the game loops isn't the best idea, but does anyone have any tips on how to best optimize these things to prevent lag?

Draw_Char:

void Draw_Char(int code,Window& window,int x,int y)
{
  if(x<window.mw && x>=0 && y>=0 && y<window.mh)
  {
    window.oldtile[x][y]=window.tile[x][y];
    window.tile[x][y].symbol=code;
    window.tile[x][y].color="white";
    window.tile[x][y].backcolor="black";
  }
}

Win_Draw:

#SelectExpand
1void Win_Draw(Window& windowsource) 2{ 3for(int j=0;j<=windowsource.h;++j) 4for(int i=0;i<=windowsource.w;++i) 5{ 6ALLEGRO_COLOR color=al_map_rgba(0,0,0,0); 7if(strcmp(windowsource.tile[i][j].color,"black")==0) 8color=al_map_rgba(0,0,0,255); 9else if(strcmp(windowsource.tile[i][j].color,"lightgrey")==0) 10color=al_map_rgba(192,192,192,255); 11else if(strcmp(windowsource.tile[i][j].color,"blue")==0) 12color=al_map_rgba(0,0,128,255); 13else if(strcmp(windowsource.tile[i][j].color,"green")==0) 14color=al_map_rgba(0,128,0,255); 15else if(strcmp(windowsource.tile[i][j].color,"cyan")==0) 16color=al_map_rgba(0,128,128,255); 17else if(strcmp(windowsource.tile[i][j].color,"red")==0) 18color=al_map_rgba(128,0,0,255); 19else if(strcmp(windowsource.tile[i][j].color,"magenta")==0) 20color=al_map_rgba(128,0,128,255); 21else if(strcmp(windowsource.tile[i][j].color,"brown")==0) 22color=al_map_rgba(128,128,0,255); 23else if(strcmp(windowsource.tile[i][j].color,"darkgrey")==0) 24color=al_map_rgba(128,128,128,255); 25else if(strcmp(windowsource.tile[i][j].color,"lightblue")==0) 26color=al_map_rgba(0,0,255,255); 27else if(strcmp(windowsource.tile[i][j].color,"lightgreen")==0) 28color=al_map_rgba(0,255,0,255); 29else if(strcmp(windowsource.tile[i][j].color,"lightcyan")==0) 30color=al_map_rgba(0,255,255,255); 31else if(strcmp(windowsource.tile[i][j].color,"lightred")==0) 32color=al_map_rgba(255,0,0,255); 33else if(strcmp(windowsource.tile[i][j].color,"lightmagenta")==0) 34color=al_map_rgba(255,0,255,255); 35else if(strcmp(windowsource.tile[i][j].color,"yellow")==0) 36color=al_map_rgba(255,255,0,255); 37else if(strcmp(windowsource.tile[i][j].color,"white")==0) 38color=al_map_rgba(255,255,255,255); 39ALLEGRO_COLOR backcolor=al_map_rgba(0,0,0,0); 40if(strcmp(windowsource.tile[i][j].backcolor,"black")==0) 41backcolor=al_map_rgba(0,0,0,255); 42else if(strcmp(windowsource.tile[i][j].backcolor,"lightgrey")==0) 43backcolor=al_map_rgba(192,192,192,255); 44else if(strcmp(windowsource.tile[i][j].backcolor,"blue")==0) 45backcolor=al_map_rgba(0,0,128,255); 46else if(strcmp(windowsource.tile[i][j].backcolor,"green")==0) 47backcolor=al_map_rgba(0,128,0,255); 48else if(strcmp(windowsource.tile[i][j].backcolor,"cyan")==0) 49backcolor=al_map_rgba(0,128,128,255); 50else if(strcmp(windowsource.tile[i][j].backcolor,"red")==0) 51backcolor=al_map_rgba(128,0,0,255); 52else if(strcmp(windowsource.tile[i][j].backcolor,"magenta")==0) 53backcolor=al_map_rgba(128,0,128,255); 54else if(strcmp(windowsource.tile[i][j].backcolor,"brown")==0) 55backcolor=al_map_rgba(128,128,0,255); 56else if(strcmp(windowsource.tile[i][j].backcolor,"darkgrey")==0) 57backcolor=al_map_rgba(128,128,128,255); 58else if(strcmp(windowsource.tile[i][j].backcolor,"lightblue")==0) 59backcolor=al_map_rgba(0,0,255,255); 60else if(strcmp(windowsource.tile[i][j].backcolor,"lightgreen")==0) 61backcolor=al_map_rgba(0,255,0,255); 62else if(strcmp(windowsource.tile[i][j].backcolor,"lightcyan")==0) 63backcolor=al_map_rgba(0,255,255,255); 64else if(strcmp(windowsource.tile[i][j].backcolor,"lightred")==0) 65backcolor=al_map_rgba(255,0,0,255); 66else if(strcmp(windowsource.tile[i][j].backcolor,"lightmagenta")==0) 67backcolor=al_map_rgba(255,0,255,255); 68else if(strcmp(windowsource.tile[i][j].backcolor,"yellow")==0) 69backcolor=al_map_rgba(255,255,0,255); 70else if(strcmp(windowsource.tile[i][j].backcolor,"white")==0) 71backcolor=al_map_rgba(255,255,255,255); 72 73int code=windowsource.tile[i][j].symbol; 74if(code<0 || code>255) 75code=63; 76int backcode=219; 77int row = code / colnum; 78int backrow = backcode / colnum; 79while(code>=colnum) 80code-=colnum; 81while(backcode>=colnum) 82backcode-=colnum; 83if(i<windowsource.w && j<windowsource.h) 84{ 85al_draw_tinted_bitmap_region(ascii, backcolor, tilewidth*backcode, tileheight*backrow, tilewidth, tileheight, (tilewidth*i)+(tilewidth*windowsource.x), (tileheight*j)+(tileheight*windowsource.y), 0); 86al_draw_tinted_bitmap_region(ascii, color, tilewidth*code, tileheight*row, tilewidth, tileheight, (tilewidth*i)+(tilewidth*windowsource.x), (tileheight*j)+(tileheight*windowsource.y), 0); 87} 88} 89}

Mark Oates

al_color_name(); will help clean up your code, at least.

here's a list of color names.

Gatleos

The problem is that the ALLEGRO_COLOR names aren't the same as traditional ASCII colors. I'll try to see what I can do with it, though.

Edgar Reynaldo

What's with all the strcmp's in Win_Draw? Make a color map :

ColorMap.hpp

#include <map>
#include <string>

extern std::map<std::string , ALLEGRO_COLOR> color_map;

void InitializeColorMap();

ColorMap.cpp

using std::map;
using std::string;

map<string , ALLEGRO_COLOR> color_map;

void InitializeColorMap() {
   color_map.clear();
   color_map["black"] = al_map_rgba(0,0,0,255);
   color_map["lightgrey"] = al_map_rgba(192,192,192,255);
   // repeat for all of your named colors
}

Win_Draw.cpp

#SelectExpand
1#include "ColorMap.hpp" 2 3void Win_Draw(Window& windowsource) 4{ 5for(int j=0;j<=windowsource.h;++j) 6for(int i=0;i<=windowsource.w;++i) 7{ 8const char* wcolor = windowsource.tile[i][j].color; 9const char* wbcolor = windowsource.tile[i][j].backcolor; 10ALLEGRO_COLOR color=al_map_rgba(0,0,0,0); 11if (color_map.find(wcolor) != color_map.end()) { 12 color = color_map[wcolor]; 13} 14ALLEGRO_COLOR backcolor=al_map_rgba(0,0,0,0); 15if (color_map.find(wbcolor) != color_map.end()) { 16 color = color_map[wbcolor]; 17} 18 19 20 21int code=windowsource.tile[i][j].symbol; 22if(code<0 || code>255) 23code=63; 24int backcode=219; 25int row = code / colnum; 26int backrow = backcode / colnum; 27while(code>=colnum) 28code-=colnum; 29while(backcode>=colnum) 30backcode-=colnum; 31if(i<windowsource.w && j<windowsource.h) 32{ 33al_draw_tinted_bitmap_region(ascii, backcolor, tilewidth*backcode, tileheight*backrow, tilewidth, tileheight, (tilewidth*i)+(tilewidth*windowsource.x), (tileheight*j)+(tileheight*windowsource.y), 0); 34al_draw_tinted_bitmap_region(ascii, color, tilewidth*code, tileheight*row, tilewidth, tileheight, (tilewidth*i)+(tilewidth*windowsource.x), (tileheight*j)+(tileheight*windowsource.y), 0); 35} 36} 37}

Other things - Why are you using al_draw_tinted_bitmap_region? Why not just use al_draw_filled_rectangle? And I don't see you actually draw the character anywhere.

Using the std::map will at least give you a binary search, which should be decently faster than strcmp'ing every known color value every iteration of the loop.

Also, why is tile one wider and one taller than window?

SiegeLord

As Peter Wang said in the other thread, why not just use ALLEGRO_COLOR directly, instead of storing the color name?

Gatleos

I could not, for the life of me, get ALLEGRO_COLORs to work correctly. But using the code above, that doesn't really matter anymore.

Why not just use al_draw_filled_rectangle? And I don't see you actually draw the character anywhere.

I assume primitives are faster than drawing bitmap regions, then? The character is drawn by the second al_draw_tinted_bitmap_region in Win_Draw.

Anyway, I think the code above helped a bit, but it's still using more CPU than it has any right to.

Edgar Reynaldo
Gatleos said:

I assume primitives are faster than drawing bitmap regions, then?

Maybe, maybe not. But al_draw_filled_rectangle should be faster than using al_draw_tinted_bitmap_region, at least I would think so.

How do your draw your characters background using al_draw_tinted_bitmap_region? And why are you tinting it? Don't you want just the colors from the background/foreground? Why not use al_draw_text for the character? Just use a char array[2] and set array[0] to your character and array[1] to '\0'.

About the colors : just add an ALLEGRO_COLOR entry to your TILE class and when your users set the color using a color name, find the ALLEGRO_COLOR from your color map and use that.

Gatleos

Maybe, maybe not. But al_draw_filled_rectangle should be faster than using al_draw_tinted_bitmap_region, at least I would think so.

How do your draw your characters background using al_draw_tinted_bitmap_region? And why are you tinting it? Don't you want just the colors from the background/foreground? Why not use al_draw_text for the character? Just use a char array[2] and set array[0] to your character and array[1] to '\0'.

About the colors : just add an ALLEGRO_COLOR entry to your TILE class and when your users set the color using a color name, find the ALLEGRO_COLOR from your color map and use that.

The ascii table is in a bitmap like this one:
{"name":"3oNIz.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/6\/06e4de4fdba7ae5cd41a73426a5d3992.png","w":256,"h":112,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/6\/06e4de4fdba7ae5cd41a73426a5d3992"}3oNIz.png
First, the background is alpha'd out. It draws the ASCII character's background using the "blank" character tinted to the correct background color. It then draws the ASCII character over it with the specified foreground color.

Can al_draw_text use unicode characters, or just regular old keyboard characters?

SiegeLord
Gatleos said:

But using the code above, that doesn't really matter anymore.

Yeah, it kind of does. std::map is still a lot slower than doing absolutely nothing would be.

Here's how it'd look:

void Draw_Char(int code,Window& window,int x,int y)
{
  if(x<window.mw && x>=0 && y>=0 && y<window.mh)
  {
    window.oldtile[x][y]=window.tile[x][y];
    window.tile[x][y].symbol=code;
    window.tile[x][y].color=color_map["white"];
    window.tile[x][y].backcolor=color_map["black"];
  }
}

#SelectExpand
1void Win_Draw(Window& windowsource) 2{ 4for(int j=0;j<=windowsource.h;++j) 5for(int i=0;i<=windowsource.w;++i) 6{ 7ALLEGRO_COLOR color = tile[i][j].color; 8ALLEGRO_COLOR backcolor = tile[i][j].backcolor; 9 10int code=windowsource.tile[i][j].symbol; 11if(code<0 || code>255) 12code=63; 13int backcode=219; 14int row = code / colnum; 15int backrow = backcode / colnum; 16while(code>=colnum) 17code-=colnum; 18while(backcode>=colnum) 19backcode-=colnum; 20if(i<windowsource.w && j<windowsource.h) 21{ 22al_draw_tinted_bitmap_region(ascii, backcolor, tilewidth*backcode, tileheight*backrow, tilewidth, tileheight, (tilewidth*i)+(tilewidth*windowsource.x), (tileheight*j)+(tileheight*windowsource.y), 0); 23al_draw_tinted_bitmap_region(ascii, color, tilewidth*code, tileheight*row, tilewidth, tileheight, (tilewidth*i)+(tilewidth*windowsource.x), (tileheight*j)+(tileheight*windowsource.y), 0); 24} 25} 27}

EDIT: nvm

EDIT2: Also, try adding al_hold_bitmap_drawing like I did above (highlighted).

Nazerith

How are are changes occurring on the screen? Are all the ascii constantly changing (like an ascii video player), or only changing periodically?

If the ascii isn't changing every time you draw the screen, you could store a copy to use when you refresh, so you are not needlessly going through this loop to produce the same results.

Thread #606371. Printed from Allegro.cc