gep::StdAllocator& gep::StdAllocator::globalInstance() #endif { // double locking pattern // this is NOT an anti pattern if you know what the pitfalls are if(s_globalInstance == nullptr) { ScopedLock<Mutex> lock(s_creationMutex); if(s_globalInstance == nullptr) { static char allocatorInstanceMemory[sizeof(StdAllocator)]; StdAllocator* stdAllocator = new(allocatorInstanceMemory) StdAllocator(); #ifdef TRACK_MEMORY_LEAKS static char leakDetectorMemory[sizeof(LeakDetectorAllocatorStatistics)]; s_globalInstance = new(leakDetectorMemory) LeakDetectorAllocatorStatistics(stdAllocator); #else s_globalInstance = stdAllocator; #endif auto result = gep::atexit(&destroyInstance); GEP_ASSERT(result == SUCCESS, "registering exit function failed"); } } GEP_ASSERT(s_globalInstance != nullptr); return (StdAllocator&)(*s_globalInstance); }
void* scriptAllocator(void* userData, void* ptr, size_t originalSize, size_t newSize) { GEP_ASSERT(userData != nullptr, "Lua allocation called with invalid user data!"); auto& allocator = *reinterpret_cast<IAllocator*>(userData); if (newSize == 0) // We are supposed to free the pointer. { allocator.freeMemory(ptr); return nullptr; } if (ptr == nullptr) // we are supposed to allocate new memory. { return allocator.allocateMemory(newSize); } auto newPtr = allocator.allocateMemory(newSize); GEP_ASSERT(newPtr, "Out of memory."); auto size = GEP_MIN(originalSize, newSize); GEP_ASSERT(size <= newSize); GEP_ASSERT(size <= originalSize); memcpy(newPtr, ptr, size); allocator.freeMemory(ptr); return newPtr; }
void* gep::ElectricFenceAllocator::allocateMemory(size_t size) { ScopedLock<Mutex> lock(m_mutex); auto numPages = (size - 1) / s_pageSize + 2; auto sizeNeeded = numPages * s_pageSize; auto address = static_cast<char*>(VirtualAlloc( nullptr, // optional starting address sizeNeeded, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE )); if (address == nullptr) { wchar_t buffer[2048]; DWORD errorCode = GetLastError(); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, nullptr, errorCode, 0, (LPTSTR)buffer, 2048, nullptr); GEP_ASSERT(false, "Error allocating memory!"); } auto padding = s_pageSize - (size % s_pageSize); if (size % s_pageSize == 0) { padding = 0; } else { padding &= ~0x7; } GEP_ASSERT(padding % 8 == 0); auto result = address + padding; DWORD unused; VirtualProtect( address + sizeNeeded - s_pageSize, s_pageSize, PAGE_NOACCESS, &unused ); *result = 0; *(address + sizeNeeded - s_pageSize - 1) = 0; AllocationInfo allocationInfo = { address, sizeNeeded }; m_memLookup[result] = allocationInfo; return result; }
gep::CollisionMesh* gep::CollisionMeshFileLoader::loadResource(CollisionMesh* pInPlace) { CollisionMesh* result = nullptr; bool isInPlace = true; if (pInPlace == nullptr) { result = new CollisionMesh(); isInPlace = false; } auto* havokLoader = g_resourceManager.getHavokResourceLoader(); auto* container = havokLoader->load(m_path.c_str()); GEP_ASSERT(container != nullptr, "Could not load asset! %s", m_path.c_str()); if (container) { auto* physicsData = reinterpret_cast<hkpPhysicsData*>(container->findObjectByType(hkpPhysicsDataClass.getName())); GEP_ASSERT(physicsData != nullptr, "Unable to load physics data!"); if (physicsData) { const auto& physicsSystems = physicsData->getPhysicsSystems(); GEP_ASSERT(physicsSystems.getSize() == 1, "Wrong number of physics systems!"); auto body = physicsSystems[0]->getRigidBodies()[0]; auto hkShape = body->getCollidable()->getShape(); auto shape = conversion::hk::from(const_cast<hkpShape*>(hkShape)); auto type = shape->getShapeType(); if ( type == hkcdShapeType::BV_COMPRESSED_MESH || type == hkcdShapeType::CONVEX_VERTICES ) { hkTransform transform = body->getTransform(); transform.getRotation().setAxisAngle(hkVector4(0.0f, 0.0f, 1.0f), GetPi<float>::value()); auto hkTransformShape = new hkpTransformShape(hkShape, transform); hkTransformShape->addReference(); shape = GEP_NEW(m_pAllocator, HavokShape_Transform)(hkTransformShape); //auto meshShape = static_cast<HavokMeshShape*>(shape); //Transform* tempTrans = new Transform(); //conversion::hk::from(transform, *tempTrans); // //// Since havok content tools are buggy (?) and no custom transformation can be applied, //// we have to convert into our engine's space by hand. //// TODO: Ensure, that this transformation is correct in every case //tempTrans->setRotation(tempTrans->getRotation() * Quaternion(vec3(1,0,0),180)); //meshShape->setTransform(tempTrans); } result->setShape(shape); } } return result; }
void gep::HavokWorld::setCollisionFilter(ICollisionFilter* pFilter) { auto pHkFilterWrapper = static_cast<HavokCollisionFilterWrapper*>(pFilter); GEP_ASSERT(dynamic_cast<HavokCollisionFilterWrapper*>(pFilter), "Invalid type of collision filter!"); auto pHkFilter = pHkFilterWrapper->getHkCollisionFilter(); GEP_ASSERT(pHkFilter, "Filter wrapper has an invalid hk object!"); m_pWorld->setCollisionFilter(pHkFilter); }
void gep::HavokRigidBodySyncAction::applyAction(const hkStepInfo& stepInfo) { const auto* rb = getRigidBody(); GEP_ASSERT(rb); hkUlong userData = rb->getUserData(); GEP_ASSERT(userData, "It seems you did not initialize your rigid body!"); reinterpret_cast<HavokRigidBody*>(userData)->triggerSimulationCallbacks(); }
void gep::CollisionMesh::setLoader(IResourceLoader* loader) { GEP_ASSERT(loader != nullptr); #ifdef _DEBUG m_pCollisionMeshFileLoader = dynamic_cast<CollisionMeshFileLoader*>(loader); GEP_ASSERT(m_pCollisionMeshFileLoader != nullptr); #else m_pCollisionMeshFileLoader = static_cast<CollisionMeshFileLoader*>(loader); #endif }
void gep::ElectricFenceAllocator::freeMemory(void* mem) { if (mem == nullptr) { return; } ScopedLock<Mutex> lock(m_mutex); AllocationInfo allocationInfo; Result exists = m_memLookup.tryGet(mem, allocationInfo); GEP_ASSERT(exists == SUCCESS, "Double or invalid free!", mem); m_memLookup.remove(mem); DWORD unused; VirtualProtect( allocationInfo.ptr, allocationInfo.size, PAGE_NOACCESS, &unused ); m_queue.append(allocationInfo); if (m_queue.count() > s_maxFreeQueueElements) { auto info = m_queue.take(); VirtualFree(info.ptr, info.size, MEM_DECOMMIT | MEM_RELEASE); } }
gep::AnimationFactory::AnimationFactory(IAllocator* allocator): m_pAllocator(allocator), m_Skeletons(), m_AnimationControls() { GEP_ASSERT(m_pAllocator, "Allocator cannot be nullptr!"); }
void gep::HavokCharacterRigidBody::setLinearVelocity(const vec3& newVelocity, float deltaTime) { GEP_ASSERT(deltaTime > 0.0f || !epsilonCompare(deltaTime, 0.0f), "The delta time must be greater than zero!"); hkVector4 linearVelocity; conversion::hk::to(newVelocity, linearVelocity); m_pHkCharacterRigidBody->setLinearVelocity(linearVelocity, deltaTime); }
void gep::StdAllocator::destroyInstance() { ScopedLock<Mutex> lock(s_creationMutex); if(s_globalInstance != nullptr) { #ifdef TRACK_MEMORY_LEAKS auto temp = (LeakDetectorAllocatorStatistics*)s_globalInstance; auto wrapped = (StdAllocator*)temp->getWrapped(); { // Will empty the file if it already existed. std::ofstream leakfile("memoryLeaks.log", std::ios_base::trunc); if(temp->hasLeaks()) { temp->findLeaks(leakfile); GEP_ASSERT(false, "you have memory leaks, check 'memoryLeaks.log' for details"); } else { leakfile << "No leaks detected." << std::endl; } } temp->~LeakDetectorAllocatorStatistics(); wrapped->~StdAllocator(); #else auto temp = s_globalInstance; s_globalInstance = nullptr; temp->~StdAllocator(); #endif } }
gep::IRigidBody* gep::HavokPhysicsFactory::createRigidBody(const RigidBodyCInfo& cinfo) const { GEP_ASSERT(m_pAllocator, "Allocator cannot be nullptr!"); HavokRigidBody* rb = GEP_NEW(m_pAllocator, HavokRigidBody)(cinfo); rb->initialize(); return rb; }
gep::ICharacterRigidBody* gep::HavokPhysicsFactory::createCharacterRigidBody(const CharacterRigidBodyCInfo& cinfo) const { GEP_ASSERT(m_pAllocator, "Allocator cannot be nullptr!"); auto pCharacterRigidBody = GEP_NEW(m_pAllocator, HavokCharacterRigidBody)(cinfo); pCharacterRigidBody->initialize(); return pCharacterRigidBody; }
gpp::StateMachine* gpp::StateMachineFactory::create(const std::string& name) { GEP_ASSERT(m_stateMachines.exists(name) == false, "A top-level state machine of the given name already exists!", name); auto pFsm = GEP_NEW(m_pAllocator, StateMachine)(name, m_pAllocator); m_stateMachines[name] = pFsm; return pFsm; }
void gep::DirectoryWatcher::enumerateChanges(std::function<void(const char* filename, Action::Enum action)> func) { OVERLAPPED* lpOverlapped; DWORD numberOfBytes; ULONG_PTR completionKey; while( GetQueuedCompletionStatus(m_completionPort, &numberOfBytes, &completionKey, &lpOverlapped, 0) != 0) { //Copy the buffer GEP_ASSERT(numberOfBytes > 0); void* buffer = alloca(numberOfBytes); memcpy(buffer, m_buffer, numberOfBytes); //Reissue the read request doRead(); //Progress the messages auto info = (const FILE_NOTIFY_INFORMATION*)buffer; while(true) { int bytesNeeded = WideCharToMultiByte(CP_UTF8, 0, info->FileName, info->FileNameLength/2, nullptr, 0, nullptr, nullptr); if(bytesNeeded > 0) { char* dir = (char*)alloca(bytesNeeded+1); WideCharToMultiByte(CP_UTF8, 0, info->FileName, info->FileNameLength/2, dir, bytesNeeded, nullptr, nullptr); dir[bytesNeeded] = '\0'; func(dir, (Action::Enum)info->Action); } if(info->NextEntryOffset == 0) break; else info = (const FILE_NOTIFY_INFORMATION*)(((char*)info) + info->NextEntryOffset); } } }
gep::CollisionMeshFileLoader::CollisionMeshFileLoader(IAllocator* pAllocator, const char* path) : m_pAllocator(pAllocator), m_path(path) { GEP_ASSERT(m_pAllocator, "CollisionMeshFileLoader needs an allocator!"); }
std::string gep::ScriptingManager::constructFileName(const std::string& filename, LoadOptions::Enum loadOptions) { if (loadOptions == LoadOptions::None) { return filename; } std::stringstream completeName; switch (loadOptions) { case LoadOptions::PathIsAbsolute: completeName << filename; break; case LoadOptions::PathIsRelative: completeName << m_scriptsRoot << filename; break; case LoadOptions::IsImportantScript: completeName << m_importantScriptsRoot << filename; break; default: GEP_ASSERT(false, "Invalid script loading option!", loadOptions); break; } return completeName.str(); }
gep::IResource* gep::FmodSoundLoader::loadResource(IResource* pInst) { if(!m_isIdResolved) { FmodSoundSystem* pSystem = static_cast<FmodSoundSystem*>(g_globalManager.getSoundSystem()); auto result = pSystem->getFmodHandle().lookupEventID(m_path.c_str(), &m_id); if(result != FMOD_OK) { std::ostringstream msg; msg << "Failed to find event '" << m_path << "' with error: " << FMOD_ErrorString(result); throw LoadingError(msg.str()); } m_isIdResolved = true; } FmodSound* pInstance = nullptr; if(pInst != nullptr) { pInstance = dynamic_cast<FmodSound*>(pInst); GEP_ASSERT(pInstance != nullptr, "passed resource is not a FmodSound"); } if(pInstance == nullptr) { pInstance = new FmodSound(); } pInstance->unload(); pInstance->load(m_id); return pInstance; }
void gep::ScriptingManager::registerScript(const std::string& filename, LoadOptions::Enum loadOptions) { GEP_ASSERT(m_state == State::AcceptingScriptRegistration, "You are not allowed to register a script at this point! " "Check 'filename' below to see which script was supposed to be registered", filename); m_scriptsToLoad.append(constructFileName(filename, loadOptions)); }
void gep::HavokWorld::addEntity(IPhysicsEntity* entity) { //TODO: can only add rigid bodies at the moment. auto* actualEntity = static_cast<HavokRigidBody*>(entity); GEP_ASSERT(dynamic_cast<HavokRigidBody*>(entity) != nullptr, "Attempted to add wrong kind of entity. (only rigid bodies are supported at the moment)"); addEntity(actualEntity->getHkpRigidBody()); m_entities.append(entity); }
void gep::HavokWorld::removeCharacter(ICharacterRigidBody* character) { GEP_ASSERT(character != nullptr); size_t index; for (index = 0; index < m_characters.length(); ++index) { auto& characterPtr = m_characters[index]; if (characterPtr.get() == character) { break; } } GEP_ASSERT(index < m_characters.length(), "Attempt to remove character from world that does not exist there", character, index, m_characters.length()); m_characters.removeAtIndex(index); removeEntity(character->getRigidBody()); }
void gpp::CharacterComponent::createCharacterRigidBody(gep::CharacterRigidBodyCInfo cinfo) { GEP_ASSERT(m_pWorld != nullptr, "The Physics World for of the CharacterComponent on %s has not been set.", m_pParentGameObject->getName().c_str()); GEP_ASSERT(m_pParentGameObject->getComponent<PhysicsComponent>() == nullptr, "The GameObject already has physical behavior. Currently no character can be added. TODO: FIX ME!"); auto physicsComponent = m_pParentGameObject->createComponent<PhysicsComponent>(); auto* physicsSystem = g_globalManager.getPhysicsSystem(); auto* physicsFactory = physicsSystem->getPhysicsFactory(); m_pCharacterRigidBody = physicsFactory->createCharacterRigidBody(cinfo); m_pCharacterRigidBody->initialize(); //Note: The world is taking ownership of the rigid body here. m_pWorld->addCharacter(m_pCharacterRigidBody.get()); physicsComponent->setRigidBody(m_pCharacterRigidBody->getRigidBody()); }
float gep::UpdateFramework::calcElapsedTimeAverage(size_t numFrames) const { GEP_ASSERT(numFrames <= m_FrameTimesPtr.length(), "numFrames is too large!"); GEP_ASSERT(numFrames > 0, "numFrames must not be 0!"); float averageTime = 0.0f; for (size_t tempFrameIdx = m_frameIdx, i = 0; i < numFrames; ++i) { float frameTime = m_FrameTimesPtr[tempFrameIdx]; averageTime += frameTime; // Count the index down and wrap around if needed tempFrameIdx = (tempFrameIdx == 0 ? m_FrameTimesPtr.length() - 1 : tempFrameIdx - 1); } return averageTime / float(numFrames); }
gep::HavokCollidable::HavokCollidable(hkpCollidable* collidable) : m_pHkCollidable(collidable), m_pShape(nullptr), m_pEntity(nullptr) { GEP_ASSERT(collidable, "The input 'collidable' is not supposed to be null!"); m_pEntity = static_cast<IPhysicsEntity*>(collidable->getOwner()); m_pShape = conversion::hk::fromHkShape( const_cast<hkpShape*>(collidable->getShape()) ); }
gpp::GameObject* gpp::GameObjectManager::createGameObject(const std::string& guid) { //GEP_ASSERT(m_state == State::PreInitialization, "You are not allowed to create game objects after the initialization process."); GameObject* pGameObject = nullptr; GEP_ASSERT(!m_gameObjects.tryGet(guid, pGameObject), "GameObject %s already exists!", guid.c_str()); pGameObject = new GameObject(); pGameObject->m_name = guid; m_gameObjects[guid] = pGameObject; return pGameObject; }
void gep::TaskQueue::scheduleForExecution(TaskGroup* pGroup) { GEP_ASSERT(pGroup->m_tasks.length() > 0, "there are no tasks in the group"); pGroup->m_isExecuting = true; pGroup->m_numRemainingTasks = (uint32)pGroup->m_tasks.length(); ScopedLock<Mutex> lock(m_schedulingMutex); m_remainingTaskGroups.append(pGroup); if(m_currentTaskGroup == nullptr) { scheduleNextGroup(); } }
void gpp::CameraComponent::setState(State::Enum state) { GEP_ASSERT(state != State::Initial, "Cannot set the initial state!"); m_state = state; switch (state) { case State::Active: g_globalManager.getCameraManager()->setActiveCamera(m_pCamera); g_gameObjectManager.setCurrentCameraObject(m_pParentGameObject); break; case State::Inactive: GEP_ASSERT(false, "Cannot directly set a camera to be Inactive." "If you set any other camera to Active, all other cameras will " "automatically be set to be Inactive."); break; default: GEP_ASSERT(false, "Invalid state input!", state); break; } }
gep::CallbackId gep::HavokRigidBody::registerSimulationCallback(PositionChangedCallback callback) { GEP_ASSERT(callback); for(size_t i=0; i < m_positionChangedCallbacks.length(); ++i) { if(!m_positionChangedCallbacks[i]) { m_positionChangedCallbacks[i] = callback; return CallbackId(i); } } m_positionChangedCallbacks.append(callback); return gep::CallbackId(m_positionChangedCallbacks.length() - 1); }
void gep::LeakDetector::trackFree(void* mem) { ScopedLock<Mutex> lock(m_mutex); AllocationInfo* info = nullptr; if(m_allocationMap.tryGet(mem, info)) { GEP_DELETE(m_allocator, info); m_allocationMap.remove(mem); } else { GEP_ASSERT(false, "double or invalid free"); } }
void gep::HavokWorld::removeEntity(IPhysicsEntity* entity) { GEP_ASSERT(entity != nullptr, "Attempt to remove nullptr."); // TODO Can only remove rigid bodies at the moment. auto* actualEntity = dynamic_cast<HavokRigidBody*>(entity); GEP_ASSERT(actualEntity != nullptr, "Attempt to remove wrong kind of entity. (only rigid bodies are supported at the moment)"); size_t index; for (index = 0; index < m_entities.length(); ++index) { auto& entityPtr = m_entities[index]; if (entityPtr.get() == actualEntity) { break; } } GEP_ASSERT(index < m_entities.length(), "Attempt to remove character from world that does not exist there", actualEntity, index, m_entities.length()); m_entities.removeAtIndex(index); // Remove the actual havok entity removeEntity(actualEntity->getHkpRigidBody()); }