void AbstractResourceItem::validateItem()
{
    if (_state == ResourceState::FILE_ERROR || _state == ResourceState::NOT_LOADED) {
        return;
    }

    ErrorList err;

    // check dependencies
    bool dependenciesOk = true;
    for (auto& dep : _dependencies) {
        AbstractResourceItem* dItem = _project->findResourceItem(dep.type, dep.name);

        if (dItem == nullptr) {
            if (auto* rl = _project->findResourceList(dep.type)) {
                QString rtn = rl->resourceTypeNameSingle();
                err.addError("Dependency Error: Missing " + rtn.toStdString() + u8" · " + dep.name.toStdString());
            }
            else {
                err.addError("Dependency Error: Missing " + dep.name.toStdString());
            }
            dependenciesOk = false;
        }
        else if (dItem->state() != ResourceState::VALID) {
            QString rtn = dItem->resourceList()->resourceTypeNameSingle();
            err.addError("Dependency Error: " + rtn.toStdString() + u8" · " + dep.name.toStdString());

            dependenciesOk = false;
        }
    }

    if (dependenciesOk) {
        try {
            bool s = compileResource(err);
            setState(s ? ResourceState::VALID : ResourceState::ERROR);
        }
        catch (const std::exception& ex) {
            err.addError(std::string("EXCEPTION: ") + ex.what());
            setState(ResourceState::ERROR);
        }

        _errorList = std::move(err);
        emit errorListChanged();

        emit resourceComplied();
    }
    else {
        _errorList = std::move(err);
        emit errorListChanged();

        setState(ResourceState::DEPENDENCY_ERROR);
    }
}
Beispiel #2
0
ActionPointMapping MetaSprite::generateActionPointMapping(const NamedList<ActionPointFunction>& apFunctions, ErrorList& err)
{
    bool valid = true;
    auto addError = [&](const std::string msg) {
        err.addError(std::move(msg));
        valid = false;
    };
    auto addApfError = [&](const ActionPointFunction& apf, const std::string msg) {
        err.addError(std::make_unique<ListItemError>(&apf, std::move(msg)));
        valid = false;
    };

    ActionPointMapping ret;

    if (apFunctions.empty()) {
        addError("Expected at least one action point function");
        return ret;
    }

    if (apFunctions.size() > MAX_ACTION_POINT_FUNCTIONS) {
        addError("Too many action point functions (max " + std::to_string(MAX_ACTION_POINT_FUNCTIONS) + ")");
        return ret;
    }

    ret.reserve(apFunctions.size());

    for (unsigned i = 0; i < apFunctions.size(); i++) {
        const unsigned romValue = (i + 1) * 2;
        assert(romValue <= 255 - 2);

        const ActionPointFunction& apf = apFunctions.at(i);

        if (not apf.name.isValid()) {
            addApfError(apf, "Missing action point function name");
        }

        auto success = ret.emplace(apf.name, romValue);

        if (success.second == false) {
            addApfError(apf, "Action point function name already exists: " + apf.name);
        }
    }

    if (not valid) {
        ret.clear();
    }

    return ret;
}
bool AnimationFramesInput::validate(ErrorList& err) const
{
    bool valid = true;

    if (bitDepth != 2 && bitDepth != 4 && bitDepth != 8) {
        err.addError("Invalid bit-depth, expected 2, 4 or 8");
        valid = false;
    }

    if (frameImageFilenames.empty()) {
        err.addError("Missing frame image");
        valid = false;
    }

    std::vector<usize> imageSizes(frameImageFilenames.size());

    for (unsigned i = 0; i < frameImageFilenames.size(); i++) {
        const auto& imageFilename = frameImageFilenames.at(i);
        const auto& image = ImageCache::loadPngImage(imageFilename);
        imageSizes.at(i) = image->size();

        if (image->empty()) {
            err.addError("Missing frame image: " + image->errorString());
            valid = false;
            break;
        }

        if (image->size().width % 8 != 0 || image->size().height % 8 != 0) {
            err.addError("image size invalid (height and width must be a multiple of 8): " + imageFilename);
            valid = false;
        }
    }

    if (valid) {
        for (const usize& imgSize : imageSizes) {
            if (imgSize != imageSizes.front()) {
                err.addError("All frame images must be the same size");
                valid = false;
                break;
            }
        }
    }

    return valid;
}
static bool _testFrameSet(const FrameSetExportOrder& eo, const FrameSetT& frameSet,
                          ErrorList& errorList)
{
    bool valid = true;

    for (auto& en : eo.stillFrames) {
        if (en.frameExists(frameSet.frames) == false) {
            errorList.addError("Cannot find frame " + en.name);
            valid = false;
        }
    }

    for (auto& en : eo.animations) {
        if (en.animationExists(frameSet.animations) == false) {
            errorList.addError("Cannot find animation " + en.name);
            valid = false;
        }
    }

    return valid;
}
bool Animation::_validate(const FrameSetT& frameSet, ErrorList& err) const
{
    const unsigned oldErrorCount = err.errorCount();

    if (oneShot == false && nextAnimation.isValid()) {
        if (!frameSet.animations.find(nextAnimation)) {
            err.addError(animationError(*this, "Cannot find animation " + nextAnimation));
        }
    }

    if (frames.size() == 0) {
        err.addError(animationError(*this, "Expected at least one animation frame"));
    }

    for (unsigned i = 0; i < frames.size(); i++) {
        const AnimationFrame& aFrame = frames.at(i);

        if (aFrame.testFrameValid(frameSet) == false) {
            err.addError(animationFrameError(*this, i, "Cannot find frame " + aFrame.frame.name));
        }
    }

    return err.errorCount() == oldErrorCount;
}
void AbstractResourceItem::loadResource()
{
    Q_ASSERT(_undoStack->count() == 0);

    ErrorList err;

    try {
        bool s = loadResourceData(err);
        setState(s ? ResourceState::UNCHECKED : ResourceState::FILE_ERROR);
    }
    catch (const std::exception& ex) {
        err.addError(std::string("EXCEPTION: ") + ex.what());
        setState(ResourceState::FILE_ERROR);
    }

    _errorList = std::move(err);

    emit resourceLoaded();
    emit errorListChanged();
}
static std::vector<std::vector<FrameTile>> tilesFromFrameImages(const AnimationFramesInput input,
                                                                const std::vector<Snes::SnesColor>& palettes,
                                                                ErrorList& err)
{
    const unsigned colorsPerPalette = 1 << input.bitDepth;

    std::vector<std::vector<FrameTile>> frameTiles;
    frameTiles.reserve(input.frameImageFilenames.size());

    const unsigned nFrames = input.frameImageFilenames.size();
    for (unsigned frameId = 0; frameId < nFrames; frameId++) {
        auto imageErr = std::make_unique<InvalidImageError>(frameId);

        const auto& image = ImageCache::loadPngImage(input.frameImageFilenames.at(frameId));
        frameTiles.emplace_back(
            tilesFromFrameImage(*image, palettes, colorsPerPalette, *imageErr));

        if (imageErr->hasError()) {
            err.addError(std::move(imageErr));
        }
    }

    return frameTiles;
}
static AnimatedTilesetIntermediate combineFrameTiles(const std::vector<std::vector<FrameTile>>& frameTiles, unsigned tileWidth,
                                                     ErrorList& err)
{
    assert(!frameTiles.empty());
    const unsigned nTiles = frameTiles.front().size();
    for (const auto& tf : frameTiles) {
        assert(tf.size() == nTiles);
    }

    auto getTile = [&](unsigned frameId, unsigned tileId) -> const Tile8px& {
        return frameTiles.at(frameId).at(tileId).tile;
    };
    auto getPalette = [&](unsigned frameId, unsigned tileId) -> unsigned {
        return frameTiles.at(frameId).at(tileId).palette;
    };

    const unsigned nFrames = frameTiles.size();

    auto imageErr = std::make_unique<InvalidImageError>();

    AnimatedTilesetIntermediate ret;
    ret.animatedTiles.reserve(64);
    ret.tileMap.resize(nTiles);

    for (unsigned tileId = 0; tileId < nTiles; tileId++) {
        const static unsigned TS = Tile8px::TILE_SIZE;

        auto& tm = ret.tileMap.at(tileId);

        unsigned palette = getPalette(0, tileId);
        for (unsigned frameId = 1; frameId < nFrames; frameId++) {
            if (getPalette(frameId, tileId) != palette) {
                imageErr->addInvalidTile(TS, (tileId % tileWidth) * TS, (tileId / tileWidth) * TS, InvalidImageError::NOT_SAME_PALETTE);
                break;
            }
        }
        tm.palette = palette;

        const Tile8px& firstTile = getTile(0, tileId);
        bool isAnimated = false;
        for (unsigned frameId = 1; frameId < nFrames; frameId++) {
            if (getTile(frameId, tileId) != firstTile) {
                isAnimated = true;
                break;
            }
        }

        tm.isAnimated = isAnimated;
        if (isAnimated == false) {
            tm.tile = ret.staticTiles.size();
            ret.staticTiles.emplace_back(firstTile);
        }
        else {
            tm.tile = ret.animatedTiles.size();

            ret.animatedTiles.emplace_back(nFrames);
            auto& animatedTile = ret.animatedTiles.back();
            for (unsigned frameId = 0; frameId < nFrames; frameId++) {
                animatedTile.at(frameId) = getTile(frameId, tileId);
            }
        }
    }

    if (imageErr->hasError()) {
        err.addError(std::move(imageErr));
    }

    return ret;
}