Пример #1
0
void Sys_ShowCursor(boolean show)
{
#ifdef WIN32
    ShowCursor(show);
#else
    // The cursor is controlled using Qt in Canvas.
    DENG2_UNUSED(show);
#endif
}
Пример #2
0
Feed::PopulatedFiles StaticLibraryFeed::populate(Folder const &folder)
{
    PopulatedFiles files;
#if defined (DENG_STATIC_LINK)
    for (String name : Library::staticLibraries())
    {
        if (!folder.has(name))
        {
            files << new LibraryFile(NativePath(name));
        }
    }
#else
    DENG2_UNUSED(folder);
#endif
    return files;
}
Пример #3
0
void SV_LoadGameClient(uint /*sessionId*/)
{
    throw de::Error("SV_LoadGameClient", "Not currently implemented");

#if 0
#if !__JHEXEN__ // unsupported in libhexen
    player_t *cpl = players + CONSOLEPLAYER;
    mobj_t *mo    = cpl->plr->mo;

    if(!IS_CLIENT || !mo)
        return;

    de::game::GameStateFolder *session = new de::game::GameStateFolder(saveNameForClientSessionId(sessionId));
    de::game::GameStateMetadata *metadata = new de::game::GameStateMetadata;
    //G_ReadLegacySessionMetadata(metadata, reader);
    metadata->set("sessionId", sessionId);
    session->replaceMetadata(metadata);

    de::Path path = de::String("/savegame") / "client" / session->path();
    if(!SV_OpenFileForRead(path))
    {
        delete session;
        App_Log(DE2_RES_WARNING, "SV_LoadGameClient: Failed opening \"%s\" for reading",
                path.toString().toLatin1().constData());
        return;
    }

    if((*metadata)["magic"].value().asNumber() != MY_CLIENT_SAVE_MAGIC)
    {
        SV_CloseFile();
        delete session;
        App_Log(DE2_RES_ERROR, "Client save file format not recognized");
        return;
    }

    Reader1 *reader = SV_NewReader();

    int const saveVersion = (*metadata)["version"].value().asNumber();
    Uri *mapUri           = Uri_NewWithPath2((*metadata)["mapUri"].value().asText().toUtf8().constData(), RC_NULL);
    GameRules *rules    = 0;
    if(metadata->hasSubrecord("gameRules"))
    {
        rules = GameRules::fromRecord(metadata->subrecord("gameRules"));
    }

    // Do we need to change the map?
    if(gfw_Session()->mapUri() != *reinterpret_cast<de::Uri *>(mapUri))
    {
        gfw_Session()->begin(*mapUri, 0/*default*/, *rules);
    }
    else if(rules)
    {
        gfw_Session()->rules() = *rules;
    }

    delete rules; rules = 0;
    Uri_Delete(mapUri); mapUri = 0;

    mapTime = (*metadata)["mapTime"].value().asNumber();

    P_MobjUnlink(mo);
    mo->origin[VX] = FIX2FLT(Reader_ReadInt32(reader));
    mo->origin[VY] = FIX2FLT(Reader_ReadInt32(reader));
    mo->origin[VZ] = FIX2FLT(Reader_ReadInt32(reader));
    P_MobjLink(mo);
    mo->floorZ     = FIX2FLT(Reader_ReadInt32(reader));
    mo->ceilingZ   = FIX2FLT(Reader_ReadInt32(reader));
    mo->angle      = Reader_ReadInt32(reader); /* $unifiedangles */

    cpl->plr->lookDir = Reader_ReadFloat(reader); /* $unifiedangles */

#if __JHEXEN__
    if(saveVersion >= 4)
#else
    if(saveVersion >= 5)
#endif
    {
        SV_AssertSegment(ASEG_PLAYER_HEADER);
    }
    playerheader_t plrHdr;
    plrHdr.read(reader, saveVersion);

    cpl->read(reader, plrHdr);

    MapStateReader(*session).read(Str_Text(Uri_Resolved(mapUri)));

    SV_CloseFile();
    Reader_Delete(reader);
    delete session;
#else
    DENG2_UNUSED(sessionId);
#endif
#endif
}
Пример #4
0
void SV_SaveGameClient(uint /*sessionId*/)
{
    throw de::Error("SV_SaveGameClient", "Not currently implemented");

#if 0
#if !__JHEXEN__ // unsupported in libhexen
    player_t *pl = &players[CONSOLEPLAYER];
    mobj_t *mo   = pl->plr->mo;

    if(!IS_CLIENT || !mo)
        return;

    // Prepare new saved game session session.
    de::game::GameStateFolder *session = new de::game::GameStateFolder(saveNameForClientSessionId(sessionId));
    de::game::GameStateMetadata *metadata = G_CurrentSessionMetadata();
    metadata->set("sessionId", sessionId);
    session->replaceMetadata(metadata);

    de::Path path = de::String("/savegame") / "client" / session->path();
    if(!SV_OpenFileForWrite(path))
    {
        App_Log(DE2_RES_WARNING, "SV_SaveGameClient: Failed opening \"%s\" for writing",
                path.toString().toLatin1().constData());

        // Discard the useless session.
        delete session;
        return;
    }

    Writer1 *writer = SV_NewWriter();
    SV_WriteSessionMetadata(*metadata, writer);

    // Some important information.
    // Our position and look angles.
    Writer_WriteInt32(writer, FLT2FIX(mo->origin[VX]));
    Writer_WriteInt32(writer, FLT2FIX(mo->origin[VY]));
    Writer_WriteInt32(writer, FLT2FIX(mo->origin[VZ]));
    Writer_WriteInt32(writer, FLT2FIX(mo->floorZ));
    Writer_WriteInt32(writer, FLT2FIX(mo->ceilingZ));
    Writer_WriteInt32(writer, mo->angle); /* $unifiedangles */

    Writer_WriteFloat(writer, pl->plr->lookDir); /* $unifiedangles */

    SV_BeginSegment(ASEG_PLAYER_HEADER);
    playerheader_t plrHdr;
    plrHdr.write(writer);

    players[CONSOLEPLAYER].write(writer, plrHdr);

    ThingArchive thingArchive;
    MapStateWriter(thingArchive).write(writer);
    /// @todo No consistency bytes in client saves?

    SV_CloseFile();
    Writer_Delete(writer);
    delete session;
#else
    DENG2_UNUSED(sessionId);
#endif
#endif
}
Пример #5
0
void SV_TranslateLegacyMobjFlags(mobj_t *mo, int ver)
{
#if __JDOOM64__
    // Nothing to do.
    DENG2_UNUSED(mo);
    DENG2_UNUSED(ver);
    return;
#endif

#if __JDOOM__ || __JHERETIC__
    if(ver < 6)
    {
        // mobj.flags
# if __JDOOM__
        // switched values for MF_BRIGHTSHADOW <> MF_BRIGHTEXPLODE
        if((mo->flags & MF_BRIGHTEXPLODE) != (mo->flags & MF_BRIGHTSHADOW))
        {
            if(mo->flags & MF_BRIGHTEXPLODE) // previously MF_BRIGHTSHADOW
            {
                mo->flags |= MF_BRIGHTSHADOW;
                mo->flags &= ~MF_BRIGHTEXPLODE;
            }
            else // previously MF_BRIGHTEXPLODE
            {
                mo->flags |= MF_BRIGHTEXPLODE;
                mo->flags &= ~MF_BRIGHTSHADOW;
            }
        } // else they were both on or off so it doesn't matter.
# endif
        // Remove obsoleted flags in earlier save versions.
        mo->flags &= ~MF_V6OBSOLETE;

        // mobj.flags2
# if __JDOOM__
        // jDoom only gained flags2 in ver 6 so all we can do is to
        // apply the values as set in the mobjinfo.
        // Non-persistent flags might screw things up a lot worse otherwise.
        mo->flags2 = mo->info->flags2;
# endif
    }
#endif

#if __JDOOM__ || __JHERETIC__
    if(ver < 9)
    {
        mo->spawnSpot.flags &= ~MASK_UNKNOWN_MSF_FLAGS;
        // Spawn on the floor by default unless the mobjtype flags override.
        mo->spawnSpot.flags |= MSF_Z_FLOOR;
    }
#endif

#if __JHEXEN__
    if(ver < 5)
#else
    if(ver < 7)
#endif
    {
        // flags3 was introduced in a latter version so all we can do is to
        // apply the values as set in the mobjinfo.
        // Non-persistent flags might screw things up a lot worse otherwise.
        mo->flags3 = mo->info->flags3;
    }
}
Пример #6
0
/**
 * Reads all versions of archived lines.
 * Including the old Ver1.
 */
void SV_ReadLine(Line *li, MapStateReader *msr)
{
    xline_t *xli   = P_ToXLine(li);
    Reader1 *reader = msr->reader();
    int mapVersion = msr->mapVersion();

    bool xgDataFollows = false;
#if __JHEXEN__
    if(mapVersion >= 4)
#else
    if(mapVersion >= 2)
#endif
    {
        xgDataFollows = Reader_ReadByte(reader) == 1;
    }
#ifdef __JHEXEN__
    DENG2_UNUSED(xgDataFollows);
#endif

    // A version byte?
    int ver = 1;
#if __JHEXEN__
    if(mapVersion >= 3)
#else
    if(mapVersion >= 5)
#endif
    {
        ver = (int) Reader_ReadByte(reader);
    }

    if(ver >= 4)
    {
        P_SetIntp(li, DMU_FLAGS, Reader_ReadInt16(reader));
    }

    int flags = Reader_ReadInt16(reader);
    if(xli->flags & ML_TWOSIDED)
    {
        flags |= ML_TWOSIDED;
    }

    if(ver < 4)
    {
        // Translate old line flags.
        int ddLineFlags = 0;

        if(flags & 0x0001) // old ML_BLOCKING flag
        {
            ddLineFlags |= DDLF_BLOCKING;
            flags &= ~0x0001;
        }

        if(flags & 0x0008) // old ML_DONTPEGTOP flag
        {
            ddLineFlags |= DDLF_DONTPEGTOP;
            flags &= ~0x0008;
        }

        if(flags & 0x0010) // old ML_DONTPEGBOTTOM flag
        {
            ddLineFlags |= DDLF_DONTPEGBOTTOM;
            flags &= ~0x0010;
        }

        P_SetIntp(li, DMU_FLAGS, ddLineFlags);
    }

    if(ver < 3)
    {
        if(flags & ML_MAPPED)
        {
            int lineIDX = P_ToIndex(li);

            // Set line as having been seen by all players..
            de::zap(xli->mapped);
            for(int i = 0; i < MAXPLAYERS; ++i)
            {
                P_SetLineAutomapVisibility(i, lineIDX, true);
            }
        }
    }

    xli->flags = flags;

    if(ver >= 3)
    {
        for(int i = 0; i < MAXPLAYERS; ++i)
        {
            xli->mapped[i] = Reader_ReadByte(reader);
        }
    }

#if __JHEXEN__
    xli->special = Reader_ReadByte(reader);
    xli->arg1    = Reader_ReadByte(reader);
    xli->arg2    = Reader_ReadByte(reader);
    xli->arg3    = Reader_ReadByte(reader);
    xli->arg4    = Reader_ReadByte(reader);
    xli->arg5    = Reader_ReadByte(reader);
#else
    xli->special = Reader_ReadInt16(reader);
    /*xli->tag     =*/ Reader_ReadInt16(reader);
#endif

    // For each side
    for(int i = 0; i < 2; ++i)
    {
        Side *si = (Side *)P_GetPtrp(li, (i? DMU_BACK:DMU_FRONT));
        if(!si) continue;

        // Versions latter than 2 store per surface texture offsets.
        if(ver >= 2)
        {
            float offset[2];

            offset[VX] = (float) Reader_ReadInt16(reader);
            offset[VY] = (float) Reader_ReadInt16(reader);
            P_SetFloatpv(si, DMU_TOP_MATERIAL_OFFSET_XY, offset);

            offset[VX] = (float) Reader_ReadInt16(reader);
            offset[VY] = (float) Reader_ReadInt16(reader);
            P_SetFloatpv(si, DMU_MIDDLE_MATERIAL_OFFSET_XY, offset);

            offset[VX] = (float) Reader_ReadInt16(reader);
            offset[VY] = (float) Reader_ReadInt16(reader);
            P_SetFloatpv(si, DMU_BOTTOM_MATERIAL_OFFSET_XY, offset);
        }
        else
        {
            float offset[2];

            offset[VX] = (float) Reader_ReadInt16(reader);
            offset[VY] = (float) Reader_ReadInt16(reader);

            P_SetFloatpv(si, DMU_TOP_MATERIAL_OFFSET_XY,    offset);
            P_SetFloatpv(si, DMU_MIDDLE_MATERIAL_OFFSET_XY, offset);
            P_SetFloatpv(si, DMU_BOTTOM_MATERIAL_OFFSET_XY, offset);
        }

        if(ver >= 3)
        {
            P_SetIntp(si, DMU_TOP_FLAGS,    Reader_ReadInt16(reader));
            P_SetIntp(si, DMU_MIDDLE_FLAGS, Reader_ReadInt16(reader));
            P_SetIntp(si, DMU_BOTTOM_FLAGS, Reader_ReadInt16(reader));
        }

        world_Material *topMaterial = 0, *bottomMaterial = 0, *middleMaterial = 0;

#if !__JHEXEN__
        if(mapVersion >= 4)
#endif
        {
            topMaterial    = msr->material(Reader_ReadInt16(reader), 1);
            bottomMaterial = msr->material(Reader_ReadInt16(reader), 1);
            middleMaterial = msr->material(Reader_ReadInt16(reader), 1);
        }

        P_SetPtrp(si, DMU_TOP_MATERIAL,    topMaterial);
        P_SetPtrp(si, DMU_BOTTOM_MATERIAL, bottomMaterial);
        P_SetPtrp(si, DMU_MIDDLE_MATERIAL, middleMaterial);

        // Ver2 includes surface colours
        if(ver >= 2)
        {
            float rgba[4];
            int flags;

            for(int k = 0; k < 3; ++k)
                rgba[k] = (float) Reader_ReadByte(reader) / 255.f;
            rgba[3] = 1;
            P_SetFloatpv(si, DMU_TOP_COLOR, rgba);

            for(int k = 0; k < 3; ++k)
                rgba[k] = (float) Reader_ReadByte(reader) / 255.f;
            rgba[3] = 1;
            P_SetFloatpv(si, DMU_BOTTOM_COLOR, rgba);

            for(int k = 0; k < 4; ++k)
                rgba[k] = (float) Reader_ReadByte(reader) / 255.f;
            P_SetFloatpv(si, DMU_MIDDLE_COLOR, rgba);

            P_SetIntp(si, DMU_MIDDLE_BLENDMODE, Reader_ReadInt32(reader));

            flags = Reader_ReadInt16(reader);

            if(mapVersion < 12)
            {
                if(P_GetIntp(si, DMU_FLAGS) & SDF_SUPPRESS_BACK_SECTOR)
                    flags |= SDF_SUPPRESS_BACK_SECTOR;
            }
            P_SetIntp(si, DMU_FLAGS, flags);
        }
    }

#if !__JHEXEN__
    if(xgDataFollows)
    {
        SV_ReadXGLine(li, msr);
    }
#endif
}
Пример #7
0
void playerheader_s::read(Reader1 *reader, int saveVersion)
{
#if __JHEXEN__
    if(saveVersion >= 4)
#else
    if(saveVersion >= 5)
#endif
    {
        int ver = Reader_ReadByte(reader);
#if !__JHERETIC__
        DENG2_UNUSED(ver);
#endif

        numPowers      = Reader_ReadInt32(reader);
        numKeys        = Reader_ReadInt32(reader);
        numFrags       = Reader_ReadInt32(reader);
        numWeapons     = Reader_ReadInt32(reader);
        numAmmoTypes   = Reader_ReadInt32(reader);
        numPSprites    = Reader_ReadInt32(reader);
#if __JHERETIC__
        if(ver >= 2)
            numInvItemTypes = Reader_ReadInt32(reader);
        else
            numInvItemTypes = NUM_INVENTORYITEM_TYPES;
#endif
#if __JHEXEN__ || __JDOOM64__
        numInvItemTypes = Reader_ReadInt32(reader);
#endif
#if __JHEXEN__
        numArmorTypes  = Reader_ReadInt32(reader);
#endif
    }
    else // The old format didn't save the counts.
    {
#if __JHEXEN__
        numPowers       = 9;
        numKeys         = 11;
        numFrags        = 8;
        numWeapons      = 4;
        numAmmoTypes    = 2;
        numPSprites     = 2;
        numInvItemTypes = 33;
        numArmorTypes   = 4;
#elif __JDOOM__ || __JDOOM64__
        numPowers       = 6;
        numKeys         = 6;
        numFrags        = 4; // Why was this only 4?
        numWeapons      = 9;
        numAmmoTypes    = 4;
        numPSprites     = 2;
# if __JDOOM64__
        numInvItemTypes = 3;
# endif
#elif __JHERETIC__
        numPowers       = 9;
        numKeys         = 3;
        numFrags        = 4; // ?
        numWeapons      = 8;
        numInvItemTypes = 14;
        numAmmoTypes    = 6;
        numPSprites     = 2;
#endif
    }
}
Пример #8
0
int de::KeyEvent::ddKeyFromQt(int qtKey, int nativeVirtualKey, int nativeScanCode)
{
#ifdef MACOSX
    switch (qtKey)
    {
    case Qt::Key_Meta:          return DDKEY_RCTRL;
    case Qt::Key_Control:       return 0; // Don't map the Command key.
    case Qt::Key_F14:           return DDKEY_PAUSE; // No pause key on the Mac.
    case Qt::Key_F15:           return DDKEY_PRINT;

    default:
        break;
    }
#endif

#ifdef XFREE_KEYMAPPING
    // We'll check before the generic Qt keys to detect the numpad.
    int mapped = x11ScancodeToDDKey(nativeScanCode);
    if (mapped) return mapped;
#else
    DENG2_UNUSED(nativeScanCode);
#endif

    // Non-character-inserting keys.
    switch (qtKey)
    {
    case Qt::Key_Escape:        return DDKEY_ESCAPE;
    case Qt::Key_Tab:           return DDKEY_TAB;
    case Qt::Key_Backtab:       return DDKEY_TAB; // Shift detected separately
    case Qt::Key_Backspace:     return DDKEY_BACKSPACE;
    case Qt::Key_Space:         return ' ';
    case Qt::Key_Pause:         return DDKEY_PAUSE;
    case Qt::Key_Up:            return DDKEY_UPARROW;
    case Qt::Key_Down:          return DDKEY_DOWNARROW;
    case Qt::Key_Left:          return DDKEY_LEFTARROW;
    case Qt::Key_Right:         return DDKEY_RIGHTARROW;
    case Qt::Key_Control:       return DDKEY_RCTRL;
    case Qt::Key_Shift:         return DDKEY_RSHIFT;
    case Qt::Key_Alt:           return DDKEY_RALT;
    case Qt::Key_AltGr:         return DDKEY_LALT;
    case Qt::Key_Menu:          return DDKEY_WINMENU;
    case Qt::Key_Return:        return DDKEY_RETURN;
    case Qt::Key_F1:            return DDKEY_F1;
    case Qt::Key_F2:            return DDKEY_F2;
    case Qt::Key_F3:            return DDKEY_F3;
    case Qt::Key_F4:            return DDKEY_F4;
    case Qt::Key_F5:            return DDKEY_F5;
    case Qt::Key_F6:            return DDKEY_F6;
    case Qt::Key_F7:            return DDKEY_F7;
    case Qt::Key_F8:            return DDKEY_F8;
    case Qt::Key_F9:            return DDKEY_F9;
    case Qt::Key_F10:           return DDKEY_F10;
    case Qt::Key_F11:           return DDKEY_F11;
    case Qt::Key_F12:           return DDKEY_F12;
    case Qt::Key_NumLock:       return DDKEY_NUMLOCK;
    case Qt::Key_ScrollLock:    return DDKEY_SCROLL;
    case Qt::Key_Enter:         return DDKEY_ENTER;
    case Qt::Key_Insert:        return DDKEY_INS;
    case Qt::Key_Delete:        return DDKEY_DEL;
    case Qt::Key_Home:          return DDKEY_HOME;
    case Qt::Key_End:           return DDKEY_END;
    case Qt::Key_PageUp:        return DDKEY_PGUP;
    case Qt::Key_PageDown:      return DDKEY_PGDN;
    case Qt::Key_SysReq:        return DDKEY_PRINT;
    case Qt::Key_Print:         return DDKEY_PRINT;
    case Qt::Key_CapsLock:      return DDKEY_CAPSLOCK;
#ifdef WIN32
    case Qt::Key_Meta:          return 0; // Ignore Windows key.
#endif
    default:
        break;
    }

    /// We'll have to use the native virtual keys to make a distinction, e.g.,
    /// between the number row and the keypad. These are the real physical keys
    /// -- the insertion text is provided outside this mapping.

#ifdef WIN32
    /// @todo Would the native scancodes be more appropriate than virtual keys?
    /// (no influence from language settings)
    checkWin32Keymap();
    if (win32Keymap[nativeVirtualKey] > 0)
    {
        // We know a mapping for this.
        return win32Keymap[nativeVirtualKey];
    }
#endif

#ifdef MACOSX
    switch (nativeVirtualKey)
    {
    case 0x00:                  return 'a';
    case 0x01:                  return 's';
    case 0x02:                  return 'd';
    case 0x03:                  return 'f';
    case 0x04:                  return 'h';
    case 0x05:                  return 'g';
    case 0x06:                  return 'z';
    case 0x07:                  return 'x';
    case 0x08:                  return 'c';
    case 0x09:                  return 'v';
    case 0x0A:                  return DDKEY_SECTION;
    case 0x0B:                  return 'b';
    case 0x0C:                  return 'q';
    case 0x0D:                  return 'w';
    case 0x0E:                  return 'e';
    case 0x0F:                  return 'r';
    case 0x10:                  return 'y';
    case 0x11:                  return 't';
    case 0x12:                  return '1';
    case 0x13:                  return '2';
    case 0x14:                  return '3';
    case 0x15:                  return '4';
    case 0x16:                  return '6';
    case 0x17:                  return '5';
    case 0x18:                  return '=';
    case 0x19:                  return '9';
    case 0x1A:                  return '7';
    case 0x1B:                  return '-';
    case 0x1C:                  return '8';
    case 0x1D:                  return '0';
    case 0x1E:                  return ']';
    case 0x1F:                  return 'o';
    case 0x20:                  return 'u';
    case 0x21:                  return '[';
    case 0x22:                  return 'i';
    case 0x23:                  return 'p';
    case 0x25:                  return 'l';
    case 0x26:                  return 'j';
    case 0x27:                  return '\'';
    case 0x28:                  return 'k';
    case 0x29:                  return ';';
    case 0x2A:                  return '\\';
    case 0x2B:                  return ',';
    case 0x2C:                  return '/';
    case 0x2D:                  return 'n';
    case 0x2E:                  return 'm';
    case 0x2F:                  return '.';
    case 0x32:                  return '`';
    case 82:                    return DDKEY_NUMPAD0;
    case 83:                    return DDKEY_NUMPAD1;
    case 84:                    return DDKEY_NUMPAD2;
    case 85:                    return DDKEY_NUMPAD3;
    case 86:                    return DDKEY_NUMPAD4;
    case 87:                    return DDKEY_NUMPAD5;
    case 88:                    return DDKEY_NUMPAD6;
    case 89:                    return DDKEY_NUMPAD7;
    case 91:                    return DDKEY_NUMPAD8;
    case 92:                    return DDKEY_NUMPAD9;
    case 65:                    return DDKEY_DECIMAL;
    case 69:                    return DDKEY_ADD;
    case 78:                    return DDKEY_SUBTRACT;
    case 75:                    return DDKEY_DIVIDE;
    case 0x43:                  return DDKEY_MULTIPLY;

    default:
        break;
    }
#endif

    // Not supported!
    LOGDEV_INPUT_WARNING("Ignored unknown key: Qt key %i (%x), virtualKey %i, scancode %i")
            << qtKey << qtKey << nativeVirtualKey << nativeScanCode;

    return 0;
}
Пример #9
0
    /**
     * Remove all the line segments from the list, partitioning them into the
     * left or right sets according to their position relative to partition line.
     * Adds any intersections onto the intersection list as it goes.
     *
     * @param node    Block tree node containing the line segments to be partitioned.
     * @param rights  Set of line segments on the right side of the partition.
     * @param lefts   Set of line segments on the left side of the partition.
     */
    void divideSegments(LineSegmentBlockTreeNode &node, LineSegmentBlockTreeNode &rights,
                        LineSegmentBlockTreeNode &lefts)
    {
        /**
         * @todo Revise this algorithm so that @var segments is not modified
         * during the partitioning process.
         */
        int const totalSegs = node.userData()->totalCount();
        DENG2_ASSERT(totalSegs != 0);
        DENG2_UNUSED(totalSegs);

        // Iterative pre-order traversal of SuperBlock.
        LineSegmentBlockTreeNode *cur  = &node;
        LineSegmentBlockTreeNode *prev = nullptr;
        while(cur)
        {
            while(cur)
            {
                LineSegmentBlock &segs = *cur->userData();

                LineSegmentSide *seg;
                while((seg = segs.pop()))
                {
                    // Disassociate the line segment from the block tree.
                    seg->setBlockTreeNode(nullptr);

                    divideOneSegment(*seg, rights, lefts);
                }

                if(prev == cur->parentPtr())
                {
                    // Descending - right first, then left.
                    prev = cur;
                    if(cur->hasRight()) cur = cur->rightPtr();
                    else                cur = cur->leftPtr();
                }
                else if(prev == cur->rightPtr())
                {
                    // Last moved up the right branch - descend the left.
                    prev = cur;
                    cur = cur->leftPtr();
                }
                else if(prev == cur->leftPtr())
                {
                    // Last moved up the left branch - continue upward.
                    prev = cur;
                    cur = cur->parentPtr();
                }
            }

            if(prev)
            {
                // No left child - back up.
                cur = prev->parentPtr();
            }
        }

        // Sanity checks...
        DENG2_ASSERT(rights.userData()->totalCount());
        DENG2_ASSERT(lefts.userData ()->totalCount());
        DENG2_ASSERT((  rights.userData()->totalCount()
                      + lefts.userData ()->totalCount()) >= totalSegs);
    }