Hi
I try to create a little "vector drawing" application.
I have found some functions to get the x/y point on a bezier curve, and it works fine (by baxslash).
So to draw the curve with stroke it's ok.
But, I try to fill the interior of the poygon.
I have found this great code by swissolo :
https://forum.thegamecreators.com/thread/211123
[edit : ok I have found the bug I have made, it's fixed ! I have inversed the last point ^^ (10h18)]
But I have a bug, a polygon isn't filled, I dont know why, as we can see on the screenshot.
Here is the code of the application (will be opensource) :
Foldstart // infos
// Project: vectordrawing
// Created: 2023-09-09
// based on code from baxslash (getx/Yonbezier) and swissolo (polygon filled)
#constant C_VD_Version = "0.01"
foldend
Foldstart // types, variables, constants, init
Foldstart // types for the application
type tpoint
x
y
spriteid
typ // 0 start end, 1 control
endtype
Type tShapes
depth
points as tpoint
name$
color
alpha
r
g
b
Hide
selected
scale
rotation
img // the image renderiamge for the shapes
spriteID
x as float
y as float
endtype
Type tVdLayer
depth
spriteID // for the UI
name$
textid // fot the name
Hide
locked
shapes as tShapes[]
x
y
w
h
endtype
type tScene
VDlayer as tVdlayer[0]
name$
x
y
w
h
endtype
global dim scene[0] as tScene
// the scene is composed from layers, each layer can have 1 or several shapes/Paths, (a shapes or path is created by points)
Foldend
Foldstart // variables.agc
Type sGameProp
state
mode
zoom
Endtype
Function InitVariable()
FoldStart // pour cacher dans bytecode les strings ! (save \ load et autres )
Global Dim CHR[240] as String
For i = 0 to chr.length
CHR[i] = chr(i)
next
//~ Global C_fr$, C_Eng$, C_Be$
#constant C_Fr$ = Chr[102]+Chr[114]
#constant C_eng$ = Chr[101]+Chr[110]
#constant C_windows$ = Chr[119]+Chr[105]+Chr[110]+Chr[100]+Chr[111]+Chr[119]+Chr[115] // "windows"
#constant C_android$ = Chr[97]+Chr[110]+Chr[100]+Chr[114]+Chr[111]+Chr[105]+Chr[100] // "android"
#constant C_save$ = Chr[115]+Chr[97]+Chr[118]+Chr[101]+Chr[92] // save\
#constant C_PNG$ = Chr[46]+Chr(112)+Chr(110)+Chr(103) // .png
#constant C_JPG$ = Chr[46]+Chr(106)+Chr(112)+Chr(103) // .jpg
#constant C_txt$ = Chr[116]+Chr[120]+Chr[116] // txt
Foldend
Global GameProp as sGameprop
Global G_width, g_height
endfunction
Foldend
Foldstart // constants (sprite, text..)
//colors
#constant C_COLORCLEARCOLOR 80
#constant c_red = MakeColor(255,0,0)
// gadget depth
#constant C_Depth_Gadget = 20
Foldend
Foldstart // init application
Function InitGeneral()
InitVariable()
Foldstart // init reso, sizewindow
// show all errors
SetErrorMode(2)
G_width = GetDeviceWidth()
g_height = GetDeviceHeight()
// set window properties
if GetDeviceBaseName() = c_windows$
G_width = 1280
g_height = 768
endif
//~ message(str(G_width)+"/"+str(G_height))
//~ message(str(GetDeviceWidth())+"/"+str(GetDeviceHeight()))
SetWindowTitle( "AGK VectorDrawing" )
SetWindowSize( G_width, g_height, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window
MaximizeWindow()
// set display properties
SetVirtualResolution( G_width, g_height ) // doesn‘t have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 30, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 ) // since version 2.0.22 we can use nicer default fonts
//~ if AGK_Studio = 1
//~ SetSyncRate( 60, 0 )
//~ else
SetSyncRate( 30, 0 ) // 30fps instead of 60 to save battery : to get the shadow not flicked on my pc
//~ endif
//~ SetImmersiveMode(1)
Foldend
Foldstart // on crée l‘écran splash pour le loading du jeu et update reso
#constant iTitre = 2
// LoadImage(2, c_image$+Chr[116]+Chr[105]+Chr[116]+Chr[114]+Chr[101]+C_png$) // titre.png
#Constant iAGK = 1
loadimage(iAGK, Chr[97]+Chr[103]+Chr[107]+Chr[115]+Chr[112]+Chr[108]+Chr[97]+Chr[115]+Chr[104]+C_png$) // agksplash.png
createsprite(1, iAGK)
//~ SetSpritePosition(1,g_width/2-GetSpriteWidth(iAGK)/2, g_height/2-GetSpriteHeight(iAGK)/2-50)
SetSpritePosition(1,g_width/2-GetSpriteWidth(iAGK)/2, 50+GetImageHeight(iTitre))
sync()
//~ G_width = gw // 1280
//~ endif
H = GetDeviceHeight()
w = GetDeviceWidth()
G_height = (h*G_width)/w
SetVirtualResolution( G_width, g_height )
Foldend
Foldstart // version, date
// version et date : voir info !!
#CONSTANT C_AUTHOR = Chr[66]+Chr[108]+Chr[101]+Chr[110]+Chr[100]+Chr[109]+Chr[97]+Chr[110] // Blendman
Foldend
// InitImages()
Gameprop.state =C_SCREENDRAWING
// the delete all
DeleteAllSprites()
DeleteAllText()
Endfunction
Foldend
Foldend
InitGeneral()
Foldstart // ***** SCREEN Start
// screento see our files
Function ScreenStart()
Endfunction
Foldend
Foldstart // ***** SCREEN DRAWING
global pNm : pNm = -1 //number of points you'll be using
//~ global width //image width
//~ global height//image height
global polyImage
Foldstart // type for screendrawing()
Type tVD_canvas
x
y
endtype
Global VD_canvas as tVD_canvas
type tgadget
spriteid
x
y
textid
endtype
global dim gadget[] as tgadget
#Constant C_Action_PAN = 0
#Constant C_Action_Add = 1
#Constant C_Action_Delete = 2
#Constant C_Action_Move = 3
foldend
Function ScreenDrawing()
Foldstart // createt the UI, point ....
Foldstart // clear color, resolution..
c = C_COLORCLEARCOLOR //60 // old : 80
SetClearColor(c,c,c)
SetViewOffset(0,0)
SetViewzoom(1)
gw = 1600
if GetDeviceBaseName() = C_android$
gw = 1000
endif
G_width = gw // 2600 // 1280
//~ endif
H = GetDeviceHeight()
w = GetDeviceWidth()
G_height = (h*G_width)/w
SetVirtualResolution(g_width, g_height)
Foldend
e = 4
width = g_width/e
height = g_height/e
InitPolygon(width, height)
Foldstart // create UI
c = 51
h1 = 60
n=1
CreateSprite(n, 0)
SetSpriteSize(n, 4000, h1)
SetSpritePosition(n, -1000, 0)
SetSpriteColor(n, c, c, c, 255)
SetSpriteDepth(n, C_Depth_Gadget+1)
FixSpriteToScreen(n, 1)
x = 10
AddButton(2, 0, x, 0, "add") : inc x, 120
btnAction = 2
btnNew =AddButton(5, 0, x, 0, "New") : inc x, 120
btnLoad =AddButton(3, 0, x, 0, "Load") : inc x, 120
btnSave =AddButton(4, 0, x, 0, "Save") : inc x, 120
action$="Movecanvas,Add,delete,move point,"
nbActionMAx = FindStringCount(action$, ",")
pointID =-1
foldend
Foldstart // add temporary points
// temporary point array to test
x1 = 300
y1 = 700
cx1 = 350
cy1 = 400
x2 = 700
y2 = 600
cx2 = 660
cy2 = 400
cx3 = 660
cy3 = 800
cx4 = 350
cy4 = 800
global dim point[] as tpoint
scene.length =-1
VD_Addscene()
//~ addpoint(0, cx4, cy4,1)
//~ addpoint(1, x1, y1, 0)
//~ addpoint(2, cx1, cy1, 1)
//~
//~
//~ addpoint(3, cx2, cy2, 1)
//~ addpoint(4,x2, y2, 0)
//~ addpoint(5, cx3, cy3, 1)
Foldend
global polySpr = 100
CreateSprite(polySpr,polyImg)
xx = G_width*0.5
yy = G_height*0.5
setSpritePositionByOffset(polySpr, xx, yy)
SetSpriteDepth(PolySpr, 100)
SetSpriteScaleByOffset(PolySpr, e, e)
c = makecolor(0,0,0)
// zoom
Zoom = 100
z as float
z = zoom*0.01
actionid=0
VD_LoadDoc("test3")
okrender=1
Foldend
Repeat
print(GetStringToken(action$, ",", actionid+1))
print(str(actionid))
Foldstart // ************** pointer ***************************//
mx = ScreenToWorldX(getpointerx())
my = ScreenToWorldy(getpointery())
Foldstart // windows wheel
if GetDeviceBaseName()= C_windows$ // "windows"
wheel = GetRawMouseWheelDelta()
if wheel <> 0
zoom = zoom + wheel
if zoom<0
zoom =1
elseif zoom > 10000
zoom = 10000
endif
z = zoom*0.01
SetViewZoom(z)
okrender =1
//~ SetTextString(TxtInfo, "Action : "+GetStringToken(action$, ",", action)+"/ Zoom : "+str(z*100,0))
endif
endif
foldend
Foldstart // pointer pressed
if GetPointerPressed()
buton = GetSpriteHit(mx, my)
if buton = 0 or buton = polySpr
pointID = -1
// on the canvas, to move it
select actionid
case C_Action_PAN
sx = mx
sy = my
movecanvas=1
endcase
case C_Action_Add
// add point
//~ message("ok add point")
pointID = addpoint(-1, mx-10, my-10, 1)
addpoint(-1, mx, my, 0)
addpoint(-1, mx+10, my+10, 1)
movecanvas=0
endcase
endselect
elseif buton=btnAction
inc actionid
if actionid >nbActionMAx
actionid=0
endif
else
select actionID
case C_Action_Move // select
pointid = -1
for i=0 to point.length
n = point[i].spriteid
if n = buton
pointid = i
exit
endif
next
endcase
endselect
Endif
endif
foldend
Foldstart // pointer state
if GetPointerState()
if movecanvas =1
newx = mx - viewx
newy = my - viewy
viewx = (sx - newx)
viewy = (sy - newy)
// scroll the screen
SetViewOffset(viewx, viewy)
else
if buton = 0 or buton >= 100
select actionID
case C_Action_Add
if pointid>-1
i= pointid
point[i].x = mx
point[i].y = my
UpdateTheCanvas(VD_canvas.x, VD_canvas.y)
endif
endcase
case C_Action_Move
if pointid>-1
okrender=1
i= pointid
point[i].x = mx
point[i].y = my
UpdateTheCanvas(VD_canvas.x, VD_canvas.y)
endif
endcase
endselect
endif
endif
endif
foldend
foldstart // pointer released
IF GetPointerReleased()
bb = GetSpriteHit(mx, my)
if bb>0 and bb<100
if bb = buton
select buton
case BtnNew
Vd_DocNew()
endcase
case BtnLoad
VD_LoadDoc("")
okrender=1
endcase
case BtnSave
VD_SaveDoc("")
endcase
endselect
endif
else
if okrender=1
if P.length >= 2
okrender =0
RenderPolygon(width, height)
setSpriteImage(polySpr, polyImage) //update image
endif
endif
endif
movecanvas=0
endif
foldend
Foldend
Foldstart //**************** drawings ************************//
// draw the line for the points (should be sprite not drawline, because drawline are drawned over interface
for i=0 to point.length
if mod(i,3) <> 2
x = (point[i].x-viewx)*z
y = (point[i].y-viewy)*z
if i < point.length
drawline(x, y, (point[i+1].x-viewx)*z, (point[i+1].y-viewy)*z, c,c)
else
drawline(x, y, (point[0].x-viewx)*z, (point[0].y-viewy)*z, c ,c )
endif
endif
next
// size of the stroke (temporary)
size = 5
// and draw the shapes
pNm = -1
for i=0 to point.length step 3
// the nb of segment for the lines :
a = 30
for j=0 to a
// the % on the curve
d# = 1
d# = d#/a
// get the position of the points
if i <= point.length-3
Foldstart
//~ if i+3<=point.length
cx1 = point[i+2].x
cy1 = point[i+2].y
x1 = point[i+1].x
y1 = point[i+1].y
//~ endif
//~ if i+3<=point.length
cx2 = point[i+3].x
cy2 = point[i+3].y
//~ endif
if i < point.length and i+4<=point.length
x2 = point[i+4].x
y2 = point[i+4].y
else
x2 = point[0].x
y2 = point[0].y
endif
x = (getPointXOnBezier(x1, y1, x2, y2, cx1, cy1, cx2, cy2, j*d#) - viewx)*z
y = (getPointYOnBezier(x1, y1, x2, y2, cx1, cy1, cx2, cy2, j*d#) - viewy)*z
if j>0
drawline(x, y, x4, y4, c,c)
//**** create the stroke ***//
// calcul of the distance between each point
dist = dist(x,y,x4,y4)
// get the angle between each point
d1# = atan2(y4-y,x4-x)+90
// c is the color of the stroke
for k=0 to dist
DrawEllipse(x+sin(d1#)*k,y-cos(d1#)*k,size,size,c,c,1)
next
endif
x4 = x
y4 = y
foldend
else
// if the point is the last
// if shapes is closed // temporary
if i >= point.length-3 and i >3
ShapeIsClosed= 1
if ShapeIsClosed =1
// print(str(i))
x1 = point[1].x
y1 = point[1].y
x2 = point[i+1].x
y2 = point[i+1].y
cx1 = point[i+2].x
cy1 = point[i+2].y
cx2 = point[0].x
cy2 = point[0].y
// get the position of the point on the curve
x = (getPointXOnBezier(x2, y2, x1, y1, cx1, cy1, cx2, cy2, j*d#) - viewx)*z
y = (getPointYOnBezier(x2, y2, x1, y1, cx1, cy1, cx2, cy2, j*d#) - viewy)*z
if j>0
drawline(x, y, x4, y4, c,c)
//**** create the stroke ***//
// calcul of the distance between each point
dist=dist(x,y,x4,y4)
// get the angle between each point
d1#=atan2(y4-y,x4-x)+90
// c is the color of the stroke
// draw the stroke
for k=0 to dist
DrawEllipse(x+sin(d1#)*k,y-cos(d1#)*k,size,size,c,c,1)
next
endif
x4 = x
y4 = y
endif
endif
endif
// then save the point for the renderpolygon
// e = 4, it's to divide the size of the renderimage by e (4), to be faster
// position of the sprite
x7 = xx - G_width*0.5
y7 = yy - G_height*0.5
// then add a new point for the renderpolygon
inc pNm
P.length = pNm
k = pNm
p[k].x# = (x/e)/z - x7 + viewx/e
p[k].y# = (y/e)/Z - y7 + viewy/e
next
next
// update the polygon
if okrender= 1
if P.length >= 2
okrender=0
RenderPolygon(width, height)
setSpriteImage(polySpr, polyImage) //update image
endif
endif
// to see the polygon
x7 = (xx - width*0.5 *e)*z
y7 = (yy - height*0.5*e)*z
//~ For i=0 to p.length
//~ drawbox(p[i].x#+x7, p[i].y#+y7, p[i].x#+5+x7, p[i].y#+5+y7, c_red, c_red, c_red,c_red, 0)
//~ drawbox(p[i].x#, p[i].y#, p[i].x#+5, p[i].y#+5, c_red, c_red, c_red,c_red, 0)
//~ next
DrawBox(x7-viewx*z, y7- viewy*z, x7+width*e*z-viewx*z, y7 + height*e*z- viewy*z, c, c, c, c, 0)
Foldend
//~ print(str(p.length))
//~ if point.length>-1
//~ print(str(buton)+"/"+str(point[point.length].spriteid))
//~ endif
if GetRawKeyPressed(27)
quit =1
endif
sync()
until quit>= 1
DeleteAllSprites()
DeleteAllText()
end
Endfunction
Foldstart // update
Function UpdateTheCanvas(nx, ny)
x1 = VD_canvas.x
y1 = VD_canvas.y
For i=0 to point.length
x = point[i].x
y = point[i].y
SetSpritePositionByOffset(point[i].spriteid, x, y)
next
endFunction
foldend
Foldend
Foldstart // ***** general loop
#constant C_SCREENSTART 0
#constant C_SCREENOPTION 1
#constant C_SCREENDRAWING 2
Function GeneralLoop()
Select Gameprop.state
Case C_SCREENSTART
//~ ScreenStart()
endcase
Case C_SCREENOPTION
//~ ScreenOption()
endcase
Case C_SCREENDRAWING
ScreenDrawing()
endcase
endselect
Endfunction
foldend
// our main loop
do
GeneralLoop()
loop
Foldstart // functions for vectordrawing
Function Vd_DocNew()
for i=0 to point.length
if point[i].spriteid>1000
DeleteSprite(point[i].spriteid)
endif
next
Global dim point[] as tpoint
EndFunction
Function VD_SaveDoc(filename$)
if filename$=""
filename$ = Input(filename$,20)
endif
d$ =","
if filename$ <> ""
file$ = C_save$+filename$+".txt"
f=OpenToWrite(file$)
txt$ = "// created by VD_agk"+d$+GetCurrentDate()+d$+GetCurrentTime()+d$
WriteLine(f, txt$)
txt$ = "vdgen"+d$+C_VD_Version+d$+GetCurrentDate()+d$+GetCurrentTime()+d$
WriteLine(f, txt$)
For i=0 to scene.length
txt$ = "vdscene"+d$
txt$ = txt$ +str(i)+d$
txt$ = txt$ +scene[i].name$+d$
txt$ = txt$ +Str(scene[i].VDlayer.length)+d$
txt$ = txt$ +Str(scene[i].x)+d$
txt$ = txt$ +Str(scene[i].y)+d$
txt$ = txt$ +Str(scene[i].w)+d$
txt$ = txt$ +Str(scene[i].h)+d$
WriteLine(f, txt$)
For j=0 to scene[i].vdlayer.length
txt$ = "vdlayer"+d$
txt$ = txt$ +str(i) +d$
txt$ = txt$ +str(j) +d$
txt$ = txt$ +scene[i].vdlayer[j].name$ +d$
txt$ = txt$ +Str(scene[i].VDlayer[j].x)+d$
txt$ = txt$ +Str(scene[i].VDlayer[j].y)+d$
txt$ = txt$ +Str(scene[i].VDlayer[j].w)+d$
txt$ = txt$ +Str(scene[i].VDlayer[j].h)+d$
txt$ = txt$ +Str(scene[i].VDlayer[j].hide)+d$
txt$ = txt$ +Str(scene[i].VDlayer[j].locked)+d$
txt$ = txt$ +Str(scene[i].VDlayer[j].shapes.length)+d$
WriteLine(f, txt$)
for k=0 to scene[i].vdlayer[j].shapes.length
txt$ = "vdshape"+d$
txt$ = txt$ +str(i) +d$
txt$ = txt$ +str(j) +d$
txt$ = txt$ +str(k) +d$
txt$ = txt$ +scene[i].vdlayer[j].shapes[k].name$ +d$
txt$ = txt$ +str(scene[i].vdlayer[j].shapes[k].x) +d$
txt$ = txt$ +str(scene[i].vdlayer[j].shapes[k].y) +d$
txt$ = txt$ +str(scene[i].vdlayer[j].shapes[k].r) +d$
txt$ = txt$ +str(scene[i].vdlayer[j].shapes[k].g) +d$
txt$ = txt$ +str(scene[i].vdlayer[j].shapes[k].b) +d$
txt$ = txt$ +str(scene[i].vdlayer[j].shapes[k].alpha) +d$
txt$ = txt$ +str(scene[i].vdlayer[j].shapes[k].scale) +d$
WriteLine(f, txt$)
next
next
next
For i=0 to point.length
txt$ = "vdpoint"+d$
txt$ = txt$ +str(i) +d$
txt$ = txt$ +str(point[i].x) +d$
txt$ = txt$ +str(point[i].y) +d$
txt$ = txt$ +str(point[i].typ) +d$
WriteLine(f, txt$)
next
CloseFile(f)
endif
Endfunction
Function VD_LoadDoc(filename$)
if filename$=""
filename$ = Input(filename$,20)
endif
d$ =","
if filename$ <> ""
file$ = C_save$+filename$+".txt"
if GetFileExists(file$)
VD_docNew()
f=OpenToread(file$)
while FileEOF(f)=0
line$ = ReadLine(f)
index$ = GetStringToken(line$, d$, 1)
select index$
case "vdpoint"
u = 2
i = val(GetStringToken(line$, d$, u)) : inc u
x = val(GetStringToken(line$, d$, u)) : inc u
y = val(GetStringToken(line$, d$, u)) : inc u
typ = val(GetStringToken(line$, d$, u)) : inc u
addpoint(-1, x, y, typ)
endcase
endselect
endwhile
closefile(f)
endif
endif
Endfunction
Function Input(textin$,length)
SetCursorBlinkTime(0.5)
SetTextInputMaxChars(length)
StartTextInput(textin$)
do
state=GetTextInputState()
c=GetLastChar()
if GetTextInputCompleted()
if GetTextInputCancelled()
text$="" // textin$
cancel =1
exit
else
text$=GetTextInput()
//~ cancel=1
exit
endif
endif
sync()
loop
StopTextInput()
sync()
if cancel=1
text$ = ""
quitok=0
if GetDeviceBaseName()=C_windows$ or getrawkeypressed(27)
repeat
if GetRawKeyReleased(27)
quitok=1
endif
sync()
until quitok=1
endif
endif
endfunction text$
Function VD_Addscene()
i = scene.length+1
scene.length = i
Scene[i].name$ = "scene"+str(i)
Scene[i].w = 600
Scene[i].h = 400
Scene[i].vdlayer[0].name$ = "layer0"
endfunction
function dist(x1,y1,x2,y2)
dist= sqrt((x2-X1)*(x2-x1)+(y2-y1)*(y2-y1))
endfunction dist
function AddButton(n, img, x, y, txt$)
i = gadget.length +1
gadget.length = i
if n=-1
n = CreateSprite(img)
else
createsprite(n, img)
endif
SetSpriteSize(n, 120, 40)
c = 70
setspritecolor(n, c,c,c,255)
SetSpritePosition(n, x, y)
FixSpriteToScreen(n, 1)
gadget[i].x = x
gadget[i].y = y
gadget[i].spriteid = n
n1 = createtext(txt$)
SetTextSize(n1, 30)
SetTextPosition(n1, x, y)
FixTextToScreen(n1, 1)
gadget[i].textid = n1
endfunction n
// by Baxslash
rem full function for getting a bezier curve x component
rem where points x1,y1 and x2,y2 are the start/end points
rem and c1x,c1y and c2x,c2y are the control points
function getPointXOnBezier(x1#, y1#, x2#, y2#, c1x#, c1y#, c2x#, c2y#, v#)
cx# = 3 * (c1x# - x1#)
bx# = 3 * (c2x# - c1x#) - cx#
ax# = x2# - x1# - cx# - bx#
x# = ((ax# * v# + bx#) * v# + cx#) * v# + x1#
endfunction x#
rem full function for getting a bezier curve y component
function getPointYOnBezier(x1#, y1#, x2#, y2#, c1x#, c1y#, c2x#, c2y#, v#)
cy# = 3 * (c1y# - y1#)
by# = 3 * (c2y# - c1y#) - cy#
ay# = y2# - y1# - cy# - by#
y# = ((ay# * v# + by#) * v# + cy#) * v# + y1#
endfunction y#
// fonction temporary to add a point to the curve
function addpoint(i, x1, y1, typ)
if i=-1
i =point.length +1
point.length = i
else
if i>point.length
point.length=i
endif
endif
n = createsprite(0)
SetSpritePositionByOffset(n, x1, y1)
if typ =0
setspritecolor(n, 200, 100, 100, 200)
else
setspritecolor(n, 100, 100, 200, 200)
endif
setspritesize(n, 20,20)
SetSpriteDepth(n, C_Depth_Gadget +50)
point[i].x =x1
point[i].y =y1
point[i].spriteid = n
point[i].typ = typ
endfunction i
foldend
Function RenderPolygon(width, height)
// by swissolo
if GetImageExists(polyImage) and PolyImage >0
DeleteImage(polyImage)
endif
//calculate bounds
minID = 0
for i = 0 to pNm
if p[i].y# < p[minID].y# then minID = i
next i
maxID = 0
for i = 0 to pNm
if p[i].y# > p[maxID].y# then maxID = i
next i
minY = p[minID].y#
maxY = p[maxID].y#
minID = 0
for i = 0 to pNm
if p[i].x# < p[minID].x# then minID = i
next i
maxID = 0
for i = 0 to pNm
if p[i].x# > p[maxID].x# then maxID = i
next i
minX = p[minID].x#
maxX = p[maxID].x#
if minX < 0 then minX = 0
if minY < 0 then minY = 0
if maxX > width then maxX = width
if maxY > height then maxY = height
if maxX < 0 then maxX = 0
if maxY < 0 then maxY = 0
if minX > width then minX = width
if minY > height then minY = height
dim nodeX[pNm] as float
for pixelY = 0 to minY-1 //set all entirely empty rows to be clear
memIndex = 12+4*pixelY*width
for a = 0 to width-1
memIndex = memIndex+3
setMemblockByte(mem, memIndex, 0) : memIndex = memIndex+1
next a
next pixelY
for pixelY = minY to maxY-1
nodes = 0
j = pNm //build nodes
for i = 0 to pNm
if p[i].y# < pixelY and p[j].y# >= pixelY or p[j].y# < pixelY and p[i].y# >= pixelY
nodeX[nodes] = p[i].x#+(pixelY+0.0-p[i].y#)/(p[j].y#-p[i].y#)*(p[j].x#-p[i].x#)
nodes = nodes+1
endif
j = i
next i
i = 0 //sort nodes
while i < nodes-1
if nodeX[i] > nodeX[i+1]
swp# = nodeX[i]
nodeX[i] = nodeX[i+1]
nodeX[i+1] = swp#
if i <> 0 then i = i-1
else
i = i+1
endif
endwhile
memIndex = 12+4*pixelY*width
for a = 0 to width-1 //clear this row to be redrawn (or remove this chunk of code and draw empty parts alongside opaque parts in the code block below it)
memIndex = memIndex+3
setMemblockByte(mem, memIndex, 0) : memIndex = memIndex+1
next a
stop = 0 //draw nodes (if in range)
for i = 0 to nodes step 2
if nodeX[i] > maxX then stop = 1
if stop <> 1 //break if following nodes will exceed range
if i<=nodes-1
if nodeX[i+1] > minX
if nodeX[i] < minX then nodeX[i] = minX
if nodeX[i+1] > maxX then nodeX[i+1] = maxX
memIndex = 12+4*pixelY*width+4*trunc(nodeX[i])
top = trunc(nodeX[i+1]-1)+1
if top > width-1 then top = width-1
// ici les couleur
r = 240
g = 255
b = 255
for a = trunc(nodeX[i]) to top
setMemblockByte(mem, memIndex, r) : memIndex = memIndex+1
setMemblockByte(mem, memIndex, g) : memIndex = memIndex+1
setMemblockByte(mem, memIndex, b) : memIndex = memIndex+1
alpha = 255
if a = trunc(nodeX[i]) then alpha = 255-(nodeX[i]-trunc(nodeX[i]))*255
if a = top then alpha = (nodeX[i+1]-top)*255
if top = width then alpha = 255
setMemblockByte(mem, memIndex, alpha) : memIndex = memIndex+1
next a
endif
endif
endif
next i
next pixelY
for pixelY = maxY to height-1 //set the rest of the rows to be empty
memIndex = 12+4*pixelY*width
for a = 0 to width-1
memIndex = memIndex+3
setMemblockByte(mem, memIndex, 0) : memIndex = memIndex+1
next a
next pixelY
polyImage = createImageFromMemblock(mem)
endfunction
// by swissolo
type point_UDT
x#
y#
endtype
Function InitPolygon(width, height)
// by swissolo
global dim p[] as point_UDT
global mem : mem = createMemblock(12+4*width*height)
setMemblockInt(mem, 0, width)
setMemblockInt(mem, 4, height)
setMemblockInt(mem, 8, 32)
global polyImg
polyImg = createImageFromMemblock(mem) //the image to work with
endfunction
And a file if needed to test :
// just name it test.txt for exemple and load it with load buton
// created by VD_agk,2023-09-10,10:59:15,
vdgen,0.01,2023-09-10,10:59:15,
vdscene,0,scene0,0,0,0,600,400,
vdlayer,0,0,layer0,0,0,0,0,0,0,-1,
vdpoint,0,188,427,1,
vdpoint,1,684,536,0,
vdpoint,2,212,160,1,
vdpoint,3,904,140,1,
vdpoint,4,654,256,0,
vdpoint,5,664,266,1,
vdpoint,6,1399,126,1,
vdpoint,7,1192,399,0,
vdpoint,8,1404,500,1,
vdpoint,9,1086,820,1,
vdpoint,10,807,634,0,
vdpoint,11,852,762,1,
vdpoint,12,355,819,1,
vdpoint,13,526,645,0,
vdpoint,14,254,799,1,
If you have an idea how I don' t have the last polygon filled, I will be very interested

.
Another question : it's not very fast, so perhaps you know a better technic to fill a polygon, maybe with a spriteshader ?
thanks
EDIT :
What I would like to add :
- layer system with dim shape[] to add several shapes (to create character, objects and complete scene)
- add point between two existing point
- delete point
- export as image
- change stroke size and color
- change polygon color
- and perhaps other features

AGK2 tier1 - http://www.dracaena-studio.com