Irregular polygon, using OS API

Just starting out? Need help? Post your questions and find answers here.
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Irregular polygon, using OS API

Post by Shardik »

ken_anthony wrote:The most severe for me is that only RGB values of 0 or 255 work. Any value from 1 to 254 is treated as zero.
Sorry, that was caused by an error converting integer into double values. Cairo uses doubles between 0 and 1 for RGB instead of integer values from 0 to 255, so I had to convert from integer to double values. You have to change

Code: Select all

  ColorPart = (Color & $FF) / 255
  Polygon()\ColorRed = ColorPart
to

Code: Select all

  ColorPart = Color & $FF
  Polygon()\ColorRed = ColorPart / 255
in the procedure CreatePolygon() for a correct conversion.
ken_anthony wrote:Question: Why is the green polygon showing up on the second form?
You are using only one callback with a global list of polygons, so always all polygons for all forms are drawn on each window refresh. If using multiple windows you have to take care that only the polygons for a specific window are drawn. I have therefore modified your code and extended the procedure CreatePolygon() and the linked list Polygon() with a further parameter Form, so that the callback can discriminate the Form causing a refresh and draw only the polygons for that form. I have taken your code and for easiness of testing I have combined your 3 files into one example:

Code: Select all

EnableExplicit

Global wMain, wSecond

Enumeration
#m1   
EndEnumeration

Structure Point
  x.D
  y.D
EndStructure

Structure PolygonEntry
  ColorRed.D
  ColorGreen.D
  ColorBlue.D
  Fill.L
  List PolygonPoint.Point()
  Form.I
EndStructure

Global MainForm.I, SecondForm.l

Declare WidgetExposeHandler(*a,*b)
Global NewList Polygon.PolygonEntry()
Global NewList PolygonPoint.Point()
; IncludeFile "/home/ken/PureBasic/polygon.Shardik"   ;This file hasn't changed from first test. Use the same one.
; IncludeFile "/home/ken/PureBasic/Second.form"

Procedure Load_data()
Define i.I
For i = 1 To 5
  AddElement(PolygonPoint())
  Read.D PolygonPoint()\x
  Read.D PolygonPoint()\y
Next i
EndProcedure

Load_data()
DataSection
  ; -- Pentagon
  Data.D   0,   0
  Data.D 150,   0
  Data.D 175,  75
  Data.D 150, 200
  Data.D  50, 125
EndDataSection

; Third file is same as first test.

ImportC ""
  gdk_cairo_create(*Drawable.GdkDrawable)
EndImport

ImportC "-lcairo"
  cairo_close_path(*CairoContext)
  cairo_destroy(*CairoContext)
  cairo_fill(*CairoContext)
  cairo_line_to(*CairoContext, x.D, y.D)
  cairo_set_line_width(*CairoContext, LineWidth.D)
  cairo_set_source_rgb(*CairoContext, Red.D, Green.D, Blue.D)
  cairo_stroke(*CairoContext)
EndImport

Procedure CreatePolygon(List PolygonPoint.Point(), x.D, y.D, Color.L, Fill.L, Form.I)
  Shared Polygon.PolygonEntry()

  Protected ColorPart.L
  Protected i.I

  AddElement(Polygon())

  ForEach PolygonPoint()
    AddElement(Polygon()\PolygonPoint())
    Polygon()\PolygonPoint()\x = x + PolygonPoint()\x
    Polygon()\PolygonPoint()\y = y + PolygonPoint()\y
  Next

  ColorPart = Color & $FF
  Polygon()\ColorRed = ColorPart / 255
  ColorPart = (Color >> 8) & $FF
  Polygon()\ColorGreen = ColorPart / 255
  ColorPart = (Color >> 16) & $FF
  Polygon()\ColorBlue = ColorPart / 255
  Polygon()\Fill = Fill
  Polygon()\Form = Form
EndProcedure

Procedure DrawPolygons(*Widget.GtkWidget)
  Shared Polygon.PolygonEntry()

  Protected CairoContext.I = gdk_cairo_create(*Widget\window)

  ForEach Polygon()
    If *Widget = Polygon()\Form
      If Polygon()\Fill
        ForEach Polygon()\PolygonPoint()
          cairo_line_to(CairoContext, Polygon()\PolygonPoint()\x, Polygon()\PolygonPoint()\y)
        Next
        
        cairo_close_path(CairoContext)
        cairo_set_source_rgb(CairoContext, Polygon()\ColorRed, Polygon()\ColorGreen, Polygon()\ColorBlue)
        cairo_fill(CairoContext)
      Else
        cairo_set_line_width(CairoContext, 1)
        cairo_set_source_rgb(CairoContext, Polygon()\ColorRed, Polygon()\ColorGreen, Polygon()\ColorBlue)
        
        ForEach Polygon()\PolygonPoint()
          cairo_line_to(CairoContext, Polygon()\PolygonPoint()\x, Polygon()\PolygonPoint()\y)
        Next
        
        cairo_close_path(CairoContext)
        cairo_stroke(CairoContext)
      EndIf
    EndIf
  Next

  cairo_destroy(CairoContext)
EndProcedure

ProcedureC WidgetExposeHandler(*Widget.GtkWidget, *Event.GdkEventExpose)
  DrawPolygons(*Widget.GtkWidget)
EndProcedure

; Second file: "Second.form"

Procedure wSecond_Events(event, SecondForm)
  Select event
    Case #PB_Event_CloseWindow
        End
       
    Case #PB_Event_Menu
        Select EventMenu()
            Case #m1
                CreatePolygon(PolygonPoint(), 200, 150, RGB(0, 255, 0), #True, SecondForm)
                WidgetExposeHandler(SecondForm, 0)
        EndSelect
  EndSelect
EndProcedure

Procedure OpenSecondForm()
    wSecond = OpenWindow(#PB_Any, 350, 150, 500, 500, "Second Form", #PB_Window_SizeGadget)
    SetWindowColor(wSecond, 0)
    SecondForm = g_list_nth_data_(gtk_container_get_children_(gtk_bin_get_child_(WindowID(wSecond))), 0)
    g_signal_connect_data_(SecondForm, "expose-event", @WidgetExposeHandler(), 0, 0, #G_CONNECT_AFTER)
 
    CreateMenu(#PB_Any, WindowID(wSecond))
    MenuTitle("Test")
    MenuItem(#m1, "Do_test")
   
    Repeat  :  wSecond_Events(WaitWindowEvent(), SecondForm) : ForEver
   
EndProcedure

; ----- Display window and define expose handler
Procedure OpenMain()
  wMain = OpenWindow(#PB_Any, 270, 100, 500, 500, "Polygon demo", #PB_Window_SizeGadget)
  SetWindowColor(wMain, 0)
  MainForm = g_list_nth_data_(gtk_container_get_children_(gtk_bin_get_child_(WindowID(wMain))), 0)
  g_signal_connect_data_(MainForm, "expose-event", @WidgetExposeHandler(), 0, 0, #G_CONNECT_AFTER)
  CreatePolygon(PolygonPoint(), 250, 200, RGB(255, 255, 0), #True, MainForm) ; THIS SHOULD BE YELLOW, NOT GREEN.
  WidgetExposeHandler(MainForm, 0)
 
   CreateMenu(#PB_Any, WindowID(wMain))
   MenuTitle("Open")
   MenuItem(#m1, "2nd form")
EndProcedure 

Procedure wMain_Events(event)
  Select event
    Case #PB_Event_CloseWindow
        End
       
    Case #PB_Event_Menu
        Select EventMenu()
            Case #m1
                OpenSecondForm()
        EndSelect
  EndSelect
EndProcedure

OpenMain()
Repeat  :  wMain_Events(WaitWindowEvent()) : ForEver
ken_anthony
User
User
Posts: 77
Joined: Thu Jun 20, 2013 5:41 am
Location: Springerville AZ USA

Re: Irregular polygon, using OS API

Post by ken_anthony »

Thank you Shardik. Above and beyond.

I understand. Of course the first thing I did was test it with a non primary. It works. I'm a happy camper.

If I can find the time I really need to dig into Cairo. <strike>I suspect</strike> I'm possitive it has a lot of useful goodness in it.

That's a good point about putting demos in one file. My habit is to break things up into separate files, but for demos it makes things a lot simpler and I will always do so in the future (assuming there isn't some really, emphatically strong reason to do otherwise... not that I can see one, but it's always good to avoid absolutes.)
ken_anthony
User
User
Posts: 77
Joined: Thu Jun 20, 2013 5:41 am
Location: Springerville AZ USA

Re: Irregular polygon, using OS API

Post by ken_anthony »

Shardik,

Just thinking out loud here as I adapt your code to my project.

It would seem to me that I would want a separate callback for each form. So what I believe I will do is create separate versions of WidgetExposeHandler as part of each forms file. My reasoning is so I can clear and rebuild polygon lists separately for each form (up to 30 times per second.) When I created separate versions of your FixBox handle I hadn't thought it all the way through (not unusual for me. I am a bit slow really. Reminding me of when Einstein told his math friend... "slow down. I don't tink that fast.") Yes, I just compared myself with Einstein. Aren't I the humble programmer?

My brain is beginning to turn into a pretzel... but that happens with events. I'll let you know my results and share my code when I get it done. I've been distracted lately by other life events. It's a neat puzzle.

It's funny to me how that color processing code doesn't look any different but is because of the under the cover type conversions going on. Just the sort of thing that commonly trips up us humans. I'm wondering what the best way (from a 'humble programmer' standpoint) is to address that sort of issue? Not expecting any ideas really, this is just my random musings.
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Irregular polygon, using OS API

Post by Shardik »

ken_anthony wrote:It's funny to me how that color processing code doesn't look any different but is because of the under the cover type conversions going on.
Then you should take a second look into the old conversion:

Code: Select all

  ColorPart = (Color & $FF) / 255
ColorPart is defined as a long integer at the beginning of the procedure CreatePolygon():

Code: Select all

  Protected ColorPart.L
So the resulting integer value of dividing by 255 (the part behind the decimal point is cut off because ColorPart is defined as long integer!) is always 0 for a Color=0..254 and 1 for Color=255. Since the colors in Cairo have to be doubles in the range from 0.0 to 1.0, the values all inbetween are missing. And this is just the result you have reported: :wink:
ken_anthony wrote:The most severe for me is that only RGB values of 0 or 255 work. Any value from 1 to 254 is treated as zero.
So the only change necessary was to do the division in the next step and putting the floating point result into a variable declared as double:

Code: Select all

Polygon()\ColorRed = ColorPart / 255
ken_anthony
User
User
Posts: 77
Joined: Thu Jun 20, 2013 5:41 am
Location: Springerville AZ USA

Re: Irregular polygon, using OS API

Post by ken_anthony »

Yeah, I saw that which brings out my weird sense of humor because if it weren't for types, the code doesn't logically change. C is similar with it's header files. Both things violate my probably over broad generalization of encapsulation.

I'm a simple guy easily confused (was that four levels of indirection or just three???) I purchased PowerBasic years ago and it just floors me how many ways you can define a calling parameter. I'm not talking about foreign calls like, do you use the C stack order or Pascal stack order (which might be the same. I don't remember things like that off hand after years.) I mean just the calls within the language itself.

You have to understand, I think Euphoria has too many types with only the two: Atom and Sequence (how's that for extreme?) I've toyed with the idea of a language with only one type (Sequence) with all functions being passed just one (or none) and return just one (which can be ignored) or none. That would certainly put to rest the question of stack order. I'd like to see sequences as a native API get/set in the OS. It also makes it trivial to return more than one parameter.

If performance is really an issue, allow some parameter to be direct register entries something like:

SomeRoutine(Reg32 A, Reg8 'b', Reg64 C, Seq D)

Then again, not sure that helps much since A, C, D are all sequences and the literal 'b' is just some value the compiler tucks away somewhere (well... you wouldn't have a literal if that were the declaration, duh.)
ken_anthony
User
User
Posts: 77
Joined: Thu Jun 20, 2013 5:41 am
Location: Springerville AZ USA

Re: Irregular polygon, using OS API

Post by ken_anthony »

I should add, one of the performance benefits of sequences is that if you have two that are only slightly different, only the difference needs another allocation (at least that's my understanding of how Euphoria does it) and only pointers are being passed or assigned. Also sequences are technically immutable for similar reasons... they are sort of mutable immutables which shouldn't make any sense, but in Euphora's case it does.
ken_anthony
User
User
Posts: 77
Joined: Thu Jun 20, 2013 5:41 am
Location: Springerville AZ USA

Re: Irregular polygon, using OS API

Post by ken_anthony »

Still attempting to adapt code, but while I have this on my mind...

Code: Select all

ProcedureC Second_ExposeHandler(*Widget.GtkWidget, *Event.GdkEventExpose)
  DrawPolygons(*Widget.GtkWidget)
EndProcedure
Doesn't this call DrawPolygons multiple times since GdkEventExpose isn't being used?
Post Reply