//----------------------------------------------------------------------------------------------- Texture::Texture( const std::string& imageFilePath ) : m_openglTextureID( 0 ) , m_size( 0, 0 ) { int numComponents = 0; // Filled in for us to indicate how many color/alpha components the image had (e.g. 3=RGB, 4=RGBA) int numComponentsRequested = 0; // don't care; we support 3 (RGB) or 4 (RGBA) unsigned char* imageData = stbi_load( imageFilePath.c_str(), &m_size.x, &m_size.y, &numComponents, numComponentsRequested ); if( imageData == nullptr ) { RECOVERABLE_ERROR( "Failed to load texture " + imageFilePath ); return; } // Enable texturing OpenGLRenderer::EnableTexture2D(); // Tell OpenGL that our pixel data is single-byte aligned OpenGLRenderer::PixelStore(); // Ask OpenGL for an unused texName (ID number) to use for this texture OpenGLRenderer::GenerateTextures( &m_openglTextureID ); // Tell OpenGL to bind (set) this as the currently active texture OpenGLRenderer::BindTexture2D( m_openglTextureID ); // Set texture clamp vs. wrap (repeat) OpenGLRenderer::SetTexture2DWrapS( REPEAT ); // GL_CLAMP or GL_REPEAT OpenGLRenderer::SetTexture2DWrapT( REPEAT ); // GL_CLAMP or GL_REPEAT // Set magnification (texel > pixel) and minification (texel < pixel) filters OpenGLRenderer::SetTexture2DMagnificationFilter( LINEAR ); // one of: GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR OpenGLRenderer::SetTexture2DMinificationFilter( LINEAR_MIPMAP_LINEAR ); // one of: GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR //OpenGLRenderer::SetTexture2DMaxLevel( 5 ); pixelDataFormat bufferFormat = RGBA; // the format our source pixel data is currently in; any of: GL_RGB, GL_RGBA, GL_LUMINANCE, GL_LUMINANCE_ALPHA, ... if( numComponents == 1 ) bufferFormat = LUMINANCE; else if( numComponents == 3 ) bufferFormat = RGB; pixelDataFormat internalFormat = bufferFormat; // the format we want the texture to me on the card; allows us to translate into a different texture format as we upload to OpenGL OpenGLRenderer::SetTexture2DImage( // Upload this pixel data to our new OpenGL texture 0, // Which mipmap level to use as the "root" (0 = the highest-quality, full-res image), if mipmaps are enabled internalFormat, // Type of texel format we want OpenGL to use for this texture internally on the video card m_size.x, // Texel-width of image; for maximum compatibility, use 2^N + 2^B, where N is some integer in the range [3,10], and B is the border thickness [0,1] m_size.y, // Texel-height of image; for maximum compatibility, use 2^M + 2^B, where M is some integer in the range [3,10], and B is the border thickness [0,1] 0, // Border size, in texels (must be 0 or 1) bufferFormat, // Pixel format describing the composition of the pixel data in buffer imageData ); // Location of the actual pixel data bytes/buffer OpenGLRenderer::GenerateMipmapHint(); OpenGLRenderer::GenerateMipmapTexture2D(); stbi_image_free( imageData ); s_textureRegistry[ imageFilePath ] = this; }
///===================================================== /// ///===================================================== bool NetworkMessageDefinition::ValidateID(MessageID id) { if (s_definitionRegistry.find(id) == s_definitionRegistry.cend()) { RECOVERABLE_ERROR("Invalid Message ID: " + std::to_string(id)); return false; } return true; }
///===================================================== /// //assumes NPC has RetreatToAllyBehavior ///===================================================== RememberedActor* AISystem::FindAllyToRetreatTo(NPC& retreatingNPC, bool retreatToBuffers, bool findClosest) const{ RetreatToAllyBehavior* retreatToAllyBehavior = (RetreatToAllyBehavior*)retreatingNPC.FindBehaviorByName("RetreatToAlly"); retreatToAllyBehavior->m_avoidEnemies = !retreatToBuffers && findClosest; if (retreatToAllyBehavior == nullptr){ RECOVERABLE_ERROR(); return nullptr; } RememberedActor* prevTargetAlly = retreatingNPC.m_targetAlly; RememberedActor* allyToRetreatTo = nullptr; int bestDistanceSquared = findClosest ? INT_MAX : -1; for (std::vector<Actor*>::const_iterator actorIter = retreatingNPC.m_visibleActors.cbegin(); actorIter != retreatingNPC.m_visibleActors.cend(); ++actorIter){ Actor* actor = *actorIter; FATAL_ASSERT(actor != nullptr); RECOVERABLE_ASSERT(actor != &retreatingNPC); if (retreatToBuffers){ if (actor->IsPlayer()) continue; NPC* npc = (NPC*)actor; AOEBuffBehavior* buffBehavior = (AOEBuffBehavior*)npc->FindBehaviorByName("AOEBuff"); if (buffBehavior == nullptr || buffBehavior->m_hasBeenUsed) continue; } if (retreatingNPC.GetFactionStatus(actor->m_faction->m_factionID, actor->m_ID) > 0){ //is ally int distanceSquared = CalcDistanceSquared(actor->m_position, retreatingNPC.m_position); if ((findClosest && distanceSquared < bestDistanceSquared) || (!findClosest && distanceSquared > bestDistanceSquared)){ RememberedActor remActor = RememberedActor(*actor); retreatingNPC.m_targetAlly = &remActor; IntVec2 possibleMoveLocation = retreatToAllyBehavior->CalcNextPathStep(); if ((possibleMoveLocation.x != -1) && (retreatToBuffers || !findClosest || CalcDistanceSquared(possibleMoveLocation, retreatingNPC.m_targetEnemy->m_position) > CalcDistanceSquared(retreatingNPC.m_position, retreatingNPC.m_targetEnemy->m_position))){ //only retreat if the first step would take us further away from the enemy in the case of findFurthest bestDistanceSquared = distanceSquared; if (allyToRetreatTo == nullptr) allyToRetreatTo = new RememberedActor(remActor); else *allyToRetreatTo = remActor; } } } } if (allyToRetreatTo == nullptr){ //we didn't find anyone to retreat to, so let's see if we remember any nearby allies for (std::map<int, RememberedActor>::const_iterator actorIter = retreatingNPC.m_previouslyVisibleActors.cbegin(); actorIter != retreatingNPC.m_previouslyVisibleActors.cend(); ++actorIter){ const RememberedActor& rememberedActorData = actorIter->second; if (Entity::s_turnCount - 5 > rememberedActorData.m_turn) continue; if (retreatToBuffers && !rememberedActorData.m_canAOEBuff){ continue; } if (retreatingNPC.GetFactionStatus(rememberedActorData.m_factionID, actorIter->first) > 0){ //is ally int distanceSquared = CalcDistanceSquared(rememberedActorData.m_position, retreatingNPC.m_position); if ((findClosest && distanceSquared < bestDistanceSquared) || (!findClosest && distanceSquared > bestDistanceSquared)){ retreatingNPC.m_targetAlly = (RememberedActor*)&rememberedActorData; IntVec2 possibleMoveLocation = retreatToAllyBehavior->CalcNextPathStep(); if ((possibleMoveLocation.x != -1) && (retreatToBuffers || !findClosest || CalcDistanceSquared(possibleMoveLocation, retreatingNPC.m_targetEnemy->m_position) > CalcDistanceSquared(retreatingNPC.m_position, retreatingNPC.m_targetEnemy->m_position))){ //only retreat if the first step would take us further away from the enemy in the case of findFurthest bestDistanceSquared = distanceSquared; if (allyToRetreatTo == nullptr) allyToRetreatTo = new RememberedActor(rememberedActorData); else *allyToRetreatTo = rememberedActorData; } } } } } retreatingNPC.m_targetAlly = prevTargetAlly; return allyToRetreatTo; }
///===================================================== /// ///===================================================== void AISystem::PlanNextMove(const Player& player){ int numChases = 0; int numAttacks = 0; int numTargetingThePlayer = 0; float attackerBravery = 0.0f; bool anNPCCanNotRetreat = false; for (Actors::const_iterator actorIter = Actor::s_actorsOnMap.cbegin(); actorIter != Actor::s_actorsOnMap.cend(); ++actorIter){ Actor* actor = actorIter->second; if (actor->m_isDead || actor->GetFactionStatus(player.m_faction->m_factionID, player.m_ID) > 0) continue; if (actor->IsPlayer()){ break; } NPC* npc = (NPC*)actor; if (npc->m_targetEnemy != nullptr && npc->m_targetEnemy->m_isPlayer && npc->m_targetEnemy->m_turn == Entity::s_turnCount){ ++numTargetingThePlayer; if (npc->m_ignoreRetreatStrategy == true) anNPCCanNotRetreat = true; if (npc->m_plannedBehavior->m_name == "Chase"){ ++numChases; if (npc->m_targetEnemy->m_isFromYellForHelp) attackerBravery += npc->m_bravery * 0.5f; //half bravery from NPCs that weren't planning on being aggressive else attackerBravery += npc->m_bravery; } else if (npc->m_plannedBehavior->m_name == "MeleeAttack"){ ++numAttacks; attackerBravery += npc->m_bravery; } else if (!npc->m_targetEnemy->m_isFromYellForHelp){ attackerBravery += npc->m_bravery * 0.5f; //half bravery from NPCs that weren't planning on being aggressive } } } switch (m_currentStrategy) { case AISystem::Default: if (numAttacks != 0 || attackerBravery > 2.0f || anNPCCanNotRetreat || NPC::s_mostRecentYellForHelpDueToPlayerTurn != -1){ m_currentStrategy = Attack; AttackStrategy(player); break; } else{ m_currentStrategy = Retreat; RetreatStrategy(player); break; } break; case AISystem::Attack: if (numAttacks == 0 && attackerBravery <= 1.0f && !anNPCCanNotRetreat && (NPC::s_mostRecentYellForHelpDueToPlayerTurn + 10 < Entity::s_turnCount)){ //reset any Retreat Strategy Ignoring from previous set of retreats for (Actors::const_iterator actorIter = Actor::s_actorsOnMap.cbegin(); actorIter != Actor::s_actorsOnMap.cend(); ++actorIter){ Actor* actor = actorIter->second; if (!actor->IsPlayer()){ NPC* npc = (NPC*)actor; npc->m_ignoreRetreatStrategy = false; RetreatBehavior* retreatBehavior = (RetreatBehavior*)npc->FindBehaviorByName("Retreat"); if (retreatBehavior != nullptr){ retreatBehavior->m_retreatCount = 0; } } } m_currentStrategy = Retreat; RetreatStrategy(player); break; } AttackStrategy(player); break; case AISystem::Retreat: if (numAttacks != 0 || attackerBravery > 2.0f || anNPCCanNotRetreat || (NPC::s_mostRecentYellForHelpDueToPlayerTurn + 10 >= Entity::s_turnCount)){ m_currentStrategy = Attack; AttackStrategy(player); break; } RetreatStrategy(player); break; case AISystem::Defend: DefendStrategy(); break; default: RECOVERABLE_ERROR(); break; } }
///===================================================== /// ///===================================================== void* SignpostMemoryManager::Alloc(size_t numBytes, bool doTracking, const char* file, unsigned int line) { if (numBytes <= 0) { RECOVERABLE_ERROR("Invalid allocation of " + std::to_string(numBytes) + " bytes."); return nullptr; } numBytes = (numBytes + 3) & ~3; //byte alignment ValidateSignposts(); m_criticalSection.Enter(); ++m_totalAllocationsRequested; ++m_allocationsThisFrame; size_t numBytesWithSignpost = numBytes + sizeof(Signpost); for (Signpost* signpost = firstSignpost; signpost != nullptr;) { if (signpost->m_isFree == false || (signpost->m_size < numBytesWithSignpost)) { signpost = signpost->m_next; continue; } Signpost* newSignpost = (Signpost*)((size_t)signpost + numBytesWithSignpost); FATAL_ASSERT((size_t)newSignpost <= (size_t)m_buffer + m_size - sizeof(Signpost)); newSignpost->m_prev = signpost; newSignpost->m_next = signpost->m_next; newSignpost->m_size = signpost->m_size - numBytesWithSignpost; newSignpost->m_isFree = true; signpost->m_isFree = false; signpost->m_size = numBytes; if (signpost->m_next != nullptr) signpost->m_next->m_prev = newSignpost; signpost->m_next = newSignpost; ValidateSignposts(); //stat tracking m_currentBytesFree -= (unsigned int)numBytesWithSignpost; m_totalBytesAllocated += (unsigned long)numBytes; if (numBytes > m_largestAllocationRequested) m_largestAllocationRequested = (unsigned int)numBytes; #ifndef NDEBUG if (doTracking && m_allocationTracking != nullptr) { m_allocationTracking->emplace(signpost, AllocationTracker(file, line)); } #endif ValidateSignposts(); m_criticalSection.Exit(); return (void*)((size_t)signpost + sizeof(Signpost)); } m_criticalSection.Exit(); if (doTracking) ConsolePrintf("\nOut of Memory at:\n%s(%u)\n\n", file, line); else ConsolePrintf("\nOut of Memory\n\n"); __debugbreak(); //FATAL_ERROR_RELEASE("Out of Memory at:\n" + std::string(file) + "(" + std::to_string(line) + ")\n\n"); //uses new :( return nullptr; }