Forum Replies Created
-
AuthorPosts
-
I have a feeling the high dpi functionality is buggy at SDL2’s end (or within graphics drivers), at least on the MacOS platform. I run the following code on my 5k Retina iMac and receive incorrect results. It states that the DPIs are approx 108 and the desktop resolution is 2560×1440, all incorrect.
EDIT: Just had a thought. The 27″ 5k iMac has a stated resolution of 5120×2880 at 218 PPI. The values I get from my code are half of those values. Might not be a “bug” after all, just “unexpected behaviour”.
[/crayon]Monkey12345678910111213141516171819202122232425262728293031323334353637[crayon-5cba94d065a0a532958970 inline="true" ]#Import "<sdl2>"#Import "<std>"#Import "<mojo>"Using std..Using mojo..Using sdl2..Class MyWindow Extends WindowMethod New()Super.New( "HIGH DPI", 1024, 768, WindowFlags.Resizable | WindowFlags.HighDPI)Local ddpi:FloatLocal hdpi:FloatLocal vdpi:FloatSDL_GetDisplayDPI(0, Varptr(ddpi), Varptr(hdpi), Varptr(vdpi))Print "ddpi: " + ddpiPrint "hdpi: " + hdpiPrint "vdpi: " + vdpiEndMethod OnRender( canvas:Canvas ) OverrideApp.RequestRender()canvas.DrawText("Desktop resolution: " + App.DesktopSize.X + " x " + App.DesktopSize.Y, 10, 10)EndEndFunction Main()New AppInstanceNew MyWindowApp.Run()EndOn the positive side, the undocumented WindowFlags.HighDPI creation flag works nicely, though I need to load my fonts at a larger size, obviously. Text is very sharp. (Ted2 makes use of that flag too).
My next project is very text heavy, so I also would like bug-free DPI-related functionality, if possible…
Assuming there are no *extremely* negative currency exchange rate variations / economic events, the Patreon pledge total will remain above $1,000 for the next 12 months – I have personally committed to keep it there (to Mark, via email exchanges) and set aside the necessary funds to do so. (I have a private, proven history of repeated “higher level” donations to BRL).
That said, I’m hoping the burden won’t fall exclusively on my shoulders (but I’ll *happily* accept that responsibility if necessary). Every single dollar pledged is *important*, and not only because it’s a nice boost to the total – it’s also a nice boost for morale! Even if you can afford only one dollar per month it shows a genuine interest in the project.
A software engineer of Mark’s caliber could earn considerably more than $1,000 per month if employed by a company, as I’m sure you’re all aware, so I think it’s a bargain price to employ his services through Patreon.
Besides, I think we’re all keen for a nice little 3D engine from Mark.
I’m not sure what’s going on behind the scenes, but I’d call it a “ternary operation” because it takes three elements and behaves like an operator.
Monkey 2’s
? Else
is basically equivalent to C’s
? :https://en.wikipedia.org/wiki/Ternary_operation
one interesting thing is the FPS in my Original template runs at 60 frames per second , on yours the frame rate is much higher, on Windows and OSX.
SwapInterval = 0 disables vsync, I believe, so that’s the frame rate difference.
I suppose if we sum the Patreon+PayPal donate that amount was already reached.
True. I have been donating regularly via PayPal myself but have rejoined Patreon now, hoping they have learned their security lessons from the 2015 hack.
You could try something like this:?
[/crayon]Monkey12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758[crayon-5cba94d075a61683458447 inline="true" ]#Import "<std>"#Import "<mojo>"#Import "<mojox>"Using std..Using mojo..Using mojox..Class MyApp Extends WindowField UpdateTimer:TimerField ticker:ULong = 0Method New( title:String,width:Int,height:Int,flags:WindowFlags=WindowFlags.Resizable )Super.New( title,width,height,flags)App.Activated += OnActivatedApp.Deactivated += OnDeactivatedUpdateTimer = New Timer(60, OnUpdate)SwapInterval = 0EndMethod OnUpdate()ticker += 1EndMethod OnRender( canvas:Canvas ) OverrideIf Not App.Active Then ReturnApp.RequestRender()canvas.DrawText("Click Minimize/Maximize Window", 10, 10)canvas.DrawText("FPS: " + App.FPS, 10, 50)canvas.DrawText("Ticker: " + ticker, 10, 90)canvas.Flush()EndMethod OnActivated:Void()UpdateTimer.Suspended = FalseEndMethod OnDeactivated:Void()UpdateTimer.Suspended = TrueEndEndFunction Main()New AppInstanceNew MyApp( "MX2 Template", 640, 480 )App.Run()End[/crayon]Monkey123456789101112131415161718[crayon-5cba94d079e86338965157 inline="true" ]Namespace myapp#Import "<std>"Using std..Function Main()SeedRnd(Microsecs())Local val := Floor(Rnd(0, 100))Local msg := (val >= 50) ? val + " >= 50" Else val + " < 50"Print msgEndAdam, I’m not sure the comparison is fair/valid.
Yoyo Games probably have an employee dedicated full-time to writing documentation for their Gamemaker product. And they can afford it: Gamemaker is not open source and the Pro and Master editions are $149.99 and $799.99 respectively. Plus it is listed on Steam and so benefits from that exposure.
BRL is basically a one man show, and Monkey 2 is an open source project. Therefore it survives purely on the generosity of contributors via Patreon and Paypal donations. And Mark’s time is limited.
That said, I agree documentation is very important. So, aside from cash donations, maybe the best way people can contribute to Monkey 2 is via documentation, whether examples, tutorials, API references, etc. There are already docs available, though scattered in various places such as the official Monkey 2 docs, forums, youtube, github and other websites.
Maybe we do need a centralized documentation aggregation point? (ie a Wiki, as scurty suggests)…
I’ve been coding some image filtering functions, one of which is a normal map generator. Still a WIP (no docs, etc), but take a look:
[deleted embedded code, it’s in the attachment.]
@Richard: That link is dead for me…
EDIT: I should point out the normal map generation code uses MX2’s “hidden” Vec3 class, so may break in the future?
EDIT2: Zipped up the code with a “test.jpg” image and attached it to this post (I hope)…
Attachments:
TED2’s File->Quit works for me, but not the File->Quit from the MacOS “bar”. Latest MacOS version.
Define a namespace at the top of ultim.monkey2 e.g:
Namespace ultim
In your main.monkey2 your import should be:
#Import "ultim.monkey2"
and then you need to put the following at the top:
Using ultim..
Alternatively, just delete the Namespace defined in main.monkey2 and fix the import statement, as above.
Here’s the other pooling technique I experimented with:
[/crayon]Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232[crayon-5cba94d088a26742302929 inline="true" ]#import "<std>"Using std.collectionsInterface iPoolableField idx:Int'*** For TESTING only.Method ToString:String()'***EndClass ArrayPoolPrivateField _capacity:IntField _objs:iPoolable[]Field _autoResize:BoolField _autoResizeMultiplier:FloatField _creator:iPoolable()Field _idxAvailable:IntPublicMethod New(creator:iPoolable(), capacity:Int = 10, autoResize:bool = True, autoResizeMultiplier:Float = 2.0)AutoResize = autoResizeAutoResizeMultiplier = autoResizeMultiplierCreator = creatorCapacity = capacity_idxAvailable = 0EndProperty AutoResize:Bool()Return _autoResizeSetter (value:Bool)_autoResize = valueEndProperty AutoResizeMultiplier:Float()Return _autoResizeMultiplierSetter (value:Float)If value <= 1.0 Then value = 1.1_autoResizeMultiplier = valueEndProperty Capacity:Int()Return _capacitySetter (value:Int)If value >= _capacityLocal arr := New iPoolable[value]_objs.CopyTo(arr, 0, 0, _objs.Length)_objs = arrFor Local i:= _capacity Until value_objs[i] = _creator()_objs[i].idx = iNextFindAvailableIdx()Else_objs = _objs.Slice(0, value)If _objs[value] = Null Then _idxAvailable = valueEndif_capacity = valueEndProperty Creator:Void(func:iPoolable())If func = Null Then RuntimeError("Error: Poolable object creation function cannot be null.")_creator = funcEndProperty Contents:iPoolable[]()Return _objsEndMethod FindAvailableIdx:Void()For Local i:Int = 0 Until _objs.LengthIf _objs[i] <> Null_idxAvailable = iReturnEndifNext_idxAvailable = _capacityEndMethod Free:Void(obj:iPoolable)If obj = Null Then Return_idxAvailable -= 1_objs[_idxAvailable] = objEndMethod Allocate:iPoolable()If _idxAvailable >= _capacityIf Not _autoResizeReturn NullElseCapacity *= _autoResizeMultiplierEndifEndifLocal obj := _objs[_idxAvailable]_objs[_idxAvailable] = Null_idxAvailable += 1Return objEnd'*** For TESTINGMethod PrintAll:Void()Print "------"For Local obj := Eachin _objsIf obj = Null Then ContinuePrint obj.ToString() + " -- IDX = " + obj.idxNextPrint "------"End'***End'---------------Class Obj Implements iPoolablePrivateGlobal IdCounter:UInt = 1Field _id:UIntPublicFunction Create:iPoolable()Return New Obj()EndMethod New()_id = IdCounterIdCounter += 1EndMethod ToString:string()Return "ID: " + _idEnd'*** For TESTING only.Function PrintStack:Void(stack:Stack<Obj>)If stack = Null Then ReturnIf stack.Empty Then ReturnFor Local obj:= Eachin stackPrint obj.ToString()NextEnd'***End'---------------Function Main:Void()Local pool:=New ArrayPool(Obj.Create, 5, True)Local active := New Stack<Obj>Print "~n------------"Print "ALLOCATION"Print "------------"Print "~nActive:"For Local n:= 1 To 9Local obj := Cast<Obj>(pool.Allocate())If (obj<>Null)active.Push(obj)ElsePrint "NULL"EndifNextObj.PrintStack(active)Print "~nPooled:"pool.PrintAll()Print "~n------------"Print "FREE"Print "------------"For Local n := 1 To 5pool.Free(active.Pop())NextPrint "~nActive:"Obj.PrintStack(active)Print "~nPooled:"pool.PrintAll()Print "~nAllocate again"For Local n:= 1 To 4Local obj := Cast<Obj>(pool.Allocate())If (obj<>Null)active.Push(obj)ElsePrint "NULL"EndifNextPrint "~nActive:"Obj.PrintStack(active)Print "~nPooled:"pool.PrintAll()EndObjects to be pooled must implement the iPoolable Interface. The pool also requires a “creator function” (basically a constructor replacement).
This technique affords greater flexibility though at a cost of greater abstraction.
I used an array instead of a stack for performance testing reasons – surprisingly there was no performance benefit. Maybe I should reimplement it with a Stack…
IIRC, there is no Monkey1-like Pool class in MX2’s collections library.
I did some pooling experiments several MX2 releases back. I could not find a solution that performed quicker than run-time Newing of objects, regardless of the quantity (on PC hardware). Memory fragmentation issues, however, are theoretically solved by object pooling.
Here’s a simple generic object pooling class:
Note that any objects added to it require a default New() constructor.
[/crayon]Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170[crayon-5cba94d091688724749587 inline="true" ]#import "<std>"Using std.collections'----Class Pool<T>PrivateField _autoResize:BoolField _autoResizeMultiplier:FloatField _capacity:UIntField _objs:Stack<T>Method Fill:Void()For Local n:= _objs.Length Until _capacity'A default constructor (New() without parameters) is required'otherwise the compiler will raise the following error:'Can't find overload for 'new(...)' with argument types ()_objs.Push(New T())NextEndPublicMethod New(capacity:UInt = 10, autoResize:Bool = True, autoResizeMultiplier:Float = 2.0)_objs = New Stack<T>Capacity = capacityAutoResize = autoResizeAutoResizeMultiplier = autoResizeMultiplierEndProperty AutoResize:Bool()Return _autoResizeSetter (value:Bool)_autoResize = valueEndProperty AutoResizeMultiplier:Float()Return _autoResizeMultiplierSetter (value:Float)_autoResizeMultiplier = valueIf _autoResizeMultiplier < 1.1 Then _autoResizeMultiplier = 1.1EndProperty Capacity:UInt()Return _capacitySetter (value:UInt)If value >= _capacity_capacity = valueFill()Else_capacity = valueFor Local n := _objs.Length until _capacity Step - 1_objs.Pop()NextEndifEndProperty Contents:Stack<T>()Return _objsEndMethod Put:Void(obj:T, forceAppend:Bool = False)If _objs.Length < _capacity_objs.Push(obj)ElseIf forceAppend_objs.Push(obj)_capacity += 1EndifEndifEndMethod Get:T()If _objs.EmptyIf AutoResizeCapacity *= AutoResizeMultiplierElseReturn NullEndifEndifReturn _objs.Pop()EndEnd'--------------------Class ObjPrivateGlobal IdCounter:UInt = 1Field _id:UIntPublicMethod New()_id = IdCounterIdCounter += 1EndMethod ToString:string()Return "ID: " + _idEndFunction PrintStack:Void(objs:Stack<Obj>)If objs = Null Then ReturnFor Local obj := Eachin objsPrint obj.ToString()NextEndEnd'--------------------Function Main:Void()Local pool:=New Pool<Obj>(5)Obj.PrintStack(pool.Contents)'pool.Capacity = 15'Obj.PrintStack(pool.Contents)Local active := New Stack<Obj>Print "~n------------"Print "ALLOCATION"Print "------------"Print "~nActive:"For Local n:= 1 To 6Local obj := Cast<Obj>(pool.Get())If (obj<>Null)active.Push(obj)ElsePrint "NULL"EndifNextObj.PrintStack(active)Print "~nPooled:"Obj.PrintStack(pool.Contents)Print "~n------------"Print "FREEING"Print "------------"For Local n := 1 To 3pool.Put(active.Pop(), True)NextPrint "~nActive:"Obj.PrintStack(active)Print "~nPooled:"Obj.PrintStack(pool.Contents)EndI do have another solution somewhere that makes use of objects that implement a “Pooleable” Interface. I’ll see if I can dig it up and post it as another example…
Another tinyxml2 example with element attributes and “embedded XML”:
[/crayon]Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134[crayon-5cba94d098507006274581 inline="true" ]#Import "<std>"#Import "<mojo>"#import "<mojox>"#Import "<tinyxml2>"Using std..Using mojo..Using mojox..Using tinyxml2..Function Main()New AppInstanceNew MyWindow()App.Run()EndClass MyWindow Extends WindowField _tree:TreeViewMethod New()Super.New("XML TreeView Test", 640, 480, WindowFlags.Resizable)Local xml := LoadEmbeddedXMLString()Local doc := New XMLDocument()If doc.Parse(xml) <> XMLError.XML_SUCCESSPrint "Failed to parse embedded XML!"ReturnEndifLocal _tree := New TreeView_tree.RootNode.Text = "XML document"AddXMLNodeToTree(doc, _tree.RootNode)ContentView = _treedoc.Destroy()EndMethod AddXMLNodeToTree(xmlNode:XMLNode, parent:TreeView.Node)Local str := ""Local xmlElement := xmlNode.ToElement()If xmlElementstr += "<" + xmlNode.Value()Local attrib := xmlElement.FirstAttribute()While attribstr += " " + attrib.Name() + "=~q" + attrib.Value() + "~q "attrib=attrib.NextAttribute()wendstr += ">"Elsestr += xmlNode.Value()EndifLocal treeNode:TreeView.NodeIf strtreeNode = New TreeView.Node(str, parent)EndifLocal xmlChild := xmlNode.FirstChild()While xmlChildIf Not xmlChild.NoChildren()If treeNode Then parent = treeNodeEndifAddXMLNodeToTree(xmlChild, parent)xmlChild = xmlChild.NextSibling()WendEndEndFunction LoadEmbeddedXMLString:string()Local str := "<?xml version=~q1.0~q encoding=~qUTF-8~q?><recipes><recipe><name>Recall Scroll</name><results><item name=~qRecall Scroll~q quantity=~q1~q /></results><requirements><skill name=~qAlchemy~q level=~q0~q /><item name=~qMortar and Pestle~q quantity=~q1~q /><item name=~qWood Pulp~q quantity=~q5~q /><item name=~qNightshade~q quantity=~q10~q /><item name=~qBlack Pearl~q quantity=~q10~q /></requirements></recipe><recipe><name>Teleport Scroll</name><results><item name=~qTeleport Scroll~q quantity=~q1~q /></results><requirements><skill name=~qAlchemy~q level=~q0~q /><item name=~qMortar and Pestle~q quantity=~q1~q /><item name=~qWood Pulp~q quantity=~q5~q /><item name=~qMandrake Root~q quantity=~q10~q /><item name=~qBlack Pearl~q quantity=~q10~q /></requirements></recipe></recipes>"Return strEnd -
AuthorPosts