Renderen van teksten in moderne browsers met behulp van HTML5 Afstudeeronderzoek van Simon Karman bij Tingly Games
Student Simon Karman Hogeschool van Amsterdam Alexander Mulder Tingly Games Mark Overmars
Renderen van teksten in moderne browsers met behulp van HTML5 Afstudeeronderzoek van Simon Karman bij Tingly Games
Student Simon Karman – S. J. Karman Student nr.: 500621839 Telefoon nr.: 06 26 808 237 Website: www.simonkarman.nl
Hogeschool van Amsterdam Opleiding Informatica - richting Game Technologie Begeleidende docent: Alexander Mulder
Tingly Games Westersingel 18-I 3014GP Rotterdam 010-8467812 Begeleider: Mark Overmars Website: www.tinglygames.nl
Periode 2 februari 2014 – 27 juni 2014, Studiejaar 2013-2014, Semester 2
Voorwoord Mijn naam is Simon Karman, vierdejaars student Technische Informatica, Game Technologie, aan de Hogeschool van Amsterdam. Dit onderzoeksrapport heb ik geschreven naar aanleiding van mijn onderzoek tijdens de afstudeerstage. In dit onderzoeksrapport beschrijf ik hoe ik het onderzoek heb aangepakt en wat mijn bevindingen hierbij zijn geweest. Ik heb de afstudeerstage uitgevoerd bij en in opdracht van Tingly Games. Ik wil de medewerkers van Tingly Games hartelijk bedanken voor de plezierige werksfeer tijdens mijn stageperiode. Daarnaast hoop ik dat mijn onderzoek bijdraagt aan een verdere ontwikkeling van het bedrijf. Veel plezier met het lezen van mijn verslag. Simon Karman zondag 1 juni 2014
Simon Karman - Tingly Games, 2014 3
.
Inhoudsopgave RENDEREN VAN TEKSTEN IN MODERNE BROWSERS MET BEHULP VAN HTML5 AFSTUDEERONDERZOEK VAN SIMON KARMAN BIJ TINGLY GAMES
2 2
VOORWOORD
3
INHOUDSOPGAVE
4
SAMENVATTING
7
TERMEN
8
INLEIDING
10
RENDEREN VAN TEKSTEN IN MODERNE BROWSERS MET BEHULP VAN HTML5
11
1 DE CONTEXT VAN DE OPDRACHT 1.1 TINGLY GAMES 1.2 OPDRACHTAANLEIDING 1.3 OPDRACHTOMSCHRIJVING 1.4 OPDRACHTANALYSE 1.5 PROBLEEMVRAAG 1.6 DEELVRAGEN 1.7 WERKWIJZE 2 ONDERZOEKSMETHODE 2.1 KWALITEITSCRITERIA 2.2 BESTAANDE IMPLEMENTATIE 3 VERKENNING VAN DE AANPAKKEN 4 ONDERZOEK VAN DE AANPAKKEN 4.1 BITMAP FONT 4.2 VECTOR FONT 5 DE KEUZE VOOR EEN AANPAK 6 ONTWERPFASE 6.1 STRUCTUUR 6.2 COMPTABILITEIT MET BESTAANDE VERSIES 6.3 INLADEN 6.4 BROWSER SPECIFIEKE EISEN 6.5 VECTOR FONT EIGENSCHAPPEN 6.6 TEKST BREEDTE 6.7 CONTEXT WIJZIGINGEN TERUGDRAAIEN 7 REALISATIEFASE 7.1 IMPLEMENTATIE 7.2 DOCUMENTATIE 7.3 GEBRUIK 7.4 LETTERTYPEN
11 11 11 11 11 11 12 12 13 13 15 16 17 17 17 19 20 20 21 22 22 23 25 25 27 27 27 28 28 Simon Karman - Tingly Games, 2014 4
.
8 EFFICIËNTIE 8.1 VECTOR FONT EFFECT SNELHEID 8.2 VECTOR FONT VERSUS BITMAP FONT EN LOSSE CANVAS SNELHEDEN 9 WORD ART 9.1 EFFECTEN 9.2 API 9.3 DEMO SITE 9.4 GEBRUIK 10 NIET-WESTERSE KARAKTERS
31 31 33 35 35 38 39 39 40
CONCLUDEREND OVERZICHT
41
BRONNENLIJST
42
BIJLAGEN
43
BIJLAGE A: TINGLY GAMES BIJLAGE B: WEBSITE ARTIKEL – SIMON KARMAN BIJ TINGLY GAMES ACHTERGRONDINFORMATIE WEBARTIKEL BIJLAGE C: DE MEETWAARDEN VOOR DE KWALITEITSCRITERIA 1-BRUIKBARE TEKENSET 2-RENDERTIJD 3-BROWSER COMPATIBILITEIT 4-LAADTIJD 5-TOEPASSINGSMOGELIJKHEDEN BIJLAGE D: MEETWAARDEN BITMAP FONT BRUIKBARE TEKENSET RENDERTIJD BROWSER COMPATIBILITEIT LAADTIJD TOEPASSINGSMOGELIJKHEDEN LEESBAARHEID BIJLAGE E: MEETWAARDEN VECTOR FONTS BRUIKBARE TEKENSET RENDERTIJD BROWSER COMPATIBILITEIT LAADTIJD TOEPASSINGSMOGELIJKHEDEN LEESBAARHEID BIJLAGE F: HET TBVECTORFONT PROTOTYPE LOSSE PROTOTYPE PROTOTYPE IN DE TINGLY BUILDER BIJLAGE G: RENDERTIJD IN DE TESTOMGEVINGEN TESTOMGEVING 1: TIJD PER CONFIG TEST OMGEVING 2: FRAMES PER SECONDE
43 44 44 44 45 45 45 46 46 47 48 48 48 48 48 49 49 50 50 50 50 50 51 51 53 53 55 58 58 60 Simon Karman - Tingly Games, 2014
5
.
BIJLAGE H: CONTEXT SAVE/RESTORE EN TRANSFORMATIES SNELHEDEN BIJLAGE I: VECTOR FONT LIBRARY DOCUMENTATIE VECTOR FONT RESOURCE TBVECTORFONT API BIJLAGE J: TEKSTBREEDTE BIJ HET GEBRUIK VAN SPATIES BIJLAGE K: VECTOR FONT EFFECT SNELHEID DE PROFIELEN DE STIJLEN RESULTATEN EXTRA 1: EXTERN ARIAL VS BUILD-IN ARIAL EXTRA 2: FILLTYPEN GLOBALE WAARNEMINGEN BIJLAGE L: VECTOR FONT VERSUS BITMAP FONT EN LOSSE CANVAS SNELHEDEN DE PROFIELEN EN STIJLEN RESULTATEN WAARNEMINGEN BIJLAGE M: ANTI-ALIASING IN VERSCHILLENDE BROWSERS WAARNEMINGEN CONSLUSIE BIJLAGE N: GECOMBINEERDE LETTERTYPEN INLADEN FALLBACK MECHANISME TOEPASBAARHEID BIJLAGE O: SKEW TRANSFORMATIES OP DE CANVAS BIJLAGE P: WORDART DOCUMENTATIE WORDART TBWORDART NAMESPACE KIND CHARINFO OBJECT PRESETS CHANGERS BIJLAGE Q: STROKE ARTIFACTS DE OPLOSSING SNELHEIDSTEST BIJLAGE R: NIET-WESTERSE KARAKTERS LOKALISATIE TOOL TINGLY BUILDER BROWSERS
Simon Karman - Tingly Games, 2014 6
62 64 64 67 72 73 73 73 74 78 79 80 81 81 81 83 84 84 85 86 86 86 87 88 90 90 90 90 92 92 93 94 94 94 96 96 96 96
.
Samenvatting Tingly Games is een bedrijf dat spellen ontwikkelt. De spellen worden ontwikkeld in een relatieve nieuwe omgeving: HTML5. Tingly Games wil graag meer controle over het gebruik van teksten in deze omgeving. Het doel van dit onderzoek is om hiervoor de beste aanpak te vinden. De volgende onderzoeksvraag is opgesteld naar aanleiding van de vraag van Tingly Games: Wat is, volgens de samen met Tingly Games op te stellen kwaliteitscriteria, de beste aanpak om teksten te renderen voor het gebruik in de HTML5 engine van Tingly Games? Op basis van de resultaten en conclusies van dit onderzoek kan worden gesteld dat vector fonts het best aan de kwaliteitscriteria van Tingly Games voldoen. Mark Overmars (de CTO) heeft hiermee ingestemd. Andere werknemers, waaronder developers en artists waren ook erg enthousiast over de mogelijkheden met het gebruik van vector fonts. Nadat duidelijk was dat vector fonts gebruikt moeten kunnen worden, was het zaak te beginnen aan een ontwerp voor een vector font library. De API van deze library heeft een eenvoudig te gebruiken structuur gekregen en is consistent gehouden met eerdere versies van de font library. Daarnaast laadt de library voor de browser onbekende lettertype in en ondersteunt de library alle vector font eigenschappen die standaard door HTML5 worden ondersteund. Deze library is vervolgens gerealiseerd en door Tingly Games in gebruik genomen. Na gebruik zijn nog enkele kleine aanpassingen gemaakt naar aanleiding van feedback. Deze feedback ging over de werking en het gebruiksgemak voor andere developers. Ook is er documentatie geschreven op basis van de API en het gebruik van lettertypen in browsers. Na de implementatie is er gekeken naar de snelheid van het gebruik van vector fonts. Onderzocht is de snelheid van het tekenen van de tekst bij verschillende eigenschappen. Ook is de library vergeleken met de vorige font implementatie die door Tingly Games werd gebruikt. Op basis van deze resultaten is een bedrijfspresentatie gegeven en zijn tips opgesteld voor het gebruik van de library. Naast dat de standaard HTML5 eigenschappen worden ondersteund is het ook erg interessant om handmatig effecten mogelijk te maken. Hiervoor zijn de mogelijkheden binnen HTML5 onderzocht. Vervolgens is een losse library geschreven waarmee deze mogelijkheden door middel van een eenvoudige API kunnen worden toegepast. Hierbij is een demo website ontwikkeld. Een van de aanleidingen voor dit onderzoek was dat Tingly Games graag ziet dat de engine waarmee de games ontwikkeld worden het gebruik van niet-westerse karakters kan ondersteunen. Om nietwesterse karakters te ondersteunen zijn alle stappen in het ontwikkelingsproces binnen Tingly Games doorgelopen zodat elke stap ondersteuning biedt aan het gebruik van niet-westerse karakters. Het eindresultaat voldoet uitstekend aan de wensen van Tingly Games. Mijn product is direct en enthousiast in gebruik genomen. In alle lopende projecten is mijn product toegevoegd. Ook in projecten die in de toekomst gemaakt zullen worden, zal mijn product verwerkt zitten. Een erg mooi, leerzaam en bruikbaar eindresultaat van een geslaagd afstudeeronderzoek.
Simon Karman - Tingly Games, 2014 7
.
Termen In dit onderzoekrapport zal worden onderstaande termen veel gebruikt. Om mijn onderzoek te goed kunnen volgen is het van belang dat deze termen voor de lezer duidelijk zijn. Wanneer een term niet duidelijk is, staat hieronder de betekenis binnen de context van mijn onderzoek. Tingly Games Tingly Games is het bedrijf waar ik mijn onderzoek heb uitvoerd. Er werken ongeveer acht mensen en het bedrijf is gevestigd in Rotterdam. Meer informatie is te vinden op www.tinglygames.com. Greeting Games Greeting Games is (op het moment van schrijven) de enige dienst die Tingly Games levert. Eenvoudig gezegd is een Greeting Game een combinatie van een wenskaart en een leuk spelletje. Greeting Games wenskaarten zijn er voor iedere gelegenheid. Je kunt ze bijvoorbeeld verzenden als kaart voor Valentijnsdag. Je kunt ze versturen als verjaardagskaart of beterschapkaart. Je kunt ze gebruiken als bedankje, felicitatie, of uitnodiging. Je kunt er bijvoorbeeld je vrienden mee uitnodigen voor een feest, een verjaardag, of een date. De Greeting Games bevatten populaire spellen. Denk hierbij aan bubbleshooters, matchers, slicers, mahjong, sudoku, woordzoekers, legpuzzels en nog veel meer. Meer informatie is te vinden op www.greetinggames.com. Tingly Builder Tingly Builder is het door Tingly Games ontwikkelde programma waarin HTML5 spellen kunnen worden opgebouwd en geconfigureerd. De Greeting Games worden met gebruik van de Tingly Builder ontwikkeld. De Tingly Builder is opgezet door Mark Overmars en hij onderhoud deze ook. De Tingly Builder bevat uitgebreide documentatie en de game programmeurs hebben een eigen framework opgezet in de Tingly Builder. Framework De werkomgeving in de Tingly Builder waarbinnen de Greeting Games worden ontwikkeld. Het framework is gebouwd op de functionaliteit van de engine en voegt hier Greeting Games specifieke functionaliteit aan toe. Engine De engine is de javascript code die wordt gebruikt door de Tingly Builder en waarmee de HTML5 spellen worden gegenereerd. Mijn code zal worden opgenomen als onderdeel van de engine. HTML5 HTML5 (HyperText Markup Language 5) is de nieuwste, nog onafgewerkte versie van de HTMLstandaard1. In HTML5 zitten een aantal nieuwe functionaliteiten. Deze nieuwe functionaliteiten worden door Tingly Games gebruikt om games te kunnen maken die draaien op een webpagina in de verschillende browsers. 1
http://nl.wikipedia.org/wiki/HTML5
Simon Karman - Tingly Games, 2014 8
.
Het feit dat HTML5 werkt via de browser, garandeert brede ondersteuning voor pc, tablet en telefoon. Canvas De canvas is een nieuwe feature die HTML5 aanbiedt. De canvas is voor dit onderzoek de belangrijkste nieuwe feature van HTML5. De canvas wordt gebruikt voor het maken van interactieve omgevingen op een webpagina. De engine gebruikt het canvas element om de games in een webpagina te kunnen renderen. Renderen (van tekst) Renderen is het proces waarin een datamodel wordt omgezet in een afbeelding2. In de context van deze opdracht kan het renderen worden gezien als het tekenen van tekst op het scherm. Karakter Een letter of letterteken. Voorbeelden van karakters zijn letters, cijfers, leestekens, chinese karakters en symbolen. Font Een font (Engels voor schrift) beschrijft een tekenset door middel van een visuele representatie van een groep karakters3. Er zijn drie soorten fonts: - Bitmap font; - Vector font (ook wel Outline font); - Stroke font. Deze types verschillen in de manier waarop de karakters door de computer worden gerenderd. Bitmap: De karakters zijn gedefinieerd als pixel plaatjes. Deze kunnen direct naar het scherm worden gerenderd, maar kunnen bijvoorbeeld niet mooi worden geschaald of geroteerd. Vector: De karakters zijn gedefinieerd als een mathematische formule voor de omlijning van het karakter. De karakters kunnen op elke grote worden geschaald maar moeten wel eerst worden omgezet naar een pixel plaatje voordat ze kunnen worden gerenderd op het scherm. Stroke: De karakters zijn gedefinieerd als een collectie van lijnen en een penprofiel. Deze lijnen worden vervolgens gerenderd door middel van het penprofiel. Library Een library (Engels voor bibliotheek) is een verzameling code (functies en routines). API Een API (application programming interface) is een interface die door programmeurs wordt gebruikt om met een library te kunnen werken. Een library is een verzameling van functionaliteit en code. De API is de manier waarop de programmeur deze library kan gebruiken. Een API is een abstracte laag op de library waardoor gebruikers makkelijk van de library gebruik kunnen maken.
2 3
http://en.wikipedia.org/wiki/Rendering_(computer_graphics) http://en.wikipedia.org/wiki/Computer_font
Simon Karman - Tingly Games, 2014 9
.
Inleiding HTML5 is in opkomst. Er is vanuit de industrie steeds meer interesse in het gebruik van deze technologie bij het maken van games. Op deze interesse is adequaat ingespeeld door Tingly Games. Tingly Games is een game ontwikkeling bedrijf dat december 2012 is opgericht. Sindsdien heeft het bedrijf zich gespecialiseerd in het maken van games in HTML5. Ik zocht een uitdagende en vernieuwende onderzoeksopdracht voor mijn afstudeerscriptie. De onderzoeksopdracht die Tingly Games me aanbood voldeed hieraan. Het gebruik van deze nieuwe technologie in combinatie met het leren van de voor mij onbekende taal JavaScript sprak me erg aan.
Tingly Games ziet meer mogelijkheden met het gebruik van teksten in de games die ze maken. Daarnaast ziet Tingly Games graag dat de engine in de toekomst het gebruik van niet-westerse karakters ondersteunt. Dit geeft aanleiding tot het vinden van een nieuwe manier om teksten te renderen in HTML5 en die toe te passen in de engine van Tingly Games. De onderzoeksvraag die hieruit kan worden opgesteld is de volgende: Wat is, volgens de samen met Tingly Games op te stellen kwaliteitscriteria, de beste aanpak om teksten te renderen voor het gebruik in de HTML5 engine van Tingly Games? Om deze onderzoeksvraag te beantwoorden moeten eerst de mogelijke aanpakken op een rijtje worden gezet. Vervolgens moet op basis van de met Tingly Games op te stellen kwaliteitscriteria een keuze gemaakt voor de beste aanpak. Deze aanpak moet vervolgens uitgewerkt worden tot een product dat binnen Tingly Games inzetbaar is. Dit onderzoeksrapport laat zien hoe de kwaliteitscriteria tot stand komen, welke aanpakken er worden geanalyseerd en welke keuzes er tijdens de ontwerp- en realisatiefase van het product gemaakt worden.
Simon Karman - Tingly Games, 2014 10
.
Renderen van teksten in moderne browsers met behulp van HTML5 1 De context van de opdracht 1.1 Tingly Games Dit onderzoek is uitgevoerd bij Tingly Games. Tingly Games opereert internationaal. Het bedrijf heeft momenteel acht medewerkers in dienst. Daarnaast werken er ook een aantal stagiaires en een aantal freelancers. Zie ‘Bijlage A: Tingly Games’ voor de bedrijfsstructuur.
Tingly Games biedt een dienst aan genaamd Greeting Games (www.greetinggames.com). Greeting Games zijn een blend van elektronische wenskaarten en digitale games. Het geeft mensen de mogelijkheid om gepersonaliseerde games met een geïntegreerde wens naar hun vrienden te verzenden. Alle games worden ontwikkeld in HTML5 zodat ze ook op mobiele apparaten goed te spelen zijn. 1.2 Opdrachtaanleiding In de toekomst wil Tingly Games haar games ook in Aziatische talen aan gaan bieden. Momenteel maken alle producten die Tingly Games ontwikkelt gebruik van het Westerse schrift. De games kunnen eenvoudig gelokaliseerd worden in verschillende talen. Het gebruik van niet westerse karakters wordt met de huidige technologie die Tingly Games gebruikt niet ondersteund. Tingly Games wil dat de engine waarmee de games ontwikkeld worden het gebruik van niet-westerse karakters in de toekomst wel zal ondersteunen. Daarnaast ziet Tingly Games graag meer mogelijkheden met de te weergeven tekst. 1.3 Opdrachtomschrijving Er moeten geschikte aanpakken gevonden worden voor het renderen van teksten binnen HTML5 voor het gebruik in de engine van Tingly Games. Dit bekent dat er samen met Tingly Games kwaliteitscriteria moeten worden opgesteld. Uit de gevonden aanpakken moet op basis van deze kwaliteitscriteria de beste aanpak worden gekozen. De gekozen aanpak moet vervolgens uitgewerkt en geïmplementeerd worden. 1.4 Opdrachtanalyse De opdracht is een onderzoek gericht op een onderbouwde keuze van een aanpak. Dit onderzoek zal uit twee delen bestaan. Deel een is het in kaart brengen van mogelijke aanpakken. Deel twee is de beoordeling welke aanpak het beste voldoet aan de kwaliteitscriteria van Tingly Games. Na het uitvoeren van het onderzoek zal de beste aanpak worden uitgewerkt en geïmplementeerd. Het product dat dit oplevert zal worden opgenomen in de engine. 1.5 Probleemvraag Wat is, volgens de samen met Tingly Games op te stellen kwaliteitscriteria, de beste aanpak om teksten te renderen voor het gebruik in de HTML5 engine van Tingly Games? Simon Karman - Tingly Games, 2014 11
.
1.6 Deelvragen - Wat zijn de kwaliteitscriteria voor de keuze van een aanpak? - Hoe is het renderen van teksten op dit moment binnen de engine geïmplementeerd? - Wat zijn de mogelijke aanpakken voor het renderen van teksten binnen HTML5? - Wat is op basis van de opgestelde kwaliteitscriteria de beste aanpak? 1.7 Werkwijze De developers bij Tingly Games hebben hun eigen werkwijze ontwikkelt. Bij deze werkwijze horen tools en is gekozen voor een bepaalde software ontwikkelmethode. Hieronder is weergegeven hoe het bij Tingly Games in z’n werk gaat. 1.7.1 Tools Bij Tingly Games worden de volgende tools gebruikt: BitBucket Notepad++ JIRA FileZilla Tingly Builder
Voor versie beheer van de code Voor het schrijven van code Voor het bijhouden van taken en bugs Voor het uploaden van games naar het web Tool voor het maken van HTML5 games. Deze tool is door Tingly Games ontwikkeld
1.7.2 Software ontwikkelmethode Bij Tingly Games wordt gewerkt met een agile sofware ontwikkelmethode. Deze methode heeft veel raakvlakken met de SCRUM methode. Bij Tingly Games wordt niet geheel volgens SCRUM gewerkt, maar met een variatie hierop. Ik werk bij Tingly Games aan een losstaande opdracht. Het ontwikkelteam waar ik deel van uit maak bestaat daardoor alleen uit mijzelf. Mark is de SCRUM master van dit team. Het is niet nodig om dagelijkse standups te houden. Aangezien dit een eenmansteam is, weet “iedereen” binnen het team waar de rest van het team mee bezig is. Wel is er elke maandag ochtend een standup met het hele bedrijf. Ook vindt er om de twee a drie weken een retrospective plaats met het team en de SCRUM master. Hierin wordt het functioneren van het team in de afgelopen sprint besproken. Direct na elke retrospective wordt een sprintplanning gehouden. Tijdens de sprintplanning worden de werkzaamheden op basis van de productbacklog ingepland. Aangezien dit een eenmansteam is, is er voor gekozen om bij elke sprint maar één nieuwe user story op te pakken. Daarnaast is er tijdens elke sprint tijd om aan mijn scriptie te werken. Verder vindt er uiteraard communicatie plaats binnen het bedrijf. Deze communicatie met andere programmeurs en artists vindt plaats wanneer ik informatie nodig heb van anderen of anderen van mij.
Simon Karman - Tingly Games, 2014 12
.
2 Onderzoeksmethode In de onderzoeksmethode worden de deelvragen concreet gemaakt. Dit gebeurt door het opstellen van de kwaliteitscriteria, het beoordelen van de huidige implementatie en het documenteren en beoordelen van mogelijke aanpakken. 2.1 Kwaliteitscriteria Om goed te kunnen beoordelen welke aanpak de beste aanpak is, is het van belang dat de aanpakken op basis van duidelijke kwaliteitscriteria worden beoordeeld. Deze kwaliteitscriteria moeten uiteraard gebaseerd zijn op de visie van Tingly Games. De aanpakken zullen op basis van de volgende criteria worden beoordeeld: 123456-
Bruikbare tekenset; Rendertijd; Browser compatibiliteit; Laadtijd; Toepassingsmogelijkheden; Leesbaarheid.
De criteria zijn geprioriteerd op mate van belang voor het eindproduct. De prioritering loopt van meest belangrijk (bovenaan) tot minst belangrijk (onderaan). Een hogere prioriteit betekend echter niet dat een eventueel slecht scorend criterium met een lagere prioriteit niet mee weegt. De prioritering kan meer gezien worden als een richtlijn bij het kiezen tussen vergelijkbare aanpakken. Hieronder staat per criterium een toelichting. De toelichting bevat de betekenis van het criterium, hoe het criterium de algehele kwaliteit van de aanpak beïnvloedt en de aspecten van het criterium waar aan getoetst moet worden bij de beoordeling. De meetwaarden per criterium zijn te vinden in ‘Bijlage C: De meetwaarden voor de kwaliteitscriteria’. Hierbij staat ook de scoringstabel beschreven. 1-Bruikbare tekenset De bruikbare tekenset is de hoeveelheid karakters die wordt ondersteund wanneer deze aanpak wordt toegepast. Elk font heeft een bruikbare tekenset. Daarnaast zal elke aanpak toegang geven tot de gehele of tot een deel van een bruikbare tekenset van een font. Hoe meer karakters de tekenset bevat hoe beter dit is voor de kwaliteit van de aanpak. Dit criterium staat boven aan de prioriteitenlijst, omdat het toegankelijk maken van niet-westerse karakters de aanleiding is van dit onderzoek. 2-Rendertijd De tekst zal bij de gebruiker gerenderd moeten worden op het scherm. Welke aanpak er ook wordt gebruikt, bij elke aanpak is er sprake van het renderen op de HTML5 canvas. En dit kost tijd. Hoe sneller de tekst gerenderd kan worden hoe beter dit is voor de kwaliteit van de aanpak. Dit criterium staat als tweede in de prioriteitenlijst, omdat het erg belangrijk is dat de producten niet te traag worden. De producten moeten snel genoeg zijn om te draaien in browsers op bijvoorbeeld een trage mobiele telefoon. Simon Karman - Tingly Games, 2014 13
.
3-Browser compatibiliteit De HTML5 games draaien op veel verschillende apparaten. Het is belangrijk dat de aanpak op zoveel mogelijk van deze apparaten en bijbehorende browsers compatibel is. Hoe meer browsers er zijn waarop de aanpak werkt, hoe beter dit is voor de kwaliteit van de aanpak. Daarnaast moet er op gelet worden dat de browsers die de aanpak niet ondersteunen wel een logische en duidelijke terugvalmethode hebben. Op deze terugvalmethode kan de engine terugvallen wanneer de aanpak niet werkt. Aangezien we met HTML5 werken, hoeven we alleen versies van browsers te testen vanaf het moment dat ze het canvas element van HTML5 ondersteunen. Ondersteunt de browser het gebruik van de canvas niet, dan kunnen we deze browser buiten beschouwing laten. 4-Laadtijd De laadtijd is de tijd die de aanpak nodigt heeft voordat er gebruik van kan worden gemaakt. Deze tijd kan uit meerdere onderdelen bestaan. Een van de onderdelen is de downloadtijd. De downloadtijd is de tijd die het kost om de benodigde bestanden bij de gebruiker te krijgen. Hoe groter de benodigde bestanden hoe langer dit duurt. Daarnaast kan het zijn dat de browser of server verwerkingstijd heeft. Deze verwerkingstijd is ook onderdeel van de laadtijd. Hoe korter de laadtijd hoe beter dit is voor kwaliteit van de aanpak. 5-Toepassingsmogelijkheden De gerenderde tekst moet goed toepasbaar zijn binnen een game. Dit criteria definieert extra features die handig zijn als ze werken. Elke feature is een pluspunt. Hoe meer features haalbaar zijn, hoe beter dit is voor de kwaliteit van de aanpak. Features waar naar gekeken wordt zijn: Het schalen van tekst, het verkleuren van tekst en het renderen van schaduwen achter de tekst. 6-Leesbaarheid De leesbaarheid van de tekst is de mate waarin de tekst op lagere resoluties leesbaar blijft. De gebruiker kan de tekst bijvoorbeeld via mobiele apparaten op kleine beeldschermen bekijken. Het is belangrijk dat de tekst in deze situaties leesbaar blijft.
Simon Karman - Tingly Games, 2014 14
.
2.2 Bestaande implementatie Op dit moment is er al een implementatie van een Font systeem in de engine aanwezig. Om van dit systeem te kunnen leren, en om ook de tekortkomingen van dit systeem te kennen, is het belangrijk om de bestaande implementatie in kaart te brengen.
Figuur 1: Bestaande implementatie
In Figuur 1 is te zien hoe de bestaande implementatie eruit ziet. In de bestaande implementatie geef je aan welk font je wilt gebruiken en welke karakters je nodig hebt. Vervolgens worden alle karakters op een grote afbeelding geplaatst. De rode rechthoeken geven de randen van de karakters aan. De rode lijn onder in deze rechthoek geeft de baseline van de tekst weer. Wanneer je een karakter op het scherm wilt renderen wordt simpelweg het bijbehorende gedeelte van deze afbeelding op het scherm gerenderd. Bij het renderen van een stuk tekst wordt steeds een los karakter naast het vorige gerenderd. Via deze vorm zijn ook breedtemetingen, kerning, spacing en alignment geïmplementeerd. Daarnaast is het ook mogelijk om de tekst te schalen en te roteren. Dit gebeurt doormiddel van het aanpassen van de canvas matrix. De bestaande implementatie is een toepassing van bitmap fonts.
Simon Karman - Tingly Games, 2014 15
.
3 Verkenning van de aanpakken Het is nu duidelijk op basis van de welke kwaliteitscriteria de aanpak wordt beoordeeld. Ook is de huidige situatie bekend. De volgende stap is het opsommen van de mogelijke aanpakken. In HTML5 zijn er twee mogelijke aanpakken. Namelijk de bitmap font aanpak en de vector font aanpak. Bij de bitmap font aanpak zijn afbeeldingen van de verschillende karakters opgeslagen. Bij het renderen van een stuk tekst wordt steeds een losse karakterafbeelding naast de vorige karakterafbeelding gerenderd door de browsers. De huidige implementatie maakt gebruik deze aanpak. Bij de vector font aanpak wordt het renderen van de tekens gedaan vanuit een mathematische formule voor de omlijning van de karakters. De browsers maken hierbij gebruik van lettertypebestanden waarin deze omlijning staat gedefinieerd. Deze definitie is grootte onafhankelijk.
Simon Karman - Tingly Games, 2014 16
.
4 Onderzoek van de aanpakken Nu de mogelijke aanpakken bekend zijn zullen de kwaliteitscriteria hieronder per aanpak doorlopen worden. 4.1 Bitmap font De bruikbare tekenset van deze implementatie is beperkt tot een (relatief) kleine selectie die in de Tingly Builder moet worden gespecificeerd. Ook kunnen de karakters alleen in de kleur en grootte op het scherm worden weergeven zoals aangegeven in de Tingly Builder. Hoe meer karakters hoe groter de gegenereerde bitmap van het font en dus hoe langer het duurt om het font te downloaden. Daarnaast moet voor elke tekstkleur een aparte bitmap worden gegenereerd. Dit geldt ook voor elke tekstgrootte. Niet-westerse schriften bevatten veel karakters en vergt dus veel karakterafbeeldingen. Wanneer een niet-westers schrift in deze implementatie wordt opgenomen, zal het bitmap font daarom vele malen groter worden. Bij het renderen van tekst wordt (een gedeelte van) een afbeelding op het scherm getekend. Alle browsers die HTML5 en de canvas ondersteunen kunnen hiermee omgaan. Ook kunnen alle browsers zien wanneer een afbeelding geladen is. Hierdoor is er een consistente terugvalmethode te maken. Zie ‘Bijlage D: Meetwaarden bitmap font’ voor de meetwaarden.
Bruikbare tekenset Rendertijd Browser compatibiliteit Laadtijd Toepassingsmogelijkheden Leesbaarheid Eindoordeel
Latin-only, 0 – 399 karakters 0,205ms 82,5% 0,6s 1 punt
+ ++ +/+/+ +/-
4.2 Vector font Bij het gebruik van vector fonts worden de karakters beschreven door het uiterlijk van de randen van de karakters. De randen worden op het moment van renderen omgezet naar pixels. Deze pixels worden vervolgens op het scherm weergeven. Wanneer een font een karakter niet bevat zal worden terug gevallen op een fallback font waarin het karakter wel is opgenomen. Hierdoor kunnen alle karakters worden gerenderd. Het renderen van een vector font gaat erg snel. Het renderen van een woord gaat ongeveer drie keer zo snel met een vector font dan wanneer dit met een bitmap font wordt gedaan. De vector font bestanden waar het vector font in beschreven staat zijn .WOFF bestanden. Deze bestanden worden door alle moderne browsers ondersteund. De .WOFF bestanden zijn vrij klein en er is zeer weinig fontspecifieke code nodig. Daardoor gaat het laden snel. Ook zijn er veel toepassingsmogelijkheden bij het gebruik van vector fonts. Zo is het makkelijk om de tekst te schalen, te kleuren en er effecten op toe te passen.
Simon Karman - Tingly Games, 2014 17
.
Zie ‘Bijlage E: Meetwaarden vector fonts’ voor de meetwaarden.
Bruikbare tekenset Rendertijd Browser compatibiliteit Laadtijd Toepassingsmogelijkheden Leesbaarheid Eindoordeel
Alle UNICODE karakters, 2000+ karakters 0,065ms 77,0% 0,18s 3 punten
++ ++ + ++ ++ + ++
Er zijn meerdere aspecten die moeten worden uitgezocht wanneer de vector fonts worden uitgewerkt. Hieronder licht ik drie aspecten kort toe: Elk font heeft een fallback font. Het is goed om te weten welke fonts op praktisch elke browser zijn geïmplementeerd. Deze fonts noemen we websafe fonts. De websafe fonts worden verderop in dit onderzoek op een rijtje gezet. Voor het gebruik van de .WOFF bestanden van een font moet duidelijk zijn dat deze bestanden legaal gebruikt en gedistribueerd. Wanneer de vector font aanpak wordt gekozen vergt dit verder onderzoek. Lettertypebestanden die binnen Tingly Games worden gebruikt zijn .TTF en .OTF bestanden. Wanneer de vector font aanpak wordt gekozen, moeten deze bestanden door de engine worden omgezet naar .WOFF bestanden. Binnen de engine is voor deze conversie een tool nodig.
Simon Karman - Tingly Games, 2014 18
.
5 De keuze voor een aanpak De aanpakken zijn onderzocht. Er zijn nu meetresultaten op basis van de kwaliteitscriteria beschikbaar. Met deze informatie kan er een keuze worden gemaakt voor de aanpak die gebruikt moet gaan worden. De meetresultaten zijn vrij overweldigend in het voordeel van de vector fonts. De belangrijkste reden is dat er een grotere tekenset bruikbaar is. Daarnaast is de rendertijd een factor drie korter en de laadtijd is ook een factor drie korter. Ook zijn er een veel verschillende toepassingsmogelijkheden. Deze uitgebreidere mogelijkheden voor het renderen van tekst bieden nieuwe uitdagingen en mogelijkheden voor de artists en de developers. Er zijn vanzelfsprekend ook een aantal nadelen aan het gebruik van vector fonts. Zo kunnen vector fonts niet met de hand worden aangepast en opgemaakt. Ook is de browser compatibiliteit minder volledig. Dit houdt in dat er voor een aantal browsers uitzonderingen gemaakt moeten worden. Zo zijn er meerdere bestanden nodig om voor verschillende browsers de fonts te kunnen ondersteunen. Ook hangt de kwaliteit van de tekst af van de browser die wordt gebruikt. Kijkend naar deze voor en nadelen en naar de onderzochte kwaliteitscriteria concludeer ik dat de vector font aanpak de beste is. Vanwege deze conclusie is in overleg met Mark Overmars afgesproken dat vector font aanpak uitgewerkt zal worden. Er zitten nog wel enkele voordelen aan het gebruik van bitmap fonts. Ook maakt de huidige implementatie gebruik van deze techniek. Om van deze voordelen gebruik te kunnen blijven maken en oude projecten die de huidige techniek gebruik te blijven ondersteunen wordt de huidige bitmap font implementatie ook in stand te houden.
Simon Karman - Tingly Games, 2014 19
.
6 Ontwerpfase De keuze is gevallen op een vector font aanpak. In dit deel van het onderzoek staan de ontwerpeisen en bijbehorende ontwerpkeuzes uitgelegd en beargumenteerd. Dit laat zien hoe de aanpak moet worden ontworpen. Het product dat moet wordt ontworpen is een codebibliotheek die het gebruik van vector fonts mogelijk maakt voor de developers bij Tingly Games. De codebibliotheek wordt vector font library of simpelweg library genoemd. De belangrijkste eis aan het ontwerpen van de library is dat de developers binnen Tingly Games de library moeten kunnen gebruiken. Om hiervoor te zorgen is het belangrijk dat de structuur van de library overeenkomt met de structuur van andere delen van de engine. Daarnaast moet de library de standaard functionaliteit die de HTML5 canvas aan teksten biedt ondersteunen. De ontwerpkeuzes die gemaakt zijn om deze eisen te bereiken worden in onderstaande paragrafen uitgelegd. Tijdens het uitwerken van de ontwerpkeuzes zijn twee prototypen ontstaan. Deze staan beschreven in ‘Bijlage F: Het tbVectorFont Prototype’. 6.1 Structuur De twee objecten die de library bevat zijn het tbVectorFont object en het tbVectorFontLoader object. De namen van de objecten in de engine hebben allemaal de tb prefix. Dit staat voor Tingly Builder. De naam van de resource in de Tingly Builder is VectorFont resource.
tbVectorFont object Het tbVectorFont object is het object waarmee teksten op het scherm gerenderd kunnen worden. Vaak wil je eigenschappen hergebruiken bij het renderen van meerdere stukken tekst. Zo wil je misschien met hetzelfde lettertype titels en teksten renderen. Hiervoor gebruik je meerdere tbVectorFont objecten. Deze objecten gebruiken hetzelfde lettertype, maar overige eigenschappen kunnen verschillen. Een tbVectorFont is dus iets anders dan een lettertype. Een tbVectorFont is een staat van eigenschappen (waaronder het lettertype) en een collectie render-routines. Simon Karman - Tingly Games, 2014 20
.
tbVectorFontLoader object Het tbVectorFontLoader object is een object dat het inladen van een lettertype voor z’n rekening neemt. De tbVectorFontLoader zorgt ervoor dat een lettertype door de browsers wordt ingeladen voor het gebruik in de HTML5 canvas. Dit object wordt door de engine aangemaakt en door de developer niet gebruikt. Een tbVectorFontLoader object heeft een naam. Deze naam is de naam van het lettertype. Meerdere tbVectorFont objecten kunnen hetzelfde tbVectorFontLoader lettertype gebruiken door de zelfde naam te gebruiken. Er kunnen dus meerdere tbVectorFont objecten worden gemaakt op basis van een enkel tbVectorFontLoader object. Het gebruik van een tbVectorFontLoader is optioneel. Een tbVectorFont kan als lettertype de naam van een websafe font bevatten. Voorbeelden zijn Arial en Helvetica. Ook de standaard browserwaarden ‘sans-serif’, ‘serif’, ‘monospace’, ‘script’ en ‘fantasy’ kunnen hier worden gebruikt. De naam van het lettertype van een tbVectorFont wordt in de code het fontFace genoemd. VectorFont resource Een developer kan een nieuwe VectorFont resource aanmaken in de Tingly Builder. Een VectorFont resource kan een van de volgende opbouwen hebben: - Een combinatie van een tbVectorFont en een tbVectorFontLoader object. Deze opbouw wordt gebruikt wanneer een nieuw lettertype wordt toegevoegd en er van dit lettertype meteen een tbVectorFont object aanwezig moet zijn. Het tbVectorFontLoader object zorgt dat het nieuwe lettertype wordt geladen. Het tbVectorFont object is een instantie die van dit lettertype gebruikt maakt. - Alleen een tbVectorFont object. Deze opbouw wordt gebruikt wanneer je een bestaand lettertype wilt gebruiken en hiervan een nieuwe tbVectorFont instantie wilt maken. Een bestaand lettertype is vaak een websafe font (zoals Arial), maar kan ook de naam zijn van een andere VectorFont Resource. - Alleen een tbVectorFontLoader object. Deze opbouw gebruik je wanneer je een lettertype wilt inladen, maar hierbij geen tbVectorFont object wilt maken. 6.2 Comptabiliteit met bestaande versies Het moet mogelijk zijn om in bestaande projecten een bitmap font te kunnen verwisselen door een vector font. Hiervoor is het van belang dat de eigenschappen en routines van een bitmap font het zelfde werken in de vector font implementatie. Een bitmap font heeft de volgende eigenschappen: - Align - Baseline - Spacing - Tracking De functionaliteit van deze eigenschappen moet binnen een vector font hetzelfde werken. Voor ‘Align’, ‘Baseline’ en ‘Spacing’ is dit geen probleem. Het toepassen van ‘Tracking’ is echter niet mogelijk met de standaard HTML5 canvas. In overleg met Mark Overmars is besloten de ‘Tracking’ functionaliteit niet meer te ondersteunen voor vector fonts. Simon Karman - Tingly Games, 2014 21
.
6.3 Inladen Alle resources in de engine die externe gegevens moeten inladen, of vanwege een andere oorzaak meer laadtijd hebben, maken gebruik van het tbLoader object. Dit tbLoader object houdt bij welke resources klaar zijn met laden. Dit kan succesvol zijn afgerond of niet succesvol zijn afgerond. De tbLoader houdt daarnaast bij op welk moment de resources geladen moeten worden. Een vector font moet externe gegevens downloaden en deze gegevens vervolgens in de browser inladen. Om deze reden gaat een vector font gebruik maken van de tbLoader. Van een vector font is niet bekend wanneer het succesvol geladen is. Om te checken of een font is geladen is wordt gekeken of de breedte van een getekende tekst in een standaard font verschilt van de breedte van het zelfde stukje tekst getekend met het te laden font. Is het font geladen dan heeft het stukje tekst een andere breedte dan het standaard font. De lengte van de tekst kan toevallig even lang zijn bij het gebruik van het standaard font en het ingeladen font. Om dit te omzeilen wordt de tekstbreedte vergeleken met twee verschillende fonts. Hierdoor moet minimaal een van de twee lengtes veranderen wanneer het font ingeladen is. Daarnaast moet de browser weten dat we het font willen gebruiken. De browsers moet worden verteld dat hij het font moet inladen. Het gebruiken van het font op een canvas is helaas geen rede voor de browser om het font te downloaden. Om de browser toch te vertellen dat we dit font graag willen gebruiken moet er een DOM element worden toegevoegd aan de webpagina waarin het font wordt gebruikt. Door het gebruiken van het font in een element om de webpagina zal het font wel geprobeerd worden in te laden. Zolang het vector font niet succesvol geladen is kan het betekenen dat het laden nog bezig is, of dat het laden van het vector font is mislukt. De tbLoader kan niet op te hoogte worden gebracht wanneer het laden is mislukt. Dit kan resulteren in een tbLoader die voor eeuwig wacht op een vector font. De gebruiker van de library moet deze mogelijke eeuwige wachttijd zelf opvangen. 6.4 Browser specifieke eisen Voor verschillende browsers bestaan specifieke eisen waaraan moet worden voldaan: - Op Android apparaten die gebruik maken van Android versie 4.3 of eerder wordt het WOFF formaat niet ondersteund. Voor deze apparaten moet er naast een WOFF formaat ook een TTF formaat worden aangeboden. Dit TTF formaat krijgt een lagere prioriteit dan het WOFF formaat. Hierdoor maken browsers die WOFF wel ondersteuren gebruik van het WOFF formaat. - De naam van een fontFace moet in sommige browsers beginnen met een hoofdletter of een kleine letter (A-Za-z). Developers zijn vaak geneigd zijn om namen te beginnen met een laagstreepje (‘_’). In deze gevallen werkt het fontFace niet. De developer zal zelf rekening moeten houden met deze restrictie. De Tingly Builder zal dit niet afvangen, om dezelfde reden dat de Tingly Builder JavaScript gereserveerde namen zoals: console, window en function ook niet afvangt. - Er treden foutjes op bij schaduw- en kwaliteitsinstellingen binnen webkit. Webkit is de technologie die gebruikt wordt door bijvoorbeeld Google Chrome en Safari. Voorbeelden van foutjes zijn dat de tekst niet goed wordt geanti-aliased of dat de tekst onverwachte effecten geeft. Er is geen omschrijving bekend wanneer deze foutjes plaatsvinden. Uit tests blijkt dat bij Simon Karman - Tingly Games, 2014 22
.
het gebruik van zeer grootte fonts (190px en meer) foutjes optreden in de gerenderde tekst. Het zelfde geldt voor wanneer er een zeer grote waardes voor shadow-blur worden toegepast. Bij dit soort extreme instellingen is het van belang dat je de tekst in verschillende browsers test. Deze browserspecifieke eisen zijn in het product toegepast. 6.5 Vector font eigenschappen Nu is duidelijk hoe de structuur van de library eruitziet. De volgende stap is uitvinden hoe de structuur van het tbVectorFont object eruit komt te zien. Een belangrijke vraag is: Welke eigenschappen ondersteunt de HTML5 canvas voor het gebruik van vector fonts? Hieronder staan een lijst van vector font eigenschappen. Deze vector font eigenschappen zijn via de HTML5 standaard gedocumenteerd. Het tbVectorFont object ondersteunt deze eigenschappen. Font - fontFace - fontStyle - fontWeight - fontSize
De naam van het fontFace De stijl van het font (‘normal’, ‘oblique’ of ‘italic’) De weight van het font (100-900, ‘bold’, ‘lighter’ of ‘bolder’) De grootte van het font in pixels
De fontVariant eigenschap mist in deze lijst. De fontVariant eigenschap geeft de mogelijkheid om de tekst in small-caps te renderen. De small-caps eigenschap wordt door weinig lettertypen ondersteund. Ook wordt deze eigenschap niet gebruikt door Tingly Games. Deze eigenschap is daarom weggelaten in de library. Wanneer de developer deze eigenschap toch wilt gebruiken kan hij er handmatig bij. Fill -
style fill
De stijl waarmee wordt gerenderd. Door setColor(), setPattern() of setGradient() Of de tekst moet worden gevuld met een stijl
Stroke - style De stijl waarmee wordt gerenderd. Door setColor() - stroke Of de tekst moet worden omlijnd met een stijl - lineWidth De dikte van de omlijning van de tekst Shadow - shadow
De schaduw van de tekst. Bevat color, offsetX, offsetY en blur. Via setShadow()
Simon Karman - Tingly Games, 2014 23
.
Alignment - textAlign - textBaseline -
lineSpacing
De horizontale uitlijning van de tekst (‘start’, ‘end’, ‘left’, ‘center’, ‘right’) De verticale uitlijning van de tekst (‘alphabetic’, ‘top’, ‘hanging’, ‘middle’, ‘ideographic’ of ‘bottom’) De ruimte tussen lijnen van de tekst
De baseline eigenschap zal alleen ‘top’, ‘middle’ en ‘bottom’ ondersteunen.
Simon Karman - Tingly Games, 2014 24
.
6.6 Tekst breedte Een andere belangrijke eigenschap van een vector font is dat het gerenderd kan worden met een vooraf bepaalde maximum breedte. Wanneer de tekst buiten deze breedte valt wordt de tekst opgesplitst in meerder lijnen. Voor het opsplitsen van de tekst wordt het volgende algoritme gebruikt. 1 for each line in the text: 2 split the text up in words at each space character 3 create a new outputline 4 for each word in the line: 5 calculate the length of the word 6 calculate the length of a space 7 sum these lengths, does this length fit within the maximum width when 8 appended to the width of current outputline: 9 add a space and the word to the current outputline and go to the 10 next word 11 otherwise: 12 end the current outputline and create a new outputline starting 13 with the word 14 end the current outputline
In regel 7 is te zien dat dit algoritme uitgaat van de waarheid van de volgende bewering: Lengte(woord) + Lengte(spatie) = Lengte(woord + spatie)
Om er zeker van te zijn dat het algoritme naar behoren werkt is het belangrijk dat bovenstaande bewering waar is. De bewering is bewezen in ‘Bijlage J: Tekstbreedte bij het gebruik van spaties’ en blijkt waar te zijn.
6.7 Context wijzigingen terugdraaien Voor het renderen van tekst op het scherm wordt de context aangepast. Deze aanpassingen wil je na het renderen van de tekst weer terugdraaien. Zodat de context wordt teruggezet in de oorspronkelijk staat.
Er zijn twee manieren waarop de aanpassingen kunnen worden teruggedraaid. - De aanpassingen van de context bijhouden en handmatig terugdraaien. - De save() en restore() routines van de HTML5 canvas gebruiken om de aanpassingen via bestaande routines terug te draaien. Simon Karman - Tingly Games, 2014 25
.
Het gebruiken van de save() en restore() routines heeft de voorkeur. Dit omdat deze routines: - door de browsers zijn gedefinieerd en dus ook worden onderhouden, - altijd alle eigenschappen terugdraaien, - geen JavaScript code zijn, maar geoptimaliseerd zijn door de browsers. Een voordeel dat waarschijnlijk behaald kan worden door het handmatig bijhouden en terugdraaien van de aanpassingen is de snelheid. Door het handmatig bijhouden van aanpassingen kan er voor worden gezorgd dat alleen de aangepaste eigenschappen worden teruggedraaid. Om te testen of dit snelheidsvoordeel daadwerkelijk te behalen valt, is er een onderzoek gedaan. Dit onderzoek staat beschreven in ‘Bijlage H: Context Save/Restore en Transformaties snelheden’. Uit dit onderzoek blijkt dat het gebruik van de save() en restore() routines sneller is dan het handmatig bijhouden en terugdraaien van de aanpassingen. Om deze reden worden de save() en restore() routines gebruikt. De context bevat een transformatie matrix. Deze transformatie matrix kan niet worden opgevraagd. Wanneer deze matrix wordt aangepast zijn de save() en restore() routines vereist. Nu deze routines altijd worden gebruikt zou de transformatie matrix ook altijd kunnen worden aangepast. Uit hetzelfde onderzoek blijkt echter dat sommige browsers tekst trager renderen bij het gebruik van matrixtransformaties. In de betreffende browsers zal waarschijnlijk een optimalisatie plaatsvinden. Deze optimalisatie zorgt ervoor dat wanneer er geen wijzigingen in de matrix zijn, hier geen berekeningen voor gedaan hoeven te worden. Om van deze optimalisatie gebruik te maken moeten de transformaties alleen worden toegepast wanneer nodig. De code is geoptimaliseerd zodat bij het renderen van tekst, waarbij de transformaties niet noodzakelijk zijn, ook geen transformaties worden toegepast.
Simon Karman - Tingly Games, 2014 26
.
7 Realisatiefase Nu de library is ontworpen kan worden begonnen aan de realisatie. Door al het voorbereidende werk is de realisatie niet veel meer dan het uitwerken van de gemaakte keuzes en de gevonden oplossingen. 7.1 Implementatie Een eerste implementatie van het tbVectorFontLoader object en het tbVectorFont object zijn geschreven. Deze twee objecten zijn samen ongeveer achthonderd regels code. Beide objecten zijn gevalideerd en volledig opgeschoond met behulp van de code kwaliteitstool JSLint4. Vervolgens is deze library opgestuurd naar Mark Overmars voor een code review en een verwerking in de Tingly Builder. Na deze review heeft hij de library toegevoegd aan de engine. Mark Overmars heeft in de Tingly Builder een resource ‘VectorFont’ toegevoegd. Een vector font resource is in de Tingly Builder te bekijken en aan te passen. Het bekijken gaat via een scherm waarin een HTML5 canvas draait. De vector font library wordt daarin toegepast. In het onderstaande plaatje is te zien hoe het vector font scherm er in de Tingly Builder uitziet. In dit scherm kan een vector font ontworpen worden. Ook kunnen nieuwe lettertypen worden toegevoegd.
7.2 Documentatie Na de implementatie is het belangrijk dat het de andere developers binnen Tingly Games duidelijk wordt hoe de library in elkaar zit en hoe deze gebruikt moet worden. Om deze reden is er een stuk documentatie geschreven over het gebruik van de vector fonts. Deze documentatie is te lezen in ‘Bijlage I: Vector font library documentatie’.
4
http://www.jslint.com/lint.html
Simon Karman - Tingly Games, 2014 27
.
7.3 Gebruik De library is na de realisatiefase door de developers in gebruik genomen. Het is voor de developers interessant om in een bestaand project een bitmap font te vervangen door een vector font, omdat deze nieuwe mogelijkheden biedt. Door de opbouw van de library kan een bitmap font zonder aanpassingen aan de code worden vervangen door een vector font. Dit is in een project succesvol uitgeprobeerd. Een attentiepunt voor de developer is dat het schalen van een vector font andere resultaten geeft dan het schalen van een bitmap font. Bij een vector font verandert de tekengrootte. Hierdoor blijven de karakters mooi wanneer ze opgeschaald worden. De tekengrootte is helaas een geheel getal. Deze afrondingen leiden tot merkbare haperingen wanneer de schaal van de tekst wordt geanimeerd. Deze haperingen zijn te omzeilen door de tekst eerst op een losse canvas te renderen en deze canvas vervolgens te schalen. 7.3.1 tbVectorFont objecten instantiëren Voor het gebruik van de tbVectorFont objecten is het belangrijk om te weten hoe je een tbVectorFont aan kunt maken. Je kan dit op twee verschillende manieren doen. Je kan de Tingly Builder het tbVectorFont object voor je laten maken of je kan handmatig in code het tbVectorFont object maken. Wanneer de Tingly Builder een tbVectorFont object voor het ‘Kahlesv2’ lettertype aanmaakt worden de volgende regels code gebruikt:
Hierna is het tbVectorFont object met de naam Font1 te gebruiken. Wanneer je zelf via code het tbVectorFont object aan maakt, dan doe je dat op de volgende manier:
Ook hier is vervolgens het tbVectorFont object met de naam Font1 te gebruiken. 7.4 Lettertypen In de Tingly Builder kunnen verschillende lettertypen worden gespecificeerd. Je hebt de mogelijkheid tot het importeren van een eigen lettertype en het gebruiken van build-in lettertype. 7.4.1 Importeren Als je een eigen lettertype wilt importeren, dan moet je een .ttf formaat aanleveren. Dit bestand wordt door de Tingly Builder omgezet naar de benodigde andere formaten. Het kan voorkomen dat je het lettertype dat je graag wilt gebruiken niet in het .ttf formaat beschikbaar is. Toch verwacht de Tingly Builder een .ttf formaat. Op het internet bestaan een hoop online-tools waarmee het lettertype omgezet kan worden dit .ttf formaat. Zo bestaat er de website: http://everythingfonts.com. Via deze website kunnen vrijwel alle lettertype formaten naar het .ttf formaat worden omgezet. Simon Karman - Tingly Games, 2014 28
.
In de Tingly Builder wordt een tool gebruikt om de .ttf formaten om te zetten naar .woff formaten. Hierdoor kunnen de browsers die .woff formaten gebruiken in plaats van de .ttf formaten. Voor het geïmporteerde lettertype is het belangrijk om een fallback lettertype op te geven. Dit fallback lettertype is vaak de naam van een build-in lettertype zoals ‘Arial’, maar kan ook de naam van een andere vector font resource zijn of een combinatie van meerdere namen gescheiden met een komma. 7.4.2 Legal en Distribution Wanneer je een eigen lettertype gebruikt dan zal dit lettertypebestand op de webserver komen te staan. Dit houdt in dat iedereen dit lettertype via jouw server kan downloaden. Je bent het lettertype in theorie dus aan het distribueren. Dit is natuurlijk ook wat je wilt. Je wilt namelijk dat andere mensen het lettertype kunnen downloaden om te gebruiken in jouw game. De kans bestaat dat de speler dit lettertype ook voor andere doeleinden gebruikt. Waar goed op moet worden gelet bij het gebruik van deze lettertypebestanden is dat je ze rechtsgeldig distribueert en je geen illegale handelingen uitvoert. “So the most basic legal rule of font copyright is that unless the license specifically allows it, fonts cannot be shared among multiple computers, even if they are all owned by the same person or corporation, and fonts cannot be given away to others” - ‘(Gaultney, 2003)’ De basis regel waarvan kan worden uitgegaan is dat je het font niet mag distribueren tenzij dit specifiek wordt toegestaan door de licentie overeenkomst. Op veel website waar fonts te downloaden zijn vind je onderstaande licenties. Deze licenties staan weergeven wanneer je een font wilt downloaden. Let hier bij dus goed op dat je het recht hebt om het font commercieel te gebruiken en te distribueren.
7.4.3 Build-in Er zijn in de Tingly Builder een aantal vooraf gedefinieerde build-in fonts. Wanneer je een nieuwe Font Resource maakt kan je een keuze maken voor een van deze build-in fonts. De build-in fonts die standaard in de Tingly Builder gekozen kunnen worden zijn: -
Arial Arial Black Arial Narrow Calibri Cambria Courier New Helvetica Impact Monaco Palatino Papyrus Verdana
Simon Karman - Tingly Games, 2014 29
.
Ook kunnen de door de browser gedefinieerde standaard waarden ‘sans-serif’, ‘serif’, ‘monospace’, ‘script’ en ‘fantasy’ worden opgegeven. Daarnaast kan je ook een andere font naam invullen. Er wordt dan door de engine van uitgegaan dat dit een build-in font is. Dit font moet dus net zoals bijvoorbeeld ‘Arial’ in alle browsers beschikbaar zijn. 7.4.4 Combinaties Veel fonts zijn opgebouwd uit een combinatie van meerdere lettertype varianten. Deze fonts gebruiken naast een standaard font file (.ttf bestand), aparte font files voor elke variant. Een variant is bijvoorbeeld bold, italic of bold-italic. In bijlage: ‘Bijlage N: Gecombineerde Lettertypen’ staat een onderzoek beschreven naar de mogelijkheid tot een implementatie van deze gecombineerde lettertypen. In deze bijlage is de conclusie opgenomen dat het fallback mechanisme bij het gebruik van lettertype combinaties niet meer intuïtief werkt. Daarnaast is het niet mogelijk om meerdere bestanden te koppelen aan een enkele resource in de Tingly Builder. Het ondersteunen hiervan zou een grote herschrijving van de Tingly Builder vereisen. Op grond van deze renderen heeft Mark Overmars geconcludeerd dat er geen verder stappen ondernomen worden om gecombineerde lettertypen te implementeren.
Simon Karman - Tingly Games, 2014 30
.
8 Efficiëntie Het is voor de gebruiker van de library belangrijk om informatie te hebben over de snelheden en efficiency van het gebruik van vector fonts. Nu de library klaar is heb ik tests uitgevoerd om de snelheid van het gebruik van verschillende eigenschappen van de tekst te meten.
Ik heb snelheidsmetingen gedaan met de vector font implementatie. Deze metingen zijn terug te vinden in ‘Bijlage K: Vector font effect snelheid’ en ‘Bijlage L: Vector font versus bitmap font en losse canvas snelheden’. Hieronder geef ik de conclusies van deze metingen weer. 8.1 Vector font effect snelheid Zie ‘Bijlage K: Vector font effect snelheid’
Hieronder staat een schematische weergave van de tijdsbesteding bij het renderen van teksten met verschillende effecten. Deze weergave geeft relatieve verschillen aan en geeft dus geen precieze waarden weer.
Daarnaast is het belangrijk te beseffen dat elke regel tekst die gerenderd moet worden de totale rendertijd aanzienlijk verhoogt. Dit geldt voor het gebruik van NEWLINE karakters in de tekst, maar ook voor tekst die wordt opgesplitst om aan een bepaalde breedte te voldoen. Waarnemingen op basis van alle browsers zijn: - De tijdsduur van ‘Fill en Stroke’ is ongeveer een opsomming van de losse ‘Fill’ en ‘Stroke’ tijd. - Het gebruik van `GradientFill` kost weinig meer dan het gebruik van een standaard `Fill`. - Er is weinig verschil tussen het renderen van een grote (titel) of kleine (button) tekst. Noemenswaardige browserspecifieke waarnemingen: - De absolute resultaten verschillen substantieel tussen de verschillende browsers. Zo is Chrome een factor tien sneller dan Firefox en zelfs een factor twintig sneller dan Internet Explorer. Chrome op Android is ook vrij snel, maar wel een kwart van de snelheid van Chrome onder Windows. Waarschijnlijk wordt dit veroorzaakt doordat Chrome geen anti-aliassing toepast. - Heel opvallend is dat Safari op iOS zeer sloom is in externe fonts. Voornamelijk met het gebruik van ‘Stroke’.
Simon Karman - Tingly Games, 2014 31
.
8.1.1 Extern Font vs Build-in Font Zie ‘Extra 1: Extern Arial vs Build-in Arial’ in ‘Bijlage K: Vector font effect snelheid’ Uit tests blijkt dat het gebruik van een extern font niet verschilt met de snelheid van het gebruik van een Build-in font. Er is dus geen voordeel in rendersnelheid bij het gebruik van een Build-in font in plaats van een Extern Font. Het gebruiken van een Build-in Font heeft toch de voorkeur. Een Build-in Font hoeft niet gedownload te worden. De laadtijd is hierdoor korter.
8.1.2 Filltypen Zie ‘Extra 2: Filltypen’ in ‘Bijlage K: Vector font effect snelheid’
Er bestaan drie filltypen bij het renderen van vector fonts. Dit zijn Color, Pattern en Gradient. Het gebruik van een Color is het snelste filltype, daarna het gebruik van een Gradient en tenslotte het gebruik van een Pattern. Deze volgorde in snelheid geldt voor alle browsers. De absolute waarden van de snelheid verschillen wel sterk.
In contrast met de meeste browsers is het verschil tussen Pattern en Color in Chrome aanzienlijk. Pattern is in Chrome een stuk trager. Daarnaast is binnen Internet Explorer de snelheid van de Gradient lager dan in de ander browsers.
Simon Karman - Tingly Games, 2014 32
.
8.2 Vector font versus bitmap font en losse canvas snelheden Zie ‘Bijlage L: Vector font versus bitmap font en losse canvas snelheden’ voor metingen Om de snelheidsafweging compleet te maken is een vergelijking gemaakt tussen de snelheden bij het gebruik van vector fonts, bitmap fonts en een losse canvas. De snelheden hangen voor een deel samen met het aantal effecten dat wordt toegepast op de tekst. Een losse canvas houdt in dat de tekst op een niet-zichtbare canvas wordt getekend. De tekst staat hier nu op ‘opgeslagen’. Deze losse canvas kan in z’n geheel naar het scherm worden getekend. Dit zou een snelheidsvoordeel kunnen opleveren aangezien de opgeslagen afbeelding sneller getekend zou kunnen worden dan het steeds opnieuw tekenen van een vector font. 8.2.1 Bitmap font vs vector font De snelheid van het renderen van het meeste eenvoudige vector font is vele maal sneller dan het renderen van een bitmap font (zoals bewezen in ‘3 Verkenning van de aanpakken’). De snelheid van het renderen met een bitmap font wordt ongeveer vergelijkbaar wanneer een uitgebreid vector font wordt getekend. Onder uitgebreid vallen onder andere: meerdere regels met tekst, het gebruik van schaduw en het gebruik van een gradiënt. Het voordeel van het gebruik van een vector font is dat het schaalbaar, kleurbaar en het lettertype veranderbaar is. Ook zijn de bestanden kleiner. Het voordeel van het gebruik van bitmap font is dat bij het gebruik van veel effecten het renderen niet vertraagt. Vector Font
Bitmap Font
Schaalbaar Kleurbaar Lettertype veranderbaar Kleinere bestanden
Niet schaalbaar Niet kleurbaar Vast Lettertype Grotere bestanden
Trager bij meerdere effecten
Snelheid blijft gelijk bij meerdere effecten
Uit de test in de bijlage blijkt dat het gebruik van een vector font sneller is dan het gebruik van een bitmap font wanneer er weinig effecten worden toegepast. Het gebruik van bitmap fonts wordt afgeraden. Wel is er een uitzondering. Wanneer je de tekst wilt personaliseren met tekeningen en/of andere effecten die in het Font zitten, en deze effecten zijn niet haalbaar bij het gebruik van een vector font dan kan er toch voor gekozen worden om bitmap fonts te gebruiken. 8.2.2 Losse canvas vs vector font De rendertijd van het renderen van een canvas is sneller dan het renderen van tekst via een vector font. Onthoud wel dat de tekst eenmalig naar de canvas moet worden gerenderd. Dit zal gebeuren met de snelheid van een vector font. Deze canvas wordt opgeslagen en in erop volgende renderfuncties in z’n geheel naar het scherm gerenderd.
Simon Karman - Tingly Games, 2014 33
.
De losse canvas heeft dezelfde nadelen en voordelen als het gebruik van bitmap fonts heeft in vergelijking met vector fonts. Zo kan de losse canvas niet zonder kwaliteitsverlies worden geschaald, gekleurd of op een andere manier worden aangepast. Een ander nadeel dat verbonden is aan het gebruik van een losse canvas, is dat wanneer de tekst vaak verandert er steeds een nieuwe losse canvas moeten worden gecreëerd. De tekst op deze losse canvas moet opnieuw worden gerenderd. Dit kost tijd. De vraag is nu: Vanaf hoeveel frames levert het gebruik van een losse canvas een snelheidswinst op?
Uit de waarnemingen in ‘Bijlage L: Vector font versus bitmap font en losse canvas snelheden’ blijkt dat het renderen van een canvas vele malen sneller is dan het steeds opnieuw renderen van de tekst. Wel is er natuurlijk extra tijd nodig om een nieuwe canvas aan te maken en hier vervolgens op te renderen. Maar de waarnemingen laten zien dat het vanaf zes renders al rendabel is om een losse canvas te gebruiken. Rendabel na zes renders betekent dat een tekst die zes frames onveranderd op het scherm staat, het best met een losse canvas kan worden gerenderd. Bij een game van zestig frames per seconde staan zes frames gelijk aan een tiende van een seconde. Een losse canvas is rendabel voor teksten die langer dan een tiende van een seconde onveranderd op het scherm staan. Dit geldt voor alle teksten. Gebruik een losse canvas voor alle teksten, tenzij de tekst vaker dan tien keer per seconde verandert. Een goed voorbeeld van het gebruik van een losse canvas is een titeltekst. Deze tekst zal statisch zijn en veel effecten hebben. Het gebruik van een losse canvas zorgt bij het gebruik van veel effecten en een statische tekst dat de rendertijd zeer snel blijft. Dat een losse canvas sneller is wordt nog beter merkbaar wanneer de tekst over meerdere regels loopt. Dit komt omdat er nog maar één render-functie aanroep nodig is voor de gehele tekst in plaats van een render-functie aanroep per regel.
Simon Karman - Tingly Games, 2014 34
.
9 Word Art De tbVectorFont library maakt gebruik van alle standaard functionaliteit die de browsers bieden. Naast deze standaard functionaliteit ziet Tingly Games graag ook uitgebreidere tekst effecten. De bedoeling van deze effecten is dat er een decoratieve stijl kan worden gebruikt die past bij de stijl van een game.
Een decoratieve stijl van een tekst wordt Word Art genoemd. Deze Word Art moet ondersteuning bieden aan allerlei verschillende effecten. Voor deze effecten moet een voor de programmeur duidelijk te begrijpen API worden opgezet. De documentatie van deze API is te lezen in ‘Bijlage P: WordArt Documentatie’. 9.1 Effecten Er zijn veel verschillende effecten die leuk kunnen zijn bij het tekenen van een tekst. De effecten die in de Word Art API zitten staan hieronder opgesomd. Met deze losse effecten is elke Word Art stijl te maken. 9.1.1 Lijn De tekst volgt een lijn. In onderstaande afbeelding volgt de lijn een sinus golf. Een developer heeft volledige vrijheid. Hij of zij kan namelijk de functie die de positie van elk karakter berekent zelf aanpassen. Op deze manier kan de tekst elk mogelijke lijn volgen.
9.1.2 Loodrecht De karakters worden op een lijn getekend. Elk karakter staat onder een bepaalde hoek op de lijn. Er kan worden ingesteld hoe het karakter zichzelf tekent aan de hand van deze hoek. Er zijn drie mogelijkheden waarop de karakters aan de hand van de hoek kunnen worden afgebeeld. Dit zijn none (recht op), rotate (loodrecht gedraaid) en skew (scheef gezet). Simon Karman - Tingly Games, 2014 35
.
In onderstaande afbeelding staan alle varianten uitgebeeld.
Bij het gebruik van none wordt niet gekeken naar de rotatie van de lijn. Elk karakter wordt rechtop in de canvas getekend. Wanneer rotate wordt gebruikt dan wordt het karakter geroteerd op basis van de hoek van de lijn. Bij skew wordt het teken scheef gezet op de lijn. Een karakter blijft in dit geval wel altijd rechtop staan. Voor het gebruik van skew moest een onderzoek worden gedaan naar de mogelijkheden hiervan binnen HTML5. Dit onderzoek is terug te vinden in ‘Bijlage O: Skew Transformaties op de canvas’. Uit dit onderzoek blijkt dat het mogelijk is om skew te gebruiken.
9.1.3 Lagen Een karakter kan meerdere keren getekend worden door middel van verschillende lagen. Elke laag heeft een eigen font en een offset. In het font kunnen alle vector font eigenschappen (zoals kleuren en schaduwen) worden aangepast. Hieronder staan enkele voorbeelden afgebeeld:
Simon Karman - Tingly Games, 2014 36
.
9.1.4 Karakters Naast dat er per laag eigenschappen kunnen worden aangepast, is dit ook mogelijk per karakter. Voor elk karakter kunnen het vector font, de graphics-context en het karakter zelf worden aangepast. In onderstaande afbeelding is een tekst te zien waarin de kleur en grootte van het font per karakter verandert aan de hand van de relatieve progressie in het stuk tekst.
vector font: Onder het lettertype vallen alle eigenschappen die een vector font heeft. Dit zijn bijvoorbeeld de kleur en tekstgrootte, maar ook schaduw en omlijning. graphics-context: De graphics-context is de staat van de grafische omgeving waarin de tekst wordt getekend. Deze context kan onder andere worden verplaatst, uitgerekt, gedraaid en geschaald. karakter: Ook het karakter zelf kan worden aangepast. Dit houdt in dat je een ander karakter kan tekenen dan in de tekst staat. Zo zou je alle karakters in een bepaalde laag kunnen vervangen door een bloemetjeskarakter van een speciaal font. 9.1.5 Tracking Tracking is het toevoegen van ruimte tussen de karakters.
Het is bij Word Art mogelijk om ondersteuning te bieden voor tracking. Deze eigenschap was in eerste instantie wel aanwezig bij bitmap fonts, maar vervallen is vector fonts. 9.1.6 Meerdere omlijningen Door middel van verschillende lagen is een tekst met meerdere omlijningen te simuleren. Door de omlijnbreedte van de tekst steeds een aantal pixels te verkleinen is het volgende effect te bereiken:
Bij deze vorm worden omlijningen van een dikte breder dan 10 pixels gebruikt. Wat opvalt is dat bij omlijningen breder dan 10 pixels erg lelijke artifacts optreden. In bijlage ‘Bijlage Q: Stroke artifacts’ staat de oplossing voor dit probleem uitgelegd. De oplossing is om bij bredere omlijningen een andere strokeJoin waarde te gebruiken voor het vector font. Simon Karman - Tingly Games, 2014 37
.
9.2 API Om de Word Art instellingen toegankelijk te maken is het belangrijk dat alle instellingen eenvoudig aan te passen zijn. In ‘Bijlage P: WordArt Documentatie’ is de API beschrijving te lezen. Om goed te begrijpen hoe de Word Art library in elkaar zit, worden hieronder enkele onderwerpen besproken. 9.2.1 Kinds Wanneer je een Word Art wilt gebruiken heb je een zogenaamde Word Art “kind” nodig. Deze kind beschrijft de stijl van de Word Art. Een kind object beschrijft alle eigenschappen van de Word Art stijl. Op deze manier kan je bijvoorbeeld een title-kind een logo-kind of een rainbow-kind maken om te gebruiken wanneer je tekst wilt tekenen. 9.2.2 Losse canvas De Word Art kinds maken gebruik van een grote hoeveelheid effecten en gebruiken meerdere render-functie aanroepen per karakter. De tijd die het kost om een Word Art tekst te renderen kan al snel enkele frames aan tijd kosten. Dit leent zich goed voor het gebruik van een losse canvas. De Word Art API zal een losse canvas gebruiken om de gerenderde tekst op te leveren. De grootte van deze losse canvas moet bepaald worden. Omdat de positie van de karakters niet bekend is, moet deze worden uitgerekend op basis van de positiefunctie en de tekstgrootte op de verschillende lagen in de Word Art.
Om elk karakter dat wordt getekend, wordt een cirkel getekend. Vervolgens wordt er om deze cirkels een rechthoek getekend. Deze rechthoek bevat alle cirkels en daarmee ook alle karakters. Op basis van deze rechthoek wordt de grootte van de losse canvas bepaald. Sommige effecten zoals schaduw kunnen buiten de radius van de cirkel vallen. Dit houdt in dat het kan voorkomen dat er getekend wordt buiten de losse canvas. Wanneer dit gebeurt kan de developer de canvas handmatig groter maken.
Simon Karman - Tingly Games, 2014 38
.
9.3 Demo site Er is een demo site opgezet waarop Word Art kan worden getest. Op deze demo site kunnen allerlei presets worden bekeken en getest.
Deze demo is beschikbaar op http://www.simonkarman.nl/projects/html5_wordart 9.4 Gebruik Word Art is gemaakt nadat de vector font library in gebruik is genomen. Op het moment van schrijven is de Word Art library nog maar net af. Wordt Art wordt nog niet gebruikt in huidige producten. Wel is dit een feature die in de komende projecten in gebruik genomen zal gaan worden.
Simon Karman - Tingly Games, 2014 39
.
10 Niet-westerse karakters De aanleiding voor dit onderzoek was dat Tingly Games graag ziet dat de engine waarmee de games ontwikkeld worden het gebruik van niet-westerse karakters kan ondersteunen. Naar aanleiding van deze wens zijn de tbVectorFont API en tbWordArt API gemaakt. Nu de implementatie gereed is, is er gekeken in hoeverre het nu mogelijk is om niet-westerse karakters te gebruiken. Deze informatie staat in ‘Bijlage R: Niet-westerse karakters’ uitgewerkt. Lokalisatie tool Tingly Builder Browsers Uit deze bijlage blijkt dat het gebruik van niet-westerse karakters na enkele kleine aanpassingen mogelijk is. Na het toepassen van de enkele kleine aanpassingen die in de bijlage staan beschreven kunnen de games gebruik maken van niet-westerse karakters. In onderstaande afbeeldingen zijn niet-westerse karakters weergegeven die als proef in een game gebruikt zijn.
Let op: De tekst in de afbeeldingen is vertaald door middel van Google Translate en kan incorrecte vertalingen bevatten
Simon Karman - Tingly Games, 2014 40
.
Concluderend overzicht Tijdens deze afstudeeropdracht heb ik de volgende onderzoeken uitgevoerd: -
Een onderzoek naar de kwaliteitscriteria van Tingly Games Een onderzoek naar de meetwaarde van bitmap fonts op basis van de kwaliteitscriteria Een onderzoek naar de meetwaarde van vector fonts op basis van de kwaliteitscriteria Een onderzoek naar de snelheid van de save/restore en transformatie functionaliteit binnen de HTML5 context Onderzoek naar de bruikbaarheid van de tekstbreedte van een losse spatie en een los woord Onderzoek naar de snelheden van verschillende vector font effecten Onderzoek naar het verschil in snelheid tussen build-in en externe vector fonts Onderzoek naar het moment waarop het gebruik van een losse canvas rendabel wordt Onderzoek naar de verschillen tussen de anti-aliasing in browsers Onderzoek naar het gebruik van gecombineerde lettertype en bijbehorende terugvalmethoden Onderzoek naar de mogelijkheid om de canvas te 'skewen' Onderzoek naar het voorkomen van onverwachte resultaten bij de omlijning van tekst Onderzoek naar het gebruik van niet-westerse karakters binnen de gehele ontwikkel cyclus van een product bij Tingly Games
Tijdens deze afstudeeropdracht heb ik op basis van bovenstaande onderzoeken de onderstaande producten kunnen maken: - Een vector font library inclusief Engelstalige documentatie - Een Word Art API inclusief Engelstalige documentatie Deze onderzoeken en producten, in combinatie met dit onderzoeksrapport, kunnen worden gezien als het eindresultaat van mijn afstudeeropdracht. Het eindresultaat voldoet aan de wensen van Tingly Games. Mijn producten zijn direct en enthousiast in gebruik genomen. In alle al lopende projecten is de vector font library al toegevoegd. De Word Art API zal spoedig in gebruik worden genomen. In de toekomst kan blijken dat het wenselijk is om extra onderzoek uit te voeren naar de volgende onderwerpen: - Onderzoek naar een manier om verschillende lettertypeformaten in de Tingly Builder om te kunnen zetten naar het .TTF bestandsformaat - Onderzoek naar het gelijktrekken van het gebruik van anti-aliasing in de verschillende browsers
Simon Karman - Tingly Games, 2014 41
.
Bronnenlijst Can I Use. (2014, Januari 12). Retrieved Februari 28, 2014, from Compatibility tables for support of HTML5, CSS3, SVG and more in desktop and mobile browsers.: http://caniuse.com/ Deal, M. (2011, 3 1). Canvas Text Effects. Retrieved 3 5, 2014, from HTML5 Rocks: http://www.html5rocks.com/en/tutorials/canvas/texteffects/ Flanagan, D. (2011). JavaScipt The Definitive Guide. Sebastopol: O'Reilly Media. Gaultney, V. (2003). Font Licensing and Protection Details. SIL Non-roman Script Initiative (NRSI) , 1-3. Geary, D. (2012). Core HTML5 Canvas. Crawfordsville, Indiana: Prentice Hall. Irish, P. (2009, Oktober 7). Fighting the @font-face FOUT. Retrieved Februari 10, 2014, from Paul Irish: http://www.paulirish.com/2009/fighting-the-font-face-fout/ Kyrnin, J. (2013). Font Families - How to decide which Font Family to use. Retrieved 3 5, 2014, from About.com: http://webdesign.about.com/od/fonts/a/aa080204.htm W3Schools Online Web http://www.w3schools.com
Tutorials.
(2012).
Retrieved
2014,
from
W3Schools:
Wikipedia, de vrije encyclopedie. (2001, januari 15). (Wikimedia Foundation, Inc.) Retrieved 2014, from Wikipedia: http://www.wikipedia.nl
Simon Karman - Tingly Games, 2014 42
.
Bijlagen Bijlage A: Tingly Games
In bovenstaand diagram staat de bedrijfsstructuur van Tingly Games weergeven. Mijn foto en gegevens staan rechts onderin. Bij vragen, hulp, oplevering en rapportage spreek ik met Mark Overmars. Daarnaast overleg ik met de andere programmeurs. Ook overleg ik met Gerrit Willemse wanneer mijn keuzes consequenties hebben voor de artists.
Simon Karman - Tingly Games, 2014 43
.
Bijlage B: Website Artikel – Simon Karman bij Tingly Games Voor iedere nieuwe werknemer, stagiaire en freelancer wordt een korte biografie op de website geplaatst. Zo heb ook ik een korte biografie geschreven die hieronder is weergeven. Achtergrondinformatie Ik ben Simon Karman (www.simonkarman.nl), 20 jaar en ik kom stage lopen bij Tingly. Ik ben programmeur en game developer. Ik studeer op dit moment nog aan de Hogeschool van Amsterdam. Hier volg ik de opleiding Technische Informatica met als richting Game Technology. Ik zit in mijn vierde jaar en ik hoef alleen mijn afstudeeropdracht nog af te ronden. Voor mijn afstudeerstage ben ik op zoek gegaan naar een uitdagende programmeer opdracht. Het liefst gerelateerd aan een game. Tingly Games heeft me een leuke opdracht aangeboden op het gebied van Font rendering en hoe hiermee om te gaan binnen HTML5. De titel van mijn onderzoek is: Renderen van teksten in moderne browsers met behulp van HTML5. Ik verwacht dat ik me bij Tingly Games kan ontwikkelen in HTML5 en Javascript. Quote Ik ben altijd op zoek naar leuke en eenvoudige oplossingen voor complexe programmeer problemen. Tingly Games geeft me de kans om, het renderen van niet-westerse fonts in moderne browsers met behulp van HTML5, te onderzoeken en hier leuke en eenvoudige oplossingen voor te vinden. Op het maken van een aantal eenvoudige websites na heb ik nog niet met HTML5 of Javascript gewerkt en hoop hierover veel bij te kunnen leren. Daarnaast geeft deze stage mij een kans om aan de ontwikkeling van het geweldige Greeting Game concept een bijdrage te kunnen leveren. – Simon Webartikel Welcome Simon! February 19th, 2014 Welcome to Simon Karman, our new intern! He’s going to strengthen our team with his internship as a programmer and game developer. Simon is studying Computer Science at the University of Applied Sciences in Amsterdam with Game Technology as specialization. He’s going to do research how to cope with Asian fonts. There are a large amount of possible approaches and Simon’s goal is to find out which approach works best for us. “I’m always looking for simple, but fun solutions to complex issues. Tingly Games makes it possible for me to do research and find a solution for my graduation project. I don’t have that much experience with HTML5 or Javascript, so this will be a nice challenge for me. Besides all this, my internship gives me the opportunity to be involved with the development of the amazing Greeting Game concept.” - Simon
Simon Karman - Tingly Games, 2014 44
.
Bijlage C: De meetwaarden voor de kwaliteitscriteria Meetwaarden worden geclassificeerd als een van de volgende waarden: -
<waarde>
--
<waarde>
-
<waarde> +<waarde>
+
<waarde> ++
Sommige meetwaarden kunnen niet als geclassificeerd.
<waarde>
--
of als
<waarde> ++
worden
Bij de meetresultaten zullen deze labels terug komen. 1-Bruikbare tekenset De meetwaarde van de bruikbare tekenset is te schrijven als een van de volgende waarde: Latin-only 0 – 399 karakters -
400 – 2000 karakters +/-
Alle UNICODE karakters 2000+ karakters +
Dit is niet de technisch haalbare tekenset, maar de praktisch toepasbare tekenset. De tekenset is nog praktisch toepasbaar zolang de performance er niet onder lijdt. 2-Rendertijd De snelheid van het renderen kan afhangen van een heleboel factoren. De basisfactoren waar we rekening mee gaan houden zijn: -
Het aantal woorden Het aantal karakters per woord De hoogte van de karakters
Om deze factoren te kunnen testen zijn twee verschillende test omgevingen opgezet. Binnen de ene test omgeving worden een aantal woorden, met een bepaald aantal karakters en van een bepaalde hoogte gerenderd en de tijd die de browser hierover doet wordt opgeslagen. De andere testomgeving rendert ook een aantal woorden, met een bepaald aantal karakters en van een bepaalde hoogte en houdt vervolgens bij hoeveel frames per seconden de applicatie nog haalt. Bij beide tests worden een veel verschillende waarden toegepast en gemeten. Dit is vervolgens te visualiseren in grafieken. Daarnaast zullen de tests worden uitgevoerd in verschillende browsers. De browsers kunnen namelijk erg verschillende rendersnelheden hebben. Om te kunnen vergelijken drukken we de meetwaarde uit in het aantal ms dat het renderen van een woord duurt. Een frame heeft ongeveer 16ms, hiervan kan maximaal rond de 5ms besteed worden Simon Karman - Tingly Games, 2014 45
.
aan het renderen van tekst en er worden waarschijnlijk rond de 20 woorden gerenderd per frame. Dit houdt in dat een goede snelheid rond de (5ms / 20 woorden =) 0,25ms per woord ligt. > 1 ms --
0,51 – 1 ms -
0,31 – 0,50 ms +/-
0,20 – 0,30 ms +
< 0,20 ms ++
3-Browser Compatibiliteit De meetwaarde wordt bepaald door het aantal browsers waarop de technieken die worden gebruikt voor deze aanpak compatibel zijn. Hiervoor wordt de informatie van http://caniuse.com/ gebruikt. De informatie op deze website wordt verzameld door unit tests uit te voeren op de bezoekers en de gegevens hiervan voor iedereen toegankelijk te maken. Elke feature heeft een score. Dit is een gewogen gemiddelde van de browsers die de feature ondersteunen, op basis van het aantal gebruikers per browser. Deze score geeft dus aan hoeveel procent van de gebruikers beschikken over de feature. We hoeven alleen support te bieden op browsers die de HTML5 canvas ondersteunen. HTML5 wordt ondersteund voor 82,5% van de gebruikers. Dit houdt in dat we deze waarde als richtlijn kunnen gebruiken voor andere features. < 60% -
60% - 69,9% +/-
70,0 % - 82,4% +
> 82,5% ++
Er kan nooit met honderd procent zekerheid vanuit worden gegaan dat een feature geïmplementeerd is door de browser die de gebruiker gebruikt. Het is belangrijk dat er goed word gekeken naar mogelijke terugvalmethodes. Dit zodat deze terugvalmethodes kunnen worden gebruikt wanneer de originele feature niet blijkt te werken. Ook wanneer een bestand niet (goed) worden gedownload kan worden teruggevallen op deze terugvalmethoden.
4-Laadtijd De meetwaarde is de tijd die het kost om de aanpak te kunnen gebruiken. De laadtijd bestaat uit de downloadtijd en de verwerkingstijd. De laadtijd is een opsomming van de downloadtijd en de verwerkingstijd. De downloadtijd is de tijd om de data, die de gebruiker nodig heeft, bij de gebruiker te krijgen. De tijd is uitgedrukt in seconden. Voor het berekenen van de downloadtijd wordt uitgegaan van een internet verbinding van 200 kb/s. De verwerkingstijd kan per aanpak verschillen. >3s --
1–3s -
0,5 – 1 s +/-
0,2 – 0,5 s +
< 0,2 s ++
Simon Karman - Tingly Games, 2014 46
.
5-Toepassingsmogelijkheden De meetwaarde voor de toepassingsmogelijkheden wordt berekend door een punt toe te kennen per onderstaande feature die de aanpak ondersteund: -
De kleur van de tekst kunnen aanpassen De tekst helder kunnen schalen Schaduwen van de tekst kunnen renderen 0 -
1 +/-
2 +
3 ++
Simon Karman - Tingly Games, 2014 47
.
Bijlage D: Meetwaarden bitmap font Bruikbare tekenset Net zoveel karakters als gekozen in de Tingly Builder. Dit valt dus te classificeren als ‘Latin-only, 0 – 399 karakters’. Latin-only, 0 – 399 karakters
-
Rendertijd Zoals in de grafieken van ‘Bijlage G: Rendertijd in de testomgevingen (Test omgeving 2: Frames Per Seconde)’ te zien is, verschilt de rendertijd nogal per browser. Over het algemeen wordt bij het renderen van 75 zesletterwoorden van grootte 16 de 60 frames per seconde nog gehaald. De browsers waarin dit niet het geval is zijn een stuk trager en zullen ook bij andere taken veel minder snel zijn dan snellere browsers. Dit valt dus niet te wijten aan de bitmap fonts. Het renderen van 1000 woorden duurt bij verschillende browsers 90, 160, 250 en 320 ms. Dit is een gemiddelde van 205 ms. Dit betekend dat één woord ongeveer te renderen is in 0,205 ms. Dit valt dus te classificeren als ‘0,20 – 0,30 ms’. 0,205 ms
+
Browser compatibiliteit Voor de implementatie van deze aanpak hoeft alleen de basis implementatie van de canvas door de browser ondersteund te worden. 82,5% ++ Laadtijd De laadtijd van deze implementatie bestaat uit de downloadtijd van de afbeeldingbestanden waar het font in staat afgebeeld plus de download tijd van de code waarin het font staat gedefinieerd. De bestandsgrootte van de afbeeldingbestanden verschilt per font er per grootte. Daarnaast is er voor elke grootte een apart bestand nodig. Een afbeeldingbestand waarin voor 2 fonts de groottes 8 tot en met 40 zijn opgenomen (met tussenstappen van 4) is 201kb groot. Een los afbeeldingbestand voor een font met grootte 8 is 2kb en voor een font met grootte 40 is dit 20kb. Een afbeeldingbestand voor een font met groottes 8, 16, 28 en 40 is 40kb groot. Dit is een redelijke afspiegeling van een aantal groottes dat gebruikt kan worden binnen de Tingly Builder. Voor elke kleur waarin je het font wilt renderen zal je weer ongeveer 40kb aan ruimte nodig hebben. Download tijd afbeeldingbestanden = (40kb x 2kleuren) / (200kb/s) = 0,4s Daarnaast moet er ook een stuk code worden gedownload. Deze grootte ligt rond de 5kb per font. Voor de 4 groottes is dit nodig en ook per kleur. Download tijd code = (5kb x 4groottes x 2kleuren) / (200kb/s) = 0,2s Simon Karman - Tingly Games, 2014 48
.
De download tijd van de afbeeldingbestanden (0,4s) plus de download tijd van de code (0,2s) geeft een totale laadtijd van 0,6s. 0,6s +/Toepassingsmogelijkheden De kleur van de tekst is niet aanpasbaar tijdens runtime. De tekst kan alleen in de kleur die in de Tingly Builder voor het font is gebruikt worden gerenderd. 0 punten. De tekst is schaalbaar. Echter wanneer de tekst te groot wordt geschaald zullen de pixels van de bitmap zichtbaar worden. 0,5 punt. Schaduw achter de tekst is mogelijk, maar dit zal zelf geïmplementeerd moeten worden. 0,5 punt. 1 punt +/Leesbaarheid De leesbaarheid van een bitmap font is optimaal als het op originele grootte wordt gerenderd. De tekst is wel schaalbaar maar dit heeft altijd verlies in de leesbaarheid tot gevolg. In onderstaande afbeelding zie je een tekst van grootte 36 die op verschillende schalen is gerenderd. Hier is het leesbaarheidsverlies goed zichtbaar. Kleiner is goed leesbaar bij x0.25 wordt de tekst wazig en de grotere versies worden heel duidelijk waziger. Een oplossing hiervoor zou zijn om het font op een grotere grootte op te slaan. Dit heeft echter als nadeel dat de laadtijd veel groter wordt.
Een voordeel aan bitmap fonts is dat ze met de hand kunnen worden gedesigned. En de karakters daardoor beter en preciezer gepersonaliseerd kunnen worden voor een spel.
Simon Karman - Tingly Games, 2014 49
.
Bijlage E: Meetwaarden vector fonts Bruikbare tekenset De bruikbare tekenset omvat even veel karakters als het gekozen font beschikbaar heeft. Wanneer het gekozen font niet over de karakters beschikt zal het fallback font worden gebruikt en worden de karakters alsnog op het scherm getoond. Dit valt dus te classificeren als ‘Alle UNICODE karakters, 2000+ karakters’. Alle UNICODE karakters, 2000+ tekens ++ Rendertijd Zoals in de grafieken van ‘Bijlage G: Rendertijd in de testomgevingen (Test omgeving 2: Frames Per Seconde)’ te zien is, verschilt de rendertijd nogal per browser. Over het algemeen wordt bij het renderen van 75 zesletterwoorden van grootte 16 de 60 frames per seconde nog gehaald. De browsers waarin dit niet het geval is zijn een stuk trager en zullen ook bij andere taken veel minder snel zijn dan snellere browsers. Dit valt dus niet te wijten aan de vector fonts. Daarnaast is in de vergelijking test van ‘Bijlage G: Rendertijd in de testomgevingen (Testomgeving 1: Tijd per config)’ te zien dat de vector fonts over het algemeen een factor 2 sneller zijn dan bitmap fonts. In Chrome en Internet Explorer zelfs een factor 3. Het renderen van 1000 woorden duurt bij verschillende browsers 30, 50, 80 en 100 ms. Dit is een gemiddelde van 65 ms. Dit betekend dat één woord ongeveer te renderen is in 0,065 ms. Dit valt dus te classificeren als ‘< 0,20ms’. 0,065ms ++ Browser compatibiliteit Voor de implementatie van deze aanpak moeten de onderstaande features geïmplementeerd zijn door de browsers. - WOFF fonts* - @font-face - Canvas Text API
| 77,0 % | 82,3 % | 83,8 %
*Een probleem is dat WOFF fonts niet werken binnen versies van de Android Browsers vóór Android Browser versie 4.4. Voor deze browsers kan een terugvalmethode naar een TTF een oplossing bieden. 77,0 %
+
Laadtijd De laadtijd van deze implementatie bestaat uit het downloaden van een .WOFF bestand en het downloaden van een regel code. De browser moet daarna het font inladen voordat het gebruikt kan worden.
Simon Karman - Tingly Games, 2014 50
.
.WOFF bestanden zijn rond de 30kb groot en de regel code is 0,03kb groot. Dit geeft een totale download tijd van (30kb + 0,03kb) / (200kb/s) = 0,15s. Het inladen van de fonts voor de browser kost laadtijd. Het inladen van een font lukt makkelijk binnen een frame. De tijd die het kost is dus afhankelijk van de frametijd. De frametijd van de Tingly Builder staat vastgesteld op maximaal 33ms. De totale laadtijd van deze aanpak bestaat uit de download tijd (0,15s) plus de laadtijd (0,033s) en bedraagt 0,18s. 0,18s ++ Toepassingsmogelijkheden De tekst is in elke kleur te renderen. 1 punten. De tekst is schaalbaar. 1 punt. Het renderen van schaduwen voor de tekst is mogelijk. 1 punt. Daarnaast zijn er nog veel meer effecten te maken met het gebruik van vector fonts. Een aantal voorbeelden zijn te vinden op http://www.html5rocks.com/en/tutorials/canvas/texteffects/. 3 punten ++ Leesbaarheid De leesbaarheid van een vector font is grootteonafhankelijk. Dit houdt in dat een vector font op elke gewenste grootte gerenderd kan worden zonder leesbaarheidsverlies. In de onderstaande afbeelding is te zien hoe een vector font er op verschillende groottes uit ziet. Zoals te zien, is de tekst op elke grootte even scherp.
Simon Karman - Tingly Games, 2014 51
.
Voor het gebruik in webkit browsers is het belangrijk dat de kwaliteitsinstellingen goed worden ingesteld. In deze browsers rendert de tekst namelijk niet met anti-alliasing. Dit is een bug binnen deze browsers.
Simon Karman - Tingly Games, 2014 52
.
Bijlage F: Het tbVectorFont Prototype Voor het testen van het renderen van vector fonts moet er een prototype beschikbaar zijn, waarmee ook de verschillende aanpakken getest kunnen worden. Er is gewerkt met twee prototypes. Allereerst is gewerkt met een los prototype dat buiten de Tingly Builder werkt. Daarna is gewerkt met een prototype dat in de Tingly Builder zit. In deze prototypes kunnen vervolgens metingen worden uitgevoerd. Losse prototype Het doel van dit losse prototype is het kunnen testen van de technieken die nodig zijn voor de meetcriteria. Dit losse prototype moet een aantal verschillende fonts laden en, zodra ze geladen zijn, een tekst op het canvas renderen gebruikmakend van het gekozen font. Wanneer een font niet geladen kan worden moet er een ook een tekst op het scherm komen te staan. Aan de hand van de geleerde technieken kan ik dit prototype vervolgens uitproberen in de Tingly Builder. Tijdens het maken van dit prototype heb ik er rekening mee gehouden dat de interface duidelijk en eenvoudig moet zijn. In het figuur hieronder is te zien dat er een nieuw Font object kan worden aangemaakt. Wanneer het font geladen wordt, is door de developer zelf te implementeren, aan de hand van wanneer de startLoading methode wordt aangeroepen.
Nadat gestart is met het laden zijn er een aantal events die kunnen worden aangeroepen door het font. Deze events zijn: -
Font.onLoadSucceeded(fontfamily) Font.onLoadFailed(fontfamily) Font.onLoadFinished(succes, fontfamily)
Aan deze events kan weer functionaliteit worden gehangen. De fontfamily die je opgeeft bij het creëren van het Font object is de font-family property die je in je @font-face5 rule in de css file opgeeft.
De fonts moeten allemaal in het .WOFF formaat worden meegegeven. Dit font formaat wordt door de browsers namelijk universeel ondersteund. 5
http://www.w3schools.com/cssref/css3_pr_font-face_rule.asp
Simon Karman - Tingly Games, 2014 53
.
De techniek die ik hier gebruik om te controleren of een font is geladen, is door te kijken of de breedte van een stukje tekst in een standaard font verschilt van de breedte van het zelfde stukje tekst in het te laden font. Is het font geladen dan heeft het stukje tekst een andere breedte dan het standaard font. Is het font nog niet geladen dan zal met het standaard font worden gerenderd, oftewel de breedte is dan nog gelijk. De browser moet weten dat we het font willen gebruiken. Anders zal de browser het font namelijk niet downloaden. Het renderen van tekst in de canvas is helaas geen reden voor de browser om het font te downloaden. Om de browser te vertellen dat we dit font willen gebruiken zullen we een DOM element moeten creëren6 dat in zijn style naar het font toe linked. Dit DOM element kan vervolgens ook worden gebruikt om de breedte van het stukje tekst te meten en op die manier dus vast te stellen of een Font geladen is. Wanneer het Font na een timeout van 2500 ms nog altijd niet geladen is, gaan we er vanuit dat het Font niet bestaat of niet geladen kan worden. Deze implementatie heeft als nadeel dat elk Font zelf een check loop bijhoudt waarin het steeds checkt of het al geladen is. Dit probleem zal wanneer het font in de engine gebruikt wordt niet meer voorkomen, omdat in de engine al een loop zit. Afstemming met Mark Tijdens een overleg met Mark kwamen we op een aantal ideeën om te kunnen controleren of een font geladen is. Op deze ideeën ga ik hieronder verder in. - Ten eerste leek het ons een goed idee om niet op basis van een enkel stuk tekst, maar op basis van meerdere kleinere stukjes tekst te baseren of een font van breedte is veranderd. Er even simpelweg van uit gaande dat een zelfde stuk tekst bij verschillende fonts tussen de 80 en 120 pixels breed is, kan er van worden uitgegaan dat ongeveer 1 op de 40 fonts een zelfde breedte heeft voor een zelfde stukje tekst. De kans hierop wordt kwadratisch kleiner als we meerdere stukjes tekst gaan controleren. Twee of drie verschillende stukjes tekst zullen de kans dus al bijna nihil maken dat een font de zelfde breedte heeft. - Een tweede idee was om op basis van het wel of niet bestaan van bepaalde karakters binnen een font te kunnen vergelijken of het font is geladen. Bevat het font de karakters niet dan zal dit het fallback font zijn. Bevat het font de karakters wel dan zal het font dus geladen moeten zijn. Een nadeel hiervan is dat het font karakters moet bevatten die niet in het fallback font zitten. Hiervoor zullen we dus het fallback font moeten kunnen instellen of een ‘test’-karakter toe moeten voegen aan custom fonts. - Een derde idee ontstond op basis van het tweede idee en gaat uit de vergelijking van het aantal karakters dat een font heeft met het in te laden font. Houd er rekening mee dat bovenstaande idee allemaal uit gaan van het feit dat de waardes van de vergelijking bij het te laden font en het fallback font niet gelijk zijn. Als deze waarden verschillen weten we zeker dat er een font is geladen. Dit betekend echter dat theoretisch gezien de fonts na het laden nog steeds precies de zelfde waarden zouden kunnen hebben voor alle vergelijkingen. De kans hierop is in de praktijk echter verwaarloosbaar klein.
6
http://www.paulirish.com/2009/fighting-the-font-face-fout/ - all wait until they encounter HTML that matches a CSS rule with a fontstack including the @font-face font -
Simon Karman - Tingly Games, 2014 54
.
Daarnaast als het echter toch voor blijkt te komen dat de vergelijkingen bij een custom fonts allemaal het zelfde resultaat geven dan kan er alsnog gewoon met het font geschreven worden. De engine gaat er dan namelijk alleen vanuit dat die het font niet heeft kunnen laden, maar kan het font gewoon gebruiken. Prototype in de Tingly Builder Aan de hand van het losse prototype ben ik begonnen aan het schrijven van een versie die in de Tingly Builder kan worden gebruikt. Met deze versie kunnen later alle meetcriteria worden getest voor deze aanpak.
De interface die ik heb opgesteld voor het prototype in de Tingly Builder lijkt vanzelfsprekend heel sterk op de interface van het losse prototype. Er zijn echter enkele verschillen. 1- De naam van het object in de Tingly Builder is tbVectorFont; 2- De Tingly Builder heeft z’n eigen update loop. Hierdoor hoeft het font geen eigen loop meerbij te houden in de startLoading methode Aangezien het font geen eigen loop meer bij hoeft te houden kan deze functionaliteit worden opgeschoven naar de handleBeginStep methode. Om te zorgen dat deze methode door de engine wordt aangeroepen moet een tbVectorFont een token zijn. 3- Aangezien het handig en wenselijk is de functionaliteit af te stemmen op de huidige implementatie van de engine implementeert tbVectorFont ook z’n eigen render-functies. Een voorbeeld van zo’n render-functie is de laatste functie die te zien is in het figuur. De ‘drawTextSimple’ methode. Dit is een goed voorbeeld van een mogelijke functie. Er zijn echter nog veel meer vormen te bedenken. Denk dan bijvoorbeeld aan methode waarbij je parameters zoals rotatie, schaal en kleuren mee kan geven. 4- In de Engine zijn de events niet meer zo van belang. Aangezien ze nog wel handig kunnen zijn bij bijvoorbeeld het laden van het spel heb ik ze erin laten zitten. De useEvents parameter die mee wordt gegeven aan het creëren van het font object geeft aan of het font events moet aansturen (true) of dat het font geen events hoeft aan te sturen (false). Wanneer je geen gebruik maakt van de events is het slim om ze uit te zetten. De functionaliteit die voor de vector font implementatie in de Tingly Builder zal moeten komen bevat de volgende stappen: 1- Het font (het .woff bestand) moet bij het builden in de media folder worden geplaatst. 2- Er moet een @font-face rule aan de css worden toegevoegd. 3- Het font moet in JavaScript worden gedefinieerd. Simon Karman - Tingly Games, 2014 55
.
Hierna kan je in je project gebruiken maken van het vector font. Afstemming met Mark Na het maken van het prototype binnen de Tingly Builder heb ik weer met Mark overlegt over de implementatie en toegepaste technieken. Hieronder de implementatie wijzigingen die uit ons gesprek kwamen: - @font-face aan css toevoegen via JavaScript; - DOM Element alleen gebruiken voor het starten van het laden, vervolgens de text breedte meten door middel van de context.measureWidth; - Het laden van een vector font los bouwen van het gebruiken van een vector font; - tbVectorFont zou geen token moeten zijn. Desnoods moet het font toch z’n eigen loop bijhouden om ervoor te zorgen dat de lijst met tokens geen engine functionaliteit bevat. Deze wijzigingen heb ik doorgevoerd. Daarnaast waren er nog een aantal opmerkingen waar ik naar kan kijken wanneer ik deze implementatie verder wil beoordelen: - Het verschil in snelheid tussen het renderen van 1 woord van 1000 karakters of het renderen van 1000 woorden van 1 karakter; - De kwaliteitsinstellingen van vector fonts in de browser; - Het op een rijtje zetten van de ‘websafe fonts’ die door elke browsers worden ondersteund; - De juridische zaken omtrent het gebruik van ‘WOFF’ fonts en het versleutelen van deze fonts. Na het doorvoeren van de wijzigingen is de interface iets gewijzigd. Het font voegt zijn eigen css toe, het font gebruikt geen DOM Element meer voor de metingen, het vector font is geen token meer, het laden van het font staat nu los van het renderen en om fallback fonts te supporten heeft elk font een fallback font. Het fallback font kan de naam van een font of een tbVectorFont object zijn. De interface van het tbVectorFont object ziet er nu als volgt uit:
Simon Karman - Tingly Games, 2014 56
.
Zoals in het bovenstaande plaatje te zien is, kan je nu een fallbackFont aangeven. Dit font zal gebruikt worden wanneer het font niet geladen is of niet geladen kan worden. Dit fallbackFont kan drie verschillende waarde bevatten: - Undefined: Wanneer het fallbackFont niet wordt opgegeven zal worden teruggevallen op Arial. - String Font-Family: De naam van het font waarop terug te vallen. - instanceof tbVectorFont: Het tbVectorFont object waarop terug te vallen Elke andere waarde die wordt meegegeven zal worden geïnterpreteerd als ‘Undefined`. In het plaatje hieronder zie je een voorbeeld van de mogelijke fallbackFonts. Font3 zal terugvallen op Font2, Font 2 valt zelf weer terug op ‘Monospace’ en Font 1 zal terugvallen op ‘Arial’.
Simon Karman - Tingly Games, 2014 57
.
Bijlage G: Rendertijd in de testomgevingen Voor het testen van de rendertijd heb ik twee test omgevingen opgezet. In deze bijlage zal ik beide testomgevingen kort omschrijven en vervolgens de meetresultaten in een aantal grafieken visualiseren. De gegevens die worden geanalyseerd zijn: - Het aantal woorden - Het aantal karakters per woord - De hoogte van de karakters Deze bijlage bevat alleen de meetgegevens en dus geen interpretatie hiervan. De interpretatie van de meetgegevens is terug te vinden bij de desbetreffende aanpak. Testomgeving 1: Tijd per config Deze testomgeving voert tests uit met bitmap fonts en met vector fonts en is vooral bedoeld om de snelheid van bitmap fonts en vector fonts met elkaar te vergelijken. Programma flow 1- Wacht tot de benodigde fonts geladen zijn 2- Voor elke config (1x als bitmap font en 1x als vector font) 3Voer onderstaande handelingen 15 keer uit voor deze config 4Houdt de begintijd bij 5Render een ‘x’ aantal woorden met ‘x’ woordlengte en ‘x’ woordgrootte 6Bereken de eindtijd en daarmee een van de 15 metingen van deze config 7Bereken de gemiddelde tijd over de 15 metingen (dus 1x als bitmap font en 1x als vector font) Meetresultaten Grafieken van Chrome 32.0 op Android, Chrome 33.0 op Windows, Firefox 27.0 op Windows en Internet Explorer 11 op Windows.
Simon Karman - Tingly Games, 2014 58
.
Simon Karman - Tingly Games, 2014 59
.
Test omgeving 2: Frames Per Seconde De tweede test omgeving die ik heb opgezet is gericht op de daadwerkelijke toepassing van de fonts. In de engine zullen de woorden namelijk elk frame gerenderd gaan worden. Met deze tests probeer ik verbanden te vinden tussen het renderen van tekst en de frames per seconde (FPS) die tijdens het renderen haalbaar is. Deze test is vooral bedoeld om een beeld te krijgen van de prestaties van vector fonts binnen de engine en het aantal woorden dat haalbaar is met de huidige implementatie. Programma flow 1- Wacht tot de vector fonts geladen zijn 2- Start met een standaard woordgrootte, standaard woordlengte en standaard aantal woorden 3- Loop door verschillende woordgrootte, woordlengte en aantal woorden 4Voor 5 seconden 5Render een ‘x’ aantal woorden met ‘x’ woordlengte en ‘x’ woordgrootte 6Sla de frame tijd op 7Bereken de gemiddelde frametijd van deze 5 seconden Meetresultaten
Simon Karman - Tingly Games, 2014 60
.
Simon Karman - Tingly Games, 2014 61
.
Bijlage H: Context Save/Restore en Transformaties snelheden Vergelijking in snelheid met betrekking tot het save en restoren van de context. En het toepassen van transformaties op de transformatiematrix van de context. Het tienduizend keer uitvoeren van bepaalde functionaliteit.
De tests die worden uitgevoerd zijn. Het gebruik van transformaties vereist save+restore (kan niet handmatig worden gerestored)
Simon Karman - Tingly Games, 2014 62
.
De verschillende test resultaten op verschillende browsers staan hieronder. Chrome
Firefox
Internet Explorer
In de tabel zijn de resultaten nogmaals naast elkaar weergeven.
Save-Restore Save-Restore-Transform Manual
Chrome 187ms 217ms 262ms
Firefox 1209ms 1208ms 3913ms
Internet Explorer 356ms 350ms 433ms
Zoals is te zien is op elke browser de handmatige implementatie (manual) trager dan het gebruik van de build-in save en restore functionaliteit van de browsers. Daarnaast is te zien dat het gebruik van de transformaties in Internet Explorer en Firefox geen effect hebben op de snelheid. In Chrome is dit wel het geval, het niet gebruiken van transformaties zal binnen Chrome waarschijnlijk geoptimaliseerd zijn.
Simon Karman - Tingly Games, 2014 63
.
Bijlage I: Vector font library documentatie Dit is de documentatie die ik bij de vector font library heb geschreven. Deze documentatie is vrij toegankelijk voor alle developers die gebruik maken van de Tingly Builder. De documentatie is bedoelt om ondersteuning te bieden aan de developer tijdens het gebruik van de library. Aangezien de developer niet per defenitie Nederlands is, is de documentatie in het Engels geschreven. De documentatie bestaat uit twee onderdelen. De uitleg over de ‘Vector font resource’ en de uitleg over de ‘tbVectorFont API’. Vector font resource A vector font resource stores a font in the form of a font description. You can then use these fonts in the engine to draw text. You add a vector font resource in the usual way. Once a vector font resource is created, you must use the Import button to select a TTF font face. (Later other font types might be supported as well. There are though lots of tools and websites to convert other font face files to the TTF format.) Vector fonts give you considerable control over the way text is drawn. You can specify the size, the color, the way the letters are filled, etc. Realize though that the speed is dependent on the style you use. See the section in the engine on Fonts for more information.
Fonts and font faces Realize there is a distinction between a font and a font face. A font face described the shape of the characters. A font described the particular settings with which to draw the text on the screen. This includes the font face but also setting for size, color, fill style, etc. When you add a vector font Simon Karman - Tingly Games, 2014 64
.
resource default both a font face with the name of the vector font is generated and an actual font that uses this font face. (Note that a font face is represented by a string. A font is an object.) When the vector font you create does not have an associated font face data file only a font is created. In this case you must specify that you want to use an existing font face. This can be a built-in font face, like Arial or serif. But it can also be the font face of a different vector font. In this way you can created many different fonts for the same font face, each with different settings. This is a lot more efficient than including the same TTF file for each of these fonts cause now the file is loaded only once by the engine and reused for the different fonts. Global Settings You can change the following global settings: Create only the fontface definition: When set only a font face definition is created and no font. This is useful when you want to create the fonts based on this font face in code. Note that in this case you must import a TTF file in the vector font. Otherwise you will get an error when building the solution. Export location: The location where the font face files will be stored, relative to the solution folder. (The builder will create two: a woff file and a ttf file.) You can use the following placeholders: -
%d: the data folder %s: the scripts folder %m: the media folder %a: the audio folder %f: the font folder (default) %o: the folder for other files
You can set the location for these in the Configuration. Obviously, this setting is only relevant when there is a font face data file. Loading moment: When the font face will be loaded. There are three default values: - start: So at the start of the game. Use this as little as possible. Only use it for images you need for a loading screen. - load: The default. The font files are loaded during the loading phase of the game. - game: The font files are only loaded when the game has started. You can use this for fonts that are only needed later in the game. It will speed up the loading phase. You can also use your own loading moments. Simply type a string for this. In this case you must yourself start the loading for such a moment. For more information, see the section on Loaders. Obviously, this setting is only relevant when there is a font face data file. Use an existing fontface: When set the font will use an existing font face. As indicated above, this can be used to created different fonts based on the same font face. When set, no font face file is created (not even when a font face data file is present). Existing fontface: The existing font face to use. You can either select one of the standard font faces in the drop down list that all (most) browsers support or type in a font face name yourself. Simon Karman - Tingly Games, 2014 65
.
Fallback font: When for some reason, the engine fails to load the font this font is used instead. You can type the name of another font you define or you can use one of the build-in fonts using the dropdown list. This font is also used when certain characters are missing in the font face (e.g. Chinese characters). When even the fall-back font fails the game uses a default font (normally Arial). Font Settings At the top right you can specify a large number of settings for the font. (Not to be confused with the font face.) At the bottom you see an example using the settings. (This example is rendered using HTML5 so it does indeed show the font in the correct way. However, there can be slight differences between browsers.) General font settings: Here you specify the size (in pixels), the style (e.g. Italic), the weight (how bold it is; not all settings have effect for all font faces), and how the text drawn with the font should be aligned horizontally and where the baseline should be vertically. Also you can indicate an extra spacing between lines. The cross in the image shows the position where the text is drawn. Example text: Here you specify the example text you want to see in the preview. Use \n for newline characters. You can also indicate whether to show the checkerboard grid and the text box with the position of the origin. Fill settings: When checked the characters are filled. You can choose as fill style a color, a pattern, a gradient or a style you define yourself (as used in HTML5; e.g. rgba(255,0,0,0.4) to get a partially transparent red font). You can also specify the alpha transparency value used for filling. Stroke settings: When checked the characters get a stroke (outline). You can specify both fill and stroke, or one of them. You can choose as fill style a color or a style you define yourself. Next you specify the with or the outline in pixels. You can also specify the alpha transparency value used for filling. Pattern: When the fill style is set to a pattern you can specify the pattern here. You provide the name of an image in the project and whether it should be tiled horizontally and vertically. Note that the pattern image used in the preview depends on the configuration chosen in the tool bar. Only when the game is actually built what image corresponds to the image name provided. Gradient: When the fill style is set to a gradient you can specify the gradient here. You can choose a vertical or horizontal gradient, whether it has 2 or 3 colors, and you specify the colors. (Note that in code you can also use more colors.) You can also set the offset of the gradient (the position of the center of the gradient) and the size of the gradient, which specifies over which part of the text the gradient changes. Shadow: Finally you can specify the shadow. When the font is filled you get a filled shadow; otherwise you get an outline shadow. You specify the color of the shadow, its alpha value (which is combined with the color), the horizontal and vertical offset, and the amount of blur. This is typically a value between 0 (sharp shadow) or 100 (full blur). Note that shadows can be time-consuming when drawing.
Simon Karman - Tingly Games, 2014 66
.
tbVectorFont API A VectorFont uses curves, drawing instructions and mathematical formulas to describe the outlines of each glyph. As a result, the characters are scalable to any size without loss of quality. For each VectorFont resource you add to the project two things are created: - A font face. You can use this by providing the name of the resource as a string (between quotes). This is only done when you imported a font file. - A tbVectorFont object with all the settings that you indicate when creating the font resource. Unless you indicated that you only wanted a font face to be created. You can create tbVectorFonts yourself in code using the following constructor: var font = new tbVectorFont(fontFace, fallbackFontFace)
Create new font. The first argument is a string with the name of the font face. This should either be the name of one of the vector font resources you added to the project, or the name of a standard font, like "Arial" or "serif". The optional fallbackFontFace argument indicates the font to be used when the font face does not exist (was not loaded correctly) or when certain characters (like Chinese characters) are not defined in the font face. You can create a clone of a font using the following method: var font2 = font.clone()
This method clones the tbVectorFont object and all its current settings to a new tbVectorFont object. The new tbVectorFont object is returned. For the fonts you created in the builder or in code the following methods exist: Properties A font has many properties that define the way the characters are drawn. You can define them when defining the vector font resource but you can also set (and get) them in code: font.setDefault()
This method resets all the properties to their defaults. The default values for each property are given in the explanation of each property below. Font font.setFontStyle(style)
Set the style of the font. The style is a string and can be: "italic", "oblique" or empty. Empty is the default value for the font style. When no argument is passed to this method the style will be set to empty. font.getFontStyle()
Returns the current style of the font. font.setFontWeight(weight)
Sets the weight of the font. The weight is a string and can be: "bold", "bolder", "lighter", "normal", empty or any hundred below one thousand (example: "400" or "800"). Empty is the default value for the font weight. When no argument is passed to this method the weight will be set to empty. font.getFontWeight()
Returns the current weight of the font. Simon Karman - Tingly Games, 2014 67
.
font.setFontSize(size)
Sets the size of the font. The size is a number and corresponds with the height in pixels of one line of text. Default is 12. When no argument is passed to this method the weight will be set to 12. font.getFontSize()
Returns the current size of the font. Fill You can fill the characters with a color, a pattern, a gradient, or an HTML5 style that you define yourself. Also you can indicate whether the characters should be filled or not. font.setFill(fill)
Sets whether to fill the text (true) or to not fill the text (false). The default value is true. When no argument is passed fill will be set to true. font.getFill()
Returns whether the text is filled. font.setFillAlpha(alpha)
Sets the alpha transparency of the fill style. This is a number between 0 and 1. With 0 the fill is fully transparent. The default value is 1. When no argument is passed the fill alpha will be set to 1. font.getFillAlpha()
Returns the alpha of the fill style. font.setFillColor(color)
Sets the fill style to be a solid color. Color can be any valid HTML5 color code (like "red", "#A012EF" or "rgba(255,0,0,1)"). The default value is "black". When no argument is passed the fill color will be set to "black". font.getFillColor()
Returns the current fill color. font.setFillPattern(image, subImage, repeatH, repeatV)
Sets the fill style to be a repeating pattern. image is a tbImage object which will be used as a pattern. subImage is the sub-image that is used. repeatH specifies whether to repeat horizontally (true) or not (false). And repeatV specifies whether to repeat vertically (true) or not (false). font.setFillPattern(patternObject)
Sets the fill style to be a repeating pattern based on the given patternObject. font.getFillPattern()
Returns the current patternObject. The patternObject contains four properties: image, subImage, repeatH and repeatV. font.setFillGradient(vertical, number, colors, size, offset)
Sets the fill style to be a gradient. Vertical specifies whether to create a vertical (true) or horizontal (false) gradient. A vertical gradient will be applied to each individual text line and the horizontal gradient is applied to the whole text block. Number specifies the number of colors in the gradient and colors is the array of colors. The optional argument size indicates the relative size of the gradient (where the color changed). Should lie between 0 and 1. The optional argument offset is the relative offset of the center of the gradient with respect the middle (for vertical) or center (for horizontal) of the text. Simon Karman - Tingly Games, 2014 68
.
font.setFillGradient(gradientObject)
Sets the fill style to be a gradient based on the given gradientObject. font.getFillGradient()
Returns the current gradientObject. The gradientObject contains five properties: vertical, number, colors, size, and offset. font.setFillStyle(style)
Sets the fill style to any valid HTML5 fill style. This can be a color, a pattern or a gradient. The default value is "black". Use this for when you want to create your own pattern or gradient. When no argument is passed the fill style will be set to "black". font.getFillStyle()
Returns the current fill style. Note that this is the fill style when set by the previous method. When you set a color or pattern using the corresponding methods, you should also use the corresponding get methods. Stroke You can give the characters an outline or stroke with a color or an HTML5 style that you define yourself. Also you can indicate whether the characters should be stroked or not. font.setStroke(stroke)
Sets whether to stroke the text (true) or to not stroke the text (false). The default value is false. When no argument is passed stroke will be set to false. font.getStroke()
Returns whether the text is stroked. font.setStrokeAlpha(alpha)
Sets the alpha transparency of the stroke style. This is a number between 0 and 1, with 0 being fully transparent. The default value is 1. When no argument is passed the stroke alpha will be set to 1. font.getStrokeAlpha()
Returns the alpha of the stroke style. font.setStrokeColor(color)
Sets the stroke style to be a solid color. Color can be any valid HTML5 color code (like "red", "#A012EF" or "rgba(255,0,0,1)"). The default value is "black". When no argument is passed the stroke color will be set to "black". font.getStrokeColor()
Returns the current stroke color. font.setStrokeStyle(style)
Sets the stroke style to any valid HTML5 stroke style. This can be a color, a pattern or a gradient. The default value is "black". Use this for when you want to create your own pattern or gradient. When no argument is passed the stroke style will be set to "black". font.getStrokeStyle()
Returns the current stroke style. font.setStrokeWidth(width)
Sets the stroke width of the stroke to the indicated number of pixels. The default value is 1. When no argument is passed the stroke width will be set to 1. Simon Karman - Tingly Games, 2014 69
.
font.getStrokeWidth()
Returns the current stroke width. Shadow font.setShadow(active)
Sets whether to draw a shadow on the text (true) or not (false). When fill is set, the shadow is only drawn behind the filled characters. Otherwise, the shadow is drawn behind the stroked characters. The default value is false. Other shadow parameters are not changed. font.setShadow(active, color, offsetX, offsetY, blur)
Sets whether to draw a shadow on the text (true) or not (false). The other arguments specify the color of the shadow (e.g "gray" or "rgba(10, 10, 10, 0.3)"), the offset with respect to the position of the character, and the amount of blur (typically 0-100; default = 1). When no arguments are passed at all, the shadow is set to its default (not active, transparent gray, offset 3, 3 and blur of 1). font.setShadow(shadowObject)
Sets the shadow to the values in the shadow object. font.getShadow()
Returns the current shadowObject. The shadowObject contains five properties: active, color, offsetX, offsetY, and blur. Alignment font.setAlign(align)
Sets the horizontal alignment of the text. This value is a string and can be "left", "center" or "right". The default value is "left". When no argument is passed the align is set to "left". font.getAlign()
Returns the current horizontal alignment. font.setBaseline(baseline)
Sets the baseline of the text. This value is a string and can be "top", "middle" or "bottom". The default value is "top". When no argument is passed the baseline is set to "top". font.getBaseline()
Returns the current baseline. font.setLineSpacing(spacing)
Sets the extra line spacing in pixels between different lines of text. The default value is 0. When no argument is passed the line spacing is set to 0. font.getLineSpacing()
Returns the current line spacing. Drawing To draw a text with a given font, the following methods exist: font.drawSimple(text, x, y, width)
This method draws the string text in the font at the indicated position. Default (x,y) indicates the topleft position of the string but you can change the alignment (see above). A newline (\n) character in the string is correctly interpreted as moving to a new line. An optional additional width argument indicates the maximum width of the drawn text in pixels. When the text is larger it is split into lines (only at a space character at the moment). font.drawAlpha(text, x, y, alpha, width)
Simon Karman - Tingly Games, 2014 70
.
The same as the previous method but with an additional alpha transparency setting (0-1). Again, you can provide an optional additional width argument to indicate the maximum width of the drawn text in pixels. font.drawExt(text, x, y, xScale, yScale, angle, alpha, width)
Draws the string at (x,y) scaled with the indicated scale factor and rotated over angle degrees counter-clockwise. alpha indicates the alpha transparency and again, you can provide an optional additional width argument. Note that when scaling text actually the point size is changed. As a result, the characters remain nice. But it does lead to some rounding which can be noticeable when animating the scale. (In that case, better first create a surface for the text and use that to scale.) Size The following methods can be used to obtain information about the size of the text. font.textWidth(text, width)
This method returns the width of the string when drawn in the font, with the current alignment settings. An optional additional width argument indicates the maximum width of the drawn text in pixels. When the text is larger it is split into lines (only at a space character at the moment). font.textHeight(text, width)
This method returns the height of the string when drawn in the font, with the current alignment settings. An optional additional width argument indicates the maximum width of the drawn text in pixels. When the text is larger it is split into lines (only at a space character at the moment). font.textBox(text, x, y, width)
This method returns the bounding box of the string when drawn in the font, at the given location with the current alignment settings. An optional additional width argument indicates the maximum width of the drawn text in pixels. When the text is larger it is split into lines (only at a space character at the moment). The method return an object with the properties x, y, width and height. font.textFitSize(text, width, height, split)
This method returns the largest size for the font for which the text fits in a box with the given width and height. The text is always split at \n. When the optional split argument is true it is also split with the given width. This call is somewhat expensive so better calculate it once, rather than in each draw event. So to make a text drawn inside a box of 400x200 use e.g.: var size = font.textFitSize(text, 400, 200, true); font.setFontSize(size); font.drawSimple(text, x, y, 400);
Simon Karman - Tingly Games, 2014 71
.
Bijlage J: Tekstbreedte bij het gebruik van spaties Een belangrijke eigenschap van een Font is dat het gerenderd kan worden met een bepaalde breedte. Valt het te renderen stuk tekst buiten deze breedte dan moet de tekst worden opgesplitst in meerdere lijnen. Voor het berekenen van de breedte gebruik ik een algoritme. Dit algoritme gaat er van uit dat de volgende bewering waar is: Lengte(woord) + Lengte(spatie) = Lengte(woord + spatie)
Ik heb deze bewering bewezen met een aantal simpele testjes. Ik heb de test uitgevoerd met meerdere lettertype en verschillende font instellingen. Hieronder is te zien hoe ik steeds een tekst zonder spatie, een losse spatie en de tekst met spatie render. Vervolgens tel ik de breedte waarde bij elkaar op. Dit laat geen verschillende breedte waarde zien voor de losse en gecombineerde tekstbreedte.
Simon Karman - Tingly Games, 2014 72
.
Bijlage K: Vector font effect snelheid Het is voor de developers bij Tingly belangrijk om informatie te hebben over de snelheden en efficiency van de game bij het gebruik van vector fonts. Nu de implementatie van de vector fonts klaar is heb ik tests uitgevoerd om de snelheid van het gebruik van verschillende eigenschappen van de tekst te meten. De profielen Het is voor het testen van de eigenschappen handig een paar basisprofielen te gebruiken. Deze basis profielen zijn gebaseerd op voorbeelden uit de praktijk. Deze voorbeeld geven hierdoor een goede weerspiegeling van de werkelijke toepassing. De profielen zijn: - Title Profile Dit profiel is een titel tekst. Deze tekst heeft een letterhoogte van 100 pixels. Daarnaast is de lengte van de tekst is kort en zal daardoor niet worden opgebroken in meerdere tekstregels. - Button Profile Dit profiel is de tekst die je tegen zal komen op knopen. Korte duidelijke tekst met een opvallend lettertype. Ook deze tekst is vrij kort en zal niet worden opgebroken in meerdere tekstregels. Voor dit profiel wordt een letterhoogte van 32 pixels gebruikt. - Text Profile: Dit profiel is een lap tekst. De tekst is niet groot, maar is wel erg lang. De tekst zal opgebroken worden in meerdere regels. Ook dit profiel gebruikt een lettergrootte van 32 pixels. Elke profiel heeft ook een ‘A’ variant. Dit is een kopie van het profiel met als fontFace ‘Arial’. De stijlen Per profiel worden er verschillende eigenschappen getest. De meetwaarden zijn de tijd die het gemiddeld duurt om de tekst een keer te renderen. De volgende stijlen worden per profiel getest: - None Fill en Stroke staan allebei uit. In feite wordt er met deze stijl dus niks gerenderd. Wel wordt de tekst terugloop en tekstbox grootte uitgerekend en de context klaar gezet voor het renderen met een lege stijl. Deze stijl is dus geen voorbeeld uit de praktijk, maar de meeting moeten worden gezien als een basis meeting voor andere stijlen. - Fill Dit is de standaard stijl voor het rendren van tekst. Standaard wil je een stuk tekst alleen maar vullen. Vaak zijn mooie effecten overbodig en zal je deze niet gebruiken.
- Stroke Deze stijl renderd alleen de randen van de tekst.
Simon Karman - Tingly Games, 2014 73
.
- Fill and Stroke Deze stijl renderd de tekst met omlijning.
- Fill and Shadow Deze stijl renderd de tekst met een schaduw.
- Stroke and Shadow Deze stijl renderd de randen van de tekst met een schaduw. Deze stijl zal in de praktijk niet vaak voorkomen.
- Gradient Fill and Stroke Deze stijl renderd de tekst met een gradient. Wanneer de tekst met een gradient gerenderd wordt is de tekst vaak onleesbaarder. In de praktijk blijkt, dat wanneer een gradient wordt gebruikt, het gebruik van de tekst rand noodzakelijk is. Daarom wordt bij het gebruik van een gradient ook de rand gerenderd.
Resultaten De resultaten van de uitgevoerde tests per browser, profiel en stijl. De absolute resultaten verschillen nogal sterk per browser en de tests zijn om die reden op de browser afgestemd. We kunnen de resultaten uiteraard vergelijken op een relatieve basis. De tests zijn op de browsers afgestemd op een duur van ongeveer 5 minuten voor de gehele test. Dit om de standaard frametijd zo veel mogelijk teniet te doen. De tijden zijn gemiddelde in milliseconden van het een keer renderen van een profiel. Letop!: De tijdsduur van een frame bij ‘60 frames per seconden’ is 16,67 milliseconden. Aangezien de engine zelf ook een deel van deze tijd zal innemen, zal het renderen van een enkel profiel ver onder deze 16,67 milliseconden moeten blijven.
Simon Karman - Tingly Games, 2014 74
.
Firefox Om er voor te zorgen dat de test binnen Firefox ongeveer 5 minuten duurt wordt het profiel per meeting 480 keer gerenderd. De tijden zijn dus een gemiddelde in milliseconden over 480 renders.
Waarnemingen Uit bovenstaande resultaten zijn de volgende gegevens waar te nemen: -
De duur van de ‘None’ stijl is kort in vergelijking met de andere stijlen Het gebruik van het build-in font ‘Arial’ is sneller dan het gebruik van een extern font ‘Stroke’ duurt langer dan ‘Fill’ De tijdsduur van ‘Fill and Stroke’ is ongeveer een opsomming van de losse ‘Fill’ en ‘Stroke’ tijd Het gebruik van schaduw is minder zwaar dan het gebruik van een extra ‘Stroke’ of ‘Fill’ Het gebruik van `GradientFill` kost weinig meer dan het gebruik van een standaard `Fill` Een profiel duurt aanzienlijk langer wanneer de tekst moet worden opgesplitst. Er is weinig verschil tussen het renderen van een grote (titel) of kleine (button) tekst
Chrome Om er voor te zorgen dat de test binnen Chrome ongeveer 5 minuten duurt wordt het profiel per meeting 4800 keer gerenderd. De tijden zijn dus een gemiddelde in milliseconden over 4800 renders.
Waarnemingen Uit bovenstaande resultaten zijn de volgende gegevens waar te nemen: - De duur van de ‘None’ stijl is lang in vergelijking met de andere stijlen - Het gebruik van een build-in font ‘Arial’ is vergelijkbaar met het gebruik van een extern font - De tijdsduur van ‘Fill and Stroke’ is ongeveer twee derde van de opsomming van de losse ‘Fill’ en ‘Stroke’ tijd - Het gebruik van schaduw is ongeveer even zwaar als het gebruik van een extra ‘Fill’ of ‘Stroke’ - Het gebruik van `GradientFill` kost ongeveer een halve keer meer tijd dan het gebruik van een standaard `Fill` - Een profiel duurt aanzienlijk langer wanneer de tekst moet worden opgesplitst. Simon Karman - Tingly Games, 2014 75
.
- Er is weinig verschil tussen het renderen van een grote (titel) of kleine (button) tekst Internet Explorer Om er voor te zorgen dat de test binnen Internet Explorer ongeveer 5 minuten duurt wordt het profiel per meeting 240 keer gerenderd. De tijden zijn dus een gemiddelde in milliseconden over 240 renders.
Waarnemingen Uit bovenstaande resultaten zijn de volgende gegevens waar te nemen: -
De duur van de ‘None’ stijl is kort in vergelijking met de andere stijlen Het gebruik van een build-in font ‘Arial’ is aanzienlijk sneller dan het gebruik van een extern font ‘Stroke’ duurt aanzienlijk langer dan ‘Fill’ De tijdsduur van ‘Fill and Stroke’ is ongeveer een opsomming van de losse ‘Fill’ en ‘Stroke’ tijd Het gebruik van schaduw is goedkoper dan het gebruik een extra ‘Fill’ of ‘Stroke’ Het gebruik van `GradientFill` kost iets meer tijd dan het gebruik van een standaard `Fill` Een profiel duurt aanzienlijk langer wanneer de tekst moet worden opgesplitst Er is weinig verschil tussen het renderen van een grote (titel) of kleine (button) tekst
Chrome op Android Om er voor te zorgen dat de test binnen Chrome op Android ongeveer 5 minuten duurt wordt het profiel per meeting 1200 keer gerenderd. De tijden zijn dus een gemiddelde in milliseconden over 1200 renders.
Waarnemingen Uit bovenstaande resultaten zijn de volgende gegevens waar te nemen: - De duur van de ‘None’ stijl is lang in vergelijking met de andere stijlen - Het gebruik van een build-in font ‘Arial’ is vergelijkbaar met het gebruik van een extern font - De tijdsduur van ‘Fill and Stroke’ is ongeveer twee derde van de opsomming van de losse ‘Fill’ en ‘Stroke’ tijd Simon Karman - Tingly Games, 2014 76
.
- Het gebruik van schaduw is ongeveer even zwaar als het gebruik van een extra ‘Fill’ of ‘Stroke’ - Het gebruik van `GradientFill` kost ongeveer een halve keer meer tijd dan het gebruik van een standaard `Fill` - Een profiel duurt aanzienlijk langer wanneer de tekst moet worden opgesplitst. - Er is weinig verschil tussen het renderen van een grote (titel) of kleine (button) tekst Deze waarnemingen komen sterk overeen met de waarnemingen van Chrome onder Windows. Safari op iOS Om er voor te zorgen dat de test binnen Safari op iOS ongeveer 5 minuten duurt moest het profiel per meeting maar ongeveer 60 keer gerenderd worden. Ik heb de test uitgevoerd op 240 keer per meeting. De tijden zijn dus een gemiddelde in milliseconden over 240 renders.
Waarnemingen - De duur van de ‘None’ stijl is gemiddeld in vergelijking met de andere stijlen - Het gebruik van een build-in font ‘Arial’ is over het algemeen sneller dan het gebruik van een extern font - Het gebruik van ‘Stroke’ zorgt voor een gigantische achteruitgang in snelheid. Dit verschil tussen wordt versterkt in het verschil tussen externe en build-in fonts. - Het gebruik van schaduw is goedkoop. - Een profiel duurt aanzienlijk langer wanneer de tekst moet worden opgesplitst. - Er is weinig verschil tussen het renderen van een grote (titel) of kleine (button) tekst
Simon Karman - Tingly Games, 2014 77
.
Extra 1: Extern Arial vs Build-in Arial Als extra onderzoek heb ik de build-in fonts vergeleken met het zelfde font ingeladen zoals een extern font. Hieronder staan de resultaten van deze tests binnen verschillende browsers: Chrome:
Firefox:
Internet Explorer:
Waarnemingen Uit de resultaten blijkt dat er geen merkbaar verschil is in snelheid tussen het gebruik van een buildin en het gebruik van een extern font.
Simon Karman - Tingly Games, 2014 78
.
Extra 2: Filltypen Als tweede extra test heb ik de verschillende mogelijke filltypen met elkaar vergeleken. De verschillende filltypen zijn Color, Pattern en Gradient.
In onderstaande tabellen staan de resultaten van de tests per browser: Chrome:
Firefox:
Internet Explorer:
Waarnemingen Uit de resultaten blijkt dat het gebruik van een Pattern het sloomste filltype is. Daarna de Gradient en Color is het snelst. Binnen Chrome is het verschil tussen Pattern en de andere filltypen aanzienlijk groot. En binnen Internet Explorer is de Gradient relatief tot de andere filltypen een stuk minder snel dan in de ander browsers.
Simon Karman - Tingly Games, 2014 79
.
Globale waarnemingen De waarnemingen, die aan de hand van de resultaten van verschillende browsers gevonden zijn, komen gedeeltelijk overeen. Er zijn echter ook een aantal grote verschillen. Waarnemingen op basis van alle browsers zijn: - De tijdsduur van ‘Fill en Stroke’ is ongeveer een opsomming van de losse ‘Fill’ en ‘Stroke’ tijd. - Het gebruik van `GradientFill` kost weinig meer dan het gebruik van een standaard `Fill`. - Een profiel duurt aanzienlijk langer wanneer de tekst moet worden opgesplitst in meerdere tekst regels. - Er is weinig verschil tussen het renderen van een grote (titel) of kleine (button) tekst. Noemenswaardige browser specifieke waarnemingen: - De absolute resultaten verschillen heel erg tussen de verschillende browsers. Zo is Chrome een factor 10 sneller dan Firefox en zelfs een factor 20 sneller dan Internet Explorer. Chrome op Android is ook vrij snel, maar wel een kwart van de snelheid van Chrome onder Windows. - Heel opvallend is dat Safari op iOS zeer sloom is in externe fonts. Vooral met ‘Stroke’. Tijdsopsomming Om het beeld duidelijker te maken staan hieronder een deel van de resultaten verwerkt in tabelvorm.
In deze grafiek is goed te zien dat het gebruik van full (GradientFill, Stroke en Shadow) in de meeste gevallen een factor 3 aan extra tijd kost. Met uitzonderingen op Internet Explorer (factor 10) en Safari (factor 150). Daarnaast is ook te zien dat het opsplitsen van de tekst in meerder regels (in het ‘Text’ profiel) de tijd ongeveer verviervoudigt. Dit komt overeen met het aantal regels dat gerenderd moet worden. De tijd zit ‘m dus in het renderen. Het opsplitsen zelf kost naar verhoudingen minder tijd en wordt daarnaast altijd voor een deel uitgevoerd. Tijdsgrafiek Schematische weergave van de tijdsbesteding bij het renderen van teksten met verschillende effecten. Deze weergave geeft relatieve verschillen aan en geeft dus geen precieze waarden weer.
Simon Karman - Tingly Games, 2014 80
.
Bijlage L: Vector font versus bitmap font en losse canvas snelheden Nu de implementatie gereed is is het interessant om de oude bitmap font implementatie en de nieuwe vector font implementatie opnieuw met elkaar te vergelijken. De eerdere vergelijkingen waren steeds op basis van het renderen van een simpele tekst zonder effecten en regel overloop. Nu kunnen we deze effecten en regel overloop meenemen in de vergelijkingen. De profielen en stijlen De profielen zijn gelijk aan die in ‘Bijlage K: Vector font effect ’. Er zijn wel een aantal stijlen bij gekomen. Deze stijlen worden gebruikt voor zowel de losse canvas als de bitmap font implementaties. - Canvas6 De tekst wordt met de ‘Gradient Fill and Stroke and Shadow’ stijl gerenderd op een losse canvas. Deze canvas wordt vervolgens op het scherm gerenderd. Na zes keer wordt op een nieuwe losse canvas gerenderd en deze weer wordt gebruikt voor de volgende zes renders.
- Canvas12 / Canvas24 / Canvas48 Zelfde als de vorige stijl, maar dan om de 12/24/48 renders. - Canvas Zelfde als de vorige stijl, maar dan wordt er maar een losse canvas gebruikt voor alle verdere renders. - Bitmap De tekst wordt gerenderd met een bitmap font. De stijl hiervan staat vast tijdens de buildtime en heeft geen invloed op de rendertijd, maar kan dus ook niet worden gewijzigd of geschaald tijdens runtime. Resultaten De tests zijn een stuk langer geworden en zijn niet afgestemd op de 5 minuten (zoals in ‘Bijlage K: Vector font effect ’). Chrome
Simon Karman - Tingly Games, 2014 81
.
Firefox
Internet Explorer
Android Browser
Safari op iOS - iPad
Simon Karman - Tingly Games, 2014 82
.
Waarnemingen Hieronder de waarnemingen van de gevonden gegevens binnen de verschillende browsers. Chrome De tijdsduur van het renderen van de ‘Bitmap’ stijl is vergelijkbaar met een ‘Fill and Shadow’ stijl. Het gebruik van een losse canvas wordt goed bruikbaar wanneer je een tekst hebt met meerdere actieve effecten. Het gebruik wordt rendabel vanaf ongeveer 24 renders bij het renderen van het ‘Titel’ profiel. Bij het renderen van het ‘Button’ profiel is dit effect al iets eerder voordelig. Bij het renderen van een stuk tekst dat wordt opgebroken in meerdere lijnen is het effect al lonend bij zes renders. Firefox De tijdsduur van het renderen van de ‘Bitmap’ stijl is korter in vergelijking tot een simpele ‘Fill’ stijl. Het gebruik van een losse canvas is vele male sneller dan het steeds opnieuw renderen van de tekst. Dit is dus voor elk aantal renders rendabel. Internet Explorer De tijdsduur van het renderen van de ‘Bitmap’ stijl is ongeveer de helft van een simpele ‘Fill’ stijl. Het gebruik van een losse canvas is vele male sneller dan het steeds opnieuw renderen van de tekst. Dit is dus voor elk aantal renders rendabel. Android Browser De tijdsduur van het renderen van de ‘Bitmap’ stijl is vergelijkbaar met een ‘Fill and Shadow’ stijl. Het gebruik van een losse canvas lijkt hier niet veel optimalisatie te bieden. Behalve bij het ‘Text’ profiel. Safari op iOS - iPad De tijdsduur van het renderen van de ‘Bitmap’ stijl is iets langer dan het renderen van een simpele ‘Fill’ stijl. Het gebruik van een losse canvas heeft heel sterk invloed. Vooral omdat het gebruik van ‘Stroke’ enorm veel tijd in beslag neemt. Deze tijd hoeft maar een keer te worden besteed wanneer er op een losse canvas wordt gerenderd.
Simon Karman - Tingly Games, 2014 83
.
Bijlage M: Anti-Aliasing in verschillende browsers Als een browser karakter renderd dan zorgt de browser er voor dat de tekst wordt geanti-aliased. Hoe (en of) de browser anti-aliasing toepast is niet via een standard HTML5 feature beschreven of aan te geven. Waarnemingen Hieronder is per browser een voorbeeld te zien van de anti-aliasing. De kleine letter a is met een letterhoogte van 100 pixels gerenderd. En daarnaast op is een rasterversie, op pixel niveau, de antialiasing die wordt toegepast te bekijken. Android Browser
Google Chrome
Simon Karman - Tingly Games, 2014 84
.
Mozilla Firefox
Internet Explorer
Safari
Conslusie Duidelijk is dat in elke browser de anti-aliasing wordt toegepast. Wat echter op valt is dat Google Chrome de enige browser is waar de anti-aliasing duidelijk een stuk minder is dan in de ander browsers. Dit zal met zeer grootte teksten (letterhoogte van meer dan 100px) gaan opvallen. Een speculatie die direct uit deze conclusie voortvloeit is de volgende vraag: “Is het minder toepassen van anti-aliasing in Google Chrome de reden van het grootte snelheidsvoordeel op andere browsers?”. Dit is niet te achterhalen en blijft een speculatie. Het is in ieder geval zaak om goed op te letten dat wanneer deze anti-aliasing bug wordt gepatched, Google Chrome trager kan worden. Simon Karman - Tingly Games, 2014 85
.
Bijlage N: Gecombineerde Lettertypen Tijdens het gebruik van mijn library heeft een andere developer een font gevonden dat een losse variant heeft voor de bold, italic en bold-italic varianten van het font. Naast het font dat deze developer vond zijn er nog een hoop andere fonts die zijn opgebouwd uit meerdere lettertype varianten. Deze fonts gebruikt naast een standaard font file (.ttf bestand), aparte font files voor elke variant.
Het is interessant om in de Tingly Builder fonts te kunnen maken waarbij deze font files aan elkaar gekoppeld kunnen worden. Inladen De fontFace definities in css die gebruikt worden om het fontFace te definiëren geven de mogelijkheid tot het specificeren van verschillende varianten van hetzelfde font. Op deze manier kan op een via de browser geïmplementeerd manier een losse font file worden toegekend aan een bepaalde variant. Fallback mechanisme Een nadeel van deze fontFace varianten is dat het fallback mechanisme niet meer intuïtief is. Het fallback mechanisme van deze font varianten werkt anders dan verwacht. In onderstaand plaatje staat het fallback mechanisme gevisualiseerd:
Simon Karman - Tingly Games, 2014 86
.
De oranje pijlen geven aan waarop een font terug valt wanneer deze niet geladen is. De oranje pijl met het rode kruis geeft aan hoe je zou verwachten dat het fallback mechanisme zou werken. Maar tegen verwachtingen in werkt het dus niet op deze manier. Toepasbaarheid Na het tbVectorFontLoader object omgeschreven te hebben om support te bieden aan meerdere font files zijn de wijzigingen voorgelegd aan Mark Overmars. Mark was zeer te spreken over de adequate en goede response op het verwerken van feedback van een mede developer. Mark heeft er voor gekozen de feature niet te implementeren omdat het niet mogelijk is om meerdere bestanden te koppelen aan een enkele resource in de Tingly Builder. Het supporten hiervan zou een immense herschrijving van de Tingly Builder vereisen. Dit is de tijd niet waard. Daarnaast heb ik Mark uitgelegd dat het fallback mechanisme met deze feature erg vaag en onduidelijk wordt. Dit heeft er mede toe geleid geen verdere stappen te ondernemen om gecombineerde lettertypen te implementeren.
Simon Karman - Tingly Games, 2014 87
.
Bijlage O: Skew Transformaties op de canvas Elke object dat op de canvas wordt gerenderd wordt onderworpen aan een transformatie matrix. Deze transformaties kunnen worden gebruikt voor translation, rotation, scale en skew.
De bovenstaande transformaties zijn allemaal affine. Dit houdt in dat lijnen die voor de transformatie parallel lopen ook na de transformatie nog parallel lopen. Het combineren van affine transformaties zal altijd resulteren in een nieuwe affine transformatie. In onderstaande afbeelding het verschil tussen affine en none-affine goed te zien. None-affine transformaties zijn in HTML5 niet mogelijk.
Simon Karman - Tingly Games, 2014 88
.
Voor het gebruik in een WordArt tekst is het handig om de tekst none-affine te kunnen transformeren. In onderstaand figuur is te zien hoe deze none-affine transformatie eruit ziet.
Deze manier van skewing is in HTML5 niet mogelijk. Het is niet mogelijk om zo’n transformatie toe te passen voor het gebruik van een WordArt tekst. Het is wel mogelijk om de tekst steeds iets kleiner te renderen. Hierdoor mis je echter het verschil in grootte tussen de linker en rechter kant van elk karakter. Dit zorgt voor een schokkerige en minder mooi effect.
Daarnaast kunnen we de skewing per karakter toepassen. Hierdoor krijg je toch een redelijk effect bij sommige stijlen. Hieronder staan de verschillende transformaties afgebeeld.
Simon Karman - Tingly Games, 2014 89
.
Bijlage P: WordArt Documentatie Dit is de documentatie die is geschreven voor de WordArt implementatie. Deze WordArt implentatie maakt gebruik van de vector font library. De documentatie is vrij te bekijken door developers die gebruik maken van de Tingly Builder. De documentatie is bedoeld om ondersteuning te bieden aan de developer tijdens het gebruik van de library. De developer is niet per definitie Nederlands, de onderstaande documentatie is daarom geschreven in het Engels. WordArt WordArt is a decorative way of styling text. You can create your own WordArt styles or use predefined WordArt styles to draw text. Note: drawing WordArt can take up way more time than drawing an average VectorFont text. A WordArt drawing always returns a surface. This surface contains the drawn text. You must draw this surface to the screen. tbWordArt Namespace WordArt uses its own namespace. This is tbWordArt. The tbWordArt namespace consists of the following elements: - Presets; - Changers; - Render Function Presets Presets are the predefined WordArt kinds that can be used for creating WordArt. Changers Changers are functions that change a WordArt kind. Render Function Render function is the function that can render text using a WordArt kind. This function expects the WordArt kind and a text. The function returns a surface. var surface = tbWordArt.renderText(kind, “Hello World”); surface.drawSimple(10, 10);
Kind A kind describes a singly style of WordArt. A WordArt kind is simply an object that consists of the following properties: layers Layers is an array of layer objects. Each layer is an individual render. Each layer contains the following properties: - font - The tbVectorFont or tbBitmapFont that is used when drawing characters for this layers; - x and y – The offset in pixels for the x and y direction - (optional) transformLayerOffset – A boolean whether to apply the transformations on the offset Simon Karman - Tingly Games, 2014 90
.
mainLayer The index of the layer that is used for calculating the width of the characters. (default 0) Note: The mainLayer must be a VectorFont! loopedProgress A boolean whether the relative progress is looped or not-looped. (default false) Text H E L L O Looped 0.00 0.20 0.40 0.60 0.80 Progress Not-Looped 0.00 0.25 0.50 0.75 1.00 CharID 0 1 2 3 4 The relative progress is a property of the charInfo object. This object is send to the positionFunc, contextFunc, fontFunc and charmapFunc. - A looped progress is useful when drawing text in a circle. - A not-looped progress is used in most other situation. When not-looped is used, the last character will have a relative progress of 1.00. trackingWidthBased A boolean whether the tracking between characters is based on the width of the characters. When false the tracking will be based on the height of the characters. (default true) tracking The extra tracking between each character. (default 0) positionFunc A function that returns the positions for the characters. The charInfo argument is passed to this function. perpendicular A boolean whether the characters should be rotated perpendicular on the line. (default true) perpendicularType A value what type of perpendicular type to use. Can be “skew” or “rotate”. When using skewing the line angles greater than 60 degrees are not recommended, otherwise artifacts may appear. (default “rotate”) pixelOffsetFactor The offset factor used for calculating the angle of a point on the line (default 8). Higher numbers will inspect a smaller portion of the line to calculate the angle. canvasExtendAll, canvasExtendLeft, canvasExtendTop, canvasExtendRight, canvasExtendBottom The values by which the canvas is extended in pixels. (default 0) contextFunc A function that will receive the charInfo and context as arguments. (default undefined) fontFunc A function that will receive the charInfo and font as arguments. (default undefined)
Simon Karman - Tingly Games, 2014 91
.
charmapFunc A function that will receive the charInfo and current character as arguments. You must return a character. (default undefined) Note: the width of the mainLayer will be calculated before applying the charmapFunc. If you want the width based on the new character-width you should simply change the text before passing it to the renderText-function. CharInfo object All function that you can specify on the WordArt kind receive the charInfo object as first argument. The charInfo object is an object that holds information about the character that is currently being drawn. The charInfo object contains the following information: - progress – An object containing the absolute progress in pixels and the relative progress as a value between 0 and 1; - layerId – The id of the current layer. Note that in the postionFunc this is always the mainLayer; - charId – The id of the current character in the text; - text – The text that is drawn; - totalWidth – The total width in pixels of the text that is drawn. charInfo object: { progress: { relative absolute }, layerId charId text totalWidth }
Presets Presets are predefined styles of WordArt. Presets will always return a newly created WordArt kind object. You can create a WordArt kind from a preset by using the following code: var kind = tbWordArt.presets.
(font, <arguments>)
Each preset has a name. Some presets have additional arguments you need to specify. The presets currently available are: - normal – This is the default WordArt preset that can be used to create your own. - rainbow – This is a rainbow WordArt preset that can be used to create rainbow text. This preset also expects one additional argument: The height of the rainbow. This value is usually between 40 and 100. Note: You can add your own presets. Simply set a property on the preset object. Example: tbWordArt.presets.myPreset = function(font) { var kind = tbWordArt.presets.normal(font); //Alter kind here! return kind; }
Simon Karman - Tingly Games, 2014 92
.
Changers Changers are predefined operations on a Word Art kind that change the behavior of it. A changer always expects the kind as a first argument and it will modify the given kind. Some changers expect some additional arguments. You can use a changer by running the following code: tbWordArt.change..(kind, <arguments>)
All the changers are displayed in following code block. Arguments surrounded by [ and ] are optional and can be omitted. layers tbWordArt.change.layers.normal(kind, font) tbWordArt.change.layers.multistroke(kind, font, strokes) tbWordArt.change.layers.neon(kind, font) tbWordArt.change.layers.anaglyphic(kind, font, [color1], [color2]) positionFunc tbWordArt.change.positionFunc.normal(kind) tbWordArt.change.positionFunc.vertical(kind, [perpendicular]) tbWordArt.change.positionFunc.arc(kind, height) tbWordArt.change.positionFunc.circle(kind, [radius]) contextFunc tbWordArt.change.contextFunc.normal(kind) tbWordArt.change.contextFunc.rotationOffset(kind, angle) tbWordArt.change.contextFunc.yScaling(kind, normalSize, peakSize, [layerId]) fontFunc tbWordArt.change.fontFunc.normal(kind) tbWordArt.change.fontFunc.colorSpectrum(kind) tbWordArt.change.fontFunc.fontSize(kind, normalSize, peakSize, [layerId]) charmapFunc tbWordArt.change.charmapFunc.normal(kind)
All changers that are named normal will reset the function to their default. You can use the above changers as examples for your own functions. When creating your own WordArt you can take a look at these changers in the engine code and alter them to your liking. Note: You can add your own changers. Simply set a property on the change object. Example: tbWordArt.change.positionFunc.sinusWave = function(kind) { .. }
Simon Karman - Tingly Games, 2014 93
.
Bijlage Q: Stroke artifacts Wanneer er strokes worden gebruikt verschijnen er lelijke artifacts van strokes die uitsteken.
Dit begon bij het gebruikt van WordArt erg op te vallen. Er moest dus een oplossing voor worden gevonden. De oplossing Standaard staat op de lineJoin van lijnen op “miter” ingesteld. Hieronder zijn de verschillende lineJoin typen te zien.
Wanneer “bevel” of “round” wordt gebruikt dan wordt de stroke afgekapt. Nu kan de stroke niet meer te ver uitsteken. Op deze manier kan het dus worden opgelost.
Aan de vector font API moet deze lineJoin eigenschap toegevoegd worden. Een vector font heeft daarom nu een strokeJoin eigenschap. Deze eigenschap kan “round”, “bevel” of “miter” zijn. Standaard staat deze eigenschap op “miter”. De volgende documentatie is toegevoegd aan de vector fonts informatie in de Tingly Builder. font.setStrokeJoin(join) Sets the stroke join of the stroke. The default value is "miter". Allowed values are "round", "bevel" and "miter". When no argument is passed the stroke width will be set to "miter". font.getStrokeJoin() Returns the current stroke join Snelheidstest Nu er verschillende waarde kunnen worden ingesteld voor lineJoin is het interessant om de kijken of deze verschillende waarde ook verschillende tekensnelheden hebben. Er is een test uitgevoerd naar de tekensnelheden van de verschillende lineJoin typen. Simon Karman - Tingly Games, 2014 94
.
IE “miter” 1,250ms “round” 1,345ms “bevel” 1,236ms
Firefox 0,974ms 1,124ms 1,054ms
Chrome 0,060ms 0,058ms 0,057ms
Uit deze test blijkt dat het gebruik van “round” of “bevel” ongeveer tien procent extra tijd kost dan het gebruik van het standaard joinType “miter”. De verschillen tussen de joinTypen zijn daarentegen wel erg klein. Toch valt op dat het standaard joinType “miter” in IE en Firefox ondanks het minieme verschil het snelste is. Dit is de reden dat ook in de vector font library het joinType standaard op “miter” staat ingesteld.
Simon Karman - Tingly Games, 2014 95
.
Bijlage R: Niet-westerse karakters De aanleiding van dit onderzoek was dat Tingly Games graag ziet dat de engine waarmee de games ontwikkeld worden het gebruik van niet-westerse karakters kan ondersteunen. Naar aanleiding van deze wens zijn de tbVectorFont API en tbWordArt API gemaakt. Om niet-westerse karakters te ondersteunen moeten alle stappen in het ontwikkelingsproces overweg kunnen en ondersteuning bieden aan niet-westerse karakters. Hieronder staan alle stappen beschreven. Lokalisatie tool De lokalisatie tool wordt gebruikt om de teksten in verschillende talen in te kunnen voeren voor het gebruik in de spellen. In deze tool kunnen de verschillende talen worden beheert, aangepast en samengesteld voor games. Onderdelen in de tool: Tekst invoer: De tekst invoer ondersteund het invoeren van niet-westerse karakters. Samenstellen: Wanneer voor een game een lokalisatie file wordt samengesteld zijn niet-westerse karakters toegestaan.
Tingly Builder De Tingly Builder wordt gebruikt om de spellen to produceren. In deze tool moeten de nietwesterse karakters kunnen worden ingeladen, opgeslagen en worden samengevoegd bij het bouwen van een game. Onderdelen in de builder: Inladen: Bij het inladen van de karakters worden niet-westerse karakters ondersteund. Opslaan: Bij het opslaan van bestanden die niet-westerse karakters bevatten gaan nietwesterse karakters verloren. Deze karakters worden via een RichTextBox opgeslagen op de harde schijf. Deze opslag methode maakt gebruik van een ASCII encoding. In deze encoding gaan de niet-westerse tekens verloren. Door een kleine aanpassing in de code worden de teksten opgeslagen met een UTF-8 encoding waardoor de niet-westerse tekens behouden blijven. Bouwen: Wanneer een game wordt gebouwd en de JavaScript file wordt samengesteld zijn nietwesterse karakters toegestaan.
Browsers De browsers moeten de games uiteindelijk aan de eindgebruiker laten zien. De browsers moeten het tekenen van de niet-westerse karakters ondersteunen. Onderdelen in de browser: Tekenen: Alle browsers ondersteunen het gebruik van niet-westerse karakters. Simon Karman - Tingly Games, 2014 96
.