1
0
mirror of https://github.com/lxsang/Diya-API.git synced 2025-02-20 18:12:48 +01:00

FreeType face now is cached as bitmap font

This commit is contained in:
Dany LE 2022-03-06 00:58:28 +01:00
parent 7fa21d524b
commit b8897a6351
9 changed files with 177 additions and 70 deletions

View File

@ -27,6 +27,12 @@ DiyaBoot class >> startx [
self uniqueInstance run
]
{ #category : #events }
DiyaBoot >> GLinit. [
OpenGL viewportX: 0 Y:0 W: display w H: display h.
OpenGL enable: GL_TEXTURE_2D.
]
{ #category : #events }
DiyaBoot >> createGLContext [
context := SDL2 glCreateContext: window.
@ -107,9 +113,10 @@ DiyaBoot >> render [
rec := root addNode: (DiyaRectangle size: 50@50 shader: GLSimpleShader uniqueInstance) at: 250 @ 500.
rec rotation: (Float pi / -8.0).
rec scale: 1.5@1.5.
text := root addNode: (DiyaText data: String loremIpsum shader: TotoShader uniqueInstance) at: 20@320.
text := root addNode: (DiyaText data: String loremIpsum shader: TotoShader uniqueInstance) at: 20@320.
text extent: 200@320.
"text rotation:(Float pi / 4.0)."
self GLinit.
OpenGL viewportX: 0 Y:0 W: display w H: display h.
"TODO: maybe give node to customize this"
[ running ] whileTrue: [
@ -118,7 +125,6 @@ DiyaBoot >> render [
].
DiyaRenderer uniqueInstance render.
SDL2 glSwapWindow: window.
"SDL2 delay: 50. "
].
]

View File

@ -2,9 +2,9 @@ Class {
#name : #DiyaFontStyle,
#superclass : #DiyaBaseObject,
#instVars : [
'texmap',
'face',
'name',
'charmap'
'name'
],
#category : #'Diya-Fonts'
}
@ -21,27 +21,13 @@ DiyaFontStyle >> face [
{ #category : #accessing }
DiyaFontStyle >> face: anObject [
face := anObject.
name := anObject styleName
face := anObject
]
{ #category : #initialization }
DiyaFontStyle >> initialize [
super initialize.
charmap := Dictionary new.
]
{ #category : #initialization }
DiyaFontStyle >> loadChar: charCode size: size [
|tex dic|
"lookup in the char map"
dic := charmap at: charCode ifAbsentPut: Dictionary new.
tex := dic at: size ifAbsentPut: [
face setPixelWidth:0 height: size.
face loadCharacter: charCode flags: (1 << 2).
OpenGLFontTex fromFace: face
].
^tex
texmap := Dictionary new.
]
{ #category : #accessing }
@ -53,3 +39,18 @@ DiyaFontStyle >> name [
DiyaFontStyle >> name: anObject [
name := anObject
]
{ #category : #accessing }
DiyaFontStyle >> texmap [
^ texmap
]
{ #category : #initialization }
DiyaFontStyle >> textureOf: size [
|tex|
tex := texmap at: size ifAbsentPut: [
""
OpenGLFontTex fromFace: face ofSize: size
].
^tex
]

View File

@ -14,16 +14,15 @@ DiyaRectangle >> draw [
} doWithIndex: [:e :i| context buffer at: i put: e].
shader use.
shader setUniform: #u_time value: DiyaClock uniqueInstance elapsedTime asFloat.
shader setUniform: #u_transform value: {GL_TRUE. self tf asGLBuffer}.
shader setUniform: #u_projection value: {GL_FALSE. context projection buffer}.
shader setUniform: #u_resolution value: { context resolution x. context resolution y }.
shader setUniform: #u_transform value: {GL_TRUE. self tf asGLBuffer}.
context mouse ifNotNil: [
"in shader, window origin is bottom left conor of the window
the mouse position should be transformed to this coodinate"
shader setUniform: #u_mouse value: { context mouse x. context resolution y - context mouse y }.
].
context vao enableAttribute: 0.
context vbo bind: GL_ARRAY_BUFFER.
OpenGLVertexArray vertexAttributePointerIndex: 0 size:3 type: GL_FLOAT normalized: GL_FALSE stride: 0 pointer: nil.
context vbo subData: GL_ARRAY_BUFFER offset:0 data: context buffer.
OpenGL drawArrays: GL_QUADS first:0 count: 4.

View File

@ -8,6 +8,7 @@ Class {
DiyaRootNode >> draw [
OpenGL clearColorR: 1.0 G: 0.0 B: 1.0 A:0.
OpenGL clear: GL_COLOR_BUFFER_BIT.
context vbo bind: GL_ARRAY_BUFFER.
]
{ #category : #initialization }

View File

@ -36,12 +36,11 @@ DiyaText >> data: anObject [
{ #category : #accessing }
DiyaText >> draw [
| offset|
| offset tex2D|
data ifNil: [ ^self ].
offset := 0.0@0.0.
OpenGL enable: GL_CULL_FACE.
OpenGL enable: GL_BLEND.
OpenGL enable: GL_TEXTURE_2D.
OpenGL blendFnWithSfactor: GL_SRC_ALPHA dfactor: GL_ONE_MINUS_SRC_ALPHA.
self shader use.
shader setUniform: #u_time value: DiyaClock uniqueInstance elapsedTime asFloat.
@ -53,9 +52,15 @@ DiyaText >> draw [
OpenGL pixelstorei: GL_UNPACK_ALIGNMENT param: 1.
"configure vao vbo for texture QUAD"
context texture0 active.
tex2D := style textureOf: self fontSize.
context texture0 setImage2D: tex2D.
OpenGLTexture parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_WRAP_S param: GL_CLAMP_TO_EDGE.
OpenGLTexture parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_WRAP_T param: GL_CLAMP_TO_EDGE.
OpenGLTexture parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_MIN_FILTER param: GL_LINEAR.
OpenGLTexture parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_MAG_FILTER param: GL_LINEAR.
context vao enableAttribute: 0.
OpenGLVertexArray vertexAttributePointerIndex: 0 size:4 type: GL_FLOAT normalized: GL_FALSE stride: 16 pointer: nil .
data do:[:c | self drawCharacter: c at: offset].
data do:[:c | self drawCharacter: c asciiValue at: offset withTexture:tex2D. ].
context vao disableAttribute: 0.
"reset value"
OpenGL pixelstorei: GL_UNPACK_ALIGNMENT param: 4.
@ -65,36 +70,56 @@ DiyaText >> draw [
]
{ #category : #accessing }
DiyaText >> drawCharacter: c at: offset [
|tex2D|
tex2D := style loadChar: c asciiValue size: self fontSize.
context texture0 setImage2D: tex2D.
OpenGLTexture parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_WRAP_S param: GL_CLAMP_TO_EDGE.
OpenGLTexture parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_WRAP_T param: GL_CLAMP_TO_EDGE.
OpenGLTexture parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_MIN_FILTER param: GL_LINEAR.
OpenGLTexture parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_MAG_FILTER param: GL_LINEAR.
"fill the buffer"
((offset x > extent x) and: (tex2D width > 0)) ifTrue:[
DiyaText >> drawCharacter: c at: offset withTexture: tex2D [
|x y w h charsize texcoord|
c = (Character space asciiValue) ifTrue:[
^offset setX: (offset x + ((tex2D spacing )* (self scale x)) ) setY: offset y.
].
charsize := tex2D charSize: c.
((offset x > extent x) and: (charsize x > 0)) ifTrue:[
offset setX: 0.0 setY: (offset y )- (tex2D linespace * (self scale y)).].
self fillVerticesBuffer: context buffer at: offset tex: tex2D.
charsize := tex2D charSize: c.
texcoord := tex2D texCoordOf: c.
x := offset x "+ ((tex bearing x )*(self scale x))".
y := offset y - ((tex2D cellh) * (self scale y)) "(((tex height) - (tex bearing y))*(self scale y))".
w := (charsize x)*(self scale x).
h := (charsize y)*(self scale y).
{x. y + h. texcoord origin x. texcoord origin y.
x. y. texcoord origin x. texcoord corner y.
x + w. y. texcoord corner x. texcoord corner y.
x. y + h. texcoord origin x. texcoord origin y.
x + w. y. texcoord corner x. texcoord corner y.
x + w. y + h. texcoord corner x. texcoord origin y. } withIndexDo: [ :e :i| context buffer at:i put: e ].
context vbo subData: GL_ARRAY_BUFFER offset: 0 data: context buffer.
OpenGL drawArrays: GL_TRIANGLES first:0 count:6.
offset setX: (offset x + ((tex2D advance x )* (self scale x)) ) setY: offset y.
offset setX: (offset x + ((charsize x )* (self scale x)) ) setY: offset y.
]
{ #category : #accessing }
DiyaText >> fillVerticesBuffer: buffer at: offset tex: tex [
|x y w h|
x := offset x + ((tex bearing x )*(self scale x)).
"x := offset x + ((tex bearing x )*(self scale x)).
y := offset y - (((tex height) - (tex bearing y))*(self scale y)).
w := (tex width)*(self scale x).
h := (tex height)*(self scale y).
h := (tex height)*(self scale y)."
x := 0.
y := 0.
w := tex width.
h := tex height.
{x. y + h. 0.0. 0.0.
x. y. 0.0. 1.0.
x + w. y. 1.0. 1.0.
x. y + h. 0.0. 0.0.
x + w. y. 1.0. 1.0.
x + w. y + h. 1.0. 0.0. } withIndexDo: [ :e :i| buffer at:i put: e ]
"{x. y + h. 0.0. 0.0.
x. y. 0.0. 1.0.
x + w. y. 1.0. 1.0.
x. y + h. 0.0. 0.0.
x + w. y. 1.0. 1.0.
x + w. y + h. 1.0. 0.0. }"
]
{ #category : #accessing }

12
Diya/LibC.extension.st Normal file
View File

@ -0,0 +1,12 @@
Extension { #name : #LibC }
{ #category : #'*Diya' }
LibC >> memset:pointer value: value size: size [
^self ffiCall: #(void *memset(void *pointer, int value, size_t size))
]
{ #category : #'*Diya' }
LibC class >> memset:pointer value: value size: size [
^self uniqueInstance memset: pointer value: value size: size
]

View File

@ -2,9 +2,9 @@ Class {
#name : #OpenGLFontTex,
#superclass : #OpenGLTexImage2D,
#instVars : [
'bearing',
'advance',
'linespace'
'charmap',
'cellw',
'cellh'
],
#pools : [
'OpenGLConstants',
@ -14,58 +14,117 @@ Class {
}
{ #category : #'instance creation' }
OpenGLFontTex class >> fromFace: face [
^self new fromFace: face; yourself
OpenGLFontTex class >> fromFace: face ofSize: size [
^self new fromFace: face ofSize: size; yourself
]
{ #category : #'instance creation' }
OpenGLFontTex >> blitPixel8: bitmap at: offset size: size [
size = (0@0) ifTrue:[^self].
0 to: size y - 1 do: [ :i|
LibC memCopy: (bitmap getHandle + (i* (size x))) to:(data getHandle + ((i + offset y) * width + (offset x) )) size: size x
]
]
{ #category : #accessing }
OpenGLFontTex >> advance [
^ advance
OpenGLFontTex >> cellh [
^ cellh
]
{ #category : #accessing }
OpenGLFontTex >> advance: anObject [
advance := anObject
OpenGLFontTex >> cellw [
^ cellw
]
{ #category : #accessing }
OpenGLFontTex >> bearing [
^ bearing
OpenGLFontTex >> charSize: c [
^(self charmap at: c + 1) extent
]
{ #category : #accessing }
OpenGLFontTex >> bearing: anObject [
bearing := anObject
OpenGLFontTex >> charmap [
^ charmap
]
{ #category : #accessing }
OpenGLFontTex >> fromFace: aFTFace [
|size glyph rec|
glyph := aFTFace glyph.
size := glyph width * glyph height.
data := FFIExternalArray externalNewType: #uint8 size:size.
rec := (FTFaceRec fromHandle: aFTFace getHandle).
{ #category : #'instance creation' }
OpenGLFontTex >> createBitmapFontFrom: bitmaps metrics: metrics maxBearing: maxbearing [
|currChar offset|
data ifNotNil: [data free ].
charmap := OrderedCollection new.
data := FFIExternalArray externalNewType: GLubyte size:cellw * cellh * 256.
LibC memset: data getHandle value: 0 size: data size.
data autoRelease.
LibC memCopy: (rec glyph bitmap buffer) to:data getHandle size: size.
currChar := 1.
offset := 0@0.
width := cellw * 16.
height := cellh * 16.
"linespace := (rec size metrics height / 64) asInteger."
0 to: 15 do: [ :row|
0 to: 15 do: [ :col|
offset := (col * cellw) @ (row*cellh).
charmap add: (Rectangle origin: offset extent: (((metrics at: currChar) first x) @ cellh)).
self blitPixel8: (bitmaps at: currChar) at: (offset x) @ ((offset y) + maxbearing - ((metrics at: currChar) last) ) size: (metrics at: currChar) first.
currChar := currChar + 1.
]
].
]
{ #category : #'instance creation' }
OpenGLFontTex >> fromFace: face ofSize: size [
|minhang maxbearing rec metrics bitmaps |
face setPixelWidth:0 height: size.
"set up a buffer for 256 characters"
bitmaps := OrderedCollection new.
metrics := OrderedCollection new.
cellw := 0.
cellh := 0.
minhang := 0.
maxbearing := 0.
rec := (FTFaceRec fromHandle: face getHandle).
0 to: 255 do: [ :c |
|bmp bmpsize|
face loadCharacter: c flags: (1 << 2).
metrics add: { ((rec glyph metrics width) /64)@ ((rec glyph metrics height) /64). (rec glyph metrics horiBearingY) / 64}.
maxbearing := maxbearing max: ((rec glyph metrics horiBearingY) / 64).
cellw := cellw max: ((rec glyph metrics width) / 64).
minhang := minhang min: ((( rec glyph metrics horiBearingY) - (rec glyph metrics height )) / 64).
"copy buffer"
bmpsize := (rec glyph bitmap width)*(rec glyph bitmap rows).
bmp := FFIExternalArray externalNewType: GLubyte size:bmpsize.
LibC memCopy: rec glyph bitmap buffer to: bmp getHandle size: bmpsize.
bitmaps add: bmp.
].
cellh := maxbearing - minhang.
self createBitmapFontFrom: bitmaps metrics: metrics maxBearing: maxbearing.
bitmaps do:[:p| p free].
]
{ #category : #initialization }
OpenGLFontTex >> initialize [
super initialize.
charmap := OrderedCollection new.
data := nil.
level := 0.
internalFormat := GL_ALPHA.
width := glyph width.
height := glyph height.
linespace := (rec size metrics height / 64) asInteger.
border := 0.
format := GL_ALPHA.
internalFormat := GL_ALPHA.
type := GL_UNSIGNED_BYTE.
target := GL_TEXTURE_2D.
bearing := (glyph hBearingX )@ (glyph hBearingY).
advance := (glyph advanceX )@ (glyph advanceY).
]
{ #category : #accessing }
OpenGLFontTex >> linespace [
^ linespace
^ cellh
]
{ #category : #accessing }
OpenGLFontTex >> linespace: anObject [
linespace := anObject
OpenGLFontTex >> spacing [
^ cellw / 2
]
{ #category : #accessing }
OpenGLFontTex >> texCoordOf: c [
|rec|
rec := self charmap at: c + 1.
^ Rectangle origin: ((rec origin )/ (self extent) ) asFloatPoint corner: ((rec corner) / (self extent)) asFloatPoint
]

View File

@ -52,6 +52,11 @@ OpenGLTexImage2D >> debug [
stdlog: 'internalformat :',internalFormat hex
]
{ #category : #accessing }
OpenGLTexImage2D >> extent [
^ width @ height
]
{ #category : #accessing }
OpenGLTexImage2D >> format [
^ format

View File

@ -76,7 +76,6 @@ OpenGLTexture >> bind: target [
{ #category : #initialization }
OpenGLTexture >> delete [
self class delete: 1 pointer: textureID getHandle.
textureID free.
]
{ #category : #initialization }