bool ImGui::ImageButton(const ImVec2& size, const char* spriteFrameName, bool selected, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return false; ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; GLuint textID = cocos2d::SpriteFrameCache::getInstance()->getSpriteFrameByName(spriteFrameName)->getTexture()->getName(); cocos2d::Rect rectange = cocos2d::SpriteFrameCache::getInstance()->getSpriteFrameByName(spriteFrameName)->getRect(); cocos2d::Size orgSize = cocos2d::SpriteFrameCache::getInstance()->getSpriteFrameByName(spriteFrameName)->getTexture()->getContentSize(); // Default to using texture ID as ID. User can still push string/integer prefixes. // We could hash the size/uv to create a unique ID but that would prevent the user from animating UV. ImGui::PushID((void *)textID); const ImGuiID id = window->GetID("#image"); ImGui::PopID(); const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding; const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2); const ImRect image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size); ItemSize(bb); if (!ItemAdd(bb, &id)) return false; bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held); // Render ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); if (selected) col = GetColorU32(ImGuiCol_ButtonActive); RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, style.FrameRounding)); if (bg_col.w > 0.0f) window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, GetColorU32(bg_col)); float focus_x = rectange.origin.x; float focus_y = rectange.origin.y; ImVec2 uv0 = ImVec2((focus_x) / orgSize.width, (focus_y) / orgSize.height); ImVec2 uv1 = ImVec2((focus_x + rectange.size.width) / orgSize.width, (focus_y + rectange.size.height) / orgSize.height); window->DrawList->AddImage((ImTextureID)textID, image_bb.Min, image_bb.Max, uv0, uv1, GetColorU32(tint_col)); return pressed; }
bool ImGuiFreeType::BuildFontAtlas(ImFontAtlas* atlas, unsigned int extra_flags) { IM_ASSERT(atlas->ConfigData.Size > 0); IM_ASSERT(atlas->TexGlyphPadding == 1); // Not supported ImFontAtlasBuildRegisterDefaultCustomRects(atlas); atlas->TexID = NULL; atlas->TexWidth = atlas->TexHeight = 0; atlas->TexUvScale = ImVec2(0.0f, 0.0f); atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); atlas->ClearTexData(); ImVector<FreeTypeFont> fonts; fonts.resize(atlas->ConfigData.Size); ImVec2 max_glyph_size(1.0f, 1.0f); // Count glyphs/ranges, initialize font int total_glyphs_count = 0; int total_ranges_count = 0; for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) { ImFontConfig& cfg = atlas->ConfigData[input_i]; FreeTypeFont& font_face = fonts[input_i]; IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas)); if (!font_face.Init(cfg, extra_flags)) return false; max_glyph_size.x = ImMax(max_glyph_size.x, font_face.Info.MaxAdvanceWidth); max_glyph_size.y = ImMax(max_glyph_size.y, font_face.Info.Ascender - font_face.Info.Descender); if (!cfg.GlyphRanges) cfg.GlyphRanges = atlas->GetGlyphRangesDefault(); for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[ 1 ]; in_range += 2, total_ranges_count++) total_glyphs_count += (in_range[1] - in_range[0]) + 1; } // We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish. // Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512; // We don't do the original first pass to determine texture height, but just rough estimate. // Looks ugly inaccurate and excessive, but AFAIK with FreeType we actually need to render glyphs to get exact sizes. // Alternatively, we could just render all glyphs into a big shadow buffer, get their sizes, do the rectangle packing and just copy back from the // shadow buffer to the texture buffer. Will give us an accurate texture height, but eat a lot of temp memory. Probably no one will notice.) const int total_rects = total_glyphs_count + atlas->CustomRects.size(); float min_rects_per_row = ceilf((atlas->TexWidth / (max_glyph_size.x + 1.0f))); float min_rects_per_column = ceilf(total_rects / min_rects_per_row); atlas->TexHeight = (int)(min_rects_per_column * (max_glyph_size.y + 1.0f)); // Create texture atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight); memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); // Start packing ImVector<stbrp_node> pack_nodes; pack_nodes.resize(total_rects); stbrp_context context; stbrp_init_target(&context, atlas->TexWidth, atlas->TexHeight, pack_nodes.Data, total_rects); // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). ImFontAtlasBuildPackCustomRects(atlas, &context); // Render characters, setup ImFont and glyphs for runtime for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++) { ImFontConfig& cfg = atlas->ConfigData[input_i]; FreeTypeFont& font_face = fonts[input_i]; ImFont* dst_font = cfg.DstFont; if (cfg.MergeMode) dst_font->BuildLookupTable(); const float ascent = font_face.Info.Ascender; const float descent = font_face.Info.Descender; ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); const float font_off_x = cfg.GlyphOffset.x; const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f); bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f); unsigned char multiply_table[256]; if (multiply_enabled) ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2) { for (uint32_t codepoint = in_range[0]; codepoint <= in_range[1]; ++codepoint) { if (cfg.MergeMode && dst_font->FindGlyphNoFallback((unsigned short)codepoint)) continue; FT_Glyph ft_glyph = NULL; FT_BitmapGlyph ft_glyph_bitmap = NULL; // NB: will point to bitmap within FT_Glyph GlyphInfo glyph_info; if (!font_face.CalcGlyphInfo(codepoint, glyph_info, ft_glyph, ft_glyph_bitmap)) continue; // Pack rectangle stbrp_rect rect; rect.w = (uint16_t)glyph_info.Width + 1; // Account for texture filtering rect.h = (uint16_t)glyph_info.Height + 1; stbrp_pack_rects(&context, &rect, 1); // Copy rasterized pixels to main texture uint8_t* blit_dst = atlas->TexPixelsAlpha8 + rect.y * atlas->TexWidth + rect.x; font_face.BlitGlyph(ft_glyph_bitmap, blit_dst, atlas->TexWidth, multiply_enabled ? multiply_table : NULL); FT_Done_Glyph(ft_glyph); float char_advance_x_org = glyph_info.AdvanceX; float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX); float char_off_x = font_off_x; if (char_advance_x_org != char_advance_x_mod) char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f; // Register glyph dst_font->AddGlyph((ImWchar)codepoint, glyph_info.OffsetX + char_off_x, glyph_info.OffsetY + font_off_y, glyph_info.OffsetX + char_off_x + glyph_info.Width, glyph_info.OffsetY + font_off_y + glyph_info.Height, rect.x / (float)atlas->TexWidth, rect.y / (float)atlas->TexHeight, (rect.x + glyph_info.Width) / (float)atlas->TexWidth, (rect.y + glyph_info.Height) / (float)atlas->TexHeight, char_advance_x_mod); } } } // Cleanup for (int n = 0; n < fonts.Size; n++) fonts[n].Shutdown(); ImFontAtlasBuildFinish(atlas); return true; }