Open m-7761 opened 5 years ago
I'd be happy to consider a pull request focused on this particular aspect of GLUI.
But if it has obvious side-effects, limitations or breaks compatibility, I would have reservations.
Have you pushed code to a repo where we can go peruse the details? Or you'd rather build the suspense?
Here is what I came up with today:
class Font
{
public:
int height;
void *font;
const char(*width)[256];
public: //Compatibility layer
inline const Font &operator=(void *font)const
{
Control *p = (Control*)this;
(char*&)p-=(char*)&p->font-(char*)p;
p->set_font(font); return *this;
}
inline operator void*()const{ return font; }
};
static const Font _glut_fonts[7];
It's worth noting that char_width
had taken a char
type. Therefore it could not exceed 128, and had it been negative would have accessed out-of-bounds memory. So the whole, hash-map like think is not even achieving anything. I had to double-check this morning that CHAR_WIDTH_HASH_SIZE is 128 in the original code.
The GLUT documentations says "Character to render (not confined to 8 bits). " however I believe freeglut is limited to 256. And I'm unsure what code-page it uses for its 8-bit values. So, I don't know why int
would have been chosen for that array, quadrupling its size, other than theoretically GLUT claims to support Unicode or something.
Here Font
replaces the void *font
member. The sizing methods are made inline
and the _glut_fonts
sizing caches are initialized the first time their font is selected.
It dawned on me last night that the default font semantics can be straightforward if set_font
locks in the font. To do that get_font
just returns the control's font pointer instead of looking for the default. And set_font
looks for a default, and finding none uses _glut_fonts[0]
. So Control::Control
just needs to call set_font(NULL)
. The downside is that [0]
always gets initialized. (I think that's unavoidable without adding a method to change which is [0]
and so change which font GLUI::GLUI
selects for itself.)
/*************** GLUI_Control::set_font() **********/
static char glui_control_char_widths[7][256];
const UI::Control::Font UI::Control::_glut_fonts[7] =
{
//glutBitmapHeight
//These hail from fg_font_data.c
{16,GLUT_BITMAP_HELVETICA_12},
{14,GLUT_BITMAP_HELVETICA_10},
{23,GLUT_BITMAP_HELVETICA_18},
{14,GLUT_BITMAP_TIMES_ROMAN_10},
{29,GLUT_BITMAP_TIMES_ROMAN_24},
{14,GLUT_BITMAP_8_BY_13},
{16,GLUT_BITMAP_9_BY_15},
};
void UI::Control::set_font(void *new_font)
{
int i;
if(!new_font) if(ui&&ui->font)
{
new_font = ui->font;
}
else goto use_default_font;
for(i=0;i<7;i++)
if(new_font==_glut_fonts[i].font)
{
break;
}
if(i==7) use_default_font:
{
i = 0; new_font = _glut_fonts[0].font;
}
if(!_glut_fonts[i].width)
{
char *w = glui_control_char_widths[i];
(void*&)_glut_fonts[i].width = w;
for(int i=0;i<256;i++)
w[i] = 0xFF&glutBitmapWidth(new_font,i);
}
const_cast<Font&>(font) = _glut_fonts[i]; redraw();
}
P.S. I'm going to have to really rethink the constructors. I think it will make sense to inherit the font from the parent in most cases. That will inherit the GLUI container, and it will, I think, avoid initializing [0]
as discussed too. The parent just has to be passed to the Control class's constructor.
The "main_panel" control may require a special, internal constructor to pull it off. The constructors will need to be inline
methods. Some of them that take a lot of arguments might be simplified with templates somehow, to avoid error-prone code. Mainly to deal with the live-variable type stuff.
Part of the reason for the following quote is likely that glui_textbox.cpp
abuses the hell out of substring_width
as if it is akin to magic.
/* Hash table for faster character width lookups - JVK
Speeds up the textbox a little bit.
*/
It's going to take some work to rewrite it. But basically in like 20 or 30 places there are loops that measure a string, add 1 character to the end, measure the whole string again, and so on, rather than just measuring the added character, and adding that to the total length. Whether that is significant work or not (it's hard to believe processing text could've caused detectable slowdown under any circumstances) it is definitely domestic abuse of your home computer.
You'd want to look the whole string to support Kerning, for example.
You'd want to look the whole string to support Kerning, for example.
The pattern is not sizing the string. It's sizing letter 1. Sizing letter 1,2. Next 1,2,3. And so on, up to the length of each touched line. It accounts for tabs. (I assume you know, but GLUT doesn't do kerning since it doesn't have a string rendering API, in case someone reading this gets the impression otherwise.)
Tonight I was looking at the font subroutines.
I noticed GLUT has a
glutBitmapLength
method that could replace the cache of widths currently stored (in a really zany way) in every single control.In my code I reduced the control cache to 128
char
sizers. Part of the reason trying to do anything for GLUI is miserable is back in 2017 even suggesting insane code like this required patching to be taken seriously was met with intense resistance!The
char_widths
field isint char_widths[128][2]
. Yeah, every control stores 1KB of useless memory, or more. 100 controls and you exceed the comment inglui.cpp
that says:Anyway, I've made the 256 char cache one per GLUT font, instead of per control. Assuming that's better (or at least simpler at this point) than
glutBitmapLength
. But also, the textbox control has a fixed height for fonts, set at 15 pixels. I'm now wondering what edittext uses.So I dug this out from the "freeglut" source code:
Assuming it holds for other versions of GLUT, this is the height of each of these fonts.
One problem that remains, is the controls fall back onto the GLUI object's font if their font is zeroed. To fix this somewhat I had the controls initialize their font stuff when added to the GLUI object. But it's not foolproof because the GLUI object's font pointer is exposed, and the control's is too. But at least controls have a
set_font
method.Anyway, that's the state of fonts. I just wanted to share the height information. And remind how sloppy things are, ahead of providing a major service in auditing/rewriting GLUI's code next week.