Beispiel #1
0
static uint32
find_best_size(uint32 img_count, const image_t** imgs) {
	static uint32	texture_size[] = { 128,	256, 512, 1024, 2048 };
	bool			success	= true;
	uint32			size	= 0;
	uint32			r;
	uint32			s;

	stbrp_rect*		rects	= (stbrp_rect*)malloc(sizeof(stbrp_rect) * img_count);
	for( r = 0; r < img_count; ++r ) {
		rects[r]	= image_to_rect(r, imgs[r]);
	}

	for( s = 0; s < sizeof(texture_size) / sizeof(uint32); ++s ) {
		stbrp_context	ctx;
		uint32			r;
		uint32			width	= texture_size[s];
		stbrp_node*		nodes	= (stbrp_node*)malloc(sizeof(stbrp_node) * width * 2);
		memset(nodes, 0, sizeof(stbrp_node) * width * 2);

		stbrp_init_target(&ctx, (sint32)width, (sint32)width, nodes, (sint32)width * 2);
		stbrp_pack_rects(&ctx, rects, (sint32)img_count);

		free(nodes);

		/* check if all rectangles were packed */
		success	= true;
		for( r = 0; r < img_count; ++r ) {
			if( !rects[r].was_packed ) {
				success	= false;
				size	= 0;
				break;
			}
		}

		if( success ) {
			size	= width;
			break;
		}
	}

	free(rects);

	if( !success ) return 0;
	else return size;
}
Beispiel #2
0
bool MTR_FontTryToPackTtf(uint32_t ttfNum, int textureSide, int currentAtlas,
 stbrp_rect *glyph)
{
    stbrp_node   *node;
    int           nodesCount;
    stbrp_context rectPackContext;
    int           i;
    int           glyphWidth;
    int           glyphHeight;
    bool          success = true;

    nodesCount = textureSide * 2;
    node = malloc(sizeof(stbrp_node) * nodesCount);
    if (node == NULL) {
        MTR_LogWrite(
         "Unable to allocate memory for nodes needed by packing algorithm", 2,
         MTR_LMT_ERROR);
        return false;
    }
    for (i = 0; i < 256; i++) {
        glyph[i].id = i;
        glyph[i].x = 0;
        glyph[i].y = 0;
        glyph[i].was_packed = false;
        MTR_TtfGetGlyphSizes(ttfNum, (currentAtlas * 256) + i, &glyphWidth,
         &glyphHeight);
        glyph[i].w = glyphWidth;
        glyph[i].h = glyphHeight;
    }
    stbrp_init_target (&rectPackContext, textureSide, textureSide, node,
     nodesCount);
//    stbrp_setup_allow_out_of_mem (&rectPackContext, true);
    stbrp_pack_rects(&rectPackContext, glyph, 256);
    for (i = 0; i < 256; i++) {
        if (!glyph[i].was_packed) {
            success = false;
            break;
        }
    }
    free(node);
    return success;
}
Beispiel #3
0
    unsigned int TextureAtlas::addTexture(const Image& image)
    {
        if (m_isSheet)
        {
            JOP_DEBUG_WARNING("Texture being packed into atlas is a sheet, not a single image");
            return 0;
        }

        // Find an empty spot in the texture
        // Add padding to avoid pixel overflow (1 empty pixel)
        stbrp_rect rectangle = {0, static_cast<stbrp_coord>(image.getSize().x + 1), static_cast<stbrp_coord>(image.getSize().y + 1)};
        stbrp_pack_rects(&m_packer->context, &rectangle, 1);
        rectangle.w -= 1;
        rectangle.h -= 1;

        if (rectangle.was_packed)
        {
            // Pass pixel data to texture
            if (image.getPixels())
            {
                m_texture.setPixels(glm::uvec2(rectangle.x, rectangle.y), image);

                m_textures.emplace_back(glm::vec2(rectangle.x, rectangle.y) / glm::vec2(m_texture.getSize()),
                    (glm::vec2(rectangle.x, rectangle.y) + glm::vec2(image.getSize())) / glm::vec2(m_texture.getSize()));

                return m_textures.size() - 1;
            }
            else
            {
                JOP_DEBUG_ERROR("Texture being packed into atlas has no data");
                return 0;
            }
        }
        else
        {
            JOP_DEBUG_ERROR("Failed to pack texture into atlas: Atlas full or texture too large");
            return 0;
        }

    }
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;
}
Beispiel #5
0
atlas_t*
image_atlas_make(uint32 image_count, const image_t** images) {
	stbrp_rect*	rects	= NULL;
	stbrp_node*	nodes	= NULL;
	stbrp_context	ctx;
	uint32		r;
	uint32		best_size;
	image_t*	tex		= NULL;
	atlas_t*	atlas	= NULL;
	rect_t*		drects	= NULL;

	/* try to find the best texture size */
	best_size	= find_best_size(image_count, images);

	/* create the texture and fill in the pixels */
	tex	= image_allocate(best_size, best_size, PF_R8G8B8A8);
	assert( NULL != tex );

	/* image to rect */
	rects	= (stbrp_rect*)malloc(sizeof(stbrp_rect) * image_count);
	assert( NULL != rects );

	for( r = 0; r < image_count; ++r ) {
		rects[r]	= image_to_rect(r, images[r]);
	}

	/* nodes */
	nodes	= (stbrp_node*)malloc(sizeof(stbrp_node) * best_size * 2);
	assert( NULL != nodes );

	memset(nodes, 0, sizeof(stbrp_node) * best_size * 2);

	/* desitnation rectangles */
	drects	= (rect_t*)malloc(sizeof(rect_t) * image_count);
	assert( NULL != drects );

	memset(drects, 0, sizeof(rect_t) * image_count);

	/* pack */
	stbrp_init_target(&ctx, (int)best_size, (int)best_size, nodes, (int)best_size * 2);
	stbrp_pack_rects(&ctx, rects, (int)image_count);

	free(nodes);

	/* copy the rectangle */
	for( r = 0; r < image_count; ++r ) {
		uint32	y;
		uint32	h	= images[r]->height;
		uint32	w	= images[r]->width;

		assert( rects[r].was_packed );

		drects[r].x	= rects[r].x;
		drects[r].y	= rects[r].y;
		drects[r].width	= rects[r].w;
		drects[r].height= rects[r].h;

		for( y = 0; y < h ; ++y ) {
			uint32	x;
			for( x = 0; x < w; ++x ) {
				color4b_t	src	= image_get_pixelb(images[r], x, y);
				image_set_pixelb(tex, rects[r].x + x, rects[r].y + y, src);
			}
		}
	}

	/* release resources */
	free(rects);

	/* final result */
	atlas	= (atlas_t*)malloc(sizeof(atlas_t));
	assert( NULL != atlas );

	atlas->baked_image	= tex;
	atlas->coordinates	= drects;
	atlas->image_count	= image_count;
	return atlas;
}