<commit_before>#include "World.hpp"

#include <cmath>

// serialization headers
#include <tinyxml2.h>

namespace swift
{
	World::World(const std::string& n, const sf::Vector2i& s, AssetManager& am, SoundPlayer& sp, MusicPlayer& mp)
		:	assets(am),
			soundPlayer(sp),
			musicPlayer(mp),
			noisySystem(soundPlayer, assets),
			size(s),
			name(n)
	{
		tilemap.setSize(static_cast<sf::Vector2u>(s));
	}

	World::~World()
	{
		save();

		// set all script's world to nullptr, so scripts don't call destroyed worlds
		for(auto& it : scripts)
		{
			it.second->setWorld(nullptr);
		}

		for(auto& e : entities)
		{
			delete e;
		}
	}

	void World::update(float dt)
	{
		for(auto& e : entities)
		{
			moveSystem.update(*e, dt);
			physicalSystem.update(*e, dt);
			drawSystem.update(*e, dt);
			noisySystem.update(*e, dt);
		}

		std::vector<std::string> doneScripts;

		for(auto& s : scripts)
		{
			if(s.second->getWorld() != this)
				s.second->setWorld(*this);

			s.second->update();

			// check if script is done, if so, push it for deletion
			if(s.second->toDelete())
				doneScripts.push_back(s.first);
		}

		// remove all done scripts
		for(auto& s : doneScripts)
		{
			removeScript(s);
		}
	}

	/* save file format */
	/* It is an xml file
	 * <world>
	 * 	<entity>
	 * 		<component type = "">
	 * 			<variable>component data</variable>
	 * 		</component>
	 * 	</entity>
	 * .
	 * .
	 * .
	 * </world>
	 */
	bool World::load()
	{
		std::string file = "./data/saves/" + name + ".world";

		tinyxml2::XMLDocument loadFile;

		if(loadFile.LoadFile(file.c_str()))
		{
			tinyxml2::XMLError error = loadFile.LoadFile(file.c_str());
			log << error << '\n';
			log << "[ERROR] Loading world save file \"" << file << "\" failed.\n";
			return false;
		}

		tinyxml2::XMLElement* worldRoot = loadFile.FirstChildElement("world");
		if(worldRoot == nullptr)
		{
			log << "[WARNING] World save file \"" << file << "\" does not have a \"world\" root element.\n";
			return false;
		}

		tinyxml2::XMLElement* entityElement = worldRoot->FirstChildElement("entity");
		while(entityElement != nullptr)
		{
			Entity* entity = addEntity();

			tinyxml2::XMLElement* component = entityElement->FirstChildElement();
			while(component != nullptr)
			{
				std::string componentName = component->Value();
				entity->add(componentName);

				std::map<std::string, std::string> variables;
				tinyxml2::XMLElement* variableElement = component->FirstChildElement();
				while(variableElement != nullptr)
				{
					// make sure the strings aren't empty...
					if(std::string(variableElement->Value()).size() > 0 && std::string(variableElement->GetText()).size() > 0)
						variables.emplace(variableElement->Value(), variableElement->GetText());
					variableElement = variableElement->NextSiblingElement();
				}

				// get component and add to it
				entity->get(componentName)->unserialize(variables);

				if(componentName == "Drawable")
				{
					entity->get<Drawable>()->sprite.setTexture(assets.getTexture(entity->get<Drawable>()->texture));
				}

				component = component->NextSiblingElement();
			}

			entityElement = entityElement->NextSiblingElement("entity");
		}

		return true;
	}

	bool World::save()
	{
		std::string file = "./data/saves/" + name + ".world";

		tinyxml2::XMLDocument saveFile;

		if(saveFile.LoadFile(file.c_str()))
		{
			log << "[ERROR] Saving world save file \"" << file << "\" failed.\n";
			return false;
		}

		tinyxml2::XMLElement* root = saveFile.FirstChildElement("world");
		if(root == nullptr)
		{
			log << "[WARNING] World save file \"" << file << "\" does not have a \"world\" root element.\n";
			//return false;
			root = saveFile.NewElement("world");
			saveFile.InsertFirstChild(root);
		}
		else
			root->DeleteChildren();

		for(auto& e : entities)
		{
			tinyxml2::XMLElement* entity = saveFile.NewElement("entity");

			for(auto& c : e->getComponents())
			{
				tinyxml2::XMLElement* component = saveFile.NewElement(c.first.c_str());

				for(auto& v : c.second->serialize())
				{
					tinyxml2::XMLElement* variable = saveFile.NewElement(v.first.c_str());
					variable->SetText(v.second.c_str());
					component->InsertEndChild(variable);
				}

				entity->InsertEndChild(component);
			}

			root->InsertEndChild(entity);
		}

		saveFile.SaveFile(file.c_str());

		return true;
	}

	void World::drawWorld(sf::RenderTarget& target, sf::RenderStates states)
	{
		target.draw(tilemap, states);
	}

	void World::drawEntities(sf::RenderTarget& target, sf::RenderStates states)
	{
		for(auto& e : entities)
		{
			if(e->has<Drawable>())
				target.draw(e->get<Drawable>()->sprite, states);
		}
	}

	sf::Vector2i World::getSize() const
	{
		return size;
	}

	std::string World::getName() const
	{
		return name;
	}

	Entity* World::addEntity()
	{
		unsigned oldSize = entities.size();

		entities.emplace_back(new Entity);

		return entities.size() > oldSize ? entities[entities.size() - 1] : nullptr;
	}

	bool World::removeEntity(int e)
	{
		// if e is positive, check if is greater than last entity
		// if e is negative, check if it refers to entity less than 0
		if(e >= static_cast<int>(entities.size()) || static_cast<int>(entities.size()) + e < 0)
			return false;

		entities.erase((e >= 0 ? entities.begin() : entities.end()) + e);

		return true;
	}

	bool World::addScript(const std::string& scriptFile)
	{
		if(scripts.find(scriptFile) == scripts.end())
		{
			scripts.emplace(scriptFile, &assets.getScript(scriptFile));
			assets.getScript(scriptFile).setWorld(*this);
			return true;
		}
		else
			return false;
	}

	bool World::removeScript(const std::string& scriptFile)
	{
		if(scripts.find(scriptFile) != scripts.end())
		{
			scripts.erase(scriptFile);
			return true;
		}
		else
			return false;
	}

	const std::vector<Entity*>& World::getEntities() const
	{
		return entities;
	}

	const std::vector<Entity*> World::getEntitiesAround(const sf::Vector2f& pos, float radius)
	{
		std::vector<Entity*> around;

		// if pos is outside of the world, or the radius is 0 or less, just return an empty vector
		if(!(0 <= pos.x && pos.x < size.x && 0 <= pos.y && pos.y < size.y) || radius <= 0)
			return around;

		for(auto& e : entities)
		{
			if(e->has<Physical>())
			{
				Physical* p = e->get<Physical>();
				if(distance(p->position, pos) <= radius)
					around.push_back(e);
			}
		}

		return around;
	}

	float World::distance(const sf::Vector2f& one, const sf::Vector2f& two)
	{
		return std::sqrt((two.x - one.x) * (two.x - one.x) + (two.y - one.y) * (two.y - one.y));
	}

	float World::distanceSquared(const sf::Vector2f& one, const sf::Vector2f& two)
	{
		return (two.x - one.x) * (two.x - one.x) + (two.y - one.y) * (two.y - one.y);
	}
}
<commit_msg>Should've been in previous commit now that I think about it. Eh, resetting is annoying.<commit_after>#include "World.hpp"

#include <cmath>

// serialization headers
#include <tinyxml2.h>

namespace swift
{
	World::World(const std::string& n, const sf::Vector2i& s, AssetManager& am, SoundPlayer& sp, MusicPlayer& mp)
		:	assets(am),
			soundPlayer(sp),
			musicPlayer(mp),
			noisySystem(soundPlayer, assets),
			size(s),
			name(n)
	{
		tilemap.setSize(static_cast<sf::Vector2u>(s));
	}

	World::~World()
	{
		save();

		// set all script's world to nullptr, so scripts don't call destroyed worlds
		for(auto& it : scripts)
		{
			it.second->setWorld(nullptr);
		}

		for(auto& e : entities)
		{
			delete e;
		}
	}

	void World::update(float dt)
	{
		moveSystem.update(entities, dt);
		physicalSystem.update(entities, dt);
		drawSystem.update(entities, dt);
		noisySystem.update(entities, dt);

		std::vector<std::string> doneScripts;

		for(auto& s : scripts)
		{
			if(s.second->getWorld() != this)
				s.second->setWorld(*this);

			s.second->update();

			// check if script is done, if so, push it for deletion
			if(s.second->toDelete())
				doneScripts.push_back(s.first);
		}

		// remove all done scripts
		for(auto& s : doneScripts)
		{
			removeScript(s);
		}
	}

	/* save file format */
	/* It is an xml file
	 * <world>
	 * 	<entity>
	 * 		<component type = "">
	 * 			<variable>component data</variable>
	 * 		</component>
	 * 	</entity>
	 * .
	 * .
	 * .
	 * </world>
	 */
	bool World::load()
	{
		std::string file = "./data/saves/" + name + ".world";

		tinyxml2::XMLDocument loadFile;

		if(loadFile.LoadFile(file.c_str()))
		{
			tinyxml2::XMLError error = loadFile.LoadFile(file.c_str());
			log << error << '\n';
			log << "[ERROR] Loading world save file \"" << file << "\" failed.\n";
			return false;
		}

		tinyxml2::XMLElement* worldRoot = loadFile.FirstChildElement("world");
		if(worldRoot == nullptr)
		{
			log << "[WARNING] World save file \"" << file << "\" does not have a \"world\" root element.\n";
			return false;
		}

		tinyxml2::XMLElement* entityElement = worldRoot->FirstChildElement("entity");
		while(entityElement != nullptr)
		{
			Entity* entity = addEntity();

			tinyxml2::XMLElement* component = entityElement->FirstChildElement();
			while(component != nullptr)
			{
				std::string componentName = component->Value();
				entity->add(componentName);

				std::map<std::string, std::string> variables;
				tinyxml2::XMLElement* variableElement = component->FirstChildElement();
				while(variableElement != nullptr)
				{
					// make sure the strings aren't empty...
					if(std::string(variableElement->Value()).size() > 0 && std::string(variableElement->GetText()).size() > 0)
						variables.emplace(variableElement->Value(), variableElement->GetText());
					variableElement = variableElement->NextSiblingElement();
				}

				// get component and add to it
				entity->get(componentName)->unserialize(variables);

				if(componentName == "Drawable")
				{
					entity->get<Drawable>()->sprite.setTexture(assets.getTexture(entity->get<Drawable>()->texture));
				}

				component = component->NextSiblingElement();
			}

			entityElement = entityElement->NextSiblingElement("entity");
		}

		return true;
	}

	bool World::save()
	{
		std::string file = "./data/saves/" + name + ".world";

		tinyxml2::XMLDocument saveFile;

		if(saveFile.LoadFile(file.c_str()))
		{
			log << "[ERROR] Saving world save file \"" << file << "\" failed.\n";
			return false;
		}

		tinyxml2::XMLElement* root = saveFile.FirstChildElement("world");
		if(root == nullptr)
		{
			log << "[WARNING] World save file \"" << file << "\" does not have a \"world\" root element.\n";
			//return false;
			root = saveFile.NewElement("world");
			saveFile.InsertFirstChild(root);
		}
		else
			root->DeleteChildren();

		for(auto& e : entities)
		{
			tinyxml2::XMLElement* entity = saveFile.NewElement("entity");

			for(auto& c : e->getComponents())
			{
				tinyxml2::XMLElement* component = saveFile.NewElement(c.first.c_str());

				for(auto& v : c.second->serialize())
				{
					tinyxml2::XMLElement* variable = saveFile.NewElement(v.first.c_str());
					variable->SetText(v.second.c_str());
					component->InsertEndChild(variable);
				}

				entity->InsertEndChild(component);
			}

			root->InsertEndChild(entity);
		}

		saveFile.SaveFile(file.c_str());

		return true;
	}

	void World::drawWorld(sf::RenderTarget& target, sf::RenderStates states)
	{
		target.draw(tilemap, states);
	}

	void World::drawEntities(sf::RenderTarget& target, sf::RenderStates states)
	{
		for(auto& e : entities)
		{
			if(e->has<Drawable>())
				target.draw(e->get<Drawable>()->sprite, states);
		}
	}

	sf::Vector2i World::getSize() const
	{
		return size;
	}

	std::string World::getName() const
	{
		return name;
	}

	Entity* World::addEntity()
	{
		unsigned oldSize = entities.size();

		entities.emplace_back(new Entity);

		return entities.size() > oldSize ? entities[entities.size() - 1] : nullptr;
	}

	bool World::removeEntity(int e)
	{
		// if e is positive, check if is greater than last entity
		// if e is negative, check if it refers to entity less than 0
		if(e >= static_cast<int>(entities.size()) || static_cast<int>(entities.size()) + e < 0)
			return false;

		entities.erase((e >= 0 ? entities.begin() : entities.end()) + e);

		return true;
	}

	bool World::addScript(const std::string& scriptFile)
	{
		if(scripts.find(scriptFile) == scripts.end())
		{
			scripts.emplace(scriptFile, &assets.getScript(scriptFile));
			assets.getScript(scriptFile).setWorld(*this);
			return true;
		}
		else
			return false;
	}

	bool World::removeScript(const std::string& scriptFile)
	{
		if(scripts.find(scriptFile) != scripts.end())
		{
			scripts.erase(scriptFile);
			return true;
		}
		else
			return false;
	}

	const std::vector<Entity*>& World::getEntities() const
	{
		return entities;
	}

	const std::vector<Entity*> World::getEntitiesAround(const sf::Vector2f& pos, float radius)
	{
		std::vector<Entity*> around;

		// if pos is outside of the world, or the radius is 0 or less, just return an empty vector
		if(!(0 <= pos.x && pos.x < size.x && 0 <= pos.y && pos.y < size.y) || radius <= 0)
			return around;

		for(auto& e : entities)
		{
			if(e->has<Physical>())
			{
				Physical* p = e->get<Physical>();
				if(distance(p->position, pos) <= radius)
					around.push_back(e);
			}
		}

		return around;
	}

	float World::distance(const sf::Vector2f& one, const sf::Vector2f& two)
	{
		return std::sqrt((two.x - one.x) * (two.x - one.x) + (two.y - one.y) * (two.y - one.y));
	}

	float World::distanceSquared(const sf::Vector2f& one, const sf::Vector2f& two)
	{
		return (two.x - one.x) * (two.x - one.x) + (two.y - one.y) * (two.y - one.y);
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "TextureOGL.h"
#include "core/Engine.h"
#include "RendererOGL.h"
#include "graphics/Image.h"
#include "utils/Log.h"

namespace ouzel
{
    namespace graphics
    {
        TextureOGL::TextureOGL()
        {
        }

        TextureOGL::~TextureOGL()
        {
            if (depthBufferId)
            {
                RendererOGL::deleteResource(depthBufferId, RendererOGL::ResourceType::RenderBuffer);
            }

            if (frameBufferId)
            {
                RendererOGL::deleteResource(frameBufferId, RendererOGL::ResourceType::FrameBuffer);
            }

            if (textureId)
            {
                RendererOGL::deleteResource(textureId, RendererOGL::ResourceType::Texture);
            }
        }

        void TextureOGL::free()
        {
            Texture::free();

            if (depthBufferId)
            {
                RendererOGL::deleteResource(depthBufferId, RendererOGL::ResourceType::RenderBuffer);
                depthBufferId = 0;
            }

            if (frameBufferId)
            {
                RendererOGL::deleteResource(frameBufferId, RendererOGL::ResourceType::FrameBuffer);
                frameBufferId = 0;
            }

            if (textureId)
            {
                RendererOGL::deleteResource(textureId, RendererOGL::ResourceType::Texture);
                textureId = 0;
            }

            width = 0;
            height = 0;
        }

        bool TextureOGL::upload()
        {
            if (!Texture::upload())
            {
                return false;
            }

            if (!textureId)
            {
                glGenTextures(1, &textureId);

                if (RendererOGL::checkOpenGLError())
                {
                    Log(Log::Level::ERR) << "Failed to create texture";
                    return false;
                }
            }

            RendererOGL::bindTexture(textureId, 0);

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

            RendererOGL* rendererOGL = static_cast<RendererOGL*>(sharedEngine->getRenderer());

            switch (rendererOGL->getTextureFilter())
            {
                case TextureFilter::NONE:
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, uploadData.mipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                    break;
                case TextureFilter::LINEAR:
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, uploadData.mipmaps ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST);
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                    break;
                case TextureFilter::BILINEAR:
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, uploadData.mipmaps ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                    break;
                case TextureFilter::TRILINEAR:
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, uploadData.mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                    break;
            }

            if (RendererOGL::checkOpenGLError())
            {
                Log(Log::Level::ERR) << "Failed to set texture parameters";
                return false;
            }

            if (static_cast<GLsizei>(uploadData.size.v[0]) != width ||
                static_cast<GLsizei>(uploadData.size.v[1]) != height)
            {
                width = static_cast<GLsizei>(uploadData.size.v[0]);
                height = static_cast<GLsizei>(uploadData.size.v[1]);

                for (size_t level = 0; level < uploadData.levels.size(); ++level)
                {
                    if (!uploadData.levels[level].data.empty())
                    {
                        glTexImage2D(GL_TEXTURE_2D, static_cast<GLint>(level), GL_RGBA,
                                     static_cast<GLsizei>(uploadData.levels[level].size.v[0]),
                                     static_cast<GLsizei>(uploadData.levels[level].size.v[1]), 0,
                                     GL_RGBA, GL_UNSIGNED_BYTE, uploadData.levels[level].data.data());
                    }
                }

                if (uploadData.renderTarget)
                {
                    if (!frameBufferId)
                    {
                        glGenFramebuffers(1, &frameBufferId);

                        if (RendererOGL::checkOpenGLError())
                        {
                            Log(Log::Level::ERR) << "Failed to create frame buffer";
                            return false;
                        }

                        clearMask = 0;

                        if (uploadData.clearColorBuffer) clearMask |= GL_COLOR_BUFFER_BIT;
                        if (uploadData.clearDepthBuffer) clearMask |= GL_DEPTH_BUFFER_BIT;
                    }

                    RendererOGL::bindFrameBuffer(frameBufferId);

                    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
                    {
                        RendererOGL::bindTexture(textureId, 0);

                        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                                     static_cast<GLsizei>(uploadData.size.v[0]),
                                     static_cast<GLsizei>(uploadData.size.v[1]),
                                     0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

                        if (uploadData.depth)
                        {
                            glGenRenderbuffers(1, &depthBufferId);
                            glBindRenderbuffer(GL_RENDERBUFFER, depthBufferId);
                            glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT,
                                                  static_cast<GLsizei>(uploadData.size.v[0]),
                                                  static_cast<GLsizei>(uploadData.size.v[1]));
                            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBufferId);
                        }

                        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);

#if OUZEL_SUPPORTS_OPENGL // TODO: fix this
                        //GLenum drawBuffers[1] = {GL_COLOR_ATTACHMENT0};
                        //glDrawBuffers(1, drawBuffers);
                        glDrawBuffer(GL_COLOR_ATTACHMENT0);
#endif

                        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
                        {
                            Log(Log::Level::ERR) << "Failed to create frame buffer";
                            return false;
                        }
                    }

                    frameBufferClearColor[0] = uploadData.clearColor.normR();
                    frameBufferClearColor[1] = uploadData.clearColor.normG();
                    frameBufferClearColor[2] = uploadData.clearColor.normB();
                    frameBufferClearColor[3] = uploadData.clearColor.normA();
                }
            }
            else
            {
                for (size_t level = 0; level < uploadData.levels.size(); ++level)
                {
                    if (!uploadData.levels[level].data.empty())
                    {
                        glTexSubImage2D(GL_TEXTURE_2D, static_cast<GLint>(level), 0, 0,
                                        static_cast<GLsizei>(uploadData.levels[level].size.v[0]),
                                        static_cast<GLsizei>(uploadData.levels[level].size.v[1]),
                                        GL_RGBA, GL_UNSIGNED_BYTE, uploadData.levels[level].data.data());

                        if (RendererOGL::checkOpenGLError())
                        {
                            Log(Log::Level::ERR) << "Failed to upload texture data";
                            return false;
                        }
                    }
                }
            }

            return true;
        }
    } // namespace graphics
} // namespace ouzel
<commit_msg>Fix OpenGL linear filtering<commit_after>// Copyright (C) 2017 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "TextureOGL.h"
#include "core/Engine.h"
#include "RendererOGL.h"
#include "graphics/Image.h"
#include "utils/Log.h"

namespace ouzel
{
    namespace graphics
    {
        TextureOGL::TextureOGL()
        {
        }

        TextureOGL::~TextureOGL()
        {
            if (depthBufferId)
            {
                RendererOGL::deleteResource(depthBufferId, RendererOGL::ResourceType::RenderBuffer);
            }

            if (frameBufferId)
            {
                RendererOGL::deleteResource(frameBufferId, RendererOGL::ResourceType::FrameBuffer);
            }

            if (textureId)
            {
                RendererOGL::deleteResource(textureId, RendererOGL::ResourceType::Texture);
            }
        }

        void TextureOGL::free()
        {
            Texture::free();

            if (depthBufferId)
            {
                RendererOGL::deleteResource(depthBufferId, RendererOGL::ResourceType::RenderBuffer);
                depthBufferId = 0;
            }

            if (frameBufferId)
            {
                RendererOGL::deleteResource(frameBufferId, RendererOGL::ResourceType::FrameBuffer);
                frameBufferId = 0;
            }

            if (textureId)
            {
                RendererOGL::deleteResource(textureId, RendererOGL::ResourceType::Texture);
                textureId = 0;
            }

            width = 0;
            height = 0;
        }

        bool TextureOGL::upload()
        {
            if (!Texture::upload())
            {
                return false;
            }

            if (!textureId)
            {
                glGenTextures(1, &textureId);

                if (RendererOGL::checkOpenGLError())
                {
                    Log(Log::Level::ERR) << "Failed to create texture";
                    return false;
                }
            }

            RendererOGL::bindTexture(textureId, 0);

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

            RendererOGL* rendererOGL = static_cast<RendererOGL*>(sharedEngine->getRenderer());

            switch (rendererOGL->getTextureFilter())
            {
                case TextureFilter::NONE:
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, uploadData.mipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                    break;
                case TextureFilter::LINEAR:
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, uploadData.mipmaps ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                    break;
                case TextureFilter::BILINEAR:
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, uploadData.mipmaps ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                    break;
                case TextureFilter::TRILINEAR:
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, uploadData.mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
                    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                    break;
            }

            if (RendererOGL::checkOpenGLError())
            {
                Log(Log::Level::ERR) << "Failed to set texture parameters";
                return false;
            }

            if (static_cast<GLsizei>(uploadData.size.v[0]) != width ||
                static_cast<GLsizei>(uploadData.size.v[1]) != height)
            {
                width = static_cast<GLsizei>(uploadData.size.v[0]);
                height = static_cast<GLsizei>(uploadData.size.v[1]);

                for (size_t level = 0; level < uploadData.levels.size(); ++level)
                {
                    if (!uploadData.levels[level].data.empty())
                    {
                        glTexImage2D(GL_TEXTURE_2D, static_cast<GLint>(level), GL_RGBA,
                                     static_cast<GLsizei>(uploadData.levels[level].size.v[0]),
                                     static_cast<GLsizei>(uploadData.levels[level].size.v[1]), 0,
                                     GL_RGBA, GL_UNSIGNED_BYTE, uploadData.levels[level].data.data());
                    }
                }

                if (uploadData.renderTarget)
                {
                    if (!frameBufferId)
                    {
                        glGenFramebuffers(1, &frameBufferId);

                        if (RendererOGL::checkOpenGLError())
                        {
                            Log(Log::Level::ERR) << "Failed to create frame buffer";
                            return false;
                        }

                        clearMask = 0;

                        if (uploadData.clearColorBuffer) clearMask |= GL_COLOR_BUFFER_BIT;
                        if (uploadData.clearDepthBuffer) clearMask |= GL_DEPTH_BUFFER_BIT;
                    }

                    RendererOGL::bindFrameBuffer(frameBufferId);

                    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
                    {
                        RendererOGL::bindTexture(textureId, 0);

                        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
                                     static_cast<GLsizei>(uploadData.size.v[0]),
                                     static_cast<GLsizei>(uploadData.size.v[1]),
                                     0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

                        if (uploadData.depth)
                        {
                            glGenRenderbuffers(1, &depthBufferId);
                            glBindRenderbuffer(GL_RENDERBUFFER, depthBufferId);
                            glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT,
                                                  static_cast<GLsizei>(uploadData.size.v[0]),
                                                  static_cast<GLsizei>(uploadData.size.v[1]));
                            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBufferId);
                        }

                        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);

#if OUZEL_SUPPORTS_OPENGL // TODO: fix this
                        //GLenum drawBuffers[1] = {GL_COLOR_ATTACHMENT0};
                        //glDrawBuffers(1, drawBuffers);
                        glDrawBuffer(GL_COLOR_ATTACHMENT0);
#endif

                        if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
                        {
                            Log(Log::Level::ERR) << "Failed to create frame buffer";
                            return false;
                        }
                    }

                    frameBufferClearColor[0] = uploadData.clearColor.normR();
                    frameBufferClearColor[1] = uploadData.clearColor.normG();
                    frameBufferClearColor[2] = uploadData.clearColor.normB();
                    frameBufferClearColor[3] = uploadData.clearColor.normA();
                }
            }
            else
            {
                for (size_t level = 0; level < uploadData.levels.size(); ++level)
                {
                    if (!uploadData.levels[level].data.empty())
                    {
                        glTexSubImage2D(GL_TEXTURE_2D, static_cast<GLint>(level), 0, 0,
                                        static_cast<GLsizei>(uploadData.levels[level].size.v[0]),
                                        static_cast<GLsizei>(uploadData.levels[level].size.v[1]),
                                        GL_RGBA, GL_UNSIGNED_BYTE, uploadData.levels[level].data.data());

                        if (RendererOGL::checkOpenGLError())
                        {
                            Log(Log::Level::ERR) << "Failed to upload texture data";
                            return false;
                        }
                    }
                }
            }

            return true;
        }
    } // namespace graphics
} // namespace ouzel
<|endoftext|>


<commit_before>#include <cassert>
#include <sstream>
#include <string>

namespace frog{

  template <typename ID, typename R>
  AssetManager<ID,R>::AssetManager()
  {

  }

  template <typename ID, typename R>
  AssetManager<ID,R>::~AssetManager()
  {
    m_files.clear();
  }

  template <typename ID, typename R>
  R& AssetManager<ID,R>::get(const ID& id)
  {
    auto itr = m_files.find(id);
    if (itr == m_files.end() )
      {
        std::ostringstream oss;
        oss << "AssetManager could not get "<<id<<" : asset has not been loaded";
        throw std::logic_error( oss.str().c_str() );
        oss.flush();
      }
    return *itr->second;
  }

  template <typename ID, typename R>
  const R& AssetManager<ID,R>::get(const ID& id) const
  {
    auto itr = m_files.find(id);
    if (itr == m_files.end() )
      {
        std::ostringstream oss;
        oss << "AssetManager could not get "<<id<<" : asset has not been loaded";
        throw std::logic_error( oss.str() );
        oss.flush();
      }
    return *itr->second;
  }

  template <typename ID, typename R>
  void AssetManager<ID,R>::loadFromFile(const std::string& path, const ID& id)
    throw (std::runtime_error)
  {
    if( m_files.find(id) == m_files.end() )
      {
        std::unique_ptr<R> pr(new R() );
        if( not pr->loadFromFile(path) )
          {
            std::string err = "Impossible to create asset because a problem";
            err += " occured while loading " + path;
            throw std::runtime_error(err);
          }
        auto check = m_files.insert( std::make_pair( id, std::move(pr) )  );
        assert( check.second );

      }

  }

}
<commit_msg>removed assert, replaced by an exception<commit_after>#include <sstream>
#include <string>

namespace frog{

  template <typename ID, typename R>
  AssetManager<ID,R>::AssetManager()
  {

  }

  template <typename ID, typename R>
  AssetManager<ID,R>::~AssetManager()
  {
    m_files.clear();
  }

  template <typename ID, typename R>
  R& AssetManager<ID,R>::get(const ID& id)
  {
    auto itr = m_files.find(id);
    if (itr == m_files.end() )
      {
        std::ostringstream oss;
        oss << "AssetManager could not get "<<id<<" : asset has not been loaded";
        throw std::logic_error( oss.str().c_str() );
        oss.flush();
      }
    return *itr->second;
  }

  template <typename ID, typename R>
  const R& AssetManager<ID,R>::get(const ID& id) const
  {
    auto itr = m_files.find(id);
    if (itr == m_files.end() )
      {
        std::ostringstream oss;
        oss << "AssetManager could not get "<<id<<" : asset has not been loaded";
        throw std::logic_error( oss.str() );
        oss.flush();
      }
    return *itr->second;
  }

  template <typename ID, typename R>
  void AssetManager<ID,R>::loadFromFile(const std::string& path, const ID& id)
    throw (std::runtime_error)
  {
    if( m_files.find(id) == m_files.end() )
      {
        std::unique_ptr<R> pr(new R() );
        if( not pr->loadFromFile(path) )
          {
            std::string err = "Impossible to create asset because a problem";
            err += " occured while loading " + path;
            throw std::runtime_error(err);
          }
        auto check = m_files.insert( std::make_pair( id, std::move(pr) )  );
        if (not check.second)
          {
            std::string err = "Impossible to create asset because a problem";
            err += " occured while inserting " + path;
            throw std::runtime_error(err);
          }

      }

  }

}
<|endoftext|>


<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#include "sw/device/silicon_creator/lib/drivers/spi_device.h"

#include <cstring>
#include <limits>

#include "gtest/gtest.h"
#include "sw/device/lib/base/mock_abs_mmio.h"
#include "sw/device/silicon_creator/lib/drivers/mock_lifecycle.h"
#include "sw/device/silicon_creator/lib/error.h"
#include "sw/device/silicon_creator/testing/mask_rom_test.h"

#include "flash_ctrl_regs.h"
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
#include "spi_device_regs.h"

namespace spi_device_unittest {
namespace {
using ::testing::NotNull;
using ::testing::SetArgPointee;

class SpiDeviceTest : public mask_rom_test::MaskRomTest {
 protected:
  uint32_t base_ = TOP_EARLGREY_SPI_DEVICE_BASE_ADDR;
  mask_rom_test::MockAbsMmio mmio_;
  mask_rom_test::MockLifecycle lifecycle_;
};

class InitTest : public SpiDeviceTest {};

TEST_F(InitTest, Init) {
  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_CFG_REG_OFFSET,
                     {
                         {SPI_DEVICE_CFG_CPOL_BIT, 0},
                         {SPI_DEVICE_CFG_CPHA_BIT, 0},
                         {SPI_DEVICE_CFG_TX_ORDER_BIT, 0},
                         {SPI_DEVICE_CFG_RX_ORDER_BIT, 0},
                         {SPI_DEVICE_CFG_TIMER_V_OFFSET, 0x7f},
                         {SPI_DEVICE_CFG_ADDR_4B_EN_BIT, 0},
                         {SPI_DEVICE_CFG_MAILBOX_EN_BIT, 0},
                     });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_JEDEC_CC_REG_OFFSET,
      {
          {SPI_DEVICE_JEDEC_CC_CC_OFFSET, kSpiDeviceJedecContCode},
          {SPI_DEVICE_JEDEC_CC_NUM_CC_OFFSET, kSpiDeviceJedecContCodeCount},
      });
  lifecycle_hw_rev_t hw_rev{
      .chip_gen = 1,
      .chip_rev = 3,
  };
  EXPECT_CALL(lifecycle_, HwRev(NotNull())).WillOnce(SetArgPointee<0>(hw_rev));
  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_JEDEC_ID_REG_OFFSET,
      {
          {SPI_DEVICE_DEV_ID_CHIP_REV_FIELD.index, hw_rev.chip_rev},
          {SPI_DEVICE_DEV_ID_ROM_BOOTSTRAP_BIT, 1},
          {SPI_DEVICE_DEV_ID_CHIP_GEN_FIELD.index, hw_rev.chip_gen},
          {SPI_DEVICE_DEV_ID_DENSITY_FIELD.index,
           (uint32_t)bitfield_count_trailing_zeroes32(
               FLASH_CTRL_PARAM_REG_NUM_BANKS *
               FLASH_CTRL_PARAM_BYTES_PER_BANK)},
          {SPI_DEVICE_JEDEC_ID_MF_OFFSET, kSpiDeviceJedecManufId},
      });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_CMD_INFO_0_REG_OFFSET,
      {
          {SPI_DEVICE_CMD_INFO_0_OPCODE_0_OFFSET, kSpiDeviceOpcodeReadStatus},
          {SPI_DEVICE_CMD_INFO_0_VALID_0_BIT, 1},
      });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_CMD_INFO_3_REG_OFFSET,
      {
          {SPI_DEVICE_CMD_INFO_3_OPCODE_3_OFFSET, kSpiDeviceOpcodeReadJedecId},
          {SPI_DEVICE_CMD_INFO_3_VALID_3_BIT, 1},
      });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_CMD_INFO_4_REG_OFFSET,
      {
          {SPI_DEVICE_CMD_INFO_4_OPCODE_4_OFFSET, kSpiDeviceOpcodeReadSfdp},
          {SPI_DEVICE_CMD_INFO_4_ADDR_MODE_4_OFFSET,
           SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDR3B},
          {SPI_DEVICE_CMD_INFO_4_DUMMY_SIZE_4_OFFSET, 7},
          {SPI_DEVICE_CMD_INFO_4_DUMMY_EN_4_BIT, 1},
          {SPI_DEVICE_CMD_INFO_4_VALID_4_BIT, 1},
      });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_CMD_INFO_11_REG_OFFSET,
      {
          {SPI_DEVICE_CMD_INFO_11_OPCODE_11_OFFSET, kSpiDeviceOpcodeChipErase},
          {SPI_DEVICE_CMD_INFO_11_UPLOAD_11_BIT, 1},
          {SPI_DEVICE_CMD_INFO_11_BUSY_11_BIT, 1},
          {SPI_DEVICE_CMD_INFO_11_VALID_11_BIT, 1},
      });

  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_CMD_INFO_12_REG_OFFSET,
                     {
                         {SPI_DEVICE_CMD_INFO_12_OPCODE_12_OFFSET,
                          kSpiDeviceOpcodeSectorErase},
                         {SPI_DEVICE_CMD_INFO_12_ADDR_MODE_12_OFFSET,
                          SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDR3B},
                         {SPI_DEVICE_CMD_INFO_12_UPLOAD_12_BIT, 1},
                         {SPI_DEVICE_CMD_INFO_12_BUSY_12_BIT, 1},
                         {SPI_DEVICE_CMD_INFO_12_VALID_12_BIT, 1},
                     });

  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_CMD_INFO_13_REG_OFFSET,
                     {
                         {SPI_DEVICE_CMD_INFO_13_OPCODE_13_OFFSET,
                          kSpiDeviceOpcodePageProgram},
                         {SPI_DEVICE_CMD_INFO_13_ADDR_MODE_13_OFFSET,
                          SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDR3B},
                         {SPI_DEVICE_CMD_INFO_13_UPLOAD_13_BIT, 1},
                         {SPI_DEVICE_CMD_INFO_13_BUSY_13_BIT, 1},
                         {SPI_DEVICE_CMD_INFO_13_VALID_13_BIT, 1},
                     });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_CMD_INFO_14_REG_OFFSET,
      {
          {SPI_DEVICE_CMD_INFO_14_OPCODE_14_OFFSET, kSpiDeviceOpcodeReset},
          {SPI_DEVICE_CMD_INFO_14_UPLOAD_14_BIT, 1},
          {SPI_DEVICE_CMD_INFO_14_BUSY_14_BIT, 1},
          {SPI_DEVICE_CMD_INFO_14_VALID_14_BIT, 1},
      });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_CMD_INFO_WREN_REG_OFFSET,
      {
          {SPI_DEVICE_CMD_INFO_WREN_OPCODE_OFFSET, kSpiDeviceOpcodeWriteEnable},
          {SPI_DEVICE_CMD_INFO_WREN_VALID_BIT, 1},
      });

  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_CMD_INFO_WRDI_REG_OFFSET,
                     {
                         {SPI_DEVICE_CMD_INFO_WRDI_OPCODE_OFFSET,
                          kSpiDeviceOpcodeWriteDisable},
                         {SPI_DEVICE_CMD_INFO_WRDI_VALID_BIT, 1},
                     });

  std::array<uint32_t, kSpiDeviceSfdpAreaNumBytes / sizeof(uint32_t)>
      sfdp_buffer;
  sfdp_buffer.fill(std::numeric_limits<uint32_t>::max());
  std::memcpy(sfdp_buffer.data(), &kSpiDeviceSfdpTable,
              sizeof(kSpiDeviceSfdpTable));
  uint32_t offset =
      base_ + SPI_DEVICE_BUFFER_REG_OFFSET + kSpiDeviceSfdpAreaOffset;
  for (size_t i = 0; i < sfdp_buffer.size(); ++i) {
    EXPECT_ABS_WRITE32(offset, sfdp_buffer[i]);
    offset += sizeof(uint32_t);
  }

  offset = base_ + SPI_DEVICE_BUFFER_REG_OFFSET + kSpiDevicePayloadAreaOffset;
  for (size_t i = 0; i < kSpiDevicePayloadAreaNumWords; ++i) {
    EXPECT_ABS_WRITE32(offset, 0);
    offset += sizeof(uint32_t);
  }

  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_FLASH_STATUS_REG_OFFSET, 0);

  spi_device_init();
}

TEST_F(SpiDeviceTest, FlashStatusClear) {
  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_FLASH_STATUS_REG_OFFSET, 0);

  spi_device_flash_status_clear();
}

TEST_F(SpiDeviceTest, FlashStatusGet) {
  EXPECT_ABS_READ32(base_ + SPI_DEVICE_FLASH_STATUS_REG_OFFSET, 0xa5);

  EXPECT_EQ(0xa5, spi_device_flash_status_get());
}

struct CmdGetTestCase {
  spi_device_opcode_t opcode;
  uint32_t address;
  std::vector<uint8_t> payload;
};

class CmdGetTest : public SpiDeviceTest,
                   public testing::WithParamInterface<CmdGetTestCase> {};

TEST_F(CmdGetTest, PayloadOverflow) {
  EXPECT_ABS_READ32(base_ + SPI_DEVICE_INTR_STATE_REG_OFFSET, 0);
  EXPECT_ABS_READ32(base_ + SPI_DEVICE_INTR_STATE_REG_OFFSET,
                    {
                        {SPI_DEVICE_INTR_STATE_UPLOAD_CMDFIFO_NOT_EMPTY_BIT, 1},
                        {SPI_DEVICE_INTR_STATE_UPLOAD_PAYLOAD_OVERFLOW_BIT, 1},
                    });
  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_INTR_STATE_REG_OFFSET,
                     std::numeric_limits<uint32_t>::max());

  spi_device_cmd_t cmd;
  EXPECT_EQ(spi_device_cmd_get(&cmd), kErrorSpiDevicePayloadOverflow);
}

TEST_P(CmdGetTest, CmdGet) {
  bool has_address = GetParam().address != kSpiDeviceNoAddress;

  EXPECT_ABS_READ32(base_ + SPI_DEVICE_INTR_STATE_REG_OFFSET, 0);
  EXPECT_ABS_READ32(base_ + SPI_DEVICE_INTR_STATE_REG_OFFSET,
                    {{SPI_DEVICE_INTR_STATE_UPLOAD_CMDFIFO_NOT_EMPTY_BIT, 1}});
  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_INTR_STATE_REG_OFFSET,
                     std::numeric_limits<uint32_t>::max());

  EXPECT_ABS_READ32(base_ + SPI_DEVICE_UPLOAD_CMDFIFO_REG_OFFSET,
                    GetParam().opcode);

  EXPECT_ABS_READ32(
      base_ + SPI_DEVICE_UPLOAD_STATUS_REG_OFFSET,
      {{SPI_DEVICE_UPLOAD_STATUS_ADDRFIFO_NOTEMPTY_BIT, has_address}});
  if (has_address) {
    EXPECT_ABS_READ32(base_ + SPI_DEVICE_UPLOAD_ADDRFIFO_REG_OFFSET,
                      GetParam().address);
  }

  std::vector<uint32_t> payload_area(kSpiDevicePayloadAreaNumWords,
                                     std::numeric_limits<uint32_t>::max());
  std::memcpy(payload_area.data(), GetParam().payload.data(),
              GetParam().payload.size());
  EXPECT_ABS_READ32(base_ + SPI_DEVICE_UPLOAD_STATUS2_REG_OFFSET,
                    {{SPI_DEVICE_UPLOAD_STATUS2_PAYLOAD_DEPTH_OFFSET,
                      GetParam().payload.size()}});
  uint32_t offset =
      base_ + SPI_DEVICE_BUFFER_REG_OFFSET + kSpiDevicePayloadAreaOffset;
  for (size_t i = 0; i < GetParam().payload.size(); i += sizeof(uint32_t)) {
    EXPECT_ABS_READ32(offset + i, payload_area[i / sizeof(uint32_t)]);
  }

  spi_device_cmd_t cmd;
  EXPECT_EQ(spi_device_cmd_get(&cmd), kErrorOk);
  EXPECT_EQ(cmd.opcode, GetParam().opcode);
  EXPECT_EQ(cmd.address, GetParam().address);
  EXPECT_EQ(cmd.payload_byte_count, GetParam().payload.size());
  std::vector<uint8_t> payload(cmd.payload, std::end(cmd.payload));
  payload.resize(cmd.payload_byte_count);
  EXPECT_THAT(payload, GetParam().payload);
}

INSTANTIATE_TEST_SUITE_P(
    CmdGetTestCases, CmdGetTest,
    testing::Values(
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodeChipErase,
            .address = kSpiDeviceNoAddress,
            .payload = {},
        },
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodeSectorErase,
            .address = 0x00,
            .payload = {},
        },
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodePageProgram,
            .address = 0x0a0b0c,
            .payload = {0x01, 0x02, 0x03, 0x04},
        },
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodePageProgram,
            .address = 0x0a0b0c,
            .payload = {0x01, 0x02, 0x03, 0x04, 0x05},
        },
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodePageProgram,
            .address = 0x0a0b0c,
            .payload = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
        },
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodePageProgram,
            .address = 0x0a0b0c,
            .payload = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07},
        },
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodePageProgram,
            .address = 0x0a0b0c,
            .payload = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
        }));

}  // namespace
}  // namespace spi_device_unittest
<commit_msg>[sw/silicon_creator] Fix spi_device_unittest gcc-12 compatibility<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#include "sw/device/silicon_creator/lib/drivers/spi_device.h"

#include <array>
#include <cstring>
#include <limits>

#include "gtest/gtest.h"
#include "sw/device/lib/base/mock_abs_mmio.h"
#include "sw/device/silicon_creator/lib/drivers/mock_lifecycle.h"
#include "sw/device/silicon_creator/lib/error.h"
#include "sw/device/silicon_creator/testing/mask_rom_test.h"

#include "flash_ctrl_regs.h"
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
#include "spi_device_regs.h"

namespace spi_device_unittest {
namespace {
using ::testing::NotNull;
using ::testing::SetArgPointee;

class SpiDeviceTest : public mask_rom_test::MaskRomTest {
 protected:
  uint32_t base_ = TOP_EARLGREY_SPI_DEVICE_BASE_ADDR;
  mask_rom_test::MockAbsMmio mmio_;
  mask_rom_test::MockLifecycle lifecycle_;
};

class InitTest : public SpiDeviceTest {};

TEST_F(InitTest, Init) {
  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_CFG_REG_OFFSET,
                     {
                         {SPI_DEVICE_CFG_CPOL_BIT, 0},
                         {SPI_DEVICE_CFG_CPHA_BIT, 0},
                         {SPI_DEVICE_CFG_TX_ORDER_BIT, 0},
                         {SPI_DEVICE_CFG_RX_ORDER_BIT, 0},
                         {SPI_DEVICE_CFG_TIMER_V_OFFSET, 0x7f},
                         {SPI_DEVICE_CFG_ADDR_4B_EN_BIT, 0},
                         {SPI_DEVICE_CFG_MAILBOX_EN_BIT, 0},
                     });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_JEDEC_CC_REG_OFFSET,
      {
          {SPI_DEVICE_JEDEC_CC_CC_OFFSET, kSpiDeviceJedecContCode},
          {SPI_DEVICE_JEDEC_CC_NUM_CC_OFFSET, kSpiDeviceJedecContCodeCount},
      });
  lifecycle_hw_rev_t hw_rev{
      .chip_gen = 1,
      .chip_rev = 3,
  };
  EXPECT_CALL(lifecycle_, HwRev(NotNull())).WillOnce(SetArgPointee<0>(hw_rev));
  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_JEDEC_ID_REG_OFFSET,
      {
          {SPI_DEVICE_DEV_ID_CHIP_REV_FIELD.index, hw_rev.chip_rev},
          {SPI_DEVICE_DEV_ID_ROM_BOOTSTRAP_BIT, 1},
          {SPI_DEVICE_DEV_ID_CHIP_GEN_FIELD.index, hw_rev.chip_gen},
          {SPI_DEVICE_DEV_ID_DENSITY_FIELD.index,
           (uint32_t)bitfield_count_trailing_zeroes32(
               FLASH_CTRL_PARAM_REG_NUM_BANKS *
               FLASH_CTRL_PARAM_BYTES_PER_BANK)},
          {SPI_DEVICE_JEDEC_ID_MF_OFFSET, kSpiDeviceJedecManufId},
      });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_CMD_INFO_0_REG_OFFSET,
      {
          {SPI_DEVICE_CMD_INFO_0_OPCODE_0_OFFSET, kSpiDeviceOpcodeReadStatus},
          {SPI_DEVICE_CMD_INFO_0_VALID_0_BIT, 1},
      });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_CMD_INFO_3_REG_OFFSET,
      {
          {SPI_DEVICE_CMD_INFO_3_OPCODE_3_OFFSET, kSpiDeviceOpcodeReadJedecId},
          {SPI_DEVICE_CMD_INFO_3_VALID_3_BIT, 1},
      });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_CMD_INFO_4_REG_OFFSET,
      {
          {SPI_DEVICE_CMD_INFO_4_OPCODE_4_OFFSET, kSpiDeviceOpcodeReadSfdp},
          {SPI_DEVICE_CMD_INFO_4_ADDR_MODE_4_OFFSET,
           SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDR3B},
          {SPI_DEVICE_CMD_INFO_4_DUMMY_SIZE_4_OFFSET, 7},
          {SPI_DEVICE_CMD_INFO_4_DUMMY_EN_4_BIT, 1},
          {SPI_DEVICE_CMD_INFO_4_VALID_4_BIT, 1},
      });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_CMD_INFO_11_REG_OFFSET,
      {
          {SPI_DEVICE_CMD_INFO_11_OPCODE_11_OFFSET, kSpiDeviceOpcodeChipErase},
          {SPI_DEVICE_CMD_INFO_11_UPLOAD_11_BIT, 1},
          {SPI_DEVICE_CMD_INFO_11_BUSY_11_BIT, 1},
          {SPI_DEVICE_CMD_INFO_11_VALID_11_BIT, 1},
      });

  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_CMD_INFO_12_REG_OFFSET,
                     {
                         {SPI_DEVICE_CMD_INFO_12_OPCODE_12_OFFSET,
                          kSpiDeviceOpcodeSectorErase},
                         {SPI_DEVICE_CMD_INFO_12_ADDR_MODE_12_OFFSET,
                          SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDR3B},
                         {SPI_DEVICE_CMD_INFO_12_UPLOAD_12_BIT, 1},
                         {SPI_DEVICE_CMD_INFO_12_BUSY_12_BIT, 1},
                         {SPI_DEVICE_CMD_INFO_12_VALID_12_BIT, 1},
                     });

  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_CMD_INFO_13_REG_OFFSET,
                     {
                         {SPI_DEVICE_CMD_INFO_13_OPCODE_13_OFFSET,
                          kSpiDeviceOpcodePageProgram},
                         {SPI_DEVICE_CMD_INFO_13_ADDR_MODE_13_OFFSET,
                          SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDR3B},
                         {SPI_DEVICE_CMD_INFO_13_UPLOAD_13_BIT, 1},
                         {SPI_DEVICE_CMD_INFO_13_BUSY_13_BIT, 1},
                         {SPI_DEVICE_CMD_INFO_13_VALID_13_BIT, 1},
                     });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_CMD_INFO_14_REG_OFFSET,
      {
          {SPI_DEVICE_CMD_INFO_14_OPCODE_14_OFFSET, kSpiDeviceOpcodeReset},
          {SPI_DEVICE_CMD_INFO_14_UPLOAD_14_BIT, 1},
          {SPI_DEVICE_CMD_INFO_14_BUSY_14_BIT, 1},
          {SPI_DEVICE_CMD_INFO_14_VALID_14_BIT, 1},
      });

  EXPECT_ABS_WRITE32(
      base_ + SPI_DEVICE_CMD_INFO_WREN_REG_OFFSET,
      {
          {SPI_DEVICE_CMD_INFO_WREN_OPCODE_OFFSET, kSpiDeviceOpcodeWriteEnable},
          {SPI_DEVICE_CMD_INFO_WREN_VALID_BIT, 1},
      });

  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_CMD_INFO_WRDI_REG_OFFSET,
                     {
                         {SPI_DEVICE_CMD_INFO_WRDI_OPCODE_OFFSET,
                          kSpiDeviceOpcodeWriteDisable},
                         {SPI_DEVICE_CMD_INFO_WRDI_VALID_BIT, 1},
                     });

  std::array<uint32_t, kSpiDeviceSfdpAreaNumBytes / sizeof(uint32_t)>
      sfdp_buffer;
  sfdp_buffer.fill(std::numeric_limits<uint32_t>::max());
  std::memcpy(sfdp_buffer.data(), &kSpiDeviceSfdpTable,
              sizeof(kSpiDeviceSfdpTable));
  uint32_t offset =
      base_ + SPI_DEVICE_BUFFER_REG_OFFSET + kSpiDeviceSfdpAreaOffset;
  for (size_t i = 0; i < sfdp_buffer.size(); ++i) {
    EXPECT_ABS_WRITE32(offset, sfdp_buffer[i]);
    offset += sizeof(uint32_t);
  }

  offset = base_ + SPI_DEVICE_BUFFER_REG_OFFSET + kSpiDevicePayloadAreaOffset;
  for (size_t i = 0; i < kSpiDevicePayloadAreaNumWords; ++i) {
    EXPECT_ABS_WRITE32(offset, 0);
    offset += sizeof(uint32_t);
  }

  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_FLASH_STATUS_REG_OFFSET, 0);

  spi_device_init();
}

TEST_F(SpiDeviceTest, FlashStatusClear) {
  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_FLASH_STATUS_REG_OFFSET, 0);

  spi_device_flash_status_clear();
}

TEST_F(SpiDeviceTest, FlashStatusGet) {
  EXPECT_ABS_READ32(base_ + SPI_DEVICE_FLASH_STATUS_REG_OFFSET, 0xa5);

  EXPECT_EQ(0xa5, spi_device_flash_status_get());
}

struct CmdGetTestCase {
  spi_device_opcode_t opcode;
  uint32_t address;
  std::vector<uint8_t> payload;
};

class CmdGetTest : public SpiDeviceTest,
                   public testing::WithParamInterface<CmdGetTestCase> {};

TEST_F(CmdGetTest, PayloadOverflow) {
  EXPECT_ABS_READ32(base_ + SPI_DEVICE_INTR_STATE_REG_OFFSET, 0);
  EXPECT_ABS_READ32(base_ + SPI_DEVICE_INTR_STATE_REG_OFFSET,
                    {
                        {SPI_DEVICE_INTR_STATE_UPLOAD_CMDFIFO_NOT_EMPTY_BIT, 1},
                        {SPI_DEVICE_INTR_STATE_UPLOAD_PAYLOAD_OVERFLOW_BIT, 1},
                    });
  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_INTR_STATE_REG_OFFSET,
                     std::numeric_limits<uint32_t>::max());

  spi_device_cmd_t cmd;
  EXPECT_EQ(spi_device_cmd_get(&cmd), kErrorSpiDevicePayloadOverflow);
}

TEST_P(CmdGetTest, CmdGet) {
  bool has_address = GetParam().address != kSpiDeviceNoAddress;

  EXPECT_ABS_READ32(base_ + SPI_DEVICE_INTR_STATE_REG_OFFSET, 0);
  EXPECT_ABS_READ32(base_ + SPI_DEVICE_INTR_STATE_REG_OFFSET,
                    {{SPI_DEVICE_INTR_STATE_UPLOAD_CMDFIFO_NOT_EMPTY_BIT, 1}});
  EXPECT_ABS_WRITE32(base_ + SPI_DEVICE_INTR_STATE_REG_OFFSET,
                     std::numeric_limits<uint32_t>::max());

  EXPECT_ABS_READ32(base_ + SPI_DEVICE_UPLOAD_CMDFIFO_REG_OFFSET,
                    GetParam().opcode);

  EXPECT_ABS_READ32(
      base_ + SPI_DEVICE_UPLOAD_STATUS_REG_OFFSET,
      {{SPI_DEVICE_UPLOAD_STATUS_ADDRFIFO_NOTEMPTY_BIT, has_address}});
  if (has_address) {
    EXPECT_ABS_READ32(base_ + SPI_DEVICE_UPLOAD_ADDRFIFO_REG_OFFSET,
                      GetParam().address);
  }

  std::vector<uint32_t> payload_area(kSpiDevicePayloadAreaNumWords,
                                     std::numeric_limits<uint32_t>::max());
  std::memcpy(payload_area.data(), GetParam().payload.data(),
              GetParam().payload.size());
  EXPECT_ABS_READ32(base_ + SPI_DEVICE_UPLOAD_STATUS2_REG_OFFSET,
                    {{SPI_DEVICE_UPLOAD_STATUS2_PAYLOAD_DEPTH_OFFSET,
                      GetParam().payload.size()}});
  uint32_t offset =
      base_ + SPI_DEVICE_BUFFER_REG_OFFSET + kSpiDevicePayloadAreaOffset;
  for (size_t i = 0; i < GetParam().payload.size(); i += sizeof(uint32_t)) {
    EXPECT_ABS_READ32(offset + i, payload_area[i / sizeof(uint32_t)]);
  }

  spi_device_cmd_t cmd;
  EXPECT_EQ(spi_device_cmd_get(&cmd), kErrorOk);
  EXPECT_EQ(cmd.opcode, GetParam().opcode);
  EXPECT_EQ(cmd.address, GetParam().address);
  EXPECT_EQ(cmd.payload_byte_count, GetParam().payload.size());
  std::vector<uint8_t> payload(cmd.payload, std::end(cmd.payload));
  payload.resize(cmd.payload_byte_count);
  EXPECT_THAT(payload, GetParam().payload);
}

INSTANTIATE_TEST_SUITE_P(
    CmdGetTestCases, CmdGetTest,
    testing::Values(
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodeChipErase,
            .address = kSpiDeviceNoAddress,
            .payload = {},
        },
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodeSectorErase,
            .address = 0x00,
            .payload = {},
        },
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodePageProgram,
            .address = 0x0a0b0c,
            .payload = {0x01, 0x02, 0x03, 0x04},
        },
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodePageProgram,
            .address = 0x0a0b0c,
            .payload = {0x01, 0x02, 0x03, 0x04, 0x05},
        },
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodePageProgram,
            .address = 0x0a0b0c,
            .payload = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06},
        },
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodePageProgram,
            .address = 0x0a0b0c,
            .payload = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07},
        },
        CmdGetTestCase{
            .opcode = kSpiDeviceOpcodePageProgram,
            .address = 0x0a0b0c,
            .payload = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
        }));

}  // namespace
}  // namespace spi_device_unittest
<|endoftext|>


<commit_before>/*  Copyright (c) MediaArea.net SARL. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license that can
 *  be found in the License.html file in the root of the source tree.
 */

//---------------------------------------------------------------------------
#include "GUI/Common/GUI_Main_Easy_Box_Core.h"
#include "GUI/Common/GUI_Main_Easy_Core.h"
#include "ZenLib/Conf.h"
using namespace ZenLib;
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
const size_t Title_Pos=94; //TODO: Position of Title in General.csv, should shange this...
//---------------------------------------------------------------------------

//***************************************************************************
// Constructor/Destructor
//***************************************************************************

//---------------------------------------------------------------------------
GUI_Main_Easy_Box_Core::GUI_Main_Easy_Box_Core(Core* Core_, GUI_Main_Easy_Core* Parent_Core_, stream_t StreamKind, size_t StreamPos)
{
    //Internal
    C=Core_;
    Parent_Core=Parent_Core_;

    //Configuration
    GUI_Main_Easy_Box_Core::StreamKind=StreamKind;
    GUI_Main_Easy_Box_Core::StreamPos=StreamPos;
}

//***************************************************************************
// Actions - Per StreamKind
//***************************************************************************

//---------------------------------------------------------------------------
size_t GUI_Main_Easy_Box_Core::Boxes_Count_Get()
{
    return Parent_Core->Boxes_Count_Get(StreamKind);
}

//---------------------------------------------------------------------------
size_t GUI_Main_Easy_Box_Core::Boxes_Show_Get()
{
    size_t StreamCount=Parent_Core->StreamsCount_Get(StreamKind);
    if (Parent_Core->StreamsCount_Get(Stream_General)==0)
        StreamCount=Boxes_Count_Get();
    if (StreamCount>Boxes_Count_Get())
        StreamCount=Boxes_Count_Get();
    return StreamCount;
}

//---------------------------------------------------------------------------
size_t GUI_Main_Easy_Box_Core::Lines_Count_Get()
{
    switch (StreamKind)
    {
        case 0 : return 5;
        case 1 : return 2;
        case 2 : return 2;
        case 3 : return 2;
        default: return 0;
    }
}

//***************************************************************************
// Actions - Per Stream
//***************************************************************************

//---------------------------------------------------------------------------
bool GUI_Main_Easy_Box_Core::MustHide()
{
    size_t StreamCount=C->MI->Count_Get(Parent_Core->FilesPos_Get(), StreamKind);
    if (Parent_Core->StreamsCount_Get(Stream_General)==0)
        StreamCount=Boxes_Count_Get();
    if (StreamCount<=StreamPos)
        return true;
    else
        return false;
}

//---------------------------------------------------------------------------
bool GUI_Main_Easy_Box_Core::IsLastBox()
{
    if (StreamPos+1==Boxes_Show_Get())
        return true;
    else
        return false;
}

//---------------------------------------------------------------------------
String GUI_Main_Easy_Box_Core::Box_Get()
{
    String Temp;
    switch (StreamKind)
    {
        case Stream_General : Temp=__T("General"); break;
        case Stream_Video   : Temp=__T("Video");   break;
        case Stream_Audio   : Temp=__T("Audio");   break;
        case Stream_Text    : Temp=__T("Text");    break;
        default             : Temp=__T("");
    }

    return Temp;
}

//---------------------------------------------------------------------------
String GUI_Main_Easy_Box_Core::Text_Get()
{
    //First line
    if (Lines_Count_Get()==0)
        return __T("");
    String Temp=Parent_Core->Summary_Get(StreamKind, StreamPos);

    //Depend of StreamKind
    if (Parent_Core->StreamsCount_Get(Stream_General)==0)
    {
        //Empty box
        Temp+=EOL;
        Temp+=EOL;
    }
    else if (StreamKind==Stream_General)
    {
        //Stream_General
        size_t Lines=1;
        for (int KindOfStream=1; KindOfStream<Stream_Max; KindOfStream++)
        {
            if (C->MI->Count_Get(Parent_Core->FilesPos_Get(), (stream_t)KindOfStream)>0)
            {
                String Z1=String(C->MI->Get(Parent_Core->FilesPos_Get(), (stream_t)KindOfStream, 0, __T("StreamKind"), Info_Measure))+__T("StreamCount");
                String Z2=String(__T(" "))+C->MI->Get(Parent_Core->FilesPos_Get(), (stream_t)KindOfStream, 0, __T("StreamKind"), Info_Text);
                if (C->MI->Count_Get(Parent_Core->FilesPos_Get(), (stream_t)KindOfStream)==1)
                    Z2+=__T(" stream");//__T(" stream1");
                else
                    Z2+=__T(" streams");//__T(" stream2");
                String Z3=String(C->MI->Get(Parent_Core->FilesPos_Get(), (stream_t)KindOfStream, 0, __T("StreamKind"), Info_Text)+__T("_Format_WithHint_List"));
                Temp+=EOL;
                Temp+=(C->MI->Get(Parent_Core->FilesPos_Get(), (stream_t)KindOfStream, 0, Z1)+/*Prefs->Translate(*/Z2/*)*/+/*Prefs->Translate(*/__T(": ")/*)*/+C->MI->Get(Parent_Core->FilesPos_Get(), Stream_General, 0, Z3)).c_str();
                Lines++;
            }

            if (Lines>=Lines_Count_Get())
                KindOfStream=Stream_Max;
        }
    }
    else if (Lines_Count_Get()>1)
    {
        //Other than Stream_General
        String Title=C->MI->Get(Parent_Core->FilesPos_Get(), StreamKind, StreamPos, __T("Title"));
        if (!Title.empty())
        {
            Temp+=EOL;
            Temp+=Title;
        }
    }

    return Temp.c_str();
}

//---------------------------------------------------------------------------
String GUI_Main_Easy_Box_Core::ToolTip_Get()
{
    return Parent_Core->Inform_Get(StreamKind, StreamPos);
}

//---------------------------------------------------------------------------
String GUI_Main_Easy_Box_Core::Tags_Get()
{
    //First line
    if (StreamKind!=Stream_General || Lines_Count_Get()==0)
        return __T("");

    size_t MI_Pos=Title_Pos; //Should begin with "Title"
    size_t MI_Max=C->MI->Count_Get(Parent_Core->FilesPos_Get(), Stream_General, 0);
    String Temp;
    size_t Lines=0;
    while(MI_Pos<MI_Max)
    {
        String Z1=C->MI->Get(Parent_Core->FilesPos_Get(), Stream_General, 0, MI_Pos);
        String Options=C->MI->Get(Parent_Core->FilesPos_Get(), Stream_General, 0, MI_Pos, Info_Options);
        if (Options.size()>InfoOption_ShowInInform && Options[InfoOption_ShowInInform]==__T('Y') && Z1.size()>0)
        {
            String Z2=C->MI->Get(Parent_Core->FilesPos_Get(), Stream_General, 0, MI_Pos, Info_Name_Text);
            if (Z2.size()==0)
                Z2=C->MI->Get(Parent_Core->FilesPos_Get(), Stream_General, 0, MI_Pos, Info_Name);
            Z2+=/*Prefs->Translate(*/__T(": ")/*)*/;
            Z2+=Z1;
            if (Lines>0)
                Temp+=EOL;
            Temp+=Z2;

            Lines++;
            if (Lines>=Lines_Count_Get())
                MI_Pos=MI_Max;
        }
        MI_Pos++;
    }

    return Temp;
}

//---------------------------------------------------------------------------
String GUI_Main_Easy_Box_Core::Button_Get()
{
    if (StreamKind==Stream_General)
        return __T("Go to the website of a player for this file");
    else
        return __T("Go to the website of this codec");
}

//---------------------------------------------------------------------------
bool GUI_Main_Easy_Box_Core::Button_Show()
{
    if (Parent_Core->CodecID_Url_Get(StreamKind, StreamPos).empty())
        return false;
    else
        return true;
}

//---------------------------------------------------------------------------
String GUI_Main_Easy_Box_Core::Button_Click()
{
    return Parent_Core->CodecID_Url_Get(StreamKind, StreamPos);
}

<commit_msg>x List of fields in GUI metadata part was not starting at the right field<commit_after>/*  Copyright (c) MediaArea.net SARL. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license that can
 *  be found in the License.html file in the root of the source tree.
 */

//---------------------------------------------------------------------------
#include "GUI/Common/GUI_Main_Easy_Box_Core.h"
#include "GUI/Common/GUI_Main_Easy_Core.h"
#include "ZenLib/Conf.h"
using namespace ZenLib;
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
const size_t Title_Pos=156; //TODO: Position of Title in General.csv, should shange this...
//---------------------------------------------------------------------------

//***************************************************************************
// Constructor/Destructor
//***************************************************************************

//---------------------------------------------------------------------------
GUI_Main_Easy_Box_Core::GUI_Main_Easy_Box_Core(Core* Core_, GUI_Main_Easy_Core* Parent_Core_, stream_t StreamKind, size_t StreamPos)
{
    //Internal
    C=Core_;
    Parent_Core=Parent_Core_;

    //Configuration
    GUI_Main_Easy_Box_Core::StreamKind=StreamKind;
    GUI_Main_Easy_Box_Core::StreamPos=StreamPos;
}

//***************************************************************************
// Actions - Per StreamKind
//***************************************************************************

//---------------------------------------------------------------------------
size_t GUI_Main_Easy_Box_Core::Boxes_Count_Get()
{
    return Parent_Core->Boxes_Count_Get(StreamKind);
}

//---------------------------------------------------------------------------
size_t GUI_Main_Easy_Box_Core::Boxes_Show_Get()
{
    size_t StreamCount=Parent_Core->StreamsCount_Get(StreamKind);
    if (Parent_Core->StreamsCount_Get(Stream_General)==0)
        StreamCount=Boxes_Count_Get();
    if (StreamCount>Boxes_Count_Get())
        StreamCount=Boxes_Count_Get();
    return StreamCount;
}

//---------------------------------------------------------------------------
size_t GUI_Main_Easy_Box_Core::Lines_Count_Get()
{
    switch (StreamKind)
    {
        case 0 : return 5;
        case 1 : return 2;
        case 2 : return 2;
        case 3 : return 2;
        default: return 0;
    }
}

//***************************************************************************
// Actions - Per Stream
//***************************************************************************

//---------------------------------------------------------------------------
bool GUI_Main_Easy_Box_Core::MustHide()
{
    size_t StreamCount=C->MI->Count_Get(Parent_Core->FilesPos_Get(), StreamKind);
    if (Parent_Core->StreamsCount_Get(Stream_General)==0)
        StreamCount=Boxes_Count_Get();
    if (StreamCount<=StreamPos)
        return true;
    else
        return false;
}

//---------------------------------------------------------------------------
bool GUI_Main_Easy_Box_Core::IsLastBox()
{
    if (StreamPos+1==Boxes_Show_Get())
        return true;
    else
        return false;
}

//---------------------------------------------------------------------------
String GUI_Main_Easy_Box_Core::Box_Get()
{
    String Temp;
    switch (StreamKind)
    {
        case Stream_General : Temp=__T("General"); break;
        case Stream_Video   : Temp=__T("Video");   break;
        case Stream_Audio   : Temp=__T("Audio");   break;
        case Stream_Text    : Temp=__T("Text");    break;
        default             : Temp=__T("");
    }

    return Temp;
}

//---------------------------------------------------------------------------
String GUI_Main_Easy_Box_Core::Text_Get()
{
    //First line
    if (Lines_Count_Get()==0)
        return __T("");
    String Temp=Parent_Core->Summary_Get(StreamKind, StreamPos);

    //Depend of StreamKind
    if (Parent_Core->StreamsCount_Get(Stream_General)==0)
    {
        //Empty box
        Temp+=EOL;
        Temp+=EOL;
    }
    else if (StreamKind==Stream_General)
    {
        //Stream_General
        size_t Lines=1;
        for (int KindOfStream=1; KindOfStream<Stream_Max; KindOfStream++)
        {
            if (C->MI->Count_Get(Parent_Core->FilesPos_Get(), (stream_t)KindOfStream)>0)
            {
                String Z1=String(C->MI->Get(Parent_Core->FilesPos_Get(), (stream_t)KindOfStream, 0, __T("StreamKind"), Info_Measure))+__T("StreamCount");
                String Z2=String(__T(" "))+C->MI->Get(Parent_Core->FilesPos_Get(), (stream_t)KindOfStream, 0, __T("StreamKind"), Info_Text);
                if (C->MI->Count_Get(Parent_Core->FilesPos_Get(), (stream_t)KindOfStream)==1)
                    Z2+=__T(" stream");//__T(" stream1");
                else
                    Z2+=__T(" streams");//__T(" stream2");
                String Z3=String(C->MI->Get(Parent_Core->FilesPos_Get(), (stream_t)KindOfStream, 0, __T("StreamKind"), Info_Text)+__T("_Format_WithHint_List"));
                Temp+=EOL;
                Temp+=(C->MI->Get(Parent_Core->FilesPos_Get(), (stream_t)KindOfStream, 0, Z1)+/*Prefs->Translate(*/Z2/*)*/+/*Prefs->Translate(*/__T(": ")/*)*/+C->MI->Get(Parent_Core->FilesPos_Get(), Stream_General, 0, Z3)).c_str();
                Lines++;
            }

            if (Lines>=Lines_Count_Get())
                KindOfStream=Stream_Max;
        }
    }
    else if (Lines_Count_Get()>1)
    {
        //Other than Stream_General
        String Title=C->MI->Get(Parent_Core->FilesPos_Get(), StreamKind, StreamPos, __T("Title"));
        if (!Title.empty())
        {
            Temp+=EOL;
            Temp+=Title;
        }
    }

    return Temp.c_str();
}

//---------------------------------------------------------------------------
String GUI_Main_Easy_Box_Core::ToolTip_Get()
{
    return Parent_Core->Inform_Get(StreamKind, StreamPos);
}

//---------------------------------------------------------------------------
String GUI_Main_Easy_Box_Core::Tags_Get()
{
    //First line
    if (StreamKind!=Stream_General || Lines_Count_Get()==0)
        return __T("");

    size_t MI_Pos=Title_Pos; //Should begin with "Title"
    size_t MI_Max=C->MI->Count_Get(Parent_Core->FilesPos_Get(), Stream_General, 0);
    String Temp;
    size_t Lines=0;
    while(MI_Pos<MI_Max)
    {
        String Z1=C->MI->Get(Parent_Core->FilesPos_Get(), Stream_General, 0, MI_Pos);
        String Options=C->MI->Get(Parent_Core->FilesPos_Get(), Stream_General, 0, MI_Pos, Info_Options);
        if (Options.size()>InfoOption_ShowInInform && Options[InfoOption_ShowInInform]==__T('Y') && Z1.size()>0)
        {
            String Z2=C->MI->Get(Parent_Core->FilesPos_Get(), Stream_General, 0, MI_Pos, Info_Name_Text);
            if (Z2.size()==0)
                Z2=C->MI->Get(Parent_Core->FilesPos_Get(), Stream_General, 0, MI_Pos, Info_Name);
            Z2+=/*Prefs->Translate(*/__T(": ")/*)*/;
            Z2+=Z1;
            if (Lines>0)
                Temp+=EOL;
            Temp+=Z2;

            Lines++;
            if (Lines>=Lines_Count_Get())
                MI_Pos=MI_Max;
        }
        MI_Pos++;
    }

    return Temp;
}

//---------------------------------------------------------------------------
String GUI_Main_Easy_Box_Core::Button_Get()
{
    if (StreamKind==Stream_General)
        return __T("Go to the website of a player for this file");
    else
        return __T("Go to the website of this codec");
}

//---------------------------------------------------------------------------
bool GUI_Main_Easy_Box_Core::Button_Show()
{
    if (Parent_Core->CodecID_Url_Get(StreamKind, StreamPos).empty())
        return false;
    else
        return true;
}

//---------------------------------------------------------------------------
String GUI_Main_Easy_Box_Core::Button_Click()
{
    return Parent_Core->CodecID_Url_Get(StreamKind, StreamPos);
}

<|endoftext|>


<commit_before>#include "../Flare.h"
#include "FlareSectorHelper.h"
#include "../Economy/FlareCargoBay.h"
#include "FlareCompany.h"

UFlareSimulatedSpacecraft*  SectorHelper::FindTradeStation(FlareTradeRequest Request)
{
	if(!Request.Client || !Request.Client->GetCurrentSector())
	{
		FLOG("Invalid find trade query");
		return NULL;
	}

	UFlareSimulatedSector* Sector = Request.Client->GetCurrentSector();
	TArray<UFlareSimulatedSpacecraft*>& SectorStations = Sector->GetSectorStations();

	float UnloadQuantityScoreMultiplier = 0;
	float LoadQuantityScoreMultiplier = 0;
	float SellQuantityScoreMultiplier = 0;
	float BuyQuantityScoreMultiplier = 0;
	float FullRatioBonus = 0;
	float EmptyRatioBonus = 0;
	bool  NeedInput = false;
	bool  NeedOutput = false;

	switch(Request.Operation)
	{
		case EFlareTradeRouteOperation::Buy:
			BuyQuantityScoreMultiplier = 10.f;
			FullRatioBonus = 0.1;
			NeedOutput = true;
		break;
		case EFlareTradeRouteOperation::Sell:
			SellQuantityScoreMultiplier = 10.f;
			EmptyRatioBonus = 0.1;
			NeedInput = true;
		break;
		case EFlareTradeRouteOperation::Load:
			LoadQuantityScoreMultiplier = 10.f;
			FullRatioBonus = 0.1;
			NeedOutput = true;
		break;
		case EFlareTradeRouteOperation::Unload:
			UnloadQuantityScoreMultiplier = 10.f;
			EmptyRatioBonus = 0.1;
			NeedInput = true;
		break;
		case EFlareTradeRouteOperation::LoadOrBuy:
			LoadQuantityScoreMultiplier = 10.f;
			BuyQuantityScoreMultiplier = 1.f;
			FullRatioBonus = 0.1;
			NeedOutput = true;
		break;
		case EFlareTradeRouteOperation::UnloadOrSell:
			UnloadQuantityScoreMultiplier = 10.f;
			SellQuantityScoreMultiplier = 1.f;
			EmptyRatioBonus = 0.1;
			NeedInput = true;
		break;
	}

	float BestScore = 0;
	UFlareSimulatedSpacecraft* BestStation = NULL;
	uint32 AvailableQuantity = Request.Client->GetCargoBay()->GetResourceQuantity(Request.Resource, Request.Client->GetCompany());
	uint32 FreeSpace = Request.Client->GetCargoBay()->GetFreeSpaceForResource(Request.Resource, Request.Client->GetCompany());

	for (int32 StationIndex = 0; StationIndex < SectorStations.Num(); StationIndex++)
	{
		UFlareSimulatedSpacecraft* Station = SectorStations[StationIndex];

		if(!Request.Client->CanTradeWith(Station))
		{
			continue;
		}
		EFlareResourcePriceContext::Type StationResourceUsage = Station->GetResourceUseType(Request.Resource);

		if(NeedOutput && StationResourceUsage != EFlareResourcePriceContext::FactoryOutput)
		{
			continue;
		}

		if(NeedInput && (StationResourceUsage != EFlareResourcePriceContext::FactoryInput &&
						 StationResourceUsage != EFlareResourcePriceContext::ConsumerConsumption &&
						 StationResourceUsage != EFlareResourcePriceContext::MaintenanceConsumption))
		{
			continue;
		}

		uint32 StationFreeSpace = Station->GetCargoBay()->GetFreeSpaceForResource(Request.Resource, Request.Client->GetCompany());
		uint32 StationResourceQuantity = Station->GetCargoBay()->GetResourceQuantity(Request.Resource, Request.Client->GetCompany());

		if (StationFreeSpace == 0 && StationResourceQuantity == 0)
		{
			continue;
		}

		float Score = 0;
		float FullRatio =  (float) StationResourceQuantity / (float) (StationResourceQuantity + StationFreeSpace);
		float EmptyRatio = 1 - FullRatio;
		uint32 UnloadMaxQuantity  = 0;
		uint32 LoadMaxQuantity  = 0;

		if(Station->GetCargoBay()->WantBuy(Request.Resource, Request.Client->GetCompany()))
		{
			UnloadMaxQuantity = StationFreeSpace;
			UnloadMaxQuantity  = FMath::Min(UnloadMaxQuantity , AvailableQuantity);
		}

		if(Station->GetCargoBay()->WantSell(Request.Resource, Request.Client->GetCompany()))
		{
			LoadMaxQuantity = StationResourceQuantity;
			LoadMaxQuantity = FMath::Min(LoadMaxQuantity , FreeSpace);
		}

		if(Station->GetCompany() == Request.Client->GetCompany())
		{
			Score += UnloadMaxQuantity * UnloadQuantityScoreMultiplier;
			Score += LoadMaxQuantity * LoadQuantityScoreMultiplier;
		}
		else
		{
			EFlareResourcePriceContext::Type ResourceUsage = Station->GetResourceUseType(Request.Resource);

			uint32 MaxBuyableQuantity = Request.Client->GetCompany()->GetMoney() / Sector->GetResourcePrice(Request.Resource, ResourceUsage);
			LoadMaxQuantity = FMath::Min(LoadMaxQuantity , MaxBuyableQuantity);

			uint32 MaxSellableQuantity = Station->GetCompany()->GetMoney() / Sector->GetResourcePrice(Request.Resource, ResourceUsage);
			UnloadMaxQuantity = FMath::Min(UnloadMaxQuantity , MaxSellableQuantity);

			Score += UnloadMaxQuantity * SellQuantityScoreMultiplier;
			Score += LoadMaxQuantity * BuyQuantityScoreMultiplier;
		}

		Score *= 1 + (FullRatio * FullRatioBonus) + (EmptyRatio * EmptyRatioBonus);

		if(Score > 0 && Score > BestScore)
		{
			BestScore = Score;
			BestStation = Station;
		}
	}

	return BestStation;
}

int32 SectorHelper::Trade(UFlareSimulatedSpacecraft*  SourceSpacecraft, UFlareSimulatedSpacecraft* DestinationSpacecraft, FFlareResourceDescription* Resource, int32 MaxQuantity)
{
	if(!SourceSpacecraft->CanTradeWith(DestinationSpacecraft))
	{
		FLOG("Both spacecraft cannot trade");
		return 0;
	}

	int32 ResourcePrice = SourceSpacecraft->GetCurrentSector()->GetTransfertResourcePrice(SourceSpacecraft, DestinationSpacecraft, Resource);
	int32 QuantityToTake = MaxQuantity;

	if (SourceSpacecraft->GetCompany() != DestinationSpacecraft->GetCompany())
	{
		// Limit transaction bay available money
		int32 MaxAffordableQuantity = DestinationSpacecraft->GetCompany()->GetMoney() / ResourcePrice;
		QuantityToTake = FMath::Min(QuantityToTake, MaxAffordableQuantity);
	}
	int32 ResourceCapacity = DestinationSpacecraft->GetCargoBay()->GetFreeSpaceForResource(Resource, SourceSpacecraft->GetCompany());

	QuantityToTake = FMath::Min(QuantityToTake, ResourceCapacity);

	int32 TakenResources = SourceSpacecraft->GetCargoBay()->TakeResources(Resource, QuantityToTake, DestinationSpacecraft->GetCompany());
	int32 GivenResources = DestinationSpacecraft->GetCargoBay()->GiveResources(Resource, TakenResources, SourceSpacecraft->GetCompany());

	if (GivenResources > 0 && SourceSpacecraft->GetCompany() != DestinationSpacecraft->GetCompany())
	{
		// Pay
		int64 Price = ResourcePrice * GivenResources;
		DestinationSpacecraft->GetCompany()->TakeMoney(Price);
		SourceSpacecraft->GetCompany()->GiveMoney(Price);

		SourceSpacecraft->GetCompany()->GiveReputation(DestinationSpacecraft->GetCompany(), 0.5f, true);
		DestinationSpacecraft->GetCompany()->GiveReputation(SourceSpacecraft->GetCompany(), 0.5f, true);
	}

	if(GivenResources > 0)
	{
		if(!SourceSpacecraft->IsStation())
		{
			SourceSpacecraft->SetTrading(true);
		}

		if(!DestinationSpacecraft->IsStation())
		{
			DestinationSpacecraft->SetTrading(true);
		}
	}

	return GivenResources;

}
<commit_msg>#433 Don't put the player ship in the trading state when in FPV<commit_after>#include "../Flare.h"
#include "FlareSectorHelper.h"

#include "FlareCompany.h"
#include "../Game/FlareGame.h"
#include "../Economy/FlareCargoBay.h"
#include "../Player/FlarePlayerController.h"

UFlareSimulatedSpacecraft*  SectorHelper::FindTradeStation(FlareTradeRequest Request)
{
	if(!Request.Client || !Request.Client->GetCurrentSector())
	{
		FLOG("Invalid find trade query");
		return NULL;
	}

	UFlareSimulatedSector* Sector = Request.Client->GetCurrentSector();
	TArray<UFlareSimulatedSpacecraft*>& SectorStations = Sector->GetSectorStations();

	float UnloadQuantityScoreMultiplier = 0;
	float LoadQuantityScoreMultiplier = 0;
	float SellQuantityScoreMultiplier = 0;
	float BuyQuantityScoreMultiplier = 0;
	float FullRatioBonus = 0;
	float EmptyRatioBonus = 0;
	bool  NeedInput = false;
	bool  NeedOutput = false;

	switch(Request.Operation)
	{
		case EFlareTradeRouteOperation::Buy:
			BuyQuantityScoreMultiplier = 10.f;
			FullRatioBonus = 0.1;
			NeedOutput = true;
		break;
		case EFlareTradeRouteOperation::Sell:
			SellQuantityScoreMultiplier = 10.f;
			EmptyRatioBonus = 0.1;
			NeedInput = true;
		break;
		case EFlareTradeRouteOperation::Load:
			LoadQuantityScoreMultiplier = 10.f;
			FullRatioBonus = 0.1;
			NeedOutput = true;
		break;
		case EFlareTradeRouteOperation::Unload:
			UnloadQuantityScoreMultiplier = 10.f;
			EmptyRatioBonus = 0.1;
			NeedInput = true;
		break;
		case EFlareTradeRouteOperation::LoadOrBuy:
			LoadQuantityScoreMultiplier = 10.f;
			BuyQuantityScoreMultiplier = 1.f;
			FullRatioBonus = 0.1;
			NeedOutput = true;
		break;
		case EFlareTradeRouteOperation::UnloadOrSell:
			UnloadQuantityScoreMultiplier = 10.f;
			SellQuantityScoreMultiplier = 1.f;
			EmptyRatioBonus = 0.1;
			NeedInput = true;
		break;
	}

	float BestScore = 0;
	UFlareSimulatedSpacecraft* BestStation = NULL;
	uint32 AvailableQuantity = Request.Client->GetCargoBay()->GetResourceQuantity(Request.Resource, Request.Client->GetCompany());
	uint32 FreeSpace = Request.Client->GetCargoBay()->GetFreeSpaceForResource(Request.Resource, Request.Client->GetCompany());

	for (int32 StationIndex = 0; StationIndex < SectorStations.Num(); StationIndex++)
	{
		UFlareSimulatedSpacecraft* Station = SectorStations[StationIndex];

		if(!Request.Client->CanTradeWith(Station))
		{
			continue;
		}
		EFlareResourcePriceContext::Type StationResourceUsage = Station->GetResourceUseType(Request.Resource);

		if(NeedOutput && StationResourceUsage != EFlareResourcePriceContext::FactoryOutput)
		{
			continue;
		}

		if(NeedInput && (StationResourceUsage != EFlareResourcePriceContext::FactoryInput &&
						 StationResourceUsage != EFlareResourcePriceContext::ConsumerConsumption &&
						 StationResourceUsage != EFlareResourcePriceContext::MaintenanceConsumption))
		{
			continue;
		}

		uint32 StationFreeSpace = Station->GetCargoBay()->GetFreeSpaceForResource(Request.Resource, Request.Client->GetCompany());
		uint32 StationResourceQuantity = Station->GetCargoBay()->GetResourceQuantity(Request.Resource, Request.Client->GetCompany());

		if (StationFreeSpace == 0 && StationResourceQuantity == 0)
		{
			continue;
		}

		float Score = 0;
		float FullRatio =  (float) StationResourceQuantity / (float) (StationResourceQuantity + StationFreeSpace);
		float EmptyRatio = 1 - FullRatio;
		uint32 UnloadMaxQuantity  = 0;
		uint32 LoadMaxQuantity  = 0;

		if(Station->GetCargoBay()->WantBuy(Request.Resource, Request.Client->GetCompany()))
		{
			UnloadMaxQuantity = StationFreeSpace;
			UnloadMaxQuantity  = FMath::Min(UnloadMaxQuantity , AvailableQuantity);
		}

		if(Station->GetCargoBay()->WantSell(Request.Resource, Request.Client->GetCompany()))
		{
			LoadMaxQuantity = StationResourceQuantity;
			LoadMaxQuantity = FMath::Min(LoadMaxQuantity , FreeSpace);
		}

		if(Station->GetCompany() == Request.Client->GetCompany())
		{
			Score += UnloadMaxQuantity * UnloadQuantityScoreMultiplier;
			Score += LoadMaxQuantity * LoadQuantityScoreMultiplier;
		}
		else
		{
			EFlareResourcePriceContext::Type ResourceUsage = Station->GetResourceUseType(Request.Resource);

			uint32 MaxBuyableQuantity = Request.Client->GetCompany()->GetMoney() / Sector->GetResourcePrice(Request.Resource, ResourceUsage);
			LoadMaxQuantity = FMath::Min(LoadMaxQuantity , MaxBuyableQuantity);

			uint32 MaxSellableQuantity = Station->GetCompany()->GetMoney() / Sector->GetResourcePrice(Request.Resource, ResourceUsage);
			UnloadMaxQuantity = FMath::Min(UnloadMaxQuantity , MaxSellableQuantity);

			Score += UnloadMaxQuantity * SellQuantityScoreMultiplier;
			Score += LoadMaxQuantity * BuyQuantityScoreMultiplier;
		}

		Score *= 1 + (FullRatio * FullRatioBonus) + (EmptyRatio * EmptyRatioBonus);

		if(Score > 0 && Score > BestScore)
		{
			BestScore = Score;
			BestStation = Station;
		}
	}

	return BestStation;
}

int32 SectorHelper::Trade(UFlareSimulatedSpacecraft*  SourceSpacecraft, UFlareSimulatedSpacecraft* DestinationSpacecraft, FFlareResourceDescription* Resource, int32 MaxQuantity)
{
	if(!SourceSpacecraft->CanTradeWith(DestinationSpacecraft))
	{
		FLOG("Both spacecraft cannot trade");
		return 0;
	}

	int32 ResourcePrice = SourceSpacecraft->GetCurrentSector()->GetTransfertResourcePrice(SourceSpacecraft, DestinationSpacecraft, Resource);
	int32 QuantityToTake = MaxQuantity;

	if (SourceSpacecraft->GetCompany() != DestinationSpacecraft->GetCompany())
	{
		// Limit transaction bay available money
		int32 MaxAffordableQuantity = DestinationSpacecraft->GetCompany()->GetMoney() / ResourcePrice;
		QuantityToTake = FMath::Min(QuantityToTake, MaxAffordableQuantity);
	}
	int32 ResourceCapacity = DestinationSpacecraft->GetCargoBay()->GetFreeSpaceForResource(Resource, SourceSpacecraft->GetCompany());

	QuantityToTake = FMath::Min(QuantityToTake, ResourceCapacity);

	int32 TakenResources = SourceSpacecraft->GetCargoBay()->TakeResources(Resource, QuantityToTake, DestinationSpacecraft->GetCompany());
	int32 GivenResources = DestinationSpacecraft->GetCargoBay()->GiveResources(Resource, TakenResources, SourceSpacecraft->GetCompany());

	// Pay
	if (GivenResources > 0 && SourceSpacecraft->GetCompany() != DestinationSpacecraft->GetCompany())
	{
		int64 Price = ResourcePrice * GivenResources;
		DestinationSpacecraft->GetCompany()->TakeMoney(Price);
		SourceSpacecraft->GetCompany()->GiveMoney(Price);

		SourceSpacecraft->GetCompany()->GiveReputation(DestinationSpacecraft->GetCompany(), 0.5f, true);
		DestinationSpacecraft->GetCompany()->GiveReputation(SourceSpacecraft->GetCompany(), 0.5f, true);
	}

	// Set the trading state if not player fleet
	if (GivenResources > 0)
	{
		AFlarePlayerController* PC = SourceSpacecraft->GetGame()->GetPC();
		UFlareFleet* PlayerFleet = PC->GetPlayerFleet();
		check(PC);

		if (SourceSpacecraft->GetCurrentFleet() != PlayerFleet && !SourceSpacecraft->IsStation())
		{
			SourceSpacecraft->SetTrading(true);
		}

		if (DestinationSpacecraft->GetCurrentFleet() != PlayerFleet && !DestinationSpacecraft->IsStation())
		{
			DestinationSpacecraft->SetTrading(true);
		}
	}

	return GivenResources;

}
<|endoftext|>