Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request: Make opaque structures in STB read-accessible #358

Closed
dotSp0T opened this issue Dec 10, 2017 · 8 comments
Closed

Request: Make opaque structures in STB read-accessible #358

dotSp0T opened this issue Dec 10, 2017 · 8 comments

Comments

@dotSp0T
Copy link

dotSp0T commented Dec 10, 2017

LWJGL tries to represent structs used in the STB bindings, e.g. stbtt_pack_context with classes. It does a good job at this, but while some of them can be properly accessed with read/write operations, those that are marked in the stb sources as opaque have no accessors.

The example making me request this feature is the struct already linked above. The comments in the original sources read:

// this is an opaque structure that you shouldn't mess with which holds
// all the context needed from PackBegin to PackEnd.

While it makes sense to prevent write-access to prevent messing, there is no good reason to prevent read-access. In fact right now it is counter-productive for me.

I am trying to play around with the packing to, i.a., pack the .notdef character commonly found in most true-type-fonts into the texture that is created with stbtt_PackFontRange(s), to do that I am currently playing around with recreating said method and methods it calls as this is not really a representation of unicode characters.

Maybe I am doing too much work and I could achieve it another way, but I don't think so, and it's difficult to work with the whole thing in the first place as the LWJGL bindings are only wrappers of the underlying c libraries.

@Spasi
Copy link
Member

Spasi commented Dec 10, 2017

LWJGL does not expose internal state that is not part of the public API, unless it's useful somehow. Sounds like you can do something interesting with stbtt_pack_context, so I'll make sure it's readable in the next 3.1.6 snapshot.

In the meantime, you could easily access its members with MemoryUtil unsafe memory accessors (memGetInt, memGetAddress, etc). To get ctx->width for example:

int width = memGetInt(ctx.address() + 2 * POINTER_SIZE);

@dotSp0T
Copy link
Author

dotSp0T commented Dec 11, 2017

Thank you for the tip with the MemoryUtil. I've spent some time going over the whole thing again before digging into it and I realized that there is a similar stumbling stone with stbtt_packedchar only providing read, but no write-access.

As the intializing of the STBTTPackedchar.Buffer is performed within the stbtt_packFontRanges(...) method I need to rewrite, I need not only read-, but also write-access. I am looking if I can do it with the MemoryUtil as well for now.


below is the code of the original method and markers to where you can add additional glyphs and stuff with the least effort, for anyone interested/doing the same and struggling as well (//> comments):

STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
{
   stbtt_fontinfo info;
   int i,j,n, return_value = 1;
   //stbrp_context *context = (stbrp_context *) spc->pack_info;
   stbrp_rect    *rects;

   // flag all characters as NOT packed
   for (i=0; i < num_ranges; ++i)
      for (j=0; j < ranges[i].num_chars; ++j)
         ranges[i].chardata_for_range[j].x0 =
         ranges[i].chardata_for_range[j].y0 =
         ranges[i].chardata_for_range[j].x1 =
         ranges[i].chardata_for_range[j].y1 = 0;

   n = 0;
   for (i=0; i < num_ranges; ++i)
      n += ranges[i].num_chars;
         
   rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);
   if (rects == NULL)
      return 0;

   info.userdata = spc->user_allocator_context;
   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));

   n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);

   //> PACK additional rects (see method above) with the glyphs or other things

   stbtt_PackFontRangesPackRects(spc, rects, n);
  
   return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);

   //> RENDER your additional rects the way you want them to, if it's only glyphs you can almost copy the above method

   STBTT_free(rects, spc->user_allocator_context);
   return return_value;
}

@Spasi
Copy link
Member

Spasi commented Dec 11, 2017

In the next snapshot, structs stbrp_context, stbrp_node and stbtt_pack_context won't be opaque and stbtt_packedchar will be mutable. If you need setters in any other struct, please reply here.

Thanks!

@dotSp0T
Copy link
Author

dotSp0T commented Dec 27, 2017

Hey @Spasi , thank you for your help in this!

After playing around with the code I managed to do what I want by abusing the nature of Unicode Codepoints instead, allowing me to not having to rewrite any-much logic at all which was very nice.

Right now though I am working on making the packer render SDF-bitmaps instead of regular ones into the eventual texture. For that I need to replace stbtt_PackFontRangesRenderIntoRects(...) with my own code that either uses the provided SDF method(s) or a custom implementation (doesn't really matter at this stage).

Currently I reproduce the above mentioned method to make sure it works properly and thus need read access to the stbtt_pack_range struct. Currently solving it with the MemoryUtil again.

Cheers

@dotSp0T
Copy link
Author

dotSp0T commented Dec 27, 2017

Should probably just have written that there are some members on that struct that are not public visible yet (h_oversample, v_oversample) which are used in the code I am replicating. They can easily be accessed using the MemoryUtil so it's probably just convenience

@dotSp0T
Copy link
Author

dotSp0T commented Dec 27, 2017

I know these are no public API functions, but when modifying the behaviour on the java side access to the stbtt__* functions would be neat (such as stbtt__h_prefilter(...). This would allow reusing code instead of writing it oneself. Although it's again just some convenience, no real blocker

@Spasi
Copy link
Member

Spasi commented Dec 29, 2017

Should probably just have written that there are some members on that struct that are not public visible yet (h_oversample, v_oversample) which are used in the code I am replicating.

Done.

but when modifying the behaviour on the java side access to the stbtt__* functions would be neat

That's a ton of internal, mostly simple, functions. I would consider exposing a subset of those, if you could post a list of functions that you think would be useful and are not trivial to port to Java.

@dotSp0T
Copy link
Author

dotSp0T commented Dec 30, 2017

That's a ton of internal, mostly simple, functions. I would consider exposing a subset of those, if you could post a list of functions that you think would be useful and are not trivial to port to Java.

I'll spend more time with the code and assemble a list of functions necessary to easily expand the API

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants