@@ -3244,7 +3244,8 @@ ImFontAtlasRectId ImFontAtlas::AddCustomRect(int width, int height, ImFontAtlasR
3244
3244
3245
3245
void ImFontAtlas::RemoveCustomRect (ImFontAtlasRectId id)
3246
3246
{
3247
- IM_ASSERT (id != ImFontAtlasRectId_Invalid);
3247
+ if (ImFontAtlasPackGetRectSafe (this , id) == NULL )
3248
+ return ;
3248
3249
ImFontAtlasPackDiscardRect (this , id);
3249
3250
}
3250
3251
@@ -3300,10 +3301,12 @@ int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, Im
3300
3301
3301
3302
bool ImFontAtlas::GetCustomRect (ImFontAtlasRectId id, ImFontAtlasRect* out_r) const
3302
3303
{
3303
- ImTextureRect* r = ImFontAtlasPackGetRect ((ImFontAtlas*)this , id);
3304
+ ImTextureRect* r = ImFontAtlasPackGetRectSafe ((ImFontAtlas*)this , id);
3304
3305
if (r == NULL )
3305
3306
return false ;
3306
3307
IM_ASSERT (TexData->Width > 0 && TexData->Height > 0 ); // Font atlas needs to be built before we can calculate UV coordinates
3308
+ if (out_r == NULL )
3309
+ return true ;
3307
3310
out_r->x = r->x ;
3308
3311
out_r->y = r->y ;
3309
3312
out_r->w = r->w ;
@@ -4007,7 +4010,7 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h)
4007
4010
ImFontAtlasBuildGrowTexture (atlas, w, h); // Recurse
4008
4011
return ;
4009
4012
}
4010
- IM_ASSERT (new_r_id == builder->RectsIndex .index_from_ptr (&index_entry));
4013
+ IM_ASSERT (ImFontAtlasRectId_GetIndex ( new_r_id) == builder->RectsIndex .index_from_ptr (&index_entry));
4011
4014
ImTextureRect* new_r = ImFontAtlasPackGetRect (atlas, new_r_id);
4012
4015
ImFontAtlasTextureBlockCopy (old_tex, old_r.x , old_r.y , new_tex, new_r->x , new_r->y , new_r->w , new_r->h );
4013
4016
}
@@ -4236,41 +4239,48 @@ static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas* atlas, int r
4236
4239
builder->RectsIndex .resize (builder->RectsIndex .Size + 1 );
4237
4240
index_idx = builder->RectsIndex .Size - 1 ;
4238
4241
index_entry = &builder->RectsIndex [index_idx];
4242
+ memset (index_entry, 0 , sizeof (*index_entry));
4239
4243
}
4240
4244
else
4241
4245
{
4242
4246
index_idx = builder->RectsIndexFreeListStart ;
4243
4247
index_entry = &builder->RectsIndex [index_idx];
4244
- IM_ASSERT (index_entry->IsUsed == false );
4248
+ IM_ASSERT (index_entry->IsUsed == false && index_entry-> Generation > 0 ); // Generation is incremented during DiscardRect
4245
4249
builder->RectsIndexFreeListStart = index_entry->TargetIndex ;
4246
4250
}
4247
4251
index_entry->TargetIndex = rect_idx;
4248
4252
index_entry->IsUsed = 1 ;
4249
- return (ImFontAtlasRectId) index_idx;
4253
+ return ImFontAtlasRectId_Make ( index_idx, index_entry-> Generation ) ;
4250
4254
}
4251
4255
4252
4256
// Overwrite existing entry
4253
4257
static ImFontAtlasRectId ImFontAtlasPackReuseRectEntry (ImFontAtlas* atlas, ImFontAtlasRectEntry* index_entry)
4254
4258
{
4255
4259
IM_ASSERT (index_entry->IsUsed );
4256
4260
index_entry->TargetIndex = atlas->Builder ->Rects .Size - 1 ;
4257
- return atlas->Builder ->RectsIndex .index_from_ptr (index_entry);
4261
+ int index_idx = atlas->Builder ->RectsIndex .index_from_ptr (index_entry);
4262
+ return ImFontAtlasRectId_Make (index_idx, index_entry->Generation );
4258
4263
}
4259
4264
4260
4265
// This is expected to be called in batches and followed by a repack
4261
4266
void ImFontAtlasPackDiscardRect (ImFontAtlas* atlas, ImFontAtlasRectId id)
4262
4267
{
4263
4268
IM_ASSERT (id != ImFontAtlasRectId_Invalid);
4264
- ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder ;
4265
- ImFontAtlasRectEntry* index_entry = &builder->RectsIndex [id];
4266
- IM_ASSERT (index_entry->IsUsed && index_entry->TargetIndex >= 0 );
4267
4269
4268
4270
ImTextureRect* rect = ImFontAtlasPackGetRect (atlas, id);
4271
+ if (rect == NULL )
4272
+ return ;
4273
+
4274
+ ImFontAtlasBuilder* builder = atlas->Builder ;
4275
+ int index_idx = ImFontAtlasRectId_GetIndex (id);
4276
+ ImFontAtlasRectEntry* index_entry = &builder->RectsIndex [index_idx];
4277
+ IM_ASSERT (index_entry->IsUsed && index_entry->TargetIndex >= 0 );
4269
4278
index_entry->IsUsed = false ;
4270
4279
index_entry->TargetIndex = builder->RectsIndexFreeListStart ;
4280
+ index_entry->Generation ++;
4271
4281
4272
4282
const int pack_padding = atlas->TexGlyphPadding ;
4273
- builder->RectsIndexFreeListStart = id ;
4283
+ builder->RectsIndexFreeListStart = index_idx ;
4274
4284
builder->RectsDiscardedCount ++;
4275
4285
builder->RectsDiscardedSurface += (rect->w + pack_padding) * (rect->h + pack_padding);
4276
4286
rect->w = rect->h = 0 ; // Clear rectangle so it won't be packed again
@@ -4325,16 +4335,36 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon
4325
4335
return ImFontAtlasPackAllocRectEntry (atlas, builder->Rects .Size - 1 );
4326
4336
}
4327
4337
4328
- // Important: return pointer is valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers .
4338
+ // Generally for non-user facing functions: assert on invalid ID .
4329
4339
ImTextureRect* ImFontAtlasPackGetRect (ImFontAtlas* atlas, ImFontAtlasRectId id)
4330
4340
{
4331
4341
IM_ASSERT (id != ImFontAtlasRectId_Invalid);
4342
+ int index_idx = ImFontAtlasRectId_GetIndex (id);
4343
+ int generation = ImFontAtlasRectId_GetGeneration (id);
4332
4344
ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder ;
4333
- ImFontAtlasRectEntry* index_entry = &builder->RectsIndex [id];
4345
+ ImFontAtlasRectEntry* index_entry = &builder->RectsIndex [index_idx];
4346
+ IM_ASSERT (index_entry->Generation == generation);
4334
4347
IM_ASSERT (index_entry->IsUsed );
4335
4348
return &builder->Rects [index_entry->TargetIndex ];
4336
4349
}
4337
4350
4351
+ // For user-facing functions: return NULL on invalid ID.
4352
+ // Important: return pointer is valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers.
4353
+ ImTextureRect* ImFontAtlasPackGetRectSafe (ImFontAtlas* atlas, ImFontAtlasRectId id)
4354
+ {
4355
+ if (id == ImFontAtlasRectId_Invalid)
4356
+ return NULL ;
4357
+ int index_idx = ImFontAtlasRectId_GetIndex (id);
4358
+ int generation = ImFontAtlasRectId_GetGeneration (id);
4359
+ ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder ;
4360
+ if (index_idx >= builder->RectsIndex .Size )
4361
+ return NULL ;
4362
+ ImFontAtlasRectEntry* index_entry = &builder->RectsIndex [index_idx];
4363
+ if (index_entry->Generation != generation || !index_entry->IsUsed )
4364
+ return NULL ;
4365
+ return &builder->Rects [index_entry->TargetIndex ];
4366
+ }
4367
+
4338
4368
// Important! This assume by ImFontConfig::GlyphFilter is a SMALL ARRAY (e.g. <10 entries)
4339
4369
static bool ImFontAtlasBuildAcceptCodepointForSource (ImFontConfig* src, ImWchar codepoint)
4340
4370
{
0 commit comments