root/trunk/src/shared/vmap/VMapManager.cpp @ 102

Revision 102, 24.8 kB (checked in by yumileroy, 17 years ago)

[svn] Fixed copyright notices to comply with GPL.

Original author: w12x
Date: 2008-10-23 03:29:52-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "VMapManager.h"
22#include "VMapDefinitions.h"
23
24using namespace G3D;
25
26namespace VMAP
27{
28
29    //=========================================================
30
31    VMapManager::VMapManager()
32    {
33#ifdef _VMAP_LOG_DEBUG
34        iCommandLogger.setFileName("vmapcmd.log");
35        iCommandLogger.setResetFile();
36#endif
37    }
38
39    //=========================================================
40
41    VMapManager::~VMapManager(void)
42    {
43        Array<unsigned int > keyArray = iInstanceMapTrees.getKeys();
44        for(int i=0;i<keyArray.size(); ++i)
45        {
46            delete iInstanceMapTrees.get(keyArray[i]);
47            iInstanceMapTrees.remove(keyArray[i]);
48        }
49    }
50
51    //=========================================================
52
53    Vector3 VMapManager::convertPositionToInternalRep(float x, float y, float z) const
54    {
55        float pos[3];
56        pos[0] = y;
57        pos[1] = z;
58        pos[2] = x;
59        double full = 64.0*533.33333333;
60        double mid = full/2.0;
61        pos[0] = full- (pos[0] + mid);
62        pos[2] = full- (pos[2] + mid);
63
64        return(Vector3(pos));
65    }
66
67    //=========================================================
68
69    Vector3 VMapManager::convertPositionToTrinityRep(float x, float y, float z) const
70    {
71        float pos[3];
72        pos[0] = z;
73        pos[1] = x;
74        pos[2] = y;
75        double full = 64.0*533.33333333;
76        double mid = full/2.0;
77        pos[0] = -((mid+pos[0])-full);
78        pos[1] = -((mid+pos[1])-full);
79
80        return(Vector3(pos));
81    }
82    //=========================================================
83
84    std::string VMapManager::getDirFileName(unsigned int pMapId, int x, int y) const
85    {
86        char name[FILENAMEBUFFER_SIZE];
87
88        sprintf(name, "%03u_%d_%d%s",pMapId, x, y, DIR_FILENAME_EXTENSION);
89        return(std::string(name));
90    }
91
92    //=========================================================
93    std::string VMapManager::getDirFileName(unsigned int pMapId) const
94    {
95        char name[FILENAMEBUFFER_SIZE];
96
97        sprintf(name, "%03d%s",pMapId, DIR_FILENAME_EXTENSION);
98        return(std::string(name));
99    }
100    //=========================================================
101    // remote last return or LF
102    void chomp(std::string& str)
103    {
104        while(str.length() >0)
105        {
106            char lc = str[str.length()-1];
107            if(lc == '\r' || lc == '\n')
108            {
109                str = str.substr(0,str.length()-1);
110            }
111            else
112            {
113                break;
114            }
115        }
116    }
117    //=========================================================
118
119    void chompAndTrim(std::string& str)
120    {
121        while(str.length() >0)
122        {
123            char lc = str[str.length()-1];
124            if(lc == '\r' || lc == '\n' || lc == ' ' || lc == '"' || lc == '\'')
125            {
126                str = str.substr(0,str.length()-1);
127            }
128            else
129            {
130                break;
131            }
132        }
133        while(str.length() >0)
134        {
135            char lc = str[0];
136            if(lc == ' ' || lc == '"' || lc == '\'')
137            {
138                str = str.substr(1,str.length()-1);
139            }
140            else
141            {
142                break;
143            }
144        }
145    }
146
147    //=========================================================
148    // result false, if no more id are found
149
150    bool getNextMapId(const std::string& pString, unsigned int& pStartPos, unsigned int& pId)
151    {
152        bool result = false;
153        unsigned int i;
154        for(i=pStartPos;i<pString.size(); ++i)
155        {
156            if(pString[i] == ',')
157            {
158                break;
159            }
160        }
161        if(i>pStartPos)
162        {
163            std::string idString = pString.substr(pStartPos, i-pStartPos);
164            pStartPos = i+1;
165            chompAndTrim(idString);
166            pId = atoi(idString.c_str());
167            result = true;
168        }
169        return(result);
170    }
171
172    //=========================================================
173    /**
174    Block maps from being used.
175    parameter: String of map ids. Delimiter = ","
176    e.g.: "0,1,590"
177    */
178
179    void VMapManager::preventMapsFromBeingUsed(const char* pMapIdString)
180    {
181        if(pMapIdString != NULL)
182        {
183            unsigned int pos =0;
184            unsigned int id;
185            std::string confString(pMapIdString);
186            chompAndTrim(confString);
187            while(getNextMapId(confString, pos, id))
188            {
189                iIgnoreMapIds.set(id, true);
190            }
191        }
192    }
193
194    //=========================================================
195
196    int VMapManager::loadMap(const char* pBasePath, unsigned int pMapId, int x, int y)
197    {
198        int result = VMAP_LOAD_RESULT_IGNORED;
199        if(isMapLoadingEnabled() && !iIgnoreMapIds.containsKey(pMapId))
200        {
201            bool loaded = _loadMap(pBasePath, pMapId, x, y, false);
202            if(!loaded)
203            {
204                // if we can't load the map it might be splitted into tiles. Try that one and store the result
205                loaded = _loadMap(pBasePath, pMapId, x, y, true);
206                if(loaded)
207                {
208                    iMapsSplitIntoTiles.set(pMapId, true);
209                }
210            }
211            if(loaded)
212            {
213                result = VMAP_LOAD_RESULT_OK;
214                // just for debugging
215#ifdef _VMAP_LOG_DEBUG
216                Command c = Command();
217                c.fillLoadTileCmd(x, y, pMapId);
218                iCommandLogger.appendCmd(c);
219#endif
220            }
221            else
222            {
223                result = VMAP_LOAD_RESULT_ERROR;
224            }
225        }
226        return result;
227    }
228
229    //=========================================================
230    // load one tile (internal use only)
231
232    bool VMapManager::_loadMap(const char* pBasePath, unsigned int pMapId, int x, int y, bool pForceTileLoad)
233    {
234        bool result = false;
235        std::string dirFileName;
236        if(pForceTileLoad || iMapsSplitIntoTiles.containsKey(pMapId))
237        {
238            dirFileName = getDirFileName(pMapId,x,y);
239        }
240        else
241        {
242            dirFileName = getDirFileName(pMapId);
243        }
244        MapTree* instanceTree;
245        if(!iInstanceMapTrees.containsKey(pMapId))
246        {
247            instanceTree = new MapTree(pBasePath);
248            iInstanceMapTrees.set(pMapId, instanceTree);
249        }
250        else
251            instanceTree = iInstanceMapTrees.get(pMapId);
252
253        unsigned int mapTileIdent = MAP_TILE_IDENT(x,y);
254        result = instanceTree->loadMap(dirFileName, mapTileIdent);
255        if(!result)                                         // remove on fail
256        {
257            if(instanceTree->size() == 0)
258            {
259                iInstanceMapTrees.remove(pMapId);
260                delete instanceTree;
261            }
262        }
263        return(result);
264    }
265
266    //=========================================================
267
268    bool VMapManager::_existsMap(const std::string& pBasePath, unsigned int pMapId, int x, int y, bool pForceTileLoad)
269    {
270        bool result = false;
271        std::string dirFileName;
272        if(pForceTileLoad || iMapsSplitIntoTiles.containsKey(pMapId))
273        {
274            dirFileName = getDirFileName(pMapId,x,y);
275        }
276        else
277        {
278            dirFileName = getDirFileName(pMapId);
279        }
280        size_t len = pBasePath.length() + dirFileName.length();
281        char *filenameBuffer = new char[len+1];
282        sprintf(filenameBuffer, "%s%s", pBasePath.c_str(), dirFileName.c_str());
283        FILE* df = fopen(filenameBuffer, "rb");
284        if(df)
285        {
286            char lineBuffer[FILENAMEBUFFER_SIZE];
287            if (fgets(lineBuffer, FILENAMEBUFFER_SIZE-1, df) != 0)
288            {
289                std::string name = std::string(lineBuffer);
290                chomp(name);
291                if(name.length() >1)
292                {
293                    sprintf(filenameBuffer, "%s%s", pBasePath.c_str(), name.c_str());
294                    FILE* df2 = fopen(filenameBuffer, "rb");
295                    if(df2)
296                    {
297                        char magic[8];
298                        fread(magic,1,8,df2);
299                        if(!strncmp(VMAP_MAGIC,magic,8))
300                            result = true;
301                        fclose(df2);
302                    }
303                }
304            }
305            fclose(df);
306        }
307        delete[] filenameBuffer;
308        return result;
309    }
310
311    //=========================================================
312
313    bool VMapManager::existsMap(const char* pBasePath, unsigned int pMapId, int x, int y)
314    {
315        std::string basePath = std::string(pBasePath);
316        if(basePath.length() > 0 && (basePath[basePath.length()-1] != '/' || basePath[basePath.length()-1] != '\\'))
317        {
318            basePath.append("/");
319        }
320        bool found = _existsMap(basePath, pMapId, x, y, false);
321        if(!found)
322        {
323            // if we can't load the map it might be splitted into tiles. Try that one and store the result
324            found = _existsMap(basePath, pMapId, x, y, true);
325            if(found)
326            {
327                iMapsSplitIntoTiles.set(pMapId, true);
328            }
329        }
330        return found;
331    }
332
333    //=========================================================
334
335    void VMapManager::unloadMap(unsigned int pMapId, int x, int y)
336    {
337        _unloadMap(pMapId, x, y);
338
339#ifdef _VMAP_LOG_DEBUG
340        Command c = Command();
341        c.fillUnloadTileCmd(pMapId, x,y);
342        iCommandLogger.appendCmd(c);
343#endif
344    }
345
346    //=========================================================
347
348    void VMapManager::_unloadMap(unsigned int  pMapId, int x, int y)
349    {
350        if(iInstanceMapTrees.containsKey(pMapId))
351        {
352            MapTree* instanceTree = iInstanceMapTrees.get(pMapId);
353            std::string dirFileName;
354            if(iMapsSplitIntoTiles.containsKey(pMapId))
355            {
356                dirFileName = getDirFileName(pMapId,x,y);
357            }
358            else
359            {
360                dirFileName = getDirFileName(pMapId);
361            }
362            unsigned int mapTileIdent = MAP_TILE_IDENT(x,y);
363            instanceTree->unloadMap(dirFileName, mapTileIdent);
364            if(instanceTree->size() == 0)
365            {
366                iInstanceMapTrees.remove(pMapId);
367                delete instanceTree;
368            }
369        }
370    }
371
372    //=========================================================
373
374    void VMapManager::unloadMap(unsigned int pMapId)
375    {
376        if(iInstanceMapTrees.containsKey(pMapId))
377        {
378            MapTree* instanceTree = iInstanceMapTrees.get(pMapId);
379            std::string dirFileName = getDirFileName(pMapId);
380            instanceTree->unloadMap(dirFileName, 0, true);
381            if(instanceTree->size() == 0)
382            {
383                iInstanceMapTrees.remove(pMapId);
384                delete instanceTree;
385            }
386#ifdef _VMAP_LOG_DEBUG
387            Command c = Command();
388            c.fillUnloadTileCmd(pMapId);
389            iCommandLogger.appendCmd(c);
390#endif
391        }
392    }
393    //==========================================================
394
395    bool VMapManager::isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2)
396    {
397        bool result = true;
398        if(isLineOfSightCalcEnabled() && iInstanceMapTrees.containsKey(pMapId))
399        {
400            Vector3 pos1 = convertPositionToInternalRep(x1,y1,z1);
401            Vector3 pos2 = convertPositionToInternalRep(x2,y2,z2);
402            if(pos1 != pos2)
403            {
404                MapTree* mapTree = iInstanceMapTrees.get(pMapId);
405                result = mapTree->isInLineOfSight(pos1, pos2);
406#ifdef _VMAP_LOG_DEBUG
407                Command c = Command();
408                                                            // save the orig vectors
409                c.fillTestVisCmd(pMapId,Vector3(x1,y1,z1),Vector3(x2,y2,z2),result);
410                iCommandLogger.appendCmd(c);
411#endif
412            }
413        }
414        return(result);
415    }
416    //=========================================================
417    /**
418    get the hit position and return true if we hit something
419    otherwise the result pos will be the dest pos
420    */
421    bool VMapManager::getObjectHitPos(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float pModifyDist)
422    {
423        bool result = false;
424        rx=x2;
425        ry=y2;
426        rz=z2;
427        if(isLineOfSightCalcEnabled())
428        {
429            if(iInstanceMapTrees.containsKey(pMapId))
430            {
431                Vector3 pos1 = convertPositionToInternalRep(x1,y1,z1);
432                Vector3 pos2 = convertPositionToInternalRep(x2,y2,z2);
433                Vector3 resultPos;
434                MapTree* mapTree = iInstanceMapTrees.get(pMapId);
435                result = mapTree->getObjectHitPos(pos1, pos2, resultPos, pModifyDist);
436                resultPos = convertPositionToTrinityRep(resultPos.x,resultPos.y,resultPos.z);
437                rx = resultPos.x;
438                ry = resultPos.y;
439                rz = resultPos.z;
440#ifdef _VMAP_LOG_DEBUG
441                Command c = Command();
442                c.fillTestObjectHitCmd(pMapId, pos1, pos2, resultPos, result);
443                iCommandLogger.appendCmd(c);
444#endif
445            }
446        }
447        return result;
448    }
449
450    //=========================================================
451    /**
452    get height or INVALID_HEIGHT if to hight was calculated
453    */
454
455    //int gGetHeightCounter = 0;
456    float VMapManager::getHeight(unsigned int pMapId, float x, float y, float z)
457    {
458        float height = VMAP_INVALID_HEIGHT_VALUE;           //no height
459        if(isHeightCalcEnabled() && iInstanceMapTrees.containsKey(pMapId))
460        {
461            Vector3 pos = convertPositionToInternalRep(x,y,z);
462            MapTree* mapTree = iInstanceMapTrees.get(pMapId);
463            height = mapTree->getHeight(pos);
464            if(!(height < inf()))
465            {
466                height = VMAP_INVALID_HEIGHT_VALUE;         //no height
467            }
468#ifdef _VMAP_LOG_DEBUG
469            Command c = Command();
470            c.fillTestHeightCmd(pMapId,Vector3(x,y,z),height);
471            iCommandLogger.appendCmd(c);
472#endif
473        }
474        return(height);
475    }
476
477    //=========================================================
478    /**
479    used for debugging
480    */
481    bool VMapManager::processCommand(char *pCommand)
482    {
483        bool result = false;
484        std::string cmd = std::string(pCommand);
485        if(cmd == "startlog")
486        {
487#ifdef _VMAP_LOG_DEBUG
488
489            iCommandLogger.enableWriting(true);
490#endif
491            result = true;
492        }
493        else if(cmd == "stoplog")
494        {
495#ifdef _VMAP_LOG_DEBUG
496            iCommandLogger.appendCmd(Command());            // Write stop command
497            iCommandLogger.enableWriting(false);
498#endif
499            result = true;
500        }
501        else if(cmd.find_first_of("pos ") == 0)
502        {
503            float x,y,z;
504            sscanf(pCommand, "pos %f,%f,%f",&x,&y,&z);
505#ifdef _VMAP_LOG_DEBUG
506            Command c = Command();
507            c.fillSetPosCmd(convertPositionToInternalRep(x,y,z));
508            iCommandLogger.appendCmd(c);
509            iCommandLogger.enableWriting(false);
510#endif
511            result = true;
512        }
513        return result;
514    }
515
516    //=========================================================
517    //=========================================================
518    //=========================================================
519
520    MapTree::MapTree(const char* pBaseDir)
521    {
522        iBasePath = std::string(pBaseDir);
523        if(iBasePath.length() > 0 && (iBasePath[iBasePath.length()-1] != '/' || iBasePath[iBasePath.length()-1] != '\\'))
524        {
525            iBasePath.append("/");
526        }
527        iTree = new AABSPTree<ModelContainer *>();
528    }
529
530    //=========================================================
531    MapTree::~MapTree()
532    {
533        Array<ModelContainer *> mcArray;
534        iTree->getMembers(mcArray);
535        int no = mcArray.size();
536        while(no >0)
537        {
538            --no;
539            delete mcArray[no];
540        }
541        delete iTree;
542    }
543    //=========================================================
544
545    // just for visual debugging with an external debug class
546    #ifdef _DEBUG_VMAPS
547    #ifndef gBoxArray
548    extern Vector3 p1,p2,p3,p4,p5,p6,p7;
549    extern Array<AABox>gBoxArray;
550    extern int gCount1, gCount2, gCount3, gCount4;
551    extern bool myfound;
552    #endif
553    #endif
554
555    //=========================================================
556    /**
557    return dist to hit or inf() if no hit
558    */
559
560    float MapTree::getIntersectionTime(const Ray& pRay, float pMaxDist, bool pStopAtFirstHit)
561    {
562        float firstDistance = inf();
563        IntersectionCallBack<ModelContainer> intersectionCallBack;
564        float t = pMaxDist;
565        iTree->intersectRay(pRay, intersectionCallBack, t, pStopAtFirstHit, false);
566#ifdef _DEBUG_VMAPS
567        {
568            if(t < pMaxDist)
569            {
570                myfound = true;
571                p4 = pRay.origin + pRay.direction*t;
572            }
573        }
574#endif
575        if(t > 0 && t < inf() && pMaxDist > t)
576        {
577            firstDistance = t;
578        }
579        return firstDistance;
580    }
581    //=========================================================
582
583    bool MapTree::isInLineOfSight(const Vector3& pos1, const Vector3& pos2)
584    {
585        bool result = true;
586        float maxDist = abs((pos2 - pos1).magnitude());
587                                                            // direction with length of 1
588        Ray ray = Ray::fromOriginAndDirection(pos1, (pos2 - pos1)/maxDist);
589        float resultDist = getIntersectionTime(ray, maxDist, true);
590        if(resultDist < maxDist)
591        {
592            result = false;
593        }
594        return result;
595    }
596    //=========================================================
597    /**
598    When moving from pos1 to pos2 check if we hit an object. Return true and the position if we hit one
599    Return the hit pos or the original dest pos
600    */
601
602    bool MapTree::getObjectHitPos(const Vector3& pPos1, const Vector3& pPos2, Vector3& pResultHitPos, float pModifyDist)
603    {
604        bool result;
605        float maxDist = abs((pPos2 - pPos1).magnitude());
606        Vector3 dir = (pPos2 - pPos1)/maxDist;              // direction with length of 1
607        Ray ray = Ray::fromOriginAndDirection(pPos1, dir);
608        float dist = getIntersectionTime(ray, maxDist, false);
609        if(dist < maxDist)
610        {
611            pResultHitPos = pPos1 + dir * dist;
612            if(pModifyDist < 0)
613            {
614                if(abs((pResultHitPos - pPos1).magnitude()) > -pModifyDist)
615                {
616                    pResultHitPos = pResultHitPos + dir*pModifyDist;
617                }
618                else
619                {
620                    pResultHitPos = pPos1;
621                }
622            }
623            else
624            {
625                pResultHitPos = pResultHitPos + dir*pModifyDist;
626            }
627            result = true;
628        }
629        else
630        {
631            pResultHitPos = pPos2;
632            result = false;
633        }
634        return result;
635    }
636
637    //=========================================================
638
639    float MapTree::getHeight(const Vector3& pPos)
640    {
641        float height = inf();
642        Vector3 dir = Vector3(0,-1,0);
643        Ray ray = Ray::fromOriginAndDirection(pPos, dir);   // direction with length of 1
644        float maxDist = VMapDefinitions::getMaxCanFallDistance();
645        float dist = getIntersectionTime(ray, maxDist, false);
646        if(dist < inf())
647        {
648            height = (pPos + dir * dist).y;
649        }
650        return(height);
651    }
652
653    //=========================================================
654
655    bool MapTree::PrepareTree()
656    {
657        iTree->balance();
658        return true;
659    }
660
661    bool MapTree::loadMap(const std::string& pDirFileName, unsigned int pMapTileIdent)
662    {
663        bool result = true;
664        size_t len = iBasePath.length() + pDirFileName.length();
665        char *filenameBuffer = new char[len+1];
666        if(!hasDirFile(pDirFileName))
667        {
668            FilesInDir filesInDir;
669            result = false;
670            sprintf(filenameBuffer, "%s%s", iBasePath.c_str(), pDirFileName.c_str());
671            FILE* df = fopen(filenameBuffer, "rb");
672            if(df)
673            {
674                char lineBuffer[FILENAMEBUFFER_SIZE];
675                result = true;
676                bool newModelLoaded = false;
677                while(result && (fgets(lineBuffer, FILENAMEBUFFER_SIZE-1, df) != 0))
678                {
679                    std::string name = std::string(lineBuffer);
680                    chomp(name);
681                    if(name.length() >1)
682                    {
683                        filesInDir.append(name);
684                        ManagedModelContainer *mc;
685                        if(!isAlreadyLoaded(name))
686                        {
687                            std::string fname = iBasePath;
688                            fname.append(name);
689                            mc = new ManagedModelContainer();
690                            result = mc->readFile(fname.c_str());
691                            if(result)
692                            {
693                                addModelContainer(name, mc);
694                                newModelLoaded = true;
695                            }
696                        }
697                        else
698                        {
699                            mc = getModelContainer(name);
700                        }
701                        mc->incRefCount();
702                    }
703                }
704                if(result && newModelLoaded)
705                {
706                    iTree->balance();
707                }
708                if(result && ferror(df) != 0)
709                {
710                    result = false;
711                }
712                fclose(df);
713                if(result)
714                {
715                    filesInDir.incRefCount();
716                    addDirFile(pDirFileName, filesInDir);
717                    setLoadedMapTile(pMapTileIdent);
718                }
719            }
720        }
721        else
722        {
723            // Already loaded, so just inc. the ref count if mapTileIdent is new
724            if(!containsLoadedMapTile(pMapTileIdent))
725            {
726                setLoadedMapTile(pMapTileIdent);
727                FilesInDir& filesInDir = getDirFiles(pDirFileName);
728                filesInDir.incRefCount();
729            }
730        }
731        delete [] filenameBuffer;
732        return (result);
733    }
734
735    //=========================================================
736
737    void MapTree::unloadMap(const std::string& dirFileName, unsigned int pMapTileIdent, bool pForce)
738    {
739        if(hasDirFile(dirFileName) && (pForce || containsLoadedMapTile(pMapTileIdent)))
740        {
741            if(containsLoadedMapTile(pMapTileIdent))
742                removeLoadedMapTile(pMapTileIdent);
743            FilesInDir& filesInDir = getDirFiles(dirFileName);
744            filesInDir.decRefCount();
745            if(filesInDir.getRefCount() <= 0)
746            {
747                Array<std::string> fileNames = filesInDir.getFiles();
748                bool treeChanged = false;
749                for(int i=0; i<fileNames.size(); ++i)
750                {
751                    std::string name = fileNames[i];
752                    ManagedModelContainer* mc = getModelContainer(name);
753                    mc->decRefCount();
754                    if(mc->getRefCount() <= 0)
755                    {
756                        iLoadedModelContainer.remove(name);
757                        iTree->remove(mc);
758                        delete mc;
759                        treeChanged = true;
760                    }
761                }
762                iLoadedDirFiles.remove(dirFileName);
763                if(treeChanged)
764                {
765                    iTree->balance();
766                }
767            }
768        }
769    }
770
771    //=========================================================
772    //=========================================================
773
774    void MapTree::addModelContainer(const std::string& pName, ManagedModelContainer *pMc)
775    {
776        iLoadedModelContainer.set(pName, pMc);
777        iTree->insert(pMc);
778    }
779    //=========================================================
780    //=========================================================
781    //=========================================================
782}
Note: See TracBrowser for help on using the browser.