<commit_before>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gl/builders/GrGLProgramBuilder.h"
#include "GrGLProgramDesc.h"
#include "GrBackendEffectFactory.h"
#include "GrEffect.h"
#include "GrGpuGL.h"
#include "GrOptDrawState.h"

#include "SkChecksum.h"

/**
 * The key for an individual coord transform is made up of a matrix type and a bit that
 * indicates the source of the input coords.
 */
enum {
    kMatrixTypeKeyBits   = 1,
    kMatrixTypeKeyMask   = (1 << kMatrixTypeKeyBits) - 1,
    kPositionCoords_Flag = (1 << kMatrixTypeKeyBits),
    kTransformKeyBits    = kMatrixTypeKeyBits + 1,
};

/**
 * We specialize the vertex code for each of these matrix types.
 */
enum MatrixType {
    kNoPersp_MatrixType  = 0,
    kGeneral_MatrixType  = 1,
};

/**
 * Do we need to either map r,g,b->a or a->r. configComponentMask indicates which channels are
 * present in the texture's config. swizzleComponentMask indicates the channels present in the
 * shader swizzle.
 */
static bool swizzle_requires_alpha_remapping(const GrGLCaps& caps,
                                             uint32_t configComponentMask,
                                             uint32_t swizzleComponentMask) {
    if (caps.textureSwizzleSupport()) {
        // Any remapping is handled using texture swizzling not shader modifications.
        return false;
    }
    // check if the texture is alpha-only
    if (kA_GrColorComponentFlag == configComponentMask) {
        if (caps.textureRedSupport() && (kA_GrColorComponentFlag & swizzleComponentMask)) {
            // we must map the swizzle 'a's to 'r'.
            return true;
        }
        if (kRGB_GrColorComponentFlags & swizzleComponentMask) {
            // The 'r', 'g', and/or 'b's must be mapped to 'a' according to our semantics that
            // alpha-only textures smear alpha across all four channels when read.
            return true;
        }
    }
    return false;
}

static uint32_t gen_attrib_key(const GrEffect* effect) {
    uint32_t key = 0;

    const GrEffect::VertexAttribArray& vars = effect->getVertexAttribs();
    int numAttributes = vars.count();
    SkASSERT(numAttributes <= 2);
    for (int a = 0; a < numAttributes; ++a) {
        uint32_t value = 1 << a;
        key |= value;
    }
    return key;
}

static uint32_t gen_transform_key(const GrEffectStage& effectStage,
                                  bool useExplicitLocalCoords) {
    uint32_t totalKey = 0;
    int numTransforms = effectStage.getEffect()->numTransforms();
    for (int t = 0; t < numTransforms; ++t) {
        uint32_t key = 0;
        if (effectStage.isPerspectiveCoordTransform(t, useExplicitLocalCoords)) {
            key |= kGeneral_MatrixType;
        } else {
            key |= kNoPersp_MatrixType;
        }

        const GrCoordTransform& coordTransform = effectStage.getEffect()->coordTransform(t);
        if (kLocal_GrCoordSet != coordTransform.sourceCoords() && useExplicitLocalCoords) {
            key |= kPositionCoords_Flag;
        }
        key <<= kTransformKeyBits * t;
        SkASSERT(0 == (totalKey & key)); // keys for each transform ought not to overlap
        totalKey |= key;
    }
    return totalKey;
}

static uint32_t gen_texture_key(const GrEffect* effect, const GrGLCaps& caps) {
    uint32_t key = 0;
    int numTextures = effect->numTextures();
    for (int t = 0; t < numTextures; ++t) {
        const GrTextureAccess& access = effect->textureAccess(t);
        uint32_t configComponentMask = GrPixelConfigComponentMask(access.getTexture()->config());
        if (swizzle_requires_alpha_remapping(caps, configComponentMask, access.swizzleMask())) {
            key |= 1 << t;
        }
    }
    return key;
}

/**
 * A function which emits a meta key into the key builder.  This is required because shader code may
 * be dependent on properties of the effect that the effect itself doesn't use
 * in its key (e.g. the pixel format of textures used). So we create a meta-key for
 * every effect using this function. It is also responsible for inserting the effect's class ID
 * which must be different for every GrEffect subclass. It can fail if an effect uses too many
 * textures, attributes, etc for the space allotted in the meta-key.
 */

static bool gen_effect_meta_key(const GrEffectStage& effectStage,
                                bool useExplicitLocalCoords,
                                const GrGLCaps& caps,
                                GrEffectKeyBuilder* b) {

    uint32_t textureKey = gen_texture_key(effectStage.getEffect(), caps);
    uint32_t transformKey = gen_transform_key(effectStage,useExplicitLocalCoords);
    uint32_t attribKey = gen_attrib_key(effectStage.getEffect());
    uint32_t classID = effectStage.getEffect()->getFactory().effectClassID();

    // Currently we allow 16 bits for each of the above portions of the meta-key. Fail if they
    // don't fit.
    static const uint32_t kMetaKeyInvalidMask = ~((uint32_t) SK_MaxU16);
    if ((textureKey | transformKey | attribKey | classID) & kMetaKeyInvalidMask) {
        return false;
    }

    uint32_t* key = b->add32n(2);
    key[0] = (textureKey << 16 | transformKey);
    key[1] = (classID << 16 | attribKey);
    return true;
}

bool GrGLProgramDesc::GetEffectKey(const GrEffectStage& stage, const GrGLCaps& caps,
                                   bool useExplicitLocalCoords, GrEffectKeyBuilder* b,
                                   uint16_t* effectKeySize) {
    const GrBackendEffectFactory& factory = stage.getEffect()->getFactory();
    const GrEffect& effect = *stage.getEffect();
    factory.getGLEffectKey(effect, caps, b);
    size_t size = b->size();
    if (size > SK_MaxU16) {
        *effectKeySize = 0; // suppresses a warning.
        return false;
    }
    *effectKeySize = SkToU16(size);
    if (!gen_effect_meta_key(stage, useExplicitLocalCoords, caps, b)) {
        return false;
    }
    return true;
}

bool GrGLProgramDesc::Build(const GrOptDrawState& optState,
                            GrGpu::DrawType drawType,
                            GrBlendCoeff srcCoeff,
                            GrBlendCoeff dstCoeff,
                            GrGpuGL* gpu,
                            const GrDeviceCoordTexture* dstCopy,
                            const GrEffectStage** geometryProcessor,
                            SkTArray<const GrEffectStage*, true>* colorStages,
                            SkTArray<const GrEffectStage*, true>* coverageStages,
                            GrGLProgramDesc* desc) {
    colorStages->reset();
    coverageStages->reset();

    bool inputColorIsUsed = optState.inputColorIsUsed();
    bool inputCoverageIsUsed = optState.inputColorIsUsed();

    // The descriptor is used as a cache key. Thus when a field of the
    // descriptor will not affect program generation (because of the attribute
    // bindings in use or other descriptor field settings) it should be set
    // to a canonical value to avoid duplicate programs with different keys.

    bool requiresColorAttrib = optState.hasColorVertexAttribute();
    bool requiresCoverageAttrib = optState.hasCoverageVertexAttribute();
    bool requiresLocalCoordAttrib = optState.requiresLocalCoordAttrib();

    int numStages = optState.numTotalStages();

    GR_STATIC_ASSERT(0 == kEffectKeyOffsetsAndLengthOffset % sizeof(uint32_t));
    // Make room for everything up to and including the array of offsets to effect keys.
    desc->fKey.reset();
    desc->fKey.push_back_n(kEffectKeyOffsetsAndLengthOffset + 2 * sizeof(uint16_t) * numStages);

    int offsetAndSizeIndex = 0;
    bool effectKeySuccess = true;

    KeyHeader* header = desc->header();
    // make sure any padding in the header is zeroed.
    memset(desc->header(), 0, kHeaderSize);

    // We can only have one effect which touches the vertex shader
    if (optState.hasGeometryProcessor()) {
        uint16_t* offsetAndSize =
                reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
                                            offsetAndSizeIndex * 2 * sizeof(uint16_t));

            GrEffectKeyBuilder b(&desc->fKey);
            uint16_t effectKeySize;
            uint32_t effectOffset = desc->fKey.count();
            effectKeySuccess |= GetEffectKey(*optState.getGeometryProcessor(), gpu->glCaps(),
                                             requiresLocalCoordAttrib, &b, &effectKeySize);
            effectKeySuccess |= (effectOffset <= SK_MaxU16);

            offsetAndSize[0] = SkToU16(effectOffset);
            offsetAndSize[1] = effectKeySize;
            ++offsetAndSizeIndex;
            *geometryProcessor = optState.getGeometryProcessor();
            header->fHasGeometryProcessor = true;
    }

    for (int s = 0; s < optState.numColorStages(); ++s) {
        uint16_t* offsetAndSize =
            reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
                                        offsetAndSizeIndex * 2 * sizeof(uint16_t));

        GrEffectKeyBuilder b(&desc->fKey);
        uint16_t effectKeySize;
        uint32_t effectOffset = desc->fKey.count();
        effectKeySuccess |= GetEffectKey(optState.getColorStage(s), gpu->glCaps(),
                                         requiresLocalCoordAttrib, &b, &effectKeySize);
        effectKeySuccess |= (effectOffset <= SK_MaxU16);

        offsetAndSize[0] = SkToU16(effectOffset);
        offsetAndSize[1] = effectKeySize;
        ++offsetAndSizeIndex;
    }

    for (int s = 0; s < optState.numCoverageStages(); ++s) {
        uint16_t* offsetAndSize =
            reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
                                        offsetAndSizeIndex * 2 * sizeof(uint16_t));

        GrEffectKeyBuilder b(&desc->fKey);
        uint16_t effectKeySize;
        uint32_t effectOffset = desc->fKey.count();
        effectKeySuccess |= GetEffectKey(optState.getCoverageStage(s), gpu->glCaps(),
                                         requiresLocalCoordAttrib, &b, &effectKeySize);
        effectKeySuccess |= (effectOffset <= SK_MaxU16);

        offsetAndSize[0] = SkToU16(effectOffset);
        offsetAndSize[1] = effectKeySize;
        ++offsetAndSizeIndex;
    }

    if (!effectKeySuccess) {
        desc->fKey.reset();
        return false;
    }

    // Because header is a pointer into the dynamic array, we can't push any new data into the key
    // below here.

    header->fUseFragShaderOnly = gpu->caps()->pathRenderingSupport() &&
        GrGpu::IsPathRenderingDrawType(drawType) &&
        gpu->glPathRendering()->texturingMode() == GrGLPathRendering::FixedFunction_TexturingMode;
    SkASSERT(!header->fUseFragShaderOnly || !optState.hasGeometryProcessor());

    header->fEmitsPointSize = GrGpu::kDrawPoints_DrawType == drawType;

    // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
    // other than pass through values from the VS to the FS anyway).
#if GR_GL_EXPERIMENTAL_GS
#if 0
    header->fExperimentalGS = gpu->caps().geometryShaderSupport();
#else
    header->fExperimentalGS = false;
#endif
#endif
    bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || header->fUseFragShaderOnly;

    if (!inputColorIsUsed) {
        header->fColorInput = kAllOnes_ColorInput;
    } else if (defaultToUniformInputs && !requiresColorAttrib) {
        header->fColorInput = kUniform_ColorInput;
    } else {
        header->fColorInput = kAttribute_ColorInput;
        header->fUseFragShaderOnly = false;
    }

    bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == optState.getCoverageColor();

    if (covIsSolidWhite || !inputCoverageIsUsed) {
        header->fCoverageInput = kAllOnes_ColorInput;
    } else if (defaultToUniformInputs && !requiresCoverageAttrib) {
        header->fCoverageInput = kUniform_ColorInput;
    } else {
        header->fCoverageInput = kAttribute_ColorInput;
        header->fUseFragShaderOnly = false;
    }

    if (optState.readsDst()) {
        SkASSERT(dstCopy || gpu->caps()->dstReadInShaderSupport());
        const GrTexture* dstCopyTexture = NULL;
        if (dstCopy) {
            dstCopyTexture = dstCopy->texture();
        }
        header->fDstReadKey = GrGLFragmentShaderBuilder::KeyForDstRead(dstCopyTexture,
                gpu->glCaps());
        SkASSERT(0 != header->fDstReadKey);
    } else {
        header->fDstReadKey = 0;
    }

    if (optState.readsFragPosition()) {
        header->fFragPosKey = GrGLFragmentShaderBuilder::KeyForFragmentPosition(
                optState.getRenderTarget(), gpu->glCaps());
    } else {
        header->fFragPosKey = 0;
    }

    // Record attribute indices
    header->fPositionAttributeIndex = optState.positionAttributeIndex();
    header->fLocalCoordAttributeIndex = optState.localCoordAttributeIndex();

    // For constant color and coverage we need an attribute with an index beyond those already set
    int availableAttributeIndex = optState.getVertexAttribCount();
    if (requiresColorAttrib) {
        header->fColorAttributeIndex = optState.colorVertexAttributeIndex();
    } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
        SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
        header->fColorAttributeIndex = availableAttributeIndex;
        availableAttributeIndex++;
    } else {
        header->fColorAttributeIndex = -1;
    }

    if (requiresCoverageAttrib) {
        header->fCoverageAttributeIndex = optState.coverageVertexAttributeIndex();
    } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
        SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
        header->fCoverageAttributeIndex = availableAttributeIndex;
    } else {
        header->fCoverageAttributeIndex = -1;
    }

    header->fPrimaryOutputType = optState.getPrimaryOutputType();
    header->fSecondaryOutputType = optState.getSecondaryOutputType();

    for (int s = 0; s < optState.numColorStages(); ++s) {
        colorStages->push_back(&optState.getColorStage(s));
    }
    for (int s = 0; s < optState.numCoverageStages(); ++s) {
        coverageStages->push_back(&optState.getCoverageStage(s));
    }

    header->fColorEffectCnt = colorStages->count();
    header->fCoverageEffectCnt = coverageStages->count();

    desc->finalize();
    return true;
}

void GrGLProgramDesc::finalize() {
    int keyLength = fKey.count();
    SkASSERT(0 == (keyLength % 4));
    *this->atOffset<uint32_t, kLengthOffset>() = SkToU32(keyLength);

    uint32_t* checksum = this->atOffset<uint32_t, kChecksumOffset>();
    *checksum = 0;
    *checksum = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.begin()), keyLength);
}

GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
    size_t keyLength = other.keyLength();
    fKey.reset(keyLength);
    memcpy(fKey.begin(), other.fKey.begin(), keyLength);
    return *this;
}
<commit_msg>Fix inputCoverageIsUsed bug in GrGLProgramDesc<commit_after>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gl/builders/GrGLProgramBuilder.h"
#include "GrGLProgramDesc.h"
#include "GrBackendEffectFactory.h"
#include "GrEffect.h"
#include "GrGpuGL.h"
#include "GrOptDrawState.h"

#include "SkChecksum.h"

/**
 * The key for an individual coord transform is made up of a matrix type and a bit that
 * indicates the source of the input coords.
 */
enum {
    kMatrixTypeKeyBits   = 1,
    kMatrixTypeKeyMask   = (1 << kMatrixTypeKeyBits) - 1,
    kPositionCoords_Flag = (1 << kMatrixTypeKeyBits),
    kTransformKeyBits    = kMatrixTypeKeyBits + 1,
};

/**
 * We specialize the vertex code for each of these matrix types.
 */
enum MatrixType {
    kNoPersp_MatrixType  = 0,
    kGeneral_MatrixType  = 1,
};

/**
 * Do we need to either map r,g,b->a or a->r. configComponentMask indicates which channels are
 * present in the texture's config. swizzleComponentMask indicates the channels present in the
 * shader swizzle.
 */
static bool swizzle_requires_alpha_remapping(const GrGLCaps& caps,
                                             uint32_t configComponentMask,
                                             uint32_t swizzleComponentMask) {
    if (caps.textureSwizzleSupport()) {
        // Any remapping is handled using texture swizzling not shader modifications.
        return false;
    }
    // check if the texture is alpha-only
    if (kA_GrColorComponentFlag == configComponentMask) {
        if (caps.textureRedSupport() && (kA_GrColorComponentFlag & swizzleComponentMask)) {
            // we must map the swizzle 'a's to 'r'.
            return true;
        }
        if (kRGB_GrColorComponentFlags & swizzleComponentMask) {
            // The 'r', 'g', and/or 'b's must be mapped to 'a' according to our semantics that
            // alpha-only textures smear alpha across all four channels when read.
            return true;
        }
    }
    return false;
}

static uint32_t gen_attrib_key(const GrEffect* effect) {
    uint32_t key = 0;

    const GrEffect::VertexAttribArray& vars = effect->getVertexAttribs();
    int numAttributes = vars.count();
    SkASSERT(numAttributes <= 2);
    for (int a = 0; a < numAttributes; ++a) {
        uint32_t value = 1 << a;
        key |= value;
    }
    return key;
}

static uint32_t gen_transform_key(const GrEffectStage& effectStage,
                                  bool useExplicitLocalCoords) {
    uint32_t totalKey = 0;
    int numTransforms = effectStage.getEffect()->numTransforms();
    for (int t = 0; t < numTransforms; ++t) {
        uint32_t key = 0;
        if (effectStage.isPerspectiveCoordTransform(t, useExplicitLocalCoords)) {
            key |= kGeneral_MatrixType;
        } else {
            key |= kNoPersp_MatrixType;
        }

        const GrCoordTransform& coordTransform = effectStage.getEffect()->coordTransform(t);
        if (kLocal_GrCoordSet != coordTransform.sourceCoords() && useExplicitLocalCoords) {
            key |= kPositionCoords_Flag;
        }
        key <<= kTransformKeyBits * t;
        SkASSERT(0 == (totalKey & key)); // keys for each transform ought not to overlap
        totalKey |= key;
    }
    return totalKey;
}

static uint32_t gen_texture_key(const GrEffect* effect, const GrGLCaps& caps) {
    uint32_t key = 0;
    int numTextures = effect->numTextures();
    for (int t = 0; t < numTextures; ++t) {
        const GrTextureAccess& access = effect->textureAccess(t);
        uint32_t configComponentMask = GrPixelConfigComponentMask(access.getTexture()->config());
        if (swizzle_requires_alpha_remapping(caps, configComponentMask, access.swizzleMask())) {
            key |= 1 << t;
        }
    }
    return key;
}

/**
 * A function which emits a meta key into the key builder.  This is required because shader code may
 * be dependent on properties of the effect that the effect itself doesn't use
 * in its key (e.g. the pixel format of textures used). So we create a meta-key for
 * every effect using this function. It is also responsible for inserting the effect's class ID
 * which must be different for every GrEffect subclass. It can fail if an effect uses too many
 * textures, attributes, etc for the space allotted in the meta-key.
 */

static bool gen_effect_meta_key(const GrEffectStage& effectStage,
                                bool useExplicitLocalCoords,
                                const GrGLCaps& caps,
                                GrEffectKeyBuilder* b) {

    uint32_t textureKey = gen_texture_key(effectStage.getEffect(), caps);
    uint32_t transformKey = gen_transform_key(effectStage,useExplicitLocalCoords);
    uint32_t attribKey = gen_attrib_key(effectStage.getEffect());
    uint32_t classID = effectStage.getEffect()->getFactory().effectClassID();

    // Currently we allow 16 bits for each of the above portions of the meta-key. Fail if they
    // don't fit.
    static const uint32_t kMetaKeyInvalidMask = ~((uint32_t) SK_MaxU16);
    if ((textureKey | transformKey | attribKey | classID) & kMetaKeyInvalidMask) {
        return false;
    }

    uint32_t* key = b->add32n(2);
    key[0] = (textureKey << 16 | transformKey);
    key[1] = (classID << 16 | attribKey);
    return true;
}

bool GrGLProgramDesc::GetEffectKey(const GrEffectStage& stage, const GrGLCaps& caps,
                                   bool useExplicitLocalCoords, GrEffectKeyBuilder* b,
                                   uint16_t* effectKeySize) {
    const GrBackendEffectFactory& factory = stage.getEffect()->getFactory();
    const GrEffect& effect = *stage.getEffect();
    factory.getGLEffectKey(effect, caps, b);
    size_t size = b->size();
    if (size > SK_MaxU16) {
        *effectKeySize = 0; // suppresses a warning.
        return false;
    }
    *effectKeySize = SkToU16(size);
    if (!gen_effect_meta_key(stage, useExplicitLocalCoords, caps, b)) {
        return false;
    }
    return true;
}

bool GrGLProgramDesc::Build(const GrOptDrawState& optState,
                            GrGpu::DrawType drawType,
                            GrBlendCoeff srcCoeff,
                            GrBlendCoeff dstCoeff,
                            GrGpuGL* gpu,
                            const GrDeviceCoordTexture* dstCopy,
                            const GrEffectStage** geometryProcessor,
                            SkTArray<const GrEffectStage*, true>* colorStages,
                            SkTArray<const GrEffectStage*, true>* coverageStages,
                            GrGLProgramDesc* desc) {
    colorStages->reset();
    coverageStages->reset();

    bool inputColorIsUsed = optState.inputColorIsUsed();
    bool inputCoverageIsUsed = optState.inputCoverageIsUsed();

    // The descriptor is used as a cache key. Thus when a field of the
    // descriptor will not affect program generation (because of the attribute
    // bindings in use or other descriptor field settings) it should be set
    // to a canonical value to avoid duplicate programs with different keys.

    bool requiresColorAttrib = optState.hasColorVertexAttribute();
    bool requiresCoverageAttrib = optState.hasCoverageVertexAttribute();
    bool requiresLocalCoordAttrib = optState.requiresLocalCoordAttrib();

    int numStages = optState.numTotalStages();

    GR_STATIC_ASSERT(0 == kEffectKeyOffsetsAndLengthOffset % sizeof(uint32_t));
    // Make room for everything up to and including the array of offsets to effect keys.
    desc->fKey.reset();
    desc->fKey.push_back_n(kEffectKeyOffsetsAndLengthOffset + 2 * sizeof(uint16_t) * numStages);

    int offsetAndSizeIndex = 0;
    bool effectKeySuccess = true;

    KeyHeader* header = desc->header();
    // make sure any padding in the header is zeroed.
    memset(desc->header(), 0, kHeaderSize);

    // We can only have one effect which touches the vertex shader
    if (optState.hasGeometryProcessor()) {
        uint16_t* offsetAndSize =
                reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
                                            offsetAndSizeIndex * 2 * sizeof(uint16_t));

            GrEffectKeyBuilder b(&desc->fKey);
            uint16_t effectKeySize;
            uint32_t effectOffset = desc->fKey.count();
            effectKeySuccess |= GetEffectKey(*optState.getGeometryProcessor(), gpu->glCaps(),
                                             requiresLocalCoordAttrib, &b, &effectKeySize);
            effectKeySuccess |= (effectOffset <= SK_MaxU16);

            offsetAndSize[0] = SkToU16(effectOffset);
            offsetAndSize[1] = effectKeySize;
            ++offsetAndSizeIndex;
            *geometryProcessor = optState.getGeometryProcessor();
            header->fHasGeometryProcessor = true;
    }

    for (int s = 0; s < optState.numColorStages(); ++s) {
        uint16_t* offsetAndSize =
            reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
                                        offsetAndSizeIndex * 2 * sizeof(uint16_t));

        GrEffectKeyBuilder b(&desc->fKey);
        uint16_t effectKeySize;
        uint32_t effectOffset = desc->fKey.count();
        effectKeySuccess |= GetEffectKey(optState.getColorStage(s), gpu->glCaps(),
                                         requiresLocalCoordAttrib, &b, &effectKeySize);
        effectKeySuccess |= (effectOffset <= SK_MaxU16);

        offsetAndSize[0] = SkToU16(effectOffset);
        offsetAndSize[1] = effectKeySize;
        ++offsetAndSizeIndex;
    }

    for (int s = 0; s < optState.numCoverageStages(); ++s) {
        uint16_t* offsetAndSize =
            reinterpret_cast<uint16_t*>(desc->fKey.begin() + kEffectKeyOffsetsAndLengthOffset +
                                        offsetAndSizeIndex * 2 * sizeof(uint16_t));

        GrEffectKeyBuilder b(&desc->fKey);
        uint16_t effectKeySize;
        uint32_t effectOffset = desc->fKey.count();
        effectKeySuccess |= GetEffectKey(optState.getCoverageStage(s), gpu->glCaps(),
                                         requiresLocalCoordAttrib, &b, &effectKeySize);
        effectKeySuccess |= (effectOffset <= SK_MaxU16);

        offsetAndSize[0] = SkToU16(effectOffset);
        offsetAndSize[1] = effectKeySize;
        ++offsetAndSizeIndex;
    }

    if (!effectKeySuccess) {
        desc->fKey.reset();
        return false;
    }

    // Because header is a pointer into the dynamic array, we can't push any new data into the key
    // below here.

    header->fUseFragShaderOnly = gpu->caps()->pathRenderingSupport() &&
        GrGpu::IsPathRenderingDrawType(drawType) &&
        gpu->glPathRendering()->texturingMode() == GrGLPathRendering::FixedFunction_TexturingMode;
    SkASSERT(!header->fUseFragShaderOnly || !optState.hasGeometryProcessor());

    header->fEmitsPointSize = GrGpu::kDrawPoints_DrawType == drawType;

    // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
    // other than pass through values from the VS to the FS anyway).
#if GR_GL_EXPERIMENTAL_GS
#if 0
    header->fExperimentalGS = gpu->caps().geometryShaderSupport();
#else
    header->fExperimentalGS = false;
#endif
#endif
    bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || header->fUseFragShaderOnly;

    if (!inputColorIsUsed) {
        header->fColorInput = kAllOnes_ColorInput;
    } else if (defaultToUniformInputs && !requiresColorAttrib) {
        header->fColorInput = kUniform_ColorInput;
    } else {
        header->fColorInput = kAttribute_ColorInput;
        header->fUseFragShaderOnly = false;
    }

    bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == optState.getCoverageColor();

    if (covIsSolidWhite || !inputCoverageIsUsed) {
        header->fCoverageInput = kAllOnes_ColorInput;
    } else if (defaultToUniformInputs && !requiresCoverageAttrib) {
        header->fCoverageInput = kUniform_ColorInput;
    } else {
        header->fCoverageInput = kAttribute_ColorInput;
        header->fUseFragShaderOnly = false;
    }

    if (optState.readsDst()) {
        SkASSERT(dstCopy || gpu->caps()->dstReadInShaderSupport());
        const GrTexture* dstCopyTexture = NULL;
        if (dstCopy) {
            dstCopyTexture = dstCopy->texture();
        }
        header->fDstReadKey = GrGLFragmentShaderBuilder::KeyForDstRead(dstCopyTexture,
                gpu->glCaps());
        SkASSERT(0 != header->fDstReadKey);
    } else {
        header->fDstReadKey = 0;
    }

    if (optState.readsFragPosition()) {
        header->fFragPosKey = GrGLFragmentShaderBuilder::KeyForFragmentPosition(
                optState.getRenderTarget(), gpu->glCaps());
    } else {
        header->fFragPosKey = 0;
    }

    // Record attribute indices
    header->fPositionAttributeIndex = optState.positionAttributeIndex();
    header->fLocalCoordAttributeIndex = optState.localCoordAttributeIndex();

    // For constant color and coverage we need an attribute with an index beyond those already set
    int availableAttributeIndex = optState.getVertexAttribCount();
    if (requiresColorAttrib) {
        header->fColorAttributeIndex = optState.colorVertexAttributeIndex();
    } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
        SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
        header->fColorAttributeIndex = availableAttributeIndex;
        availableAttributeIndex++;
    } else {
        header->fColorAttributeIndex = -1;
    }

    if (requiresCoverageAttrib) {
        header->fCoverageAttributeIndex = optState.coverageVertexAttributeIndex();
    } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
        SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
        header->fCoverageAttributeIndex = availableAttributeIndex;
    } else {
        header->fCoverageAttributeIndex = -1;
    }

    header->fPrimaryOutputType = optState.getPrimaryOutputType();
    header->fSecondaryOutputType = optState.getSecondaryOutputType();

    for (int s = 0; s < optState.numColorStages(); ++s) {
        colorStages->push_back(&optState.getColorStage(s));
    }
    for (int s = 0; s < optState.numCoverageStages(); ++s) {
        coverageStages->push_back(&optState.getCoverageStage(s));
    }

    header->fColorEffectCnt = colorStages->count();
    header->fCoverageEffectCnt = coverageStages->count();

    desc->finalize();
    return true;
}

void GrGLProgramDesc::finalize() {
    int keyLength = fKey.count();
    SkASSERT(0 == (keyLength % 4));
    *this->atOffset<uint32_t, kLengthOffset>() = SkToU32(keyLength);

    uint32_t* checksum = this->atOffset<uint32_t, kChecksumOffset>();
    *checksum = 0;
    *checksum = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.begin()), keyLength);
}

GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
    size_t keyLength = other.keyLength();
    fKey.reset(keyLength);
    memcpy(fKey.begin(), other.fKey.begin(), keyLength);
    return *this;
}
<|endoftext|>


<commit_before>#ifndef __BUF_PATCH_HPP__
#define	__BUF_PATCH_HPP__

/*
 * This file provides the basic buf_patch_t type as well as a few low-level binary
 * patch implementations (currently memmove and memcpy patches)
 */

class buf_patch_t;

#include "buffer_cache/types.hpp"
#include "serializer/types.hpp"

typedef uint32_t patch_counter_t;
typedef byte patch_operation_code_t;

/*
 * A buf_patch_t is an in-memory representation for a patch. A patch describes
 * a specific change which can be applied to a buffer.
 * Each buffer patch has a patch counter as well as a transaction id. The transaction id
 * is used to determine to which version of a block the patch applies. Within
 * one version of a block, the patch counter explicitly encodes an ordering, which
 * is used to ensure that patches can be applied in the correct order
 * (even if they get serialized to disk in a different order).
 *
 * While buf_patch_t provides the general interface of a buffer patch and a few
 * universal methods, subclasses are required to implement an apply_to_buf method
 * (which executes the actual patch operation) as well as methods which handle
 * serializing and deserializing the subtype specific data.
 */
class buf_patch_t {
public:
    virtual ~buf_patch_t() { }

    // Unserializes a patch an returns a buf_patch_t object
    // If *(uint16_t*)source is 0, it returns NULL
    //
    // TODO: This allocates a patch, which you have to manually delete it.  Fix it.
    static buf_patch_t* load_patch(const char* source);

    // Serializes the patch to the given destination address
    void serialize(char* destination) const;

    inline uint16_t get_serialized_size() const {
        return sizeof(uint16_t) + sizeof(block_id) + sizeof(patch_counter) + sizeof(applies_to_transaction_id) + sizeof(operation_code) + get_data_size();
    }
    inline static uint16_t get_min_serialized_size() {
        return sizeof(uint16_t) + sizeof(block_id) + sizeof(patch_counter) + sizeof(applies_to_transaction_id) + sizeof(operation_code);
    }

    inline patch_counter_t get_patch_counter() const {
        return patch_counter;
    }
    inline ser_transaction_id_t get_transaction_id() const {
        return applies_to_transaction_id;
    }
    inline void set_transaction_id(const ser_transaction_id_t transaction_id) {
        applies_to_transaction_id = transaction_id;
    }
    inline block_id_t get_block_id() const {
        return block_id;
    }

    virtual size_t get_affected_data_size() const = 0;

    // This is called from buf_t
    virtual void apply_to_buf(char* buf_data) = 0;

    bool operator<(const buf_patch_t& p) const;

protected:
    // These are for usage in subclasses
    buf_patch_t(const block_id_t block_id, const patch_counter_t patch_counter, const patch_operation_code_t operation_code);
    virtual void serialize_data(char* destination) const = 0;
    virtual uint16_t get_data_size() const = 0;

    static const patch_operation_code_t OPER_MEMCPY = 0;
    static const patch_operation_code_t OPER_MEMMOVE = 1;
    static const patch_operation_code_t OPER_LEAF_SHIFT_PAIRS = 2;
    static const patch_operation_code_t OPER_LEAF_INSERT_PAIR = 3;
    static const patch_operation_code_t OPER_LEAF_INSERT = 4;
    static const patch_operation_code_t OPER_LEAF_REMOVE = 5;
    /* Assign an operation id to new subtypes here */
    /* Please note: you also have to "register" new operations in buf_patch_t::load_patch() */

private:
    block_id_t block_id;
    patch_counter_t patch_counter;
    ser_transaction_id_t applies_to_transaction_id;
    patch_operation_code_t operation_code;
};

/* Binary patches */

/* memcpy_patch_t copies n bytes from src to the offset dest_offset of a buffer */
class memcpy_patch_t : public buf_patch_t {
public:
    memcpy_patch_t(const block_id_t block_id, const patch_counter_t patch_counter, const uint16_t dest_offset, const char *src, const uint16_t n);
    memcpy_patch_t(const block_id_t block_id, const patch_counter_t patch_counter, const char* data, const uint16_t data_length);

    virtual ~memcpy_patch_t();

    virtual void apply_to_buf(char* buf_data);

    virtual size_t get_affected_data_size() const;

protected:
    virtual void serialize_data(char* destination) const;
    virtual uint16_t get_data_size() const;

private:
    uint16_t dest_offset;
    uint16_t n;
    char* src_buf;
};

/* memove_patch_t moves data from src_offset to dest_offset within a single buffer (with semantics equivalent to memmove()) */
class memmove_patch_t : public buf_patch_t {
public:
    memmove_patch_t(const block_id_t block_id, const patch_counter_t patch_counter, const uint16_t dest_offset, const uint16_t src_offset, const uint16_t n);
    memmove_patch_t(const block_id_t block_id, const patch_counter_t patch_counter, const char* data, const uint16_t data_length);

    virtual void apply_to_buf(char* buf_data);

    virtual size_t get_affected_data_size() const;

protected:
    virtual void serialize_data(char* destination) const;
    virtual uint16_t get_data_size() const;

private:
    uint16_t dest_offset;
    uint16_t src_offset;
    uint16_t n;
};

#endif	/* __BUF_PATCH_HPP__ */

<commit_msg>Switch sizeof(variable)s to sizeof(type).<commit_after>#ifndef __BUF_PATCH_HPP__
#define	__BUF_PATCH_HPP__

/*
 * This file provides the basic buf_patch_t type as well as a few low-level binary
 * patch implementations (currently memmove and memcpy patches)
 */

class buf_patch_t;

#include "buffer_cache/types.hpp"
#include "serializer/types.hpp"

typedef uint32_t patch_counter_t;
typedef byte patch_operation_code_t;

/*
 * A buf_patch_t is an in-memory representation for a patch. A patch describes
 * a specific change which can be applied to a buffer.
 * Each buffer patch has a patch counter as well as a transaction id. The transaction id
 * is used to determine to which version of a block the patch applies. Within
 * one version of a block, the patch counter explicitly encodes an ordering, which
 * is used to ensure that patches can be applied in the correct order
 * (even if they get serialized to disk in a different order).
 *
 * While buf_patch_t provides the general interface of a buffer patch and a few
 * universal methods, subclasses are required to implement an apply_to_buf method
 * (which executes the actual patch operation) as well as methods which handle
 * serializing and deserializing the subtype specific data.
 */
class buf_patch_t {
public:
    virtual ~buf_patch_t() { }

    // Unserializes a patch an returns a buf_patch_t object
    // If *(uint16_t*)source is 0, it returns NULL
    //
    // TODO: This allocates a patch, which you have to manually delete it.  Fix it.
    static buf_patch_t* load_patch(const char* source);

    // Serializes the patch to the given destination address
    void serialize(char* destination) const;

    inline uint16_t get_serialized_size() const {
        return sizeof(uint16_t) + sizeof(block_id) + sizeof(patch_counter_t) + sizeof(ser_transaction_id_t) + sizeof(patch_operation_code_t) + get_data_size();
    }
    inline static uint16_t get_min_serialized_size() {
        return sizeof(uint16_t) + sizeof(block_id_t) + sizeof(patch_counter_t) + sizeof(ser_transaction_id_t) + sizeof(patch_operation_code_t);
    }

    inline patch_counter_t get_patch_counter() const {
        return patch_counter;
    }
    inline ser_transaction_id_t get_transaction_id() const {
        return applies_to_transaction_id;
    }
    inline void set_transaction_id(const ser_transaction_id_t transaction_id) {
        applies_to_transaction_id = transaction_id;
    }
    inline block_id_t get_block_id() const {
        return block_id;
    }

    virtual size_t get_affected_data_size() const = 0;

    // This is called from buf_t
    virtual void apply_to_buf(char* buf_data) = 0;

    bool operator<(const buf_patch_t& p) const;

protected:
    // These are for usage in subclasses
    buf_patch_t(const block_id_t block_id, const patch_counter_t patch_counter, const patch_operation_code_t operation_code);
    virtual void serialize_data(char* destination) const = 0;
    virtual uint16_t get_data_size() const = 0;

    static const patch_operation_code_t OPER_MEMCPY = 0;
    static const patch_operation_code_t OPER_MEMMOVE = 1;
    static const patch_operation_code_t OPER_LEAF_SHIFT_PAIRS = 2;
    static const patch_operation_code_t OPER_LEAF_INSERT_PAIR = 3;
    static const patch_operation_code_t OPER_LEAF_INSERT = 4;
    static const patch_operation_code_t OPER_LEAF_REMOVE = 5;
    /* Assign an operation id to new subtypes here */
    /* Please note: you also have to "register" new operations in buf_patch_t::load_patch() */

private:
    block_id_t block_id;
    patch_counter_t patch_counter;
    ser_transaction_id_t applies_to_transaction_id;
    patch_operation_code_t operation_code;
};

/* Binary patches */

/* memcpy_patch_t copies n bytes from src to the offset dest_offset of a buffer */
class memcpy_patch_t : public buf_patch_t {
public:
    memcpy_patch_t(const block_id_t block_id, const patch_counter_t patch_counter, const uint16_t dest_offset, const char *src, const uint16_t n);
    memcpy_patch_t(const block_id_t block_id, const patch_counter_t patch_counter, const char* data, const uint16_t data_length);

    virtual ~memcpy_patch_t();

    virtual void apply_to_buf(char* buf_data);

    virtual size_t get_affected_data_size() const;

protected:
    virtual void serialize_data(char* destination) const;
    virtual uint16_t get_data_size() const;

private:
    uint16_t dest_offset;
    uint16_t n;
    char* src_buf;
};

/* memove_patch_t moves data from src_offset to dest_offset within a single buffer (with semantics equivalent to memmove()) */
class memmove_patch_t : public buf_patch_t {
public:
    memmove_patch_t(const block_id_t block_id, const patch_counter_t patch_counter, const uint16_t dest_offset, const uint16_t src_offset, const uint16_t n);
    memmove_patch_t(const block_id_t block_id, const patch_counter_t patch_counter, const char* data, const uint16_t data_length);

    virtual void apply_to_buf(char* buf_data);

    virtual size_t get_affected_data_size() const;

protected:
    virtual void serialize_data(char* destination) const;
    virtual uint16_t get_data_size() const;

private:
    uint16_t dest_offset;
    uint16_t src_offset;
    uint16_t n;
};

#endif	/* __BUF_PATCH_HPP__ */

<|endoftext|>


<commit_before>//===- Driver.cpp ---------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lld/Common/Driver.h"
#include "Config.h"
#include "SymbolTable.h"
#include "Writer.h"
#include "lld/Common/Args.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Object/Wasm.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"

using namespace llvm;
using namespace llvm::sys;
using namespace llvm::wasm;

using namespace lld;
using namespace lld::wasm;

namespace {

// Parses command line options.
class WasmOptTable : public llvm::opt::OptTable {
public:
  WasmOptTable();
  llvm::opt::InputArgList parse(ArrayRef<const char *> Argv);
};

// Create enum with OPT_xxx values for each option in Options.td
enum {
  OPT_INVALID = 0,
#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
#include "Options.inc"
#undef OPTION
};

class LinkerDriver {
public:
  void link(ArrayRef<const char *> ArgsArr);

private:
  void createFiles(llvm::opt::InputArgList &Args);
  void addFile(StringRef Path);
  void addLibrary(StringRef Name);
  std::vector<InputFile *> Files;
};

} // anonymous namespace

Configuration *lld::wasm::Config;

bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly,
                     raw_ostream &Error) {
  errorHandler().LogName = Args[0];
  errorHandler().ErrorOS = &Error;
  errorHandler().ColorDiagnostics = Error.has_colors();
  errorHandler().ErrorLimitExceededMsg =
      "too many errors emitted, stopping now (use "
      "-error-limit=0 to see all errors)";

  Config = make<Configuration>();
  Symtab = make<SymbolTable>();

  LinkerDriver().link(Args);

  // Exit immediately if we don't need to return to the caller.
  // This saves time because the overhead of calling destructors
  // for all globally-allocated objects is not negligible.
  if (CanExitEarly)
    exitLld(errorCount() ? 1 : 0);

  freeArena();
  return !errorCount();
}

// Create OptTable

// Create prefix string literals used in Options.td
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "Options.inc"
#undef PREFIX

// Create table mapping all options defined in Options.td
static const opt::OptTable::Info OptInfo[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
  {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,       \
   X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
#include "Options.inc"
#undef OPTION
};

// Set color diagnostics according to -color-diagnostics={auto,always,never}
// or -no-color-diagnostics flags.
static void handleColorDiagnostics(opt::InputArgList &Args) {
  auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
                              OPT_no_color_diagnostics);
  if (!Arg)
    return;

  if (Arg->getOption().getID() == OPT_color_diagnostics)
    errorHandler().ColorDiagnostics = true;
  else if (Arg->getOption().getID() == OPT_no_color_diagnostics)
    errorHandler().ColorDiagnostics = false;
  else {
    StringRef S = Arg->getValue();
    if (S == "always")
      errorHandler().ColorDiagnostics = true;
    if (S == "never")
      errorHandler().ColorDiagnostics = false;
    if (S != "auto")
      error("unknown option: -color-diagnostics=" + S);
  }
}

// Find a file by concatenating given paths.
static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
  SmallString<128> S;
  path::append(S, Path1, Path2);
  if (fs::exists(S))
    return S.str().str();
  return None;
}

// Inject a new wasm global into the output binary with the given value.
// Wasm global are used in relocatable object files to model symbol imports
// and exports.  In the final exectuable the only use of wasm globals is the
// for the exlicit stack pointer (__stack_pointer).
static void addSyntheticGlobal(StringRef Name, int32_t Value) {
  log("injecting global: " + Name);
  Symbol *S = Symtab->addDefinedGlobal(Name);
  S->setOutputIndex(Config->SyntheticGlobals.size());

  WasmGlobal Global;
  Global.Mutable = true;
  Global.Type = WASM_TYPE_I32;
  Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
  Global.InitExpr.Value.Int32 = Value;
  Config->SyntheticGlobals.emplace_back(S, Global);
}

// Inject a new undefined symbol into the link.  This will cause the link to
// fail unless this symbol can be found.
static void addSyntheticUndefinedFunction(StringRef Name) {
  log("injecting undefined func: " + Name);
  Symtab->addUndefinedFunction(Name);
}

static void printHelp(const char *Argv0) {
  WasmOptTable Table;
  Table.PrintHelp(outs(), Argv0, "LLVM Linker", false);
}

WasmOptTable::WasmOptTable() : OptTable(OptInfo) {}

opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> Argv) {
  SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());

  unsigned MissingIndex;
  unsigned MissingCount;
  opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);

  handleColorDiagnostics(Args);
  for (auto *Arg : Args.filtered(OPT_UNKNOWN))
    error("unknown argument: " + Arg->getSpelling());
  return Args;
}

void LinkerDriver::addFile(StringRef Path) {
  Optional<MemoryBufferRef> Buffer = readFile(Path);
  if (!Buffer.hasValue())
    return;
  MemoryBufferRef MBRef = *Buffer;

  if (identify_magic(MBRef.getBuffer()) == file_magic::archive)
    Files.push_back(make<ArchiveFile>(MBRef));
  else
    Files.push_back(make<ObjFile>(MBRef));
}

// Add a given library by searching it from input search paths.
void LinkerDriver::addLibrary(StringRef Name) {
  for (StringRef Dir : Config->SearchPaths) {
    if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a")) {
      addFile(*S);
      return;
    }
  }

  error("unable to find library -l" + Name);
}

void LinkerDriver::createFiles(opt::InputArgList &Args) {
  for (auto *Arg : Args) {
    switch (Arg->getOption().getUnaliasedOption().getID()) {
    case OPT_l:
      addLibrary(Arg->getValue());
      break;
    case OPT_INPUT:
      addFile(Arg->getValue());
      break;
    }
  }

  if (Files.empty())
    error("no input files");
}

void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
  WasmOptTable Parser;
  opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));

  // Handle --help
  if (Args.hasArg(OPT_help)) {
    printHelp(ArgsArr[0]);
    return;
  }

  // Parse and evaluate -mllvm options.
  std::vector<const char *> V;
  V.push_back("lld-link (LLVM option parsing)");
  for (auto *Arg : Args.filtered(OPT_mllvm))
    V.push_back(Arg->getValue());
  cl::ParseCommandLineOptions(V.size(), V.data());

  errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20);

  if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) {
    outs() << getLLDVersion() << "\n";
    return;
  }

  Config->AllowUndefined = Args.hasArg(OPT_allow_undefined);
  Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
  Config->Entry = Args.getLastArgValue(OPT_entry);
  Config->ImportMemory = Args.hasArg(OPT_import_memory);
  Config->OutputFile = Args.getLastArgValue(OPT_o);
  Config->Relocatable = Args.hasArg(OPT_relocatable);
  Config->SearchPaths = args::getStrings(Args, OPT_L);
  Config->StripAll = Args.hasArg(OPT_strip_all);
  Config->StripDebug = Args.hasArg(OPT_strip_debug);
  Config->Sysroot = Args.getLastArgValue(OPT_sysroot);
  errorHandler().Verbose = Args.hasArg(OPT_verbose);
  ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);

  Config->InitialMemory = args::getInteger(Args, OPT_initial_memory, 0);
  Config->GlobalBase = args::getInteger(Args, OPT_global_base, 1024);
  Config->MaxMemory = args::getInteger(Args, OPT_max_memory, 0);
  Config->ZStackSize =
      args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize);

  if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file))
    if (Optional<MemoryBufferRef> Buf = readFile(Arg->getValue()))
      for (StringRef Sym : args::getLines(*Buf))
        Config->AllowUndefinedSymbols.insert(Sym);

  if (Config->OutputFile.empty())
    error("no output file specified");

  if (!Args.hasArg(OPT_INPUT))
    error("no input files");

  if (Config->Relocatable && !Config->Entry.empty())
    error("entry point specified for relocatable output file");

  if (!Config->Relocatable) {
    if (Config->Entry.empty())
      Config->Entry = "_start";
    addSyntheticUndefinedFunction(Config->Entry);

    addSyntheticGlobal("__stack_pointer", 0);
  }

  createFiles(Args);
  if (errorCount())
    return;

  // Add all files to the symbol table. This will add almost all
  // symbols that we need to the symbol table.
  for (InputFile *F : Files)
    Symtab->addFile(F);

  // Make sure we have resolved all symbols.
  if (!Config->Relocatable && !Config->AllowUndefined) {
    Symtab->reportRemainingUndefines();
    if (errorCount())
      return;
  }

  if (!Config->Entry.empty()) {
    Symbol *Sym = Symtab->find(Config->Entry);
    if (!Sym->isFunction())
      fatal("entry point is not a function: " + Sym->getName());
  }

  // Write the result to the file.
  writeResult();
}
<commit_msg>Fix spelling. NFC.<commit_after>//===- Driver.cpp ---------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lld/Common/Driver.h"
#include "Config.h"
#include "SymbolTable.h"
#include "Writer.h"
#include "lld/Common/Args.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Object/Wasm.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"

using namespace llvm;
using namespace llvm::sys;
using namespace llvm::wasm;

using namespace lld;
using namespace lld::wasm;

namespace {

// Parses command line options.
class WasmOptTable : public llvm::opt::OptTable {
public:
  WasmOptTable();
  llvm::opt::InputArgList parse(ArrayRef<const char *> Argv);
};

// Create enum with OPT_xxx values for each option in Options.td
enum {
  OPT_INVALID = 0,
#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
#include "Options.inc"
#undef OPTION
};

class LinkerDriver {
public:
  void link(ArrayRef<const char *> ArgsArr);

private:
  void createFiles(llvm::opt::InputArgList &Args);
  void addFile(StringRef Path);
  void addLibrary(StringRef Name);
  std::vector<InputFile *> Files;
};

} // anonymous namespace

Configuration *lld::wasm::Config;

bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly,
                     raw_ostream &Error) {
  errorHandler().LogName = Args[0];
  errorHandler().ErrorOS = &Error;
  errorHandler().ColorDiagnostics = Error.has_colors();
  errorHandler().ErrorLimitExceededMsg =
      "too many errors emitted, stopping now (use "
      "-error-limit=0 to see all errors)";

  Config = make<Configuration>();
  Symtab = make<SymbolTable>();

  LinkerDriver().link(Args);

  // Exit immediately if we don't need to return to the caller.
  // This saves time because the overhead of calling destructors
  // for all globally-allocated objects is not negligible.
  if (CanExitEarly)
    exitLld(errorCount() ? 1 : 0);

  freeArena();
  return !errorCount();
}

// Create OptTable

// Create prefix string literals used in Options.td
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "Options.inc"
#undef PREFIX

// Create table mapping all options defined in Options.td
static const opt::OptTable::Info OptInfo[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
  {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,       \
   X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
#include "Options.inc"
#undef OPTION
};

// Set color diagnostics according to -color-diagnostics={auto,always,never}
// or -no-color-diagnostics flags.
static void handleColorDiagnostics(opt::InputArgList &Args) {
  auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
                              OPT_no_color_diagnostics);
  if (!Arg)
    return;

  if (Arg->getOption().getID() == OPT_color_diagnostics)
    errorHandler().ColorDiagnostics = true;
  else if (Arg->getOption().getID() == OPT_no_color_diagnostics)
    errorHandler().ColorDiagnostics = false;
  else {
    StringRef S = Arg->getValue();
    if (S == "always")
      errorHandler().ColorDiagnostics = true;
    if (S == "never")
      errorHandler().ColorDiagnostics = false;
    if (S != "auto")
      error("unknown option: -color-diagnostics=" + S);
  }
}

// Find a file by concatenating given paths.
static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
  SmallString<128> S;
  path::append(S, Path1, Path2);
  if (fs::exists(S))
    return S.str().str();
  return None;
}

// Inject a new wasm global into the output binary with the given value.
// Wasm global are used in relocatable object files to model symbol imports
// and exports.  In the final exectuable the only use of wasm globals is the
// for the exlicit stack pointer (__stack_pointer).
static void addSyntheticGlobal(StringRef Name, int32_t Value) {
  log("injecting global: " + Name);
  Symbol *S = Symtab->addDefinedGlobal(Name);
  S->setOutputIndex(Config->SyntheticGlobals.size());

  WasmGlobal Global;
  Global.Mutable = true;
  Global.Type = WASM_TYPE_I32;
  Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
  Global.InitExpr.Value.Int32 = Value;
  Config->SyntheticGlobals.emplace_back(S, Global);
}

// Inject a new undefined symbol into the link.  This will cause the link to
// fail unless this symbol can be found.
static void addSyntheticUndefinedFunction(StringRef Name) {
  log("injecting undefined func: " + Name);
  Symtab->addUndefinedFunction(Name);
}

static void printHelp(const char *Argv0) {
  WasmOptTable Table;
  Table.PrintHelp(outs(), Argv0, "LLVM Linker", false);
}

WasmOptTable::WasmOptTable() : OptTable(OptInfo) {}

opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> Argv) {
  SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());

  unsigned MissingIndex;
  unsigned MissingCount;
  opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);

  handleColorDiagnostics(Args);
  for (auto *Arg : Args.filtered(OPT_UNKNOWN))
    error("unknown argument: " + Arg->getSpelling());
  return Args;
}

void LinkerDriver::addFile(StringRef Path) {
  Optional<MemoryBufferRef> Buffer = readFile(Path);
  if (!Buffer.hasValue())
    return;
  MemoryBufferRef MBRef = *Buffer;

  if (identify_magic(MBRef.getBuffer()) == file_magic::archive)
    Files.push_back(make<ArchiveFile>(MBRef));
  else
    Files.push_back(make<ObjFile>(MBRef));
}

// Add a given library by searching it from input search paths.
void LinkerDriver::addLibrary(StringRef Name) {
  for (StringRef Dir : Config->SearchPaths) {
    if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a")) {
      addFile(*S);
      return;
    }
  }

  error("unable to find library -l" + Name);
}

void LinkerDriver::createFiles(opt::InputArgList &Args) {
  for (auto *Arg : Args) {
    switch (Arg->getOption().getUnaliasedOption().getID()) {
    case OPT_l:
      addLibrary(Arg->getValue());
      break;
    case OPT_INPUT:
      addFile(Arg->getValue());
      break;
    }
  }

  if (Files.empty())
    error("no input files");
}

void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
  WasmOptTable Parser;
  opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));

  // Handle --help
  if (Args.hasArg(OPT_help)) {
    printHelp(ArgsArr[0]);
    return;
  }

  // Parse and evaluate -mllvm options.
  std::vector<const char *> V;
  V.push_back("wasm-ld (LLVM option parsing)");
  for (auto *Arg : Args.filtered(OPT_mllvm))
    V.push_back(Arg->getValue());
  cl::ParseCommandLineOptions(V.size(), V.data());

  errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20);

  if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) {
    outs() << getLLDVersion() << "\n";
    return;
  }

  Config->AllowUndefined = Args.hasArg(OPT_allow_undefined);
  Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
  Config->Entry = Args.getLastArgValue(OPT_entry);
  Config->ImportMemory = Args.hasArg(OPT_import_memory);
  Config->OutputFile = Args.getLastArgValue(OPT_o);
  Config->Relocatable = Args.hasArg(OPT_relocatable);
  Config->SearchPaths = args::getStrings(Args, OPT_L);
  Config->StripAll = Args.hasArg(OPT_strip_all);
  Config->StripDebug = Args.hasArg(OPT_strip_debug);
  Config->Sysroot = Args.getLastArgValue(OPT_sysroot);
  errorHandler().Verbose = Args.hasArg(OPT_verbose);
  ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);

  Config->InitialMemory = args::getInteger(Args, OPT_initial_memory, 0);
  Config->GlobalBase = args::getInteger(Args, OPT_global_base, 1024);
  Config->MaxMemory = args::getInteger(Args, OPT_max_memory, 0);
  Config->ZStackSize =
      args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize);

  if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file))
    if (Optional<MemoryBufferRef> Buf = readFile(Arg->getValue()))
      for (StringRef Sym : args::getLines(*Buf))
        Config->AllowUndefinedSymbols.insert(Sym);

  if (Config->OutputFile.empty())
    error("no output file specified");

  if (!Args.hasArg(OPT_INPUT))
    error("no input files");

  if (Config->Relocatable && !Config->Entry.empty())
    error("entry point specified for relocatable output file");

  if (!Config->Relocatable) {
    if (Config->Entry.empty())
      Config->Entry = "_start";
    addSyntheticUndefinedFunction(Config->Entry);

    addSyntheticGlobal("__stack_pointer", 0);
  }

  createFiles(Args);
  if (errorCount())
    return;

  // Add all files to the symbol table. This will add almost all
  // symbols that we need to the symbol table.
  for (InputFile *F : Files)
    Symtab->addFile(F);

  // Make sure we have resolved all symbols.
  if (!Config->Relocatable && !Config->AllowUndefined) {
    Symtab->reportRemainingUndefines();
    if (errorCount())
      return;
  }

  if (!Config->Entry.empty()) {
    Symbol *Sym = Symtab->find(Config->Entry);
    if (!Sym->isFunction())
      fatal("entry point is not a function: " + Sym->getName());
  }

  // Write the result to the file.
  writeResult();
}
<|endoftext|>


<commit_before>#include "Runtime/Weapon/CBomb.hpp"

#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CBooRenderer.hpp"
#include "Runtime/Particle/CElementGen.hpp"
#include "Runtime/World/CGameLight.hpp"
#include "Runtime/World/CMorphBall.hpp"
#include "Runtime/World/CPlayer.hpp"

#include "DataSpec/DNAMP1/SFX/Weapons.h"

#include "TCastTo.hpp" // Generated file, do not modify include path

namespace urde {

CBomb::CBomb(const TCachedToken<CGenDescription>& particle1, const TCachedToken<CGenDescription>& particle2,
             TUniqueId uid, TAreaId aid, TUniqueId playerId, float f1, const zeus::CTransform& xf,
             const CDamageInfo& dInfo)
: CWeapon(uid, aid, true, playerId, EWeaponType::Bomb, "Bomb", xf,
          CMaterialFilter::MakeIncludeExclude(
              {EMaterialTypes::Solid, EMaterialTypes::Trigger, EMaterialTypes::NonSolidDamageable},
              {EMaterialTypes::Projectile, EMaterialTypes::Bomb}),
          {EMaterialTypes::Projectile, EMaterialTypes::Bomb}, dInfo, EProjectileAttrib::Bombs,
          CModelData::CModelDataNull())
, x17c_fuseTime(f1)
, x180_particle1(std::make_unique<CElementGen>(particle1, CElementGen::EModelOrientationType::Normal,
                                               CElementGen::EOptionalSystemFlags::One))
, x184_particle2(std::make_unique<CElementGen>(particle2, CElementGen::EModelOrientationType::Normal,
                                               CElementGen::EOptionalSystemFlags::One))
, x18c_particle2Obj(particle2.GetObj())
, x190_24_isNotDetonated(true)
, x190_25_beingDragged(false)
, x190_26_disableFuse(false) {
  x180_particle1->SetGlobalTranslation(xf.origin);
  x184_particle2->SetGlobalTranslation(xf.origin);
}

void CBomb::Accept(urde::IVisitor& visitor) { visitor.Visit(this); }

void CBomb::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
  if (msg == EScriptObjectMessage::Registered) {

    x188_lightId = mgr.AllocateUniqueId();
    CGameLight* gameLight = new CGameLight(x188_lightId, GetAreaIdAlways(), false,
                                           std::string("Bomb_PLight") + GetName().data(), GetTransform(), GetUniqueId(),
                                           x184_particle2->GetLight(), reinterpret_cast<size_t>(x18c_particle2Obj), 1, 0.f);
    mgr.AddObject(gameLight);
    mgr.AddWeaponId(xec_ownerId, xf0_weaponType);
    CSfxManager::AddEmitter(SFXwpn_bomb_drop, GetTranslation(), {}, true, false, 0x7f, -1);
    mgr.InformListeners(GetTranslation(), EListenNoiseType::BombExplode);
    return;
  } else if (msg == EScriptObjectMessage::Deleted) {
    if (x188_lightId != kInvalidUniqueId)
      mgr.FreeScriptObject(x188_lightId);

    if (x190_24_isNotDetonated)
      mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);

    return;
  }

  CActor::AcceptScriptMsg(msg, uid, mgr);
}

static CMaterialFilter kSolidFilter =
    CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {EMaterialTypes::Character, EMaterialTypes::Player,
                                                                  EMaterialTypes::ProjectilePassthrough});
void CBomb::Think(float dt, urde::CStateManager& mgr) {
  CWeapon::Think(dt, mgr);

  if (x190_24_isNotDetonated) {
    if (x17c_fuseTime <= 0.f) {
      Explode(GetTranslation(), mgr);
      if (TCastToPtr<CGameLight> light = mgr.ObjectById(x188_lightId))
        light->SetActive(true);
    }

    if (x17c_fuseTime > 0.5f)
      x180_particle1->Update(dt);
    else
      UpdateLight(dt, mgr);

    if (!x190_26_disableFuse)
      x17c_fuseTime -= dt;
  } else {
    UpdateLight(dt, mgr);
    if (x184_particle2->IsSystemDeletable())
      mgr.FreeScriptObject(GetUniqueId());
  }

  if (x190_24_isNotDetonated) {

    if (x164_acceleration.magSquared() > 0.f)
      x158_velocity += dt * x164_acceleration;

    if (x158_velocity.magSquared() > 0.f) {
      x170_prevLocation = GetTranslation();
      CActor::SetTranslation((dt * x158_velocity) + GetTranslation());

      zeus::CVector3f diffVec = (GetTranslation() - x170_prevLocation);
      float diffMag = diffVec.magnitude();
      if (diffMag == 0.f)
        Explode(GetTranslation(), mgr);
      else {
        CRayCastResult res =
            mgr.RayStaticIntersection(x170_prevLocation, (1.f / diffMag) * diffVec, diffMag, kSolidFilter);
        if (res.IsValid())
          Explode(GetTranslation(), mgr);
      }
    }
  }

  x180_particle1->SetGlobalTranslation(GetTranslation());
  x184_particle2->SetGlobalTranslation(GetTranslation());
}

void CBomb::AddToRenderer(const zeus::CFrustum& frustum, const urde::CStateManager& mgr) const {
  zeus::CVector3f origin = GetTranslation();
  float ballRadius = mgr.GetPlayer().GetMorphBall()->GetBallRadius();

  zeus::CAABox aabox(origin - (0.9f * ballRadius), origin + (0.9f * ballRadius));
  zeus::CVector3f closestPoint = aabox.closestPointAlongVector(CGraphics::g_ViewMatrix.frontVector());

  if (x190_24_isNotDetonated && x17c_fuseTime > 0.5f)
    g_Renderer->AddParticleGen(*x180_particle1, closestPoint, aabox);
  else
    g_Renderer->AddParticleGen(*x184_particle2, closestPoint, aabox);
}

void CBomb::Touch(CActor&, urde::CStateManager&) {
#if 0
    x190_24_isNotDetonated; /* wat? */
#endif
}

std::optional<zeus::CAABox> CBomb::GetTouchBounds() const {
  float radius = (x190_24_isNotDetonated ? 0.2f : x12c_curDamageInfo.GetRadius());
  float minX = (x170_prevLocation.x() >= GetTranslation().x() ? x170_prevLocation.x() : GetTranslation().x()) - radius;
  float minY = (x170_prevLocation.y() >= GetTranslation().y() ? x170_prevLocation.y() : GetTranslation().y()) - radius;
  float minZ = (x170_prevLocation.z() >= GetTranslation().z() ? x170_prevLocation.z() : GetTranslation().z()) - radius;
  float maxX = (x170_prevLocation.x() >= GetTranslation().x() ? x170_prevLocation.x() : GetTranslation().x()) + radius;
  float maxY = (x170_prevLocation.y() >= GetTranslation().y() ? x170_prevLocation.y() : GetTranslation().y()) + radius;
  float maxZ = (x170_prevLocation.z() >= GetTranslation().z() ? x170_prevLocation.z() : GetTranslation().z()) + radius;

  return {{minX, minY, minZ, maxX, maxY, maxZ}};
}

void CBomb::Explode(const zeus::CVector3f& pos, CStateManager& mgr) {
  mgr.ApplyDamageToWorld(xec_ownerId, *this, pos, x12c_curDamageInfo, xf8_filter);
  CSfxManager::AddEmitter(SFXwpn_bomb_explo, GetTranslation(), {}, true, false, 0x7f, -1);
  mgr.InformListeners(pos, EListenNoiseType::BombExplode);
  mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);
  x190_24_isNotDetonated = false;
}
void CBomb::UpdateLight(float dt, CStateManager& mgr) {
  x184_particle2->Update(dt);
  if (x188_lightId == kInvalidUniqueId)
    return;

  if (TCastToPtr<CGameLight> light = mgr.ObjectById(x188_lightId))
    if (light->GetActive())
      light->SetLight(x184_particle2->GetLight());
}

} // namespace urde
<commit_msg>CBomb: Make file-scope material filter constexpr<commit_after>#include "Runtime/Weapon/CBomb.hpp"

#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CBooRenderer.hpp"
#include "Runtime/Particle/CElementGen.hpp"
#include "Runtime/World/CGameLight.hpp"
#include "Runtime/World/CMorphBall.hpp"
#include "Runtime/World/CPlayer.hpp"

#include "DataSpec/DNAMP1/SFX/Weapons.h"

#include "TCastTo.hpp" // Generated file, do not modify include path

namespace urde {

CBomb::CBomb(const TCachedToken<CGenDescription>& particle1, const TCachedToken<CGenDescription>& particle2,
             TUniqueId uid, TAreaId aid, TUniqueId playerId, float f1, const zeus::CTransform& xf,
             const CDamageInfo& dInfo)
: CWeapon(uid, aid, true, playerId, EWeaponType::Bomb, "Bomb", xf,
          CMaterialFilter::MakeIncludeExclude(
              {EMaterialTypes::Solid, EMaterialTypes::Trigger, EMaterialTypes::NonSolidDamageable},
              {EMaterialTypes::Projectile, EMaterialTypes::Bomb}),
          {EMaterialTypes::Projectile, EMaterialTypes::Bomb}, dInfo, EProjectileAttrib::Bombs,
          CModelData::CModelDataNull())
, x17c_fuseTime(f1)
, x180_particle1(std::make_unique<CElementGen>(particle1, CElementGen::EModelOrientationType::Normal,
                                               CElementGen::EOptionalSystemFlags::One))
, x184_particle2(std::make_unique<CElementGen>(particle2, CElementGen::EModelOrientationType::Normal,
                                               CElementGen::EOptionalSystemFlags::One))
, x18c_particle2Obj(particle2.GetObj())
, x190_24_isNotDetonated(true)
, x190_25_beingDragged(false)
, x190_26_disableFuse(false) {
  x180_particle1->SetGlobalTranslation(xf.origin);
  x184_particle2->SetGlobalTranslation(xf.origin);
}

void CBomb::Accept(urde::IVisitor& visitor) { visitor.Visit(this); }

void CBomb::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
  if (msg == EScriptObjectMessage::Registered) {

    x188_lightId = mgr.AllocateUniqueId();
    CGameLight* gameLight = new CGameLight(x188_lightId, GetAreaIdAlways(), false,
                                           std::string("Bomb_PLight") + GetName().data(), GetTransform(), GetUniqueId(),
                                           x184_particle2->GetLight(), reinterpret_cast<size_t>(x18c_particle2Obj), 1, 0.f);
    mgr.AddObject(gameLight);
    mgr.AddWeaponId(xec_ownerId, xf0_weaponType);
    CSfxManager::AddEmitter(SFXwpn_bomb_drop, GetTranslation(), {}, true, false, 0x7f, -1);
    mgr.InformListeners(GetTranslation(), EListenNoiseType::BombExplode);
    return;
  } else if (msg == EScriptObjectMessage::Deleted) {
    if (x188_lightId != kInvalidUniqueId)
      mgr.FreeScriptObject(x188_lightId);

    if (x190_24_isNotDetonated)
      mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);

    return;
  }

  CActor::AcceptScriptMsg(msg, uid, mgr);
}

constexpr CMaterialFilter kSolidFilter =
    CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {EMaterialTypes::Character, EMaterialTypes::Player,
                                                                  EMaterialTypes::ProjectilePassthrough});
void CBomb::Think(float dt, urde::CStateManager& mgr) {
  CWeapon::Think(dt, mgr);

  if (x190_24_isNotDetonated) {
    if (x17c_fuseTime <= 0.f) {
      Explode(GetTranslation(), mgr);
      if (TCastToPtr<CGameLight> light = mgr.ObjectById(x188_lightId))
        light->SetActive(true);
    }

    if (x17c_fuseTime > 0.5f)
      x180_particle1->Update(dt);
    else
      UpdateLight(dt, mgr);

    if (!x190_26_disableFuse)
      x17c_fuseTime -= dt;
  } else {
    UpdateLight(dt, mgr);
    if (x184_particle2->IsSystemDeletable())
      mgr.FreeScriptObject(GetUniqueId());
  }

  if (x190_24_isNotDetonated) {

    if (x164_acceleration.magSquared() > 0.f)
      x158_velocity += dt * x164_acceleration;

    if (x158_velocity.magSquared() > 0.f) {
      x170_prevLocation = GetTranslation();
      CActor::SetTranslation((dt * x158_velocity) + GetTranslation());

      zeus::CVector3f diffVec = (GetTranslation() - x170_prevLocation);
      float diffMag = diffVec.magnitude();
      if (diffMag == 0.f)
        Explode(GetTranslation(), mgr);
      else {
        CRayCastResult res =
            mgr.RayStaticIntersection(x170_prevLocation, (1.f / diffMag) * diffVec, diffMag, kSolidFilter);
        if (res.IsValid())
          Explode(GetTranslation(), mgr);
      }
    }
  }

  x180_particle1->SetGlobalTranslation(GetTranslation());
  x184_particle2->SetGlobalTranslation(GetTranslation());
}

void CBomb::AddToRenderer(const zeus::CFrustum& frustum, const urde::CStateManager& mgr) const {
  zeus::CVector3f origin = GetTranslation();
  float ballRadius = mgr.GetPlayer().GetMorphBall()->GetBallRadius();

  zeus::CAABox aabox(origin - (0.9f * ballRadius), origin + (0.9f * ballRadius));
  zeus::CVector3f closestPoint = aabox.closestPointAlongVector(CGraphics::g_ViewMatrix.frontVector());

  if (x190_24_isNotDetonated && x17c_fuseTime > 0.5f)
    g_Renderer->AddParticleGen(*x180_particle1, closestPoint, aabox);
  else
    g_Renderer->AddParticleGen(*x184_particle2, closestPoint, aabox);
}

void CBomb::Touch(CActor&, urde::CStateManager&) {
#if 0
    x190_24_isNotDetonated; /* wat? */
#endif
}

std::optional<zeus::CAABox> CBomb::GetTouchBounds() const {
  float radius = (x190_24_isNotDetonated ? 0.2f : x12c_curDamageInfo.GetRadius());
  float minX = (x170_prevLocation.x() >= GetTranslation().x() ? x170_prevLocation.x() : GetTranslation().x()) - radius;
  float minY = (x170_prevLocation.y() >= GetTranslation().y() ? x170_prevLocation.y() : GetTranslation().y()) - radius;
  float minZ = (x170_prevLocation.z() >= GetTranslation().z() ? x170_prevLocation.z() : GetTranslation().z()) - radius;
  float maxX = (x170_prevLocation.x() >= GetTranslation().x() ? x170_prevLocation.x() : GetTranslation().x()) + radius;
  float maxY = (x170_prevLocation.y() >= GetTranslation().y() ? x170_prevLocation.y() : GetTranslation().y()) + radius;
  float maxZ = (x170_prevLocation.z() >= GetTranslation().z() ? x170_prevLocation.z() : GetTranslation().z()) + radius;

  return {{minX, minY, minZ, maxX, maxY, maxZ}};
}

void CBomb::Explode(const zeus::CVector3f& pos, CStateManager& mgr) {
  mgr.ApplyDamageToWorld(xec_ownerId, *this, pos, x12c_curDamageInfo, xf8_filter);
  CSfxManager::AddEmitter(SFXwpn_bomb_explo, GetTranslation(), {}, true, false, 0x7f, -1);
  mgr.InformListeners(pos, EListenNoiseType::BombExplode);
  mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);
  x190_24_isNotDetonated = false;
}
void CBomb::UpdateLight(float dt, CStateManager& mgr) {
  x184_particle2->Update(dt);
  if (x188_lightId == kInvalidUniqueId)
    return;

  if (TCastToPtr<CGameLight> light = mgr.ObjectById(x188_lightId))
    if (light->GetActive())
      light->SetLight(x184_particle2->GetLight());
}

} // namespace urde
<|endoftext|>


<commit_before>#pragma once

#include <memory>
#include <string>
#include <vector>

#include "Runtime/RetroTypes.hpp"
#include "Runtime/rstl.hpp"
#include "Runtime/Audio/CSfxManager.hpp"
#include "Runtime/AutoMapper/CMapWorld.hpp"
#include "Runtime/Graphics/CModel.hpp"
#include "Runtime/World/CEnvFxManager.hpp"
#include "Runtime/World/CGameArea.hpp"
#include "Runtime/World/ScriptObjectSupport.hpp"

namespace urde {
class CAudioGroupSet;
class CGameArea;
class CResFactory;
class IGameArea;
class IObjectStore;

class IWorld {
public:
  virtual ~IWorld() = default;
  virtual CAssetId IGetWorldAssetId() const = 0;
  virtual CAssetId IGetStringTableAssetId() const = 0;
  virtual CAssetId IGetSaveWorldAssetId() const = 0;
  virtual const CMapWorld* IGetMapWorld() const = 0;
  virtual CMapWorld* IGetMapWorld() = 0;
  virtual const IGameArea* IGetAreaAlways(TAreaId id) const = 0;
  virtual TAreaId IGetCurrentAreaId() const = 0;
  virtual TAreaId IGetAreaId(CAssetId id) const = 0;
  virtual bool ICheckWorldComplete() = 0;
  virtual std::string IGetDefaultAudioTrack() const = 0;
  virtual int IGetAreaCount() const = 0;
};

class CDummyWorld : public IWorld {
  bool x4_loadMap;
  enum class Phase {
    Loading,
    LoadingMap,
    LoadingMapAreas,
    Done,
  } x8_phase = Phase::Loading;
  CAssetId xc_mlvlId;
  CAssetId x10_strgId;
  CAssetId x14_savwId;
  std::vector<CDummyGameArea> x18_areas;
  CAssetId x28_mapWorldId;
  TLockedToken<CMapWorld> x2c_mapWorld;
  std::shared_ptr<IDvdRequest> x30_loadToken;
  std::unique_ptr<uint8_t[]> x34_loadBuf;
  u32 x38_bufSz;
  TAreaId x3c_curAreaId = kInvalidAreaId;

public:
  CDummyWorld(CAssetId mlvlId, bool loadMap);
  ~CDummyWorld() override;
  CAssetId IGetWorldAssetId() const override;
  CAssetId IGetStringTableAssetId() const override;
  CAssetId IGetSaveWorldAssetId() const override;
  const CMapWorld* IGetMapWorld() const override;
  CMapWorld* IGetMapWorld() override;
  const IGameArea* IGetAreaAlways(TAreaId id) const override;
  TAreaId IGetCurrentAreaId() const override;
  TAreaId IGetAreaId(CAssetId id) const override;
  bool ICheckWorldComplete() override;
  std::string IGetDefaultAudioTrack() const override;
  int IGetAreaCount() const override;
};

class CWorld : public IWorld {
  friend class CStateManager;

public:
  class CRelay {
    TEditorId x0_relay = kInvalidEditorId;
    TEditorId x4_target = kInvalidEditorId;
    s16 x8_msg = -1;
    bool xa_active = false;

  public:
    CRelay() = default;
    CRelay(CInputStream& in);

    TEditorId GetRelayId() const { return x0_relay; }
    TEditorId GetTargetId() const { return x4_target; }
    s16 GetMessage() const { return x8_msg; }
    bool GetActive() const { return xa_active; }

    static std::vector<CWorld::CRelay> ReadMemoryRelays(athena::io::MemoryReader& r);
  };

  struct CSoundGroupData {
    int x0_groupId;
    CAssetId x4_agscId;
    std::string xc_name;
    TCachedToken<CAudioGroupSet> x1c_groupData;

  public:
    CSoundGroupData(int grpId, CAssetId agsc);
  };

private:
  static constexpr CGameArea* skGlobalEnd = nullptr;
  static constexpr CGameArea* skGlobalNonConstEnd = nullptr;
  enum class Phase {
    Loading,
    LoadingMap,
    LoadingMapAreas,
    LoadingSkyBox,
    LoadingSoundGroups,
    Done,
  } x4_phase = Phase::Loading;
  CAssetId x8_mlvlId;
  CAssetId xc_strgId;
  CAssetId x10_savwId;
  std::vector<std::unique_ptr<CGameArea>> x18_areas;
  CAssetId x24_mapwId;
  TLockedToken<CMapWorld> x28_mapWorld;
  std::vector<CRelay> x2c_relays;
  std::shared_ptr<IDvdRequest> x3c_loadToken;
  std::unique_ptr<uint8_t[]> x40_loadBuf;
  u32 x44_bufSz;
  u32 x48_chainCount = 0;
  CGameArea* x4c_chainHeads[5] = {};

  IObjectStore& x60_objectStore;
  IFactory& x64_resFactory;
  TAreaId x68_curAreaId = kInvalidAreaId;
  u32 x6c_loadedAudioGrpCount = 0;

  union {
    struct {
      bool x70_24_currentAreaNeedsAllocation : 1;
      bool x70_25_loadPaused : 1;
      bool x70_26_skyboxActive : 1;
      bool x70_27_skyboxVisible : 1;
    };
    u32 dummy = 0;
  };
  std::vector<CSoundGroupData> x74_soundGroupData;
  std::string x84_defAudioTrack;
  std::optional<TLockedToken<CModel>> x94_skyboxWorld;
  std::optional<TLockedToken<CModel>> xa4_skyboxWorldLoaded;
  std::optional<TLockedToken<CModel>> xb4_skyboxOverride;
  EEnvFxType xc4_neededFx = EEnvFxType::None;
  rstl::reserved_vector<CSfxHandle, 10> xc8_globalSfxHandles;

  void LoadSoundGroup(int groupId, CAssetId agscId, CSoundGroupData& data);
  void LoadSoundGroups();
  void UnloadSoundGroups();
  void StopSounds();

public:
  void MoveToChain(CGameArea* area, EChain chain);
  void MoveAreaToAliveChain(TAreaId aid);
  bool CheckWorldComplete(CStateManager* mgr, TAreaId id, CAssetId mreaId);
  CGameArea::CChainIterator GetChainHead(EChain chain) { return {x4c_chainHeads[int(chain)]}; }
  CGameArea::CConstChainIterator GetChainHead(EChain chain) const { return {x4c_chainHeads[int(chain)]}; }
  CGameArea::CChainIterator begin() { return GetChainHead(EChain::Alive); }
  CGameArea::CChainIterator end() { return AliveAreasEnd(); }
  CGameArea::CConstChainIterator begin() const { return GetChainHead(EChain::Alive); }
  CGameArea::CConstChainIterator end() const { return GetAliveAreasEnd(); }
  bool ScheduleAreaToLoad(CGameArea* area, CStateManager& mgr);
  void TravelToArea(TAreaId aid, CStateManager& mgr, bool);
  void SetLoadPauseState(bool paused);
  void CycleLoadPauseState();

  CWorld(IObjectStore& objStore, IFactory& resFactory, CAssetId mlvlId);
  ~CWorld();
  bool DoesAreaExist(TAreaId area) const;
  const std::vector<std::unique_ptr<CGameArea>>& GetGameAreas() const { return x18_areas; }

  const CMapWorld* GetMapWorld() const { return x28_mapWorld.GetObj(); }
  u32 GetRelayCount() const { return x2c_relays.size(); }
  CRelay GetRelay(u32 idx) const { return x2c_relays[idx]; }

  CAssetId IGetWorldAssetId() const override;
  CAssetId IGetStringTableAssetId() const override;
  CAssetId IGetSaveWorldAssetId() const override;
  const CMapWorld* IGetMapWorld() const override;
  CMapWorld* IGetMapWorld() override;
  const CGameArea* GetAreaAlways(TAreaId) const;
  CGameArea* GetArea(TAreaId);
  s32 GetNumAreas() const { return x18_areas.size(); }
  const IGameArea* IGetAreaAlways(TAreaId id) const override;
  TAreaId IGetCurrentAreaId() const override;
  TAreaId GetCurrentAreaId() const { return x68_curAreaId; }
  TAreaId IGetAreaId(CAssetId id) const override;
  bool ICheckWorldComplete() override;
  std::string IGetDefaultAudioTrack() const override;
  int IGetAreaCount() const override;

  static void PropogateAreaChain(CGameArea::EOcclusionState, CGameArea*, CWorld*);
  static CGameArea::CConstChainIterator GetAliveAreasEnd() { return {skGlobalEnd}; }
  static CGameArea::CChainIterator AliveAreasEnd() { return {skGlobalNonConstEnd}; }

  void Update(float dt);
  void PreRender();
  void TouchSky();
  void DrawSky(const zeus::CTransform& xf) const;
  void StopGlobalSound(u16 id);
  bool HasGlobalSound(u16 id) const;
  void AddGlobalSound(const CSfxHandle& hnd);
  EEnvFxType GetNeededEnvFx() const { return xc4_neededFx; }
  CAssetId GetWorldAssetId() const { return x8_mlvlId; }
  bool AreSkyNeedsMet() const;
  TAreaId GetAreaIdForSaveId(s32 saveId) const;
};

struct CWorldLayers {
  struct Area {
    u32 m_startNameIdx;
    u32 m_layerCount;
    u64 m_layerBits;
  };
  std::vector<Area> m_areas;
  std::vector<std::string> m_names;
  static void ReadWorldLayers(athena::io::MemoryReader& r, int version, CAssetId mlvlId);
};

} // namespace urde
<commit_msg>CWorld: Provide parameter names for prototypes<commit_after>#pragma once

#include <memory>
#include <string>
#include <vector>

#include "Runtime/RetroTypes.hpp"
#include "Runtime/rstl.hpp"
#include "Runtime/Audio/CSfxManager.hpp"
#include "Runtime/AutoMapper/CMapWorld.hpp"
#include "Runtime/Graphics/CModel.hpp"
#include "Runtime/World/CEnvFxManager.hpp"
#include "Runtime/World/CGameArea.hpp"
#include "Runtime/World/ScriptObjectSupport.hpp"

namespace urde {
class CAudioGroupSet;
class CGameArea;
class CResFactory;
class IGameArea;
class IObjectStore;

class IWorld {
public:
  virtual ~IWorld() = default;
  virtual CAssetId IGetWorldAssetId() const = 0;
  virtual CAssetId IGetStringTableAssetId() const = 0;
  virtual CAssetId IGetSaveWorldAssetId() const = 0;
  virtual const CMapWorld* IGetMapWorld() const = 0;
  virtual CMapWorld* IGetMapWorld() = 0;
  virtual const IGameArea* IGetAreaAlways(TAreaId id) const = 0;
  virtual TAreaId IGetCurrentAreaId() const = 0;
  virtual TAreaId IGetAreaId(CAssetId id) const = 0;
  virtual bool ICheckWorldComplete() = 0;
  virtual std::string IGetDefaultAudioTrack() const = 0;
  virtual int IGetAreaCount() const = 0;
};

class CDummyWorld : public IWorld {
  bool x4_loadMap;
  enum class Phase {
    Loading,
    LoadingMap,
    LoadingMapAreas,
    Done,
  } x8_phase = Phase::Loading;
  CAssetId xc_mlvlId;
  CAssetId x10_strgId;
  CAssetId x14_savwId;
  std::vector<CDummyGameArea> x18_areas;
  CAssetId x28_mapWorldId;
  TLockedToken<CMapWorld> x2c_mapWorld;
  std::shared_ptr<IDvdRequest> x30_loadToken;
  std::unique_ptr<uint8_t[]> x34_loadBuf;
  u32 x38_bufSz;
  TAreaId x3c_curAreaId = kInvalidAreaId;

public:
  CDummyWorld(CAssetId mlvlId, bool loadMap);
  ~CDummyWorld() override;
  CAssetId IGetWorldAssetId() const override;
  CAssetId IGetStringTableAssetId() const override;
  CAssetId IGetSaveWorldAssetId() const override;
  const CMapWorld* IGetMapWorld() const override;
  CMapWorld* IGetMapWorld() override;
  const IGameArea* IGetAreaAlways(TAreaId id) const override;
  TAreaId IGetCurrentAreaId() const override;
  TAreaId IGetAreaId(CAssetId id) const override;
  bool ICheckWorldComplete() override;
  std::string IGetDefaultAudioTrack() const override;
  int IGetAreaCount() const override;
};

class CWorld : public IWorld {
  friend class CStateManager;

public:
  class CRelay {
    TEditorId x0_relay = kInvalidEditorId;
    TEditorId x4_target = kInvalidEditorId;
    s16 x8_msg = -1;
    bool xa_active = false;

  public:
    CRelay() = default;
    CRelay(CInputStream& in);

    TEditorId GetRelayId() const { return x0_relay; }
    TEditorId GetTargetId() const { return x4_target; }
    s16 GetMessage() const { return x8_msg; }
    bool GetActive() const { return xa_active; }

    static std::vector<CWorld::CRelay> ReadMemoryRelays(athena::io::MemoryReader& r);
  };

  struct CSoundGroupData {
    int x0_groupId;
    CAssetId x4_agscId;
    std::string xc_name;
    TCachedToken<CAudioGroupSet> x1c_groupData;

  public:
    CSoundGroupData(int grpId, CAssetId agsc);
  };

private:
  static constexpr CGameArea* skGlobalEnd = nullptr;
  static constexpr CGameArea* skGlobalNonConstEnd = nullptr;
  enum class Phase {
    Loading,
    LoadingMap,
    LoadingMapAreas,
    LoadingSkyBox,
    LoadingSoundGroups,
    Done,
  } x4_phase = Phase::Loading;
  CAssetId x8_mlvlId;
  CAssetId xc_strgId;
  CAssetId x10_savwId;
  std::vector<std::unique_ptr<CGameArea>> x18_areas;
  CAssetId x24_mapwId;
  TLockedToken<CMapWorld> x28_mapWorld;
  std::vector<CRelay> x2c_relays;
  std::shared_ptr<IDvdRequest> x3c_loadToken;
  std::unique_ptr<uint8_t[]> x40_loadBuf;
  u32 x44_bufSz;
  u32 x48_chainCount = 0;
  CGameArea* x4c_chainHeads[5] = {};

  IObjectStore& x60_objectStore;
  IFactory& x64_resFactory;
  TAreaId x68_curAreaId = kInvalidAreaId;
  u32 x6c_loadedAudioGrpCount = 0;

  union {
    struct {
      bool x70_24_currentAreaNeedsAllocation : 1;
      bool x70_25_loadPaused : 1;
      bool x70_26_skyboxActive : 1;
      bool x70_27_skyboxVisible : 1;
    };
    u32 dummy = 0;
  };
  std::vector<CSoundGroupData> x74_soundGroupData;
  std::string x84_defAudioTrack;
  std::optional<TLockedToken<CModel>> x94_skyboxWorld;
  std::optional<TLockedToken<CModel>> xa4_skyboxWorldLoaded;
  std::optional<TLockedToken<CModel>> xb4_skyboxOverride;
  EEnvFxType xc4_neededFx = EEnvFxType::None;
  rstl::reserved_vector<CSfxHandle, 10> xc8_globalSfxHandles;

  void LoadSoundGroup(int groupId, CAssetId agscId, CSoundGroupData& data);
  void LoadSoundGroups();
  void UnloadSoundGroups();
  void StopSounds();

public:
  void MoveToChain(CGameArea* area, EChain chain);
  void MoveAreaToAliveChain(TAreaId aid);
  bool CheckWorldComplete(CStateManager* mgr, TAreaId id, CAssetId mreaId);
  CGameArea::CChainIterator GetChainHead(EChain chain) { return {x4c_chainHeads[int(chain)]}; }
  CGameArea::CConstChainIterator GetChainHead(EChain chain) const { return {x4c_chainHeads[int(chain)]}; }
  CGameArea::CChainIterator begin() { return GetChainHead(EChain::Alive); }
  CGameArea::CChainIterator end() { return AliveAreasEnd(); }
  CGameArea::CConstChainIterator begin() const { return GetChainHead(EChain::Alive); }
  CGameArea::CConstChainIterator end() const { return GetAliveAreasEnd(); }
  bool ScheduleAreaToLoad(CGameArea* area, CStateManager& mgr);
  void TravelToArea(TAreaId aid, CStateManager& mgr, bool skipLoadOther);
  void SetLoadPauseState(bool paused);
  void CycleLoadPauseState();

  CWorld(IObjectStore& objStore, IFactory& resFactory, CAssetId mlvlId);
  ~CWorld();
  bool DoesAreaExist(TAreaId area) const;
  const std::vector<std::unique_ptr<CGameArea>>& GetGameAreas() const { return x18_areas; }

  const CMapWorld* GetMapWorld() const { return x28_mapWorld.GetObj(); }
  u32 GetRelayCount() const { return x2c_relays.size(); }
  CRelay GetRelay(u32 idx) const { return x2c_relays[idx]; }

  CAssetId IGetWorldAssetId() const override;
  CAssetId IGetStringTableAssetId() const override;
  CAssetId IGetSaveWorldAssetId() const override;
  const CMapWorld* IGetMapWorld() const override;
  CMapWorld* IGetMapWorld() override;
  const CGameArea* GetAreaAlways(TAreaId id) const;
  CGameArea* GetArea(TAreaId);
  s32 GetNumAreas() const { return x18_areas.size(); }
  const IGameArea* IGetAreaAlways(TAreaId id) const override;
  TAreaId IGetCurrentAreaId() const override;
  TAreaId GetCurrentAreaId() const { return x68_curAreaId; }
  TAreaId IGetAreaId(CAssetId id) const override;
  bool ICheckWorldComplete() override;
  std::string IGetDefaultAudioTrack() const override;
  int IGetAreaCount() const override;

  static void PropogateAreaChain(CGameArea::EOcclusionState occlusionState, CGameArea* area, CWorld* world);
  static CGameArea::CConstChainIterator GetAliveAreasEnd() { return {skGlobalEnd}; }
  static CGameArea::CChainIterator AliveAreasEnd() { return {skGlobalNonConstEnd}; }

  void Update(float dt);
  void PreRender();
  void TouchSky();
  void DrawSky(const zeus::CTransform& xf) const;
  void StopGlobalSound(u16 id);
  bool HasGlobalSound(u16 id) const;
  void AddGlobalSound(const CSfxHandle& hnd);
  EEnvFxType GetNeededEnvFx() const { return xc4_neededFx; }
  CAssetId GetWorldAssetId() const { return x8_mlvlId; }
  bool AreSkyNeedsMet() const;
  TAreaId GetAreaIdForSaveId(s32 saveId) const;
};

struct CWorldLayers {
  struct Area {
    u32 m_startNameIdx;
    u32 m_layerCount;
    u64 m_layerBits;
  };
  std::vector<Area> m_areas;
  std::vector<std::string> m_names;
  static void ReadWorldLayers(athena::io::MemoryReader& r, int version, CAssetId mlvlId);
};

} // namespace urde
<|endoftext|>


<commit_before>
// Implementation for TestArray. See TestByte.cc
//
// jhrg 1/12/95

// $Log: TestArray.cc,v $
// Revision 1.4  1995/03/04 14:38:00  jimg
// Modified these so that they fit with the changes in the DAP classes.
//
// Revision 1.3  1995/02/10  02:33:37  jimg
// Modified Test<class>.h and .cc so that they used to new definitions of
// read_val().
// Modified the classes read() so that they are more in line with the
// class library's intended use in a real subclass set.
//
// Revision 1.2  1995/01/19  21:58:50  jimg
// Added read_val from dummy_read.cc to the sample set of sub-class
// implementations.
// Changed the declaration of readVal in BaseType so that it names the
// mfunc read_val (to be consistant with the other mfunc names).
// Removed the unnecessary duplicate declaration of the abstract virtual
// mfuncs read and (now) read_val from the classes Byte, ... Grid. The
// declaration in BaseType is sufficient along with the decl and definition
// in the *.cc,h files which contain the subclasses for Byte, ..., Grid.
//
// Revision 1.1  1995/01/19  20:20:34  jimg
// Created as an example of subclassing the class hierarchy rooted at
// BaseType.
//

#ifdef __GNUG__
#pragma implementation
#endif

#include <assert.h>

#include "TestArray.h"
#include "Test.h"

String testarray = "TestArray";

Array *
NewArray(const String &n, BaseType *v)
{
    return new TestArray(n, v);
}

BaseType *
TestArray::ptr_duplicate()
{
    return new TestArray(*this);
}

TestArray::TestArray(const String &n, BaseType *v) : Array(n, v)
{
}

TestArray::~TestArray()
{
}

bool
TestArray::read(String dataset, String var_name, String constraint)
{
    unsigned int wid = var()->width(); // size of the contained variable

    // run read() on the contained variable to get, via the read() mfuncs
    // defined in the other Test classes, a value in the *contained* object.
    var()->read(dataset, var_name, constraint);

    // OK, now make an array of those things, and copy the value length()
    // times.
    unsigned int len = length();
    char *tmp = new char[width()];
    void *elem_val = 0;		// the null forces a new object to be
				// allocated

    var()->read_val(&elem_val);

    for (int i = 0; i < len; ++i)
	memcpy(tmp + i * wid, elem_val, wid);

    store_val(tmp);

    delete tmp;
}
<commit_msg>Fixed bugs with read()s new & delete calls.<commit_after>
// Implementation for TestArray. See TestByte.cc
//
// jhrg 1/12/95

// $Log: TestArray.cc,v $
// Revision 1.5  1995/03/16 17:32:27  jimg
// Fixed bugs with read()s new & delete calls.
//
// Revision 1.4  1995/03/04  14:38:00  jimg
// Modified these so that they fit with the changes in the DAP classes.
//
// Revision 1.3  1995/02/10  02:33:37  jimg
// Modified Test<class>.h and .cc so that they used to new definitions of
// read_val().
// Modified the classes read() so that they are more in line with the
// class library's intended use in a real subclass set.
//
// Revision 1.2  1995/01/19  21:58:50  jimg
// Added read_val from dummy_read.cc to the sample set of sub-class
// implementations.
// Changed the declaration of readVal in BaseType so that it names the
// mfunc read_val (to be consistant with the other mfunc names).
// Removed the unnecessary duplicate declaration of the abstract virtual
// mfuncs read and (now) read_val from the classes Byte, ... Grid. The
// declaration in BaseType is sufficient along with the decl and definition
// in the *.cc,h files which contain the subclasses for Byte, ..., Grid.
//
// Revision 1.1  1995/01/19  20:20:34  jimg
// Created as an example of subclassing the class hierarchy rooted at
// BaseType.
//

#ifdef __GNUG__
#pragma implementation
#endif

#include "config.h"

#include <assert.h>

#include "TestArray.h"

#ifdef TRACE_NEW
#include "trace_new.h"
#endif

Array *
NewArray(const String &n, BaseType *v)
{
    return new TestArray(n, v);
}

BaseType *
TestArray::ptr_duplicate()
{
    return new TestArray(*this);
}

TestArray::TestArray(const String &n, BaseType *v) : Array(n, v)
{
}

TestArray::~TestArray()
{
}

bool
TestArray::read(String dataset, String var_name, String constraint)
{
    unsigned int wid = var()->width(); // size of the contained variable

    // run read() on the contained variable to get, via the read() mfuncs
    // defined in the other Test classes, a value in the *contained* object.
    var()->read(dataset, var_name, constraint);

    // OK, now make an array of those things, and copy the value length()
    // times.
    unsigned int len = length();
    char *tmp = new char[width()];
    void *elem_val = 0;		// the null forces a new object to be
				// allocated

    var()->read_val(&elem_val);	// read_val() allocates space as an array...

    for (int i = 0; i < len; ++i)
	memcpy(tmp + i * wid, elem_val, wid);

    store_val(tmp);

    delete[] elem_val;
    delete[] tmp;
}
<|endoftext|>