Skip to content

Commit 4c56f22

Browse files
committed
Font rendering now respects composition posteffects
1 parent d89ae32 commit 4c56f22

File tree

3 files changed

+94
-65
lines changed

3 files changed

+94
-65
lines changed

nimx/composition.nim

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -251,18 +251,20 @@ type
251251
source*: string
252252
setupProc*: proc(cc: CompiledComposition)
253253
mainProcName*: string
254+
seenFlag: bool # Used on compilation phase, should not be used elsewhere.
254255
id*: int
255256

256257
CompiledComposition = ref object
257258
program*: ProgramRef
258-
uniformLocations: seq[UniformLocation]
259+
uniformLocations*: seq[UniformLocation]
259260
iTexIndex*: GLint
260261
iUniform*: int
261262

262263
var programCache = initTable[Hash, CompiledComposition]()
263264

264265
type Composition* = object
265266
definition: string
267+
vsDefinition: string # Vertex shader source code
266268
requiresPrequel: bool
267269
id*: int
268270

@@ -311,19 +313,27 @@ proc newPostEffect*(definition: static[string], mainProcName: string): PostEffec
311313
result.mainProcName = mainProcName
312314
result.id = hash(preprocessedDefinition)
313315

314-
proc newComposition*(definition: static[string], requiresPrequel: bool = true): Composition =
315-
const preprocessedDefinition = preprocessDefinition(definition)
316+
proc newComposition*(vsDef, fsDef: static[string], requiresPrequel: bool = true): Composition =
317+
const preprocessedDefinition = preprocessDefinition(fsDef)
316318
result.definition = preprocessedDefinition
319+
result.vsDefinition = vsDef
317320
result.requiresPrequel = requiresPrequel
318321
result.id = hash(preprocessedDefinition)
319322

323+
template newComposition*(definition: static[string], requiresPrequel: bool = true): Composition =
324+
newComposition(nil, definition, requiresPrequel)
325+
320326
template newCompositionWithNimsl*(mainProc: typed): Composition =
321327
newComposition(getGLSLFragmentShader(mainProc, "compose"), false)
322328

323-
var postEffectStack = newSeq[PostEffect]()
329+
type PostEffectStackElem = object
330+
postEffect: PostEffect
331+
setupProc*: proc(cc: CompiledComposition)
332+
333+
var postEffectStack = newSeq[PostEffectStackElem]()
324334
var postEffectIdStack = newSeq[Hash]()
325335

326-
proc compileComposition*(gl: GL, comp: var Composition, cchash: Hash): CompiledComposition =
336+
proc compileComposition*(gl: GL, comp: Composition, cchash: Hash): CompiledComposition =
327337
var fragmentShaderCode = ""
328338
if comp.requiresPrequel:
329339
fragmentShaderCode = """
@@ -342,18 +352,29 @@ uniform vec4 bounds;
342352

343353
fragmentShaderCode &= comp.definition
344354

345-
for pe in postEffectStack:
346-
fragmentShaderCode &= pe.source
355+
let ln = postEffectStack.len
356+
var i = 0
357+
while i < ln:
358+
let pe = postEffectStack[i].postEffect
359+
if not pe.seenFlag:
360+
fragmentShaderCode &= pe.source
361+
pe.seenFlag = true
362+
inc i
363+
364+
i = 0
365+
while i < ln:
366+
postEffectStack[i].postEffect.seenFlag = false
367+
inc i
347368

348369
fragmentShaderCode &= """void main() { gl_FragColor = vec4(0.0); compose(); """
349-
var i = postEffectStack.len - 1
370+
i = postEffectStack.len - 1
350371
while i >= 0:
351-
fragmentShaderCode &= postEffectStack[i].mainProcName & "();"
372+
fragmentShaderCode &= postEffectStack[i].postEffect.mainProcName & "();"
352373
dec i
353374
fragmentShaderCode &= "}"
354375

355376
result.new()
356-
result.program = gl.newShaderProgram(vertexShaderCode, fragmentShaderCode, [(posAttr, "aPosition")])
377+
result.program = gl.newShaderProgram(if comp.vsDefinition.isNil: vertexShaderCode else: comp.vsDefinition, fragmentShaderCode, [(posAttr, "aPosition")])
357378
result.uniformLocations = newSeq[UniformLocation]()
358379
programCache[cchash] = result
359380

@@ -368,7 +389,7 @@ proc unwrapPointArray(a: openarray[Point]): seq[GLfloat] =
368389

369390
var texQuad : array[4, GLfloat]
370391

371-
template compositionDrawingDefinitions(cc: CompiledComposition, ctx: GraphicsContext, gl: GL) =
392+
template compositionDrawingDefinitions*(cc: CompiledComposition, ctx: GraphicsContext, gl: GL) =
372393
template uniformLocation(name: string): UniformLocation =
373394
inc cc.iUniform
374395
if cc.uniformLocations.len - 1 < cc.iUniform:
@@ -407,29 +428,38 @@ template compositionDrawingDefinitions(cc: CompiledComposition, ctx: GraphicsCon
407428
inc cc.iTexIndex
408429

409430
template pushPostEffect*(pe: PostEffect, body: untyped) =
410-
pe.setupProc = proc(cc: CompiledComposition) =
431+
postEffectStack.add(PostEffectStackElem(postEffect: pe, setupProc: proc(cc: CompiledComposition) =
411432
let ctx = currentContext()
412433
let gl = ctx.gl
413434
compositionDrawingDefinitions(cc, ctx, gl)
414435
body
436+
))
415437

416-
postEffectStack.add(pe)
417438
let oh = if postEffectIdStack.len > 0: postEffectIdStack[^1] else: 0
418439
postEffectIdStack.add(oh !& pe.id)
419440

420441
template popPostEffect*() =
421442
postEffectStack.setLen(postEffectStack.len - 1)
422443
postEffectIdStack.setLen(postEffectIdStack.len - 1)
423444

424-
template draw*(comp: var Composition, r: Rect, code: untyped): stmt =
425-
let ctx = currentContext()
426-
let gl = ctx.gl
445+
template getCompiledComposition*(gl: GL, comp: Composition): CompiledComposition =
427446
let pehash = if postEffectIdStack.len > 0: postEffectIdStack[^1] else: 0
428447
let cchash = !$(pehash !& comp.id)
429-
430448
var cc = programCache.getOrDefault(cchash)
431449
if cc.isNil:
432450
cc = gl.compileComposition(comp, cchash)
451+
cc.iUniform = -1
452+
cc.iTexIndex = 0
453+
cc
454+
455+
template setupPosteffectUniforms*(cc: CompiledComposition) =
456+
for pe in postEffectStack:
457+
pe.setupProc(cc)
458+
459+
template draw*(comp: var Composition, r: Rect, code: untyped): stmt =
460+
let ctx = currentContext()
461+
let gl = ctx.gl
462+
let cc = gl.getCompiledComposition(comp)
433463
gl.useProgram(cc.program)
434464
var points : array[8, GLfloat]
435465
points[0] = r.minX; points[1] = r.minY
@@ -440,17 +470,14 @@ template draw*(comp: var Composition, r: Rect, code: untyped): stmt =
440470
const componentCount : GLint = 2
441471
gl.enableVertexAttribArray(posAttr)
442472
gl.vertexAttribPointer(posAttr, componentCount, false, 0, points)
443-
cc.iUniform = -1
444-
cc.iTexIndex = 0
445473

446474
compositionDrawingDefinitions(cc, ctx, gl)
447475

448476
gl.uniformMatrix4fv(uniformLocation("uModelViewProjectionMatrix"), false, ctx.transform)
449477

450478
setUniform("bounds", r)
451479

452-
for pe in postEffectStack:
453-
pe.setupProc(cc)
480+
setupPosteffectUniforms(cc)
454481

455482
block:
456483
code

nimx/context.nim

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ type GraphicsContext* = ref object of RootObj
8484
fillColor*: Color
8585
strokeColor*: Color
8686
strokeWidth*: Coord
87-
fontShaderProgram: ProgramRef
8887
testPolyShaderProgram: ProgramRef
8988
debugClipColor: Color
9089
alpha*: Coord
@@ -134,7 +133,6 @@ proc newGraphicsContext*(canvas: ref RootObj = nil): GraphicsContext =
134133
when not defined(ios) and not defined(android) and not defined(js):
135134
loadExtensions()
136135

137-
result.fontShaderProgram = result.gl.newShaderProgram(fontVertexShader, fontFragmentShader)
138136
#result.testPolyShaderProgram = result.gl.newShaderProgram(testPolygonVertexShader, testPolygonFragmentShader)
139137
result.gl.clearColor(0.93, 0.93, 0.93, 0.0)
140138
result.alpha = 1.0
@@ -236,19 +234,57 @@ proc drawEllipseInRect*(c: GraphicsContext, r: Rect) =
236234
setUniform("uStrokeColor", if c.strokeWidth == 0: c.fillColor else: c.strokeColor)
237235
setUniform("uStrokeWidth", c.strokeWidth)
238236

237+
let fontComposition = newComposition("""
238+
attribute vec4 position;
239+
240+
uniform mat4 uModelViewProjectionMatrix;
241+
242+
varying vec2 vTexCoord;
243+
244+
void main() {
245+
vTexCoord = position.zw;
246+
gl_Position = uModelViewProjectionMatrix * vec4(position.xy, 0, 1);
247+
}
248+
""",
249+
"""
250+
#ifdef GL_ES
251+
#extension GL_OES_standard_derivatives : enable
252+
precision mediump float;
253+
#endif
254+
255+
uniform sampler2D texUnit;
256+
uniform vec4 fillColor;
257+
uniform float uGamma;
258+
uniform float uBase;
259+
260+
varying vec2 vTexCoord;
261+
262+
void compose() {
263+
float dist = texture2D(texUnit, vTexCoord).a;
264+
float alpha = smoothstep(uBase - uGamma, uBase + uGamma, dist);
265+
gl_FragColor = vec4(fillColor.rgb, alpha * fillColor.a);
266+
}
267+
""", false)
268+
239269
proc drawText*(c: GraphicsContext, font: Font, pt: var Point, text: string) =
240270
# assume orthographic projection with units = screen pixels, origin at top left
241271
let gl = c.gl
242-
gl.useProgram(c.fontShaderProgram)
243-
c.setFillColorUniform(c.fontShaderProgram)
244-
gl.activeTexture(gl.TEXTURE0)
272+
let cc = gl.getCompiledComposition(fontComposition)
273+
gl.useProgram(cc.program)
274+
275+
compositionDrawingDefinitions(cc, c, gl)
276+
setUniform("fillColor", c.fillColor)
277+
setUniform("uGamma", font.gamma.GLfloat)
278+
setUniform("uBase", font.base.GLfloat)
279+
gl.uniformMatrix4fv(uniformLocation("uModelViewProjectionMatrix"), false, c.transform)
280+
setupPosteffectUniforms(cc)
281+
282+
gl.activeTexture(gl.TEXTURE0 + cc.iTexIndex.GLenum)
283+
gl.uniform1i(uniformLocation("texUnit"), cc.iTexIndex)
245284

246285
gl.enableVertexAttribArray(saPosition.GLuint)
247-
c.setTransformUniform(c.fontShaderProgram)
248-
gl.uniform1f(gl.getUniformLocation(c.fontShaderProgram, "uGamma"), font.gamma.GLfloat)
249-
gl.uniform1f(gl.getUniformLocation(c.fontShaderProgram, "uBase"), font.base.GLfloat)
250-
gl.enable(gl.BLEND)
251-
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
286+
# gl.enable(gl.BLEND)
287+
# gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
252288

253289
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, c.quadIndexBuffer)
254290

nimx/shaders.nim

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,4 @@
11

2-
3-
const fontVertexShader = """
4-
attribute vec4 position;
5-
6-
uniform mat4 modelViewProjectionMatrix;
7-
8-
varying vec2 vTexCoord;
9-
10-
void main() {
11-
vTexCoord = position.zw;
12-
gl_Position = modelViewProjectionMatrix * vec4(position.xy, 0, 1);
13-
}
14-
"""
15-
16-
const fontFragmentShader = """
17-
#ifdef GL_ES
18-
#extension GL_OES_standard_derivatives : enable
19-
precision mediump float;
20-
#endif
21-
22-
uniform sampler2D texUnit;
23-
uniform vec4 fillColor;
24-
uniform float uGamma;
25-
uniform float uBase;
26-
27-
varying vec2 vTexCoord;
28-
29-
void main() {
30-
float dist = texture2D(texUnit, vTexCoord).a;
31-
float alpha = smoothstep(uBase - uGamma, uBase + uGamma, dist);
32-
gl_FragColor = vec4(fillColor.rgb, alpha * fillColor.a);
33-
}
34-
"""
35-
362
# this is a fragment shader, using distance function in polygon.
373
# TODO: research later
384
discard """

0 commit comments

Comments
 (0)