BVB Source Codes

CRYENGINE Show ObjectsTree_Serialize.cpp Source code

Return Download CRYENGINE: download ObjectsTree_Serialize.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include "PolygonClipContext.h"
  5. #include "Brush.h"
  6. #include "RoadRenderNode.h"
  7. #include "DecalRenderNode.h"
  8. #include "WaterVolumeRenderNode.h"
  9. #include "DistanceCloudRenderNode.h"
  10. #include "WaterWaveRenderNode.h"
  11. #include "MergedMeshRenderNode.h"
  12. #include "MergedMeshGeometry.h"
  13. #include "VisAreas.h"
  14. #include "Brush.h"
  15.  
  16. #pragma warning(disable: 4244)
  17.  
  18. #pragma pack(push,4)
  19.  
  20. // common node data
  21. struct SRenderNodeChunk
  22. {
  23.         SRenderNodeChunk() { m_nObjectTypeIndex = 0; m_nLayerId = 0; m_ucDummy = 0; }
  24.         AABB   m_WSBBox;
  25.         uint16 m_nLayerId;
  26.         int8   m_cShadowLodBias;
  27.         uint8  m_ucDummy;
  28.         uint32 m_dwRndFlags;
  29.         uint16 m_nObjectTypeIndex;
  30.         uint8  m_ucViewDistRatio;
  31.         uint8  m_ucLodRatio;
  32.  
  33.         AUTO_STRUCT_INFO_LOCAL;
  34. };
  35.  
  36. struct SVegetationChunkOld : public SRenderNodeChunk
  37. {
  38.         Vec3  m_vPos;
  39.         float m_fScale;
  40.         uint8 m_ucBright;
  41.         uint8 m_ucAngle;
  42.  
  43.         AUTO_STRUCT_INFO_LOCAL;
  44. };
  45.  
  46. struct SVegetationChunk : public SRenderNodeChunk
  47. {
  48.         Vec3  m_vPos;
  49.         float m_fScale;
  50.         uint8 m_ucBright;
  51.         uint8 m_ucAngle;
  52.         uint8 m_ucAngleX;
  53.         uint8 m_ucAngleY;
  54.  
  55.         AUTO_STRUCT_INFO_LOCAL;
  56. };
  57.  
  58. struct SMergedMeshChunk : public SRenderNodeChunk
  59. {
  60.         uint32 m_nGroups;
  61.         AABB   m_Extents;
  62.         AUTO_STRUCT_INFO_LOCAL;
  63. };
  64.  
  65. struct SMergedMeshGroupChunk
  66. {
  67.         uint32 m_StatInstGroupID;
  68.         uint32 m_nSamples;
  69.         AUTO_STRUCT_INFO_LOCAL;
  70. };
  71.  
  72. struct SBrushChunk : public SRenderNodeChunk
  73. {
  74.         SBrushChunk() { m_flags = 0; }
  75.         Matrix34 m_Matrix;
  76.         int16    m_collisionClassIdx;
  77.         uint16   m_flags;
  78.         int32    m_nMaterialId;
  79.         int32    m_nMaterialLayers;
  80.  
  81.         AUTO_STRUCT_INFO_LOCAL;
  82. };
  83.  
  84. #define ROADCHUNKFLAG_IGNORE_TERRAIN_HOLES 1
  85. #define ROADCHUNKFLAG_PHYSICALIZE          2
  86.  
  87. struct SRoadChunk : public SRenderNodeChunk
  88. {
  89.         CRoadRenderNode::SData m_roadData;
  90.  
  91.         int16 m_nSortPriority;
  92.         int16 m_nFlags;
  93.         int32 m_nMaterialId;
  94.  
  95.         AUTO_STRUCT_INFO_LOCAL;
  96. };
  97.  
  98. struct SDecalChunk : public SRenderNodeChunk
  99. {
  100.         int16    m_projectionType;
  101.         uint8    m_deferred;
  102.         uint8    m_depth;
  103.         Vec3     m_pos;
  104.         Vec3     m_normal;
  105.         Matrix33 m_explicitRightUpFront;
  106.         f32      m_radius;
  107.         int32    m_nMaterialId;
  108.         int32    m_nSortPriority;
  109.  
  110.         AUTO_STRUCT_INFO_LOCAL;
  111. };
  112.  
  113. struct SWaterVolumeChunk : public SRenderNodeChunk
  114. {
  115.         // volume type and id
  116.         int32  m_volumeTypeAndMiscBits;
  117.         uint64 m_volumeID;
  118.  
  119.         // material
  120.         int32 m_materialID;
  121.  
  122.         // fog properties
  123.         f32   m_fogDensity;
  124.         Vec3  m_fogColor;
  125.         Plane m_fogPlane;
  126.         f32   m_fogShadowing;
  127.  
  128.         // caustic propeties
  129.         uint8 m_caustics;
  130.         f32   m_causticIntensity;
  131.         f32   m_causticTiling;
  132.         f32   m_causticHeight;
  133.  
  134.         // render geometry
  135.         f32    m_uTexCoordBegin;
  136.         f32    m_uTexCoordEnd;
  137.         f32    m_surfUScale;
  138.         f32    m_surfVScale;
  139.         uint32 m_numVertices;
  140.  
  141.         // physics properties
  142.         f32    m_volumeDepth;
  143.         f32    m_streamSpeed;
  144.         uint32 m_numVerticesPhysAreaContour;
  145.  
  146.         AUTO_STRUCT_INFO_LOCAL;
  147. };
  148.  
  149. struct SWaterVolumeVertex
  150. {
  151.         Vec3 m_xyz;
  152.  
  153.         AUTO_STRUCT_INFO_LOCAL;
  154. };
  155.  
  156. struct SDistanceCloudChunk : public SRenderNodeChunk
  157. {
  158.         Vec3  m_pos;
  159.         f32   m_sizeX;
  160.         f32   m_sizeY;
  161.         f32   m_rotationZ;
  162.         int32 m_materialID;
  163.  
  164.         AUTO_STRUCT_INFO_LOCAL;
  165. };
  166.  
  167. struct SWaterWaveChunk : public SRenderNodeChunk
  168. {
  169.         int32 m_nID;
  170.  
  171.         // Geometry properties
  172.         Matrix34 m_pWorldTM;
  173.         uint32   m_nVertexCount;
  174.  
  175.         f32      m_fUScale;
  176.         f32      m_fVScale;
  177.  
  178.         // Material
  179.         int32 m_nMaterialID;
  180.  
  181.         // Animation properties
  182.  
  183.         f32 m_fSpeed;
  184.         f32 m_fSpeedVar;
  185.  
  186.         f32 m_fLifetime;
  187.         f32 m_fLifetimeVar;
  188.  
  189.         f32 m_fPosVar;
  190.  
  191.         f32 m_fHeight;
  192.         f32 m_fHeightVar;
  193.  
  194.         f32 m_fCurrLifetime;
  195.         f32 m_fCurrFrameLifetime;
  196.         f32 m_fCurrSpeed;
  197.         f32 m_fCurrHeight;
  198.  
  199.         AUTO_STRUCT_INFO_LOCAL;
  200. };
  201.  
  202. #pragma pack(pop)
  203.  
  204. AUTO_TYPE_INFO(EERType);
  205.  
  206. #include <CryCore/TypeInfo_impl.h>
  207. #include "ObjectsTree_Serialize_info.h"
  208.  
  209. inline void CopyCommonData(SRenderNodeChunk* pChunk, IRenderNode* pObj, const Vec3& segmentOffset)
  210. {
  211.         pChunk->m_WSBBox = pObj->GetBBox();
  212.         pChunk->m_WSBBox.Move(segmentOffset);
  213.         //COPY_MEMBER_SAVE(pChunk,pObj,m_fWSMaxViewDist);
  214.         COPY_MEMBER_SAVE(pChunk, pObj, m_dwRndFlags);
  215.         COPY_MEMBER_SAVE(pChunk, pObj, m_ucViewDistRatio);
  216.         COPY_MEMBER_SAVE(pChunk, pObj, m_ucLodRatio);
  217.         COPY_MEMBER_SAVE(pChunk, pObj, m_cShadowLodBias);
  218.         pChunk->m_nLayerId = pObj->GetLayerId();
  219. }
  220.  
  221. inline void LoadCommonData(SRenderNodeChunk* pChunk, IRenderNode* pObj, const SLayerVisibility* pLayerVisibility)
  222. {
  223.         //COPY_MEMBER_LOAD(pObj,pChunk,m_fWSMaxViewDist);
  224.         COPY_MEMBER_LOAD(pObj, pChunk, m_dwRndFlags);
  225.         COPY_MEMBER_LOAD(pObj, pChunk, m_ucViewDistRatio);
  226.         COPY_MEMBER_LOAD(pObj, pChunk, m_ucLodRatio);
  227.         COPY_MEMBER_LOAD(pObj, pChunk, m_cShadowLodBias);
  228.         pObj->m_dwRndFlags &= ~(ERF_HIDDEN | ERF_SELECTED);
  229.         if (pObj->m_dwRndFlags & ERF_CASTSHADOWMAPS)
  230.                 pObj->m_dwRndFlags |= ERF_HAS_CASTSHADOWMAPS;
  231.  
  232.         if (NULL != pLayerVisibility)
  233.         {
  234.                 const uint16 newLayerId = pLayerVisibility->pLayerIdTranslation[pChunk->m_nLayerId];
  235.                 pObj->SetLayerId(newLayerId);
  236.         }
  237.         else
  238.         {
  239.                 pObj->SetLayerId(pChunk->m_nLayerId);
  240.         }
  241. }
  242.  
  243. //////////////////////////////////////////////////////////////////////////
  244. inline static uint8 CheckLayerVisibility(const uint16 layerId, const SLayerVisibility* pLayerVisibility)
  245. {
  246.         return pLayerVisibility->pLayerVisibilityMask[layerId >> 3] & (1 << (layerId & 7));
  247. }
  248.  
  249. int32 COctreeNode::SaveObjects_CompareRenderNodes(const void* v1, const void* v2)
  250. {
  251.         IRenderNode* p[2] = { *(IRenderNode**)v1, *(IRenderNode**)v2 };
  252.  
  253.         EERType t0 = p[0]->GetRenderNodeType();
  254.         int f0 = p[0]->m_dwRndFlags;
  255.  
  256.         EERType t1 = p[1]->GetRenderNodeType();
  257.         int f1 = p[1]->m_dwRndFlags;
  258.  
  259.         if (IsObjectStreamable(t0, f0) > IsObjectStreamable(t1, f1))
  260.                 return 1;
  261.         if (IsObjectStreamable(t0, f0) < IsObjectStreamable(t1, f1))
  262.                 return -1;
  263.  
  264.         if (t0 > t1)
  265.                 return 1;
  266.         if (t0 < t1)
  267.                 return -1;
  268.  
  269.         return 0;
  270. }
  271.  
  272. //////////////////////////////////////////////////////////////////////////
  273. int COctreeNode::SaveObjects(CMemoryBlock* pMemBlock, std::vector<IStatObj*>* pStatObjTable, std::vector<IMaterial*>* pMatTable, std::vector<IStatInstGroup*>* pStatInstGroupTable, EEndian eEndian, const SHotUpdateInfo* pExportInfo, const Vec3& segmentOffset)
  274. {
  275. #if !ENGINE_ENABLE_COMPILATION
  276.         CryFatalError("serialization code removed, please enable ENGINE_ENABLE_COMPILATION in Cry3DEngine/StdAfx.h");
  277.         return 0;
  278. #else
  279.         uint32 nObjTypeMask = pExportInfo ? pExportInfo->nObjTypeMask : (uint32) ~0;
  280.  
  281.         int nBlockSize = 0;
  282.  
  283.         //  FreeAreaBrushes();
  284.  
  285.         for (int l = 0; l < eRNListType_ListsNum; l++)
  286.                 for (IRenderNode* pObj = m_arrObjects[l].m_pFirstNode; pObj; pObj = pObj->m_pNext)
  287.                 {
  288.                         IRenderNode* pRenderNode = pObj;
  289.                         EERType eType = pRenderNode->GetRenderNodeType();
  290.  
  291.                         if (!(nObjTypeMask & (1 << eType)))
  292.                                 continue;
  293.  
  294.                         // Do not serialize nodes owned by the Entity
  295.                         if (pRenderNode->GetOwnerEntity())
  296.                                 continue;
  297.  
  298.                         nBlockSize += GetSingleObjectFileDataSize(pObj, pExportInfo);
  299.                 }
  300.  
  301.         if (!pMemBlock || !nBlockSize)
  302.                 return nBlockSize;
  303.  
  304.         pMemBlock->Allocate(nBlockSize);
  305.         byte* pPtr = (byte*)pMemBlock->GetData();
  306.  
  307.         int nDatanSize = nBlockSize;
  308.  
  309.         PodArray<IRenderNode*> arrSortedObjects;
  310.  
  311.         for (int l = 0; l < eRNListType_ListsNum; l++)
  312.         {
  313.                 for (IRenderNode* pRenderNode = m_arrObjects[l].m_pFirstNode; pRenderNode; pRenderNode = pRenderNode->m_pNext)
  314.                 {
  315.                         EERType eType = pRenderNode->GetRenderNodeType();
  316.  
  317.                         if (!(nObjTypeMask & (1 << eType)))
  318.                                 continue;
  319.  
  320.                         // Do not serialize nodes owned by the Entity
  321.                         if (pRenderNode->GetOwnerEntity())
  322.                                 continue;
  323.  
  324.                         arrSortedObjects.Add(pRenderNode);
  325.                 }
  326.         }
  327.  
  328.         // Sort for streaming: sort first by stream/no_stream and then by type
  329.         if (arrSortedObjects.Count() > 1)
  330.                 qsort(arrSortedObjects.GetElements(), arrSortedObjects.Count(), sizeof(arrSortedObjects[0]), SaveObjects_CompareRenderNodes);
  331.  
  332.         for (int i = 0; i < arrSortedObjects.Count(); i++)
  333.         {
  334.                 SaveSingleObject(pPtr, nDatanSize, arrSortedObjects[i], pStatObjTable, pMatTable, pStatInstGroupTable, eEndian, pExportInfo, segmentOffset);
  335.         }
  336.  
  337.         assert(pPtr == (byte*)pMemBlock->GetData() + nBlockSize);
  338.         assert(nDatanSize == 0);
  339.  
  340.         return nBlockSize;
  341. #endif
  342. }
  343.  
  344. //////////////////////////////////////////////////////////////////////////
  345. int COctreeNode::LoadObjects(byte* pPtr, byte* pEndPtr, std::vector<IStatObj*>* pStatObjTable, std::vector<IMaterial*>* pMatTable, EEndian eEndian, int nChunkVersion, const SLayerVisibility* pLayerVisibility, const Vec3& segmentOffset, ELoadObjectsMode eLoadMode)
  346. {
  347.         while (pPtr < pEndPtr)
  348.         {
  349.                 IRenderNode* pRN = 0;
  350.                 LoadSingleObject(pPtr, pStatObjTable, pMatTable, eEndian, nChunkVersion, pLayerVisibility, m_nSID, segmentOffset, eLoadMode, pRN);
  351.  
  352.                 if (eLoadMode == LOM_LOAD_ONLY_STREAMABLE && pRN && IsObjectStreamable(pRN->GetRenderNodeType(), pRN->m_dwRndFlags))
  353.                 {
  354.                         // Make sure instance is registered in the same octree node it was loaded from
  355.                         // TODO: this needs to be investigated, currently the way octree is exported may change depending on current spec settings in the editor and this may move instances into different octree nodes
  356.                         if (pRN && pRN->m_pOcNode != this)
  357.                         {
  358.                                 Get3DEngine()->UnRegisterEntityDirect(pRN);
  359.                                 LinkObject(pRN, pRN->GetRenderNodeType());
  360.                                 pRN->m_pOcNode = this;
  361.                                 pRN->m_nSID = m_nSID;
  362.                                 SetCompiled(false);
  363.                         }
  364.  
  365.                         m_nInstCounterLoaded++;
  366.                 }
  367.         }
  368.  
  369.         return 0;
  370. }
  371.  
  372. int COctreeNode::GetSingleObjectFileDataSize(IRenderNode* pObj, const SHotUpdateInfo* pExportInfo)
  373. {
  374.         IRenderNode* pRenderNode = pObj;
  375.         EERType eType = pRenderNode->GetRenderNodeType();
  376.  
  377.         int nBlockSize = 0;
  378.  
  379.         if (eType == eERType_Vegetation && !(pRenderNode->GetRndFlags() & ERF_PROCEDURAL))
  380.         {
  381.                 nBlockSize += sizeof(eType);
  382.                 nBlockSize += sizeof(SVegetationChunk);
  383.         }
  384.         else if (eType == eERType_MergedMesh)
  385.         {
  386.                 // merged meshes are not sent by LiveCreate (yet)
  387.                 if (NULL == pExportInfo)
  388.                 {
  389.                         nBlockSize += sizeof(eType);
  390.                         nBlockSize += sizeof(SMergedMeshChunk);
  391.                         nBlockSize += ((CMergedMeshRenderNode*)pRenderNode)->NumGroups() * sizeof(SMergedMeshGroupChunk);
  392.                 }
  393.         }
  394.         else if (eType == eERType_Brush && !(pRenderNode->GetRndFlags() & ERF_PROCEDURAL))
  395.         {
  396.                 nBlockSize += sizeof(eType);
  397.                 nBlockSize += sizeof(SBrushChunk);
  398.         }
  399.         else if (eType == eERType_Decal && !(pRenderNode->GetRndFlags() & ERF_PROCEDURAL))
  400.         {
  401.                 nBlockSize += sizeof(eType);
  402.                 nBlockSize += sizeof(SDecalChunk);
  403.         }
  404.         else if (eType == eERType_WaterVolume)
  405.         {
  406.                 CWaterVolumeRenderNode* pWVRN(static_cast<CWaterVolumeRenderNode*>(pRenderNode));
  407.                 const SWaterVolumeSerialize* pSerParams(pWVRN->GetSerializationParams());
  408.                 if (pSerParams)
  409.                 {
  410.                         nBlockSize += sizeof(eType);
  411.                         nBlockSize += sizeof(SWaterVolumeChunk);
  412.                         nBlockSize += (pSerParams->m_vertices.size() + pSerParams->m_physicsAreaContour.size()) * sizeof(SWaterVolumeVertex);
  413.                         int cntAux;
  414.                         pWVRN->GetAuxSerializationDataPtr(cntAux);
  415.                         nBlockSize += cntAux * sizeof(float);
  416.                 }
  417.         }
  418.         else if (eType == eERType_Road)
  419.         {
  420.                 nBlockSize += sizeof(eType);
  421.                 nBlockSize += sizeof(SRoadChunk);
  422.  
  423.                 nBlockSize += ((CRoadRenderNode*)pRenderNode)->m_dynamicData.vertices.GetDataSize();
  424.                 nBlockSize += ((CRoadRenderNode*)pRenderNode)->m_dynamicData.tangents.GetDataSize();
  425.  
  426.                 // vtx_idx is not used since we are exporting from PC and possibly loading on platform with <32 bit vertex indices
  427.                 nBlockSize += ((CRoadRenderNode*)pRenderNode)->m_dynamicData.indices.size() * sizeof(uint32);
  428.  
  429.                 // Should be zero if m_bPhysicalize is false
  430.                 nBlockSize += ((CRoadRenderNode*)pRenderNode)->m_dynamicData.physicsGeometry.GetDataSize();
  431.  
  432.                 // Include source vertex info
  433.                 nBlockSize += ((CRoadRenderNode*)pRenderNode)->m_arrVerts.GetDataSize();
  434.         }
  435.         else if (eType == eERType_DistanceCloud)
  436.         {
  437.                 nBlockSize += sizeof(eType);
  438.                 nBlockSize += sizeof(SDistanceCloudChunk);
  439.         }
  440.         else if (eType == eERType_WaterWave)
  441.         {
  442.                 CWaterWaveRenderNode* pWaveRenderNode(static_cast<CWaterWaveRenderNode*>(pRenderNode));
  443.                 const SWaterWaveSerialize* pSerParams(pWaveRenderNode->GetSerializationParams());
  444.  
  445.                 nBlockSize += sizeof(eType);
  446.                 nBlockSize += sizeof(SWaterWaveChunk);
  447.  
  448.                 nBlockSize += (pSerParams->m_pVertices.size()) * sizeof(Vec3);
  449.         }
  450.         // align to 4
  451.         while (UINT_PTR(nBlockSize) & 3)
  452.                 nBlockSize++;
  453.  
  454.         return nBlockSize;
  455. }
  456.  
  457. void COctreeNode::SaveSingleObject(byte*& pPtr, int& nDatanSize, IRenderNode* pEnt, std::vector<IStatObj*>* pStatObjTable, std::vector<IMaterial*>* pMatTable, std::vector<IStatInstGroup*>* pStatInstGroupTable, EEndian eEndian, const SHotUpdateInfo* pExportInfo, const Vec3& segmentOffset)
  458. {
  459.         EERType eType = pEnt->GetRenderNodeType();
  460.  
  461.         if (eType == eERType_Brush && !(pEnt->GetRndFlags() & ERF_PROCEDURAL))
  462.         {
  463.                 AddToPtr(pPtr, nDatanSize, eType, eEndian);
  464.  
  465.                 CBrush* pObj = (CBrush*)pEnt;
  466.  
  467.                 SBrushChunk chunk;
  468.  
  469.                 CopyCommonData(&chunk, pObj, segmentOffset);
  470.  
  471.                 COPY_MEMBER_SAVE(&chunk, pObj, m_nMaterialLayers);
  472.  
  473.                 // brush data
  474.                 COPY_MEMBER_SAVE(&chunk, pObj, m_Matrix);
  475.                 chunk.m_Matrix.SetTranslation(chunk.m_Matrix.GetTranslation() + segmentOffset);
  476.  
  477.                 chunk.m_nMaterialId = CObjManager::GetItemId(pMatTable, pObj->GetMaterial());
  478.  
  479.                 COPY_MEMBER_SAVE(&chunk, pObj, m_collisionClassIdx);
  480.  
  481.                 {
  482.                         // find StatObj Id
  483.                         int nItemId = CObjManager::GetItemId<IStatObj>(pStatObjTable, pObj->GetEntityStatObj());
  484.                         if (nItemId < 0)
  485.                                 assert(!"StatObj not found in BrushTable on exporting");
  486.                         chunk.m_nObjectTypeIndex = nItemId;
  487.                 }
  488.  
  489.                 chunk.m_flags |= pObj->GetDrawLast() ? 1 : 0;
  490.  
  491.                 AddToPtr(pPtr, nDatanSize, chunk, eEndian);
  492.         }
  493.         else if (eType == eERType_Vegetation && !(pEnt->GetRndFlags() & ERF_PROCEDURAL))
  494.         {
  495.                 AddToPtr(pPtr, nDatanSize, eType, eEndian);
  496.  
  497.                 CVegetation* pObj = (CVegetation*)pEnt;
  498.  
  499.                 SVegetationChunk chunk;
  500.  
  501.                 CopyCommonData(&chunk, pObj, segmentOffset);
  502.  
  503.                 // vegetation data
  504.                 COPY_MEMBER_SAVE(&chunk, pObj, m_vPos);
  505.                 chunk.m_vPos += segmentOffset;
  506.                 chunk.m_fScale = pObj->GetScale();
  507.                 COPY_MEMBER_SAVE(&chunk, pObj, m_nObjectTypeIndex);
  508.                 COPY_MEMBER_SAVE(&chunk, pObj, m_ucAngle);
  509.                 COPY_MEMBER_SAVE(&chunk, pObj, m_ucAngleX);
  510.                 COPY_MEMBER_SAVE(&chunk, pObj, m_ucAngleY);
  511.  
  512.                 {
  513.                         // find StatInstGroup Id
  514.                         StatInstGroup& group = pObj->GetStatObjGroup();
  515.                         int nItemId = CObjManager::GetItemId<IStatInstGroup>(pStatInstGroupTable, &group);
  516.                         if (nItemId < 0)
  517.                                 assert(!"StatObj not found in StatInstGroupTable on exporting");
  518.                         chunk.m_nObjectTypeIndex = nItemId;
  519.                 }
  520.  
  521.                 AddToPtr(pPtr, nDatanSize, chunk, eEndian);
  522.         }
  523.         else if (eType == eERType_MergedMesh)
  524.         {
  525.                 // don't send MergedMeshes data when using LiveCreate (yet)
  526.                 if (NULL == pExportInfo)
  527.                 {
  528.                         SMergedMeshChunk chunk;
  529.                         CMergedMeshRenderNode* pObj = (CMergedMeshRenderNode*)pEnt;
  530.  
  531.                         AddToPtr(pPtr, nDatanSize, eType, eEndian);
  532.                         CopyCommonData(&chunk, pObj, segmentOffset);
  533.                         chunk.m_nGroups = pObj->NumGroups();
  534.                         chunk.m_Extents = pObj->GetExtents();
  535.                         chunk.m_Extents.Move(segmentOffset);
  536.                         AddToPtr(pPtr, nDatanSize, chunk, eEndian);
  537.  
  538.                         for (size_t i = 0; i < pObj->NumGroups(); ++i)
  539.                         {
  540.                                 SMergedMeshGroupChunk groupChunk;
  541.                                 int grpid = pObj->Group(i)->instGroupId;
  542.                                 StatInstGroup& group = pObj->GetStatObjGroup(grpid);
  543.                                 int nItemId = CObjManager::GetItemId<IStatInstGroup>(pStatInstGroupTable, &group);
  544.                                 if (nItemId < 0)
  545.                                         assert(!"StatObj not found in StatInstGroupTable on exporting");
  546.                                 groupChunk.m_StatInstGroupID = nItemId;
  547.                                 groupChunk.m_nSamples = pObj->Group(i)->numSamples;
  548.                                 AddToPtr(pPtr, nDatanSize, groupChunk, eEndian);
  549.                         }
  550.                 }
  551.         }
  552.         else if (eType == eERType_Road)
  553.         {
  554.                 AddToPtr(pPtr, nDatanSize, eType, eEndian);
  555.  
  556.                 CRoadRenderNode* pObj = (CRoadRenderNode*)pEnt;
  557.  
  558.                 SRoadChunk chunk;
  559.  
  560.                 CopyCommonData(&chunk, pObj, segmentOffset);
  561.  
  562.                 // road data
  563.                 chunk.m_nMaterialId = CObjManager::GetItemId(pMatTable, pObj->GetMaterial());
  564.                 chunk.m_nSortPriority = pObj->m_sortPrio;
  565.                 chunk.m_nFlags = pObj->m_bIgnoreTerrainHoles ? ROADCHUNKFLAG_IGNORE_TERRAIN_HOLES : 0;
  566.                 chunk.m_nFlags |= pObj->m_bPhysicalize ? ROADCHUNKFLAG_PHYSICALIZE : 0;
  567.  
  568.                 chunk.m_roadData = pObj->m_serializedData;
  569.  
  570.                 chunk.m_roadData.numVertices = pObj->m_dynamicData.vertices.size();
  571.                 chunk.m_roadData.numIndices = pObj->m_dynamicData.indices.size();
  572.                 chunk.m_roadData.numTangents = pObj->m_dynamicData.tangents.size();
  573.  
  574.                 chunk.m_roadData.physicsGeometryCount = pObj->m_dynamicData.physicsGeometry.Count();
  575.  
  576.                 chunk.m_roadData.sourceVertexCount = pObj->m_arrVerts.Count();
  577.  
  578.                 AddToPtr(pPtr, nDatanSize, chunk, eEndian);
  579.  
  580.                 CRY_ASSERT_MESSAGE(sizeof(vtx_idx) == sizeof(uint32), "Road exporting can only occur on a platform with 32-bit vertex indices");
  581.  
  582.                 AddToPtr(pPtr, nDatanSize, pObj->m_dynamicData.vertices.GetElements(), chunk.m_roadData.numVertices, eEndian);
  583.                 AddToPtr(pPtr, nDatanSize, pObj->m_dynamicData.indices.GetElements(), chunk.m_roadData.numIndices, eEndian);
  584.                 AddToPtr(pPtr, nDatanSize, pObj->m_dynamicData.tangents.GetElements(), chunk.m_roadData.numTangents, eEndian);
  585.  
  586.                 if (chunk.m_roadData.physicsGeometryCount > 0)
  587.                 {
  588.                         AddToPtr(pPtr, nDatanSize, pObj->m_dynamicData.physicsGeometry.GetElements(), chunk.m_roadData.physicsGeometryCount, eEndian);
  589.                 }
  590.  
  591.                 AddToPtr(pPtr, nDatanSize, pObj->m_arrVerts.GetElements(), pObj->m_arrVerts.Count(), eEndian);
  592.         }
  593.         else if (eERType_Decal == eType && !(pEnt->GetRndFlags() & ERF_PROCEDURAL))
  594.         {
  595.                 AddToPtr(pPtr, nDatanSize, eType, eEndian);
  596.  
  597.                 CDecalRenderNode* pObj((CDecalRenderNode*) pEnt);
  598.  
  599.                 SDecalChunk chunk;
  600.  
  601.                 CopyCommonData(&chunk, pObj, segmentOffset);
  602.  
  603.                 // decal properties
  604.                 const SDecalProperties* pDecalProperties(pObj->GetDecalProperties());
  605.                 assert(pDecalProperties);
  606.                 chunk.m_projectionType = pDecalProperties->m_projectionType;
  607.                 chunk.m_deferred = pDecalProperties->m_deferred;
  608.                 chunk.m_pos = pDecalProperties->m_pos + segmentOffset;
  609.                 chunk.m_normal = pDecalProperties->m_normal;
  610.                 chunk.m_explicitRightUpFront = pDecalProperties->m_explicitRightUpFront;
  611.                 chunk.m_radius = pDecalProperties->m_radius;
  612.                 chunk.m_depth = (uint8)SATURATEB(255.f - pDecalProperties->m_depth * 255);
  613.  
  614.                 chunk.m_nMaterialId = CObjManager::GetItemId(pMatTable, pObj->GetMaterial());
  615.                 chunk.m_nSortPriority = pDecalProperties->m_sortPrio;
  616.  
  617.                 AddToPtr(pPtr, nDatanSize, chunk, eEndian);
  618.         }
  619.         else if (eERType_WaterVolume == eType)
  620.         {
  621.                 CWaterVolumeRenderNode* pObj((CWaterVolumeRenderNode*) pEnt);
  622.  
  623.                 // get access to serialization parameters
  624.                 const SWaterVolumeSerialize* pSerData(pObj->GetSerializationParams());
  625.                 if (pSerData)
  626.                 {
  627.                         //assert( pSerData ); // trying to save level outside the editor?
  628.  
  629.                         // save type
  630.                         AddToPtr(pPtr, nDatanSize, eType, eEndian);
  631.  
  632.                         // save node data
  633.                         SWaterVolumeChunk chunk;
  634.                         int cntAux;
  635.                         float* pAuxData = pObj->GetAuxSerializationDataPtr(cntAux);
  636.  
  637.                         CopyCommonData(&chunk, pObj, segmentOffset);
  638.  
  639.                         chunk.m_volumeTypeAndMiscBits = (pSerData->m_volumeType & 0xFFFF) | ((pSerData->m_capFogAtVolumeDepth ? 1 : 0) << 16) | ((pSerData->m_fogColorAffectedBySun ? 0 : 1) << 17) | (cntAux << 24);
  640.                         chunk.m_volumeID = pSerData->m_volumeID;
  641.  
  642.                         chunk.m_materialID = CObjManager::GetItemId(pMatTable, pSerData->m_pMaterial);
  643.  
  644.                         chunk.m_fogDensity = pSerData->m_fogDensity;
  645.                         chunk.m_fogColor = pSerData->m_fogColor;
  646.                         chunk.m_fogPlane = pSerData->m_fogPlane;
  647.                         chunk.m_fogShadowing = pSerData->m_fogShadowing;
  648.  
  649.                         chunk.m_caustics = pSerData->m_caustics;
  650.                         chunk.m_causticIntensity = pSerData->m_causticIntensity;
  651.                         chunk.m_causticTiling = pSerData->m_causticTiling;
  652.                         chunk.m_causticHeight = pSerData->m_causticHeight;
  653.  
  654.                         chunk.m_uTexCoordBegin = pSerData->m_uTexCoordBegin;
  655.                         chunk.m_uTexCoordEnd = pSerData->m_uTexCoordEnd;
  656.                         chunk.m_surfUScale = pSerData->m_surfUScale;
  657.                         chunk.m_surfVScale = pSerData->m_surfVScale;
  658.                         chunk.m_numVertices = pSerData->m_vertices.size();
  659.  
  660.                         chunk.m_volumeDepth = pSerData->m_volumeDepth;
  661.                         chunk.m_streamSpeed = pSerData->m_streamSpeed;
  662.                         chunk.m_numVerticesPhysAreaContour = pSerData->m_physicsAreaContour.size();
  663.  
  664.                         AddToPtr(pPtr, nDatanSize, chunk, eEndian);
  665.                         AddToPtr(pPtr, pAuxData, cntAux, eEndian);
  666.                         nDatanSize -= cntAux * sizeof(pAuxData[0]);
  667.  
  668.                         // save vertices
  669.                         for (size_t i(0); i < pSerData->m_vertices.size(); ++i)
  670.                         {
  671.                                 SWaterVolumeVertex v;
  672.                                 v.m_xyz = pSerData->m_vertices[i] + segmentOffset;
  673.  
  674.                                 AddToPtr(pPtr, nDatanSize, v, eEndian);
  675.                         }
  676.  
  677.                         // save physics area contour vertices
  678.                         for (size_t i(0); i < pSerData->m_physicsAreaContour.size(); ++i)
  679.                         {
  680.                                 SWaterVolumeVertex v;
  681.                                 v.m_xyz = pSerData->m_physicsAreaContour[i] + segmentOffset;
  682.  
  683.                                 AddToPtr(pPtr, nDatanSize, v, eEndian);
  684.                         }
  685.                 }
  686.  
  687.         }
  688.         else if (eERType_DistanceCloud == eType)
  689.         {
  690.                 AddToPtr(pPtr, nDatanSize, eType, eEndian);
  691.  
  692.                 CDistanceCloudRenderNode* pObj((CDistanceCloudRenderNode*)pEnt);
  693.  
  694.                 SDistanceCloudChunk chunk;
  695.  
  696.                 CopyCommonData(&chunk, pObj, segmentOffset);
  697.  
  698.                 // distance cloud properties
  699.                 SDistanceCloudProperties properties(pObj->GetProperties());
  700.                 chunk.m_pos = properties.m_pos + segmentOffset;
  701.                 chunk.m_sizeX = properties.m_sizeX;
  702.                 chunk.m_sizeY = properties.m_sizeY;
  703.                 chunk.m_rotationZ = properties.m_rotationZ;
  704.                 chunk.m_materialID = CObjManager::GetItemId(pMatTable, pObj->GetMaterial());
  705.  
  706.                 AddToPtr(pPtr, nDatanSize, chunk, eEndian);
  707.         }
  708.         else if (eERType_WaterWave == eType)
  709.         {
  710.                 CWaterWaveRenderNode* pObj((CWaterWaveRenderNode*) pEnt);
  711.  
  712.                 // get access to serialization parameters
  713.                 const SWaterWaveSerialize* pSerData(pObj->GetSerializationParams());
  714.                 assert(pSerData);       // trying to save level outside the editor?
  715.  
  716.                 // save type
  717.                 AddToPtr(pPtr, nDatanSize, eType, eEndian);
  718.  
  719.                 SWaterWaveChunk chunk;
  720.  
  721.                 CopyCommonData(&chunk, pObj, segmentOffset);
  722.  
  723.                 chunk.m_nID = (int32)pSerData->m_nID;
  724.                 chunk.m_nMaterialID = CObjManager::GetItemId(pMatTable, pSerData->m_pMaterial);
  725.  
  726.                 chunk.m_fUScale = pSerData->m_fUScale;
  727.                 chunk.m_fVScale = pSerData->m_fVScale;
  728.  
  729.                 chunk.m_nVertexCount = pSerData->m_nVertexCount;
  730.  
  731.                 chunk.m_pWorldTM = pSerData->m_pWorldTM;
  732.                 chunk.m_pWorldTM.SetTranslation(chunk.m_pWorldTM.GetTranslation() + segmentOffset);
  733.  
  734.                 chunk.m_fSpeed = pSerData->m_pParams.m_fSpeed;
  735.                 chunk.m_fSpeedVar = pSerData->m_pParams.m_fSpeedVar;
  736.                 chunk.m_fLifetime = pSerData->m_pParams.m_fLifetime;
  737.                 chunk.m_fLifetimeVar = pSerData->m_pParams.m_fLifetimeVar;
  738.                 chunk.m_fPosVar = pSerData->m_pParams.m_fPosVar;
  739.                 chunk.m_fHeight = pSerData->m_pParams.m_fHeight;
  740.                 chunk.m_fHeightVar = pSerData->m_pParams.m_fHeightVar;
  741.  
  742.                 chunk.m_fCurrLifetime = pSerData->m_pParams.m_fCurrLifetime;
  743.                 chunk.m_fCurrFrameLifetime = pSerData->m_pParams.m_fCurrFrameLifetime;
  744.                 chunk.m_fCurrSpeed = pSerData->m_pParams.m_fCurrSpeed;
  745.                 chunk.m_fCurrHeight = pSerData->m_pParams.m_fCurrHeight;
  746.  
  747.                 AddToPtr(pPtr, nDatanSize, chunk, eEndian);
  748.  
  749.                 // save vertices
  750.                 for (size_t i(0); i < pSerData->m_nVertexCount; ++i)
  751.                 {
  752.                         Vec3 vPos(pSerData->m_pVertices[i] + segmentOffset);
  753.                         AddToPtr(pPtr, nDatanSize, vPos, eEndian);
  754.                 }
  755.         }
  756.  
  757.         // align to 4
  758.         while (UINT_PTR(pPtr) & 3)
  759.         {
  760.                 byte emptyByte = 222;
  761.                 memcpy(pPtr, &emptyByte, sizeof(emptyByte));
  762.                 pPtr += sizeof(emptyByte);
  763.                 nDatanSize -= sizeof(emptyByte);
  764.         }
  765. }
  766.  
  767. bool COctreeNode::IsObjectStreamable(EERType eType, uint64 dwRndFlags)
  768. {
  769.         return (eType == eERType_Vegetation && !(dwRndFlags & ERF_PROCEDURAL)) || (eType == eERType_Decal) || (eType == eERType_Road) || (eType == eERType_MergedMesh); // || (dwRndFlags & ERF_STREAMABLE)
  770. }
  771.  
  772. bool COctreeNode::CheckSkipLoadObject(EERType eType, uint64 dwRndFlags, ELoadObjectsMode eLoadMode)
  773. {
  774.         return
  775.           (eLoadMode == LOM_LOAD_ONLY_NON_STREAMABLE && (IsObjectStreamable(eType, dwRndFlags))) ||
  776.           (eLoadMode == LOM_LOAD_ONLY_STREAMABLE && !(IsObjectStreamable(eType, dwRndFlags)));
  777. }
  778.  
  779. void COctreeNode::LoadSingleObject(byte*& pPtr, std::vector<IStatObj*>* pStatObjTable, std::vector<IMaterial*>* pMatTable, EEndian eEndian, int nChunkVersion, const SLayerVisibility* pLayerVisibility, int nSID, const Vec3& segmentOffset, ELoadObjectsMode eLoadMode, IRenderNode*& pRN)
  780. {
  781.         EERType eType = *StepData<EERType>(pPtr, eEndian);
  782.  
  783.         // For these structures, our Endian swapping is built in to the member copy.
  784.         if (eType == eERType_Brush)
  785.         {
  786.                 MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_Terrain, 0, "Brush object");
  787.  
  788.                 SBrushChunk* pChunk = StepData<SBrushChunk>(pPtr, eEndian);
  789.  
  790.                 if (CheckSkipLoadObject(eType, pChunk->m_dwRndFlags, eLoadMode) || !CheckRenderFlagsMinSpec(pChunk->m_dwRndFlags))
  791.                         return;
  792.  
  793.                 if (Get3DEngine()->IsLayerSkipped(pChunk->m_nLayerId))
  794.                         return;
  795.  
  796.                 CBrush* pObj = new CBrush();
  797.                 pRN = pObj;
  798.  
  799.                 // common node data
  800.                 COPY_MEMBER_LOAD(pObj, pChunk, m_WSBBox);
  801.                 LoadCommonData(pChunk, pObj, pLayerVisibility);
  802.  
  803.                 // brush data
  804.                 COPY_MEMBER_LOAD(pObj, pChunk, m_nMaterialLayers);
  805.                 COPY_MEMBER_LOAD(pObj, pChunk, m_Matrix);
  806.                 COPY_MEMBER_LOAD(pObj, pChunk, m_collisionClassIdx);
  807.  
  808.                 pObj->SetStatObj(CObjManager::GetItemPtr(pStatObjTable, (int)pChunk->m_nObjectTypeIndex));
  809.  
  810.                 // set material
  811.                 pObj->SetMaterial(CObjManager::GetItemPtr(pMatTable, pChunk->m_nMaterialId));
  812.  
  813.                 pObj->OffsetPosition(segmentOffset);
  814.  
  815.                 // to get correct indirect lighting the registration must be done before checking if this object is inside a VisArea
  816.                 Get3DEngine()->RegisterEntity(pObj, nSID, nSID);
  817.  
  818.                 if (NULL != pLayerVisibility)
  819.                 {
  820.                         if (!CheckLayerVisibility(pObj->GetLayerId(), pLayerVisibility))
  821.                         {
  822.                                 pObj->SetRndFlags(ERF_HIDDEN, true);
  823.                         }
  824.                 }
  825.                 else if (Get3DEngine()->IsObjectsLayerHidden(pObj->GetLayerId(), pObj->GetBBox()))
  826.                 {
  827.                         // keep everything deactivated, game will activate it later
  828.                         pObj->SetRndFlags(ERF_HIDDEN, true);
  829.                 }
  830.  
  831.                 if (!(Get3DEngine()->IsObjectsLayerHidden(pObj->GetLayerId(), pObj->GetBBox()) && GetCVars()->e_ObjectLayersActivationPhysics == 1) && !(pChunk->m_dwRndFlags & ERF_NO_PHYSICS))
  832.                         pObj->Physicalize();
  833.  
  834.                 pObj->SetDrawLast((pChunk->m_flags & 1) != 0);
  835.         }
  836.         else if (eType == eERType_Vegetation)
  837.         {
  838.                 MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_Terrain, 0, "Vegetation object");
  839.  
  840.                 SVegetationChunk* pChunk = StepData<SVegetationChunk>(pPtr, eEndian);
  841.  
  842.                 bool bStreamAllVegetation = true;
  843.  
  844.                 if (CheckSkipLoadObject(eType, pChunk->m_dwRndFlags, eLoadMode) || !CheckRenderFlagsMinSpec(GetObjManager()->m_lstStaticTypes[nSID][pChunk->m_nObjectTypeIndex].m_dwRndFlags))
  845.                         return;
  846.  
  847.                 StatInstGroup* pGroup = &GetObjManager()->m_lstStaticTypes[nSID][pChunk->m_nObjectTypeIndex];
  848.                 if (!pGroup->GetStatObj() || (pGroup->GetStatObj()->GetRadius() * pChunk->m_fScale < GetCVars()->e_VegetationMinSize))
  849.                         return;   // skip creation of very small objects
  850.  
  851.                 CVegetation* pObj = new CVegetation();
  852.                 pRN = pObj;
  853.  
  854.                 // common node data
  855.                 LoadCommonData(pChunk, pObj, pLayerVisibility);
  856.  
  857.                 // vegetation data
  858.                 COPY_MEMBER_LOAD(pObj, pChunk, m_vPos);
  859.  
  860.                 pObj->SetScale(pChunk->m_fScale);
  861.  
  862.                 COPY_MEMBER_LOAD(pObj, pChunk, m_nObjectTypeIndex);
  863.                 COPY_MEMBER_LOAD(pObj, pChunk, m_ucAngle);
  864.                 COPY_MEMBER_LOAD(pObj, pChunk, m_ucAngleX);
  865.                 COPY_MEMBER_LOAD(pObj, pChunk, m_ucAngleY);
  866.  
  867.                 pObj->SetBBox(pChunk->m_WSBBox);
  868. #ifdef SEG_WORLD
  869.                 assert(nSID < 65536);
  870.                 pObj->m_nStaticTypeSlot = nSID;
  871. #endif
  872.                 pObj->Physicalize();
  873.                 pObj->OffsetPosition(segmentOffset);
  874.                 Get3DEngine()->RegisterEntity(pObj, nSID, nSID);
  875.                 pObj->CheckCreateDeformable();
  876.  
  877.                 assert(!(pObj->GetRndFlags() & ERF_PROCEDURAL));
  878.         }
  879.         else if (eType == eERType_MergedMesh)
  880.         {
  881.                 MEMSTAT_CONTEXT(EMemStatContextTypes::MSC_Terrain, 0, "Merged Mesh Object");
  882.                 SMergedMeshChunk* pChunk = StepData<SMergedMeshChunk>(pPtr, eEndian);
  883.  
  884.                 if (CheckSkipLoadObject(eType, pChunk->m_dwRndFlags, eLoadMode))
  885.                 {
  886.                         for (size_t i = 0; i < pChunk->m_nGroups; ++i)
  887.                                 StepData<SMergedMeshGroupChunk>(pPtr, eEndian);
  888.  
  889.                         return;
  890.                 }
  891.  
  892.                 CMergedMeshRenderNode* pObj = m_pMergedMeshesManager->GetNode((pChunk->m_Extents.max + pChunk->m_Extents.min) * 0.5f + segmentOffset);
  893.                 if (pObj->StreamedIn()) // MM is already streamed in
  894.                         return;
  895.  
  896.                 pRN = pObj;
  897.  
  898. #ifdef WH_MMRN_DEBUG
  899.                 TRACE_MSG(trace::e_Debug, trace::CTX_Engine, "COctreeNode::LoadSingleObject(), pObj:%p, flags:%d", pObj, pChunk->m_dwRndFlags);
  900. #endif
  901.                 LoadCommonData(pChunk, pObj, pLayerVisibility);
  902.                 pObj->Setup(pChunk->m_Extents, pChunk->m_WSBBox, NULL);
  903. #ifdef SEG_WORLD
  904.                 assert(nSID < 65536);
  905.                 pObj->m_nStaticTypeSlot = nSID;
  906. #endif
  907.                 bool bHasValidData = false;
  908.                 for (size_t i = 0; i < pChunk->m_nGroups; ++i)
  909.                 {
  910.                         SMergedMeshGroupChunk* pGroupChunk = StepData<SMergedMeshGroupChunk>(pPtr, eEndian);
  911.                         if (!gEnv->IsDedicated())
  912.                         {
  913.                                 bHasValidData |= pObj->AddGroup(pGroupChunk->m_StatInstGroupID, pGroupChunk->m_nSamples);
  914.                         }
  915.                 }
  916.  
  917.                 pObj->OffsetPosition(segmentOffset);
  918.                 if (bHasValidData)
  919.                 {
  920.                         Get3DEngine()->RegisterEntity(pObj, nSID, nSID);
  921.                 }
  922.                 else
  923.                 {
  924.                         delete pObj;
  925.                 }
  926.         }
  927.         else if (eType == eERType_Road)
  928.         {
  929.                 SRoadChunk* pChunk = StepData<SRoadChunk>(pPtr, eEndian);
  930.  
  931.                 // Make sure we always step through the data, even if we return below
  932.                 SVF_P3F_C4B_T2S* pVertices = StepData<SVF_P3F_C4B_T2S>(pPtr, pChunk->m_roadData.numVertices, eEndian);
  933.                 uint32* pIndices = StepData<uint32>(pPtr, pChunk->m_roadData.numIndices, eEndian);
  934.                 SPipTangents* pTangents = StepData<SPipTangents>(pPtr, pChunk->m_roadData.numTangents, eEndian);
  935.  
  936.                 CRoadRenderNode::SPhysicsGeometryParams* pPhysParams = nullptr;
  937.                 if (pChunk->m_roadData.physicsGeometryCount > 0)
  938.                 {
  939.                         pPhysParams = StepData<CRoadRenderNode::SPhysicsGeometryParams>(pPtr, pChunk->m_roadData.physicsGeometryCount, eEndian);
  940.                 }
  941.  
  942.                 Vec3* pSourceVertices = StepData<Vec3>(pPtr, pChunk->m_roadData.sourceVertexCount, eEndian);
  943.  
  944.                 if (CheckSkipLoadObject(eType, pChunk->m_dwRndFlags, eLoadMode) || !CheckRenderFlagsMinSpec(pChunk->m_dwRndFlags) || Get3DEngine()->IsLayerSkipped(pChunk->m_nLayerId))
  945.                 {
  946.                         return;
  947.                 }
  948.  
  949.                 CRoadRenderNode* pObj = new CRoadRenderNode();
  950.                 pRN = pObj;
  951.  
  952.                 pObj->m_serializedData = pChunk->m_roadData;
  953.  
  954.                 // common node data
  955.                 LoadCommonData(pChunk, pObj, pLayerVisibility);
  956.  
  957.                 // road data
  958.                 pObj->SetMaterial(CObjManager::GetItemPtr(pMatTable, pChunk->m_nMaterialId));
  959.                 pObj->m_sortPrio = pChunk->m_nSortPriority;
  960.                 pObj->m_bIgnoreTerrainHoles = (pChunk->m_nFlags & ROADCHUNKFLAG_IGNORE_TERRAIN_HOLES) != 0;
  961.                 pObj->m_bPhysicalize = (pChunk->m_nFlags & ROADCHUNKFLAG_PHYSICALIZE) != 0;
  962.  
  963.                 pObj->m_dynamicData.vertices.AddList(pVertices, pObj->m_serializedData.numVertices);
  964.  
  965.                 if (sizeof(vtx_idx) != sizeof(uint32))
  966.                 {
  967.                         // Strided copy, need to cast uint32 from uint16 since we exported from PC (uint32 vertices) and load on console / mobile (uint16)
  968.                         for (uint32 i = 0; i < pChunk->m_roadData.numIndices; i++)
  969.                         {
  970.                                 pObj->m_dynamicData.indices.Add(static_cast<vtx_idx>(pIndices[i]));
  971.                         }
  972.                 }
  973.                 else
  974.                 {
  975.                         pObj->m_dynamicData.indices.AddList(reinterpret_cast<vtx_idx*>(pIndices), pObj->m_serializedData.numIndices);
  976.                 }
  977.  
  978.                 pObj->m_dynamicData.tangents.AddList(pTangents, pObj->m_serializedData.numTangents);
  979.  
  980.                 if (pObj->m_serializedData.physicsGeometryCount > 0)
  981.                 {
  982.                         pObj->m_dynamicData.physicsGeometry.AddList(pPhysParams, pObj->m_serializedData.physicsGeometryCount);
  983.                 }
  984.  
  985.                 pObj->m_arrVerts.PreAllocate(pChunk->m_roadData.sourceVertexCount);
  986.                 pObj->m_arrVerts.AddList(pSourceVertices, pObj->m_serializedData.sourceVertexCount);
  987.  
  988.                 // Trigger CRoadRenderNode::Compile, but don't perform a full rebuild
  989.                 pObj->ScheduleRebuild(false);
  990.  
  991.                 // set object visibility
  992.                 if (NULL != pLayerVisibility)
  993.                 {
  994.                         CRY_ASSERT(pChunk->m_nLayerId != 0);
  995.                         if (!CheckLayerVisibility(pObj->GetLayerId(), pLayerVisibility))
  996.                         {
  997.                                 pObj->SetRndFlags(ERF_HIDDEN, true);
  998.                         }
  999.                 }
  1000.                 else if (Get3DEngine()->IsObjectsLayerHidden(pObj->GetLayerId(), pObj->GetBBox()))
  1001.                 {
  1002.                         // keep everything deactivated, game will activate it later
  1003.                         pObj->SetRndFlags(ERF_HIDDEN, true);
  1004.                 }
  1005.  
  1006.                 pObj->OffsetPosition(segmentOffset);
  1007.  
  1008.                 Get3DEngine()->RegisterEntity(pObj, nSID, nSID);
  1009.         }
  1010.         else if (eERType_Decal == eType)
  1011.         {
  1012.                 SDecalChunk* pChunk(StepData<SDecalChunk>(pPtr, eEndian));
  1013.  
  1014.                 if (CheckSkipLoadObject(eType, pChunk->m_dwRndFlags, eLoadMode) || !CheckRenderFlagsMinSpec(pChunk->m_dwRndFlags))
  1015.                         return;
  1016.  
  1017.                 if (Get3DEngine()->IsLayerSkipped(pChunk->m_nLayerId))
  1018.                         return;
  1019.  
  1020.                 CDecalRenderNode* pObj(new CDecalRenderNode());
  1021.                 pRN = pObj;
  1022.  
  1023.                 // common node data
  1024.                 pObj->SetBBox(pChunk->m_WSBBox);
  1025.                 LoadCommonData(pChunk, pObj, pLayerVisibility);
  1026.  
  1027.                 // decal properties
  1028.                 SDecalProperties properties;
  1029.  
  1030.                 switch (pChunk->m_projectionType)
  1031.                 {
  1032.                 case SDecalProperties::eProjectOnTerrainAndStaticObjects:
  1033.                         {
  1034.                                 properties.m_projectionType = SDecalProperties::eProjectOnTerrainAndStaticObjects;
  1035.                                 break;
  1036.                         }
  1037.                 case SDecalProperties::eProjectOnStaticObjects:
  1038.                         {
  1039.                                 properties.m_projectionType = SDecalProperties::eProjectOnStaticObjects;
  1040.                                 break;
  1041.                         }
  1042.                 case SDecalProperties::eProjectOnTerrain:
  1043.                         {
  1044.                                 properties.m_projectionType = SDecalProperties::eProjectOnTerrain;
  1045.                                 break;
  1046.                         }
  1047.                 case SDecalProperties::ePlanar:
  1048.                 default:
  1049.                         {
  1050.                                 properties.m_projectionType = SDecalProperties::ePlanar;
  1051.                                 break;
  1052.                         }
  1053.                 }
  1054.                 memcpy(&properties.m_pos, &pChunk->m_pos, sizeof(pChunk->m_pos));
  1055.                 memcpy(&properties.m_normal, &pChunk->m_normal, sizeof(pChunk->m_normal));
  1056.                 memcpy(&properties.m_explicitRightUpFront, &pChunk->m_explicitRightUpFront, sizeof(pChunk->m_explicitRightUpFront));
  1057.                 memcpy(&properties.m_radius, &pChunk->m_radius, sizeof(pChunk->m_radius));
  1058.  
  1059.                 uint8 depth = MIN(pChunk->m_depth, 254);
  1060.                 properties.m_depth = 1.f - 1.f / 255.f * depth;
  1061.  
  1062.                 IMaterial* pMaterial(CObjManager::GetItemPtr(pMatTable, pChunk->m_nMaterialId));
  1063.                 assert(pMaterial);
  1064.                 properties.m_pMaterialName = pMaterial ? pMaterial->GetName() : "";
  1065.                 properties.m_sortPrio = pChunk->m_nSortPriority;
  1066.                 properties.m_deferred = pChunk->m_deferred;
  1067.  
  1068.                 pObj->SetDecalProperties(properties);
  1069.  
  1070.                 // set object visibility
  1071.                 if (NULL != pLayerVisibility)
  1072.                 {
  1073.                         CRY_ASSERT(pChunk->m_nLayerId != 0);
  1074.                         if (!CheckLayerVisibility(pObj->GetLayerId(), pLayerVisibility))
  1075.                         {
  1076.                                 pObj->SetRndFlags(ERF_HIDDEN, true);
  1077.                         }
  1078.                 }
  1079.                 else if (Get3DEngine()->IsObjectsLayerHidden(pObj->GetLayerId(), pObj->GetBBox()))
  1080.                 {
  1081.                         // keep everything deactivated, game will activate it later
  1082.                         pObj->SetRndFlags(ERF_HIDDEN, true);
  1083.                 }
  1084.  
  1085.                 pObj->OffsetPosition(segmentOffset);
  1086.  
  1087.                 //if( pObj->GetMaterialID() != pChunk->m_materialID )
  1088.                 if (pObj->GetMaterial() != pMaterial)
  1089.                 {
  1090.                         const char* pMatName("_can't_resolve_material_name_");
  1091.                         int32 matID(pChunk->m_nMaterialId);
  1092.                         if (matID >= 0 && matID < (int)pMatTable->size())
  1093.                                 pMatName = pMaterial ? pMaterial->GetName() : "";
  1094.                         Warning("Warning: Removed placement decal at (%4.2f, %4.2f, %4.2f) with invalid material \"%s\"!\n", pChunk->m_pos.x, pChunk->m_pos.y, pChunk->m_pos.z, pMatName);
  1095.                         pObj->ReleaseNode();
  1096.                         pRN = NULL;
  1097.                 }
  1098.                 else
  1099.                 {
  1100.                         Get3DEngine()->RegisterEntity(pObj, nSID, nSID);
  1101.                         GetObjManager()->m_decalsToPrecreate.push_back(pObj);
  1102.                 }
  1103.         }
  1104.         else if (eERType_WaterVolume == eType)
  1105.         {
  1106.                 // read common info
  1107.                 SWaterVolumeChunk* pChunk(StepData<SWaterVolumeChunk>(pPtr, eEndian));
  1108.  
  1109.                 const int volumeTypeAndMiscBitShift = 24;
  1110.  
  1111.                 if (CheckSkipLoadObject(eType, pChunk->m_dwRndFlags, eLoadMode) || !CheckRenderFlagsMinSpec(pChunk->m_dwRndFlags) || Get3DEngine()->IsLayerSkipped(pChunk->m_nLayerId))
  1112.                 {
  1113.                         int auxCntSrc = pChunk->m_volumeTypeAndMiscBits >> volumeTypeAndMiscBitShift;
  1114.                         const float *pAuxDataSrc = StepData<float>(pPtr, auxCntSrc, eEndian);
  1115.  
  1116.                         for (uint32 j(0); j < pChunk->m_numVertices; ++j)
  1117.                         {
  1118.                                 SWaterVolumeVertex* pVertex(StepData<SWaterVolumeVertex>(pPtr, eEndian));
  1119.                         }
  1120.  
  1121.                         for (uint32 j(0); j < pChunk->m_numVerticesPhysAreaContour; ++j)
  1122.                         {
  1123.                                 SWaterVolumeVertex* pVertex(StepData<SWaterVolumeVertex>(pPtr, eEndian));
  1124.                         }
  1125.  
  1126.                         return;
  1127.                 }
  1128.  
  1129.                 CWaterVolumeRenderNode* pObj(new CWaterVolumeRenderNode());
  1130.                 pRN = pObj;
  1131.  
  1132.                 int auxCntSrc = pChunk->m_volumeTypeAndMiscBits >> volumeTypeAndMiscBitShift, auxCntDst;
  1133.                 float* pAuxDataDst = pObj->GetAuxSerializationDataPtr(auxCntDst);
  1134.                 const float* pAuxDataSrc = StepData<float>(pPtr, auxCntSrc, eEndian);
  1135.                 memcpy(pAuxDataDst, pAuxDataDst, min(auxCntSrc, auxCntDst) * sizeof(float));
  1136.  
  1137.                 // read common node data
  1138.                 pObj->SetBBox(pChunk->m_WSBBox);
  1139.                 LoadCommonData(pChunk, pObj, pLayerVisibility);
  1140.  
  1141.                 // read vertices
  1142.                 std::vector<Vec3> vertices;
  1143.                 vertices.reserve(pChunk->m_numVertices);
  1144.                 for (uint32 j(0); j < pChunk->m_numVertices; ++j)
  1145.                 {
  1146.                         SWaterVolumeVertex* pVertex(StepData<SWaterVolumeVertex>(pPtr, eEndian));
  1147.                         vertices.push_back(pVertex->m_xyz);
  1148.                 }
  1149.  
  1150.                 // read physics area contour vertices
  1151.                 std::vector<Vec3> physicsAreaContour;
  1152.                 physicsAreaContour.reserve(pChunk->m_numVerticesPhysAreaContour);
  1153.                 for (uint32 j(0); j < pChunk->m_numVerticesPhysAreaContour; ++j)
  1154.                 {
  1155.                         SWaterVolumeVertex* pVertex(StepData<SWaterVolumeVertex>(pPtr, eEndian));
  1156.                         physicsAreaContour.push_back(pVertex->m_xyz);
  1157.                 }
  1158.  
  1159.                 const int volumeType = pChunk->m_volumeTypeAndMiscBits & 0xFFFF;
  1160.                 const bool capFogAtVolumeDepth = ((pChunk->m_volumeTypeAndMiscBits & 0x10000) != 0) ? true : false;
  1161.                 const bool fogColorAffectedBySun = ((pChunk->m_volumeTypeAndMiscBits & 0x20000) == 0) ? true : false;
  1162.                 const bool enableCaustics = (pChunk->m_caustics != 0) ? true : false;
  1163.  
  1164.                 // create volume
  1165.                 switch (volumeType)
  1166.                 {
  1167.                 case IWaterVolumeRenderNode::eWVT_River:
  1168.                         {
  1169.                                 pObj->CreateRiver(pChunk->m_volumeID, &vertices[0], pChunk->m_numVertices, pChunk->m_uTexCoordBegin, pChunk->m_uTexCoordEnd, Vec2(pChunk->m_surfUScale, pChunk->m_surfVScale), pChunk->m_fogPlane, false, nSID);
  1170.                                 break;
  1171.                         }
  1172.                 case IWaterVolumeRenderNode::eWVT_Area:
  1173.                         {
  1174.                                 pObj->CreateArea(pChunk->m_volumeID, &vertices[0], pChunk->m_numVertices, Vec2(pChunk->m_surfUScale, pChunk->m_surfVScale), pChunk->m_fogPlane, false, nSID);
  1175.                                 break;
  1176.                         }
  1177.                 case IWaterVolumeRenderNode::eWVT_Ocean:
  1178.                         {
  1179.                                 assert(!"COctreeNode::SerializeObjects( ... ) -- Water volume of type \"Ocean\" not supported yet!");
  1180.                                 break;
  1181.                         }
  1182.                 default:
  1183.                         {
  1184.                                 assert(!"COctreeNode::SerializeObjects( ... ) -- Invalid water volume type!");
  1185.                                 break;
  1186.                         }
  1187.                 }
  1188.  
  1189.                 // set material
  1190.                 IMaterial* pMaterial(CObjManager::GetItemPtr(pMatTable, pChunk->m_materialID));
  1191.  
  1192.                 // set properties
  1193.                 pObj->SetFogDensity(pChunk->m_fogDensity);
  1194.                 pObj->SetFogColor(pChunk->m_fogColor);
  1195.                 pObj->SetFogColorAffectedBySun(fogColorAffectedBySun);
  1196.                 pObj->SetFogShadowing(pChunk->m_fogShadowing);
  1197.  
  1198.                 pObj->SetVolumeDepth(pChunk->m_volumeDepth);
  1199.                 pObj->SetStreamSpeed(pChunk->m_streamSpeed);
  1200.                 pObj->SetCapFogAtVolumeDepth(capFogAtVolumeDepth);
  1201.  
  1202.                 pObj->SetCaustics(enableCaustics);
  1203.                 pObj->SetCausticIntensity(pChunk->m_causticIntensity);
  1204.                 pObj->SetCausticTiling(pChunk->m_causticTiling);
  1205.                 pObj->SetCausticHeight(pChunk->m_causticHeight);
  1206.  
  1207.                 // set object visibility
  1208.                 if (NULL != pLayerVisibility)
  1209.                 {
  1210.                         CRY_ASSERT(pChunk->m_nLayerId != 0);
  1211.                         if (!CheckLayerVisibility(pObj->GetLayerId(), pLayerVisibility))
  1212.                         {
  1213.                                 pObj->SetRndFlags(ERF_HIDDEN, true);
  1214.                         }
  1215.                 }
  1216.                 else if (Get3DEngine()->IsObjectsLayerHidden(pObj->GetLayerId(), pObj->GetBBox()))
  1217.                 {
  1218.                         // keep everything deactivated, game will activate it later
  1219.                         pObj->SetRndFlags(ERF_HIDDEN, true);
  1220.                 }
  1221.  
  1222.                 // set physics
  1223.                 if (!physicsAreaContour.empty())
  1224.                 {
  1225.                         switch (volumeType)
  1226.                         {
  1227.                         case IWaterVolumeRenderNode::eWVT_River:
  1228.                                 {
  1229.                                         pObj->SetRiverPhysicsArea(&physicsAreaContour[0], physicsAreaContour.size());
  1230.                                         break;
  1231.                                 }
  1232.                         case IWaterVolumeRenderNode::eWVT_Area:
  1233.                                 {
  1234.                                         pObj->SetAreaPhysicsArea(&physicsAreaContour[0], physicsAreaContour.size());
  1235.                                         break;
  1236.                                 }
  1237.                         case IWaterVolumeRenderNode::eWVT_Ocean:
  1238.                                 {
  1239.                                         assert(!"COctreeNode::SerializeObjects( ... ) -- Water volume of type \"Ocean\" not supported yet!");
  1240.                                         break;
  1241.                                 }
  1242.                         default:
  1243.                                 {
  1244.                                         assert(!"COctreeNode::SerializeObjects( ... ) -- Invalid water volume type!");
  1245.                                         break;
  1246.                                 }
  1247.                         }
  1248.  
  1249.                         if (!(Get3DEngine()->IsObjectsLayerHidden(pObj->GetLayerId(), pObj->GetBBox()) && GetCVars()->e_ObjectLayersActivationPhysics) && !(pChunk->m_dwRndFlags & ERF_NO_PHYSICS))
  1250.                                 pObj->Physicalize();
  1251.                 }
  1252.  
  1253.                 // set material
  1254.                 pObj->SetMaterial(pMaterial);
  1255.  
  1256.                 pObj->OffsetPosition(segmentOffset);
  1257.  
  1258.                 Get3DEngine()->RegisterEntity(pObj, nSID, nSID);
  1259.         }
  1260.         else if (eERType_DistanceCloud == eType)
  1261.         {
  1262.                 SDistanceCloudChunk* pChunk(StepData<SDistanceCloudChunk>(pPtr, eEndian));
  1263.  
  1264.                 if (CheckSkipLoadObject(eType, pChunk->m_dwRndFlags, eLoadMode) || !CheckRenderFlagsMinSpec(pChunk->m_dwRndFlags))
  1265.                         return;
  1266.  
  1267.                 if (Get3DEngine()->IsLayerSkipped(pChunk->m_nLayerId))
  1268.                         return;
  1269.  
  1270.                 CDistanceCloudRenderNode* pObj(new CDistanceCloudRenderNode());
  1271.                 pRN = pObj;
  1272.  
  1273.                 // common node data
  1274.                 AABB box;
  1275.                 memcpy(&box, &pChunk->m_WSBBox, sizeof(AABB));
  1276.                 pObj->SetBBox(box);
  1277.                 LoadCommonData(pChunk, pObj, pLayerVisibility);
  1278.  
  1279.                 // distance cloud properties
  1280.                 SDistanceCloudProperties properties;
  1281.  
  1282.                 properties.m_pos = pChunk->m_pos;
  1283.                 properties.m_sizeX = pChunk->m_sizeX;
  1284.                 properties.m_sizeY = pChunk->m_sizeY;
  1285.                 properties.m_rotationZ = pChunk->m_rotationZ;
  1286.  
  1287.                 IMaterial* pMaterial(CObjManager::GetItemPtr(pMatTable, pChunk->m_materialID));
  1288.                 assert(pMaterial);
  1289.                 properties.m_pMaterialName = pMaterial ? pMaterial->GetName() : "";
  1290.  
  1291.                 pObj->SetProperties(properties);
  1292.  
  1293.                 pObj->OffsetPosition(segmentOffset);
  1294.  
  1295.                 // set object visibility
  1296.                 if (NULL != pLayerVisibility)
  1297.                 {
  1298.                         CRY_ASSERT(pChunk->m_nLayerId != 0);
  1299.                         if (!CheckLayerVisibility(pObj->GetLayerId(), pLayerVisibility))
  1300.                         {
  1301.                                 pObj->SetRndFlags(ERF_HIDDEN, true);
  1302.                         }
  1303.                 }
  1304.                 else if (Get3DEngine()->IsObjectsLayerHidden(pObj->GetLayerId(), pObj->GetBBox()))
  1305.                 {
  1306.                         // keep everything deactivated, game will activate it later
  1307.                         pObj->SetRndFlags(ERF_HIDDEN, true);
  1308.                 }
  1309.  
  1310.                 if (pObj->GetMaterial() != pMaterial)
  1311.                 {
  1312.                         const char* pMatName("_can't_resolve_material_name_");
  1313.                         int32 matID(pChunk->m_materialID);
  1314.                         if (matID >= 0 && matID < (int32)(*pMatTable).size())
  1315.                                 pMatName = pMaterial ? pMaterial->GetName() : "";
  1316.                         Warning("Warning: Removed distance cloud at (%4.2f, %4.2f, %4.2f) with invalid material \"%s\"!\n", pChunk->m_pos.x, pChunk->m_pos.y, pChunk->m_pos.z, pMatName);
  1317.                         pObj->ReleaseNode();
  1318.                         pRN = NULL;
  1319.                 }
  1320.                 else
  1321.                 {
  1322.                         Get3DEngine()->RegisterEntity(pObj, nSID, nSID);
  1323.                 }
  1324.         }
  1325.         else if (eERType_WaterWave == eType)
  1326.         {
  1327.                 // read common info
  1328.                 SWaterWaveChunk* pChunk(StepData<SWaterWaveChunk>(pPtr, eEndian));
  1329.  
  1330.                 if (CheckSkipLoadObject(eType, pChunk->m_dwRndFlags, eLoadMode) || !CheckRenderFlagsMinSpec(pChunk->m_dwRndFlags) || Get3DEngine()->IsLayerSkipped(pChunk->m_nLayerId))
  1331.                 {
  1332.                         for (uint32 j(0); j < pChunk->m_nVertexCount; ++j)
  1333.                         {
  1334.                                 Vec3* pVertex(StepData<Vec3>(pPtr, eEndian));
  1335.                         }
  1336.  
  1337.                         return;
  1338.                 }
  1339.  
  1340.                 CWaterWaveRenderNode* pObj(new CWaterWaveRenderNode());
  1341.                 pRN = pObj;
  1342.  
  1343.                 // read common node data
  1344.                 pObj->SetBBox(pChunk->m_WSBBox);
  1345.                 LoadCommonData(pChunk, pObj, pLayerVisibility);
  1346.  
  1347.                 // read vertices
  1348.                 std::vector<Vec3> pVertices;
  1349.                 pVertices.reserve(pChunk->m_nVertexCount);
  1350.                 for (uint32 j(0); j < pChunk->m_nVertexCount; ++j)
  1351.                 {
  1352.                         Vec3* pVertex(StepData<Vec3>(pPtr, eEndian));
  1353.                         pVertices.push_back(*pVertex);
  1354.                 }
  1355.  
  1356.                 // set material
  1357.                 IMaterial* pMaterial(CObjManager::GetItemPtr(pMatTable, pChunk->m_nMaterialID));
  1358.                 assert(pMaterial);
  1359.  
  1360.                 // set material
  1361.                 pObj->SetMaterial(pMaterial);
  1362.  
  1363.                 SWaterWaveParams pParams;
  1364.                 pParams.m_fSpeed = pChunk->m_fSpeed;
  1365.                 pParams.m_fSpeedVar = pChunk->m_fSpeedVar;
  1366.                 pParams.m_fLifetime = pChunk->m_fLifetime;
  1367.                 pParams.m_fLifetimeVar = pChunk->m_fLifetimeVar;
  1368.                 pParams.m_fPosVar = pChunk->m_fPosVar;
  1369.                 pParams.m_fHeight = pChunk->m_fHeight;
  1370.                 pParams.m_fHeightVar = pChunk->m_fHeightVar;
  1371.                 pParams.m_fCurrLifetime = pChunk->m_fCurrLifetime;
  1372.                 pParams.m_fCurrFrameLifetime = pChunk->m_fCurrFrameLifetime;
  1373.                 pParams.m_fCurrSpeed = pChunk->m_fCurrSpeed;
  1374.                 pParams.m_fCurrHeight = pChunk->m_fCurrHeight;
  1375.  
  1376.                 pObj->SetParams(pParams);
  1377.  
  1378.                 Vec2 vScaleUV(pChunk->m_fUScale, pChunk->m_fVScale);
  1379.                 pObj->Create(pChunk->m_nID, &pVertices[0], pChunk->m_nVertexCount, vScaleUV, pChunk->m_pWorldTM);
  1380.  
  1381.                 pObj->OffsetPosition(segmentOffset);
  1382.  
  1383.                 //Get3DEngine()->RegisterEntity( pObj );
  1384.         }
  1385.         else
  1386.                 assert(!"Unsupported object type");
  1387.  
  1388.         // align to 4
  1389.         while (UINT_PTR(pPtr) & 3)
  1390.         {
  1391.                 assert(*pPtr == 222);
  1392.                 pPtr++;
  1393.         }
  1394. }
  1395.  
downloadObjectsTree_Serialize.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top