void BarycentricMapperMeshTopology<CudaVec3fTypes,CudaVec3fTypes>::applyJT( In::MatrixDeriv& out, const Out::MatrixDeriv& in) { Out::MatrixDeriv::RowConstIterator rowItEnd = in.end(); for ( Out::MatrixDeriv::RowConstIterator rowIt = in.begin(); rowIt != rowItEnd; ++rowIt) { Out::MatrixDeriv::ColConstIterator colItEnd = rowIt.end(); Out::MatrixDeriv::ColConstIterator colIt = rowIt.begin(); int indexIn; if (colIt != colItEnd) { In::MatrixDeriv::RowIterator o = out.writeLine(rowIt.index()); for ( ; colIt != colItEnd; ++colIt) { indexIn = colIt.index(); InDeriv data = (InDeriv) colIt.val(); for (int j=0; j<maxNIn; ++j) { const OutReal f = ( OutReal ) getMapValue(indexIn,j); int index = getMapIndex(indexIn,j); if (index < 0) break; o.addCol( index, data * f ); } } } } }
bool AflMapData::setMapSize(INT iWidth,INT iHeight) { int i,j,k; for(i=0;i<5;i++) { PSHORT pData = NEW SHORT[iWidth*iHeight]; ZeroMemory(pData,sizeof(SHORT)*iWidth*iHeight); for(j=0;j < iHeight ;j++) { for(k=0;k < iWidth ;k++) pData[iWidth*j+k] = getMapIndex(i,k,j); } std::auto_ptr<SHORT> sData(pData); m_ptrData[i] = sData; } m_iMapWidth = iWidth; m_iMapHeight = iHeight; return true; }
void Pacman::moveEntity(unsigned int* cellIndex, sf::Vector2f* offset, ViewDirection* direction, ViewDirection* desiredDirection, bool* isMoving, float speed, bool isPlayer) { // Si está quieto, modificamos su dirección directamente if(!*isMoving && *direction != *desiredDirection) { *direction = *desiredDirection; } *isMoving = true; // Modificamos su dirección si es posible y movemos el objeto resolviendo colisiones if(*direction == ViewDirection::Left) { if(*desiredDirection != *direction && !checkCollision(*cellIndex, *desiredDirection, isPlayer)) { switch(*desiredDirection) { case ViewDirection::Right: *direction = *desiredDirection; break; case ViewDirection::Up: case ViewDirection::Down: if(offset->x >= 0 && (offset->x + speed) >= 0) { offset->x = 0; *direction = *desiredDirection; return; } break; default: break; } } if(offset->x <= 0 && checkCollision(*cellIndex, *direction, isPlayer)) { *isMoving = false; *desiredDirection = *direction; offset->x = 0; return; } offset->x -= speed; if(offset->x < -(m_tileSize.x / 2)) { *cellIndex = getMapIndex(*cellIndex, ViewDirection::Left); offset->x = (m_tileSize.x / 2) - abs((m_tileSize.x / 2) + offset->x); } } else if(*direction == ViewDirection::Right) { if(*desiredDirection != *direction && !checkCollision(*cellIndex, *desiredDirection, isPlayer)) { switch(*desiredDirection) { case ViewDirection::Left: *direction = *desiredDirection; break; case ViewDirection::Up: case ViewDirection::Down: if(offset->x <= 0 && (offset->x - speed) <= 0) { offset->x = 0; *direction = *desiredDirection; return; } break; default: break; } } if(offset->x >= 0 && checkCollision(*cellIndex, *direction, isPlayer)) { *isMoving = false; *desiredDirection = *direction; offset->x = 0; return; } offset->x += speed; if(offset->x > (m_tileSize.x / 2)) { *cellIndex = getMapIndex(*cellIndex, ViewDirection::Right); offset->x = -(m_tileSize.x / 2) + abs((m_tileSize.x / 2) - offset->x); } } else if(*direction == ViewDirection::Up) { if(*desiredDirection != *direction && !checkCollision(*cellIndex, *desiredDirection, isPlayer)) { switch(*desiredDirection) { case ViewDirection::Down: *direction = *desiredDirection; break; case ViewDirection::Left: case ViewDirection::Right: if(offset->y >= 0 && (offset->y + speed) >= 0) { offset->y = 0; *direction = *desiredDirection; return; } break; default: break; } } if(offset->y <= 0 && checkCollision(*cellIndex, *direction, isPlayer)) { *isMoving = false; *desiredDirection = *direction; offset->y = 0; return; } offset->y -= speed; if(offset->y < -(m_tileSize.y / 2)) { *cellIndex = getMapIndex(*cellIndex, ViewDirection::Up); offset->y = (m_tileSize.y / 2) - abs((m_tileSize.y / 2) + offset->y); } } else if(*direction == ViewDirection::Down) { if(*desiredDirection != *direction && !checkCollision(*cellIndex, *desiredDirection, isPlayer)) { switch(*desiredDirection) { case ViewDirection::Up: *direction = *desiredDirection; break; case ViewDirection::Left: case ViewDirection::Right: if(offset->y <= 0 && (offset->y - speed) <= 0) { offset->y = 0; *direction = *desiredDirection; return; } break; default: break; } } if(offset->y >= 0 && checkCollision(*cellIndex, *direction, isPlayer)) { *isMoving = false; *desiredDirection = *direction; offset->y = 0; return; } offset->y += speed; if(offset->y > (m_tileSize.y / 2)) { *cellIndex = getMapIndex(*cellIndex, ViewDirection::Down); offset->y = -(m_tileSize.y / 2) + abs((m_tileSize.y / 2) - offset->y); } } }
unsigned int Pacman::getMapInfo(unsigned int cellIndex, ViewDirection direction) { return m_mapInfo[getMapIndex(cellIndex, direction)]; }
Pacman::ViewDirection Pacman::getRandomDirection(unsigned int cellIndex, unsigned int ignoreCell) { std::vector<ViewDirection> randomDirection; ViewDirection ignoreDirection = ViewDirection::Up; // Inicializamos su valor para que no se queje el compilador if(ignoreCell != m_mapNullCell) { if(ignoreCell == getMapIndex(cellIndex, ViewDirection::Right)) { ignoreDirection = ViewDirection::Right; } else if(ignoreCell == getMapIndex(cellIndex, ViewDirection::Left)) { ignoreDirection = ViewDirection::Left; } else if(ignoreCell == getMapIndex(cellIndex, ViewDirection::Down)) { ignoreDirection = ViewDirection::Down; } else { ignoreDirection = ViewDirection::Up; } if(getMapInfo(cellIndex, ViewDirection::Right) != CellType::Wall) { if(ignoreDirection != ViewDirection::Right) { randomDirection.push_back(ViewDirection::Right); } } if(getMapInfo(cellIndex, ViewDirection::Left) != CellType::Wall) { if(ignoreDirection != ViewDirection::Left) { randomDirection.push_back(ViewDirection::Left); } } if(getMapInfo(cellIndex, ViewDirection::Up) != CellType::Wall) { if(ignoreDirection != ViewDirection::Up) { randomDirection.push_back(ViewDirection::Up); } } if(getMapInfo(cellIndex, ViewDirection::Down) != CellType::Wall) { if(ignoreDirection != ViewDirection::Down) { randomDirection.push_back(ViewDirection::Down); } } } else { if(getMapInfo(cellIndex, ViewDirection::Right) != CellType::Wall) { randomDirection.push_back(ViewDirection::Right); } if(getMapInfo(cellIndex, ViewDirection::Left) != CellType::Wall) { randomDirection.push_back(ViewDirection::Left); } if(getMapInfo(cellIndex, ViewDirection::Up) != CellType::Wall) { randomDirection.push_back(ViewDirection::Up); } if(getMapInfo(cellIndex, ViewDirection::Down) != CellType::Wall) { randomDirection.push_back(ViewDirection::Down); } } if(randomDirection.empty()) { return ignoreDirection; } else { return randomDirection[rand() % randomDirection.size()]; } }
void Pacman::onTick() { // Cambiar dirección deseada de Pacman if(m_input->getKeyPress()->Up.value) { m_player.DesiredDirection = ViewDirection::Up; } else if(m_input->getKeyPress()->Right.value) { m_player.DesiredDirection = ViewDirection::Right; } else if(m_input->getKeyPress()->Left.value) { m_player.DesiredDirection = ViewDirection::Left; } else if(m_input->getKeyPress()->Down.value) { m_player.DesiredDirection = ViewDirection::Down; } if(m_readyTimer.getTicks() > 0) { if(m_readyTimer.getTicks() >= 2000) { m_readyTimer.stop(); m_gameTimer.start(); m_frameTimer.start(); } return; } if(m_pauseTimer.getTicks() > 0) { if(m_pauseTimer.getTicks() >= 500) { m_pauseTimer.stop(); m_gameTimer.resume(); m_frameTimer.resume(); if(m_ghostKillTimer.isPaused()) { m_ghostKillTimer.resume(); } if(m_player.IsDead) { resetGame(); } } return; } // Animar Pacman y Fantasmas (Cambio de Frames) if(m_frameTimer.getTicks() > 50) { if(m_player.Moving) { m_player.CurrentFrame++; if(m_player.CurrentFrame > 3) { m_player.CurrentFrame = 0; } } else { m_player.CurrentFrame = 1; } for(unsigned int x = 0; x < m_ghostCount; ++x) { m_ghost[x].CurrentFrame++; if(m_ghost[x].CurrentFrame > 1) { m_ghost[x].CurrentFrame = 0; } } m_frameTimer.start(); } // Mover Pacman moveEntity(&m_player.CurrentCellIndex, &m_player.PositionOffset, &m_player.Direction, &m_player.DesiredDirection, &m_player.Moving, m_player.MoveSpeed, true); bool ghostForceRefresh = false; sf::Vector2i findCoin = sf::Vector2i(m_player.CurrentCellIndex % m_mapSize.x, floor(m_player.CurrentCellIndex / m_mapSize.x)); // Comer bolas (Pacman) y actualizar mapa for(unsigned int x = 0; x < m_ballPosition.size(); ++x) { if(m_ballPosition[x] == findCoin) { mapSetCell(m_player.CurrentCellIndex, CellType::Nothing); m_ballPosition.erase(m_ballPosition.begin() + x); addScore(10); m_sound.setBuffer(m_ballSound); m_sound.play(); if(m_ballPosition.empty() && m_ballBigPosition.empty()) { resetGame(); return; } } } for(unsigned int x = 0; x < m_ballBigPosition.size(); ++x) { if(m_ballBigPosition[x] == findCoin) { mapSetCell(m_player.CurrentCellIndex, CellType::Nothing); m_ballBigPosition.erase(m_ballBigPosition.begin() + x); m_powerupKillCounter = 0; m_ghostKillTimer.start(); ghostForceRefresh = true; m_sound.setBuffer(m_powerupSound); m_sound.play(); for(unsigned int x = 0; x < m_ghostCount; ++x) { m_ghost[x].Invulnerable = false; } addScore(50); if(m_ballPosition.empty() && m_ballBigPosition.empty()) { resetGame(); return; } } } if(m_ghostKillTimer.getTicks() > 7000) { m_ghostKillTimer.stop(); for(unsigned int x = 0; x < m_ghostCount; ++x) { m_ghost[x].Invulnerable = false; m_ghost[x].LastStateChange = m_gameTimer.getTicks(); m_ghost[x].StateDuration = 3000; m_ghost[x].IsInChase = true; } ghostForceRefresh = true; } // IA Fantasmas for(unsigned int x = 0; x < m_ghostCount; ++x) { if(m_ghost[x].TimeToRelease >= m_gameTimer.getTicks()) { break; } unsigned int ignoreCell; if(m_ghost[x].Direction == ViewDirection::Left) { ignoreCell = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Right); } else if(m_ghost[x].Direction == ViewDirection::Right) { ignoreCell = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Left); } else if(m_ghost[x].Direction == ViewDirection::Up) { ignoreCell = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Down); } else { ignoreCell = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Up); } float ghostMoveSpeed = m_ghostKillTimer.isStarted() && (m_ghost[x].IsDead ? false : !m_ghost[x].Invulnerable) ? (m_ghost[x].MoveSpeed / 2) : (m_ghost[x].IsDead ? m_ghost[x].MoveSpeed * 1.5: m_ghost[x].MoveSpeed); if(m_ghost[x].CurrentCellIndex == m_ghost[x].HomeIndex) { m_ghost[x].IsDead = false; if(m_ghostKillTimer.isStarted()) { m_ghost[x].Invulnerable = true; } m_ghost[x].LastStateChange = m_gameTimer.getTicks(); m_ghost[x].StateDuration = 1000; m_ghost[x].IsInChase = true; } if(m_gameTimer.getTicks() >= (m_ghost[x].LastStateChange + m_ghost[x].StateDuration)) { if(!m_ghostKillTimer.isStarted()) { ghostForceRefresh = true; } m_ghost[x].LastStateChange = m_gameTimer.getTicks(); if(m_ghost[x].IsInChase) { m_ghost[x].IsInChase = false; m_ghost[x].StateDuration = (3000 + (rand() % 3000)); } else { m_ghost[x].IsInChase = true; m_ghost[x].StateDuration = (5000 + (rand() % 3000)); } } if(m_ghost[x].LastCellChecked != m_ghost[x].CurrentCellIndex || ghostForceRefresh) { if(m_ghost[x].IsDead) { m_ghost[x].DesiredDirection = getNextDirection(m_ghost[x].CurrentCellIndex, m_ghost[x].HomeIndex, ignoreCell); } else if(m_ghost[x].IsInChase && (!m_ghostKillTimer.isStarted() || m_ghost[x].Invulnerable)) { if(m_ghost[x].CurrentCellIndex != m_player.CurrentCellIndex) { m_ghost[x].DesiredDirection = getNextDirection(m_ghost[x].CurrentCellIndex, m_player.CurrentCellIndex, ignoreCell); } } else { unsigned int tempIndex; std::vector<unsigned int> possibleCells; if(m_ghost[x].Direction != ViewDirection::Left) { tempIndex = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Left); if(tempIndex != ignoreCell && m_mapInfo[tempIndex] != CellType::Wall) { possibleCells.push_back(tempIndex); } } if(m_ghost[x].Direction != ViewDirection::Right) { tempIndex = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Right); if(tempIndex != ignoreCell && m_mapInfo[tempIndex] != CellType::Wall) { possibleCells.push_back(tempIndex); } } if(m_ghost[x].Direction != ViewDirection::Up) { tempIndex = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Up); if(tempIndex != ignoreCell && m_mapInfo[tempIndex] != CellType::Wall) { possibleCells.push_back(tempIndex); } } if(m_ghost[x].Direction != ViewDirection::Down) { tempIndex = getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Down); if(tempIndex != ignoreCell && m_mapInfo[tempIndex] != CellType::Wall) { possibleCells.push_back(tempIndex); } } // Si hay caminos alternativos a seguir (Que no sea ni a donde se dirige ni la casilla anterior) o es un callejón sin salida... if(possibleCells.size() > 0 || getMapInfo(m_ghost[x].CurrentCellIndex, m_ghost[x].Direction) == CellType::Wall) { m_ghost[x].DesiredDirection = getRandomDirection(m_ghost[x].CurrentCellIndex, ignoreCell); } } m_ghost[x].LastCellChecked = m_ghost[x].CurrentCellIndex; } moveEntity(&m_ghost[x].CurrentCellIndex, &m_ghost[x].PositionOffset, &m_ghost[x].Direction, &m_ghost[x].DesiredDirection, &m_ghost[x].Moving, ghostMoveSpeed, false); if(!m_ghost[x].IsDead) { // Calcular colisión con Pacman if(m_ghost[x].CurrentCellIndex == m_player.CurrentCellIndex) { ghostCollide(x); } else if(getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Left) == m_player.CurrentCellIndex) { if((m_player.PositionOffset.x + (m_tileSize.x / 2)) - (m_ghost[x].PositionOffset.x + (m_tileSize.x / 2)) >= 0) { ghostCollide(x); } } else if(getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Right) == m_player.CurrentCellIndex) { if((m_ghost[x].PositionOffset.x + (m_tileSize.x / 2)) - (m_player.PositionOffset.x + (m_tileSize.x / 2)) >= 0) { ghostCollide(x); } } else if(getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Up) == m_player.CurrentCellIndex) { if((m_player.PositionOffset.y + (m_tileSize.y / 2)) - (m_ghost[x].PositionOffset.y + (m_tileSize.y / 2)) >= 0) { ghostCollide(x); } } else if(getMapIndex(m_ghost[x].CurrentCellIndex, ViewDirection::Down) == m_player.CurrentCellIndex) { if((m_ghost[x].PositionOffset.y + (m_tileSize.y / 2)) - (m_player.PositionOffset.y + (m_tileSize.y / 2)) >= 0) { ghostCollide(x); } } } } }
Pacman::ViewDirection Pacman::getNextDirection(unsigned int startIndex, unsigned int searchIndex, unsigned int ignoreCell) { std::list<Node> OpenNodeList; std::list<Node> ClosedNodeList; // Guardamos en la lista de Nodos Abiertos el Nodo correspondiente a startIndex OpenNodeList.push_back(Node()); OpenNodeList.back().Index = startIndex; OpenNodeList.back().Range = abs((startIndex % m_mapSize.x) - (searchIndex % m_mapSize.x)) + abs(floor(startIndex / m_mapSize.y) - floor(searchIndex / m_mapSize.y)); if(ignoreCell == m_mapNullCell) { // Guardamos en la lista de Nodos Cerrados el Nodo correspondiente a la casilla a ignorar ClosedNodeList.push_back(Node()); ClosedNodeList.back().Index = ignoreCell; } Node* preferentNode = &OpenNodeList.back(); // Hasta que no encuentre el destino o la lista de nodos abiertos se vacíe (no haya caminos posibles)... while (preferentNode->Index != searchIndex && !OpenNodeList.empty()) { // Si el nodo preferente está en la lista de nodos cerrados... for (auto closedNode : ClosedNodeList) { if (closedNode.Index == preferentNode->Index) { preferentNode = &OpenNodeList.back(); // Elegimos el primer nodo más preferente de la lista de nodos abiertos for (auto openNodeIt = OpenNodeList.begin(); openNodeIt != OpenNodeList.end(); ++openNodeIt) //for (auto openNode : OpenNodeList) { if ((preferentNode->Range + preferentNode->Cost) > (openNodeIt->Range + openNodeIt->Cost)) { preferentNode = &*openNodeIt; } } break; } } // Guardamos el nodo preferente en la lista de Nodos cerrados y lo eliminamos de la lista de nodos abiertos for (auto openNodeIt = OpenNodeList.begin(); openNodeIt != OpenNodeList.end(); ++openNodeIt) { if (openNodeIt->Index == preferentNode->Index) { ClosedNodeList.push_back(*preferentNode); // Actualizamos los punteros for (Node openNode : OpenNodeList) { if(openNode.ParentNode == preferentNode) { openNode.ParentNode = &ClosedNodeList.back(); } } preferentNode = &ClosedNodeList.back(); OpenNodeList.erase(openNodeIt); break; } } std::vector<unsigned int> nextIndex; // Añadimos a nextIndex CADA UNA de las 4 direcciones si es posible su tránsito if (!checkCollision(preferentNode->Index, ViewDirection::Left, false)) { nextIndex.push_back(getMapIndex(preferentNode->Index, ViewDirection::Left)); } if (!checkCollision(preferentNode->Index, ViewDirection::Right, false)) { nextIndex.push_back(getMapIndex(preferentNode->Index, ViewDirection::Right)); } if (!checkCollision(preferentNode->Index, ViewDirection::Up, false)) { nextIndex.push_back(getMapIndex(preferentNode->Index, ViewDirection::Up)); } if (!checkCollision(preferentNode->Index, ViewDirection::Down, false)) { nextIndex.push_back(getMapIndex(preferentNode->Index, ViewDirection::Down)); } if (!nextIndex.empty()) { Node* previousNode = preferentNode; for (unsigned int Index : nextIndex) { bool isValid = true; // Miramos si existe en la lista de nodos abiertos for (Node openNode : OpenNodeList) { if (openNode.Index == Index) { isValid = false; break; } } if (!isValid) { continue; } // Miramos si existe en la lista de nodos cerrados for (Node closedNode : ClosedNodeList) { if (closedNode.Index == Index) { isValid = false; break; } } if (!isValid) { continue; } // Si NO existe en ninguna de las listas anteriores, añadimos el nodo a la lista de nodos abiertos OpenNodeList.push_back(Node()); OpenNodeList.back().Index = Index; OpenNodeList.back().ParentNode = previousNode; OpenNodeList.back().Cost = (previousNode->Cost + 1); OpenNodeList.back().Range = abs((int)(Index % m_mapSize.x) - (int)(searchIndex % m_mapSize.x)) + abs(floor(Index / m_mapSize.y) - floor(searchIndex / m_mapSize.y)); // ... y actualizamos preferentNode si así fuera el caso if ((preferentNode->Range + preferentNode->Cost) > (OpenNodeList.back().Range + OpenNodeList.back().Cost)) { preferentNode = &OpenNodeList.back(); } } } } // Si el ultimo nodo preferente encontró el destino... if (preferentNode->Index == searchIndex) { // Localizamos el nodo con la siguiente casilla a desplazarse desde el nodo destino while (preferentNode->ParentNode->Index != startIndex) { preferentNode = preferentNode->ParentNode; } // Nos movemos en una dirección segun el nodo posterior al nodo origen if (preferentNode->Index == (startIndex - 1)) { return ViewDirection::Left; } else if (preferentNode->Index == (startIndex + 1)) { return ViewDirection::Right; } else if (preferentNode->Index == (startIndex + m_mapSize.x)) { return ViewDirection::Down; } else { return ViewDirection::Up; } } else { return getRandomDirection(startIndex, ignoreCell); } }
void *allocBlock(terryManageHead *head , int size) { assert(head != NULL && size > 0); if(size < 0 || size > MAX_SIZE) { printf("WARNING : can not allocate block of size %d\n" , size); return NULL; } int realSize = size + BLOCK_INFO_SIZE; // printf("alloc a block of size %d and real alloc size is %d\n" , size , realSize); int cacheIndex = head->cache; terryMemPool *memPool = NULL; //if we can use cache do not need to calculate which manage we should use... if(cacheIndex != -1) { struct mapInfo *mapPtr = head->map; if(0 == cacheIndex && realSize >= FRONT_ALIGN_SIZE(mapPtr[cacheIndex].size) && realSize <= mapPtr[cacheIndex].size) memPool = mapPtr[cacheIndex].addr; else if(realSize >= FRONT_ALIGN_SIZE(mapPtr[cacheIndex].size) && realSize <= mapPtr[cacheIndex].size) memPool = mapPtr[cacheIndex].addr; } if(NULL == memPool) { int mapIndex = getMapIndex(head , realSize); if(-1 == mapIndex) { memPool = createManageStrcut(head , DO_ALIGN_SIZE(realSize)); if(NULL == memPool) return NULL; } else { memPool = (terryMemPool *)((head->map)[mapIndex].addr); head->cache = mapIndex; } } //if there is no free block , expand this memory pool then allocate block.... if(0 == memPool->allFreeNumber) expandMemPool(memPool); terryBlockManage *blockManage = memPool->cache; if(blockManage == NULL || 0 == blockManage->freeNumber) { blockManage = memPool->allocList; while(blockManage->freeNumber == 0) blockManage = blockManage->next; } //delete this block from free list... terryBlockInfo *blockInfoPtr = blockManage->free; blockManage->free = (blockInfoPtr->ptr).next; blockManage->freeNumber --; blockManage->inuseNumber ++; /* //add this block to using list... if(NULL == memPool->inuse) { memPool->inuse = blockInfoPtr; blockInfoPtr->next = blockInfoPtr->prev = NULL; } else { memPool->inuse->prev = blockInfoPtr; blockInfoPtr->next = memPool->inuse; memPool->inuse = blockInfoPtr; } */ memPool->allFreeNumber --; memPool->allInuseNumber ++; (blockInfoPtr->ptr).magic = head->magic; blockInfoPtr->manage = blockManage; return (void *)((char *)blockInfoPtr + BLOCK_INFO_SIZE); }