1
0
mirror of https://github.com/lxsang/Diya-API.git synced 2025-02-21 18:32:47 +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 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 } { #category : #events }
DiyaBoot >> createGLContext [ DiyaBoot >> createGLContext [
context := SDL2 glCreateContext: window. context := SDL2 glCreateContext: window.
@ -107,9 +113,10 @@ DiyaBoot >> render [
rec := root addNode: (DiyaRectangle size: 50@50 shader: GLSimpleShader uniqueInstance) at: 250 @ 500. rec := root addNode: (DiyaRectangle size: 50@50 shader: GLSimpleShader uniqueInstance) at: 250 @ 500.
rec rotation: (Float pi / -8.0). rec rotation: (Float pi / -8.0).
rec scale: 1.5@1.5. 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 extent: 200@320.
"text rotation:(Float pi / 4.0)." "text rotation:(Float pi / 4.0)."
self GLinit.
OpenGL viewportX: 0 Y:0 W: display w H: display h. OpenGL viewportX: 0 Y:0 W: display w H: display h.
"TODO: maybe give node to customize this" "TODO: maybe give node to customize this"
[ running ] whileTrue: [ [ running ] whileTrue: [
@ -118,7 +125,6 @@ DiyaBoot >> render [
]. ].
DiyaRenderer uniqueInstance render. DiyaRenderer uniqueInstance render.
SDL2 glSwapWindow: window. SDL2 glSwapWindow: window.
"SDL2 delay: 50. "
]. ].
] ]

View File

@ -2,9 +2,9 @@ Class {
#name : #DiyaFontStyle, #name : #DiyaFontStyle,
#superclass : #DiyaBaseObject, #superclass : #DiyaBaseObject,
#instVars : [ #instVars : [
'texmap',
'face', 'face',
'name', 'name'
'charmap'
], ],
#category : #'Diya-Fonts' #category : #'Diya-Fonts'
} }
@ -21,27 +21,13 @@ DiyaFontStyle >> face [
{ #category : #accessing } { #category : #accessing }
DiyaFontStyle >> face: anObject [ DiyaFontStyle >> face: anObject [
face := anObject. face := anObject
name := anObject styleName
] ]
{ #category : #initialization } { #category : #initialization }
DiyaFontStyle >> initialize [ DiyaFontStyle >> initialize [
super initialize. super initialize.
charmap := Dictionary new. texmap := 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
] ]
{ #category : #accessing } { #category : #accessing }
@ -53,3 +39,18 @@ DiyaFontStyle >> name [
DiyaFontStyle >> name: anObject [ DiyaFontStyle >> name: anObject [
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]. } doWithIndex: [:e :i| context buffer at: i put: e].
shader use. shader use.
shader setUniform: #u_time value: DiyaClock uniqueInstance elapsedTime asFloat. 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_projection value: {GL_FALSE. context projection buffer}.
shader setUniform: #u_resolution value: { context resolution x. context resolution y }. shader setUniform: #u_resolution value: { context resolution x. context resolution y }.
shader setUniform: #u_transform value: {GL_TRUE. self tf asGLBuffer}.
context mouse ifNotNil: [ context mouse ifNotNil: [
"in shader, window origin is bottom left conor of the window "in shader, window origin is bottom left conor of the window
the mouse position should be transformed to this coodinate" the mouse position should be transformed to this coodinate"
shader setUniform: #u_mouse value: { context mouse x. context resolution y - context mouse y }. shader setUniform: #u_mouse value: { context mouse x. context resolution y - context mouse y }.
]. ].
context vao enableAttribute: 0. 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. 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. context vbo subData: GL_ARRAY_BUFFER offset:0 data: context buffer.
OpenGL drawArrays: GL_QUADS first:0 count: 4. OpenGL drawArrays: GL_QUADS first:0 count: 4.

View File

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

View File

@ -36,12 +36,11 @@ DiyaText >> data: anObject [
{ #category : #accessing } { #category : #accessing }
DiyaText >> draw [ DiyaText >> draw [
| offset| | offset tex2D|
data ifNil: [ ^self ]. data ifNil: [ ^self ].
offset := 0.0@0.0. offset := 0.0@0.0.
OpenGL enable: GL_CULL_FACE. OpenGL enable: GL_CULL_FACE.
OpenGL enable: GL_BLEND. OpenGL enable: GL_BLEND.
OpenGL enable: GL_TEXTURE_2D.
OpenGL blendFnWithSfactor: GL_SRC_ALPHA dfactor: GL_ONE_MINUS_SRC_ALPHA. OpenGL blendFnWithSfactor: GL_SRC_ALPHA dfactor: GL_ONE_MINUS_SRC_ALPHA.
self shader use. self shader use.
shader setUniform: #u_time value: DiyaClock uniqueInstance elapsedTime asFloat. shader setUniform: #u_time value: DiyaClock uniqueInstance elapsedTime asFloat.
@ -53,9 +52,15 @@ DiyaText >> draw [
OpenGL pixelstorei: GL_UNPACK_ALIGNMENT param: 1. OpenGL pixelstorei: GL_UNPACK_ALIGNMENT param: 1.
"configure vao vbo for texture QUAD" "configure vao vbo for texture QUAD"
context texture0 active. 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. context vao enableAttribute: 0.
OpenGLVertexArray vertexAttributePointerIndex: 0 size:4 type: GL_FLOAT normalized: GL_FALSE stride: 16 pointer: nil . 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. context vao disableAttribute: 0.
"reset value" "reset value"
OpenGL pixelstorei: GL_UNPACK_ALIGNMENT param: 4. OpenGL pixelstorei: GL_UNPACK_ALIGNMENT param: 4.
@ -65,36 +70,56 @@ DiyaText >> draw [
] ]
{ #category : #accessing } { #category : #accessing }
DiyaText >> drawCharacter: c at: offset [ DiyaText >> drawCharacter: c at: offset withTexture: tex2D [
|tex2D| |x y w h charsize texcoord|
tex2D := style loadChar: c asciiValue size: self fontSize. c = (Character space asciiValue) ifTrue:[
context texture0 setImage2D: tex2D. ^offset setX: (offset x + ((tex2D spacing )* (self scale x)) ) setY: offset y.
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. charsize := tex2D charSize: c.
OpenGLTexture parameteri: GL_TEXTURE_2D pname: GL_TEXTURE_MIN_FILTER param: GL_LINEAR. ((offset x > extent x) and: (charsize x > 0)) ifTrue:[
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:[
offset setX: 0.0 setY: (offset y )- (tex2D linespace * (self scale y)).]. 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. context vbo subData: GL_ARRAY_BUFFER offset: 0 data: context buffer.
OpenGL drawArrays: GL_TRIANGLES first:0 count:6. 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 } { #category : #accessing }
DiyaText >> fillVerticesBuffer: buffer at: offset tex: tex [ DiyaText >> fillVerticesBuffer: buffer at: offset tex: tex [
|x y w h| |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)). y := offset y - (((tex height) - (tex bearing y))*(self scale y)).
w := (tex width)*(self scale x). 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 + h. 0.0. 0.0.
x. y. 0.0. 1.0. x. y. 0.0. 1.0.
x + w. y. 1.0. 1.0. x + w. y. 1.0. 1.0.
x. y + h. 0.0. 0.0. x. y + h. 0.0. 0.0.
x + w. y. 1.0. 1.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 + 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 } { #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, #name : #OpenGLFontTex,
#superclass : #OpenGLTexImage2D, #superclass : #OpenGLTexImage2D,
#instVars : [ #instVars : [
'bearing', 'charmap',
'advance', 'cellw',
'linespace' 'cellh'
], ],
#pools : [ #pools : [
'OpenGLConstants', 'OpenGLConstants',
@ -14,58 +14,117 @@ Class {
} }
{ #category : #'instance creation' } { #category : #'instance creation' }
OpenGLFontTex class >> fromFace: face [ OpenGLFontTex class >> fromFace: face ofSize: size [
^self new fromFace: face; yourself ^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 } { #category : #accessing }
OpenGLFontTex >> advance [ OpenGLFontTex >> cellh [
^ advance ^ cellh
] ]
{ #category : #accessing } { #category : #accessing }
OpenGLFontTex >> advance: anObject [ OpenGLFontTex >> cellw [
advance := anObject ^ cellw
] ]
{ #category : #accessing } { #category : #accessing }
OpenGLFontTex >> bearing [ OpenGLFontTex >> charSize: c [
^ bearing ^(self charmap at: c + 1) extent
] ]
{ #category : #accessing } { #category : #accessing }
OpenGLFontTex >> bearing: anObject [ OpenGLFontTex >> charmap [
bearing := anObject ^ charmap
] ]
{ #category : #accessing } { #category : #'instance creation' }
OpenGLFontTex >> fromFace: aFTFace [ OpenGLFontTex >> createBitmapFontFrom: bitmaps metrics: metrics maxBearing: maxbearing [
|size glyph rec| |currChar offset|
glyph := aFTFace glyph. data ifNotNil: [data free ].
size := glyph width * glyph height. charmap := OrderedCollection new.
data := FFIExternalArray externalNewType: #uint8 size:size. data := FFIExternalArray externalNewType: GLubyte size:cellw * cellh * 256.
rec := (FTFaceRec fromHandle: aFTFace getHandle). LibC memset: data getHandle value: 0 size: data size.
data autoRelease. 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. level := 0.
internalFormat := GL_ALPHA.
width := glyph width.
height := glyph height.
linespace := (rec size metrics height / 64) asInteger.
border := 0. border := 0.
format := GL_ALPHA. format := GL_ALPHA.
internalFormat := GL_ALPHA.
type := GL_UNSIGNED_BYTE. type := GL_UNSIGNED_BYTE.
target := GL_TEXTURE_2D. target := GL_TEXTURE_2D.
bearing := (glyph hBearingX )@ (glyph hBearingY).
advance := (glyph advanceX )@ (glyph advanceY).
] ]
{ #category : #accessing } { #category : #accessing }
OpenGLFontTex >> linespace [ OpenGLFontTex >> linespace [
^ linespace ^ cellh
] ]
{ #category : #accessing } { #category : #accessing }
OpenGLFontTex >> linespace: anObject [ OpenGLFontTex >> spacing [
linespace := anObject ^ 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 stdlog: 'internalformat :',internalFormat hex
] ]
{ #category : #accessing }
OpenGLTexImage2D >> extent [
^ width @ height
]
{ #category : #accessing } { #category : #accessing }
OpenGLTexImage2D >> format [ OpenGLTexImage2D >> format [
^ format ^ format

View File

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