aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/jogamp/graph/curve
Commit message (Collapse)AuthorAgeFilesLines
* Graph: Cleanup Loop & OutlineShape, more compact methodsSven Göthel2024-02-151-93/+62
|
* VectorUtil: Bring back specialized testSeg2segIntersection() w/ build-in ↵Sven Göthel2024-02-141-4/+4
| | | | | | | | FloatUtil.EPSILON epsilon and no collinear test commit 5488665474cc7b88577cedfca6416784f0fda3ba Generalize *seg2segIntersection* w/ epsilon and doCollinear caused a big performance hit about 1/3 due to added doCollinear case and manual epsilon adding branches and having the method being longer - probably not 'hotspot'ed.
* Bug 1501: Refine convex == !complex: Use 'complex' term, have env-property ↵Sven Göthel2024-02-142-20/+12
| | | | | | toggle OutlineShape's isComplex() for visibility We may use complex for other criteria than !convex, i.e. self-intersecting etc.
* VectorUtil: Generalize *seg2segIntersection* w/ epsilon and doCollinearSven Göthel2024-02-141-8/+8
|
* VectorUtil: Remove double InCircleDThreshold = DoubleUtil.EPSILONSven Göthel2024-02-141-1/+3
|
* Bug 1501: Graph CDTriangulator2D: Add properties to enforce convex and ↵Sven Göthel2024-02-141-2/+10
| | | | non-convex treatment to simplify debugging etc
* Bug 1501: Apply intersection tests for non-convex shapes to reject new CCW ↵Sven Göthel2024-02-132-103/+246
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | and non-circulcircle triangulation candidates in our Delaunay tessellator <https://jogamp.org/bugzilla//show_bug.cgi?id=1501#c6> The used Delaunay tessellation works well with (almost) convex shapes. In case e.g. a glyph gets to the extremes like 'M' in FreeMono or any other complex Chinese symbol - it may just simply happen that the new non-circumcircle triangle point crosses the inner (hope) or outer boundaries of the given polygon. Applying further constraint at Loop.cut() resolves most cases by rejecting the proposed CCW and non-circumcircle triangle candidate if its new two line-segments intersects with the original polygon. This results in mostly proper rendered Chinese fonts and also FreeMono is now readable - overal remaining bugs in Glyphs is low. +++ Of course, this intersection test is costly around >= O(log(n)*n) costs, practically adding a measured ~65% processing time. E.g. for FontView01 using FreeSerif.ttf - orig total took 1430.817638ms, per-glyph 0.2236ms, glyphs 6399 - fix total took 2377.337359ms, per-glyph 0.371517ms, glyphs 6399 Pure Glyph/Shape instantiation shows > 2x costs: 750 ms 100% convex (fake) 1875 ms 0% convex (fake) 1870 ms 13% convex 824/6399 +++ Hence it is desired to either (1) Manually mark a polygon non-convex to add described intersection test for accuracy. Also may be used to just drop the additional costs despite the lack of correctness. PROVIDED (2) Determine non-convex nature of a polygon with a and overall less expensive algorithm. If considerably cheaper, this could reduce O(log(n) * n) -> O(n) or even O(log n). Added convex/non-convex classification while ignoring off-curve points, but only ~13% of FreeSerif is pure convex, hence there is no benefit with this classification type. It might be desired to attempt other classes, i.e. being rendered in non-convex mode w/o intersection tests. See - GENERALIZED DELAUNAY TRIANGULATIONS OF NON-CONVEX DOMAINS https://deepblue.lib.umich.edu/bitstream/handle/2027.42/28782/0000614.pdf;sequence=1 - https://en.wikipedia.org/wiki/List_of_self-intersecting_polygons - https://en.wikipedia.org/wiki/Complex_polygon
* Bug 1501: Graph RenderState add debug-bits, i.e. DEBUG_LINESTRIP used in ↵Sven Göthel2024-02-131-1/+2
| | | | VBORegionSPES2 to just render lines instead of the filled area -> Used in UIShapeDemo02a
* Graph RenderState/RegionRenderer: Rename isHintMaskSet()->hintBitsSet(), ↵Sven Göthel2024-02-133-7/+8
| | | | setHintMask()->setHintBits(), clearHintMask()->clearHintBits()
* Loop.isValidNeighborDbg(): Remove DEBUG branch, always trueSven Göthel2024-02-121-8/+4
|
* Bug 1501: Graph Delaunay: Use default winding outer-boundary:=CCW and ↵Sven Göthel2024-02-122-25/+22
| | | | | | | | | | | inner-hole:=CW w/o using winding determination (might be incorrect) This simplifies our code further and it has been validated that our polygon shoelace-algo for area >= 0 ? CCW doesn't produce correct results with all curves. Hence rely on given winding depending on outer-boundary and inner-hole if CDTriangulator2D.FixedWindingRule == true (default and fixed). This also removes the more costly winding shoelace calculus, hence Outline ctor only sets dirtyWinding:=true w/o calculating the winding.
* Bug 1501: Graph Delaunay: Add double triAreaVec2() and isInCircleVec2() ↵Sven Göthel2024-02-123-88/+132
| | | | | | | | | | | | version, overcome float precision; Loop: Pass edgeType not Winding, simplify findClosestValidNeighbor() -> isValidNeighbor(); CDTriangulator2D.addCurve() enforces Winding.CCW on BOUNDARY null == loop case Add double version of triAreaVec2() and isInCircleVec2() in VectorUtil, overcoming float precision limits - Analysis exposed float precision limits within isInCircleVec2() Loop: Pass edgeType not Winding, simplify findClosestValidNeighbor() -> isValidNeighbor() - Enhance code clarity CDTriangulator2D.addCurve() enforces Winding.CCW on BOUNDARY null == loop case
* Remove Clonable and clone() in favor of explicit determined copy() and ↵Sven Göthel2024-02-022-11/+11
| | | | copy-ctor in com.jogamp.graph.* and com.jogamp.math.*
* Bug 805: Graph/GraphUI TextureSequence Scale: Move ↵Sven Göthel2024-02-016-7/+49
| | | | | | | | | Region.COLORTEXTURE_LETTERBOX_RENDERING_BIT to TextureSequence and add enabling/disabling of aratio adjustment + letter-box back-color TextureSequence color-texture params fetched from Graph VBORegion* and fed into shader. This allows more flexibility in aspect-ratio adjustment as well as setting a clipping background color for the added letter-box space.
* Graph shader (pass1 simple): USE_COLOR_TEXTURE: Clip to vec4(0) color using ↵Sven Göthel2024-01-311-4/+4
| | | | alpha 0 instead of the debug color white vec4(1), which leads to the white seam if out of gcu_ColorTexBBox
* VBORegionSPES2: Disable verbose flag in TextureSequence.setTexCoordBBox() .. ↵Sven Göthel2024-01-221-1/+1
| | | | oops
* Graph Clipping: Use Frustum Clipping using AABBox -> Mv transformed Cube -> ↵Sven Göthel2024-01-2015-103/+121
| | | | | | | | | | | | | | | | | | | | | | | | | | Frustum mapping + GraphUI Support AABBox clipping naturally couldn't be transformed into 3D Model-View (Mv) Space, as it is axis aligned and only provided 2 points (min/max). Therefor we map the Group's AABBox to a 8-point Cube, perform the Mv-transformation and then produce the 6-plane Frustum. As before, we cull fully outside shapes within the Group's draw method and perform fragment clipping with same Frustum planes in the shader. With clipping enabled, the 3D z-axis getBounds() depth will be slightly increased for functional Frustum operation. This is also done for setFixedSize(Vec2f). The Frustum planes are copied to the Graph shader via float[4*6] -> uniform vec4 gcu_ClipFrustum[6]; // L, R, B, T, N, F each {n.x, n.y, n.z, d} +++ Concludes related work of below commits - 1040bed4ecc6f4598ea459f1073a9240583fc3c3 - 5cca51e32999a882e2a5f00cb45ecafc824ffd86
* Graph/GraphUI AA-Quality + SampleCount (shader): Push params down to ↵Sven Göthel2024-01-163-49/+47
| | | | | | | | | | | | | | | | | | RegionRenderer's RenderState usually rarely set from top of user API, reducing complexity. Discussion: Alternative was to pass AA-Quality same as SampleCount from the top (e.g. GraphUI Scene), however, this convolutes the API even more. Both parameter modify the resulting shader code in pass2 rendering (only). The used 'renderMode' is still maintained within the Region, since it contains more dynamic states individual to each Region instance (color-texture, ..). This despite 'renderMode' also changes the RenderState's shader program. In the end, it really doesn't matter and is a choice of frequency - the pipeline is usually rendering from on OpenGL rendering thread sequentially. AA-Quality and SampleCount simply usually don't change that often and are set only once.
* Bump (c) -2024 for edited files + LICENSE.txtSven Göthel2024-01-145-5/+5
|
* Graph/GraphUI: Revise Graph Region ShaderMapping, fix AABBox-Clipping for ↵Sven Göthel2024-01-1410-220/+250
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Pass2-AA, revise Pass2 AA Quality parameter .. Misc: - Graph VBORegion2PVBAAES2: Drop unused FBO rescale - Move MIN/MAX QUALITY/SAMPLE from GraphUI Scene -> Graph Region +++ Quality -> Pass2 AA Quality - Drop quality field in region - Pass quality to GLRegion.draw(..) similar to sampleCount for dynamic shader and switch - TODO: Pass quality parameter in TextRegionUtil's functions Fix RegionRenderer Shader Mapping - Use ShaderKey class to properly implement the hash value and equals method - For this, TextureSequence.getTextureFragmentShaderHashID() has been added to provide actual shader-snippet for the equals function - All required criterias are included in the hash value and equals method Fix AABBox Clipping for Pass-2 AA - Clipping in pass2-AA must happen in pass2 on actual gcu_PMVMatrix01 (not ortho) +++ GraphUI GraphShape - Rename: [get,set]{->AA}Quality() GraphUI Scene - Rename: mark{All->}ShapesDirty(), set{AllShapes->}Sharpness(), set{AllShapes->AA}Quality() - Fix setSampleCount(..), i.e. markStatesDirty() not markShapesDirty() - Fix setAAQuality(), markShapesDirty() and markStatesDirty(): Use forAll(..) to traverse through all shapes and groups. GraphUI Group - Add setFixedSize() - Add setClipOnBox() - Document setRelayoutOnDirtyShapes(), isShapeDirty()
* Graph VBORegion2PVBAAES2: Fix Rescale (MAX texSize): renderFboHeight shall ↵Sven Göthel2024-01-121-1/+1
| | | | use winHeight (typo)
* Graph Clipping: Add missing Modelview-Matrix (Mv) Multiplication / ConsiderationSven Göthel2024-01-092-2/+2
| | | | | | - GLSL vertex shader sets smooth varying 'gcv_ClipBBoxCoord' w/ Mv multiplied vertex-coord - RegionRenderer.setClipBBox(AABBox) expects a pre-multiplied Mv AABBox covering an independent area, not per Shape/Region. - This works as expected with moving/scaling of each Shape/Region etc
* Graph Clipping: Initial Region impl of AABBox clipping using GLSL shader ↵Sven Göthel2024-01-093-21/+72
| | | | | | | | | | | | (Convenient using Graph/GraphUI produced AABBox) Simple demo, setting clip-bbox manually: - src/demos/com/jogamp/opengl/demos/graph/ui/UIShapeClippingDemo00.java TODO: - GLSL: Add missing Mv-multiplication of vertex-position -> gcv_ClipBBoxCoord -- AABBox min/max should be set pre-multiplied w/ Mv covering an independent area, not per Shape/Region. -- This to properly work with moving/scaling of each Shape/Region etc
* Graph Clipping: GLSL: Add `USE_AABBOX_CLIPPING`, i.e. clipping via AABBox ↵Sven Göthel2024-01-098-19/+50
| | | | | | | | | | | | | | | min/max vec3 as convenient using Graph/GraphUI produced AABBox USE_AABBOX_CLIPPING - Conditional compilation w/ macro 'USE_AABBOX_CLIPPING' - gcv_ClipBBoxCoord smooth varying setup in vertex shader - fragment shader clips via branch if( is_inside(gcv_ClipBBoxCoord, gcu_ClipBBox[0], gcu_ClipBBox[1]) < 0.5 ) { CLIP } - clipping via discard or alpha=0 in case of buggy-discard. Other optimization: - Drop gcv_ColorTexExt, fragment-shader uses gcu_ColorTexBBox[2] directly (flat) - Simplified gcv_ColorTexCoord smooth varying equation in vertex shader.
* Graph GLSL functions.glsl: Complete overload vec2 and vec3 variants; Fix ↵Sven Göthel2024-01-091-8/+52
| | | | | | | | | | | | | | | | | | 'and'/'or' semantic (swapped); Add EPSILON in clip_coord(..) and add is_inside(..) function Complete overload vec2 and vec3 variants Fix 'and'/'or' semantic (swapped) - 'and' uses multiplication, i.e. all arguments must be > 0 (ideally 1) - 'or' uses addition, i.e. only one arguments must be > 0 (ideally 1) - both uses clamp [0..1] Add EPSILON in clip_coord(..) - Only 'coord > high+EPSILON' is outside Add is_inside(..) function - Similar to clip_coord(..) but returns float 0 or 1 instead of selecting color.
* Graph Shader: Fix 'curverenderer01-single.vp' aligning w/ ↵Sven Gothel2023-12-181-2/+3
| | | | 'curverenderer01-pass1.vp' (commit 297c48f4fefd1ab59800524ea5f0dd56684d6786)
* TextureSequence.setTexCoordBBox(): Add 'verbose' parameter for debug output ↵Sven Gothel2023-10-033-3/+3
| | | | instead hard coded branch
* Bug 1465 - Graph / GraphUI: Render a Region's ColorTexture in proper ↵Sven Gothel2023-09-309-72/+80
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | aspect-ratio, letter-boxed or zoomed (config) + Bug 1466 Fix color mixing Bug 1465: Region currently simply bloats a given texture to its region AABBox, which renders textures with the wrong aspect ratio. Add facility to program the texture-coordinates to either letter-box or scaled-up (and cut) true aspect-ratio. Default shall be zoom (scale-up and cut), but user shall be able to set a flag in the Region for letter-box. Have the shader clip texture coordinates properly, best w/o branching to soothe performance. See functions.glsl +++ Bug 1466: Current color mix: texture * color_channel * color_static is useless in GraphUI. color_static shall modulate the texture, which works. But in case of color_channel (attribute/varying) we want it to be mixed so it can become the more dominant color for e.g. a border. Desired is: color = vec4( mix( tex.rgb * gcu_ColorStatic.rgb, gcv_Color.rgb, gcv_Color.a ), mix( tex.a * gcu_ColorStatic.a, 1, gcv_Color.a) );
* Bug 1452 - Decouple math functionality to 'com.jogamp.math' to be toolkit ↵Sven Gothel2023-09-206-21/+21
| | | | | | | | | | | | | | | | | | | | agnostic (PMVMatrix, Matrix4f, Vec4f, ..) Math functionality (PMVMatrix, Matrix4f, Vec4f, ..) - shall be used toolkit agnostic, e.g. independent from OpenGL - shall be reused within our upcoming Vulkan implementation - may also move outside of JOGL, i.e. GlueGen or within its own package to be reused for other purposed. The 'com.jogamp.opengl.util.PMVMatrix' currently also used to feed in GLUniformData via the toolkit agnostic SyncAction and SyncBuffer shall also be split to a toolkit agnostic variant. An OpenGL PMVMatrix specialization implementing GLMatrixFunc can still exist, being derived from the toolkit agnostic base implementation. +++ Initial commit .. compile clean, passing most unit tests.
* Debug.debugExplicit(): Define and use explicit symbol debug flag; Use it for ↵Sven Gothel2023-09-163-5/+15
| | | | certain debug output to keep most silence for debugAll()
* Graph Loop: Make initFromPolyline() and locateClosestVertex() more robust, ↵Sven Gothel2023-08-283-11/+33
| | | | | | report error but do not crash. This behavior has been evaluated with a few fonts and the WIP FontView01 demo application.
* Graph Add {GLRegion, GraphShape}.setTextureUnit(int): Allowing to set ↵Sven Gothel2023-08-013-0/+15
| | | | texture unit after ctor
* Graph CDTriangulator2D: Drop invalid innerPoly, avoiding ↵Sven Gothel2023-05-051-2/+30
| | | | | | | | | | | | | | | | | | | | | | | | | | | Loop.initFromPolyline(..) outline.getGraphPoint().size() < 3 IllegalArgumentException This issue has to be added to our CD .. /* * Font FreeMono-Bold: ID 0 + 465: Glyph[id 465 'uni020F', advance 600, leftSideBearings 42, kerning[size 0, horiz true, cross true], shape true], OutlineShape@5e8a459[outlines 2, vertices 34] Drop innerPoly ctrlpts < 3 - innerPo[vertices 2, ctrlpts 2] < 3 - outline[vertices 4, ctrlpts 4] - Input[vertices 4] * * Font FreeSans-Regular: ID 0 + 409: Glyph[id 409 'Udieresiscaron', advance 720, leftSideBearings 80, kerning[size 0, horiz true, cross false], shape true], OutlineShape@5eb97ced[outlines 3, vertices 33] Drop innerPoly ctrlpts < 3 - innerPo[vertices 1, ctrlpts 1] < 3 - outline[vertices 1, ctrlpts 1] - Input[vertices 1] * Stack: at jogamp.graph.curve.tess.CDTriangulator2D.addCurve(CDTriangulator2D.java:97) at com.jogamp.graph.curve.OutlineShape.triangulateImpl(OutlineShape.java:988) at com.jogamp.graph.curve.OutlineShape.getTriangles(OutlineShape.java:1012) at com.jogamp.graph.curve.Region.countOutlineShape(Region.java:503) at com.jogamp.graph.ui.shapes.GlyphShape.<init>(GlyphShape.java:77) */
* Graph GLRegion*: Utilize interleaved GLSL buffers for vertices, curveParams ↵Sven Gothel2023-04-203-104/+14
| | | | | | | | | | | and the optional colors (GPU effeciency and performance; Increased CPU buffer growth performance) Besides simplification, interleaved GPU memory boosts - effeciency - performance Since only one underlying backing buffer on the CPU (host) has to be managed, it also increases buffer growth performance.
* Graph VBORegion2P*.renderVBO(): Add comment on ↵Sven Gothel2023-04-192-0/+9
| | | | BITHINT_GLOBAL_DEPTH_TEST_ENABLED usage -> To be investigated.
* Graph GLRegion: Consolidate pass-1 common data (indices, vertices, ..) and ↵Sven Gothel2023-04-193-462/+2
| | | | all related methods. Add growCount stat.
* Graph + GraphUI: Consolidate Vertex: Drop SVertex and factory, use Vec[234]f ↵Sven Gothel2023-04-187-100/+111
| | | | | | | | | | | instead of float[] and remove unused VectorUtil methods After Matrix4f consolidation and proving same or better performance on non array types, this enhances code readability, simplifies API, reduces bugs and may improve performance. GraphUI: - Have RoundButton as a functional class to make a round or rectangular backdrop, i.e. impl. addShapeToRegion() via reused addRoundShapeToRegion()
* Matrix4f.mapWin*(): Drop unused temp matrices, map*() returns false on ↵Sven Gothel2023-04-092-6/+2
| | | | | | | | | | | | | | | | | | | | | | | | invPMv null; PMVMatrix: Make Mvi, Mvit optional at ctor, add user PMv and PMvi - used at gluUnProject() .. Matrix4f.mapWin*() variants w/ invPMv don't need temp matrices, they also shall handle null invPMv -> return false to streamline usage w/ PMVMatrix if inversion failed. PMVMatrix adds user space common premultiplies Pmv and Pmvi on demand like Frustum. These are commonly required for e.g. gluUnProject(..)/mapWinToObj(..) and might benefit from caching if stack is maintained and no modification occured. PMVMatrix now has the shader related Mvi and Mvit optional at construction(!), so its backing buffers. This reduces footprint for other use cases. The 2nd temp matrix is also on-demand, to reduce footprint for certain use cases. Removed public access to temporary storage. +++ While these additional matrices are on demand and/or at request @ ctor, general memory footprint is reduced per default and hence deemed acceptable while still having PMVMatrix acting as a core flexible matrix provider.
* VBORegion2P*ES2: Just instantiate SyncMatrices4f16 in place, drop local refSven Gothel2023-04-072-5/+2
|
* PMVMatrix rewrite using Matrix4f, providing SyncMatrix4f* for GLUniformData; ↵Sven Gothel2023-04-072-38/+33
| | | | | | | | | | | | | | | | | Utilize Vec3f, Recti, .. throughout API (Matrix4f, AABBox, .. Graph*) Big Easter Cleanup - Net -214 lines of code, despite new classes. - GLUniformData buffer can be synced w/ underlying data via SyncAction/SyncBuffer, e.g. SyncMatrix4f + SyncMatrices4f - PMVMatrix rewrite using Matrix4f and providing SyncMatrix4f/Matrices4f to sync w/ GLUniformData - Additional SyncMatrix4f16 + SyncMatrices4f16 covering Matrix4f sync w/ GLUniformData w/o PMVMatrix - Utilize Vec3f, Recti, .. throughout API (Matrix4f, AABBox, .. Graph*) - Moved FloatUtil -> Matrix4f, kept a few basic matrix ops for ProjectFloat - Most, if not all, float[] and int[] should have been moved to proper classes - int[] -> Recti for viewport rectangle - Matrix4f and PMVMatrix is covered by math unit tests (as was FloatUtil before) -> save Passed all unit tests on AMD64 GNU/Linux
* Graph Shader: Complete the USE_DISCARD logic avoiding output set after ↵Sven Gothel2023-03-3012-36/+67
| | | | discard, even though technically allowed (ignored after discard)
* Graph GLSL: Enable 'discard' in fragment shader w/o ↵Sven Gothel2023-03-3013-50/+53
| | | | | | | | | GLRendererQuirks.GLSLBuggyDiscard to avoid overdraw of such regions. Historically we disabled `discard` due to an old NV tegra2 compiler bug, which caused the compiler to freeze. Today we no more seem to have this GLSL compiler issue, i.e. GLRendererQuirks.GLSLBuggyDiscard never gets set.
* Graph: GLRegion: Pass curRenderModes to updateImpl() + drawImpl(), prepare ↵Sven Gothel2023-03-193-65/+100
| | | | switch by sampleCount; Don't use any resource not requested by curRenderModes
* Fix ShaderProgram ownership bug, introduced in commit ↵Sven Gothel2023-03-153-35/+9
| | | | | | | | | 67a723477ecd818fbc5859fe20ee536a3b4efae5 (reverting and clarifying) All Graph ShaderPrograms used are owned by RegionRenderer, not RenderState nor [GL]Region*, hence [GL]Region* shall only nullify the resources but not destroy the shader currently in use. One RegionRenderer maybe used for multuple Regions.
* Graph: Have RegionRenderer.reshapeNotify(..) track x/y as well (vieport); ↵Sven Gothel2023-03-141-3/+6
| | | | GraphUI.Scene using RegionRenderer's viewport (no duplicate)
* GLRegion + RegionRenderer: Add clearShader(..) to delete all ShaderPrograms ↵Sven Gothel2023-03-133-5/+32
| | | | and is references.
* Graph Perf: Region*: Add setBufferCapacity(..) and cut-off growBuffer() ↵Sven Gothel2023-03-073-123/+203
| | | | early if not needed (track capacity); Align all VBORegion* buffer init/set/grow impl.
* Graph Perf: Region: split addOutlineShape() -> addOutlineShape0() (fast) and ↵Sven Gothel2023-03-073-3/+3
| | | | addOutlineShape1() (slow perf+debug), rename growBufferSize() -> growBuffer()
* Graph Perf: Region*: Rely on growBuffer(..) per addOutlineShape() and known ↵Sven Gothel2023-03-073-50/+62
| | | | buffer data-type to directly put[34][sif](..) skipping GLArrayDataClient/Buffers buffer-growth and validations
* Graph: Region: Add perf counter (w/ API); Utilize put[34][sif](..); Fix ↵Sven Gothel2023-03-063-85/+169
| | | | | | | | | | | | | | | indices growBufferSize(); Add GLRegion.create(..) w/ initial vertices/indices count; Up default[VI]Count; Following heuristcs were found, hence we might want to calculate these for each font (TODO): /** * Heuristics with TestTextRendererNEWT00 text_1 + text_2 = 1334 chars * - FreeSans ~ vertices 64/char, indices 33/char * - Ubuntu Light ~ vertices 100/char, indices 50/char * - FreeSerif ~ vertices 115/char, indices 61/char * * Now let's assume a minimum of 10 chars will be rendered */