Page 1 of 1

Rendering thick curved lines

Posted: Fri Aug 10, 2007 2:49 am
by Antithesis
This isn't so much a game question as a graphics question. Could someone suggest an efficient method to produce geometry (I hope this can be done in terms of geometry and not pixels) for thick curved lines like Photoshop and Flash can draw?
My current approach is to create a triangle strip following the curve but at large thickness + quick direction changes, it produces very ugly artifacts as the vertex sets on either side of the curve overlap other nearby vertex sets.

Posted: Fri Aug 10, 2007 5:32 am
by netmaestro
I apologize for the sloppy coding, I just threw this together. It's taking 2.5 milliseconds on average here to render a curve 10 pixels wide on the 640*480 screen. If 2.5 ms is fast enough for your purposes, this should work:

Code: Select all

OpenLibrary(1, "msimg32.dll")

CreateImage(0, 640,480,32)

Macro ARGB(RGB=0,Transparency=255) ; by einander
    Blue(RGB)|Green(RGB)<<8|Red(RGB)<<16|Transparency<<24 
EndMacro 

Structure POINTF
  x.f
  y.f
EndStructure

Global Dim PointArray.POINTF(100)
For i=0 To 100
  PointArray(i)\x = 30*i+0.5*i
  pointArray(i)\y = 50+i*1.1*i
Next

Global *token, *surface, *redpen5

CompilerIf Defined(GdiplusStartupInput, #PB_Structure) = 0
  Structure GdiplusStartupInput 
    GdiPlusVersion.l 
    *DebugEventCallback.Debug_Event
    SuppressBackgroundThread.l 
    SuppressExternalCodecs.l 
  EndStructure 
CompilerEndIf  

Procedure DrawCurve()
  hdc = StartDrawing(ImageOutput(0))
    Box(0,0,640,480,#Black)
    CallFunction(0, "GdipCreateFromHDC", hdc, @*surface)
    CallFunction(0, "GdipDrawCurve", *surface, *redpen5, PointArray(), 100)
    CallFunction(0, "GdipDeleteGraphics", *surface)    
  StopDrawing()
  dc = GetWindowDC_(#Null)
  imagedc = CreateCompatibleDC_(dc)
  SelectObject_(imagedc, ImageID(0))
  hdc = StartDrawing(ScreenOutput())
    CallFunction(1, "TransparentBlt", hdc, 0, 0, 640,480, imagedc, 0, 0, 640,480,0) 
  StopDrawing()
  ReleaseDC_(0, dc)
  DeleteDC_(imagedc)
EndProcedure

input.GdiplusStartupInput
input\GdiPlusVersion = 1

OpenLibrary(0, "gdiplus.dll")
CallFunction(0, "GdiplusStartup", @*token, @input, #Null)
CallFunction(0, "GdipCreatePen1", ARGB(#Red, 180), 10.0, 2, @*redpen5)

InitSprite()
OpenWindow(0,0,0,640,480,"gdiplus curves",$CA0001)
OpenWindowedScreen(WindowID(0), 0,0,640,480,0,0,0)

Repeat
  EventID = WindowEvent()
  ClearScreen(#Black)
  DrawCurve()
  FlipBuffers()
  Delay(1)
Until EventID = #WM_CLOSE

CallFunction(0, "GdipDeletePen", *redpen5)
CallFunction(0, "GdiplusShutdown", *token)
CloseLibrary(0)
CloseLibrary(1)

Posted: Fri Aug 10, 2007 5:36 am
by Antithesis
Thank you for the suggestion, but unfortunately this is not fast or versatile enough for what I'm doing. I'm very inclined to do this by building geometry alone, as I will also be wanting to do textured/fakeAA lines.

Posted: Fri Aug 10, 2007 5:44 am
by netmaestro
I figured it might not do, I have no other ideas unfortunately, not being a game developer. I hope you find what you're looking for, best of luck to you.

Posted: Fri Aug 10, 2007 8:24 am
by Kaeru Gaman
I have no idea how "thick curved lines like Photoshop and Flash can draw" look,
but I would suggest using a circle to plot.

like this:

Code: Select all

InitSprite()
OpenWindow(0, #PB_Ignore, #PB_Ignore, 640, 480, "Plot")
OpenWindowedScreen(WindowID(0),0,0,640,480,0,0,0)

radius = 7

StartDrawing(ScreenOutput())
  For n=-radius To 639+radius
    x.f = n
    y.f = 240 + 200 * Sin(x/40)
    Circle(x,y,7,$F0A040)
  Next
StopDrawing()

Repeat:Until WaitWindowEvent() = #PB_Event_CloseWindow
the rounded shape of the circle keeps the artifacts low.

[edit]
if you want some lightning-effekt, use a sprite.

take this one Image and save it as a BMP in the same directory you saved the demo-code.

Code: Select all

InitSprite()
OpenWindow(0, #PB_Ignore, #PB_Ignore, 640, 480, "Plot")
OpenWindowedScreen(WindowID(0),0,0,640,480,0,0,0)

TransparentSpriteColor(-1,0)
LoadSprite(0,"ball.bmp")

radius = 7

  For n=-radius To 639+radius
    x.f = n
    y.f = 240 + 200 * Sin(x/40)
    DisplayTransparentSprite(0,x-radius,y-radius)
  Next
FlipBuffers()

Repeat:Until WaitWindowEvent() = #PB_Event_CloseWindow