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

Webgl text #3110

Merged
merged 18 commits into from Aug 29, 2018
Merged

Webgl text #3110

merged 18 commits into from Aug 29, 2018

Conversation

Spongman
Copy link
Contributor

@Spongman Spongman commented Aug 3, 2018

closes #2183

implements text() for the webgl renderer. most of the code is in src/webgl/text.js, however some other changes were required:

  • moving most of the p5.Renderer2D.prototype.text() and textAlign() code into shared methods in p5.Renderer, this necessitated:
  • changing the textAlign and textBaseline properties so they are backed directly by variables in the renderer instead of being calculated based on canvas properties. this also simplifies the logic for those properties.
  • changes to push/pop, _applyTextProperties methods to accommodate the above.
  • changes to various p5.Font methods to make them renderer-independent.
  • optimization in p5.RendererGL.prototype.getTexture which gets called a ton.
  • add support for creating p5.Texture from an ImageData object.
  • a new private p5.Shader.prototype.updateTextures() method that ensures all dirty textures are sent to the GPU.

}
};

p5.Renderer.prototype.text = function(str, x, y, maxWidth, maxHeight) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code came from p5.Renderer2D.prototype.text

var textures = this.textures;
for (var it = 0; it < textures.length; ++it) {
var texture = textures[it];
if (texture.src === img) return texture;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using a for loop instead of Array.find() which is really slow..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

@Spongman Spongman Aug 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think indexOf would work in this case since we're looking for the element that has a particular (src) property. this is what find() is intended for - apply a predicate to each element and return the first that matches. but the function call is really slow.


var gl = this._renderer.GL;
// pull texture from data, make sure width & height are appropriate
if (textureData.width !== this.width || textureData.height !== this.height) {
updated = true;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using this flag to de-duplicate the texImage2D code

@@ -0,0 +1,189 @@
#extension GL_OES_standard_derivatives : enable
Copy link
Contributor Author

@Spongman Spongman Aug 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll comment this when we have glsl minification in the build

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this file needs comments. 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i added issue #3114

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... and PR #3116

@@ -44,6 +44,8 @@ p5.Renderer = function(elt, pInst, isMainCanvas) {
this._textStyle = constants.NORMAL;
this._textAscent = null;
this._textDescent = null;
this._textAlign = constants.LEFT;
this._textBaseline = constants.BOTTOM;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are stored here now, instead of as native 2d canvas properties.

@AdilRabbani
Copy link
Member

AdilRabbani commented Aug 4, 2018

Oh boy, this is my first time reviewing a PR....please bear with me 😬

Copy link
Member

@AdilRabbani AdilRabbani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting this output on https://p5js.org/reference/#/p5/textLeading example in 2D on your build :

wrongoutput

textAscent() also seems to give unexpected results in 2D mode :

Original Now
textascentorig textascentnow

*
* the ImageInfos class holds a list of ImageDatas of a given size.
*/
function ImageInfos(width, height) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering this is private, wouldn't it be better to make it _ImageInfos? Just like other private functions in p5.js? Also there are other functions like this one in this file (setPixel, FontInfo...).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uh-oh, good catch on the 2d bugs, that definitely needs to be fixed.

as for the '_'s, i don't think this is necessary. those functions are all private to the 'text' module whose only export is the p5 object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, 1543600 should fix the alignment/metrics issues.

@AdilRabbani
Copy link
Member

AdilRabbani commented Aug 6, 2018

  1. Can there be a default font for WebGL as well? It feels odd that nothing is displayed if the user doesn't load a font. Getting 'WEBGL: only opentype fonts are supported' log in the console.

  2. I think there should be an option for z coordinates as well? (str, x, y, z, maxWidth, maxHeight)

  3. We would need a WebGL doc example also. Above p5.prototype.text().

@kjhollen can you take a final look at this as well? 😀

@Spongman
Copy link
Contributor Author

Spongman commented Aug 6, 2018

i thought about adding a z parameter, but decided against it since other primitives like arc, rect, ellipse & triangle only take 2d coordinates. i figure if you're going real 3d positioning of stuff in webgl-mode then you probably should be familiar with translate(). oh, and there's no way to distinguish between text(str,x,y,width) and text(str,x,y,z).

i added an example for text().

as for adding a default font: it's a good idea, but i'm not sure how easy this would be to implement. do we always preload it before setup()? or do we add some async on-demand loading the first time it's required? do we load it from a fixed location on the internet (what if the machine is disconnected?), do we require it to be located in a specific location relative to the sketch? do we embed it as a base64-encoded binary (~35K for latin script) in the p5.js javascript?

@AdilRabbani
Copy link
Member

This seems a bit tricky. How is 2D mode handling this? I think it seems to be using a default web safe font?

@Spongman
Copy link
Contributor Author

Spongman commented Aug 7, 2018

2d mode is using <canvas> so, as well as opentype fonts, it can use the fonts built into the browser (or OS). the default font is set here:

this.drawingContext.font = 'normal 12px sans-serif';

@AdilRabbani
Copy link
Member

AdilRabbani commented Aug 7, 2018

@kjhollen @mlarghydracept Overall the implementation is working great! There is a problem of adding a default font. What do you suggest?

@dhowe
Copy link
Contributor

dhowe commented Aug 8, 2018

I'm getting this output on https://p5js.org/reference/#/p5/textLeading example in 2D on your build
textAscent() also seems to give unexpected results in 2D mode

if you need more checks for alignment, leading etc, some of the sketches in 'manual-test-examples' might be of use in verifying that 2d, 3d, and original processing are all producing the same results (test/manual-test-examples/p5.Font/custom/index.html for example)...

screen shot 2018-08-07 at 11 45 38 pm

@Spongman Spongman closed this Aug 8, 2018
@Spongman Spongman reopened this Aug 8, 2018
@kjhollen
Copy link
Member

kjhollen commented Aug 8, 2018

thank you for the initial review, @AdilRabbani! I'm happy to take a deeper look at this—I'll do it next week once I settle in from moving a little more, if that works for you @Spongman?

@stalgiag
Copy link
Contributor

stalgiag commented Aug 8, 2018

I just had an opportunity to briefly look over this and everything looked fantastic. I can properly review it on Friday.

Edit: We have comical timing @kjhollen . Seems like @Spongman closing and reopening summoned both of us.

@Spongman
Copy link
Contributor Author

Spongman commented Aug 8, 2018

thanks everyone, no rush ;-)

@kjhollen
Copy link
Member

kjhollen commented Aug 8, 2018

or @mlarghydracept can look sooner :)

@Spongman
Copy link
Contributor Author

Spongman commented Aug 8, 2018

sorry about that - didn't mean to spam - travis got stuck for some reason on the last commit and i don't know any other way to re-trigger it.

@stalgiag
Copy link
Contributor

Okay I have been taking some more time with this and realize there are huge number of changes to look over. I will try to do a line-by-line this weekend but for now I have just managed to give it a broad-strokes once over. So far everything works really well but I have concerns that this structure in text.js may make future contributions difficult. Text rendering is a difficult task but I wonder if there are ways that this can be changed slightly to make it less intimidating to future contributors. Namely there is a high density of class declarations and utility functions. This may be unavoidable but it feels different than the rest of the library. Also, why the additions to the p5.Vector class? Maybe I am missing something but couldn't the static methods be used to accomplish this same task without adding to that class?

@Spongman
Copy link
Contributor Author

Spongman commented Aug 11, 2018

the main reason i added the private fluent methods to p5.Vector was to make the vector math in the cubic approximation code easier to read. i originally had it with the static methods, but after the linter made a mess of things, i switched it to fluent.

for example, there's a statement in splitInflections() which calculates the vector expression c = this.p1 - this.c1 - a - b*2:

        var c = p5.Vector.sub(
          p5.Vector.sub(p5.Vector.sub(this.p1, this.c1), a),
          p5.Vector.mul(b, 2)
        );

and here's the same statement with the fluent interface:

        var c = this.p1
          .minus(this.c1)
          .minus(a)
          .minus(b.times(2));

maybe it's just me, but I find it significantly easier to work out what's actually happening when reading the 2nd version mostly because it reads in my head identically to the math expression it's calculating.

also, having private/undocumented methods in one part of the library that are used by another is not without precedent.

@stalgiag
Copy link
Contributor

Hm I see how that probably looks pretty convoluted with the static methods. I still don't really know if it is okay to add these fluent methods to p5.Vector just for this single use.

So I have been trying to think about solutions to the default font issue. This feels like a pretty confusing roadbump for users. I haven't had any epiphanies but I want to keep up a conversation about it because it feels significant. It may be an inescapable aspect of the implementation, in which case we'd need to make sure that the reference clearly explains the need for a loaded font when using WebGL.

@@ -1,11 +1,25 @@
var _webgl = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting what appear to be errors for this in Chrome. I get console warnings about the number of GL contexts and the dead computer icon inside some of the canvases.

screenshot 426

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, it looks like some browsers limit the number of concurrent webgl contexts. try edge, it doesn't do this.

@Spongman
Copy link
Contributor Author

ok, i don't mind changing it back to the static methods. the math is actually a little simpler than it used to be.

@Spongman
Copy link
Contributor Author

Spongman commented Aug 19, 2018

travis stalled again, ugh. i rebased on to master (post webgl-gsoc-2018).

@Spongman Spongman closed this Aug 19, 2018
@Spongman Spongman reopened this Aug 19, 2018
@stalgiag
Copy link
Contributor

I agree that there it feels that there should be somewhere for more elaborate documentation. Reference docs focus on clarity and simplicity. Not sure about the solution there, but for now I feel that this PR is ready to merge. @kjhollen have any interest in giving this a final glance before I merge? It is a pretty large addition. Thanks for your patience @Spongman!

@AdilRabbani
Copy link
Member

WebGL docs would need an update regarding WebGL text in p5.js.

@stalgiag
Copy link
Contributor

Good call @AdilRabbani!

@stalgiag
Copy link
Contributor

@Spongman just to clarify - I think that we can move forward with a merge. I have spoken with @kjhollen. The only thing that needs to happen before that is that we need to update the [developer_docs] (https://github.com/processing/p5.js/blob/master/developer_docs/webgl_mode_architecture.md) as per @AdilRabbani's suggestion.

@stalgiag
Copy link
Contributor

Okay! @Spongman Merging now. Thanks for the final touches, especially the additional comments. It helps demystify quite a lot. This is a large and well-considered contribution!

Can you make an issue that addresses the default font when you get a chance? It seems that you have already done quite a bit of work to consider possible solutions and it would be good to document these for future contributors.

@stalgiag stalgiag merged commit 63ab55d into processing:master Aug 29, 2018
@Spongman Spongman deleted the webgl-text branch August 29, 2018 20:56
@Spongman
Copy link
Contributor Author

fantastic, thanks for reviewing this!

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

Successfully merging this pull request may close these issues.

Implement text() for webgl mode
6 participants