16 bit object names?

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
primem0ver
Posts: 57
Joined: Sat Oct 11, 2014 11:07 pm

16 bit object names?

Post by primem0ver »

How easy or difficult would it be to implement a version of Irrlicht that uses wide characters rather than single byte characters for object names?
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Re: 16 bit object names?

Post by Mel »

What do you mean by object names? If you need to convert from 8 to 16 bit strings, the core::stringw has a constructor that supports a core::stringc.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
primem0ver
Posts: 57
Joined: Sat Oct 11, 2014 11:07 pm

Re: 16 bit object names?

Post by primem0ver »

what I mean is that every object you create in irrlicht has a name property that you can use to search for nodes. ISceneNode::getName and setname take c8 parameters (char *). I want to change this into a wide character (c16) so that every node has a sixteen bit character string name instead of an 8 bit one. This will make it more compatible with other libraries I need to use.
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: 16 bit object names?

Post by mongoose7 »

UTF-8? I don't think there is any such thing as 16-bit characters. Maybe you mean UTF-16?
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: 16 bit object names?

Post by hendu »

Use UTF-8, and when passing from/to your other libs, use irr's utf8-to-wchar and back conversion functions.
primem0ver
Posts: 57
Joined: Sat Oct 11, 2014 11:07 pm

Re: 16 bit object names?

Post by primem0ver »

Here is my core problem I need to resolve. I am using multiple API's in my project (Qt and Irrlicht). I need to write an object manager because objects from both API's are going to need to be accessible from scripting. So I have a base object like so:

Code: Select all

class APPCORE_EXPORT BaseAppObject
{
    ...
    
public:
    virtual const char* appObjectName() const = 0;
    ...
};
The above appears to be compatible with Irrlicht. (I can create a class that inherits the ISceneNode and override the above appObjectName function to return the pointer returned by ISceneNode::getName() function). The problem is that Qt uses the 16 bit QChar* which is incompatible and in order to provide this functionality for Qt objects I would need to create temporary objects to last the lifetime of the script which would be terribly inefficient. The people in the Qt forums tell me their library is too complex to change the way their objects are named because of all the different things it would effect. I need to be able to directly access the object name in both libraries with a generic function. So I am wondering if a customized 16 bit char object name would work and be simple enough to do in Irrlicht.

EDIT: I suppose an object manager could use a different approach to finding the 16 bit string objects but I wouldn't be able to use a generic wrapper/interface for both classes... which is the preferred solution.
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: 16 bit object names?

Post by hendu »

Well sure, you can also modify irr to use QChar, and it's not a terrible amount of work. But given the slowness of strings in general, would the overhead of conversion to 16-bit at read time matter?
primem0ver
Posts: 57
Joined: Sat Oct 11, 2014 11:07 pm

Re: 16 bit object names?

Post by primem0ver »

hendu wrote:Well sure, you can also modify irr to use QChar, and it's not a terrible amount of work.
LOL. That is what I just looked into. I just found the places in the code to make this change to use QChar as the base character. I am going to try that.
hendu wrote:But given the slowness of strings in general, would the overhead of conversion to 16-bit at read time matter?
To me the issue isn't the time. It is the simplicity of the code and the ability to boil it down to once interface. In my experience that gives a lot more flexibility in the long run.
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Re: 16 bit object names?

Post by Seven »

you can also copy/paste the node selection code and add your own filter.
in this code, the only change is that I send in a long ot (object type) and then test against it.

CSObject* obj = getObjectFromNode(current);
if (!obj) return;
if ((current->isVisible()) && (obj->isObjectType(ot)))

all nodes are owned by CSObjects which have a variable called long ObjectType

Code: Select all

 
    //! recursive method for going through all scene nodes
    void CSLevel::getPickedNodeBB(ISceneNode* root,
        core::line3df& ray, s32 bits, bool noDebugObjects,
        f32& outbestdistance, ISceneNode*& outbestnode, long ot)
    {
        const ISceneNodeList& children = root->getChildren();
        const core::vector3df rayVector = ray.getVector().normalize();
 
        ISceneNodeList::ConstIterator it = children.begin();
        for (; it != children.end(); ++it)
        {
            ISceneNode* current = *it;
            if ((noDebugObjects ? !current->isDebugObject() : true))
            {
                CSObject* obj = getObjectFromNode(current);
                if (!obj) return;
                if ((current->isVisible()) && (obj->isObjectType(ot)))
                {
                    // Assume that single-point bounding-boxes are not meant for collision
                    const core::aabbox3df & objectBox = current->getBoundingBox();
                    if (objectBox.isEmpty())
                        continue;
 
                    // get world to object space transform
                    core::matrix4 worldToObject;
                    if (!current->getAbsoluteTransformation().getInverse(worldToObject))
                        continue;
 
                    // transform vector from world space to object space
                    core::line3df objectRay(ray);
                    worldToObject.transformVect(objectRay.start);
                    worldToObject.transformVect(objectRay.end);
 
                    // Do the initial intersection test in object space, since the
                    // object space box test is more accurate.
                    if (objectBox.isPointInside(objectRay.start))
                    {
                        // use fast bbox intersection to find distance to hitpoint
                        // algorithm from Kay et al., code from gamedev.net
                        const core::vector3df dir = (objectRay.end - objectRay.start).normalize();
                        const core::vector3df minDist = (objectBox.MinEdge - objectRay.start) / dir;
                        const core::vector3df maxDist = (objectBox.MaxEdge - objectRay.start) / dir;
                        const core::vector3df realMin(core::min_(minDist.X, maxDist.X), core::min_(minDist.Y, maxDist.Y), core::min_(minDist.Z, maxDist.Z));
                        const core::vector3df realMax(core::max_(minDist.X, maxDist.X), core::max_(minDist.Y, maxDist.Y), core::max_(minDist.Z, maxDist.Z));
 
                        const f32 minmax = core::min_(realMax.X, realMax.Y, realMax.Z);
                        // nearest distance to intersection
                        const f32 maxmin = core::max_(realMin.X, realMin.Y, realMin.Z);
 
                        const f32 toIntersectionSq = (maxmin>0 ? maxmin*maxmin : minmax*minmax);
                        if (toIntersectionSq < outbestdistance)
                        {
                            outbestdistance = toIntersectionSq;
                            outbestnode = current;
 
                            // And we can truncate the ray to stop us hitting further nodes.
                            ray.end = ray.start + (rayVector * sqrtf(toIntersectionSq));
                        }
                    }
                    else
                        if (objectBox.intersectsWithLine(objectRay))
                        {
                            // Now transform into world space, since we need to use world space
                            // scales and distances.
                            core::aabbox3df worldBox(objectBox);
                            current->getAbsoluteTransformation().transformBox(worldBox);
 
                            core::vector3df edges[8];
                            worldBox.getEdges(edges);
 
                            /* We need to check against each of 6 faces, composed of these corners:
                            /3--------/7
                            /  |      / |
                            /   |     /  |
                            1---------5  |
                            |   2- - -| -6
                            |  /      |  /
                            |/        | /
                            0---------4/
 
                            Note that we define them as opposite pairs of faces.
                            */
                            static const s32 faceEdges[6][3] =
                            {
                                { 0, 1, 5 }, // Front
                                { 6, 7, 3 }, // Back
                                { 2, 3, 1 }, // Left
                                { 4, 5, 7 }, // Right
                                { 1, 3, 7 }, // Top
                                { 2, 0, 4 }  // Bottom
                            };
 
                            core::vector3df intersection;
                            core::plane3df facePlane;
                            f32 bestDistToBoxBorder = FLT_MAX;
                            f32 bestToIntersectionSq = FLT_MAX;
 
                            for (s32 face = 0; face < 6; ++face)
                            {
                                facePlane.setPlane(edges[faceEdges[face][0]],
                                    edges[faceEdges[face][1]],
                                    edges[faceEdges[face][2]]);
 
                                // Only consider lines that might be entering through this face, since we
                                // already know that the start point is outside the box.
                                if (facePlane.classifyPointRelation(ray.start) != core::ISREL3D_FRONT)
                                    continue;
 
                                // Don't bother using a limited ray, since we already know that it should be long
                                // enough to intersect with the box.
                                if (facePlane.getIntersectionWithLine(ray.start, rayVector, intersection))
                                {
                                    const f32 toIntersectionSq = ray.start.getDistanceFromSQ(intersection);
                                    if (toIntersectionSq < outbestdistance)
                                    {
                                        // We have to check that the intersection with this plane is actually
                                        // on the box, so need to go back to object space again.
                                        worldToObject.transformVect(intersection);
 
                                        // find the closest point on the box borders. Have to do this as exact checks will fail due to floating point problems.
                                        f32 distToBorder = core::max_(core::min_(core::abs_(objectBox.MinEdge.X - intersection.X), core::abs_(objectBox.MaxEdge.X - intersection.X)),
                                            core::min_(core::abs_(objectBox.MinEdge.Y - intersection.Y), core::abs_(objectBox.MaxEdge.Y - intersection.Y)),
                                            core::min_(core::abs_(objectBox.MinEdge.Z - intersection.Z), core::abs_(objectBox.MaxEdge.Z - intersection.Z)));
                                        if (distToBorder < bestDistToBoxBorder)
                                        {
                                            bestDistToBoxBorder = distToBorder;
                                            bestToIntersectionSq = toIntersectionSq;
                                        }
                                    }
                                }
 
                                // If the ray could be entering through the first face of a pair, then it can't
                                // also be entering through the opposite face, and so we can skip that face.
                                if (!(face & 0x01))
                                    ++face;
                            }
 
                            if (bestDistToBoxBorder < FLT_MAX)
                            {
                                outbestdistance = bestToIntersectionSq;
                                outbestnode = current;
 
                                // If we got a hit, we can now truncate the ray to stop us hitting further nodes.
                                ray.end = ray.start + (rayVector * sqrtf(outbestdistance));
                            }
                        }
                }
 
                // Only check the children if this node is visible.
                getPickedNodeBB(current, ray, bits, noDebugObjects, outbestdistance, outbestnode, ot);
            }
        }
    }
 
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: 16 bit object names?

Post by CuteAlien »

To answer the original question - it wouldn't be difficult. But it changes the library interface and I only do that when the gain is large enough and there are no other workarounds.

But in the long run it might be a good idea. So when we switch to stl in next Irrlicht version (which breaks interfaces anyway) I'll consider it (aka switching to std::wstring).

I'm not sure why Niko used 8-bit here when he worked with 16-bit characters in other places. Maybe because he considered this more of a label than real text (just guessing).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
primem0ver
Posts: 57
Joined: Sat Oct 11, 2014 11:07 pm

Re: 16 bit object names?

Post by primem0ver »

CuteAlien wrote:To answer the original question - it wouldn't be difficult. But it changes the library interface and I only do that when the gain is large enough and there are no other workarounds.

But in the long run it might be a good idea. So when we switch to stl in next Irrlicht version (which breaks interfaces anyway) I'll consider it (aka switching to std::wstring).

I'm not sure why Niko used 8-bit here when he worked with 16-bit characters in other places. Maybe because he considered this more of a label than real text (just guessing).
Wow. Thanks! As I said, I made some changes today to see how involved it would be There are a lot more changes than I originally thought (compiler counted 1000+ errors because of missing conversion issue) but it would be doable in the long run Many of those issues were repeated header lines. I think for my initial prototyping I may use a temporary workaround that is based on wide characters rather than 8 bit ones. That way the change will be compatible no matter whose changes I use.

I agree with your reasoning. I asked Qt why they went with wide characters for their object names and they basically just decided they didn't want to have to deal with more than one main string type.

If you end up making the changes before I do, I would suggest doing in in the same style you currently have. This is because while the wchar_t type is interchangeable with Qt's wide char; their classes are a bit different. So if necessary I could still define a string as...

Code: Select all

typedef string<QChar> stringw
Post Reply