Hi Guys, i succeeded to use gdiplus to draw a rainbow text on a window/control DC but i´m failing to try to understand why is it working:
The resultant effect is this:
(https://i.ibb.co/X5f27zC/bxbfg-Image8.png) (https://imgbb.com/)
Which is the same as
(https://i.stack.imgur.com/GDXCl.png)
Taken at: https://stackoverrun.com/ru/q/1858879
Also there are some good examples made by Mikl here (But, it is for 64 bits and not 32):
https://board.flatassembler.net/topic.php?p=205372
https://board.flatassembler.net/topic.php?p=205373
and
https://wasm.in/threads/rectf-pointf-kak-realizovat.32727
On wasm forum the example05.zip is like this:
(https://wasm.in/attachments/00-png.3356/)
But it is not working and also is in 64Bits, instead 32 :sad:
Also. Mikl seem to do an outline text, but how to do it ? I mean, to display something like:
(https://i.stack.imgur.com/WCAit.png)
MY version i s working, but i´m failing to understand why.
What i did so far was:
; Variables and macros used:
[Pointf:
Pointf.X: F$ 10.0;.0
Pointf.Y: F$ 100.0;.0
Pointf.W: F$ 0 ; ??? What is this ???
Pointf.H: F$ 0] ; ??? What is this ???
; Macro GDIP_ARGB
[GDIP_ARGB | (#4 or (#3 shl 8) or (#2 shl 16) or (#1 shl 24))]
;;
hSrcDC(in) - The DC of teh window/control where the text should appear
pFontName(in) - Point a Ansi Null Terminated String representing the font name
pText(in) - Point a Ansi Null Terminated String representing the Text to be placed onto the DC
;;
Proc GdiTextPaint:
Arguments @hSrcDC, @pFontName, @pText
Local @pGraphics, @pFontFamily, @hStatus, @pFont, @pBlackBrush, @nativeFormat, @FontSize, @hGdiPlusStringFormat
Structure @FontNameWDis (&MAX_PATH*2)
Uses ecx, edx, edi
finit
mov D@FontSize 24
lea eax D@FontSize
fild D@FontSize | fstp F@FontSize
call 'Rosmem.ZeroMemory' D@FontNameWDis, (&MAX_PATH*2) ; Clean up the Variable used for the font name
lea eax D@pGraphics
call 'gdiplus.GdipCreateFromHDC' D@hSrcDC, eax
mov D@hStatus eax
call 'kernel32.MultiByteToWideChar' &CP_ACP, 0, D@pFontName, 0-1, D@FontNameWDis, (&MAX_PATH-1)
; quality mode
call 'gdiplus.GdipSetTextRenderingHint' D@pGraphics, TEXTRENDERINGHINT_ANTIALIAS
; Create the font
lea eax D@pFontFamily
call 'gdiplus.GdipCreateFontFamilyFromName' D@FontNameWDis, &NULL, eax
If_And eax = &S_OK, D@pFontFamily <> 0
lea eax D@pFont
call 'gdiplus.GdipCreateFont' D@pFontFamily, D@FontSize, (GDIP_FONT_STYLE_ITALIC+GDIP_FONT_STYLE_UNDERLINE), GDIP_UNIT_POINT, eax
call 'gdiplus.GdipDeleteFontFamily' D@pFontFamily
End_If
; create a gradient text
lea eax D@pBlackBrush
call GdipCreateGradientbrush 10, 100, 100, 100, {GDIP_ARGB 255, 255, 0, 0}, {GDIP_ARGB 255, 255, 255, 0}, eax
;;
; Create a solid brush . Ok to do without the rainbow effect.
lea eax D@pBlackBrush
call 'gdiplus.GdipCreateSolidFill' {GDIP_ARGB 255, 0, 0, 190}, eax
;;
; Draw the string
call 'RosMem.FastZeroMem' D@FontNameWDis, (&MAX_PATH*2)
call 'kernel32.MultiByteToWideChar' &CP_ACP, 0, D@pText, 0-1, D@FontNameWDis, (&MAX_PATH-1)
; format the string
lea eax D@hGdiPlusStringFormat
call 'gdiplus.GdipCreateStringFormat' 0 , &LANG_NEUTRAL, eax
call 'gdiplus.GdipSetStringFormatAlign' D@hGdiPlusStringFormat, GDIPLUS_STRINGALIGNMENT_NEAR;GDIPLUS_STRINGALIGNMENT_CENTER
call 'GDIPLUS.GdipSetStringFormatLineAlign' D@hGdiPlusStringFormat, GDIPLUS_STRINGALIGNMENT_NEAR;GDIPLUS_STRINGALIGNMENT_CENTER
; Draw the string
call 'gdiplus.GdipDrawString' D@pGraphics, D@FontNameWDis, 0-1, D@pFont, Pointf, D@hGdiPlusStringFormat, D@pBlackBrush
; Cleanup
If D@pFont <> 0
call 'gdiplus.GdipDeleteFont' D@pFont
End_If
If D@pBlackBrush <> 0
call 'gdiplus.GdipDeleteBrush' D@pBlackBrush
End_If
If D@pGraphics <> 0
call 'gdiplus.GdipDeleteGraphics' D@pGraphics
End_If
EndP
; GdipCreateGradientbrush is the main function responsible to create the gradient text effect
[RECT.leftDis 0
RECT.topDis 4
RECT.rightDis 8
RECT.bottomDis 12]
; LineGradient Mode
[LINEAR_GRADIENTMODE_HORIZONTAL 0
LINEAR_GRADIENTMODE_VERTICAL 1
LINEAR_GRADIENTMODE_FORWARDDIAGONAL 2
LINEAR_GRADIENTMODE_BACKWARDDIAGONAL 3]
; WarpMode constants
[WARPMODE_PERSPECTIVE 0
WARPMODE_BILINEAR 1]
Proc GdipCreateGradientbrush:
Arguments @XPos, @YPos, @Width, @Height, @Color1, @Color2, @lineGradient
Structure @RECT 16, @RECT.leftDis 0, @RECT.topDis 4, @RECT.rightDis 8, @RECT.bottomDis 12
Uses ecx, edx
mov ecx D@RECT
mov eax D@XPos | mov D$ecx+RECT.leftDis eax
mov eax D@YPos | mov D$ecx+RECT.topDis eax
mov eax D@Width | mov D$ecx+RECT.rightDis eax
mov eax D@Height | mov D$ecx+RECT.bottomDis eax
call 'gdiplus.GdipCreateLineBrushFromRectI' D@RECT, D@Color1, D@Color2, LINEAR_GRADIENTMODE_HORIZONTAL, WARPMODE_PERSPECTIVE, D@lineGradient
EndP
Example of usage:
; the following function can be placed in WM_PAINT message
call GdiTextPaint D@hMemDC, {B$ "Arial", 0}, {B$ "Hello World!", 0} ; must be placed before the bitblt to avoid flicker
call 'GDI32.BitBlt' D@hDC, 0, 0, D@Width, D@Height, D@hMemDC, 0, 0, &SRCCOPY
At GdipCreateGradientbrush what is being passed onto GdipCreateLineBrushFromRectI ??? I mean, the X, YPos seems to be the same ones as used in Pointf structure from GdipDrawString but....what are the width and height from this structure? Should it be always set to 0 ???
Also....what are the Width and Height in GdipCreateLineBrushFromRectI ? Are they the width/height of the whole control/window dc or it can be any aleatory value ? On this example, i only succeeded to make it work setting Width = 100 Height = 100 and keeping X = 10, Y = 100
Note:
Btw...The goal (once it is fixed) is try to port the below to masm/RosAsm etc to we do things like these:
(https://www.codeproject.com/KB/GDI-plus/OutlineText/century_gothic_3d1.png)
(https://www.codeproject.com/KB/GDI-plus/OutlineText/impact_italic1.png)
(https://www.codeproject.com/KB/GDI-plus/OutlineText/matisse_double_outline1.png)
As described in: https://www.codeproject.com/Articles/42529/Outline-Text
Btw....
Another question
How do i get the width and height of the text and limit it to a certain area ?
Say i want he text to wrap inside the width of the control, how to determine the maximum width of the text and how to recalculate the height ?
Like this:
Say, i have a dc from a window/control measuring
Width = 100
Height = 100
And my text is "Hello world, i´m typing this text to calculate the full length of this". Now let´s say that this text extrapolates the maximum width of 100. At the end it will need to be displayed as:
"Hello world, i´m typing this text to calculate <-----Reached limit of 100 width
the full length of this" <--- But what is the new height ????
Using gradient brushes for the text should give a rainbow effect, i guess the direction of the gradient will determine how it appears, plus also maybe the size of the brush pattern - if it repeats it might look odd, or if it stretches the gradient to fit text it might look weird.
I think using paths (GraphicPath) is the way to achieve the outline effect.In gdi you can use DT_CALCRECT flag in DrawText to calc the area needed for text wrapping. In Gdi+ I guess there will be something similar
Quote from: fearless on November 25, 2020, 12:00:07 AM
Using gradient brushes for the text should give a rainbow effect, i guess the direction of the gradient will determine how it appears, plus also maybe the size of the brush pattern - if it repeats it might look odd, or if it stretches the gradient to fit text it might look weird.
I think using paths (GraphicPath) is the way to achieve the outline effect.In gdi you can use DT_CALCRECT flag in DrawText to calc the area needed for text wrapping. In Gdi+ I guess there will be something similar
In Gdi+, the direction is given from the GdipCreateLineBrushFromRectI function using these equates as the 4th parameeter
; LineGradient Mode
[LINEAR_GRADIENTMODE_HORIZONTAL 0
LINEAR_GRADIENTMODE_VERTICAL 1
LINEAR_GRADIENTMODE_FORWARDDIAGONAL 2
LINEAR_GRADIENTMODE_BACKWARDDIAGONAL 3]
About using DrawText + DT_CALCRECT , maybe works using gdipmeasurestring ?
Some time ago, I did this text effect: text with dynamic plasma. Pure and brute GDI :thumbsup:
Quote from: caballero on November 25, 2020, 09:08:18 PM
Some time ago, I did this text effect: text with dynamic plasma. Pure and brute GDI :thumbsup:
Great work, caballero. Thank you. I´l take a look at the code.
One thing....I saw you seems to use the text as a mask, right ? But... couldnt´it also use the generated images as a texture for the font to be used as a brush with Gdi+ ?
I mean, i´m currently fixing some functions to use Gdi+ to do effects in text and maybe use a texture over the gdi+ text itself, but don´t know if it is possible to do yet.
If I'm not wrong it could be done in GDI:
http://abreojosensamblador.epizy.com/?Tarea=6&SubTarea=6#VariasGDIEjemplo
See the last example: PintarWC07e
And also with GDI+
http://abreojosensamblador.epizy.com/?Tarea=6&SubTarea=6#GDIPElipses
Thank you a lot, caballero, i´ll take a look at the code.
Today i succeeded to create the outline effect as described here: https://www.codeproject.com/Articles/42529/Outline-Text
But i´m having a small problem with the rectangle that encloses the text, since it´s not being attached to the bottom of the text as below
(https://i.ibb.co/ypdwx0b/FGHFDGFDSImage2.png) (https://ibb.co/YXPzV2q)
; Draw the rectangle that encloses the text.
If D$edi+GdipTextNfo.ShowTextRectDis <> &FALSE ; Check the flag responsible enable/disable the rectangle
; The rectangle area must be in float, because it is the same to be used in GdipDrawString
fld1 | fstp F@PenTextRectWidth
lea eax D@pPen
call 'gdiplus.GdipCreatePen1' D$edi+GdipTextNfo.FontColorDis, F@PenTextRectWidth, GDIP_UNIT_PIXEL, eax
call 'gdiplus.GdipDrawRectangle' D@pGraphics, D@pPen, F@BoundingBox.XDis, F@BoundingBox.YDis, F@BoundingBox.WidthDis, F@BoundingBox.HeightDis
End_If
But...without the text effect the rectangle is ok
(https://i.ibb.co/3rnyf1r/FGHFDGFDSImage2.png) (https://ibb.co/FxFbs6x)
I´ll try to fix that. I don´t know if i need to set the rectangle routine before the text effect or is something in the text effect itself that is ruining the height
I´m writing all the code in separated parts to avoid any gdi leaking. So, we can have an isolate function to work only with the background DC color, other that works only for the loaded images and other for the text
Edited:
Fixed it.. This is the current behaviour of the tests i´m doing
https://streamable.com/95oh2w (https://streamable.com/95oh2w)
Quote from: guga on November 28, 2020, 08:50:14 AM
Thank you a lot, caballero, i´ll take a look at the code.
Today i succeeded to create the outline effect as described here: https://www.codeproject.com/Articles/42529/Outline-Text
But i´m having a small problem with the rectangle that encloses the text, since it´s not being attached to the bottom of the text as below
(https://i.ibb.co/ypdwx0b/FGHFDGFDSImage2.png) (https://ibb.co/YXPzV2q)
; Draw the rectangle that encloses the text.
If D$edi+GdipTextNfo.ShowTextRectDis <> &FALSE ; Check the flag responsible enable/disable the rectangle
; The rectangle area must be in float, because it is the same to be used in GdipDrawString
fld1 | fstp F@PenTextRectWidth
lea eax D@pPen
call 'gdiplus.GdipCreatePen1' D$edi+GdipTextNfo.FontColorDis, F@PenTextRectWidth, GDIP_UNIT_PIXEL, eax
call 'gdiplus.GdipDrawRectangle' D@pGraphics, D@pPen, F@BoundingBox.XDis, F@BoundingBox.YDis, F@BoundingBox.WidthDis, F@BoundingBox.HeightDis
End_If
But...without the text effect the rectangle is ok
(https://i.ibb.co/3rnyf1r/FGHFDGFDSImage2.png) (https://ibb.co/FxFbs6x)
I´ll try to fix that. I don´t know if i need to set the rectangle routine before the text effect or is something in the text effect itself that is ruining the height
I´m writing all the code in separated parts to avoid any gdi leaking. So, we can have an isolate function to work only with the background DC color, other that works only for the loaded images and other for the text
Edited:
Fixed it.. This is the current behaviour of the tests i´m doing
https://streamable.com/95oh2w (https://streamable.com/95oh2w)
I worked much with button controls used them for texts instead of GDI drawing text,there are customdraw on windows controls too,what about a text control to use for text(LABEL) instead of mess with GDI+?
instead of drawtext,its invoke sendmessage,hwndbutton,WM_SETTEXT,NULL,ADDR text
Quote from: daydreamer on November 29, 2020, 12:04:32 AM
I worked much with button controls used them for texts instead of GDI drawing text,there are customdraw on windows controls too,what about a text control to use for text(LABEL) instead of mess with GDI+?
instead of drawtext,its invoke sendmessage,hwndbutton,WM_SETTEXT,NULL,ADDR text
Hi Daydreamer. Using customdraw could be an alternative for controls, but i´m not there yet. I´m not sure i understood what you told about using text control...you mean the lables inside controls is that it ? If is that so, perhaps it works with customdraw, but it will require more functions that are needed i suppose.
The problem of using customdraw is that i´ll need to create several functions to place in different parts of the code, rather then 1 or two only to be used in certain windows messages such as WM_CREATE, WM_INITDIALOG and WM_PAINT. I´m trying to do it in a sort of a dll library where we can have full control on what´s being done with less effort as possible.
I'm trying to lean a bit of the gdiplus apis, in order to create alternatives ways of adding some effects to windows (or even a image editor app) The goal is to create less functions as possible that enables to control everything. For example, to display images onto a DC (from a window or a control) without leaking, all is needed is 1 single function to setup a structure to be used on another function that needs to be located in WM_PAINT message. The same goes for Texts. Gdi+ can handle multiline texts too.
So, basically at the end we are using only 2 functions. 1 in WM_CREATE (or WM_INITDIALOG) and other in the main painting message WM_PAINT
Take a look at this other test i made using a gif animated as the background of a text: https://streamable.com/e4mhcp :smiley: :smiley:
Add those effects to text using gdi plus can be done with GdipDrawPath followed by GdipFillPath. For what i saw so far, there´s no leakings
great project :thumbsup:
any kind of animation,TIMER proc sending update screen combined with PAINT proc vs TIMER proc using GetDC/rasterize code/releaseDC instead maybe worth trying whats better?
cool video editor adding japanese subtext caps or whatever subtext you like could be end result,also have interest in anime/learning foreign languages,double subtext japanese/english helps alot understanding what is said reading English subtext,while testing/exercise japanese skill reading Japanese subtext
Quote from: daydreamer on November 29, 2020, 08:47:16 AM
great project :thumbsup:
any kind of animation,TIMER proc sending update screen combined with PAINT proc vs TIMER proc using GetDC/rasterize code/releaseDC instead maybe worth trying whats better?
cool video editor adding japanese subtext caps or whatever subtext you like could be end result,also have interest in anime/learning foreign languages,double subtext japanese/english helps alot understanding what is said reading English subtext,while testing/exercise japanese skill reading Japanese subtext
Hi Daydreamer
Many tks :thumbsup: :thumbsup:
The animaton is done only once without any timerproc involved. I created a function called SetAnimationInterval, which calculates the amount of time (in ms) to be passed onto WM_TIMER message from a given Frame Rate (29.970, 25, 50, 60 or whatever other is needed). It converts FPS (Frame Rate) to miliseconds and use SetTimer to create the proper timer id (without the needs of any timerproc callback routine). This part of the code is done as:
Proc SetAnimationInterval:
Arguments @hWnd, @IdEvent, @pFrameRate, @KeyFrame
Local @Seconds
Uses ecx, edx
finit
mov D@Seconds 1000
mov eax D@pFrameRate
fild D@Seconds | fdiv F$eax
mov eax D@KeyFrame | On eax = 0, mov eax 1
mov D@Seconds eax | fimul F@Seconds
lea eax D@Seconds
fistp D$eax
mov eax D$eax
On eax < &USER_TIMER_MINIMUM, mov eax &USER_TIMER_MINIMUM
On eax > &USER_TIMER_MAXIMUM, mov eax &USER_TIMER_MAXIMUM
mov D@Seconds eax
call 'user32.SetTimer' D@hWnd, D@IdEvent, eax, 0
mov eax D@Seconds
EndP
The above function is used internally on a single function i made to work with whatever images you need (I named it as: GdipCreateImageInfo api) . All it is needed is feed a proper structure used on this Api and place it in WM_CREATE or WM_INITDIALOG. And the to adjust the frames all is necessary is setup the current frame in WM_TIMER as:
...Else_If D@Message = &WM_TIMER
call 'USER32.InvalidateRect' D@Addressee, 0, 0 ; <--- Just to clean up the screen if needed
If D$GdipImageNfo1.TotalFrames > 1 ; ------> A member of the structure "GdipImageNfo" used in GdipCreateImageInfo. If the image have more then 1 frame (Animated gif or tiff), it wil increment the counter to use the next frame inside WM_PAINT
inc D$GdipImageNfo1.CurFramePos ; Update the current frame position
End_If
If D$GdipImageNfo2.TotalFrames > 1
inc D$GdipImageNfo2.CurFramePos
End_If
On it´s turn, to get the next frame it is also done with one single api i labeled as: "GdipImgPaint". Inside this api it will locate the TotalFrames member of the structure GdipImageNfo and will point to the next frame, without needing to do a lot of calculations. This function is as:
Proc GdipImgPaint::
Arguments @hDC, @pGdiImgNfo
Local @pGraphics, @CurXPos, @CurYPos, @ImgWidth, @ImgHeight, @ImgRatio, @Return
Uses ecx, edx, edi
lea eax D@pGraphics
call 'gdiplus.GdipCreateFromHDC' D@hDC, eax
On eax <> &S_OK, ExitP
mov edi D@pGdiImgNfo
mov eax D$edi+GdipImageNfo.TotalFramesDis ; <------------------- get the next frame oif we are dealing with animated gif or tiff. The frame is updated in WM_TIMER
.If eax > 1
If D$edi+GdipImageNfo.CurFramePosDis => eax
mov D$edi+GdipImageNfo.CurFramePosDis 0
End_If
call 'gdiplus.GdipImageSelectActiveFrame' D$edi+GdipImageNfo.pGdiImageDis, FRAME_DIMENSION_TIME, D$edi+GdipImageNfo.CurFramePosDis
If eax <> &S_OK
mov D@Return eax
call 'gdiplus.GdipDeleteGraphics' D@pGraphics
mov eax D@Return
ExitP
End_If
.End_If
mov eax D$edi+GdipImageNfo.ImgXPosDis | mov D@CurXPos eax
mov eax D$edi+GdipImageNfo.ImgYPosDis | mov D@CurYPos eax
mov eax D$edi+GdipImageNfo.DisplayTypeDis
.If eax = GDIP_DRAWIMG_DEFAULT
mov eax D$edi+GdipImageNfo.ImgWidthDis | mov D@ImgWidth eax
mov eax D$edi+GdipImageNfo.ImgHeightDis | mov D@ImgHeight eax
.Else_If eax = GDIP_DRAWIMG_FILL
mov D@CurXPos 0
mov D@CurYPos 0
mov eax D$edi+GdipImageNfo.CtrlWidthDis | mov D@ImgWidth eax
mov eax D$edi+GdipImageNfo.CtrlHeightDis | mov D@ImgHeight eax
.Else_If eax = GDIP_DRAWIMG_AUTO_FILL_HORZ
mov D@CurXPos 0
mov eax D$edi+GdipImageNfo.CtrlWidthDis | mov D@ImgWidth eax
mov eax D$edi+GdipImageNfo.ImgHeightDis | mov D@ImgHeight eax
.Else_If eax = GDIP_DRAWIMG_AUTO_FILL_VERT
mov D@CurYPos 0
mov eax D$edi+GdipImageNfo.CtrlHeightDis | mov D@ImgHeight eax
mov eax D$edi+GdipImageNfo.ImgWidthDis | mov D@ImgWidth eax
.Else_If eax = GDIP_DRAWIMG_AUTO_VERT
mov D@CurYPos 0
mov eax D$edi+GdipImageNfo.CtrlHeightDis | mov D@ImgHeight eax
; Ratio = ImgWidth/ImgHeight
; New width = Ratio*CtrlHeight
lea eax D@ImgWidth;@ImgRatio
;fild F$edi+GdipImageNfo.ImgWidthDis | fidiv F$edi+GdipImageNfo.ImgHeightDis | fimul F$edi+GdipImageNfo.CtrlWidthDis | fistp F$eax
fild F$edi+GdipImageNfo.CtrlWidthDis | fidiv F$edi+GdipImageNfo.CtrlHeightDis | fimul F$edi+GdipImageNfo.ImgWidthDis | fistp F$eax
.Else_If eax = GDIP_DRAWIMG_AUTO_HORZ
mov D@CurXPos 0
mov eax D$edi+GdipImageNfo.CtrlWidthDis | mov D@ImgWidth eax
lea eax D@ImgHeight
fild F$edi+GdipImageNfo.CtrlHeightDis | fidiv F$edi+GdipImageNfo.CtrlWidthDis | fimul F$edi+GdipImageNfo.ImgHeightDis | fistp F$eax
.Else
mov eax D$edi+GdipImageNfo.CtrlWidthDis | mov D@ImgWidth eax
mov eax D$edi+GdipImageNfo.CtrlHeightDis | mov D@ImgHeight eax
.End_If
call 'gdiplus.GdipDrawImageRectI' D@pGraphics, D$edi+GdipImageNfo.pGdiImageDis, D@CurXPos, D@CurYPos, D@ImgWidth, D@ImgHeight
If eax <> &S_OK
mov D@Return eax
call 'gdiplus.GdipDeleteGraphics' D@pGraphics
mov eax D@Return
Else
call 'gdiplus.GdipDeleteGraphics' D@pGraphics
End_If
EndP
The above function is used inside WM_PAINT. Currently on this preliminary tests, i´m using 3 main Apis to work with images and text passing them through WM_PAINT such as:
___________________________________________________________________________
(...)
...Else_If D@Message = &WM_PAINT
call On_WmPaintIconRsrc D@Addressee
(...)
___________________________________________________________________________
Proc On_WmPaintIconRsrc:
Arguments @Adressee
Local @hDC
Structure @PAINTSTRUCT 64, @PAINTSTRUCT.hdcDis 0
Uses ecx, edx, edi
call 'User32.BeginPaint' D@Adressee, D@PAINTSTRUCT
mov D@hDC eax
call GdipImageDraw D@Adressee, D@hDC
call 'USER32.EndPaint' D@Adressee, D@PAINTSTRUCT
EndP
___________________________________________________________________________
Proc GdipImageDraw:
Arguments @Adressee, @hDC
Local @ctx, @hMemDC, @hbr, @Width, @Height, @XPos, @YPos
Structure @RECT 16, @RECT.leftDis 0, @RECT.topDis 4, @RECT.rightDis 8, @RECT.bottomDis 12
Uses ecx, edx, edi
call 'GDI32.SaveDC' D@hDC | mov D@ctx eax
lea eax D@Width
lea ecx D@Height
call 'FastCRT.CreateWorkingDC' D@Adressee, eax, ecx, {RGB 47 47 47}
mov D@hMemDC eax
mov D@XPos 0
mov D@YPos 0
call 'FastCRT.GdipImgPaint' D@hMemDC, GdipImageNfo2
call 'FastCRT.GdipImgPaint' D@hMemDC, GdipImageNfo1
; must be placed before the bitblt to avoid flicker
call GdiTextPaint D@hMemDC, GdipTextNfo1
call 'GDI32.BitBlt' D@hDC, 0, 0, D@Width, D@Height, D@hMemDC, 0, 0, &SRCCOPY
call 'GDI32.DeleteDC' D@hMemDC
call 'GDI32.RestoreDC' D@hDC, D@ctx
EndP
___________________________________________________________________________
Once i succeed to fix this text function, i´ll try to create one single GdipImageDraw function to use as a dll for everything (Images texts and effects). Maybe labeling it as: GdipImageDrawEx or something. So i can use it simple as:
Proc On_WmPaintIconRsrc:
Arguments @Adressee;, @pFile, @Filesize
Local @hDC
Structure @PAINTSTRUCT 64, @PAINTSTRUCT.hdcDis 0
Uses ecx, edx, edi
call 'User32.BeginPaint' D@Adressee, D@PAINTSTRUCT
mov D@hDC eax
call 'FastCRT.GdipImageDrawEx' D@Adressee, D@hDC ; <------ This is what i plan to do. So, 1 single function/api to handle everything related to the DC of a window/control. So, we can paint, use imahges, texts etc.
; Simply setting it up in WM_CREATE and pass the main function here only once. On this case the api is built for a dll i called "FastCRT" that conains lots of general usage functions.
call 'USER32.EndPaint' D@Adressee, D@PAINTSTRUCT
EndP
All of these could be useful for all on our daily needs. I´m doing this dll for general RosAsm usage, but it could also be used for masm as well...and...JJ may also like it, since he also uses GdiPlus in his projects and in masmbasic as well :azn: :azn: :azn:
Impressive :thumbsup:
"cool video editor adding japanese subtext caps or whatever subtext you like could be end result,also have interest in anime/learning foreign languages,double subtext japanese/english helps alot understanding what is said reading English subtext,while testing/exercise japanese skill reading Japanese subtext"
I forgot answering this. Very good idea, indeed. This was what motivated the guy at codeproject from where i´m biasing these functions. The main problem is that i don´t know how to write things in japanese or other Unicode Data. I mean, i would need to know the Hexadecimal values of some text written in japanese so i could be able to test the routine. Can you post the hexadecimal values of a japanese string so i can try testing it ?
Quote from: HSE on November 29, 2020, 09:32:14 AM
Impressive :thumbsup:
Tks a lot, HSE. :thumbsup: :thumbsup:
I´m fixing this to see the better way to handle those texts. Currently the GdiTextPaint function converts a Ansi String to Unicode (needed for gdi+ apis) and allocated and deallocated the memory used in Unicode strings. When we are dealing with a still image (such as jpg, bmp, png etc) there´s no problem in terms of speed or performance from those alloc/deallocs. But, when we are dealing with animated gif/tiff, it certainly slows down a bit due to the internal allocation/deallocation routines.
So, i´m thinking what could be better to do. If i allow the conversion and allocation of the necessary buffer once in WM_CREATE/WM_INITDIALOG and let to the user deallocate the memory when it is no longer needed or i let it as the way it is already. I´l give a try later to see how it works in terms of speed in animation gifs to decide either i remove those alloc/deallocs in WM_PAINT or not.
Guga, might need download language pack to show correctly
Just easy to test character sets,ascii A = 041h,use 16bit unicode and 03041h start hiragana, 030a1h start katakana,
Cjk character set starts about 04100h
For display testing purposes it's only to add 03000h, 04100h to a ascii test string
Quote from: caballero on November 25, 2020, 09:08:18 PM
Some time ago, I did this text effect: text with dynamic plasma. Pure and brute GDI :thumbsup:
Doesn't compile with VC, Gcc and PellesC. I thought C was a standard?
If you added TinyC to that list, you would have found the solution :thumbsup:. The change that must be made so that it compiles in your list is very small and I leave it as an exercise.
Trying to compile with tcc :
C:\tcc>tcc -version
tcc version 0.9.27 (x86_64 Windows)
C:\tcc>tcc PlasmaWC03.c
PlasmaWC03.c:63: error: cannot cast 'struct <anonymous>' to 'int'
The code that I had put in the zip by mistake corresponded to another demo, I suppose it can be considered an extra :bgrin:. The compiling error is due to the same, we have already talked about it in this forum. You cannot associate a structure, such as the palette, to an integer, such as the video buffer. The new version of TinyC no longer allows it, so I continue using the old one. I attach the code that should compile in any type of compiler.
Quote from: caballero on November 29, 2020, 10:14:30 PMI attach the code that should compile in any type of compiler.
Gcc:
Tmp.cpp:73:43: error: invalid conversion from 'HGDIOBJ {aka void*}' to 'HFONT' [-fpermissive]
hOFont = SelectObject (bufLogoDC, hNFont);
PellesC:
#### COMPILING PlasmaWC02b.c ####
Tmp_file.c(63): warning #2116: Local 'hPenOld' is used without being initialized.
Tmp_file.c(93): warning #2215: Conversion from 'int' to 'unsigned char'; possible loss of data or unexpected result.
Tmp_file.c(93): warning #2215: Conversion from 'int' to 'unsigned char'; possible loss of data or unexpected result.
Tmp_file.c(93): warning #2215: Conversion from 'int' to 'unsigned char'; possible loss of data or unexpected result.
Tmp_file.c(184): warning #2229: Local 'hMainDIB' is potentially used without being initialized.
Tmp_file.c(184): warning #2229: Local 'hOldDIB' is potentially used without being initialized.
Tmp_file.c(240): warning #2805: Possible violation of strict-aliasing rules.
Tmp_file.c(226): warning #2118: Parameter 'szCmdLine' is not referenced.
Tmp_file.c(225): warning #2118: Parameter 'hPrevInstance' is not referenced.
#### LINKING PlasmaWC02b.obj sub Windows with kernel32 user32 ####
POLINK: error: Unresolved external symbol '__imp__CreateCompatibleDC@4' - referenced from 'PlasmaWC02b.obj'.
POLINK: error: Unresolved external symbol '__imp__CreateDIBSection@24' - referenced from 'PlasmaWC02b.obj'.
POLINK: error: Unresolved external symbol '__imp__SelectObject@8' - referenced from 'PlasmaWC02b.obj'.
POLINK: error: Unresolved external symbol '__imp__SetBkMode@8' - referenced from 'PlasmaWC02b.obj'.
POLINK: error: Unresolved external symbol '__imp__SetTextColor@8' - referenced from 'PlasmaWC02b.obj'.
POLINK: error: Unresolved external symbol '__imp__DeleteDC@4' - referenced from 'PlasmaWC02b.obj'.
POLINK: error: Unresolved external symbol '__imp__DeleteObject@4' - referenced from 'PlasmaWC02b.obj'.
POLINK: error: Unresolved external symbol '__imp__BitBlt@36' - referenced from 'PlasmaWC02b.obj'.
POLINK: error: Unresolved external symbol '__imp__CreateSolidBrush@4' - referenced from 'PlasmaWC02b.obj'.
POLINK: error: Unresolved external symbol '__imp__CreateFontA@56' - referenced from 'PlasmaWC02b.obj'.
POLINK: fatal error: 10 unresolved external(s).
LINK ERROR
They seem like conversion problems that will need some casting or revising the functions I've used. I don't have time to check it now, so ...
Quote from: caballero on November 29, 2020, 10:14:30 PMcode that should compile in any type of compiler as long as its name contains the word "tiny"
:toothy:
I don't like the restrictions of the bigger compilers, that's why I use TinyC (besides that it produces the executables as small as an assembler.). This code only needs some castings to work in the rest. Unfortunately I don't have time to look at it now.
Quote from: jj2007 on November 29, 2020, 11:29:26 PM
Quote from: caballero on November 29, 2020, 10:14:30 PMcode that should compile in any type of compiler as long as its name contains the word "tiny"
Hi JJ.
Do you think that such routines i´m making can be useful for you ? I mean, since you uses gdi+ in masmbasic, maybe a dll containing those functions can be of some help. The only thing i didn´t do yet was creating specific functions for encoding/decoding webp files, that´s why i´m using libwebp from google (that uses vcruntime140.dll, btw)
Quote from: caballero on November 29, 2020, 11:40:52 PM
:toothy:
I don't like the restrictions of the bigger compilers, that's why I use TinyC (besides that it produces the executables as small as an assembler.). This code only needs some castings to work in the rest. Unfortunately I don't have time to look at it now.
//*(pMainDIB + p) = (miPaleta[m].Rojo<<16)|(miPaleta[m].Verde<<8)|miPaleta[m].Azul;
*(pMainDIB + p) = *(DWORD*)&miPaleta[m];
TinyC isn't an optimizing C compiler.
With PellesC v10, 9 KB
JJ, I was going to answer, but Timo did it 1st :biggrin: :biggrin: :biggrin:
Anyway, here is attached the converted routines of caballero in asm listing using https://godbolt.org, online compiler. It won´t assemble in ml.exe, but it can be converted to masm by hand :) (The logic is not hard to understand when reading the code flow from godbolt) - Or... you can do the same with Timo using Ollydbg
Routines converted:
#include <math.h>
#define cdXPos 128
#define cdYPos 128
#define cdXSize 960
#define cdYSize 600
#define cdColFondo 0 // COLOR_BTNFACE + 1
#define cdVBarTipo 0
#define cdVBtnTipo WS_VISIBLE+WS_SYSMENU+WS_MINIMIZEBOX
#define cdMainIcon 100
#define cdIdTimer 1
#define cdDosPI 6.283185307179586476925286766559
#define cdFSize 140
#define PI128 0.02454369260617025967548940143187
int waves[4][2];
double sins1[360*6], sins2[360*6], sins3[360*6], sins4[360*6];
double coss1[360*6], coss2[360*6], coss3[360*6], coss4[360*6];
int f = 0, s1off = 0, s2off = 0, s3off = 0;
int c1off = 0, c2off = 0, c3off = 0, coloff = 0;
int hLogoDIB = 0;
int *pMainDIB = 0, *pLogoDIB = 0;
unsigned char mtImagen[cdXSize*cdYSize], mtLogo [cdXSize*cdYSize];
struct stPaleta {
unsigned char Azul;
unsigned char Verde;
unsigned char Rojo;
unsigned char Alfa;
} miPaleta[256];
void CreaImagen (void) {
int i;
for (i = 0; i < cdXSize*cdYSize; i++)
mtImagen[i] = (unsigned char) *(pLogoDIB+i);
}
void pal (int col, int r, int g, int b) {
miPaleta[col].Rojo = r; miPaleta[col].Verde = g; miPaleta[col].Azul = b;
}
void grad (int col1, double r1, double g1, double b1,
int col2, double r2, double g2, double b2) {
int col, cols;
cols = col2 - col1 + 1;
double rstep, gstep, bstep, r, g, b;
rstep = (double) ((r2 - r1 + 1) / cols);
gstep = (double) ((g2 - g1 + 1) / cols);
bstep = (double) ((b2 - b1 + 1) / cols);
r = r1;
g = g1;
b = b1;
for (col = col1; col <= col2; col++) {
r += rstep;
g += gstep;
b += bstep;
if (r > 255) r = 255;
if (r < 0 ) r = 0 ;
if (g > 255) g = 255;
if (g < 0 ) g = 0 ;
if (b > 255) b = 255;
if (b < 0 ) b = 0 ;
pal (col, (int)r, (int)g, (int)b);
}
}
void makePlasma (void) {
int i, r, g, b, r1, g1, b1, r2, g2, b2;
r1 = r = rand()&255; g1 = g = rand()&255; b1 = b = rand()&255;
for (i = 0; i <= 3; i++) {
r2 = rand()&255; g2 = rand()&255; b2 = rand()&255;
grad (64 * i, r, g, b, 64 * i + 63, r2, g2, b2);
r = r2; g = g2; b = b2;
}
grad (64 * 3, r, g, b, 255, r1, g1, b1);
for (i = 0; i < 3; i++) {
waves[i][0] = rand()&255;
waves[i][1] = 360 + rand()%180;
}
for (i = 0; i <= 360*6; i++) {
sins1[i] = (double) ((double) waves[0][0] * sin((double) i / waves[0][1] * cdDosPI));
sins2[i] = (double) ((double) waves[1][0] * sin((double) i / waves[1][1] * cdDosPI));
sins3[i] = (double) ((double) waves[2][0] * sin((double) i / waves[2][1] * cdDosPI));
coss1[i] = (double) ((double) waves[0][0] * cos((double) i / waves[0][1] * cdDosPI));
coss2[i] = (double) ((double) waves[1][0] * cos((double) i / waves[1][1] * cdDosPI));
coss3[i] = (double) ((double) waves[2][0] * cos((double) i / waves[2][1] * cdDosPI));
}
}
void doPlasma (void) {
int x, y, p, m;
double cy;
s1off = (s1off + 1) % waves[0][1];
c1off = (c1off + 3) % waves[0][1];
s2off = (s2off + 3) % waves[1][1];
c2off = (c2off + 2) % waves[1][1];
s3off = (s3off + 2) % waves[2][1];
c3off = (c3off + 1) % waves[2][1];
coloff = (coloff + 1) & 255;
p = 0;
for (y = 160; y < cdYSize; y++) {
cy = coloff + coss1[y + c1off] + sins2[y + s2off] + sins3[y + s3off];
for (x = 0; x < cdXSize; x++) {
if (mtImagen[p]!=0) {
m = ((int) (cy + sins1[x + s1off] + coss2[x + c2off] + coss3[x + y + c3off]))&255;
*(pMainDIB + p) = (miPaleta[m].Rojo<<16)|(miPaleta[m].Verde<<8)|miPaleta[m].Azul;
}
p ++;
}
}
}
If you want to read from a browser, simply paste those C code in https://godbolt.org and select (X86 msvc v 19.10 - WINE)
Quote from: guga on November 29, 2020, 11:55:47 PMHi JJ.
Do you think that such routines i´m making can be useful for you ? I mean, since you uses gdi+ in masmbasic
Right now I am too busy, but I will look into it, thanks
Quote from: daydreamer on November 29, 2020, 11:18:28 AM
Guga, might need download language pack to show correctly
Just easy to test character sets,ascii A = 041h,use 16bit unicode and 03041h start hiragana, 030a1h start katakana,
Cjk character set starts about 04100h
For display testing purposes it's only to add 03000h, 04100h to a ascii test string
here is counting numbers one,two,three... exercise with output numbers combining strings+one version chinese (CJK) instead using unicode characters to express numbers
http://masm32.com/board/index.php?topic=8114.0 (http://masm32.com/board/index.php?topic=8114.0)
@Timo,yes I know TinyC isnt an optimizing compiler,but you maybe dont need that when we sometimes act as "optimizing compilers" ourselves :tongue: :biggrin:
Quote from: caballero on November 29, 2020, 10:14:30 PM
The code that I had put in the zip by mistake corresponded to another demo, I suppose it can be considered an extra :bgrin:. The compiling error is due to the same, we have already talked about it in this forum. You cannot associate a structure, such as the palette, to an integer, such as the video buffer. The new version of TinyC no longer allows it, so I continue using the old one. I attach the code that should compile in any type of compiler.
thanks,maybe enough precision using floats instead :thumbsup: