Hi,
I've started using scroll, and I find it very useful. One extra feature that I'd really make use of, is somehow enabling object class hierarchies in config files. For instance:
[ObjectBase]
; various object fields...
ClassIdentifier = MyObjectType
[DerivedObject1@ObjectBase]
; various other object fields...
[DerivedObject2@ObjectBase]
; even more different object fields...
With this config file, if I now register the identifier "MyObjectType" to one of my ScrollObject classes, all derived objects will also be created as one.
Motivation: The reason why I'm asking for this, is that I can then start introducing custom fields for my base classes, that get handled correctly by the corresponding C++ type.
Implementation: I think ScrollObjectBinder<ScrollObject>, the binder that's used when the object type doesn't match any registered class could be made to create an object as usual, and check for the existence of the ClassIdentifier field. If it exists and the value matches a registered class, it could use the
template<class O>
ScrollObject *ScrollObjectBinder<O>::CreateObject(orxOBJECT *_pstOrxObject, const orxSTRING _zInstanceName, ScrollObject::Flag _xFlags)
wrapper method of the corresponding type.
Thanks!
Comments
The issue being that the binding actually takes place at compile time and the config info (with the ClassIdentifier property) is only available at runtime.
Lacking reflection mechanism I wouldn't be able to find the correct C++ class from the string anyway.
What I can support though, is that if you bind a C++ class to a config section, any section inheriting from that config section will also default to that binding unless it has its own binding.
My understanding was: the ClassIdentifier is a config property, from the syntax you used:
Is that correct or am I already wrong?
Assuming that's the case, that means I can't get the value of that property at compile time, only at runtime.
However the template parameter of ScrollBindObject<Class>("ConfigSection") is resolved at compile time and I wouldn't be able to extract it from the ClassIdentifier property.
But after reading your reply, it doesn't look like it was what you were proposing so I'm not sure anymore what the ClassIdentifier actually is if you still do the binding explicitly in code.
I'll reread that tonight after getting a nap, I think.
So, I've decided to describe what I want by actually doing it myself (poorly). I've basically injected the following code segment :
inside
in the file ScrollBase.inl, right after
So, what I'm basically doing is, if the object name doesn't match any of those that are registered, I'm checking if the "ClassIdentifier" field matches.
This way:
gets created as a MyClass instance, if I do the registration as:
void OrxScroll::BindObjects ()
{
ScrollBindObject<MyClass> ("myclassid");
}
This solution is clearly missing something, since the game crashes when I try to close it. I've traced the crash to the
method, with O = ScrollObject. I guess some extra plumbing needs to be added.
Cheers
So that will only work if you've already bound something to your C++ class named MyClass, otherwise the binder won't be found.
In that case why not binding all the instances in code instead of having some bound in code and some bound via config info, that doesn't sound very consistent to me.
In your case you're crashing because you've substituted the binder for the object creation but not for the object deletion, so your object will be deleted with the default binder (ScrollObject) and will not be able to free the memory bank slot.
As I said, I'm not convinced by that hybrid approach as some bindings will be done via code and some via config. I think I prefer trying to mimic inheritance by using the config section parenting to find the default parent binder if none is provided.
Btw, I've added orxDisplay_DrawMesh() but only the GLFW implementation is here for now.
XY coordinates are in pixel and UV ones are normalized.
I'll add an example on how to use it to the default orx playground (orxBounce) tomorrow.
I've just modified the GLFW implementation so that it now behaves in a triangle strip way.
I've added an example in orxBounce which will now display a (crude) trail behind the mouse cursor, at least it shows how it works.
One can use the orxRender_GetScreenPosition() function to transforw world coordinates into screen ones, of course.
I'll try to do the iOS implementation soon-ish and hopefully someone will be able to do the Android one in not so long.
I've just had the chance to check the trail. It's working really nice! The interface you provide is also very clean. I shall get down to porting my engine as soon as possible.
One little question though; since not every mesh can be expressed as a simple triangle strip, one might have to call the orxDisplay_DrawMesh() function multiple times. Is this prohibitively expensive behind the scenes? or does even the worst case of drawing each triangle one by one with an individual call has an acceptable overhead (To put a number, let's say if I have 1000s of triangles)?
I could try to do the Android bit, but I don't think I'll be able to get down to it in the near future, so someone will very likely beat me to it. I have a related question BTW. Whenever I try to dig into orx source code, I'm met with a barrier of macros that make it very hard to navigate. One method I use to familiarize myself with unfamiliar code, is to simply step through it with a debugger. Unfortunately, the same barrier of macros confuse the hell out of CDB. Do you have any hints as to how I should approach the orx source code? Which IDE/Debugger do you use personally for instance (I'm sure it handles the macros better)?
Glad you appreciate it!
Calls will get batched behind the scene as much as possible. As long as there's no change in the current rendering context (ie. change of texture, change of filtering (smoothing) or change of blending mode), things gets batched.
However the batch size is implementation defined, usually 2000 or 4000 triangles per batch. If you need to display bigger strips I recommend on slicing them in more than one call. If it's a too big limitation for you, we can try to find a compromise somewhere.
Heh, no worries, I'm sure lydesik or faistoiplaisir will port the iOS or GLFW version at some point (or fix my port if I end up doing it myself! ).
Mmh interesting.
Which macros in particular? They're mostly used as an interface for the plugins (allowing to run in either hotplug or embedded mode) and for some casting+check helpers.
When coming to a new project I usually use Source Navigator for that purpose. Other than that, I have no preferred editor really, it depends on which platform I am. On mac I use XCode, on windows I use Visual Studio Express and on Linux I use CodeLite.
They all have pros and cons unfortunately.
Just as a reminder of what we've been discussing on this thread:
if I have an orx object defined by the following config entry:
[Car@Vehicle]
...
and if I register a class for "Vehicle" in scroll, that Car would also be wrapped by that class.
My alternative suggestion was:
[Car]
classId = Vehicle ; Note here that Vehicle here does not have to be the name of the class in C++, it'll still be registered.
And it would work the same way.
Is any of these two features implemented? I've later realized that I can achieve the same effect by writing my special register function that takes a type parameter and a string and walks all the config sections, registering all that include a classId field matching the string. Though I'd like to use the standard one if it's available, or to be implemented.
I also added a default ScrollObject binding to any config section that inherits from a config section [ScrollObject].
Let me know if you have any issues.
Cheers!
It works really nicely. Now I can truly define my custom object classes, with special fields!
Is the syntax what was described earlier with the class id field, or do I just need to use [Object@Object]?
If you have:
Then you'll get:
Button -> cButton
GreenButton -> cButton
GlowingButton -> cGlowingButton
RedGlowingButton -> cGlowingButton