backported text rendering from sauer
git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@2873 e016b1c5-ed68-44aa-a2f7-31cac88cffde
This commit is contained in:
+42
-25
@@ -28,30 +28,49 @@ struct console : consolebuffer
|
||||
else fullconsole = ++fullconsole % 3;
|
||||
}
|
||||
|
||||
void addline(const char *sf, bool highlight) { consolebuffer::addline(sf, highlight, totalmillis); }
|
||||
void addline(const char *sf) { consolebuffer::addline(sf, totalmillis); }
|
||||
|
||||
vector<char *> visible;
|
||||
|
||||
void render()
|
||||
{
|
||||
if(fullconsole)
|
||||
int conwidth = VIRTW*2 - 2*CONSPAD - 2*FONTH/3, h = VIRTH*2 - 2*CONSPAD - 2*FONTH/3,
|
||||
conheight = min(fullconsole ? (h*(fullconsole==1 ? altconsize : fullconsize))/100 : FONTH*consize, h);
|
||||
|
||||
if(fullconsole) blendbox(CONSPAD, CONSPAD, conwidth+CONSPAD+2*FONTH/3, conheight+CONSPAD+2*FONTH/3, true);
|
||||
|
||||
int numl = conlines.length(), offset = min(conskip, numl);
|
||||
|
||||
if(!fullconsole && confade)
|
||||
{
|
||||
int w = VIRTW*2, h = VIRTH*2 - 2*CONSPAD - 2*FONTH/3;
|
||||
int numl = ((h*(fullconsole==1 ? altconsize : fullconsize))/100)/(FONTH*5/4);
|
||||
if(numl <= 0) return;
|
||||
int offset = min(conskip, max(conlines.length() - numl, 0));
|
||||
blendbox(CONSPAD, CONSPAD, w-CONSPAD, 2*CONSPAD+numl*(FONTH*5/4)+2*FONTH/3, true);
|
||||
loopi(numl) draw_text(offset+i>=conlines.length() ? "" : conlines[offset+i].cref, CONSPAD+FONTH/3, CONSPAD+(FONTH*5/4)*(numl-i-1)+FONTH/3);
|
||||
}
|
||||
else if(consize)
|
||||
{
|
||||
visible.setsizenodelete(0);
|
||||
loopv(conlines) if(conskip ? i>=conskip-1 || i>=conlines.length()-consize : (!confade || totalmillis-conlines[i].millis<confade*1000))
|
||||
if(!conskip)
|
||||
{
|
||||
visible.add(conlines[i].cref);
|
||||
if(visible.length()>=consize) break;
|
||||
numl = 0;
|
||||
loopvrev(conlines) if(totalmillis-conlines[i].millis < confade*1000) { numl = i+1; break; }
|
||||
}
|
||||
loopvj(visible) draw_text(visible[j], CONSPAD+FONTH/3, CONSPAD+(FONTH*5/4)*(visible.length()-j-1)+FONTH/3);
|
||||
else offset--;
|
||||
}
|
||||
|
||||
int y = 0;
|
||||
loopi(numl) //determine visible height
|
||||
{
|
||||
// shuffle backwards to fill if necessary
|
||||
int idx = offset+i < numl ? offset+i : --offset;
|
||||
char *line = conlines[idx].line;
|
||||
int width, height;
|
||||
text_bounds(line, width, height, conwidth);
|
||||
y += height;
|
||||
if(y > conheight) { numl = i; if(offset == idx) ++offset; break; }
|
||||
}
|
||||
y = CONSPAD+FONTH/3;
|
||||
loopi(numl)
|
||||
{
|
||||
int idx = offset + numl-i-1;
|
||||
char *line = conlines[idx].line;
|
||||
draw_text(line, CONSPAD+FONTH/3, y, 0xFF, 0xFF, 0xFF, 0xFF, -1, conwidth);
|
||||
int width, height;
|
||||
text_bounds(line, width, height, conwidth);
|
||||
y += height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,19 +96,17 @@ void conoutf(const char *s, ...)
|
||||
string sp;
|
||||
filtertext(sp, sf);
|
||||
puts(sp);
|
||||
s = sf;
|
||||
vector<char *> lines;
|
||||
text_block(s, curfont ? VIRTW*2-2*CONSPAD-2*FONTH/3 : 0, lines);
|
||||
loopv(lines) con.addline(lines[i], false);
|
||||
lines.deletecontentsa();
|
||||
con.addline(sf);
|
||||
}
|
||||
|
||||
void rendercommand(int x, int y)
|
||||
int rendercommand(int x, int y, int w)
|
||||
{
|
||||
s_sprintfd(s)("> %s", cmdline.buf);
|
||||
int offset = text_width(s, cmdline.pos>=0 ? cmdline.pos+2 : -1);
|
||||
rendercursor(x+offset, y, char_width(cmdline.pos>=0 ? cmdline.buf[cmdline.pos] : '_'));
|
||||
draw_text(s, x, y);
|
||||
int width, height;
|
||||
text_bounds(s, width, height, w);
|
||||
y -= height - FONTH;
|
||||
draw_text(s, x, y, 0xFF, 0xFF, 0xFF, 0xFF, cmdline.pos>=0 ? cmdline.pos+2 : strlen(s), w);
|
||||
return height;
|
||||
}
|
||||
|
||||
// keymap is defined externally in keymap.cfg
|
||||
|
||||
+4
-14
@@ -1,26 +1,16 @@
|
||||
struct cline { char *cref; int millis; };
|
||||
struct cline { char *line; int millis; };
|
||||
|
||||
struct consolebuffer
|
||||
{
|
||||
vector<cline> conlines;
|
||||
|
||||
void addline(const char *sf, bool highlight, int millis) // add a line to the console buffer
|
||||
void addline(const char *sf, int millis) // add a line to the console buffer
|
||||
{
|
||||
cline cl;
|
||||
cl.cref = conlines.length()>100 ? conlines.pop().cref : newstringbuf(""); // constrain the buffer size
|
||||
cl.line = conlines.length()>100 ? conlines.pop().line : newstringbuf(""); // constrain the buffer size
|
||||
cl.millis = millis; // for how long to keep line on screen
|
||||
conlines.insert(0,cl);
|
||||
if(highlight) // show line in a different colour, for chat etc.
|
||||
{
|
||||
cl.cref[0] = '\f';
|
||||
cl.cref[1] = '0';
|
||||
cl.cref[2] = 0;
|
||||
s_strcat(cl.cref, sf);
|
||||
}
|
||||
else
|
||||
{
|
||||
s_strcpy(cl.cref, sf);
|
||||
}
|
||||
s_strcpy(cl.line, sf);
|
||||
}
|
||||
|
||||
virtual ~consolebuffer() {}
|
||||
|
||||
+60
-37
@@ -309,7 +309,7 @@ int numargs(char *args)
|
||||
return argidx;
|
||||
}
|
||||
|
||||
void renderdoc(int x, int y)
|
||||
void renderdoc(int x, int y, int doch)
|
||||
{
|
||||
if(!docvisible) return;
|
||||
|
||||
@@ -328,10 +328,11 @@ void renderdoc(int x, int y)
|
||||
docident *ident = docidents.access(cmd);
|
||||
if(ident)
|
||||
{
|
||||
const int linemax = VIRTW*4/3;
|
||||
cvector doclines;
|
||||
vector<const char *> doclines;
|
||||
|
||||
char *label = doclines.add(newstringbuf(ident->name)); // label
|
||||
char *label = newstringbuf(); // label
|
||||
doclines.add(label);
|
||||
s_sprintf(label)("~%s", ident->name);
|
||||
loopvj(ident->arguments)
|
||||
{
|
||||
s_strcat(label, " ");
|
||||
@@ -339,9 +340,7 @@ void renderdoc(int x, int y)
|
||||
}
|
||||
doclines.add(NULL);
|
||||
|
||||
cvector desc;
|
||||
text_block(ident->desc, linemax, desc); // desc
|
||||
loopvj(desc) doclines.add(desc[j]);
|
||||
doclines.add(ident->desc);
|
||||
doclines.add(NULL);
|
||||
|
||||
if(ident->arguments.length() > 0) // args
|
||||
@@ -379,8 +378,7 @@ void renderdoc(int x, int y)
|
||||
{
|
||||
docargument *a = &ident->arguments[j];
|
||||
if(!a) continue;
|
||||
char *argstr = doclines.add(new string);
|
||||
s_sprintf(argstr)("\f%d%-8s%s %s%s%s", j == arg ? 4 : 5, a->token, a->desc,
|
||||
s_sprintf(doclines.add(newstringbuf()))("~\f%d%-8s%s %s%s%s", j == arg ? 4 : 5, a->token, a->desc,
|
||||
a->values ? "(" : "", a->values ? a->values : "", a->values ? ")" : "");
|
||||
}
|
||||
|
||||
@@ -389,35 +387,28 @@ void renderdoc(int x, int y)
|
||||
|
||||
if(ident->remarks.length()) // remarks
|
||||
{
|
||||
loopvj(ident->remarks)
|
||||
{
|
||||
cvector remarks;
|
||||
text_block(ident->remarks[j], linemax, remarks);
|
||||
loopvk(remarks) doclines.add(remarks[k]);
|
||||
}
|
||||
loopvj(ident->remarks) doclines.add(ident->remarks[j]);
|
||||
doclines.add(NULL);
|
||||
}
|
||||
|
||||
if(ident->examples.length()) // examples
|
||||
{
|
||||
doclines.add(newstring(ident->examples.length() == 1 ? "Example:" : "Examples:"));
|
||||
doclines.add(ident->examples.length() == 1 ? "Example:" : "Examples:");
|
||||
loopvj(ident->examples)
|
||||
{
|
||||
cvector lines;
|
||||
text_block(ident->examples[j].code, linemax, lines);
|
||||
text_block(ident->examples[j].explanation, linemax, lines);
|
||||
loopvk(lines) doclines.add(lines[k]);
|
||||
doclines.add(ident->examples[j].code);
|
||||
doclines.add(ident->examples[j].explanation);
|
||||
}
|
||||
doclines.add(NULL);
|
||||
}
|
||||
|
||||
if(ident->keys.length()) // default keys
|
||||
{
|
||||
doclines.add(newstring(ident->keys.length() == 1 ? "Default key:" : "Default keys:"));
|
||||
doclines.add(ident->keys.length() == 1 ? "Default key:" : "Default keys:");
|
||||
loopvj(ident->keys)
|
||||
{
|
||||
dockey &k = ident->keys[j];
|
||||
s_sprintfd(line)("%-10s %s", k.name ? k.name : k.alias, k.desc ? k.desc : "");
|
||||
s_sprintfd(line)("~%-10s %s", k.name ? k.name : k.alias, k.desc ? k.desc : "");
|
||||
doclines.add(newstring(line));
|
||||
}
|
||||
doclines.add(NULL);
|
||||
@@ -437,25 +428,57 @@ void renderdoc(int x, int y)
|
||||
loopj(sizeof(categories)/sizeof(category))
|
||||
{
|
||||
if(!strlen(categories[j].refs)) continue;
|
||||
char *line = doclines.add(newstringbuf(categories[j].label));
|
||||
s_strcat(line, ": ");
|
||||
s_strcat(line, categories[j].refs);
|
||||
s_sprintf(doclines.add(newstringbuf()))("~%s: %s", categories[j].label, categories[j].refs);
|
||||
}
|
||||
}
|
||||
|
||||
int screenlines = (VIRTH*2/3/FONTH)-1;
|
||||
if(docskip) docskip = min(docskip, doclines.length() - screenlines); // normalize
|
||||
bool more = docskip < doclines.length() - screenlines;
|
||||
|
||||
for(int j = docskip; j < min(doclines.length(), docskip+screenlines); j++)
|
||||
{
|
||||
if(doclines[j]) draw_textf("%s", x, y+j*FONTH, doclines[j]);
|
||||
}
|
||||
doclines.deletecontentsa();
|
||||
while(doclines.length() && !doclines.last()) doclines.pop();
|
||||
|
||||
if(more) draw_textf("\f4more (F3)", x, y+screenlines*FONTH); // footer
|
||||
if(docskip > 0) draw_textf("\f4less (F2)", x, y+(screenlines+1)*FONTH);
|
||||
draw_textf("\f4disable doc reference (F1)", x, y+(screenlines+2)*FONTH);
|
||||
doch -= 3*FONTH + FONTH/2;
|
||||
|
||||
int offset = min(docskip, doclines.length()-1), maxl = offset, cury = 0;
|
||||
for(int j = offset; j < doclines.length(); j++)
|
||||
{
|
||||
const char *str = doclines[j];
|
||||
int width = 0, height = FONTH;
|
||||
if(str) text_bounds(*str=='~' ? str+1 : str, width, height, *str=='~' ? -1 : VIRTW*4/3);
|
||||
if(cury + height > doch) break;
|
||||
cury += height;
|
||||
maxl = j+1;
|
||||
}
|
||||
if(offset > 0 && maxl >= doclines.length())
|
||||
{
|
||||
for(int j = offset-1; j >= 0; j--)
|
||||
{
|
||||
const char *str = doclines[j];
|
||||
int width = 0, height = FONTH;
|
||||
if(str) text_bounds(*str=='~' ? str+1 : str, width, height, *str=='~' ? -1 : VIRTW*4/3);
|
||||
if(cury + height > doch) break;
|
||||
cury += height;
|
||||
offset = j;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cury = y;
|
||||
for(int j = offset; j < maxl; j++)
|
||||
{
|
||||
const char *str = doclines[j];
|
||||
if(str)
|
||||
{
|
||||
const char *text = *str=='~' ? str+1 : str;
|
||||
draw_text(text, x, cury, 0xFF, 0xFF, 0xFF, 0xFF, -1, str==text ? VIRTW*4/3 : -1);
|
||||
int width, height;
|
||||
text_bounds(text, width, height, str==text ? VIRTW*4/3 : -1);
|
||||
cury += height;
|
||||
if(str!=text) delete[] str;
|
||||
}
|
||||
else cury += FONTH;
|
||||
}
|
||||
|
||||
if(maxl < doclines.length()) draw_text("\f4more (F3)", x, y+doch); // footer
|
||||
if(offset > 0) draw_text("\f4less (F2)", x, y+doch+FONTH);
|
||||
draw_text("\f4disable doc reference (F1)", x, y+doch+2*FONTH);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +137,29 @@ static inline uint hthash(const ivec &k)
|
||||
return k.x^k.y^k.z;
|
||||
}
|
||||
|
||||
struct bvec
|
||||
{
|
||||
union
|
||||
{
|
||||
struct { uchar x, y, z; };
|
||||
uchar v[3];
|
||||
};
|
||||
|
||||
bvec() {}
|
||||
bvec(uchar x, uchar y, uchar z) : x(x), y(y), z(z) {}
|
||||
bvec(const vec &v) : x((uchar)((v.x+1)*255/2)), y((uchar)((v.y+1)*255/2)), z((uchar)((v.z+1)*255/2)) {}
|
||||
|
||||
uchar &operator[](int i) { return v[i]; }
|
||||
uchar operator[](int i) const { return v[i]; }
|
||||
|
||||
bool operator==(const bvec &v) const { return x==v.x && y==v.y && z==v.z; }
|
||||
bool operator!=(const bvec &v) const { return x!=v.x || y!=v.y || z!=v.z; }
|
||||
|
||||
bool iszero() const { return x==0 && y==0 && z==0; }
|
||||
|
||||
vec tovec() const { return vec(x*(2.0f/255.0f)-1.0f, y*(2.0f/255.0f)-1.0f, z*(2.0f/255.0f)-1.0f); }
|
||||
};
|
||||
|
||||
struct glmatrixf
|
||||
{
|
||||
float v[16];
|
||||
|
||||
@@ -205,9 +205,7 @@ struct mitemtextinput : mitemtext
|
||||
int tw = VIRTW/4;
|
||||
if(selection) renderbg(x+w-tw, y-FONTH/6, tw, NULL);
|
||||
draw_text(text, x, y);
|
||||
int offset = text_width(input.buf, input.pos>=0 ? input.pos : -1);
|
||||
if(selection) rendercursor(x+w-tw+offset, y, char_width(input.pos>=0 ? input.buf[input.pos] : '_'));
|
||||
draw_text(input.buf, x+w-tw, y);
|
||||
draw_text(input.buf, x+w-tw, y, 255, 255, 255, 255, selection ? (input.pos>=0 ? input.pos : strlen(input.buf)) : -1);
|
||||
}
|
||||
|
||||
virtual void focus(bool on)
|
||||
@@ -364,11 +362,11 @@ struct mitemkeyinput : mitem
|
||||
DELETEA(bindcmd);
|
||||
}
|
||||
|
||||
virtual int width() { return text_width(text)+(keyname ? text_width(keyname) : char_width('_')); }
|
||||
virtual int width() { return text_width(text)+text_width(keyname ? keyname : " "); }
|
||||
|
||||
virtual void render(int x, int y, int w)
|
||||
{
|
||||
int tk = (keyname ? text_width(keyname) : char_width('_'));
|
||||
int tk = text_width(keyname ? keyname : " ");
|
||||
static color capturec(0.4f, 0, 0);
|
||||
if(isselection()) blendbox(x+w-tk-FONTH, y-FONTH/6, x+w+FONTH, y+FONTH+FONTH/6, false, -1, capture ? &capturec : NULL);
|
||||
draw_text(text, x, y);
|
||||
|
||||
+7
-6
@@ -69,7 +69,7 @@ extern int execcontext;
|
||||
|
||||
// console
|
||||
extern void keypress(int code, bool isdown, int cooked, SDLMod mod = KMOD_NONE);
|
||||
extern void rendercommand(int x, int y);
|
||||
extern int rendercommand(int x, int y, int w);
|
||||
extern void renderconsole();
|
||||
extern char *getcurcommand();
|
||||
extern char *addreleaseaction(const char *s);
|
||||
@@ -447,12 +447,13 @@ extern int VIRTW; // virtual screen size for text & HUD
|
||||
extern font *curfont;
|
||||
|
||||
extern bool setfont(const char *name);
|
||||
extern void draw_text(const char *str, int left, int top);
|
||||
extern void draw_text(const char *str, int left, int top, int r = 255, int g = 255, int b = 255, int a = 255, int cursor = -1, int maxwidth = -1);
|
||||
extern void draw_textf(const char *fstr, int left, int top, ...);
|
||||
extern int char_width(int c, int x = 0);
|
||||
extern int text_width(const char *str, int limit = -1);
|
||||
extern int text_width(const char *str);
|
||||
extern int text_visible(const char *str, int max);
|
||||
extern void text_block(const char *str, int max, vector<char *> &lines);
|
||||
extern void text_bounds(const char *str, int &width, int &height, int maxwidth = -1);
|
||||
extern int text_visible(const char *str, int hitx, int hity, int maxwidth);
|
||||
extern void text_pos(const char *str, int cursor, int &cx, int &cy, int maxwidth);
|
||||
extern void text_startcolumns();
|
||||
extern void text_endcolumns();
|
||||
|
||||
@@ -595,7 +596,7 @@ extern void checkitems(playerent *d);
|
||||
extern void perlinarea(block &b, int scale, int seed, int psize);
|
||||
|
||||
// doc
|
||||
extern void renderdoc(int x, int y);
|
||||
extern void renderdoc(int x, int y, int doch);
|
||||
extern void renderdocmenu(void *menu, bool init);
|
||||
extern void toggledoc();
|
||||
extern void scrolldoc(int i);
|
||||
|
||||
@@ -262,12 +262,12 @@ void drawradarent(float x, float y, float yaw, int col, int row, float iconsize,
|
||||
|
||||
struct hudmessages : consolebuffer
|
||||
{
|
||||
void addline(const char *sf) { consolebuffer::addline(sf, false, totalmillis); }
|
||||
void addline(const char *sf) { consolebuffer::addline(sf, totalmillis); }
|
||||
void editlastline(const char *sf)
|
||||
{
|
||||
if(!conlines.length()) return;
|
||||
conlines[0].millis = totalmillis;
|
||||
s_strcpy(conlines[0].cref, sf);
|
||||
s_strcpy(conlines[0].line, sf);
|
||||
}
|
||||
void render()
|
||||
{
|
||||
@@ -278,8 +278,8 @@ struct hudmessages : consolebuffer
|
||||
loopi(min(conlines.length(), 3)) if(totalmillis-conlines[i].millis<dispmillis)
|
||||
{
|
||||
cline &c = conlines[i];
|
||||
int tw = text_width(c.cref);
|
||||
draw_text(c.cref, int(tw > VIRTW*0.8f ? 0 : (VIRTW*0.8f-tw)/2), int(((VIRTH*0.8f)/4*3)+FONTH*i+pow((totalmillis-c.millis)/(float)dispmillis, 4)*VIRTH*0.8f/4.0f));
|
||||
int tw = text_width(c.line);
|
||||
draw_text(c.line, int(tw > VIRTW*0.8f ? 0 : (VIRTW*0.8f-tw)/2), int(((VIRTH*0.8f)/4*3)+FONTH*i+pow((totalmillis-c.millis)/(float)dispmillis, 4)*VIRTH*0.8f/4.0f));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -477,7 +477,8 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
|
||||
char *infostr = editinfo();
|
||||
if(command) rendercommand(20, 1570);
|
||||
int commandh = 1570 + FONTH;
|
||||
if(command) commandh -= rendercommand(20, 1570, VIRTW);
|
||||
else if(infostr) draw_text(infostr, 20, 1570);
|
||||
else if(targetplayer && !spectating) draw_text(colorname(targetplayer), 20, 1570);
|
||||
|
||||
@@ -486,7 +487,7 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat
|
||||
|
||||
if(!hideconsole) renderconsole();
|
||||
if(menu) rendermenu();
|
||||
else if(command) renderdoc(40, VIRTH);
|
||||
else if(command) renderdoc(40, VIRTH, max(commandh*2 - VIRTH, 0));
|
||||
if(!hidestats)
|
||||
{
|
||||
const int left = (VIRTW-225-10)*2, top = (VIRTH*7/8)*2;
|
||||
|
||||
+204
-156
@@ -54,17 +54,62 @@ bool setfont(const char *name)
|
||||
return true;
|
||||
}
|
||||
|
||||
int char_width(int c, int x)
|
||||
int text_width(const char *str)
|
||||
{
|
||||
if(!curfont) return x;
|
||||
else if(c=='\t') x = (x+PIXELTAB)/PIXELTAB*PIXELTAB;
|
||||
else if(c==' ') x += curfont->defaultw;
|
||||
else if(curfont->chars.inrange(c-33))
|
||||
{
|
||||
c -= 33;
|
||||
x += curfont->chars[c].w + 1;
|
||||
int width, height;
|
||||
text_bounds(str, width, height);
|
||||
return width;
|
||||
}
|
||||
|
||||
void draw_textf(const char *fstr, int left, int top, ...)
|
||||
{
|
||||
s_sprintfdlv(str, top, fstr);
|
||||
draw_text(str, left, top);
|
||||
}
|
||||
|
||||
static int draw_char(int c, int x, int y)
|
||||
{
|
||||
font::charinfo &info = curfont->chars[c-33];
|
||||
float tc_left = (info.x + curfont->offsetx) / float(curfont->tex->xs);
|
||||
float tc_top = (info.y + curfont->offsety) / float(curfont->tex->ys);
|
||||
float tc_right = (info.x + info.w + curfont->offsetw) / float(curfont->tex->xs);
|
||||
float tc_bottom = (info.y + info.h + curfont->offseth) / float(curfont->tex->ys);
|
||||
|
||||
glTexCoord2f(tc_left, tc_top ); glVertex2f(x, y);
|
||||
glTexCoord2f(tc_right, tc_top ); glVertex2f(x + info.w, y);
|
||||
glTexCoord2f(tc_right, tc_bottom); glVertex2f(x + info.w, y + info.h);
|
||||
glTexCoord2f(tc_left, tc_bottom); glVertex2f(x, y + info.h);
|
||||
|
||||
xtraverts += 4;
|
||||
return info.w;
|
||||
}
|
||||
|
||||
//stack[sp] is current color index
|
||||
static void text_color(char c, char *stack, int size, int &sp, bvec color, int a)
|
||||
{
|
||||
if(c=='s') // save color
|
||||
{
|
||||
c = stack[sp];
|
||||
if(sp<size-1) stack[++sp] = c;
|
||||
}
|
||||
return x;
|
||||
else
|
||||
{
|
||||
if(c=='r') c = stack[(sp > 0) ? --sp : sp]; // restore color
|
||||
else stack[sp] = c;
|
||||
switch(c)
|
||||
{
|
||||
case '0': color = bvec(64, 255, 128); break; // green: player talk
|
||||
case '1': color = bvec(96, 160, 255); break; // blue: team chat
|
||||
case '2': color = bvec(255, 192, 64); break; // yellow: gameplay action messages, only actions done by players
|
||||
case '3': color = bvec(255, 64, 64); break; // red: important errors and notes
|
||||
case '4': color = bvec(128, 128, 128); break; // gray
|
||||
case '5': color = bvec(255, 255, 255); break; // white
|
||||
case '6': color = bvec(96, 48, 0); break; // dark brown
|
||||
case '7': color = bvec(128, 48, 48); break; // dark red: dead admin
|
||||
// white (provided color): everything else
|
||||
}
|
||||
glColor4ub(color.x, color.y, color.z, a);
|
||||
}
|
||||
}
|
||||
|
||||
static vector<int> *columns = NULL;
|
||||
@@ -79,170 +124,173 @@ void text_endcolumns()
|
||||
DELETEP(columns);
|
||||
}
|
||||
|
||||
int text_width(const char *str, int limit)
|
||||
{
|
||||
if(!str) return 0;
|
||||
int x = 0, col = 0, colx = 0;
|
||||
for(int i = 0; str[i] && (limit<0 || i<limit); i++)
|
||||
{
|
||||
switch(str[i])
|
||||
{
|
||||
case '\f':
|
||||
i++;
|
||||
break;
|
||||
#define TABALIGN(x) ((((x)+PIXELTAB)/PIXELTAB)*PIXELTAB)
|
||||
|
||||
case '\t':
|
||||
if(columns)
|
||||
{
|
||||
while(col>=columns->length()) columns->add(0);
|
||||
int w = char_width('\t', x) - colx;
|
||||
w = max(w, (*columns)[col]);
|
||||
(*columns)[col] = w;
|
||||
col++;
|
||||
colx += w;
|
||||
x = colx;
|
||||
#define TEXTGETCOLUMN \
|
||||
if(columns && col<columns->length()) \
|
||||
{ \
|
||||
colx += (*columns)[col++]; \
|
||||
x = colx; \
|
||||
} \
|
||||
else x = TABALIGN(x);
|
||||
|
||||
#define TEXTSETCOLUMN \
|
||||
if(columns) \
|
||||
{ \
|
||||
while(col>=columns->length()) columns->add(0); \
|
||||
int w = TABALIGN(x) - colx; \
|
||||
w = max(w, (*columns)[col]); \
|
||||
(*columns)[col] = w; \
|
||||
col++; \
|
||||
colx += w; \
|
||||
x = colx; \
|
||||
} \
|
||||
else x = TABALIGN(x);
|
||||
|
||||
|
||||
#define TEXTSKELETON \
|
||||
int y = 0, x = 0, col = 0, colx = 0;\
|
||||
int i;\
|
||||
for(i = 0; str[i]; i++)\
|
||||
{\
|
||||
TEXTINDEX(i)\
|
||||
int c = str[i];\
|
||||
if(c=='\t') { TEXTTAB(i); TEXTWHITE(i) }\
|
||||
else if(c==' ') { x += curfont->defaultw; TEXTWHITE(i) }\
|
||||
else if(c=='\n') { TEXTLINE(i) x = 0; y += FONTH; }\
|
||||
else if(c=='\f') { if(str[i+1]) { i++; TEXTCOLOR(i) }}\
|
||||
else if(curfont->chars.inrange(c-33))\
|
||||
{\
|
||||
if(maxwidth != -1)\
|
||||
{\
|
||||
int j = i;\
|
||||
int w = curfont->chars[c-33].w;\
|
||||
for(; str[i+1]; i++)\
|
||||
{\
|
||||
int c = str[i+1];\
|
||||
if(c=='\f') { if(str[i+2]) i++; continue; }\
|
||||
if(i-j > 16) break;\
|
||||
if(!curfont->chars.inrange(c-33)) break;\
|
||||
int cw = curfont->chars[c-33].w + 1;\
|
||||
if(w + cw >= maxwidth) break;\
|
||||
w += cw;\
|
||||
}\
|
||||
if(x + w >= maxwidth && j!=0) { TEXTLINE(j-1) x = 0; y += FONTH; }\
|
||||
TEXTWORD\
|
||||
}\
|
||||
else\
|
||||
{ TEXTCHAR(i) }\
|
||||
}\
|
||||
}
|
||||
|
||||
//all the chars are guaranteed to be either drawable or color commands
|
||||
#define TEXTWORDSKELETON \
|
||||
for(; j <= i; j++)\
|
||||
{\
|
||||
TEXTINDEX(j)\
|
||||
int c = str[j];\
|
||||
if(c=='\f') { if(str[j+1]) { j++; TEXTCOLOR(j) }}\
|
||||
else { TEXTCHAR(j) }\
|
||||
}
|
||||
else x = char_width('\t', x);
|
||||
break;
|
||||
|
||||
default:
|
||||
x = char_width(str[i], x);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int text_visible(const char *str, int max)
|
||||
int text_visible(const char *str, int hitx, int hity, int maxwidth)
|
||||
{
|
||||
int i = 0, x = 0;
|
||||
while(str[i])
|
||||
{
|
||||
if(str[i]=='\f')
|
||||
{
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
x = char_width(str[i], x);
|
||||
if(x > max) return i;
|
||||
++i;
|
||||
}
|
||||
#define TEXTINDEX(idx)
|
||||
#define TEXTTAB(idx) TEXTGETCOLUMN
|
||||
#define TEXTWHITE(idx) if(y+FONTH > hity && x >= hitx) return idx;
|
||||
#define TEXTLINE(idx) if(y+FONTH > hity) return idx;
|
||||
#define TEXTCOLOR(idx)
|
||||
#define TEXTCHAR(idx) x += curfont->chars[c-33].w+1; TEXTWHITE(idx)
|
||||
#define TEXTWORD TEXTWORDSKELETON
|
||||
TEXTSKELETON
|
||||
#undef TEXTINDEX
|
||||
#undef TEXTTAB
|
||||
#undef TEXTWHITE
|
||||
#undef TEXTLINE
|
||||
#undef TEXTCOLOR
|
||||
#undef TEXTCHAR
|
||||
#undef TEXTWORD
|
||||
return i;
|
||||
}
|
||||
|
||||
// cut strings to fit on screen
|
||||
void text_block(const char *str, int max, vector<char *> &lines)
|
||||
//inverse of text_visible
|
||||
void text_pos(const char *str, int cursor, int &cx, int &cy, int maxwidth)
|
||||
{
|
||||
if(!str) return;
|
||||
int visible;
|
||||
cvector colordata;
|
||||
while((visible = max ? text_visible(str, max) : (int)strlen(str)))
|
||||
{
|
||||
const char *newline = (const char *)memchr(str, '\n', visible);
|
||||
if(newline) visible = newline+1-str;
|
||||
else if(str[visible]) // wrap words
|
||||
{
|
||||
int v = visible;
|
||||
while(v > 0 && str[v] != ' ') v--;
|
||||
if(v) visible = v+1;
|
||||
}
|
||||
size_t colorsize = colordata.length()*2;
|
||||
char *t = lines.add(newstring((size_t)visible+colorsize));
|
||||
char *color = t;
|
||||
loopv(colordata) // add colors from previous line
|
||||
{
|
||||
s_strncpy(color, colordata[i], 3);
|
||||
color += 2;
|
||||
}
|
||||
s_strncpy(color, str, visible+1);
|
||||
colordata.setsize(0);
|
||||
for(char *c = strchr(t, '\f'); c && c[1]; c = strchr(c+1, '\f')) colordata.add(c); // store colors of this line
|
||||
str += visible;
|
||||
}
|
||||
#define TEXTINDEX(idx) if(idx == cursor) { cx = x; cy = y; break; }
|
||||
#define TEXTTAB(idx) TEXTGETCOLUMN
|
||||
#define TEXTWHITE(idx)
|
||||
#define TEXTLINE(idx)
|
||||
#define TEXTCOLOR(idx)
|
||||
#define TEXTCHAR(idx) x += curfont->chars[c-33].w + 1;
|
||||
#define TEXTWORD TEXTWORDSKELETON if(i >= cursor) break;
|
||||
cx = INT_MIN;
|
||||
cy = 0;
|
||||
TEXTSKELETON
|
||||
if(cx == INT_MIN) { cx = x; cy = y; }
|
||||
#undef TEXTINDEX
|
||||
#undef TEXTTAB
|
||||
#undef TEXTWHITE
|
||||
#undef TEXTLINE
|
||||
#undef TEXTCOLOR
|
||||
#undef TEXTCHAR
|
||||
#undef TEXTWORD
|
||||
}
|
||||
|
||||
void draw_textf(const char *fstr, int left, int top, ...)
|
||||
void text_bounds(const char *str, int &width, int &height, int maxwidth)
|
||||
{
|
||||
s_sprintfdlv(str, top, fstr);
|
||||
draw_text(str, left, top);
|
||||
#define TEXTINDEX(idx)
|
||||
#define TEXTTAB(idx) TEXTSETCOLUMN
|
||||
#define TEXTWHITE(idx)
|
||||
#define TEXTLINE(idx) if(x > width) width = x;
|
||||
#define TEXTCOLOR(idx)
|
||||
#define TEXTCHAR(idx) x += curfont->chars[c-33].w + 1;
|
||||
#define TEXTWORD x += w + 1;
|
||||
width = 0;
|
||||
TEXTSKELETON
|
||||
height = y + FONTH;
|
||||
TEXTLINE(_)
|
||||
#undef TEXTINDEX
|
||||
#undef TEXTTAB
|
||||
#undef TEXTWHITE
|
||||
#undef TEXTLINE
|
||||
#undef TEXTCOLOR
|
||||
#undef TEXTCHAR
|
||||
#undef TEXTWORD
|
||||
}
|
||||
|
||||
void draw_text(const char *str, int left, int top)
|
||||
void draw_text(const char *str, int left, int top, int r, int g, int b, int a, int cursor, int maxwidth)
|
||||
{
|
||||
if(!curfont) return;
|
||||
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
#define TEXTINDEX(idx) if(idx == cursor) { cx = x; cy = y; cc = str[idx]; }
|
||||
#define TEXTTAB(idx) TEXTGETCOLUMN
|
||||
#define TEXTWHITE(idx)
|
||||
#define TEXTLINE(idx)
|
||||
#define TEXTCOLOR(idx) text_color(str[idx], colorstack, sizeof(colorstack), colorpos, color, a);
|
||||
#define TEXTCHAR(idx) x += draw_char(c, left+x, top+y)+1;
|
||||
#define TEXTWORD TEXTWORDSKELETON
|
||||
char colorstack[10];
|
||||
bvec color(r, g, b);
|
||||
int colorpos = 0, cx = INT_MIN, cy = 0, cc = ' ';
|
||||
colorstack[0] = 'c'; //indicate user color
|
||||
glBlendFunc(GL_SRC_ALPHA, curfont->tex->bpp==32 ? GL_ONE_MINUS_SRC_ALPHA : GL_ONE);
|
||||
glBindTexture(GL_TEXTURE_2D, curfont->tex->id);
|
||||
|
||||
static float colorstack[8][4];
|
||||
int colorpos = 0, x = left, y = top, col = 0, colx = 0;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
// ATI bug -- initial color must be set after glBegin
|
||||
glColor3ub(255, 255, 255);
|
||||
for(int i = 0; str[i]; i++)
|
||||
{
|
||||
int c = str[i];
|
||||
switch(c)
|
||||
{
|
||||
case '\t':
|
||||
if(columns && col<columns->length())
|
||||
{
|
||||
colx += (*columns)[col++];
|
||||
x = left + colx;
|
||||
}
|
||||
else x = (x-left+PIXELTAB)/PIXELTAB*PIXELTAB+left;
|
||||
continue;
|
||||
|
||||
case '\f':
|
||||
switch(str[++i])
|
||||
{
|
||||
case '0': glColor3ub(64, 255, 128); continue; // green: player talk
|
||||
case '1': glColor3ub(96, 160, 255); continue; // blue: team chat
|
||||
case '2': glColor3ub(255, 192, 64); continue; // yellow: gameplay action messages, only actions done by players
|
||||
case '3': glColor3ub(255, 64, 64); continue; // red: important errors and notes
|
||||
case '4': glColor3ub(128, 128, 128); continue; // gray
|
||||
case '5': glColor3ub(255, 255, 255); continue; // white: everything else
|
||||
case '6': glColor3ub(96, 48, 0); continue; // dark brown
|
||||
case '7': glColor3ub(128, 48, 48); continue; // dark red: dead admin
|
||||
case 's': // save color
|
||||
if((size_t)colorpos<sizeof(colorstack)/sizeof(colorstack[0]))
|
||||
{
|
||||
glEnd();
|
||||
glGetFloatv(GL_CURRENT_COLOR, colorstack[colorpos++]);
|
||||
glBegin(GL_QUADS);
|
||||
}
|
||||
continue;
|
||||
case 'r': // restore color
|
||||
if(colorpos>0)
|
||||
glColor4fv(colorstack[--colorpos]);
|
||||
continue;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
case ' ':
|
||||
x += curfont->defaultw;
|
||||
continue;
|
||||
}
|
||||
|
||||
c -= 33;
|
||||
if(!curfont->chars.inrange(c)) continue;
|
||||
|
||||
font::charinfo &info = curfont->chars[c];
|
||||
float tc_left = (info.x + curfont->offsetx) / float(curfont->tex->xs);
|
||||
float tc_top = (info.y + curfont->offsety) / float(curfont->tex->ys);
|
||||
float tc_right = (info.x + info.w + curfont->offsetw) / float(curfont->tex->xs);
|
||||
float tc_bottom = (info.y + info.h + curfont->offseth) / float(curfont->tex->ys);
|
||||
|
||||
glTexCoord2f(tc_left, tc_top ); glVertex2f(x, y);
|
||||
glTexCoord2f(tc_right, tc_top ); glVertex2f(x + info.w, y);
|
||||
glTexCoord2f(tc_right, tc_bottom); glVertex2f(x + info.w, y + info.h);
|
||||
glTexCoord2f(tc_left, tc_bottom); glVertex2f(x, y + info.h);
|
||||
|
||||
xtraverts += 4;
|
||||
x += info.w + 1;
|
||||
}
|
||||
glColor4ub(color.x, color.y, color.z, a);
|
||||
TEXTSKELETON
|
||||
glEnd();
|
||||
if(cursor >= 0)
|
||||
{
|
||||
if(cx == INT_MIN) { cx = x; cy = y; }
|
||||
if(maxwidth != -1 && cx >= maxwidth) { cx = 0; cy += FONTH; }
|
||||
int cw = curfont->chars.inrange(cc-33) ? curfont->chars[cc-33].w + 1 : curfont->defaultw;
|
||||
rendercursor(left+cx, top+cy, cw);
|
||||
}
|
||||
#undef TEXTINDEX
|
||||
#undef TEXTTAB
|
||||
#undef TEXTWHITE
|
||||
#undef TEXTLINE
|
||||
#undef TEXTCOLOR
|
||||
#undef TEXTCHAR
|
||||
#undef TEXTWORD
|
||||
}
|
||||
|
||||
void reloadfonts()
|
||||
|
||||
@@ -508,6 +508,7 @@ template <class K, class T> struct hashtable
|
||||
inline char *newstring(size_t l) { return new char[l+1]; }
|
||||
inline char *newstring(const char *s, size_t l) { return s_strncpy(newstring(l), s, l+1); }
|
||||
inline char *newstring(const char *s) { return newstring(s, strlen(s)); }
|
||||
inline char *newstringbuf() { return newstring(_MAXDEFSTR-1); }
|
||||
inline char *newstringbuf(const char *s) { return newstring(s, _MAXDEFSTR-1); }
|
||||
|
||||
extern char *path(char *s);
|
||||
|
||||
Reference in New Issue
Block a user