jujuadams / scribble Goto Github PK
View Code? Open in Web Editor NEWEfficient, internationalized, multi-effects text renderer for GameMaker
Home Page: https://www.jujuadams.com/Scribble/
License: MIT License
Efficient, internationalized, multi-effects text renderer for GameMaker
Home Page: https://www.jujuadams.com/Scribble/
License: MIT License
SCRIBBLE_Z
currently passes in a uniform into the default Scribble shader to control the eventual vertex z-position of text. We do this because Scribble hijacks the z-coordinate of the vertex position to communicate other data (specifically the character/line index).
Passing around SCRIBBLE_Z
as a uniform has a non-zero cost for rendering text and it adds clutter to the library in general. I feel like if someone was using GM for 3D they'd understand enough about shaders (the graphics pipeline in general) to make this edit themselves.
I'm curious if there's a way to get the width and height of a string that would be drawn using scribble_draw. Something like the build in string_width and string_height functions, but using the scribble draw state.
Is there a way to do this? If not, consider this to be a possible feature request :)
When storing text externally, Scribble is potentially exposing all of its sprites for use. This is a mild security hole as it allows sprite names/images to be accessed by changing said external files.
At this point I'm not sure if there's something wrong or if I'm just breaking everything I touch. Empty project, sprite alignment is "middle center," the alignment is set to scribble_draw_set_box_align(fa_center, fa_middle)
and the yyz is attached.
If I had to take a guess this is a similar issue to #10 and #16 .
Scribble actively prevents the user from reinitialising the library as this causes a ton of issues. This causes issues when someone wants to use game_restart()
, however.
...not sure why people are using game_restart()
but here we are.
SCRIBBLE_WARNING_REINITIALIZE
should be added as a macro to control whether a warning is shown when trying to reinitialize Scribble. Additionally, scribble_init()
should return whether the library was initialized successfully. This allows the following design pattern:
if (scribble_init(...))
{
//Initialized for the first time, define things that we need
scribble_add_spritefont(...);
scribble_add_font(...);
scribble_add_color(...);
scribble_autotype_add_event(...);
}
I thought there used to be a "default color" macro, but I guess there's not?
scribble_create, line 54 would instead be
var _def_colour = ((argument_count > 3) && (argument[3] != undefined))? argument[3] : SCRIBBLE_DEFAULT_COLOUR;
and somewhere in __scribble_config would be
#macro SCRIBBLE_DEFAULT_COLOUR c_white
Sometimes it's useful to add a font from a sprite (but not a spritefont!), for example for a testing program that allows the user to add fonts defined in their own project.
In the future, this feature can be used to handle SDF fonts.
A text preview tool would be useful to test features during development, to act as a demo, and to allow for quicker production of text. It may also be useful for localisation work.
Looks like the newest runtime, 2.2.2.326
breaks sprite fonts again, like in #3.
Fortunately, it seems like it's only the padding around the font changed.
https://github.com/GameMakerDiscord/scribble/blob/60151c89a756edc942b76a24869c88e91adffc40/scripts/scribble_init_end/scribble_init_end.gml#L150-L151
Changing the 3
to a 1
in here seems to do the trick.
It may have something to do with my texture group options (Border size: 2; Automatically crop on), but changing these does not seem to influence the generated cache files at all (at least not in a positive way - the automatic crop causes the letters to be tiny instead of too big).
I have SCRIBBLE_EMULATE_LEGACY_SPRITEFONT_SPACING
turned off, too. Turning it on just causes the spacing between the letters to be 2 pixels too short.
Running scribble v4.4.1
, Windows 10 1809.
For procedurally generated games or for games using lockstep networking, the use of randomising functions needs to be very carefully controlled. Autotype uses GM's native randomisation functions to select sound effect and pitch and this may cause unexpected issues with certain kinds of games.
These will need to be replaced with a custom internal random function. The quality of the randomisation function is particularly important so a LCG (e.g. Lehmer) will do just fine.
One of the most common requests for the typewriter is to include a [delay]
and/or [pause]
command. This ends up being quite complex to implement in a general way. It's possible to use the event system to this yourself, but that's quite complicated for new users.
The solution is just to add an example for delay/pause commands built with the events system. This could also include a tutorial on the wiki.
Scribble currently supports horizontally wrapping text but doesn't support limiting the vertical height of a textbox. It's possible to simply cut off the bottom of a textbox but that's an inelegant way to solve the problem. Adding pages to Scribble means it's possible to chuck any length of text at the system and it'll find an appropriate way to show that to the player.
Once a line of text exceeds the vertical limit of the textbox, Scribble will create a new page and begin writing text to that new page. Functions will exist to switch pages. Switching a page will reset the autotype state.
As it stands now, with the new sound feature, we can provide an array of sounds from which scribble will pick one. I think another feature where you could also provide a pitch range for the played sound would be great.
Something like audio_sound_pitch(sound_index, random_range(range_lower, range_upper))
should be pretty simple and could be incorporated great into scribble_autotype_set_sound
, e.g. scribble_autotype_set_sound(element, sound_array, overlap, pitch_array)
or even scribble_autotype_set_sound(element, sound_array, overlap, pitch_lower, pitch_upper)
. Or maybe even a pitch_offset
which would generate a range +- the offset, e.g. [0.8, 1.2]
from offset 0.2
.
I can provide a PR in the following days if you are too busy to implement that. Thanks!
Documentation for Scribble currently mostly lives in script headers. This isn't convenient for most people and limits what formatting can be used. Better documentation makes the engine easier to use and, hopefully, will reveal ways that the API can be streamlined further.
Not sure if this is a bug or not.
But when using effects, it seems they are very exaggerated with small font sizes:
example
It's especially obvious with [shake]
This font is 12x9 pixels per character.
It might be nice if there's a simple way to tweak those settings, unless I'm just missing it.
Thanks!
Spritefonts are rendered under the assumption that all characters lie on the same texture page. Due to GameMaker's texture packing behaviour, sometimes individual images of the source sprite might lie on another texture page. At this time, it is not clear if GameMaker gives us sufficient tools to detect and mitigate this problem.
The current workaround is to put the spritefont in its own texture group and I've updated the wiki accordingly.
Hey, it's me again, with a problem similar to #11, in fact, it may be the very same problem, but in v5.0.X.
I tried forking scribble and adding a clean way to "interrupt" the autotyper by adding a new property, but there is a consistent issue that the "pausing" happens one character too late.
I'm not sure, but it could very well be that the event triggers one character later, since the script call happens in the middle of the autotype processing and is directly referencing it. I don't think it's a shader issue this time. I tried looking for rounding errors, too, but I don't think that's it either.
Regardless, I'm not confident enough to just put a -=1 somewhere in there, so I was hoping you could check out the patch here:
glitchroy@815d129#diff-ea72a6c3e7f97ed30382838bacf15089
It's not about accepting the feature in the first place, since I did add this behaviour without forking scribble previously (and because it didn't work, I started taking a "cleaner" approach). This is just a convient way to see the problem, I think.
Thanks!
When dealing with usernames, it's usually not possible to constrain what Unicode characters are going to be given to your game. Many target platforms expect that you replace any missing characters with “□” (U+25A1).
GameMaker doesn't natively support this, but Scribble can!
The native GMS colors are defined in the BGR format and thus, should set the optional colourIsGameMakerBGR
in scribble_add_colour()
.
Whilst it's convenient to be able to dynamically resize lines of text depending on their contents, more often than not a fixed line height is adequate. By fixing the line height, some optimisations can be made.
If you set a spritefont's source sprite to Separate Texture Page then Scribble gets confused and draws repeating characters. This is due to Scribble reading from the wrong texture page.
GameMaker's 3D system presumes that backface culling is done on counter-clockwise triangles. At the moment, Scribble creates triangles with a counter-clockwise winding necessitating that a different culling mode is used.
This is unintuitive, and the fix is simple enough.
scribble_replace_tag()
is a little confusing as it implies the old tag can no longer be used. This should be replaced with scribble_copy_tag()
.
As this is a fully breaking change, this change should be withheld until a major version upgrade.
Events/tags/shader effects documentation is lacking and leads to confusion.
Hey,
maybe this problem only affects me, but after updating from scribble v4.5.1 to v4.7.3, the typewriter seemed to be shifted to the right by one character.
More specifically, I implement a [pause] custom event which halts the typewriter by setting json[| __SCRIBBLE.TW_SPEED]
to 0 temporarily (ugly, I know). After the update, even though __SCRIBBLE.TW_POSITION
seemed unaffected, the pause happened one character too late.
After multiple days, I tracked the change down to the shader, specifically this line:
https://github.com/JujuAdams/scribble/blob/ca1a6d1523171883f9c19b72dfbaf577ab8e32c1/shaders/shScribble/shScribble.vsh#L141
Changing the param
argument to (in_Normal.x+1.0)/u_fCharFadeCount
seems to fix my issue. Since I'm not really a shader expert and in_Normal
is some kind of default parameter, I can't really trace the root cause back. Maybe someone knows what's causing this behaviour? I compared scribble_step()
and other scripts between the versions, but I do think it's because of the shader and the corresponding call from scribble_draw()
.
Thanks!
PS: I'm only using the "per character" draw setting for the typewriter, so I'm not sure how this would affect drawing by line.
A way to get the length (numb of characters) of a scribble string without the commands would be nice.
I was hoping to just write a script that would grab _scribble_array[__SCRIBBLE.CHARACTERS]
(or some other part of the scribble element array), but __SCRIBBLE.CHARACTERS
doesn't include spaces in its count.
I can achieve what I'm needing with this estimate, but an exact string length without manually parsing would be nice.
Outlining text is a common operation for both pixel art and hires fonts. Scribble should support this.
There are many ways to achieve the effect including:
scribble_draw_set_fade()
is a legacy function left over from previous versions on Scribble. I can't imagine it gets much use.
Kerning pairs are often used in fonts (mostly non-spritefonts) to improve the look of certain letter pairs e.g. A+W = AW
This is not to be confused with a ligatures e.g. f+i= fi!
GM creates kerning pair data but Scribble does not currently respect that data (and neither does the native draw_text
as far as I know). It should be relatively easy to handle kerning pairs given the data is available, but I am concerned about backwards compatibility within Scribble, and performance due to additional ds_map hits.
Additionally, functions should exist to edit kerning pairs and to create new ones. This will be especially useful for spritefonts.
scribble_draw_set_wrap()
changed its argument order in v5.4.3, but no allowance is made for automatically checking to see if the old argument order is being used in a project.
We can scan for a value of 0 or 1 being sent in for the (optional) maxLineHeight
argument and report this as an error. It's unlikely that a line height of 0 or 1 would be used in reality so this is a fair way of checking for this mistake.
Using sprites in the middle of a scribble string is great.
but if using a spritefont, it seems to draw the image down really far.
example:
scribble_draw_set_box_align(fa_left,fa_middle)
scribble_draw(20,400,
"\n[][sfont][sprite_fire,0,.1][scale,3] this is [c_red][wobble]fire..."+
"\n[][sprite_fire,0,.1][scale,3] this is [c_red][wobble]fire...");
The top is using a spritefont, and the bottom a normal font.
Font alignment or sprite origin doesn't seem to make any difference, but scaling the font seems to make things worse. Here, the spritefont isn't scaled up:
Version 6 will include a reworking of how shaders are exposed on the GML side. This requires documentation, which is good because shader documentation for Scribble has historically been poor.
It would seem the only way to get scribble working on an HTML5 build is to use a sprite font. Might be a problem with the way HTML5 building handles included files and sprites. I am not sure thought. Glyph usages is broken too, but [c_color], [wave] and [rainbow] work.
Errors yielded are not very useful from my perspective, even from Debug mode:
Attempting to use sprPlayer sprite as a glyph
Error: must be an array
--------------------------------------------------------------------
function _Uf("must be an array")
function __yy_gml_array_check_index(0, [undefined])
function gml_Script_scribble_draw([instance], [instance], 120, 120, "[sprPlayer]")
function gml_Object_oGame_Draw_64([instance], [instance])
function(2112, 0, [instance], [instance])
function(2112, 0, [instance], [instance])
function([unknown], 2112)
function([unknown])
function()
function _q13()
function _V03()
function _A03(4919.792)
In some cases, a developer might want to recolour certain portions of a text element without regenerating the whole text element. Whilst this is possible to program in manually, Scribble could support this natively.
Given issue #14 and the impending changes with GMS2.3.0, now might be the time to spruce up the shader effects system.
The changelog for runtime 2.2.1.287 states:
- Asset Compiler
- Sped up constructing texture pages from texture groups
- Handling of cropped textures has been improved
(source)
This breaks the glyph data scanning in scribble_load_fonts()
(at line 126 and following). Looking at the generated cache files, it seems that the TexturePageEntries
for the font sprites now all generate with a 1px transparent border around them, regardless of texture page settings.
This causes the fonts to look jagged and cut off, probably because the sprite file is bigger than expected.
Downgrading to runtime 2.2.0.261 fixes the issue for now.
Taking cues from other text renderers, Scribble could use surfaces to cache static portions of text so that the number (and complexity) of vertex buffers can be reduced.
I'm not sure what this would mean for the typewriter effect. Perhaps we could limit surface caching to either 1) non-typewriter text 2) text with a fixed line height. Having a fixed line height means we can write a shader that reveals text on the surface via a fragment shader.
The newline-character in the comment of the SCRIBBLE_NEW_HASHLINE macro (__scribble_config()
, line 8) causes issues with parsing the next macro in line correctly.
Error log:
___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Create Event
for object oInit:
Variable oInit.SCRIBBLE_COMPATIBILITY_MODE(100015, -2147483648) not set before reading it.
at gml_Script_scribble_load_fonts (line 146) - if ( SCRIBBLE_COMPATIBILITY_MODE ) global.__scribble_sprite_font_map[? _name ] = font_add_sprite_ext( _sprite, _sprite_string, true, _shift_constant );
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Script_scribble_load_fonts (line 146)
called from - gml_Script_scribble_init_end (line 13) - scribble_load_fonts( global.__scribble_init_font_array );
called from - gml_Object_oInit_Create_0 (line 6) - scribble_init_end();
As you can see, the next macro in line is not created correctly.
What doesn't work:
Escaping the newline character, e.g. (//Replaces hashes (#) with newlines (\\n) to emulate GMS1 behaviour
).
What does work: Removing the \n
.
Why a comment is parsed at all in this way is beyond me.
Tested on scribble v02.03.00
, GMS2 v2.2.1.375
, GMS2 Runtime v2.2.1.291
, Windows 10 1803.
Here's a fun problem that I've tracked down the cause of, but don't know what a solution would be.
I like to pre-cache my scribbles when possible, to ensure that everything I pass to scribble_draw is a scribble array because that makes things easier when dealing with autotype.
var _stext = scribble_pre_cache_ui("the quick brown fox jumped over the lazy game dev");
All that script really does is set and unset the cache group, it's not that interesting.
scribble_draw_set_cache_group(ScribbleCacheGroups.UI, false, true);
scribble_draw_set_wrap(-1, width);
var scribble = scribble_draw(0, 0, text);
scribble_draw_set_cache_group(ScribbleCacheGroups.UI, true, true);
return scribble;
Anyway, I like to do this often, especially in menus and stuff.
var _stext = scribble_pre_cache_ui("the quick brown fox jumped over the lazy game dev");
if (scribble_text == undefined) {
scribble_text = _stext;
scribble_autotype_fade_in(scribble_text, ...);
}
scribble_draw(a, b, scribble_text);
This used to be fine, but at some point it stopped working. I'm not sure when exactly that happened, since I only noticed last night after revisiting some old code. Every time scribble_draw
is called - regardless of whether the scribble is actually drawn, or anything - the scribble's "time" value is updated.
_scribble_array[@ __SCRIBBLE.TIME] = current_time;
I guess that's all right, but when it comes to autotype, it checks the scribble's delta time before actually updating it. I suppose this makes sense, because if you would try to draw the scribble multiple times in one step, it would update more times than it's supposed to. Unfortunately, when I try to draw the scribble for real immediately afterward pre-caching it (or fetching the cached version), the Scribble's delta time is always going to be zero
var _increment_timers = ((current_time - _scribble_array[__SCRIBBLE.TIME]) > __SCRIBBLE_EXPECTED_FRAME_TIME);
and the scribble autotype position remains in the purgatorial state of 0
for the [FGothic][shake][rainbow]rest of eternity.[]
My guess at what the solution to this should be would be to only set _scribble_array[@ __SCRIBBLE.TIME]
(a) when the scribble is created or (b) when it's actually vertex_submit
ted so that it doesn't interfere with madmen like me who like to use it as a way to invisibly fetch stuff from the cache, but I don't know if there are any other reasons the time value would need to be set or not.
For debug and tutorialising it's useful to be able to draw text that has formatting tags written out in plaintext without applying the formatting e.g.
This text is not [wave]formatted[]
The suggested method to achieve this is to use a double open bracket to escape a formatting tag:
This text is not [[wave]formatted[[]
On the line (currently 39) where the script checks _scribble_array[__SCRIBBLE.FREED]
as part of determining whether a scribble should be cleared or not, it looks like it should check the opposite !_scribble_array[__SCRIBBLE.FREED]
instead, since the scribble otherwise won't enter the freed state to begin with and vertex buffers will never actually be deleted when you ask them to.
Next, the scribble doesn't get removed from the global cache map so if you try to create a scribble with a string that has already been flushed it will return an array with an already-deleted vertex buffer and nag you about drawing an invalid scribble. Adding ds_map_delete(global.__scribble_global_cache_map, _list[| _i]);
to line 35 after the scribble has been fetched from the global map seems to take care of this, but I don't know if there are any other parts to this I'm missing so far.
The new wrapping behaviour in 5.1.0 sometimes adds an empty line break to the beginning of the string. See this example:
This is the relevant code (simplified):
// Create scribble structure
// ...
scribble_draw_set_wrap(-1, 120);
scribble_element = scribble_draw(0, 0, content);
scribble_autotype_fade_in(scribble_element, SCRIBBLE_AUTOTYPE_PER_CHARACTER, tw_speed, 0);
scribble_draw_reset();
scribble_get_bbox(scribble_element, 0, 0)
output for string "123456789ABCDEFG" is [ 0, 0, 123, 0, 0, 32, 123, 32 ]
for the per-word version and [ 0, 0, 116, 0, 0, 32, 116, 32 ]
for the per-character version. The content
variable however does not have the line break, making me think this has something to do with the new word wrapping and the max width parameter.
With scribble_init_start()
, a font directory needs to be specified, even if only sprite fonts are ever used. Furthermore, the directory has to contain at least one file.
The given error (Line 22 in scribble_init_start()
) outputs an unrelated and, at least on my system, not existing folder in AppData as the problem (using game_save_id
).
I solved this error temporarily by adding a "Fonts" folder and a dummy file to my included files.
Specs: GMS2 v2.2.1.375, Runtime 2.2.1.287, Windows 10 1809
Having access to the texel width/height in the default shader will make certain effects much easier to execute.
I have scribble being used in a text object that is called on whenever the player hits the enter key near an NPC. When I call Text object the first time the scribble_autotype_set_sound script works and the sound plays but when scribble is called for the second time the text object the scribble_autotype_set_sound script won't work, it just stays silent, even though its being called. It only works the first time I boot the game up.
Seems to be similar to #10, I don't know if it's the same problem that's come back or if it's a shiny new one.
If a sprite's origin is set to the upper-left, it looks fine.
Yes I spelled "aperture" wrong, don't judge me.
If it's in the center, it starts looking a bit off.
If it's all the way at the bottom-right, it's way out in deep right field.
Code:
scribble_draw_set_wrap(32, 1200);
scribble_draw_set_cache_group(0, false, true);
scribble_draw(32, 32, "Apeture Science (sic), we do what we must because we can.\n\nFor the good of all of us, except the ones who are [spr_dead]");
scribble_autotype_fade_in(scribble, SCRIBBLE_TYPEWRITER_PER_CHARACTER, 0.125, 1);
scribble_draw_reset();
Keeping the sprite origin in the upper-left seems to align it correctly in all conceivable real-world use cases, which is to say it's automatically centered with the text, but if you have a sprite that you want to use both in Scribble and somewhere else in the project and you want it to have a different sprite origin, problems might start occurring.
The autoscan feature currently use file functions to recursively scan Included Files for fonts. It's probably possible to automatically scan for and load fonts without using these functions, instead using the list of fonts as a guide.
Scribble tries to center in-text sprites that it draws, but if the origin isn't in the upper-left - say, in the center, for example - it doesn't quite know what to do.
[spr_xbox][spr_keyboard]Show Info
where spr_xbox
originates at (0, 0) and spr_keyboard
originates in the center, you get this:
instead of this:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.