Bon c'est vraiment long, mais voila un petit aperçu de ce que je voulais faire à la base.
- découpage des mots lorsqu'ils sont trop grand (mettre un tiret etc..) entre les syllabes
- un bug lors de la présence d'un contour, qui fait que le texte n'est pas dessiné avec la bonne couleur, mais en composition avec la couleur du contour...
- diverses artéfact sur le tour du contour qui restent à corriger.
- Bug bizarre très rare qui fait qu'une seule ligne (de pixel) sur 2 est dessinée.. (vraiment chelou celui-la)
Code : Tout sélectionner
DisableDebugger
;{ MODULE Font
;{ Font Style
CompilerIf #PB_Compiler_OS <> #PB_OS_Windows
#BF_Font_Normal = 0
#BF_Font_Italic = 2
#BF_Font_Bold = 1
#BF_Font_BoldItalic = 3
CompilerEndIf
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
#BF_Font_Normal = 0
#BF_Font_Italic = 512
#BF_Font_Bold = 256
#BF_Font_BoldItalic = 768
CompilerEndIf
;}
Structure IBF_Glyphe
*Adresse_Font.IBF_Font
char.s{1}
Array Image.a(0, 0)
Largeur.w
Hauteur.w
EndStructure
Structure IBF_Font
FontId.i
Font.l
; Distance entre le bas du caractère "a" dans la police et le haut d'un glyphe dans cette police.
; Sert à écrire toutes les tailles de police sur la même ligne (hypothétiquement !!!)
BaseLine.l
FontKey.s
Size.w
Style.l
Map *Glyphe.IBF_Glyphe()
EndStructure
Structure IBF_RGBA
r.a
g.a
b.a
a.a
EndStructure
Structure IBF_Char
*Glyphe.IBF_Glyphe
StructureUnion
couleur.l
RGBA.IBF_RGBA
EndStructureUnion
EndStructure
Structure IBF_Text
List Text.IBF_Char()
EndStructure
Structure IBF_Var_Global
Map Font.IBF_Font()
Map Glyphe.IBF_Glyphe()
ImageTestTextSize.l
EndStructure
;{ VAR Global
Global IBF_Global.IBF_Var_Global
InitializeStructure(@IBF_Global, IBF_Var_Global)
IBF_Global\ImageTestTextSize = CreateImage(#PB_Any, 1, 1)
;}
Procedure IBF_GetGrayArray(Array image.l(2), Array image_gray.a(2))
Protected *adr.IBF_RGBA
w = ArraySize(image(), 1)
h = ArraySize(image(), 2)
Dim image_gray(w, h)
For x = 0 To w
For y = 0 To h
*adr = @image(x, y)
tmp.d = *adr\r + *adr\g + *adr\b
If tmp > 255 : tmp = 255 : EndIf
image_gray(x, y) = tmp * (*adr\a / 255)
Next
Next
EndProcedure
Procedure IBF_GetEdgeGray(Array image.a(2), rayon = 1)
w = ArraySize(image(), 1) - 1
h = ArraySize(image(), 2) - 1
Dim image_save.a(w + 1, h + 1)
Dim image_tab.a(w + 1, h + 1)
Dim image_tab2.a(w + 1, h + 1)
Dim *adr.POINT(w + 1, h + 1)
CopyArray(image(), image_tab2())
NewList coord.POINT()
NewList new_coord.POINT()
Macro AjoutPoint(_x_, _y_)
If *adr(_x_, _y_) = 0 And image_tab(_x_, _y_) = 0 And _x_ < w + 1 And _y_ < h + 1 And _x_ > 0 And _y_ > 0
AddElement(new_coord())
*adr(_x_, _y_) = @new_coord()
new_coord()\x = _x_
new_coord()\y = _y_
EndIf
EndMacro
CopyArray(image(), image_tab())
;{ init
For x = 1 To w
For y = 1 To h
If image_tab(x, y) < 255
deltaX_.l = (image_tab(x + 1, y - 1) + image_tab(x + 1, y) << 1 + image_tab(x + 1, y + 1)) - (image_tab(x - 1, y - 1) + image_tab(x - 1, y) << 1 + image_tab(x - 1, y + 1))
deltaY_.l = (image_tab(x - 1, y - 1) + image_tab(x, y - 1) << 1 + image_tab(x + 1, y - 1) ) - (image_tab(x - 1, y + 1) + image_tab(x, y + 1) << 1 + image_tab(x + 1, y + 1))
deltaX.d = deltaX_ / 3
deltaY.d = deltaY_ / 3
gray.l = Sqr(deltaX * deltaX + deltaY * deltaY)
If gray > 0 Or image_tab(x, y) > 0
If image_tab(x, y) > 0
gray = 255 - image_tab(x, y)
ElseIf gray > 255
gray = 255
EndIf
image_tab2(x, y) = gray
;{ ajout des points futurs
If *adr(x, y) <> 0
ChangeCurrentElement(new_coord(), *adr(x, y))
DeleteElement(new_coord())
*adr(x, y) = -1
EndIf
AjoutPoint(x+1, y)
AjoutPoint(x, y+1)
AjoutPoint(x-1, y)
AjoutPoint(x, y-1)
AjoutPoint(x+1, y+1)
AjoutPoint(x+1, y-1)
AjoutPoint(x-1, y+1)
AjoutPoint(x-1, y-1)
;}
If rayon > 1
image_save(x, y) = 255-image_tab(x, y)
Else
image_save(x, y) = gray
EndIf
;Plot(x, y, RGB(image_save(x, y), image_save(x, y), image_save(x, y)))
EndIf
EndIf
Next
Next
;}
;{ boucle normale
For i = 2 To rayon
CopyList(new_coord(), coord())
CopyArray(image_tab2(), image_tab())
Dim *adr.POINT(w + 1, h + 1)
ClearList(new_coord())
ForEach coord()
x = coord()\x
y = coord()\y
If image_save(x, y) < 255
deltaX_.l = (image_tab(x + 1, y - 1) + image_tab(x + 1, y) << 1 + image_tab(x + 1, y + 1)) - (image_tab(x - 1, y - 1) + image_tab(x - 1, y) << 1 + image_tab(x - 1, y + 1))
deltaY_.l = (image_tab(x - 1, y - 1) + image_tab(x, y - 1) << 1 + image_tab(x + 1, y - 1) ) - (image_tab(x - 1, y + 1) + image_tab(x, y + 1) << 1 + image_tab(x + 1, y + 1))
deltaX.d = deltaX_ / 3
deltaY.d = deltaY_ / 3
gray.l = Sqr(deltaX * deltaX + deltaY * deltaY)
If gray > 0 Or image_save(x, y) > 0
If image_tab(x, y) > 0
gray = 255 - image(x, y)
ElseIf gray > 255
gray = 255
EndIf
image_tab2(x, y) = gray
;{ ajout des points futurs
If *adr(x, y) <> 0
ChangeCurrentElement(new_coord(), *adr(x, y))
DeleteElement(new_coord())
*adr(x, y) = -1
EndIf
AjoutPoint(x+1, y)
AjoutPoint(x, y+1)
AjoutPoint(x-1, y)
AjoutPoint(x, y-1)
AjoutPoint(x+1, y+1)
AjoutPoint(x+1, y-1)
AjoutPoint(x-1, y+1)
AjoutPoint(x-1, y-1)
;}
If i < rayon
image_save(x, y) = 255
Else
image_save(x, y) = gray
EndIf
;Plot(x, y, RGB(image_save(x, y), image_save(x, y), image_save(x, y)))
EndIf
EndIf
Next
Next
;}
CopyArray(image_save(), image())
EndProcedure
Procedure IBF_CombineArray(Array image_IN_OUT.l(2), Array image_gray.a(2), *Couleur_Gray.IBF_RGBA)
Protected *adr.IBF_RGBA
w = ArraySize(image_IN_OUT(), 1)
h = ArraySize(image_IN_OUT(), 2)
For x = 0 To w
For y = 0 To h
If image_gray(x, y) > 0
*adr = @image_IN_OUT(x, y)
tmp.d = image_gray(x, y) / 255
inv_tmp.d = 1 - tmp
*adr\r = *adr\r * inv_tmp + *Couleur_Gray\r * tmp
*adr\g = *adr\g * inv_tmp + *Couleur_Gray\g * tmp
*adr\b = *adr\b * inv_tmp + *Couleur_Gray\b * tmp
*adr\a = *adr\a * inv_tmp + *Couleur_Gray\a * tmp
EndIf
Next
Next
EndProcedure
Procedure IBF_DrawRotatedArrayGray(Array image.a(2), centre_x, centre_y, x, y, Angle.d, couleur.l, Antialiasing = #True)
Protected.d Angle_Cos, Angle_Sin
Protected.l w, h, iXc1, iYc1, iXc2, iYc2, iXs, iYs
x - 1
y - 1
red.d = Red(Couleur) / 255
green.d = Green(Couleur) / 255
blue.d = Blue(Couleur) / 255
x_max.l = OutputWidth() - 1
y_max.l = OutputHeight() - 1
Angle_Cos = Cos(Angle)
Angle_Sin = Sin(Angle)
w_source = ArraySize(image(), 1) ;- 1
h_source = ArraySize(image(), 2) ;- 1
w = Int(w_source * Abs(Angle_Cos) + h_source * Abs(Angle_Sin))
h = Int(h_source * Abs(Angle_Cos) + w_source * Abs(Angle_Sin))
iXc1 = w_source >> 1
iYc1 = h_source >> 1
iXc2 = w >> 1
iYc2 = h >> 1
c.d = x + iXc1
d.d = y + iYc1
new_angle.d = ATan2(c, d) + Angle; * #PI / 180
dist.d = Sqr(c * c + d * d)
c = centre_x + dist * Cos(new_angle) - iXc2
d = centre_y + dist * Sin(new_angle) - iYc2
Select Antialiasing
Case #False
For iY = 0 To h - 1
For iX = 0 To w - 1
; For each nDestImage point find rotated nSrcImage source point
iXs = iXc1 + (iX - iXc2) * Angle_Cos + (iY - iYc2) * Angle_Sin
iYs = iYc1 + (iY - iYc2) * Angle_Cos - (iX - iXc2) * Angle_Sin
If iXs >= 0 And iXs < w_source And iYs >= 0 And iYs < h_source
a = c + iX
b = d + iY
If a >= 0 And a < x_max And b >= 0 And b < y_max
color.l = Point(a, b)
tmp.a = 255 - image(iXs, iYs)
; Plot(a, b, RGB(image(iXs, iYs) * red, image(iXs, iYs) * green, image(iXs, iYs) * blue))
Plot(a, b, RGB(image(iXs, iYs) * red + tmp * Red(color) / 255, image(iXs, iYs) * green + tmp * Green(color) / 255, image(iXs, iYs) * blue + tmp * Blue(color) / 255))
EndIf
EndIf
Next
Next
Case #True
For iY = 0 To h - 1
For iX = 0 To w - 1
; For each nDestImage point find rotated nSrcImage source point
fXs.d = iXc1 + (iX - iXc2) * Angle_Cos + (iY - iYc2) * Angle_Sin
fYs.d = iYc1 + (iY - iYc2) * Angle_Cos - (iX - iXc2) * Angle_Sin
; iXs0 = Int(fXs) ; Strange behaviour when pixel have color for fXs, fYs near 0
; iYs0 = Int(fYs)
iXs0 = Round(fXs, #PB_Round_Down)
iYs0 = Round(fYs, #PB_Round_Down)
If iXs0 >= 0 And iXs0 < w_source - 1 And iYs0 >= 0 And iYs0 < h_source - 1
a = c + iX
b = d + iY
If a >= 0 And a < x_max And b >= 0 And b < y_max
; Bottom left coords of bounding floating point rectangle on nSrcImage
fXfs1.d = fXs - Int(fXs)
fYfs1.d = fYs - Int(fYs)
fXfs1less.d = 1 - fXfs1 - 0.000005 : If fXfs1less < 0 : fXfs1less = 0 : EndIf
fYfs1less.d = 1 - fYfs1 - 0.000005 : If fYfs1less < 0 : fYfs1less = 0 : EndIf
ic0.d = image(iXs0 + 1, iYs0) * fXfs1 + image(iXs0, iYs0) * fXfs1less
ic1.d = image(iXs0 + 1, iYs0 + 1) * fXfs1 + image(iXs0, iYs0 + 1) * fXfs1less
; Weight along axis Y
ic = fYfs1less * ic0 + fYfs1 * ic1
color.l = Point(a, b)
tmp.a = 255 - ic
Plot(a, b, RGB(ic * red + tmp * Red(color) / 255, ic * green + tmp * Green(color) / 255, ic * blue + tmp * Blue(color) / 255))
EndIf
ElseIf iXs0 = w_source - 1 And iYs0 >= 0 And iYs0 < h_source - 1
a = c + iX
b = d + iY
If a >= 0 And a < x_max And b >= 0 And b < y_max
; Bottom left coords of bounding floating point rectangle on nSrcImage
fXfs1.d = fXs - Int(fXs)
fYfs1.d = fYs - Int(fYs)
fXfs1less.d = 1 - fXfs1 - 0.000005 : If fXfs1less < 0 : fXfs1less = 0 : EndIf
fYfs1less.d = 1 - fYfs1 - 0.000005 : If fYfs1less < 0 : fYfs1less = 0 : EndIf
ic0.d = image(iXs0, iYs0) * fXfs1less
ic1.d = image(iXs0, iYs0 + 1) * fXfs1less
; Weight along axis Y
ic = fYfs1less * ic0 + fYfs1 * ic1
color.l = Point(a, b)
tmp.a = 255 - ic
Plot(a, b, RGB(ic * red + tmp * Red(color) / 255, ic * green + tmp * Green(color) / 255, ic * blue + tmp * Blue(color) / 255))
EndIf
ElseIf iXs0 >= 0 And iXs0 < w_source - 1 And iYs0 = h_source - 1
a = c + iX
b = d + iY
If a >= 0 And a < x_max And b >= 0 And b < y_max
; Bottom left coords of bounding floating point rectangle on nSrcImage
fXfs1.d = fXs - Int(fXs)
fXfs1less.d = 1 - fXfs1 - 0.000005 : If fXfs1less < 0 : fXfs1less = 0 : EndIf
fYfs1less.d = 1 - fYfs1 - 0.000005 : If fYfs1less < 0 : fYfs1less = 0 : EndIf
ic0.d = image(iXs0 + 1, iYs0) * fXfs1 + image(iXs0, iYs0) * fXfs1less
; Weight along axis Y
ic = fYfs1less * ic0
color.l = Point(a, b)
tmp.a = 255 - ic
Plot(a, b, RGB(ic * red + tmp * Red(color) / 255, ic * green + tmp * Green(color) / 255, ic * blue + tmp * Blue(color) / 255))
EndIf
EndIf
Next
Next
EndSelect
EndProcedure
Procedure IBF_DrawRotatedArray(Array image.l(2), centre_x, centre_y, x, y, Angle.d, Antialiasing = #True, Coef_Sigmoide.d = 0)
Protected.d Angle_Cos, Angle_Sin
Protected.l w, h, iXc1, iYc1, iXc2, iYc2, iXs, iYs
x - 1
y - 1
x_max.l = OutputWidth() - 1
y_max.l = OutputHeight() - 1
Angle_Cos = Cos(Angle)
Angle_Sin = Sin(Angle)
w_source = ArraySize(image(), 1) ;- 1
h_source = ArraySize(image(), 2) ;- 1
w = Int(w_source * Abs(Angle_Cos) + h_source * Abs(Angle_Sin))
h = Int(h_source * Abs(Angle_Cos) + w_source * Abs(Angle_Sin))
iXc1 = w_source >> 1
iYc1 = h_source >> 1
iXc2 = w >> 1
iYc2 = h >> 1
c.d = x + iXc1
d.d = y + iYc1
new_angle.d = ATan2(c, d) + Angle; * #PI / 180
dist.d = Sqr(c * c + d * d)
c = centre_x + dist * Cos(new_angle) - iXc2
d = centre_y + dist * Sin(new_angle) - iYc2
; DrawingMode(#PB_2DDrawing_AlphaBlend)
Select Antialiasing
;{ Pas d'Antialiasing
Case #False
For iY = 0 To h - 1
For iX = 0 To w - 1
; For each nDestImage point find rotated nSrcImage source point
iXs = iXc1 + (iX - iXc2) * Angle_Cos + (iY - iYc2) * Angle_Sin
iYs = iYc1 + (iY - iYc2) * Angle_Cos - (iX - iXc2) * Angle_Sin
If iXs >= 0 And iXs < w_source And iYs >= 0 And iYs < h_source
a = c + iX
b = d + iY
If a >= 0 And a < x_max And b >= 0 And b < y_max And Alpha(image(iXs, iYs)) > 0
; Plot(a, b, image(iXs, iYs))
; si on ne veux pas utiliser #PB_2DDrawing_AlphaBlend :
color.l = Point(a, b)
tmpa.d = Alpha(image(iXs, iYs)) / 255
tmp_inv.d = 1 - tmpa
Plot(a, b, RGB(Red(image(iXs, iYs)) * tmpa + Red(color) * tmp_inv, Green(image(iXs, iYs)) * tmpa + Green(color) * tmp_inv, Blue(image(iXs, iYs)) * tmpa + Blue(color) * tmp_inv))
EndIf
EndIf
Next
Next
;}
;{ AntiAliasing
Case #True
Macro Sigmoide(_x_)
_x_ *(1-Coef_Sigmoide) + (Coef_Sigmoide) * ((1+TanH((-0.5+_x_) * Coef_Sigmoide * 10))/2)
EndMacro
For iY = 0 To h - 1
For iX = 0 To w - 1
; For each nDestImage point find rotated nSrcImage source point
fXs.d = iXc1 + (iX - iXc2) * Angle_Cos + (iY - iYc2) * Angle_Sin
fYs.d = iYc1 + (iY - iYc2) * Angle_Cos - (iX - iXc2) * Angle_Sin
; iXs0 = Int(fXs) ; Strange behaviour when pixel have color for fXs, fYs near 0
; iYs0 = Int(fYs)
iXs0 = Round(fXs, #PB_Round_Down)
iYs0 = Round(fYs, #PB_Round_Down)
If iXs0 >= 0 And iXs0 < w_source - 1 And iYs0 >= 0 And iYs0 < h_source - 1
a = c + iX
b = d + iY
If a >= 0 And a < x_max And b >= 0 And b < y_max
; Bottom left coords of bounding floating point rectangle on nSrcImage
fXfs1.d = fXs - Int(fXs)
fYfs1.d = fYs - Int(fYs)
fXfs1less.d = 1 - fXfs1 - 0.00005 : If fXfs1less < 0 : fXfs1less = 0 : EndIf
fYfs1less.d = 1 - fYfs1 - 0.00005 : If fYfs1less < 0 : fYfs1less = 0 : EndIf
If Coef_Sigmoide > 0
fXfs1less = Sigmoide(fXfs1less)
fYfs1less = Sigmoide(fYfs1less)
fXfs1 = Sigmoide(fXfs1)
fYfs1 = Sigmoide(fYfs1)
EndIf
icr = Red(image(iXs0, iYs0)) * fXfs1less
icg = Green(image(iXs0, iYs0)) * fXfs1less
icb = Blue(image(iXs0, iYs0)) * fXfs1less
ica = Alpha(image(iXs0, iYs0)) * fXfs1less
icr0 = Red(image(iXs0 + 1, iYs0)) * fXfs1 + icr
icg0 = Green(image(iXs0 + 1, iYs0)) * fXfs1 + icg
icb0 = Blue(image(iXs0 + 1, iYs0)) * fXfs1 + icb
ica0 = Alpha(image(iXs0 + 1, iYs0)) * fXfs1 + ica
icr = Red(image(iXs0, iYs0 + 1)) * fXfs1less
icg = Green(image(iXs0, iYs0 + 1)) * fXfs1less
icb = Blue(image(iXs0, iYs0 + 1)) * fXfs1less
ica = Alpha(image(iXs0, iYs0 + 1)) * fXfs1less
icr1 = Red(image(iXs0 + 1, iYs0 + 1)) * fXfs1 + icr
icg1 = Green(image(iXs0 + 1, iYs0 + 1)) * fXfs1 + icg
icb1 = Blue(image(iXs0 + 1, iYs0 + 1)) * fXfs1 + icb
ica1 = Alpha(image(iXs0 + 1, iYs0 + 1)) * fXfs1 + ica
; Plot(a, b, RGBA(fYfs1less * icr0 + fYfs1 * icr1, fYfs1less * icg0 + fYfs1 * icg1, fYfs1less * icb0 + fYfs1 * icb1, fYfs1less * ica0 + fYfs1 * ica1))
; si on ne veux pas utiliser #PB_2DDrawing_AlphaBlend :
color.l = Point(a, b)
tmpa.d = (fYfs1less * ica0 + fYfs1 * ica1) / 255
tmp_inv.d = 1 - tmpa
Plot(a, b, RGB((fYfs1less * icr0 + fYfs1 * icr1) * tmpa + Red(color) * tmp_inv, (fYfs1less * icg0 + fYfs1 * icg1) * tmpa + Green(color) * tmp_inv, (fYfs1less * icb0 + fYfs1 * icb1) * tmpa + Blue(color) * tmp_inv))
EndIf
EndIf
Next
Next
;}
EndSelect
EndProcedure
Procedure.i IBF_CreateGlyphe(*Font.IBF_Font, char.s)
; This Function DOES not check if the specified Font really exist.
Protected key$, *obj.IBF_Glyphe, w.w, h.w, x.w, y.w
key$ = *Font\FontKey + "|" + char
*obj = FindMapElement(IBF_Global\Glyphe(), key$)
If *obj : ProcedureReturn *obj : EndIf
*obj = AddMapElement(IBF_Global\Glyphe(), key$)
InitializeStructure(*obj, IBF_Glyphe)
*obj\Adresse_Font = *Font
*Font\Glyphe(char) = *obj
*obj\char = char
; Taille des caractères
StartDrawing(ImageOutput(IBF_Global\ImageTestTextSize))
DrawingFont(*Font\FontId)
If char = #CR$ Or char = #LF$ ; Pour linux. Pour ces caractères on obtient une hauteur double, ce qui fait des lignes énormes
w = TextWidth(" ")
h = TextHeight(" ")
Else
w = TextWidth(*obj\char)
h = TextHeight(*obj\char)
EndIf
*obj\Largeur = w
*obj\Hauteur = h
StopDrawing()
Dim *obj\Image(w, h)
If w <> 0 And h <> 0
img = CreateImage(#PB_Any, w, h, 24)
If img
If StartDrawing(ImageOutput(img))
DrawingFont(*Font\FontId)
If char = #CR$ Or char = #LF$
Else
DrawText(0, 0, *obj\char, RGB(255, 255, 255), RGB(0, 0, 0))
EndIf
; If char = " "
; For x = 0 To w - 1
; For y = 0 To h - 1
; *obj\Image(x, y) = 255
;
; Next
; Next
; Else
For x = 0 To w - 1
For y = 0 To h - 1
color.l = Point(x, y)
*obj\Image(x, y) = (Red(color) + Blue(color) + Green(color)) / 3
Next
Next
; EndIf
StopDrawing()
EndIf
; *obj\Image(0, 0) = 255
; *obj\Image(w, h) = 255
FreeImage(img)
EndIf
EndIf
ProcedureReturn *obj
EndProcedure
Procedure.i BF_LoadFont(FontName.s = "Arial", FontSize.l = 12, FontStyle.l = #BF_Font_Normal)
Protected *font.IBF_Font, key$, *glyphe.IBF_Glyphe, x.w, y.w
key$ = FontName + "|" + Str(FontSize) + "|" + Str(FontStyle)
*font = FindMapElement(IBF_Global\Font(), key$)
If *font : ProcedureReturn *font : EndIf
*font = AddMapElement(IBF_Global\Font(), key$)
InitializeStructure(*font, IBF_Font)
*font\FontKey = key$
*font\Font = LoadFont(#PB_Any, FontName, FontSize, FontStyle)
*font\FontId = FontID(*font\Font)
*font\Size = FontSize
*font\Style = FontStyle
; Détermination de \BaseLine
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
*glyphe = IBF_CreateGlyphe(*font, Chr(12))
If *glyphe
x = 0
y = *glyphe\Hauteur / 2
While x < *glyphe\Largeur - 1 And *glyphe\Image(x, y) = 0
x + 1
Wend
While y < *glyphe\Hauteur - 1 And *glyphe\Image(x, y) <> 0
y + 1
Wend
*font\BaseLine = y - 1
Else
*font\BaseLine = *glyphe\Hauteur
EndIf
CompilerDefault
*glyphe = IBF_CreateGlyphe(*obj, "a")
If *glyphe
x = 0
y = *glyphe\Hauteur
For y = *glyphe\Hauteur - 1 To 0 Step -1
For x = 0 To *glyphe\Largeur - 1
If *glyphe\Image(x, y) <> 0
Break 2
EndIf
Next
Next
*font\BaseLine = y
Else
*font\BaseLine = *glyphe\Hauteur
EndIf
CompilerEndSelect
ProcedureReturn *font
EndProcedure
Procedure.i BF_NewText(text.s, *Font.IBF_Font, couleur.l)
*txt.IBF_Text = AllocateMemory(SizeOf(IBF_Text))
InitializeStructure(*txt, IBF_Text)
len = Len(text) - 1
*adr = @text
For c = 0 To len
AddElement(*txt\Text())
*txt\Text()\Glyphe = IBF_CreateGlyphe(*font, PeekS(*adr, 1))
*txt\Text()\couleur = couleur
*adr + SizeOf(Character)
Next
ProcedureReturn *txt
EndProcedure
;}
;{ MODULE bulle_text
Structure IBT_ADR_list_POINT
List pourtour.POINT()
EndStructure
Structure BT_Bulle
Centre.POINT
List pourtour.POINT()
USE_CattmullRom.b
USE_Antialisating.b
text.s
angle_text.d ; radian
*BF_Text.IBF_Text
color.l
*bulle_list.BT_Liste_bulle
EndStructure
Structure BT_Liste_bulle
List bulle_list.BT_Bulle()
IS_init.b
EndStructure
Procedure IBT_DrawRotatedText2(centre_x, centre_y, x, y, Texte$, Angle.d, Couleur) ; x et y sont relatifs au centre
Protected new_angle.d = ATan2(x, y) - Angle * #PI / 180
Protected dist.d = Sqr(x * x + y * y)
DrawRotatedText(centre_x + dist * Cos(new_angle), centre_y + dist * Sin(new_angle), Texte$, Angle, Couleur)
; tx = centre_x + dist * Cos(new_angle)
; ty = centre_y + dist * Sin(new_angle)
; LineXY(tx, ty, tx + TextWidth(Texte$) * Cos(Radian(-Angle)), ty + TextWidth(Texte$) * Sin(Radian(-Angle)), RGB(255, 125, 0))
EndProcedure
Procedure IBT_CatmullRomSpline(t.f, *result.point, *p0.point, *p1.point, *p2.point, *p3.point)
t2.f = t * t
t3.f = t2 * t
*result\x = (( 2.0 * *p1\x) +(- *p0\x + *p2\x) * t +(2.0 * *p0\x - 5.0 * *p1\x + 4 * *p2\x - *p3\x) * t2 +(- *p0\x + 3.0 * *p1\x - 3.0 * *p2\x + *p3\x) * t3)
*result\x >> 1
*result\y = (( 2.0 * *p1\y) +(- *p0\y + *p2\y) * t +(2.0 * *p0\y - 5.0 * *p1\y + 4 * *p2\y - *p3\y) * t2 +(- *p0\y + 3.0 * *p1\y - 3.0 * *p2\y + *p3\y) * t3)
*result\y >> 1
EndProcedure
Procedure.i BT_InitBulleText(USE_CattmullRom.b)
Static Bulle_list.BT_Liste_bulle
If Bulle_list\IS_init = #False
InitializeStructure(Bulle_map, BT_Liste_bulle)
Bulle_list\IS_init = #True
EndIf
Protected *mem.BT_Bulle = AddElement(Bulle_list\bulle_list())
If *mem
InitializeStructure(*mem, BT_Bulle)
*mem\bulle_list = @Bulle_list
*mem\USE_CattmullRom = USE_CattmullRom
*mem\USE_Antialisating = #True
; Init l'emplacement du texte
*mem\BF_Text = BF_NewText("", 0, 0)
EndIf
ProcedureReturn *mem
EndProcedure
Procedure BT_DrawBulleText(*bulle.BT_Bulle, zoom.f = 0.5)
Protected angle.d, *cote.POINT
Protected NewList tour_incline.POINT()
#AFFICHE_POINT = #False
;{ Traitement du Cattmull
Protected *adr_pourtour.IBT_ADR_list_POINT = *bulle + OffsetOf(BT_Bulle\pourtour)
If *bulle\USE_CattmullRom
Protected *p.POINT
*adr_pourtour = AllocateMemory(SizeOf(IBT_ADR_list_POINT))
InitializeStructure(*adr_pourtour, IBT_ADR_list_POINT)
*p2.POINT = LastElement(*bulle\pourtour())
*p1.POINT = PreviousElement(*bulle\pourtour())
*p0.POINT = PreviousElement(*bulle\pourtour())
ForEach *bulle\pourtour()
*p3 = @*bulle\pourtour()
tmp_x.l = *p1\x - *p2\x
tmp_y.l = *p1\y - *p2\y
div.l = Sqr(tmp_x * tmp_x + tmp_y * tmp_y) / 20
For z = 1 To div
;- CatmullRom
*p = AddElement(*adr_pourtour\pourtour())
IBT_CatmullRomSpline(z / div, *p, *p0, *p1, *p2, *p3)
; Circle(*bulle\Centre\x + *p\x, *bulle\Centre\y + *p\y, 2, #Blue)
Next
*p0 = *p1
*p1 = *p2
*p2 = *p3
Next
EndIf
;}
;{ passage en coordonnées texte pivoté
*adr_haut.POINT = 0 : haut = 100000000
*adr_bas.point = 0 : bas = -100000000
Protected *old.POINT = LastElement(*adr_pourtour\pourtour())
ForEach *adr_pourtour\pourtour()
angle.d = ATan2(*adr_pourtour\pourtour()\x, *adr_pourtour\pourtour()\y) - *bulle\angle_text
dist.d = zoom * Sqr(*adr_pourtour\pourtour()\x * *adr_pourtour\pourtour()\x + *adr_pourtour\pourtour()\y * *adr_pourtour\pourtour()\y)
*elem.POINT = AddElement(tour_incline())
*elem\x = dist * Cos(angle)
*elem\y = dist * Sin(angle)
If *elem\y > bas
bas = *elem\y
*adr_bas = *elem
EndIf
If *elem\y < haut
haut = *elem\y
*adr_haut = *elem
EndIf
LineXY(*bulle\Centre\x + *old\x, *bulle\Centre\y + *old\y, *bulle\Centre\x + *adr_pourtour\pourtour()\x, *bulle\Centre\y + *adr_pourtour\pourtour()\y, #White)
*old = *adr_pourtour\pourtour()
Next
; ChangeCurrentElement(tour_incline(), *adr_haut)
; Circle(*bulle\Centre\x + *adr_haut\x, *bulle\Centre\y + *adr_haut\y, 3, #Red)
; DrawText(*bulle\Centre\x + *adr_haut\x + 5, *bulle\Centre\y + *adr_haut\y, Str(ListIndex(tour_incline())))
;
; Circle(*bulle\Centre\x + *adr_bas\x, *bulle\Centre\y + *adr_bas\y, 3, RGB(255, 125, 0))
;}
;{ liste des cotés
NewList cote_gauche.POINT()
NewList cote_droit.POINT()
;{ test pour savoir de quel coté partir
ChangeCurrentElement(tour_incline(), *adr_haut)
*elem = PreviousElement(tour_incline())
If *elem = 0 : *elem = LastElement(tour_incline()) : EndIf
angle = ATan2(*elem\x - *adr_haut\x, *elem\y - *adr_haut\y)
ChangeCurrentElement(tour_incline(), *adr_haut)
*elem = NextElement(tour_incline())
If *elem = 0 : *elem = FirstElement(tour_incline()) : EndIf
If angle > ATan2(*elem\x - *adr_haut\x, *elem\y - *adr_haut\y)
sens = -1
Else
sens = 1
EndIf
;}
;{ parcours pour coté gauche
; init
*elem = *adr_haut : *cote = 0
ChangeCurrentElement(tour_incline(), *adr_haut)
Repeat
If sens = 1
*elem_suivant.POINT = NextElement(tour_incline())
If *elem_suivant = 0 : *elem_suivant = FirstElement(tour_incline()) : EndIf
Else
*elem_suivant.POINT = PreviousElement(tour_incline())
If *elem_suivant = 0 : *elem_suivant = LastElement(tour_incline()) : EndIf
EndIf
cst_y = *elem_suivant\y - *elem\y
cst_x = *elem_suivant\x - *elem\x
For i = *elem\y + 1 To *elem_suivant\y
*cote = AddElement(cote_gauche())
*cote\y = i
*cote\x = ((i - *elem\y) * cst_x) / cst_y + *elem\x
CompilerIf #AFFICHE_POINT
Plot(*bulle\Centre\x + *cote\x, *bulle\Centre\y + *cote\y, #Blue)
CompilerEndIf
Next
*elem = *elem_suivant
Until *elem = *adr_bas
;}
;{ parcours pour coté droit
; init
*elem = *adr_haut : *cote = 0
ChangeCurrentElement(tour_incline(), *adr_haut)
sens = -sens
Repeat
If sens = 1
*elem_suivant.POINT = NextElement(tour_incline())
If *elem_suivant = 0 : *elem_suivant = FirstElement(tour_incline()) : EndIf
Else
*elem_suivant.POINT = PreviousElement(tour_incline())
If *elem_suivant = 0 : *elem_suivant = LastElement(tour_incline()) : EndIf
EndIf
cst_y = *elem_suivant\y - *elem\y
cst_x = *elem_suivant\x - *elem\x
For i = *elem\y + 1 To *elem_suivant\y
*cote = AddElement(cote_droit())
*cote\y = i
*cote\x = ((i - *elem\y) * cst_x) / cst_y + *elem\x
CompilerIf #AFFICHE_POINT
Plot(*bulle\Centre\x + *cote\x, *bulle\Centre\y + *cote\y, #Cyan)
CompilerEndIf
Next
*elem = *elem_suivant
Until *elem = *adr_bas
;}
If ListSize(cote_droit()) <> ListSize(cote_droit())
Debug "D = " + ListSize(cote_droit()) + " G = " + ListSize(cote_gauche())
EndIf
;{ correction d'une erreur de sens
FirstElement(cote_droit())
FirstElement(cote_gauche())
If cote_droit()\x < cote_gauche()\x
NewList tmp.POINT()
CopyList(cote_droit(), tmp())
CopyList(cote_gauche(), cote_droit())
CopyList(tmp(), cote_gauche())
FreeList(tmp())
EndIf
;}
;}
Select 2
Case 1
;{ dessin du texte - Standart
*curseur_text.Character = @*bulle\text
offset.POINT\x = 0
offset\y = TextHeight("a")
FirstElement(cote_gauche())
FirstElement(cote_droit())
Repeat
t$ = Chr(*curseur_text\c)
tw.l = TextWidth(t$)
If cote_droit()\x - cote_gauche()\x > tw + offset\x And *curseur_text\c <> #CR
IBT_DrawRotatedText2(*bulle\Centre\x, *bulle\Centre\y, cote_gauche()\x + offset\x, cote_gauche()\y, t$, -Degree(*bulle\angle_text), *bulle\color)
offset\x + tw
*curseur_text + SizeOf(Character)
Else
If *curseur_text\c = #CR
*curseur_text + SizeOf(Character)
EndIf
offset\x = 0
For i = 1 To offset\y
res_g = NextElement(cote_gauche())
res_d = NextElement(cote_droit())
If res_d = 0 Or res_g = 0
Break 2
EndIf
Next
EndIf
Until *curseur_text\c = 0
;}
Case 2
;{ dessin du texte - pas de coupure des mots
EndSelect
*curseur_text.Character = @*bulle\text
*curseur_text_end = @*bulle\text + Len(*bulle\text) * SizeOf(Character)
offset.POINT\x = 0
offset\y = TextHeight(" ")
FirstElement(cote_gauche())
FirstElement(cote_droit())
DEBUT.b = #True
Repeat
*c.Character = *curseur_text
Repeat
*c + SizeOf(Character)
Until *c\c = ' ' Or *c >= *curseur_text_end
len = *c - *curseur_text
t$ = PeekS(*curseur_text, len)
tw.l = TextWidth(t$)
If cote_droit()\x - cote_gauche()\x > tw + offset\x And *curseur_text\c <> #CR
IBT_DrawRotatedText2(*bulle\Centre\x, *bulle\Centre\y, cote_gauche()\x + offset\x, cote_gauche()\y, t$, -Degree(*bulle\angle_text), *bulle\color)
offset\x + tw
*curseur_text = *c
DEBUT = #False
Else
If *curseur_text\c = #CR
*curseur_text + SizeOf(Character)
EndIf
offset\x = 0
If DEBUT
res_g = NextElement(cote_gauche())
res_d = NextElement(cote_droit())
If res_d = 0 Or res_g = 0
Break 1
EndIf
Else
For i = 1 To offset\y
res_g = NextElement(cote_gauche())
res_d = NextElement(cote_droit())
If res_d = 0 Or res_g = 0
Break 2
EndIf
Next
EndIf
EndIf
Until *curseur_text >= *curseur_text_end
;}
;{ libération des ressources
If *bulle\USE_CattmullRom
FreeList(*adr_pourtour\pourtour())
FreeMemory(*adr_pourtour)
EndIf
;}
EndProcedure
#BF_Text_VerticalCentered = %0000000000000001
#BF_Text_HorizontalCentered = %0000000000000010
#BF_Text_MotsEntiers = %0000000000000100
Procedure BT_DrawBulleText_(*bulle.BT_Bulle, zoom.f = 0.5, rayon.l = 3, Couleur_contour.l = 0, coef_sigmoide.d = 0, MiseEnForme.l = #BF_Text_HorizontalCentered)
Protected angle.d, *cote.POINT
Protected NewList tour_incline.POINT()
#AFFICHE_POINT = #False
;{ Traitement du Cattmull
Protected *adr_pourtour.IBT_ADR_list_POINT = *bulle + OffsetOf(BT_Bulle\pourtour)
If *bulle\USE_CattmullRom
Protected *p.POINT
*adr_pourtour = AllocateMemory(SizeOf(IBT_ADR_list_POINT))
InitializeStructure(*adr_pourtour, IBT_ADR_list_POINT)
*p2.POINT = LastElement(*bulle\pourtour())
*p1.POINT = PreviousElement(*bulle\pourtour())
*p0.POINT = PreviousElement(*bulle\pourtour())
ForEach *bulle\pourtour()
*p3 = @*bulle\pourtour()
tmp_x.l = *p1\x - *p2\x
tmp_y.l = *p1\y - *p2\y
div.l = Sqr(tmp_x * tmp_x + tmp_y * tmp_y) / 20
For z = 1 To div
;- CatmullRom
*p = AddElement(*adr_pourtour\pourtour())
IBT_CatmullRomSpline(z / div, *p, *p0, *p1, *p2, *p3)
; Circle(*bulle\Centre\x + *p\x, *bulle\Centre\y + *p\y, 2, #Blue)
Next
*p0 = *p1
*p1 = *p2
*p2 = *p3
Next
EndIf
;}
;{ passage en coordonnées texte pivoté
*adr_haut.POINT = 0
*adr_bas.point = 0
Protected *old.POINT = LastElement(*adr_pourtour\pourtour())
Protected bulle_MAX.point, bulle_min.POINT
bulle_min\x = $7FFFFFFF
bulle_min\y = $7FFFFFFF
bulle_MAX\x = -$7FFFFFFF
bulle_MAX\y = -$7FFFFFFF
ForEach *adr_pourtour\pourtour()
angle.d = ATan2(*adr_pourtour\pourtour()\x, *adr_pourtour\pourtour()\y) - *bulle\angle_text
dist.d = zoom * Sqr(*adr_pourtour\pourtour()\x * *adr_pourtour\pourtour()\x + *adr_pourtour\pourtour()\y * *adr_pourtour\pourtour()\y)
*elem.POINT = AddElement(tour_incline())
*elem\x = dist * Cos(angle)
*elem\y = dist * Sin(angle)
If *elem\y > bulle_MAX\y
bulle_MAX\y = *elem\y
*adr_bas = *elem
EndIf
If *elem\y < bulle_min\y
bulle_min\y = *elem\y
*adr_haut = *elem
EndIf
If *elem\x > bulle_MAX\x
bulle_MAX\x = *elem\x
EndIf
If *elem\x < bulle_min\x
bulle_min\x = *elem\x
EndIf
LineXY(*bulle\Centre\x + *old\x, *bulle\Centre\y + *old\y, *bulle\Centre\x + *adr_pourtour\pourtour()\x, *bulle\Centre\y + *adr_pourtour\pourtour()\y, #White)
*old = *adr_pourtour\pourtour()
Next
;}
;{ liste des cotés
NewList cote_gauche.POINT()
NewList cote_droit.POINT()
;{ test pour savoir de quel coté partir
ChangeCurrentElement(tour_incline(), *adr_haut)
*elem = PreviousElement(tour_incline())
If *elem = 0 : *elem = LastElement(tour_incline()) : EndIf
angle = ATan2(*elem\x - *adr_haut\x, *elem\y - *adr_haut\y)
ChangeCurrentElement(tour_incline(), *adr_haut)
*elem = NextElement(tour_incline())
If *elem = 0 : *elem = FirstElement(tour_incline()) : EndIf
If angle > ATan2(*elem\x - *adr_haut\x, *elem\y - *adr_haut\y)
sens = -1
Else
sens = 1
EndIf
;}
;{ parcours pour coté gauche
; init
*elem = *adr_haut : *cote = 0
ChangeCurrentElement(tour_incline(), *adr_haut)
Repeat
If sens = 1
*elem_suivant.POINT = NextElement(tour_incline())
If *elem_suivant = 0 : *elem_suivant = FirstElement(tour_incline()) : EndIf
Else
*elem_suivant.POINT = PreviousElement(tour_incline())
If *elem_suivant = 0 : *elem_suivant = LastElement(tour_incline()) : EndIf
EndIf
cst_y = *elem_suivant\y - *elem\y
cst_x = *elem_suivant\x - *elem\x
For i = *elem\y + 1 To *elem_suivant\y
*cote = AddElement(cote_gauche())
*cote\y = i
*cote\x = ((i - *elem\y) * cst_x) / cst_y + *elem\x
CompilerIf #AFFICHE_POINT
Plot(*bulle\Centre\x + *cote\x, *bulle\Centre\y + *cote\y, #Blue)
CompilerEndIf
Next
*elem = *elem_suivant
Until *elem = *adr_bas
;}
;{ parcours pour coté droit
; init
*elem = *adr_haut : *cote = 0
ChangeCurrentElement(tour_incline(), *adr_haut)
sens = -sens
Repeat
If sens = 1
*elem_suivant.POINT = NextElement(tour_incline())
If *elem_suivant = 0 : *elem_suivant = FirstElement(tour_incline()) : EndIf
Else
*elem_suivant.POINT = PreviousElement(tour_incline())
If *elem_suivant = 0 : *elem_suivant = LastElement(tour_incline()) : EndIf
EndIf
cst_y = *elem_suivant\y - *elem\y
cst_x = *elem_suivant\x - *elem\x
For i = *elem\y + 1 To *elem_suivant\y
*cote = AddElement(cote_droit())
*cote\y = i
*cote\x = ((i - *elem\y) * cst_x) / cst_y + *elem\x
CompilerIf #AFFICHE_POINT
Plot(*bulle\Centre\x + *cote\x, *bulle\Centre\y + *cote\y, #Cyan)
CompilerEndIf
Next
*elem = *elem_suivant
Until *elem = *adr_bas
;}
If ListSize(cote_droit()) <> ListSize(cote_droit())
Debug "D = " + ListSize(cote_droit()) + " G = " + ListSize(cote_gauche())
EndIf
;{ correction d'une erreur de sens
FirstElement(cote_droit())
FirstElement(cote_gauche())
If cote_droit()\x < cote_gauche()\x
NewList tmp.POINT()
CopyList(cote_droit(), tmp())
CopyList(cote_gauche(), cote_droit())
CopyList(tmp(), cote_gauche())
FreeList(tmp())
EndIf
;}
;}
;{ dessin du texte
;{ Allocation du tableau
w = bulle_MAX\x - bulle_min\x
h = bulle_MAX\y - bulle_min\y
vect_offset = rayon + 1
Dim image.l(w+1 + vect_offset + rayon, h+1 + vect_offset + rayon)
;}
;{ Positionnement du texte dans le tableau
;{ Simple pour test affichage
; x = vect_offset : y = vect_offset
;
; ForEach *bulle\BF_Text\Text()
; With *bulle\BF_Text\Text()
;
; If x + \Glyphe\Largeur < w And y + \Glyphe\Hauteur < h
; For x1 = 0 To \Glyphe\Largeur
; For y1 = 0 To \Glyphe\Hauteur
; image(x + x1, y + y1) = RGBA(\RGBA\r, \RGBA\g, \RGBA\b, \Glyphe\Image(x1, y1))
; Next
; Next
; EndIf
;
; x + \Glyphe\Largeur
; If x > w
; x = vect_offset
; y + \Glyphe\Hauteur
; EndIf
;
; EndWith
;
; Next
;}
x = vect_offset : y = vect_offset
ClearDebugOutput()
Select MiseEnForme
Case #BF_Text_HorizontalCentered
*txt.IBF_Char = FirstElement(*bulle\BF_Text\Text())
FirstElement(cote_droit())
FirstElement(cote_gauche())
Repeat
*cote_g.POINT = @cote_gauche()
*cote_d.POINT = @cote_droit()
If *txt = 0
Break
EndIf
ligne_h.l = *txt\Glyphe\Hauteur
;{ établissement des dimensions de la ligne
Repeat
ligne_l.l = $7FFFFFFF
REDO = #False
;{ estimation de la longeur maxi possible de la ligne
ChangeCurrentElement(cote_droit(), *cote_d)
ChangeCurrentElement(cote_gauche(), *cote_g)
*cote_d_gauch.point = *cote_d
*cote_g_droit.point = *cote_g
For i = 1 To ligne_h
If cote_gauche()\x > *cote_g_droit\x
*cote_g_droit = cote_gauche()
EndIf
If cote_droit()\x < *cote_d_gauch\x
*cote_d_gauch = cote_droit()
EndIf
If NextElement(cote_droit()) = 0 : Break : EndIf
If NextElement(cote_gauche()) = 0 : Break : EndIf
Next
ligne_l = *cote_d_gauch\x - *cote_g_droit\x
*cote_d_fin = @cote_droit()
*cote_g_fin = @cote_gauche()
;}
;{ contenu de la ligne
*txt_fin.IBF_Char = *txt
ChangeCurrentElement(*bulle\BF_Text\Text(), *txt)
l_courrant.l = 0
last_space.l = 0
Repeat
largeur_mot.l = 0
If *txt_fin\Glyphe\char = " " Or *txt_fin\Glyphe\char = #CR$ Or *txt_fin\Glyphe\char = #LF$
largeur_mot = *txt_fin\Glyphe\Largeur
last_space = *txt_fin\Glyphe\Largeur
Else
*txt_fin_mot.IBF_Char = *txt_fin
While *txt_fin_mot And *txt_fin_mot\Glyphe\char <> " " And *txt_fin_mot\Glyphe\char <> #CR$ And *txt_fin_mot\Glyphe\char <> #LF$
largeur_mot + *txt_fin_mot\Glyphe\Largeur
*txt_fin_mot.IBF_Char = NextElement(*bulle\BF_Text\Text())
Wend
PreviousElement(*bulle\BF_Text\Text())
EndIf
If l_courrant + largeur_mot >= ligne_l
l_courrant - last_space
Break
EndIf
l_courrant + largeur_mot
If *txt_fin\Glyphe\Hauteur > ligne_h
ligne_h = *txt_fin\Glyphe\Hauteur
REDO = #True
EndIf
*txt_fin = NextElement(*bulle\BF_Text\Text())
If *txt_fin = 0 : Break : EndIf
If *txt_fin\Glyphe\char = #CR$ Or *txt_fin\Glyphe\char = #LF$
If *txt_fin\Glyphe\char = #CR$
If NextElement(*bulle\BF_Text\Text()) And *bulle\BF_Text\Text()\Glyphe\char = #LF$
*txt_fin = @*bulle\BF_Text\Text()
EndIf
EndIf
Break
EndIf
ForEver
;}
Until REDO = #False
;}
If *txt_fin = *txt
;{ pas la place pour une lettre, on passe à la suite
ChangeCurrentElement(cote_droit(), *cote_d)
ChangeCurrentElement(cote_gauche(), *cote_g)
*cote_g = NextElement(cote_gauche())
*cote_d = NextElement(cote_droit())
If *cote_d = 0 Or *cote_g = 0
Break ; POINT DE sortie
EndIf
;}
Else
;{ les paramètres de la ligne sont corrects
offset_x = (ligne_l - l_courrant) / 2
ChangeCurrentElement(*bulle\BF_Text\Text(), *txt)
;ChangeCurrentElement(cote_gauche(), *cote_g)
;{ boucle dessin
Repeat
For x1 = 0 To *txt\Glyphe\Largeur
For y1 = 0 To *txt\Glyphe\Hauteur
_x = vect_offset + -bulle_min\x + *cote_g_droit\x + offset_x + x1
_y = vect_offset + -bulle_min\y + *cote_g\y + y1
If _x > 0 And _x =< w + rayon And _y > 0 And _y =< h + rayon
image(_x, _y) = RGBA(*txt\RGBA\r, *txt\RGBA\g, *txt\RGBA\b, *txt\Glyphe\Image(x1, y1))
EndIf
Next
Next
offset_x + *txt\Glyphe\Largeur
*txt = NextElement(*bulle\BF_Text\Text())
If *txt = 0
Break 2 ; POINT DE sortie
EndIf
Until *txt = *txt_fin
;}
If *cote_d_fin = 0 Or *cote_g_fin = 0
Break
EndIf
ChangeCurrentElement(cote_droit(), *cote_d_fin)
ChangeCurrentElement(cote_gauche(), *cote_g_fin)
;}
EndIf
ForEver
EndSelect
;}
;{ Affichage
If rayon > 0
Dim image_gray.a(w+1, h+1)
IBF_GetGrayArray(image(), image_gray())
IBF_GetEdgeGray(image_gray(), rayon)
IBF_CombineArray(image(), image_gray(), @Couleur_contour)
EndIf
; dessin
IBF_DrawRotatedArray(image(), *bulle\Centre\x, *bulle\Centre\y, bulle_min\x - vect_offset + 1, bulle_min\y - vect_offset + 1, *bulle\angle_text, *bulle\USE_Antialisating, coef_sigmoide)
DrawingMode(#PB_2DDrawing_Default)
;}
;}
;{ libération des ressources
If *bulle\USE_CattmullRom
FreeList(*adr_pourtour\pourtour())
FreeMemory(*adr_pourtour)
EndIf
;}
EndProcedure
Procedure DrawContourControl(*bulle.BT_Bulle, *souris.POINT, eventtype.l, GD.l, DRAW = #True)
PAS_FAIT = #True
Static CLIC.l = -1
SetGadgetAttribute(GD, #PB_Canvas_Cursor, #PB_Cursor_Default)
ForEach *bulle\pourtour()
If PAS_FAIT
If eventtype = #PB_EventType_MouseMove
If CLIC = -1
dx = *bulle\Centre\x + *bulle\pourtour()\x - *souris\x
dy = *bulle\Centre\y + *bulle\pourtour()\y - *souris\y
If Sqr(dx * dx + dy * dy) =< 5
SetGadgetAttribute(GD, #PB_Canvas_Cursor, #PB_Cursor_Arrows)
PAS_FAIT = #False
EndIf
ElseIf ListIndex(*bulle\pourtour()) = CLIC
*bulle\pourtour()\x = *souris\x - *bulle\Centre\x
*bulle\pourtour()\y = *souris\y - *bulle\Centre\y
SetGadgetAttribute(GD, #PB_Canvas_Cursor, #PB_Cursor_Arrows)
PAS_FAIT = #False
If draw = #False
ProcedureReturn #True
EndIf
EndIf
ElseIf eventtype = #PB_EventType_LeftButtonDown
dx = *bulle\Centre\x + *bulle\pourtour()\x - *souris\x
dy = *bulle\Centre\y + *bulle\pourtour()\y - *souris\y
If Sqr(dx * dx + dy * dy) =< 5
CLIC = ListIndex(*bulle\pourtour())
SetGadgetAttribute(GD, #PB_Canvas_Cursor, #PB_Cursor_Arrows)
PAS_FAIT = #False
EndIf
ElseIf eventtype = #PB_EventType_LeftButtonUp
CLIC = -1
EndIf
EndIf
If DRAW
DrawingMode(#PB_2DDrawing_Outlined)
Circle(*bulle\Centre\x + *bulle\pourtour()\x, *bulle\Centre\y + *bulle\pourtour()\y, 5, #Red)
DrawingMode(#PB_2DDrawing_Default)
Circle(*bulle\Centre\x + *bulle\pourtour()\x, *bulle\Centre\y + *bulle\pourtour()\y, 3, #Red)
EndIf
Next
EndProcedure
;}
;{ fenêtre
WD_principale = OpenWindow(#PB_Any, 0, 0, 900, 600, "Bulles de Texte", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If WD_principale
GD_canvas = CanvasGadget(#PB_Any, 0, 0, 700, 600, #PB_Canvas_Keyboard)
GD_Editor = EditorGadget(#PB_Any, 700, 0, 200, 100)
TextGadget(#PB_Any, 705, 120, 200, 20, "Taille du Texte")
GD_Taille = TrackBarGadget(#PB_Any, 705, 140, 190, 20, 5, 30)
TextGadget(#PB_Any, 705, 160, 200, 20, "Angle du Texte")
GD_angle = TrackBarGadget(#PB_Any, 705, 180, 190, 20, 0, 350)
TextGadget(#PB_Any, 705, 200, 200, 20, "Zoom bulle")
GD_marge = TrackBarGadget(#PB_Any, 705, 220, 190, 20, 10, 150)
TextGadget(#PB_Any, 705, 240, 240, 20, "Rayon Contour")
GD_rayon = TrackBarGadget(#PB_Any, 705, 260, 190, 20, 0, 10)
TextGadget(#PB_Any, 705, 300, 200, 20, "Texte RGBA")
GD_couleurT_R = TrackBarGadget(#PB_Any, 705, 320, 190, 20, 0, 255)
GD_couleurT_G = TrackBarGadget(#PB_Any, 705, 340, 190, 20, 0, 255)
GD_couleurT_B = TrackBarGadget(#PB_Any, 705, 360, 190, 20, 0, 255)
GD_couleurT_A = TrackBarGadget(#PB_Any, 705, 380, 190, 20, 0, 255)
TextGadget(#PB_Any, 705, 400, 200, 20, "Contour RGBA")
GD_couleurC_R = TrackBarGadget(#PB_Any, 705, 420, 190, 20, 0, 255)
GD_couleurC_G = TrackBarGadget(#PB_Any, 705, 440, 190, 20, 0, 255)
GD_couleurC_B = TrackBarGadget(#PB_Any, 705, 460, 190, 20, 0, 255)
GD_couleurC_A = TrackBarGadget(#PB_Any, 705, 480, 190, 20, 0, 255)
GD_Check_Catmull = CheckBoxGadget(#PB_Any, 705, 500, 200, 20, "Utiliser le lissage")
GD_Check_AntiAliasing = CheckBoxGadget(#PB_Any, 705, 520, 200, 20, "Anti-aliasser la Police")
GD_LoadFONT = ButtonGadget(#PB_Any, 705, 550, 190, 20, "Changer de Police")
GD_Coef_Sigmoide = TrackBarGadget(#PB_Any, 705, 580, 190, 20, 0, 100)
AddKeyboardShortcut(WD_principale, #PB_Shortcut_Escape, 0)
SetGadgetState(GD_marge, 100)
SetGadgetState(GD_angle, 330)
SetGadgetState(GD_rayon, 3)
SetGadgetState(GD_couleurT_R, 80)
SetGadgetState(GD_couleurT_G, 255)
SetGadgetState(GD_couleurT_B, 0)
SetGadgetState(GD_couleurT_A, 255)
SetGadgetState(GD_couleurC_R, 170)
SetGadgetState(GD_couleurC_G, 0)
SetGadgetState(GD_couleurC_B, 200)
SetGadgetState(GD_couleurC_A, 255)
SetGadgetState(GD_Check_Catmull, #True)
SetGadgetState(GD_Check_AntiAliasing, #True)
SetFocus_(GadgetID(GD_angle))
EndIf
font_display = LoadFont(#PB_Any, "Arial Black", 12)
;}
;{ création de la bulle de test
*bulle.bt_Bulle = BT_InitBulleText(#True)
If ReadFile(0, "Loresdfm Ipsum.txt")
*bulle\text = ""
Repeat
*bulle\text = *bulle\text + ReadString(0)
If Eof(0) = 0
*bulle\text + #CR$
EndIf
Until Eof(0)
Else
*bulle\text = "Interloqué, David ne sait pas quoi répondre. "+
"En effet, il connaît un certain Prélude : lui."+
"C'était le pseudo qu'il utilisait dans sa jeunesse "+
"d'informaticien. Tout ses amis de l'époque le connaissaient "+
"sous ce nom. Il l'avait utilisé une fois ou deux pour signer "+
"les logiciels qu'il avait piraté. Mais jamais un logiciel "+
"important et encore moins un logiciel top secret. "+
"C'était également le surnom qu'il utilisait à la faculté." + #CR$ + #CR$ +
"Les deux gardes du corps personnels de David le prirent "+
"par le bras et suivirent le général. Les militaires s'étaient "+
"mis au « garde à vous » sur les côtés du couloir. "+
"Celui-ci menait à un ascenseur. Le général inséra à "+
"nouveau son badge et la porte s'ouvrit. Il y montèrent tous les quatre. "+
"Il n'y avait pas de niveau d'indiqué."
EndIf
*bulle\Centre\x = 400
*bulle\Centre\y = 300
*bulle\color = #White
AddElement(*bulle\pourtour()) : *bulle\pourtour()\x = 0 : *bulle\pourtour()\y = -200
AddElement(*bulle\pourtour()) : *bulle\pourtour()\x = -100 : *bulle\pourtour()\y = -150
AddElement(*bulle\pourtour()) : *bulle\pourtour()\x = -80 : *bulle\pourtour()\y = 110
AddElement(*bulle\pourtour()) : *bulle\pourtour()\x = 50 : *bulle\pourtour()\y = 120
AddElement(*bulle\pourtour()) : *bulle\pourtour()\x = 150 : *bulle\pourtour()\y = -125
;{ centrage vite fait
c.POINT
ForEach *bulle\pourtour()
c\x + *bulle\pourtour()\x
c\y + *bulle\pourtour()\y
Next
c\x / ListSize(*bulle\pourtour())
c\y / ListSize(*bulle\pourtour())
ForEach *bulle\pourtour()
*bulle\pourtour()\x - c\x
*bulle\pourtour()\y - c\y
Next
;}
SetGadgetText(GD_Editor, *bulle\text)
PostEvent(#PB_Event_Gadget, WD_principale, GD_Editor, #PB_EventType_Change)
font_size = 15
font_name.s = "Arial"
font_style = 0
reload_font = #True
SetGadgetState(GD_Taille, font_size)
;}
Define mouse.POINT
Repeat
event = WaitWindowEvent()
;{ event
If event = #PB_Event_Menu
If EventMenu() = 0
event = #PB_Event_CloseWindow
EndIf
ElseIf event = #PB_Event_Gadget
If EventGadget() = GD_Editor
If EventType() = #PB_EventType_Change
*bulle\text = GetGadgetText(GD_Editor)
redraw = #True
reload_font = #True
EndIf
ElseIf EventGadget() = GD_Taille
redraw = #True
font_size = GetGadgetState(GD_Taille)
reload_font = #True
ElseIf EventGadget() = GD_LoadFONT
redraw = #True
If FontRequester(font_name, font_size, 0, font_style)
font_name = SelectedFontName()
font_style = SelectedFontStyle()
EndIf
reload_font = #True
ElseIf EventGadget() = GD_Coef_Sigmoide
redraw = #True
ElseIf EventGadget() = GD_angle
redraw = #True
ElseIf EventGadget() = GD_marge
redraw = #True
ElseIf EventGadget() = GD_rayon
redraw = #True
ElseIf EventGadget() = GD_canvas
canvas_eventtype = EventType()
mouse\x = GetGadgetAttribute(GD_canvas, #PB_Canvas_MouseX)
mouse\y = GetGadgetAttribute(GD_canvas, #PB_Canvas_MouseY)
If DrawContourControl(*bulle, @mouse, canvas_eventtype, GD_canvas, #False)
redraw = #True
EndIf
ElseIf EventGadget() = GD_couleurT_R Or EventGadget() = GD_couleurT_G Or EventGadget() = GD_couleurT_B
redraw = #True
*bulle\color = RGBA(GetGadgetState(GD_couleurT_R), GetGadgetState(GD_couleurT_G), GetGadgetState(GD_couleurT_B), GetGadgetState(GD_couleurT_A))
ForEach *bulle\BF_Text\Text()
*bulle\BF_Text\Text()\couleur = *bulle\color
Next
ElseIf EventGadget() = GD_couleurC_R Or EventGadget() = GD_couleurC_G Or EventGadget() = GD_couleurC_B Or EventGadget() = GD_couleurC_A
redraw = #True
ElseIf EventGadget() = GD_Check_Catmull
redraw = #True
*bulle\USE_CattmullRom = GetGadgetState(GD_Check_Catmull)
ElseIf EventGadget() = GD_Check_AntiAliasing
redraw = #True
*bulle\USE_Antialisating = GetGadgetState(GD_Check_AntiAliasing)
EndIf
EndIf
;}
;{ reload font
If reload_font
reload_font = #False
If IsFont(font_test) : FreeFont(font_test) : EndIf
font_test = LoadFont(#PB_Any, font_name, font_size, font_style)
*font.IBF_Font = BF_LoadFont(font_name, font_size, font_style)
FreeList(*bulle\BF_Text\Text())
FreeMemory(*bulle\BF_Text)
*bulle\color = RGBA(GetGadgetState(GD_couleurT_R), GetGadgetState(GD_couleurT_G), GetGadgetState(GD_couleurT_B), GetGadgetState(GD_couleurT_A))
*bulle\BF_Text = BF_NewText(*bulle\text, *font, *bulle\color)
EndIf
;}
;{ redraw
If redraw
*bulle\angle_text = Radian(GetGadgetState(GD_angle))
StartDrawing(CanvasOutput(GD_canvas))
DrawingFont(FontID(font_test))
Box(0, 0, 700, 600, RGB(200, 200, 200))
*bulle\Centre\x = 150
DrawContourControl(*bulle, @mouse, canvas_eventtype, GD_canvas)
time = ElapsedMilliseconds()
*bulle\Centre\x = 530
BT_DrawBulleText(*bulle, GetGadgetState(GD_marge) / 100)
time = ElapsedMilliseconds() - time
time2 = ElapsedMilliseconds()
*bulle\Centre\x = 150
BT_DrawBulleText_(*bulle, GetGadgetState(GD_marge) / 100, GetGadgetState(GD_rayon), RGBA(GetGadgetState(GD_couleurC_R), GetGadgetState(GD_couleurC_G), GetGadgetState(GD_couleurC_B), GetGadgetState(GD_couleurC_A)), GetGadgetState(GD_Coef_Sigmoide) / 100)
time2 = ElapsedMilliseconds() - time2
DrawingFont(FontID(font_display))
DrawingMode(#PB_2DDrawing_Transparent)
DrawText(480, 10, "DrawRotatedText()")
DrawText(530, 30, Str(time) + " ms")
DrawText(100, 10, "Procedure Perso")
DrawText(150, 30, Str(time2) + " ms")
DrawText(10, OutputHeight() - 30, "[Haut / Bas] pour varier la taille de la police")
StopDrawing()
redraw = #False
EndIf
;}
Until event = #PB_Event_CloseWindow
End