Size Font::get_text_size(Canvas &canvas, const std::string &text) { Size total_size; if (impl) { FontMetrics fm = get_font_metrics(); int line_spacing = fm.get_external_leading(); std::vector<std::string> lines = StringHelp::split_text(text, "\n", false); for (std::vector<std::string>::size_type i=0; i<lines.size(); i++) { Size line_size = impl->get_text_size(canvas, lines[i]); if ((line_size.width == 0) && (line_size.height == 0) && (lines.size() > 1)) // blank line line_size.height = fm.get_descent() + fm.get_ascent(); if ((i+1) != lines.size()) // Do not add the line spacing on the last line line_size.height += line_spacing; if (total_size.width < line_size.width) // Find the widest line total_size.width = line_size.width; total_size.height += line_size.height; } } return total_size; }
CL_Size CL_Font::get_text_size(CL_GraphicContext &gc, const CL_StringRef &text) { CL_Size total_size; if (!impl.is_null()) { CL_FontMetrics fm = get_font_metrics(gc); int line_spacing = fm.get_external_leading(); std::vector<CL_String> lines = CL_StringHelp::split_text(text, "\n", false); for (std::vector<CL_String>::size_type i=0; i<lines.size(); i++) { CL_Size line_size = get_provider()->get_text_size(gc, lines[i]); if ((line_size.width == 0) && (line_size.height == 0) && (lines.size() > 1)) // blank line line_size.height = fm.get_descent() + fm.get_ascent(); if ((i+1) != lines.size()) // Do not add the line spacing on the last line line_size.height += line_spacing; if (total_size.width < line_size.width) // Find the widest line total_size.width = line_size.width; total_size.height += line_size.height; } } return total_size; }
/*! Draws the text for the loading screen \author jfpatry */ void draw_loading_text( void ) { int w = getparam_x_resolution(); int h = getparam_y_resolution(); int x_org, y_org; const char *string; int string_w, asc, desc; font_t *font; x_org = w/2.0; y_org = h/2.0; if ( !get_font_binding( "loading", &font ) ) { print_warning( IMPORTANT_WARNING, "Couldn't get font for binding loading" ); } else { string = Localize("Loading, Please Wait...",""); get_font_metrics( font, string, &string_w, &asc, &desc ); glPushMatrix(); { glTranslatef( w/2.0 - string_w/2.0, h/2.0 - desc-30, 0 ); bind_font_texture( font ); draw_string( font, string ); } glPopMatrix(); } }
/*! Draws the listbox \return None \author jfpatry \date Created: 2000-09-18 \date Modified: 2000-09-18 */ void listbox_draw( listbox_t *listbox ) { font_t *font; check_assertion( listbox != NULL, "listbox is NULL" ); glDisable( GL_TEXTURE_2D ); if(listbox->background_colour.a != 0.0) { glColor4dv( (scalar_t*)&listbox->border_colour ); glRectf( listbox->pos.x, listbox->pos.y, listbox->pos.x + listbox->w - listbox->arrow_width, listbox->pos.y + listbox->h ); glColor4dv( (scalar_t*)&listbox->background_colour ); glRectf( listbox->pos.x + listbox->border_width, listbox->pos.y + listbox->border_width, listbox->pos.x + listbox->w - listbox->border_width - listbox->arrow_width, listbox->pos.y + listbox->h - listbox->border_width ); } glEnable( GL_TEXTURE_2D ); if ( !get_font_binding( listbox->font_binding, &font ) ) { print_warning( IMPORTANT_WARNING, "Couldn't get font object for binding %s", listbox->font_binding ); } else { int w, asc, desc; char *string; string = listbox->label_gen_func( get_list_elem_data( listbox->cur_item ) ); get_font_metrics( font, string, &w, &asc, &desc ); bind_font_texture( font ); glColor4f( 1.0, 1.0, 1.0, 1.0 ); glPushMatrix(); { glTranslatef( listbox->pos.x + listbox->border_width + listbox->text_pad, listbox->pos.y + listbox->h/2.0 - asc/2.0 + desc/2.0, 0 ); draw_string( font, string ); } glPopMatrix(); } button_draw( listbox->up_button ); button_draw( listbox->down_button ); }
void Font::draw_text_ellipsis(Canvas &canvas, float dest_x, float dest_y, Rectf content_box, const std::string &text, const Colorf &color) { if (impl) { FontMetrics fm = get_font_metrics(); int ascent = fm.get_ascent(); int descent = fm.get_descent(); int line_spacing = fm.get_height() + fm.get_external_leading(); std::vector<std::string> lines = StringHelp::split_text(text, "\n", false); for (std::vector<std::string>::size_type i=0; i<lines.size(); i++) { if (i == 0 || (dest_y - ascent >= content_box.top && dest_y + descent < content_box.bottom)) { Size size = get_text_size(canvas, lines[i]); if (dest_x + size.width <= content_box.right) { draw_text(canvas, dest_x, dest_y, lines[i], color); } else { Size ellipsis = get_text_size(canvas, "..."); int seek_start = 0; int seek_end = lines[i].size(); int seek_center = (seek_start + seek_end) / 2; UTF8_Reader utf8_reader(lines[i].data(), lines[i].length()); while (true) { utf8_reader.set_position(seek_center); utf8_reader.move_to_leadbyte(); if (seek_center != utf8_reader.get_position()) utf8_reader.next(); seek_center = utf8_reader.get_position(); if (seek_center == seek_end) break; utf8_reader.set_position(seek_start); utf8_reader.next(); if (utf8_reader.get_position() == seek_end) break; Size text_size = get_text_size(canvas, lines[i].substr(0, seek_center)); if (dest_x + text_size.width + ellipsis.width >= content_box.right) seek_end = seek_center; else seek_start = seek_center; seek_center = (seek_start+seek_end)/2; } draw_text(canvas, dest_x, dest_y, lines[i].substr(0, seek_center) + "...", color); } dest_y += line_spacing; } } } }
int CL_GlyphCache::get_character_index(CL_FontEngine *font_engine, CL_GraphicContext &gc, const CL_String &text, const CL_Point &point) { int dest_x = 0; int dest_y = 0; int character_counter = 0; CL_FontMetrics fm = get_font_metrics(); int font_height = fm.get_height(); int font_ascent = fm.get_ascent(); int font_external_leading = fm.get_external_leading(); std::vector<CL_String> lines = CL_StringHelp::split_text(text, "\n", false); for (std::vector<CL_String>::size_type i=0; i<lines.size(); i++) { int xpos = dest_x; int ypos = dest_y; CL_String &textline = lines[i]; CL_String::size_type string_length = textline.length(); // Scan the string CL_UTF8_Reader reader(textline); while(!reader.is_end()) { unsigned int glyph = reader.get_char(); CL_String::size_type glyph_pos = reader.get_position(); reader.next(); CL_Font_TextureGlyph *gptr = get_glyph(font_engine, gc, glyph); if (gptr == NULL) continue; CL_Rect position(xpos, ypos - font_ascent, CL_Size(gptr->increment.x, gptr->increment.y + font_height + font_external_leading)); if (position.contains(point)) { return glyph_pos + character_counter; } xpos += gptr->increment.x; ypos += gptr->increment.y; } dest_y += font_height + font_external_leading; character_counter += string_length + 1; // (Including the '\n') } return -1; // Not found }
void Font::draw_text(Canvas &canvas, float dest_x, float dest_y, const std::string &text, const Colorf &color) { if (impl) { FontMetrics fm = get_font_metrics(); int line_spacing = fm.get_height() + fm.get_external_leading(); std::vector<std::string> lines = StringHelp::split_text(text, "\n", false); for (std::vector<std::string>::size_type i=0; i<lines.size(); i++) { impl->draw_text(canvas, dest_x, dest_y, lines[i], color); dest_y += line_spacing; } } }
void CL_Font::draw_text(CL_GraphicContext &gc, float dest_x, float dest_y, const CL_StringRef &text, const CL_Colorf &color) { if (!impl.is_null()) { CL_FontMetrics fm = get_font_metrics(gc); int line_spacing = fm.get_height() + fm.get_external_leading(); std::vector<CL_String> lines = CL_StringHelp::split_text(text, "\n", false); for (std::vector<CL_String>::size_type i=0; i<lines.size(); i++) { get_provider()->draw_text(gc, dest_x, dest_y, lines[i], color); dest_y += line_spacing; } } }
int FontProvider_Sprite::get_character_index(GraphicContext &gc, const std::string &text, const Point &point) { int dest_x = 0; int dest_y = 0; int character_counter = 0; FontMetrics fm = get_font_metrics(); int font_height = fm.get_height(); int font_external_leading = fm.get_external_leading(); std::vector<std::string> lines = StringHelp::split_text(text, "\n", false); for (std::vector<std::string>::size_type i=0; i<lines.size(); i++) { int xpos = dest_x; int ypos = dest_y; std::string &textline = lines[i]; std::string::size_type string_length = textline.length(); // Scan the string for (std::string::size_type p = 0; p < string_length; p++) { Font_Sprite_Glyph *gptr = get_glyph(textline[p]); int glyph_width; if (gptr) { glyph_width = spr_glyphs.get_frame_size(gptr->sprite_index).width; } else { glyph_width = spacelen; } Rect position(xpos, ypos - font_height, Size(glyph_width, font_height + font_external_leading)); if (position.contains(point)) return ((int) p) + character_counter; xpos += glyph_width; } dest_y += font_height + font_external_leading; character_counter += string_length + 1; // (Including the '\n') } return -1; // Not found }
font_t* clone_font(const font_t* src_font) { font_t* font = NULL; int max_x = 0, max_y = 0; int min_width = INT_MAX; const struct font_glyph* src_glyph; uint32_t i; console_log(2, "cloning font #%u from source font #%u", s_next_font_id, src_font->id); if (!(font = calloc(1, sizeof(font_t)))) goto on_error; if (!(font->glyphs = calloc(src_font->num_glyphs, sizeof(struct font_glyph)))) goto on_error; font->num_glyphs = src_font->num_glyphs; // perform the clone get_font_metrics(src_font, &min_width, &max_x, &max_y); font->height = max_y; font->min_width = min_width; font->max_width = max_x; for (i = 0; i < src_font->num_glyphs; ++i) { src_glyph = &src_font->glyphs[i]; font->glyphs[i].image = ref_image(src_glyph->image); font->glyphs[i].width = src_glyph->width; font->glyphs[i].height = src_glyph->height; } font->id = s_next_font_id++; return ref_font(font); on_error: if (font != NULL) { for (i = 0; i < font->num_glyphs; ++i) { if (font->glyphs[i].image != NULL) free_image(font->glyphs[i].image); } free(font->glyphs); free(font); } return NULL; }
/*! Scrolls the credits text up the screen. \author jfpatry \date Created: 2000-09-27 \date Modified: 2000-09-27 */ static void draw_credits_text( scalar_t time_step ) { int w = getparam_x_resolution(); int h = getparam_y_resolution(); font_t* font; coord_t text_coord; int i, string_w, asc, desc; scalar_t y; y_offset += time_step * winsys_scale(CREDITS_SPEED + time_step*joystick_y*CREDITS_JOYSTICK_SPEED); if (y_offset<0) { y_offset=0; } y = CREDITS_MIN_Y+y_offset; text_coord.x=w/2; text_coord.y=y; text_coord.x_coord_type=ABSOLUTE_COORD; text_coord.y_coord_type=ABSOLUTE_COORD; text_coord.x_just=text_coord.y_just=CENTER_JUST; for (i=0; i<sizeof( credit_lines ) / sizeof( credit_lines[0] ); i++) { credit_line_t line = credit_lines[i]; if ( !get_font_binding( line.binding, &font ) ) { print_warning( IMPORTANT_WARNING, "Couldn't get font for binding %s", line.binding ); } else { get_font_metrics( font, line.text, &string_w, &asc, &desc ); text_coord.y -= asc+desc; GameMenu_draw_text( line.text, 0, text_coord, line.binding ); } } if ( text_coord.y > h+CREDITS_MAX_Y ) { go_back(); } }
static GpStatus find_installed_font(const WCHAR *name, struct font_metrics *fm) { LOGFONTW lf; HDC hdc = CreateCompatibleDC(0); GpStatus ret = FontFamilyNotFound; if(!EnumFontFamiliesW(hdc, name, is_font_installed_proc, (LPARAM)&lf)) { HFONT hfont, old_font; hfont = CreateFontIndirectW(&lf); old_font = SelectObject(hdc, hfont); ret = get_font_metrics(hdc, fm) ? Ok : NotTrueTypeFont; SelectObject(hdc, old_font); DeleteObject(hfont); } DeleteDC(hdc); return ret; }
static void set_widget_positions_and_draw_decorations() { int h = getparam_y_resolution(); int box_width, box_height, box_max_y; int x_org, y_org; char *string; font_t *font; int text_width, asc, desc; list_t cup_list; GLuint texobj; #ifdef __APPLE__ /* set the dimensions of the box in which all widgets should fit */ box_width = 300; box_height = 310; box_max_y = h - 128; x_org = 10; y_org = h/2 - box_height/2; if ( y_org + box_height > box_max_y ) { y_org = box_max_y - box_height; } button_set_position( back_btn, make_point2d( x_org + 40 - button_get_width( back_btn )/2.0, 12 ) ); button_set_position( continue_btn, make_point2d( x_org + 232 - button_get_width( continue_btn )/2.0, 12 ) ); button_set_position( howToPlay_btn, make_point2d( x_org + 160 - button_get_width( continue_btn )/2.0, 100 ) ); //Out of the field of view //in Tux Rider World Challenge, there is no more events and cup, just training //I'm adapting from The Tux Racer system by selecting the first and only event //I hide its list box out of the field of view //and each cup for this event is a training listbox_set_position( event_listbox, make_point2d( x_org+500, y_org + 500 ) ); listbox_set_position( cup_listbox, make_point2d( x_org+50, y_org + 193 ) ); #else int w = getparam_x_resolution(); /* set the dimensions of the box in which all widgets should fit */ box_width = 460; box_height = 310; box_max_y = h - 128; x_org = w/2 - box_width/2; y_org = h/2 - box_height/2; if ( y_org + box_height > box_max_y ) { y_org = box_max_y - box_height; } button_set_position( back_btn, make_point2d( x_org + 131 - button_get_width( back_btn )/2.0, 42 ) ); button_set_position( continue_btn, make_point2d( x_org + 329 - button_get_width( continue_btn )/2.0, 42 ) ); listbox_set_position( cup_listbox, make_point2d( x_org + 52, y_org + 103 ) ); listbox_set_position( event_listbox, make_point2d( x_org + 52, y_org + 193 ) ); #endif /* * Draw other stuff */ /* Event & cup icons */ if ( !get_texture_binding( get_event_icon_texture_binding( event_data ), &texobj ) ) { texobj = 0; } glBindTexture( GL_TEXTURE_2D, texobj ); glBegin( GL_QUADS ); { point2d_t tll, tur; point2d_t ll, ur; #ifdef __APPLE__ //out of the field of view ll = make_point2d( x_org, y_org + 500 ); ur = make_point2d( x_org + 44, y_org + 500 + 44 ); tll = make_point2d( 0, 0 ); tur = make_point2d( 44.0/64.0, 44.0/64.0 ); #else ll = make_point2d( x_org, y_org + 193 ); ur = make_point2d( x_org + 44, y_org + 193 + 44 ); tll = make_point2d( 0, 0 ); tur = make_point2d( 44.0/64.0, 44.0/64.0 ); #endif glTexCoord2f( tll.x, tll.y ); glVertex2f( ll.x, ll.y ); glTexCoord2f( tur.x, tll.y ); glVertex2f( ur.x, ll.y ); glTexCoord2f( tur.x, tur.y ); glVertex2f( ur.x, ur.y ); glTexCoord2f( tll.x, tur.y ); glVertex2f( ll.x, ur.y ); } glEnd(); if ( !get_texture_binding( get_cup_icon_texture_binding( (cup_data_t*) get_list_elem_data( cur_cup ) ), &texobj ) ) { texobj = 0; } glBindTexture( GL_TEXTURE_2D, texobj ); #ifdef __APPLE__DISABLED__ { point2d_t tll, tur; point2d_t ll, ur; ll = make_point2d( x_org, y_org + 103 ); ur = make_point2d( x_org + 44, y_org + 103 + 44 ); tll = make_point2d( 0, 0 ); tur = make_point2d( 44.0/64.0, 44.0/64.0 ); const GLfloat vertices []= { ll.x, ll.y, ur.x, ll.y, ur.x, ur.y, ll.x, ur.y }; const GLfloat texCoords []= { tll.x, tll.y, tur.x, tll.y, tur.x, tur.y, tll.x, tur.y, }; glEnableClientState (GL_VERTEX_ARRAY); glVertexPointer (2, GL_FLOAT , 0, vertices); glTexCoordPointer(2, GL_FLOAT, 0, texCoords); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } #else glBegin( GL_QUADS ); { point2d_t tll, tur; point2d_t ll, ur; #ifdef __APPLE__ ll = make_point2d( x_org, y_org + 193 ); ur = make_point2d( x_org + 44, y_org + 193 + 44 ); tll = make_point2d( 0, 0 ); tur = make_point2d( 44.0/64.0, 44.0/64.0 ); #else ll = make_point2d( x_org, y_org + 103 ); ur = make_point2d( x_org + 44, y_org + 103 + 44 ); tll = make_point2d( 0, 0 ); tur = make_point2d( 44.0/64.0, 44.0/64.0 ); #endif glTexCoord2f( tll.x, tll.y ); glVertex2f( ll.x, ll.y ); glTexCoord2f( tur.x, tll.y ); glVertex2f( ur.x, ll.y ); glTexCoord2f( tur.x, tur.y ); glVertex2f( ur.x, ur.y ); glTexCoord2f( tll.x, tur.y ); glVertex2f( ll.x, ur.y ); } glEnd(); #endif if ( !get_font_binding( "menu_label", &font ) ) { print_warning( IMPORTANT_WARNING, "Couldn't get font for binding menu_label" ); } else { bind_font_texture( font ); #ifdef __APPLE__ string = "Select a training"; #else string = "Select event and cup"; #endif get_font_metrics( font, string, &text_width, &asc, &desc ); glPushMatrix(); { glTranslatef( x_org + box_width/2.0 - text_width/2.0, y_org + 310 - asc, 0 ); draw_string( font, string ); } glPopMatrix(); } if ( !get_font_binding( "event_and_cup_label", &font ) ) { print_warning( IMPORTANT_WARNING, "Couldn't get font for binding menu_label" ); } #ifdef __APPLE__ cur_event = listbox_get_current_item( event_listbox ); event_data = (event_data_t*) get_list_elem_data( cur_event ); cup_list = get_event_cup_list( event_data ); cur_cup = listbox_get_current_item( cup_listbox ); if ( is_cup_complete( event_data, cur_cup ) ) { string = "You've won this Training !"; } else if ( is_cup_first_incomplete_cup( event_data, cur_cup ) ) { string = "You must complete this training first"; } else { string = "You cannot enter this training yet"; } if ( !get_font_binding( "cup_status", &font ) ) { print_warning( IMPORTANT_WARNING, "Couldn't get font for binding cup_status" ); } else { bind_font_texture( font ); get_font_metrics( font, string, &text_width, &asc, &desc ); glPushMatrix(); { glTranslatef( x_org + box_width/2.0 - text_width/2.0, y_org+140, 0 ); draw_string( font, string ); } glPopMatrix(); } #else else {
/*! Draws a button widget \return None \author jfpatry \date Created: 2000-09-18 \date Modified: 2000-09-18 */ void button_draw( button_t *button ) { GLuint texobj; texture_region_t *tex; point2d_t pos; scalar_t w, h; char *font_binding; check_assertion( button != NULL, "button is NULL" ); pos = button->pos; w = button->w; h = button->h; glEnable( GL_TEXTURE_2D ); tex = NULL; font_binding = NULL; if ( !button->enabled ) { if ( button->disabled_tex.binding ) { tex = &button->disabled_tex; } else if ( button->tex.binding ) { tex = &button->tex; } if ( button->disabled_font_binding ) { font_binding = button->disabled_font_binding; } else if ( button->font_binding ) { font_binding = button->font_binding; } } else if ( button->clicked ) { if ( button->clicked_tex.binding ) { tex = &button->clicked_tex; } else if ( button->hilit_tex.binding ) { tex = &button->hilit_tex; } else if ( button->tex.binding ) { tex = &button->tex; } if ( button->hilit_font_binding ) { font_binding = button->hilit_font_binding; } else if ( button->font_binding ) { font_binding = button->font_binding; } } else if ( button->focused ) { if ( button->hilit_tex.binding ) { tex = &button->hilit_tex; } else if ( button->tex.binding ) { tex = &button->tex; } if ( button->hilit_font_binding ) { font_binding = button->hilit_font_binding; } else if ( button->font_binding ) { font_binding = button->font_binding; } } else { if ( button->tex.binding ) { tex = &button->tex; } if ( button->font_binding ) { font_binding = button->font_binding; } } if ( tex != NULL ) { if ( !get_texture_binding( tex->binding, &texobj ) ) { print_warning( IMPORTANT_WARNING, "Couldnt get texture object for binding %s", tex->binding ); texobj = 0; } glBindTexture( GL_TEXTURE_2D, texobj ); glColor4dv( (scalar_t*) &tex->colour ); glBegin( GL_QUADS ); { glTexCoord2f( tex->ll.x, tex->ll.y ); glVertex3f( pos.x, pos.y, 0 ); glTexCoord2f( tex->ur.x, tex->ll.y ); glVertex3f( pos.x + w, pos.y, 0 ); glTexCoord2f( tex->ur.x, tex->ur.y ); glVertex3f( pos.x + w, pos.y + h, 0 ); glTexCoord2f( tex->ll.x, tex->ur.y ); glVertex3f( pos.x, pos.y + h, 0 ); } glEnd(); } if ( font_binding && button->label != NULL ) { font_t *font; int w, asc, desc; if (!get_font_binding( font_binding, &font )) { print_warning( IMPORTANT_WARNING, "Couldn't get font object for binding %s", font_binding ); font = NULL; } else { bind_font_texture( font ); get_font_metrics( font, button->label, &w, &asc, &desc ); glPushMatrix(); { glTranslatef( button->pos.x + button->w/2.0 - w/2.0, button->pos.y + button->h/2.0 - asc/2.0 + desc/2.0, 0.0 ); draw_string( font, button->label ); } glPopMatrix(); } } }
static void advance( font_t *font, char *string ) { int w, a, d; get_font_metrics( font, string, &w, &a, &d ); glTranslatef( w, 0, 0 ); }
/*! Sets the widget positions and draws other on-screen goo \author jfpatry \date Created: 2000-09-24 \date Modified: 2000-09-24 */ static void set_widget_positions_and_draw_decorations() { int w = getparam_x_resolution(); int h = getparam_y_resolution(); int box_width, box_height, box_max_y; int x_org, y_org; char *string; font_t *font; char *current_course; int text_width, asc, desc; GLuint texobj; /* set the dimensions of the box in which all widgets should fit */ #ifdef __APPLE__ box_width = w; box_height = 200 * mHeight / 320; box_max_y = h - 128 * mHeight / 320; x_org = 10 * mHeight / 320; y_org = box_height/2 * mHeight / 320; if ( y_org + box_height > box_max_y ) { y_org = box_max_y - box_height + 50 * mHeight / 320; } button_set_position( back_btn, make_point2d( 0, 0 ) ); button_set_position( start_btn, make_point2d( box_width - button_get_width( start_btn ), 0 ) ); listbox_set_position( race_listbox, make_point2d( 160 * mHeight / 320, box_height/2.0+40 * mHeight / 320 ) ); #ifdef __APPLE__ textarea_set_position( desc_ta, make_point2d( 1000, 1000 ) ); #else textarea_set_position( desc_ta, make_point2d( x_org, y_org + 66 * mHeight / 320 ) ); #endif if ( g_game.practicing || ( cup_complete && conditions_ssbtn && wind_ssbtn && snow_ssbtn && mirror_ssbtn ) ) { ssbutton_set_position( conditions_ssbtn, make_point2d( x_org + box_width - 4*36 + 4, y_org + 151 ) ); ssbutton_set_position( wind_ssbtn, make_point2d( x_org + box_width - 3*36 + 4 , y_org + 151 ) ); ssbutton_set_position( snow_ssbtn, make_point2d( x_org + box_width - 2*36 + 4, y_org + 151 ) ); ssbutton_set_position( mirror_ssbtn, make_point2d( x_org + box_width - 1*36 + 4, y_org + 151 ) ); #else box_width = 460; box_height = 310; box_max_y = h - 128; x_org = w/2 - box_width/2; y_org = h/2 - box_height/2; if ( y_org + box_height > box_max_y ) { y_org = box_max_y - box_height; } button_set_position( back_btn, make_point2d( x_org + 131 - button_get_width( back_btn )/2.0, 42 ) ); button_set_position( start_btn, make_point2d( x_org + 343 - button_get_width( start_btn )/2.0, 42 ) ); listbox_set_position( race_listbox, make_point2d( x_org, y_org + 221 ) ); textarea_set_position( desc_ta, make_point2d( x_org, y_org + 66 ) ); if ( g_game.practicing || ( cup_complete && conditions_ssbtn && wind_ssbtn && snow_ssbtn && mirror_ssbtn ) ) { ssbutton_set_position( conditions_ssbtn, make_point2d( x_org + box_width - 4*36 + 4, y_org + 181 ) ); ssbutton_set_position( wind_ssbtn, make_point2d( x_org + box_width - 3*36 + 4 , y_org + 181 ) ); ssbutton_set_position( snow_ssbtn, make_point2d( x_org + box_width - 2*36 + 4, y_org + 181 ) ); ssbutton_set_position( mirror_ssbtn, make_point2d( x_org + box_width - 1*36 + 4, y_org + 181 ) ); #endif } else { /* Draw tux life icons */ GLuint texobj; int i; glPushMatrix(); { #ifdef __APPLE__ glTranslatef( 10 * mHeight / 320, 60 * mHeight / 320, 0 ); #else glTranslatef( x_org + box_width - 4*36 + 4, y_org + 181, 0 ); #endif check_assertion( INIT_NUM_LIVES == 4, "Assumption about number of lives invalid -- " "need to recode this part" ); if ( !get_texture_binding( "tux_life", &texobj ) ) { texobj = 0; } glBindTexture( GL_TEXTURE_2D, texobj ); for ( i=0; i<4; i++ ) { point2d_t ll, ur; if ( plyr->lives > i ) { ll = make_point2d( 0, 0.5 ); ur = make_point2d( 1, 1 ); } else { ll = make_point2d( 0, 0 ); ur = make_point2d( 1, 0.5 ); } glBegin( GL_QUADS ); { glTexCoord2f( ll.x, ll.y ); glVertex2f( 0, 0 ); glTexCoord2f( ur.x, ll.y ); glVertex2f( 32 * mHeight / 320, 0 ); glTexCoord2f( ur.x, ur.y ); glVertex2f( 32 * mHeight / 320, 32 * mHeight / 320 ); glTexCoord2f( ll.x, ur.y ); glVertex2f( 0, 32 * mHeight / 320 ); } glEnd(); glTranslatef( 36 * mHeight / 320, 0, 0 ); } } glPopMatrix(); } #ifndef __APPLE__ // We don't care about that stuff /* Draw other stuff */ if ( !get_font_binding( "menu_label", &font ) ) { print_warning( IMPORTANT_WARNING, "Couldn't get font for binding menu_label" ); } else { bind_font_texture( font ); string = "Select a race"; get_font_metrics( font, string, &text_width, &asc, &desc ); glPushMatrix(); { glTranslatef( x_org + box_width/2.0 - text_width/2.0, y_org + 310 - asc, 0 ); draw_string( font, string ); } glPopMatrix(); } /* Draw text indicating race requirements (if race not completed), or results in race if race completed. */ draw_status_msg( x_org, y_org, box_width, box_height ); #else /* Draw text indicating race requirements (if race not completed), or results in race if race completed. */ draw_status_msg( x_org, y_org, box_width, box_height ); #endif /* Draw preview */ if ( g_game.practicing ) { list_elem_t elem; open_course_data_t *data; elem = listbox_get_current_item( race_listbox ); data = (open_course_data_t*) get_list_elem_data( elem ); current_course = data->course; } else { list_elem_t elem; race_data_t *data; elem = listbox_get_current_item( race_listbox ); data = (race_data_t*) get_list_elem_data( elem ); current_course = data->course; } glDisable( GL_TEXTURE_2D ); glColor4f( 0.0, 0.0, 0.0, 0.3 ); #ifdef __APPLE__ float margin = 4.f * mHeight / 320; float yoffset = 26 * mHeight / 320 + 30 * mHeight / 320; glBegin( GL_QUADS ); { glVertex2f( x_org, y_org + yoffset ); glVertex2f( x_org + 140 * mHeight / 320, y_org + yoffset ); glVertex2f( x_org + 140 * mHeight / 320, y_org + yoffset+107 * mHeight / 320 ); glVertex2f( x_org, y_org + yoffset+107 * mHeight / 320 ); } glEnd(); #else glBegin( GL_QUADS ); { glVertex2f( x_org+box_width-140, y_org+66 ); glVertex2f( x_org+box_width, y_org+66 ); glVertex2f( x_org+box_width, y_org+66+107 ); glVertex2f( x_org+box_width-140, y_org+66+107 ); } glEnd(); #endif glColor4f( 1.0, 1.0, 1.0, 1.0 ); glEnable( GL_TEXTURE_2D ); if ( !get_texture_binding( current_course, &texobj ) ) { if ( !get_texture_binding( "no_preview", &texobj ) ) { texobj = 0; } } glBindTexture( GL_TEXTURE_2D, texobj ); #ifdef __APPLE__ glBegin( GL_QUADS ); { glTexCoord2d( 0, 0); glVertex2f( x_org + margin, y_org + yoffset+margin ); glTexCoord2d( 1, 0); glVertex2f( x_org + 140 * mHeight / 320 - margin, y_org + yoffset+margin ); glTexCoord2d( 1, 1); glVertex2f( x_org + 140 * mHeight / 320 - margin, y_org + yoffset+margin+99 * mHeight / 320 ); glTexCoord2d( 0, 1); glVertex2f( x_org + margin, y_org + yoffset+margin+99 * mHeight / 320 ); } glEnd(); #else glBegin( GL_QUADS ); { glTexCoord2d( 0, 0); glVertex2f( x_org+box_width-136, y_org+70 ); glTexCoord2d( 1, 0); glVertex2f( x_org+box_width-4, y_org+70 ); glTexCoord2d( 1, 1); glVertex2f( x_org+box_width-4, y_org+70+99 ); glTexCoord2d( 0, 1); glVertex2f( x_org+box_width-136, y_org+70+99 ); } glEnd(); #endif } /*---------------------------------------------------------------------------*/ /*! Mode initialization function \author jfpatry \date Created: 2000-09-24 \date Modified: 2000-09-24 */ static void race_select_init(void) { listbox_list_elem_to_string_fptr_t conv_func = NULL; point2d_t dummy_pos = {0, 0}; int i; winsys_set_display_func( main_loop ); winsys_set_idle_func( main_loop ); winsys_set_reshape_func( reshape ); winsys_set_mouse_func( ui_event_mouse_func ); winsys_set_motion_func( ui_event_motion_func ); winsys_set_passive_motion_func( ui_event_motion_func ); plyr = get_player_data( local_player() ); /* Setup the race list */ if ( g_game.practicing ) { g_game.current_event = "__Practice_Event__"; g_game.current_cup = "__Practice_Cup__"; race_list = get_open_courses_list(); conv_func = get_name_from_open_course_data; cup_data = NULL; last_completed_race = NULL; event_data = NULL; } else { event_data = (event_data_t*) get_list_elem_data( get_event_by_name( g_game.current_event ) ); check_assertion( event_data != NULL, "Couldn't find current event." ); cup_data = (cup_data_t*) get_list_elem_data( get_event_cup_by_name( event_data, g_game.current_cup ) ); check_assertion( cup_data != NULL, "Couldn't find current cup." ); race_list = get_cup_race_list( cup_data ); conv_func = get_name_from_race_data; } /* Unless we're coming back from a race, initialize the race data to defaults. */ if ( g_game.prev_mode != GAME_OVER ) { /* Make sure we don't play previously loaded course */ cup_complete = False; /* Initialize the race data */ cur_elem = get_list_head( race_list ); if ( g_game.practicing ) { g_game.race.course = NULL; g_game.race.name = NULL; g_game.race.description = NULL; for (i=0; i<DIFFICULTY_NUM_LEVELS; i++) { g_game.race.herring_req[i] = 0; g_game.race.time_req[i] = 0; g_game.race.score_req[i] = 0; } g_game.race.mirrored = False; g_game.race.conditions = RACE_CONDITIONS_SUNNY; g_game.race.windy = False; g_game.race.snowing = False; } else { /* Not practicing */ race_data_t *data; data = (race_data_t*) get_list_elem_data( cur_elem ); g_game.race = *data; if ( is_cup_complete( event_data, get_event_cup_by_name( event_data, g_game.current_cup ) ) ) { cup_complete = True; last_completed_race = get_list_tail( race_list ); } else { cup_complete = False; last_completed_race = NULL; } } } else { /* Back from a race */ if ( !g_game.race_aborted ) { update_race_results(); } if (!g_game.practicing && !cup_complete) { if ( was_current_race_won() ) { update_for_won_race(); /* Advance to next race */ if ( cur_elem != get_list_tail( race_list ) ) { cur_elem = get_next_list_elem( race_list, cur_elem ); } } else { /* lost race */ plyr->lives -= 1; } print_debug( DEBUG_GAME_LOGIC, "Current lives: %d", plyr->lives ); } } back_btn = button_create( dummy_pos, 80 * mWidth / 480, 48 * mHeight / 320, "button_label", (mWidth>320)?"Back":"<< " ); button_set_hilit_font_binding( back_btn, "button_label_hilit" ); button_set_visible( back_btn, True ); button_set_click_event_cb( back_btn, back_click_cb, NULL ); start_btn = button_create( dummy_pos, 80 * mWidth / 480, 48 * mHeight / 320, "button_label", (mWidth>320)?"Race":" >>" ); button_set_hilit_font_binding( start_btn, "button_label_hilit" ); button_set_disabled_font_binding( start_btn, "button_label_disabled" ); button_set_visible( start_btn, True ); button_set_click_event_cb( start_btn, start_click_cb, NULL ); #ifdef __APPLE__ race_listbox = listbox_create( dummy_pos, mWidth - 170 * mHeight / 320, 44 * mHeight / 320, "course_name_label", race_list, conv_func ); #else race_listbox = listbox_create( dummy_pos, 460 * mHeight / 320, 44 * mHeight / 320, "listbox_item", race_list, conv_func ); #endif listbox_set_current_item( race_listbox, cur_elem ); listbox_set_item_change_event_cb( race_listbox, race_listbox_item_change_cb, NULL ); listbox_set_visible( race_listbox, True ); /* * Create text area */ #ifdef __APPLE__ desc_ta = textarea_create( dummy_pos, 150, 147, "race_description", "" ); #else desc_ta = textarea_create( dummy_pos, 312, 107, "race_description", "" ); #endif if ( g_game.practicing ) { open_course_data_t *data; data = (open_course_data_t*) get_list_elem_data( cur_elem ); textarea_set_text( desc_ta, data->description ); } else { race_data_t *data; data = (race_data_t*) get_list_elem_data( cur_elem ); textarea_set_text( desc_ta, data->description ); } textarea_set_visible( desc_ta, True ); /* * Create state buttons - only if practicing or if cup_complete */ if ( g_game.practicing || cup_complete ) { /* mirror */ mirror_ssbtn = ssbutton_create( dummy_pos, 32, 32, 2 ); ssbutton_set_state_image( mirror_ssbtn, 0, "mirror_button", make_point2d( 0.0/64.0, 32.0/64.0 ), make_point2d( 32.0/64.0, 64.0/64.0 ), white ); ssbutton_set_state_image( mirror_ssbtn, 1, "mirror_button", make_point2d( 32.0/64.0, 32.0/64.0 ), make_point2d( 64.0/64.0, 64.0/64.0 ), white ); ssbutton_set_state( mirror_ssbtn, (int)g_game.race.mirrored ); #ifdef __APPLE__ ssbutton_set_visible( mirror_ssbtn, False ); #else ssbutton_set_visible( mirror_ssbtn, True ); #endif /* conditions */ conditions_ssbtn = ssbutton_create( dummy_pos, 32, 32, 4 ); float border = 2.0; ssbutton_set_state_image( conditions_ssbtn, 0, "conditions_button", make_point2d( (0.0 + border)/64.0, (32.0 + border)/64.0 ), make_point2d( (32.0 - border)/64.0, (64.0 - border)/64.0 ), white ); ssbutton_set_state_image( conditions_ssbtn, 1, "conditions_button", make_point2d( (32.0 + border)/64.0, (0.0 + border)/64.0 ), make_point2d( (64.0 - border)/64.0, (32.0 - border)/64.0 ), white ); ssbutton_set_state_image( conditions_ssbtn, 2, "conditions_button", make_point2d( (32.0 + border)/64.0, (32.0 + border)/64.0 ), make_point2d( (64.0 - border)/64.0, (64.0 - border)/64.0 ), white ); ssbutton_set_state_image( conditions_ssbtn, 3, "conditions_button", make_point2d( (0.0 + border)/64.0, (0.0 + border)/64.0 ), make_point2d( (32.0 - border)/64.0, (32.0 - border)/64.0 ), white ); ssbutton_set_state( conditions_ssbtn, (int)g_game.race.conditions ); ssbutton_set_visible( conditions_ssbtn, True ); #ifdef __APPLE__ ssbutton_set_visible( conditions_ssbtn, False ); #else ssbutton_set_visible( conditions_ssbtn, True ); #endif /* wind */ wind_ssbtn = ssbutton_create( dummy_pos, 32, 32, 2 ); ssbutton_set_state_image( wind_ssbtn, 0, "wind_button", make_point2d( 0.0/64.0, 32.0/64.0 ), make_point2d( 32.0/64.0, 64.0/64.0 ), white ); ssbutton_set_state_image( wind_ssbtn, 1, "wind_button", make_point2d( 32.0/64.0, 32.0/64.0 ), make_point2d( 64.0/64.0, 64.0/64.0 ), white ); ssbutton_set_state( wind_ssbtn, (int)g_game.race.windy ); #ifdef __APPLE__ ssbutton_set_visible( wind_ssbtn, False ); #else ssbutton_set_visible( wind_ssbtn, True ); #endif /* snow */ snow_ssbtn = ssbutton_create( dummy_pos, 32, 32, 2 ); ssbutton_set_state_image( snow_ssbtn, 0, "snow_button", make_point2d( 0.0/64.0, 32.0/64.0 ), make_point2d( 32.0/64.0, 64.0/64.0 ), white ); ssbutton_set_state_image( snow_ssbtn, 1, "snow_button", make_point2d( 32.0/64.0, 32.0/64.0 ), make_point2d( 64.0/64.0, 64.0/64.0 ), white ); ssbutton_set_state( snow_ssbtn, (int)g_game.race.snowing ); #ifdef __APPLE__ ssbutton_set_visible( snow_ssbtn, False ); #else ssbutton_set_visible( snow_ssbtn, True ); #endif /* XXX snow button doesn't do anything, so disable for now */ ssbutton_set_enabled( snow_ssbtn, False ); /* Can't change conditions if in cup mode */ if ( !g_game.practicing ) { ssbutton_set_enabled( conditions_ssbtn, False ); ssbutton_set_enabled( wind_ssbtn, False ); ssbutton_set_enabled( snow_ssbtn, False ); ssbutton_set_enabled( mirror_ssbtn, False ); } } else { conditions_ssbtn = NULL; wind_ssbtn = NULL; snow_ssbtn = NULL; mirror_ssbtn = NULL; } update_race_data(); update_button_enabled_states(); play_music( "start_screen" ); }
/*! Draws the text for the game over screen \author jfpatry \date Created: 2000-09-24 \date Modified: 2000-09-24 */ void draw_game_over_text( void ) { int w = getparam_x_resolution(); int h = getparam_y_resolution(); int x_org, y_org; int box_width, box_height; const char *string; int string_w, asc, desc; char buff[BUFF_LEN]; font_t *font; font_t *stat_label_font; player_data_t *plyr = get_player_data( local_player() ); box_width = 200; box_height = 250; x_org = w/2.0 - box_width/2.0; y_org = h/2.0 - box_height/2.0; if ( !get_font_binding( "race_over", &font ) ) { print_warning( IMPORTANT_WARNING, "Couldn't get font for binding race_over" ); } else { if ( !g_game.race_aborted && g_game.practicing && g_game.needs_save_or_display_rankings) { string = Localize("World rankings", ""); } else string = Localize("Race Over", ""); get_font_metrics( font, string, &string_w, &asc, &desc ); glPushMatrix(); { glTranslatef( x_org + box_width/2.0 - string_w/2.0, y_org + box_height - asc, 0 ); bind_font_texture( font ); draw_string( font, string ); } glPopMatrix(); } /* If race was aborted, don't print stats, and if doesnt need to print rankings, dont print them */ if ( !g_game.race_aborted && !g_game.needs_save_or_display_rankings && g_game.practicing) { if ( !get_font_binding( "race_stats_label", &stat_label_font ) || !get_font_binding( "race_stats", &font ) ) { print_warning( IMPORTANT_WARNING, "Couldn't get fonts for race stats" ); } else { int asc2; int desc2; get_font_metrics( font, "", &string_w, &asc, &desc ); get_font_metrics( stat_label_font, "", &string_w, &asc2, &desc2 ); if ( asc < asc2 ) { asc = asc2; } if ( desc < desc2 ) { desc = desc2; } glPushMatrix(); { int minutes; int seconds; int hundredths; glTranslatef( x_org, y_org + 150, 0 ); bind_font_texture( stat_label_font ); if (!strcmp(get_calculation_mode(),"jump") ) { draw_string( stat_label_font, Localize("Flying time: ","src/game_over.c")); g_game.time = plyr->control.fly_total_time; } //default mode else { draw_string( stat_label_font, Localize("Time: ","src/game_over.c")); } get_time_components( g_game.time, &minutes, &seconds, &hundredths ); sprintf( buff, "%02d:%02d:%02d", minutes, seconds, hundredths ); bind_font_texture( font ); draw_string( font, buff ); } glPopMatrix(); glPushMatrix(); { glTranslatef( x_org, y_org + 150 - (asc + desc), 0 ); bind_font_texture( stat_label_font ); #ifdef __APPLE__ if (!g_game.is_speed_only_mode) #endif draw_string( stat_label_font, Localize("Fish: ","") ); sprintf( buff, "%3d", plyr->herring ); bind_font_texture( font ); #ifdef __APPLE__ if (!g_game.is_speed_only_mode) #endif draw_string( font, buff ); } glPopMatrix(); glPushMatrix(); { glTranslatef( x_org, y_org + 150 - 2*(asc + desc), 0 ); bind_font_texture( stat_label_font ); #ifdef __APPLE__ if (!g_game.is_speed_only_mode) #endif draw_string( stat_label_font, "Score: " ); sprintf( buff, "%6d", plyr->score ); bind_font_texture( font ); #ifdef __APPLE__ if (!g_game.is_speed_only_mode) #endif draw_string( font, buff ); } glPopMatrix(); } } #ifdef __APPLE__ //display rankings if needed else if ( !g_game.race_aborted && g_game.practicing && g_game.needs_save_or_display_rankings) { if ( !get_font_binding( "race_stats_label", &stat_label_font ) || !get_font_binding( "race_stats", &font ) ) { print_warning( IMPORTANT_WARNING, "Couldn't get fonts for race stats" ); } else { int asc2; int desc2; get_font_metrics( font, "", &string_w, &asc, &desc ); get_font_metrics( stat_label_font, "", &string_w, &asc2, &desc2 ); if ( asc < asc2 ) { asc = asc2; } if ( desc < desc2 ) { desc = desc2; } glPushMatrix(); { glTranslatef( x_org - 50, y_org + 150, 0 ); bind_font_texture( stat_label_font ); draw_string( stat_label_font, Localize("Friends: ","") ); if (strcmp(friendsRanking, "Empty friends list.")==0) { free(friendsRanking); friendsRanking = strdup(Localize("No friends","")); } if (friendsPercent>=0) sprintf( buff, "%s (%.1f%%)", friendsRanking , friendsPercent); else sprintf( buff, "%s", friendsRanking); bind_font_texture( font ); draw_string( font, buff ); } glPopMatrix(); glPushMatrix(); { glTranslatef( x_org -50 , y_org + 150 - (asc + desc), 0 ); bind_font_texture( stat_label_font ); draw_string( stat_label_font, Localize("Country: ","") ); sprintf( buff, "%s (%.1f%%)", countryRanking , countryPercent ); bind_font_texture( font ); draw_string( font, buff ); } glPopMatrix(); glPushMatrix(); { glTranslatef( x_org - 50, y_org + 150 - 2*(asc + desc), 0 ); bind_font_texture( stat_label_font ); draw_string( stat_label_font, Localize("World: ","") ); sprintf( buff, "%s (%.1f%%)", worldRanking , worldPercent); bind_font_texture( font ); draw_string( font, buff ); } glPopMatrix(); } } #endif if ( g_game.race_aborted && !g_game.race_time_over) { string = Localize("Race aborted.",""); } else if ( g_game.race_aborted && g_game.race_time_over) { string = Localize("Time is up.",""); } else if ( ( g_game.practicing || is_current_cup_complete() ) && did_player_beat_best_results() ) { if ( !g_game.race_aborted && g_game.practicing && g_game.needs_save_or_display_rankings) { string = ""; } else string = Localize("You beat your best score!",""); } else { string = ""; } if ( !get_font_binding( "race_result_msg", &font ) ) { print_warning( IMPORTANT_WARNING, "Couldn't get font for binding race_result_msg" ); } else { get_font_metrics( font, string, &string_w, &asc, &desc ); glPushMatrix(); { glTranslatef( x_org + box_width/2. - string_w/2., y_org + desc +20., 0 ); bind_font_texture( font ); draw_string( font, string ); } glPopMatrix(); } #ifdef __APPLE__ //Draws "touch screen to contin"ue string = Localize("Touch screen to continue",""); if ( !get_font_binding( "fps", &font ) ) { print_warning( IMPORTANT_WARNING, "Couldn't get font for binding race_result_msg" ); } else { get_font_metrics( font, string, &string_w, &asc, &desc ); glPushMatrix(); { glTranslatef( x_org + box_width/2. - string_w/2., y_org + desc-20., 0 ); bind_font_texture( font ); draw_string( font, string ); } glPopMatrix(); } #endif }
wraptext_t* word_wrap_text(const font_t* font, const char* text, int width) { char* buffer = NULL; int glyph_width; int line_idx; int line_width; int max_lines = 10; char* line_buffer; char* new_buffer; size_t pitch; int space_width = get_text_width(font, " "); char* string = NULL; char* word; wraptext_t* wraptext; if (!(wraptext = calloc(1, sizeof(wraptext_t)))) goto on_error; // allocate initial buffer get_font_metrics(font, &glyph_width, NULL, NULL); pitch = glyph_width > 0 ? width / glyph_width + 2 : width; if (!(buffer = malloc(max_lines * pitch))) goto on_error; // run through string one word at a time, wrapping as necessary line_buffer = buffer; line_buffer[0] = '\0'; line_idx = 0; line_width = 0; string = strdup(text); word = strtok(string, " "); while (word != NULL) { line_width += get_text_width(font, word); if (line_width > width) { // time for a new line? if (++line_idx >= max_lines) { // enlarge the buffer? max_lines *= 2; if (!(new_buffer = realloc(buffer, max_lines * pitch))) goto on_error; buffer = new_buffer; line_buffer = buffer + line_idx * pitch; } else line_buffer += pitch; line_width = get_text_width(font, word); line_buffer[0] = '\0'; } strcat(line_buffer, word); word = strtok(NULL, " "); if (word != NULL) { strcat(line_buffer, " "); line_width += space_width; } } free(string); wraptext->num_lines = line_idx + 1; wraptext->buffer = buffer; wraptext->pitch = pitch; return wraptext; on_error: free(string); free(buffer); free(wraptext); return NULL; }
wraptext_t* word_wrap_text(const font_t* font, const char* text, int width) { char* buffer = NULL; uint8_t ch_byte; char* carry; size_t ch_size; uint32_t cp; int glyph_width; bool is_line_end = false; int line_idx; int line_width; int max_lines = 10; char* last_break; char* last_space; char* last_tab; char* line_buffer; size_t line_length; char* new_buffer; size_t pitch; uint32_t utf8state; wraptext_t* wraptext; const char *p, *start; if (!(wraptext = calloc(1, sizeof(wraptext_t)))) goto on_error; // allocate initial buffer get_font_metrics(font, &glyph_width, NULL, NULL); pitch = 4 * (glyph_width > 0 ? width / glyph_width : width) + 3; if (!(buffer = malloc(max_lines * pitch))) goto on_error; if (!(carry = malloc(pitch))) goto on_error; // run through one character at a time, carrying as necessary line_buffer = buffer; line_buffer[0] = '\0'; line_idx = 0; line_width = 0; line_length = 0; memset(line_buffer, 0, pitch); // fill line with NULs p = text; do { utf8state = UTF8_ACCEPT; start = p; while (utf8decode(&utf8state, &cp, ch_byte = *p++) > UTF8_REJECT); if (utf8state == UTF8_REJECT && ch_byte == '\0') --p; // don't eat NUL terminator ch_size = p - start; cp = cp == 0x20AC ? 128 : cp == 0x201A ? 130 : cp == 0x0192 ? 131 : cp == 0x201E ? 132 : cp == 0x2026 ? 133 : cp == 0x2020 ? 134 : cp == 0x2021 ? 135 : cp == 0x02C6 ? 136 : cp == 0x2030 ? 137 : cp == 0x0160 ? 138 : cp == 0x2039 ? 139 : cp == 0x0152 ? 140 : cp == 0x017D ? 142 : cp == 0x2018 ? 145 : cp == 0x2019 ? 146 : cp == 0x201C ? 147 : cp == 0x201D ? 148 : cp == 0x2022 ? 149 : cp == 0x2013 ? 150 : cp == 0x2014 ? 151 : cp == 0x02DC ? 152 : cp == 0x2122 ? 153 : cp == 0x0161 ? 154 : cp == 0x203A ? 155 : cp == 0x0153 ? 156 : cp == 0x017E ? 158 : cp == 0x0178 ? 159 : cp; cp = utf8state == UTF8_ACCEPT ? cp < (uint32_t)font->num_glyphs ? cp : 0x1A : 0x1A; switch (cp) { case '\n': case '\r': // explicit newline if (cp == '\r' && *p == '\n') ++text; // CRLF is_line_end = true; break; case '\t': // tab line_buffer[line_length++] = cp; line_width += get_text_width(font, " "); is_line_end = false; break; case '\0': // NUL terminator is_line_end = line_length > 0; // commit last line on EOT break; default: // default case, copy character as-is memcpy(line_buffer + line_length, start, ch_size); line_length += ch_size; line_width += get_glyph_width(font, cp); is_line_end = false; } if (is_line_end) carry[0] = '\0'; if (line_width > width || line_length >= pitch - 1) { // wrap width exceeded, carry current word to next line is_line_end = true; last_space = strrchr(line_buffer, ' '); last_tab = strrchr(line_buffer, '\t'); last_break = last_space > last_tab ? last_space : last_tab; if (last_break != NULL) // word break (space or tab) found strcpy(carry, last_break + 1); else // no word break, so just carry last character sprintf(carry, "%c", line_buffer[line_length - 1]); line_buffer[line_length - strlen(carry)] = '\0'; } if (is_line_end) { // do we need to enlarge the buffer? if (++line_idx >= max_lines) { max_lines *= 2; if (!(new_buffer = realloc(buffer, max_lines * pitch))) goto on_error; buffer = new_buffer; line_buffer = buffer + line_idx * pitch; } else line_buffer += pitch; memset(line_buffer, 0, pitch); // fill line with NULs // copy carry text into new line line_width = get_text_width(font, carry); line_length = strlen(carry); strcpy(line_buffer, carry); } } while (cp != '\0'); free(carry); wraptext->num_lines = line_idx; wraptext->buffer = buffer; wraptext->pitch = pitch; return wraptext; on_error: free(buffer); free(wraptext); return NULL; }
std::string Font::get_clipped_text(Canvas &canvas, const Sizef &box_size, const std::string &text, const std::string &ellipsis_text) { std::string out_string; out_string.reserve(text.length()); if (impl) { Pointf pos; FontMetrics fm = get_font_metrics(canvas); float descent = fm.get_descent(); float line_spacing = fm.get_line_height(); std::vector<std::string> lines = StringHelp::split_text(text, "\n", false); for (std::vector<std::string>::size_type i = 0; i < lines.size(); i++) { if (i == 0 || pos.y + descent < box_size.height) { Sizef size = measure_text(canvas, lines[i]).bbox_size; if (pos.x + size.width <= box_size.width) { if (!out_string.empty()) out_string += "\n"; out_string += lines[i]; } else { Sizef ellipsis = measure_text(canvas, ellipsis_text).bbox_size; int seek_start = 0; int seek_end = lines[i].size(); int seek_center = (seek_start + seek_end) / 2; UTF8_Reader utf8_reader(lines[i].data(), lines[i].length()); while (true) { utf8_reader.set_position(seek_center); utf8_reader.move_to_leadbyte(); if (seek_center != utf8_reader.get_position()) utf8_reader.next(); seek_center = utf8_reader.get_position(); if (seek_center == seek_end) break; utf8_reader.set_position(seek_start); utf8_reader.next(); if (utf8_reader.get_position() == seek_end) break; Sizef text_size = measure_text(canvas, lines[i].substr(0, seek_center)).bbox_size; if (pos.x + text_size.width + ellipsis.width >= box_size.width) seek_end = seek_center; else seek_start = seek_center; seek_center = (seek_start + seek_end) / 2; } if (!out_string.empty()) out_string += "\n"; out_string += lines[i].substr(0, seek_center) + ellipsis_text; } pos.y += line_spacing; } } } return out_string; }
/*! Scrolls the credits text up the screen. \author jfpatry \date Created: 2000-09-27 \date Modified: 2000-09-27 */ static void draw_credits_text( scalar_t time_step ) { int w = getparam_x_resolution(); int h = getparam_y_resolution(); font_t *font; int i; scalar_t y; int string_w, asc, desc; y_offset += time_step * 30; y = CREDITS_MIN_Y+y_offset; glPushMatrix(); { glTranslatef( w/2, y, 0 ); for (i=0; i<sizeof( credit_lines ) / sizeof( credit_lines[0] ); i++) { credit_line_t line = credit_lines[i]; if ( !get_font_binding( line.binding, &font ) ) { print_warning( IMPORTANT_WARNING, "Couldn't get font for binding %s", line.binding ); } else { get_font_metrics( font, line.text, &string_w, &asc, &desc ); glTranslatef( 0, -asc, 0 ); y += -asc; glPushMatrix(); { bind_font_texture( font ); glTranslatef( -string_w/2, 0, 0 ); draw_string( font, line.text ); } glPopMatrix(); glTranslatef( 0, -desc, 0 ); y += -desc; } } } glPopMatrix(); if ( y > h+CREDITS_MAX_Y ) { y_offset = 0; } /* Draw strips at the top and bottom to clip out text */ //glDisable( GL_TEXTURE_2D ); #ifdef __APPLE__DISABLED__ glColor4f( ui_background_colour.r, ui_background_colour.g, ui_background_colour.b, ui_background_colour.a ); //draws rect a la place de glRectf const GLfloat vertices []= { 0, 0, w, 0 , w , CREDITS_MIN_Y, 0, CREDITS_MIN_Y }; glEnableClientState (GL_VERTEX_ARRAY); glVertexPointer (2, GL_FLOAT , 0, vertices); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); const GLfloat vertices1 []= { 0, CREDITS_MIN_Y, w, CREDITS_MIN_Y, w, CREDITS_MIN_Y + 30, 0, CREDITS_MIN_Y + 30 }; const GLfloat colors1 []= { ui_background_colour.r, ui_background_colour.g, ui_background_colour.b, ui_background_colour.a, ui_background_colour.r, ui_background_colour.g, ui_background_colour.b, ui_background_colour.a, ui_background_colour.r, ui_background_colour.g, ui_background_colour.b, 0.0, ui_background_colour.r, ui_background_colour.g, ui_background_colour.b, 0.0, }; glEnableClientState (GL_VERTEX_ARRAY); glVertexPointer (2, GL_FLOAT , 0, vertices); glColorPointer(4, GL_FLOAT, 0, colors1); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glColor4f( ui_background_colour.r, ui_background_colour.g, ui_background_colour.b, ui_background_colour.a ); //draws rect a la place de glRectf( 0, h+CREDITS_MAX_Y, w, h ); const GLfloat vertices2 []= { 0, h+CREDITS_MAX_Y, w, h+CREDITS_MAX_Y , w , h, 0, h }; glEnableClientState (GL_VERTEX_ARRAY); glVertexPointer (2, GL_FLOAT , 0, vertices2); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); const GLfloat vertices3 []= { w, h+CREDITS_MAX_Y, 0, h+CREDITS_MAX_Y, 0, h+CREDITS_MAX_Y - 30, w, h+CREDITS_MAX_Y - 30 }; const GLfloat colors3 []= { ui_background_colour.r, ui_background_colour.g, ui_background_colour.b, ui_background_colour.a, ui_background_colour.r, ui_background_colour.g, ui_background_colour.b, ui_background_colour.a, ui_background_colour.r, ui_background_colour.g, ui_background_colour.b, 0.0, ui_background_colour.r, ui_background_colour.g, ui_background_colour.b, 0.0, }; glEnableClientState (GL_VERTEX_ARRAY); glVertexPointer (2, GL_FLOAT , 0, vertices3); glColorPointer(4, GL_FLOAT, 0, colors3); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); #else glColor4dv( (scalar_t*)&ui_background_colour ); glRectf( 0, 0, w, CREDITS_MIN_Y ); glBegin( GL_QUADS ); { glVertex2f( 0, CREDITS_MIN_Y ); glVertex2f( w, CREDITS_MIN_Y ); glColor4f( ui_background_colour.r, ui_background_colour.g, ui_background_colour.b, 0 ); glVertex2f( w, CREDITS_MIN_Y + 30 ); glVertex2f( 0, CREDITS_MIN_Y + 30 ); } glEnd(); glColor4dv( (scalar_t*)&ui_background_colour ); glRectf( 0, h+CREDITS_MAX_Y, w, h ); glBegin( GL_QUADS ); { glVertex2f( w, h+CREDITS_MAX_Y ); glVertex2f( 0, h+CREDITS_MAX_Y ); glColor4f( ui_background_colour.r, ui_background_colour.g, ui_background_colour.b, 0 ); glVertex2f( 0, h+CREDITS_MAX_Y - 30 ); glVertex2f( w, h+CREDITS_MAX_Y - 30 ); } glEnd(); #endif glColor4f( 1, 1, 1, 1 ); glEnable( GL_TEXTURE_2D ); }