<commit_before>#include "shaders.h"

//#include "mathutils.h"

#define INVALID_SHADER 0

#define DEBUG_SHADER_ERRORS true

//
// AnyShader
//

AnyShader::AnyShader() {
    //empty
}

AnyShader::~AnyShader() {
    //empty
}

/**
 * Create the shader program.
 */
bool AnyShader::create() {
    if (failed) {
        return false;
    }

    if (prog != INVALID_PROGRAM) {
        return true;
    }

    //compile
    GLuint handle = glCreateProgram();

    if (handle == INVALID_PROGRAM) {
        error = "glCreateProgram failed.";

        return false;
    }

    if (!vertexShader.empty()) {
        GLuint vertShader = compileShader(vertexShader, GL_VERTEX_SHADER);

        if (vertShader == INVALID_SHADER) {
            //cleanup
            glDeleteProgram(handle);

            return false;
        }

        glAttachShader(handle, vertShader);
        glDeleteShader(vertShader);
    }

    if (!fragmentShader.empty()) {
        GLuint fragShader = compileShader(fragmentShader, GL_FRAGMENT_SHADER);

        if (fragShader == INVALID_SHADER) {
            //cleanup
            glDeleteProgram(handle);

            return false;
        }

        glAttachShader(handle, fragShader);
        glDeleteShader(fragShader);
    }

    //link
    glLinkProgram(handle);

    GLint linkStatus;

    glGetProgramiv(handle, GL_LINK_STATUS, &linkStatus);

    if (linkStatus == GL_FALSE) {
        //cleanup
        glDeleteProgram(handle);

        //get error
        GLchar messages[256];

        glGetProgramInfoLog(handle, sizeof(messages), 0, &messages[0]);

        if (DEBUG_SHADER_ERRORS) {
            printf("shader linking failed: %s\n", messages);
        }

        return false;
    }

    prog = handle;

    //initialize
    initShader();

    return true;
}

/**
 * Compile a shader.
 *
 * Note: sets error on failure.
 */
GLuint AnyShader::compileShader(std::string source, const GLenum type) {
    GLint compileStatus;
    GLuint handle = glCreateShader(type);

    if (handle == INVALID_SHADER) {
        error = "glCreateShader() failed";
        return -1;
    }

#ifdef RPI
    //add GLSL version
    source = "#version 100\n" + source;
#endif

    GLchar *src = (GLchar *)source.c_str();

    glShaderSource(handle, 1, (const GLchar **)&src, NULL);
    glCompileShader(handle);

    //get status
    glGetShaderiv(handle, GL_COMPILE_STATUS, &compileStatus);

    if (compileStatus == GL_FALSE) {
        //free
        glDeleteShader(handle);
        handle = INVALID_SHADER;

        //get error
        GLchar messages[256];

        glGetShaderInfoLog(handle, sizeof(messages), 0, &messages[0]);

        if (DEBUG_SHADER_ERRORS) {
            std::string typeStr;

            if (type == GL_VERTEX_SHADER) {
                typeStr = "vertex shader";
            } else if (type == GL_FRAGMENT_SHADER) {
                typeStr = "fragment shader";
            }

            printf("shader compilation error: %s\ntype: %s\n", messages, typeStr.c_str());
        }

        error = std::string(messages);
    }

    return handle;
}

/**
 * Destroy the shader.
 *
 * Note: has to be called in OpenGL thread.
 */
void AnyShader::destroy() {
    if (prog != INVALID_PROGRAM) {
        glDeleteProgram(prog);
        prog = INVALID_PROGRAM;
    }

    //reset failed
    failed = false;
}

/**
 * Get attribute location.
 */
GLint AnyShader::getAttributeLocation(std::string name) {
    GLint loc = glGetAttribLocation(prog, name.c_str());

    if (DEBUG_SHADER_ERRORS) {
        if (loc == -1) {
            printf("could not get location of attribute %s\n", name.c_str());
        }
    }

    return loc;
}

/**
 * Get uniform location.
 */
GLint AnyShader::getUniformLocation(std::string name) {
    GLint loc = glGetUniformLocation(prog, name.c_str());

    if (DEBUG_SHADER_ERRORS) {
        if (loc == -1) {
            printf("could not get location of uniform %s\n", name.c_str());
        }
    }

    return loc;
}

/**
 * Use the shader.
 *
 * Note: has to be called before any setters are used!
 */
void AnyShader::useShader(bool active) {
    if (!active) {
        glUseProgram(prog);
    }
}

//
// AnyAminoShader
//

AnyAminoShader::AnyAminoShader() : AnyShader() {
    //default vertex shader
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        attribute vec4 pos;

        void main() {
            gl_Position = mvp * trans * pos;
        }
    )";
}

/**
 * Initialize the shader.
 */
void AnyAminoShader::initShader() {
    useShader(false);

    //attributes
    aPos = getAttributeLocation("pos");

    //uniforms
    uMVP = getUniformLocation("mvp");
    uTrans = getUniformLocation("trans");
}

/**
 * Set transformation matrix.
 */
void AnyAminoShader::setTransformation(GLfloat modelView[16], GLfloat transition[16]) {
    glUniformMatrix4fv(uMVP, 1, GL_FALSE, modelView);
    glUniformMatrix4fv(uTrans, 1, GL_FALSE, transition);
}

/**
 * Set vertex data.
 */
void AnyAminoShader::setVertexData(GLsizei dim, GLfloat *vertices) {
    /*
     * Coords per vertex (2 or 3).
     *
     * Note: vertices is NULL in case of VBO usage
     */

    glVertexAttribPointer(aPos, dim, GL_FLOAT, GL_FALSE, 0, vertices);
}

/**
 * Draw triangles.
 */
void AnyAminoShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aPos);

    glDrawArrays(mode, 0, vertices);

    glDisableVertexAttribArray(aPos);
}

/**
 * Draw elements.
 */
void AnyAminoShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aPos);

    //Note: indices is offset in case of VBO
    glDrawElements(mode, elements, GL_UNSIGNED_SHORT, indices);

    glDisableVertexAttribArray(aPos);
}

//
// ColorShader
//

/**
 * Create color shader.
 */
ColorShader::ColorShader() : AnyAminoShader() {
    //shaders
    fragmentShader = R"(
        uniform vec4 color;

        void main() {
            gl_FragColor = color;
        }
    )";
}

/**
 * Initialize the color shader.
 */
void ColorShader::initShader() {
    AnyAminoShader::initShader();

    //uniforms
    uColor = getUniformLocation("color");
}

/**
 * Set color.
 */
void ColorShader::setColor(GLfloat color[4]) {
    glUniform4f(uColor, color[0], color[1], color[2], color[3]);
}

//
// ColorLightingShader
//

/**
 * Create color lighting shader.
 */
ColorLightingShader::ColorLightingShader() : ColorShader() {
    //shaders
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        //uniform mat4 normalMatrix;
        uniform vec3 lightDir;

        attribute vec4 pos;
        attribute vec3 normal;

        varying float lightFac;

        void main() {
            gl_Position = mvp * trans * pos;

            //simple version
            vec4 normalTrans = trans * vec4(normal, 0.);

            lightFac = abs(dot(normalTrans.xyz, -lightDir));
        }
    )";

    fragmentShader = R"(
        varying float lightFac;

        uniform vec4 color;

        void main() {
            gl_FragColor = vec4(color.rgb * lightFac, color.a);
        }
    )";
}

/**
 * Initialize the color lighting shader.
 */
void ColorLightingShader::initShader() {
    ColorShader::initShader();

    //attributes
    aNormal = getAttributeLocation("normal");

    //uniforms
    //uNormalMatrix = getUniformLocation("normalMatrix");
    uLightDir = getUniformLocation("lightDir");

    //default values
    GLfloat lightDir[3] = { 0, 0, -1 }; //parallel light on screen

    setLightDirection(lightDir);
}

/**
 * Set light direction.
 */
void ColorLightingShader::setLightDirection(GLfloat dir[3]) {
    glUniform3f(uLightDir, dir[0], dir[1], dir[2]);
}

/**
 * Set normal vectors.
 */
void ColorLightingShader::setNormalVectors(GLfloat *normals) {
    glVertexAttribPointer(aNormal, 3, GL_FLOAT, GL_FALSE, 0, normals);
}

/**
 * Set matrix.
 */
void ColorLightingShader::setTransformation(GLfloat modelView[16], GLfloat transition[16]) {
    AnyAminoShader::setTransformation(modelView, transition);

    //normal matrix
    /*
    GLfloat invMatrix[16];
    GLfloat normalMatrix[16];

    assert(invert_matrix(transition, invMatrix));
    transpose_matrix(normalMatrix, invMatrix);

    glUniformMatrix4fv(uNormalMatrix, 1, GL_FALSE, normalMatrix);
    */
}

/**
 * Draw triangles.
 */
void ColorLightingShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    AnyAminoShader::drawTriangles(vertices, mode);

    glDisableVertexAttribArray(aNormal);
}

/**
 * Draw elements.
 */
void ColorLightingShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    AnyAminoShader::drawElements(indices, elements, mode);

    glDisableVertexAttribArray(aNormal);
}

//
// TextureShader
//

TextureShader::TextureShader() : AnyAminoShader() {
    //shader
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        attribute vec4 pos;
        attribute vec2 texCoord;

        varying vec2 uv;

        void main() {
            gl_Position = mvp * trans * pos;
            uv = texCoord;
        }
    )";

    fragmentShader = R"(
        varying vec2 uv;

        uniform float opacity;
        uniform sampler2D tex;

        void main() {
            vec4 pixel = texture2D(tex, uv);

            //discard transparent pixels
            if (pixel.a == 0.) {
                discard;
            }

            gl_FragColor = vec4(pixel.rgb, pixel.a * opacity);
        }
    )";
}

/**
 * Initialize the color shader.
 */
void TextureShader::initShader() {
    AnyAminoShader::initShader();

    //attributes
    aTexCoord = getAttributeLocation("texCoord");

    //uniforms
    uOpacity = getUniformLocation("opacity");
    uTex = getUniformLocation("tex");

    //default values
    glUniform1i(uTex, 0); //GL_TEXTURE0
}

/**
 * Set opacity.
 */
void TextureShader::setOpacity(GLfloat opacity) {
    glUniform1f(uOpacity, opacity);
}

/**
 * Set texture coordinates.
 */
void TextureShader::setTextureCoordinates(GLfloat uv[][2]) {
    glVertexAttribPointer(aTexCoord, 2, GL_FLOAT, GL_FALSE, 0, uv);
}

/**
 * Draw texture.
 */
void TextureShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aTexCoord);

    glActiveTexture(GL_TEXTURE0);

    AnyAminoShader::drawTriangles(vertices, mode);

    glDisableVertexAttribArray(aTexCoord);
}

/**
 * Draw elements.
 */
void TextureShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aTexCoord);

    glActiveTexture(GL_TEXTURE0);

    AnyAminoShader::drawElements(indices, elements, mode);

    glDisableVertexAttribArray(aTexCoord);
}

//
// TextureClampToBorderShader
//

TextureClampToBorderShader::TextureClampToBorderShader() : TextureShader() {
    //Note: supports clamp to border, using transparent texture
    fragmentShader = R"(
        varying vec2 uv;

        uniform float opacity;
        uniform bvec2 repeat;
        uniform sampler2D tex;

        float clamp_to_border_factor(vec2 coords) {
            bvec2 out1 = greaterThan(coords, vec2(1, 1));
            bvec2 out2 = lessThan(coords, vec2(0, 0));
            bool do_clamp = (any(out1) || any(out2));

            return float(!do_clamp);
        }

        void main() {
            //repeat
            vec2 uv2 = uv;

            if (repeat.x) {
                uv2.x = fract(uv.x);
            }

            if (repeat.y) {
                uv2.y = fract(uv.y);
            }

            //show pixel
            vec4 pixel = texture2D(tex, uv2);

            //discard transparent pixels
            if (pixel.a == 0.) {
                discard;
            }

            gl_FragColor = vec4(pixel.rgb, pixel.a * opacity * clamp_to_border_factor(uv2));
        }
    )";
}

/**
 * Initialize the shader.
 */
void TextureClampToBorderShader::initShader() {
    TextureShader::initShader();

    uRepeat = getUniformLocation("repeat");
}

/**
 * Set repeat directions.
 */
void TextureClampToBorderShader::setRepeat(bool repeatX, bool repeatY) {
    glUniform2i(uRepeat, repeatX, repeatY);
}

//
// TextureLightingShader
//

/**
 * Create color lighting shader.
 */
TextureLightingShader::TextureLightingShader() : TextureShader() {
    //shaders
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        uniform vec3 lightDir;

        attribute vec4 pos;
        attribute vec2 texCoord;
        attribute vec3 normal;

        varying vec2 uv;
        varying float lightFac;

        void main() {
            gl_Position = mvp * trans * pos;

            uv = texCoord;

            vec4 normalTrans = trans * vec4(normal, 0.);

            //translucent layers
            lightFac = abs(dot(normalTrans.xyz, -lightDir));
        }
    )";

    fragmentShader = R"(
        varying vec2 uv;
        varying float lightFac;

        uniform float opacity;
        uniform sampler2D tex;

        void main() {
            vec4 pixel = texture2D(tex, uv);

            //discard transparent pixels
            if (pixel.a == 0.) {
                discard;
            }

            gl_FragColor = vec4(pixel.rgb * lightFac, pixel.a * opacity);
        }
    )";
}

/**
 * Initialize the color lighting shader.
 */
void TextureLightingShader::initShader() {
    TextureShader::initShader();

    //attributes
    aNormal = getAttributeLocation("normal");

    //uniforms
    //uNormalMatrix = getUniformLocation("normalMatrix");
    uLightDir = getUniformLocation("lightDir");

    //default values
    GLfloat lightDir[3] = { 0, 0, -1 }; //parallel light on screen

    setLightDirection(lightDir);
}

/**
 * Set light direction.
 */
void TextureLightingShader::setLightDirection(GLfloat dir[3]) {
    glUniform3f(uLightDir, dir[0], dir[1], dir[2]);
}

/**
 * Set normal vectors.
 */
void TextureLightingShader::setNormalVectors(GLfloat *normals) {
    glVertexAttribPointer(aNormal, 3, GL_FLOAT, GL_FALSE, 0, normals);
}

/**
 * Draw triangles.
 */
void TextureLightingShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    TextureShader::drawTriangles(vertices, mode);

    glDisableVertexAttribArray(aNormal);
}

/**
 * Draw elements.
 */
void TextureLightingShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    TextureShader::drawElements(indices, elements, mode);

    glDisableVertexAttribArray(aNormal);
}
<commit_msg>clamp: use discard<commit_after>#include "shaders.h"

//#include "mathutils.h"

#define INVALID_SHADER 0

#define DEBUG_SHADER_ERRORS true

//
// AnyShader
//

AnyShader::AnyShader() {
    //empty
}

AnyShader::~AnyShader() {
    //empty
}

/**
 * Create the shader program.
 */
bool AnyShader::create() {
    if (failed) {
        return false;
    }

    if (prog != INVALID_PROGRAM) {
        return true;
    }

    //compile
    GLuint handle = glCreateProgram();

    if (handle == INVALID_PROGRAM) {
        error = "glCreateProgram failed.";

        return false;
    }

    if (!vertexShader.empty()) {
        GLuint vertShader = compileShader(vertexShader, GL_VERTEX_SHADER);

        if (vertShader == INVALID_SHADER) {
            //cleanup
            glDeleteProgram(handle);

            return false;
        }

        glAttachShader(handle, vertShader);
        glDeleteShader(vertShader);
    }

    if (!fragmentShader.empty()) {
        GLuint fragShader = compileShader(fragmentShader, GL_FRAGMENT_SHADER);

        if (fragShader == INVALID_SHADER) {
            //cleanup
            glDeleteProgram(handle);

            return false;
        }

        glAttachShader(handle, fragShader);
        glDeleteShader(fragShader);
    }

    //link
    glLinkProgram(handle);

    GLint linkStatus;

    glGetProgramiv(handle, GL_LINK_STATUS, &linkStatus);

    if (linkStatus == GL_FALSE) {
        //cleanup
        glDeleteProgram(handle);

        //get error
        GLchar messages[256];

        glGetProgramInfoLog(handle, sizeof(messages), 0, &messages[0]);

        if (DEBUG_SHADER_ERRORS) {
            printf("shader linking failed: %s\n", messages);
        }

        return false;
    }

    prog = handle;

    //initialize
    initShader();

    return true;
}

/**
 * Compile a shader.
 *
 * Note: sets error on failure.
 */
GLuint AnyShader::compileShader(std::string source, const GLenum type) {
    GLint compileStatus;
    GLuint handle = glCreateShader(type);

    if (handle == INVALID_SHADER) {
        error = "glCreateShader() failed";
        return -1;
    }

#ifdef RPI
    //add GLSL version
    source = "#version 100\n" + source;
#endif

    GLchar *src = (GLchar *)source.c_str();

    glShaderSource(handle, 1, (const GLchar **)&src, NULL);
    glCompileShader(handle);

    //get status
    glGetShaderiv(handle, GL_COMPILE_STATUS, &compileStatus);

    if (compileStatus == GL_FALSE) {
        //free
        glDeleteShader(handle);
        handle = INVALID_SHADER;

        //get error
        GLchar messages[256];

        glGetShaderInfoLog(handle, sizeof(messages), 0, &messages[0]);

        if (DEBUG_SHADER_ERRORS) {
            std::string typeStr;

            if (type == GL_VERTEX_SHADER) {
                typeStr = "vertex shader";
            } else if (type == GL_FRAGMENT_SHADER) {
                typeStr = "fragment shader";
            }

            printf("shader compilation error: %s\ntype: %s\n", messages, typeStr.c_str());
        }

        error = std::string(messages);
    }

    return handle;
}

/**
 * Destroy the shader.
 *
 * Note: has to be called in OpenGL thread.
 */
void AnyShader::destroy() {
    if (prog != INVALID_PROGRAM) {
        glDeleteProgram(prog);
        prog = INVALID_PROGRAM;
    }

    //reset failed
    failed = false;
}

/**
 * Get attribute location.
 */
GLint AnyShader::getAttributeLocation(std::string name) {
    GLint loc = glGetAttribLocation(prog, name.c_str());

    if (DEBUG_SHADER_ERRORS) {
        if (loc == -1) {
            printf("could not get location of attribute %s\n", name.c_str());
        }
    }

    return loc;
}

/**
 * Get uniform location.
 */
GLint AnyShader::getUniformLocation(std::string name) {
    GLint loc = glGetUniformLocation(prog, name.c_str());

    if (DEBUG_SHADER_ERRORS) {
        if (loc == -1) {
            printf("could not get location of uniform %s\n", name.c_str());
        }
    }

    return loc;
}

/**
 * Use the shader.
 *
 * Note: has to be called before any setters are used!
 */
void AnyShader::useShader(bool active) {
    if (!active) {
        glUseProgram(prog);
    }
}

//
// AnyAminoShader
//

AnyAminoShader::AnyAminoShader() : AnyShader() {
    //default vertex shader
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        attribute vec4 pos;

        void main() {
            gl_Position = mvp * trans * pos;
        }
    )";
}

/**
 * Initialize the shader.
 */
void AnyAminoShader::initShader() {
    useShader(false);

    //attributes
    aPos = getAttributeLocation("pos");

    //uniforms
    uMVP = getUniformLocation("mvp");
    uTrans = getUniformLocation("trans");
}

/**
 * Set transformation matrix.
 */
void AnyAminoShader::setTransformation(GLfloat modelView[16], GLfloat transition[16]) {
    glUniformMatrix4fv(uMVP, 1, GL_FALSE, modelView);
    glUniformMatrix4fv(uTrans, 1, GL_FALSE, transition);
}

/**
 * Set vertex data.
 */
void AnyAminoShader::setVertexData(GLsizei dim, GLfloat *vertices) {
    /*
     * Coords per vertex (2 or 3).
     *
     * Note: vertices is NULL in case of VBO usage
     */

    glVertexAttribPointer(aPos, dim, GL_FLOAT, GL_FALSE, 0, vertices);
}

/**
 * Draw triangles.
 */
void AnyAminoShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aPos);

    glDrawArrays(mode, 0, vertices);

    glDisableVertexAttribArray(aPos);
}

/**
 * Draw elements.
 */
void AnyAminoShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aPos);

    //Note: indices is offset in case of VBO
    glDrawElements(mode, elements, GL_UNSIGNED_SHORT, indices);

    glDisableVertexAttribArray(aPos);
}

//
// ColorShader
//

/**
 * Create color shader.
 */
ColorShader::ColorShader() : AnyAminoShader() {
    //shaders
    fragmentShader = R"(
        uniform vec4 color;

        void main() {
            gl_FragColor = color;
        }
    )";
}

/**
 * Initialize the color shader.
 */
void ColorShader::initShader() {
    AnyAminoShader::initShader();

    //uniforms
    uColor = getUniformLocation("color");
}

/**
 * Set color.
 */
void ColorShader::setColor(GLfloat color[4]) {
    glUniform4f(uColor, color[0], color[1], color[2], color[3]);
}

//
// ColorLightingShader
//

/**
 * Create color lighting shader.
 */
ColorLightingShader::ColorLightingShader() : ColorShader() {
    //shaders
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        //uniform mat4 normalMatrix;
        uniform vec3 lightDir;

        attribute vec4 pos;
        attribute vec3 normal;

        varying float lightFac;

        void main() {
            gl_Position = mvp * trans * pos;

            //simple version
            vec4 normalTrans = trans * vec4(normal, 0.);

            lightFac = abs(dot(normalTrans.xyz, -lightDir));
        }
    )";

    fragmentShader = R"(
        varying float lightFac;

        uniform vec4 color;

        void main() {
            gl_FragColor = vec4(color.rgb * lightFac, color.a);
        }
    )";
}

/**
 * Initialize the color lighting shader.
 */
void ColorLightingShader::initShader() {
    ColorShader::initShader();

    //attributes
    aNormal = getAttributeLocation("normal");

    //uniforms
    //uNormalMatrix = getUniformLocation("normalMatrix");
    uLightDir = getUniformLocation("lightDir");

    //default values
    GLfloat lightDir[3] = { 0, 0, -1 }; //parallel light on screen

    setLightDirection(lightDir);
}

/**
 * Set light direction.
 */
void ColorLightingShader::setLightDirection(GLfloat dir[3]) {
    glUniform3f(uLightDir, dir[0], dir[1], dir[2]);
}

/**
 * Set normal vectors.
 */
void ColorLightingShader::setNormalVectors(GLfloat *normals) {
    glVertexAttribPointer(aNormal, 3, GL_FLOAT, GL_FALSE, 0, normals);
}

/**
 * Set matrix.
 */
void ColorLightingShader::setTransformation(GLfloat modelView[16], GLfloat transition[16]) {
    AnyAminoShader::setTransformation(modelView, transition);

    //normal matrix
    /*
    GLfloat invMatrix[16];
    GLfloat normalMatrix[16];

    assert(invert_matrix(transition, invMatrix));
    transpose_matrix(normalMatrix, invMatrix);

    glUniformMatrix4fv(uNormalMatrix, 1, GL_FALSE, normalMatrix);
    */
}

/**
 * Draw triangles.
 */
void ColorLightingShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    AnyAminoShader::drawTriangles(vertices, mode);

    glDisableVertexAttribArray(aNormal);
}

/**
 * Draw elements.
 */
void ColorLightingShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    AnyAminoShader::drawElements(indices, elements, mode);

    glDisableVertexAttribArray(aNormal);
}

//
// TextureShader
//

TextureShader::TextureShader() : AnyAminoShader() {
    //shader
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        attribute vec4 pos;
        attribute vec2 texCoord;

        varying vec2 uv;

        void main() {
            gl_Position = mvp * trans * pos;
            uv = texCoord;
        }
    )";

    fragmentShader = R"(
        varying vec2 uv;

        uniform float opacity;
        uniform sampler2D tex;

        void main() {
            vec4 pixel = texture2D(tex, uv);

            //discard transparent pixels
            if (pixel.a == 0.) {
                discard;
            }

            gl_FragColor = vec4(pixel.rgb, pixel.a * opacity);
        }
    )";
}

/**
 * Initialize the color shader.
 */
void TextureShader::initShader() {
    AnyAminoShader::initShader();

    //attributes
    aTexCoord = getAttributeLocation("texCoord");

    //uniforms
    uOpacity = getUniformLocation("opacity");
    uTex = getUniformLocation("tex");

    //default values
    glUniform1i(uTex, 0); //GL_TEXTURE0
}

/**
 * Set opacity.
 */
void TextureShader::setOpacity(GLfloat opacity) {
    glUniform1f(uOpacity, opacity);
}

/**
 * Set texture coordinates.
 */
void TextureShader::setTextureCoordinates(GLfloat uv[][2]) {
    glVertexAttribPointer(aTexCoord, 2, GL_FLOAT, GL_FALSE, 0, uv);
}

/**
 * Draw texture.
 */
void TextureShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aTexCoord);

    glActiveTexture(GL_TEXTURE0);

    AnyAminoShader::drawTriangles(vertices, mode);

    glDisableVertexAttribArray(aTexCoord);
}

/**
 * Draw elements.
 */
void TextureShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aTexCoord);

    glActiveTexture(GL_TEXTURE0);

    AnyAminoShader::drawElements(indices, elements, mode);

    glDisableVertexAttribArray(aTexCoord);
}

//
// TextureClampToBorderShader
//

TextureClampToBorderShader::TextureClampToBorderShader() : TextureShader() {
    //Note: supports clamp to border, using transparent texture
    fragmentShader = R"(
        varying vec2 uv;

        uniform float opacity;
        uniform bvec2 repeat;
        uniform sampler2D tex;

        bool clamp_to_border(vec2 coords) {
            bvec2 out1 = greaterThan(coords, vec2(1, 1));
            bvec2 out2 = lessThan(coords, vec2(0, 0));
            bool do_clamp = (any(out1) || any(out2));

            return do_clamp;
        }

        void main() {
            //repeat
            vec2 uv2 = uv;

            if (repeat.x) {
                uv2.x = fract(uv.x);
            }

            if (repeat.y) {
                uv2.y = fract(uv.y);
            }

            //show pixel
            vec4 pixel = texture2D(tex, uv2);

            //discard transparent pixels
            if (pixel.a == 0. || clamp_to_border(uv2)) {
                discard;
            }

            gl_FragColor = vec4(pixel.rgb, pixel.a * opacity);
        }
    )";
}

/**
 * Initialize the shader.
 */
void TextureClampToBorderShader::initShader() {
    TextureShader::initShader();

    uRepeat = getUniformLocation("repeat");
}

/**
 * Set repeat directions.
 */
void TextureClampToBorderShader::setRepeat(bool repeatX, bool repeatY) {
    glUniform2i(uRepeat, repeatX, repeatY);
}

//
// TextureLightingShader
//

/**
 * Create color lighting shader.
 */
TextureLightingShader::TextureLightingShader() : TextureShader() {
    //shaders
    vertexShader = R"(
        uniform mat4 mvp;
        uniform mat4 trans;

        uniform vec3 lightDir;

        attribute vec4 pos;
        attribute vec2 texCoord;
        attribute vec3 normal;

        varying vec2 uv;
        varying float lightFac;

        void main() {
            gl_Position = mvp * trans * pos;

            uv = texCoord;

            vec4 normalTrans = trans * vec4(normal, 0.);

            //translucent layers
            lightFac = abs(dot(normalTrans.xyz, -lightDir));
        }
    )";

    fragmentShader = R"(
        varying vec2 uv;
        varying float lightFac;

        uniform float opacity;
        uniform sampler2D tex;

        void main() {
            vec4 pixel = texture2D(tex, uv);

            //discard transparent pixels
            if (pixel.a == 0.) {
                discard;
            }

            gl_FragColor = vec4(pixel.rgb * lightFac, pixel.a * opacity);
        }
    )";
}

/**
 * Initialize the color lighting shader.
 */
void TextureLightingShader::initShader() {
    TextureShader::initShader();

    //attributes
    aNormal = getAttributeLocation("normal");

    //uniforms
    //uNormalMatrix = getUniformLocation("normalMatrix");
    uLightDir = getUniformLocation("lightDir");

    //default values
    GLfloat lightDir[3] = { 0, 0, -1 }; //parallel light on screen

    setLightDirection(lightDir);
}

/**
 * Set light direction.
 */
void TextureLightingShader::setLightDirection(GLfloat dir[3]) {
    glUniform3f(uLightDir, dir[0], dir[1], dir[2]);
}

/**
 * Set normal vectors.
 */
void TextureLightingShader::setNormalVectors(GLfloat *normals) {
    glVertexAttribPointer(aNormal, 3, GL_FLOAT, GL_FALSE, 0, normals);
}

/**
 * Draw triangles.
 */
void TextureLightingShader::drawTriangles(GLsizei vertices, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    TextureShader::drawTriangles(vertices, mode);

    glDisableVertexAttribArray(aNormal);
}

/**
 * Draw elements.
 */
void TextureLightingShader::drawElements(GLushort *indices, GLsizei elements, GLenum mode) {
    glEnableVertexAttribArray(aNormal);

    TextureShader::drawElements(indices, elements, mode);

    glDisableVertexAttribArray(aNormal);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2000-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Steve Raasch
 *          Nathan Binkert
 *          Steve Reinhardt
 */

///
/// @file sim/main.cc
///
#include <Python.h>	// must be before system headers... see Python docs

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <libgen.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

#include <list>
#include <string>
#include <vector>

#include "base/callback.hh"
#include "base/inifile.hh"
#include "base/misc.hh"
#include "base/output.hh"
#include "base/pollevent.hh"
#include "base/statistics.hh"
#include "base/str.hh"
#include "base/time.hh"
#include "cpu/base.hh"
#include "cpu/smt.hh"
#include "sim/async.hh"
#include "sim/builder.hh"
#include "sim/configfile.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
#include "sim/sim_object.hh"
#include "sim/stat_control.hh"
#include "sim/stats.hh"
#include "sim/root.hh"

using namespace std;

// See async.h.
volatile bool async_event = false;
volatile bool async_dump = false;
volatile bool async_dumpreset = false;
volatile bool async_exit = false;
volatile bool async_io = false;
volatile bool async_alarm = false;

/// Stats signal handler.
void
dumpStatsHandler(int sigtype)
{
    async_event = true;
    async_dump = true;
}

void
dumprstStatsHandler(int sigtype)
{
    async_event = true;
    async_dumpreset = true;
}

/// Exit signal handler.
void
exitNowHandler(int sigtype)
{
    async_event = true;
    async_exit = true;
}

/// Abort signal handler.
void
abortHandler(int sigtype)
{
    cerr << "Program aborted at cycle " << curTick << endl;

#if TRACING_ON
    // dump trace buffer, if there is one
    Trace::theLog.dump(cerr);
#endif
}

const char *briefCopyright =
"Copyright (c) 2001-2006\n"
"The Regents of The University of Michigan\n"
"All Rights Reserved\n";

/// Print welcome message.
void
sayHello(ostream &out)
{
    extern const char *compileDate;     // from date.cc

    ccprintf(out, "M5 Simulator System\n");
    // display copyright
    ccprintf(out, "%s\n", briefCopyright);
    ccprintf(out, "M5 compiled %d\n", compileDate);
    ccprintf(out, "M5 started %s\n", Time::start);

    char *host = getenv("HOSTNAME");
    if (!host)
        host = getenv("HOST");

    if (host)
        ccprintf(out, "M5 executing on %s\n", host);
}

extern "C" { void init_main(); }

int
main(int argc, char **argv)
{
    sayHello(cerr);

    signal(SIGFPE, SIG_IGN);		// may occur on misspeculated paths
    signal(SIGTRAP, SIG_IGN);
    signal(SIGUSR1, dumpStatsHandler);		// dump intermediate stats
    signal(SIGUSR2, dumprstStatsHandler);	// dump and reset stats
    signal(SIGINT, exitNowHandler);		// dump final stats and exit
    signal(SIGABRT, abortHandler);

    Py_SetProgramName(argv[0]);

    // default path to m5 python code is the currently executing
    // file... Python ZipImporter will find embedded zip archive
    char *pythonpath = argv[0];

    bool interactive = false;
    bool getopt_done = false;
    do {
        switch (getopt(argc, argv, "+p:i")) {
            // -p <path> prepends <path> to PYTHONPATH instead of
            // using built-in zip archive.  Useful when
            // developing/debugging changes to built-in Python
            // libraries, as the new Python can be tested without
            // building a new m5 binary.
          case 'p':
            pythonpath = optarg;
            break;

            // -i forces entry into interactive mode after the
            // supplied script is executed (just like the -i option to
            // the Python interpreter).
          case 'i':
            interactive = true;
            break;

          case -1:
            getopt_done = true;
            break;

          default:
            fatal("Unrecognized option %c\n", optopt);
        }
    } while (!getopt_done);

    // Fix up argc & argv to hide arguments we just processed.
    // getopt() sets optind to the index of the first non-processed
    // argv element.
    argc -= optind;
    argv += optind;

    // Set up PYTHONPATH to make sure the m5 module is found
    string newpath(pythonpath);

    char *oldpath = getenv("PYTHONPATH");
    if (oldpath != NULL) {
        newpath += ":";
        newpath += oldpath;
    }

    if (setenv("PYTHONPATH", newpath.c_str(), true) == -1)
        fatal("setenv: %s\n", strerror(errno));

    // initialize embedded Python interpreter
    Py_Initialize();
    PySys_SetArgv(argc, argv);

    // initialize SWIG 'main' module
    init_main();

    if (argc > 0) {
        // extra arg(s): first is script file, remaining ones are args
        // to script file
        char *filename = argv[0];
        FILE *fp = fopen(filename, "r");
        if (!fp) {
            fatal("cannot open file '%s'\n", filename);
        }

        PyRun_AnyFile(fp, filename);
    } else {
        // no script file argument... force interactive prompt
        interactive = true;
    }

    if (interactive) {
        // The following code to import readline was copied from Python
        // 2.4.3's Modules/main.c.
        // Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006
        // Python Software Foundation; All Rights Reserved
        // We should only enable this if we're actually using an
        // interactive prompt.
        PyObject *v;
        v = PyImport_ImportModule("readline");
        if (v == NULL)
            PyErr_Clear();
        else
            Py_DECREF(v);

        PyRun_InteractiveLoop(stdin, "stdin");
    }

    // clean up Python intepreter.
    Py_Finalize();
}

/// Initialize C++ configuration.  Exported to Python via SWIG; invoked
/// from m5.instantiate().
void
initialize()
{
    configStream = simout.find("config.out");

    // The configuration database is now complete; start processing it.
    IniFile inifile;
    inifile.load("config.ini");

    // Initialize statistics database
    Stats::InitSimStats();

    // Now process the configuration hierarchy and create the SimObjects.
    ConfigHierarchy configHierarchy(inifile);
    configHierarchy.build();
    configHierarchy.createSimObjects();

    // Parse and check all non-config-hierarchy parameters.
    ParamContext::parseAllContexts(inifile);
    ParamContext::checkAllContexts();

    // Echo all parameter settings to stats file as well.
    ParamContext::showAllContexts(*configStream);

    // Any objects that can't connect themselves until after construction should
    // do so now
    SimObject::connectAll();

    // Do a second pass to finish initializing the sim objects
    SimObject::initAll();

    // Restore checkpointed state, if any.
    configHierarchy.unserializeSimObjects();

    // Done processing the configuration database.
    // Check for unreferenced entries.
    if (inifile.printUnreferenced())
        panic("unreferenced sections/entries in the intermediate ini file");

    SimObject::regAllStats();

    // uncomment the following to get PC-based execution-time profile
#ifdef DO_PROFILE
    init_profile((char *)&_init, (char *)&_fini);
#endif

    // Check to make sure that the stats package is properly initialized
    Stats::check();

    // Reset to put the stats in a consistent state.
    Stats::reset();

    SimStartup();
}

/** Simulate for num_cycles additional cycles.  If num_cycles is -1
 * (the default), do not limit simulation; some other event must
 * terminate the loop.  Exported to Python via SWIG.
 * @return The SimLoopExitEvent that caused the loop to exit.
 */
SimLoopExitEvent *
simulate(Tick num_cycles = -1)
{
    warn("Entering event queue @ %d.  Starting simulation...\n", curTick);

    // Fix up num_cycles.  Special default value -1 means simulate
    // "forever"... schedule event at MaxTick just to be safe.
    // Otherwise it's a delta for additional cycles to simulate past
    // curTick, and thus must be non-negative.
    if (num_cycles == -1)
        num_cycles = MaxTick;
    else if (num_cycles < 0)
        fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles);
    else
        num_cycles = curTick + num_cycles;

    Event *limit_event = new SimLoopExitEvent(num_cycles,
                                              "simulate() limit reached");

    while (1) {
        // there should always be at least one event (the SimLoopExitEvent
        // we just scheduled) in the queue
        assert(!mainEventQueue.empty());
        assert(curTick <= mainEventQueue.nextTick() &&
               "event scheduled in the past");

        // forward current cycle to the time of the first event on the
        // queue
        curTick = mainEventQueue.nextTick();
        Event *exit_event = mainEventQueue.serviceOne();
        if (exit_event != NULL) {
            // hit some kind of exit event; return to Python
            // event must be subclass of SimLoopExitEvent...
            SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event);
            if (se_event == NULL)
                panic("Bogus exit event class!");

            // if we didn't hit limit_event, delete it
            if (se_event != limit_event) {
                assert(limit_event->scheduled());
                limit_event->deschedule();
                delete limit_event;
            }

            return se_event;
        }

        if (async_event) {
            async_event = false;
            if (async_dump) {
                async_dump = false;

                using namespace Stats;
                SetupEvent(Dump, curTick);
            }

            if (async_dumpreset) {
                async_dumpreset = false;

                using namespace Stats;
                SetupEvent(Dump | Reset, curTick);
            }

            if (async_exit) {
                async_exit = false;
                exitSimLoop("user interrupt received");
            }

            if (async_io || async_alarm) {
                async_io = false;
                async_alarm = false;
                pollQueue.service();
            }
        }
    }

    // not reached... only exit is return on SimLoopExitEvent
}

/**
 * Queue of C++ callbacks to invoke on simulator exit.
 */
CallbackQueue exitCallbacks;

/**
 * Register an exit callback.
 */
void
registerExitCallback(Callback *callback)
{
    exitCallbacks.add(callback);
}

/**
 * Do C++ simulator exit processing.  Exported to SWIG to be invoked
 * when simulator terminates via Python's atexit mechanism.
 */
void
doExitCleanup()
{
    exitCallbacks.process();
    exitCallbacks.clear();

    cout.flush();

    ParamContext::cleanupAllContexts();

    // print simulation stats
    Stats::DumpNow();
}
<commit_msg>allow long opts to m5 and add a help flag back.<commit_after>/*
 * Copyright (c) 2000-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Steve Raasch
 *          Nathan Binkert
 *          Steve Reinhardt
 */

///
/// @file sim/main.cc
///
#include <Python.h>	// must be before system headers... see Python docs

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <libgen.h>
#include <stdlib.h>
#include <signal.h>
#include <getopt.h>

#include <list>
#include <string>
#include <vector>

#include "base/callback.hh"
#include "base/inifile.hh"
#include "base/misc.hh"
#include "base/output.hh"
#include "base/pollevent.hh"
#include "base/statistics.hh"
#include "base/str.hh"
#include "base/time.hh"
#include "cpu/base.hh"
#include "cpu/smt.hh"
#include "sim/async.hh"
#include "sim/builder.hh"
#include "sim/configfile.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
#include "sim/sim_object.hh"
#include "sim/stat_control.hh"
#include "sim/stats.hh"
#include "sim/root.hh"

using namespace std;

// See async.h.
volatile bool async_event = false;
volatile bool async_dump = false;
volatile bool async_dumpreset = false;
volatile bool async_exit = false;
volatile bool async_io = false;
volatile bool async_alarm = false;

/// Stats signal handler.
void
dumpStatsHandler(int sigtype)
{
    async_event = true;
    async_dump = true;
}

void
dumprstStatsHandler(int sigtype)
{
    async_event = true;
    async_dumpreset = true;
}

/// Exit signal handler.
void
exitNowHandler(int sigtype)
{
    async_event = true;
    async_exit = true;
}

/// Abort signal handler.
void
abortHandler(int sigtype)
{
    cerr << "Program aborted at cycle " << curTick << endl;

#if TRACING_ON
    // dump trace buffer, if there is one
    Trace::theLog.dump(cerr);
#endif
}

/// Simulator executable name
char *myProgName = "";

/// Show brief help message.
void
showBriefHelp(ostream &out)
{
    char *prog = basename(myProgName);

    ccprintf(out, "Usage:\n");
    ccprintf(out,
"%s [-p <path>] [-i ] [-h] <config file>\n"
"\n"
" -p, --path <path>  prepends <path> to PYTHONPATH instead of using\n"
"                    built-in zip archive.  Useful when developing/debugging\n"
"                    changes to built-in Python libraries, as the new Python\n"
"                    can be tested without building a new m5 binary.\n\n"
" -i, --interactive  forces entry into interactive mode after the supplied\n"
"                    script is executed (just like the -i option to  the\n"
"                    Python interpreter).\n\n"
" -h                 Prints this help\n\n"
" <configfile>       config file name (ends in .py)\n\n",
             prog);

}

const char *briefCopyright =
"Copyright (c) 2001-2006\n"
"The Regents of The University of Michigan\n"
"All Rights Reserved\n";

/// Print welcome message.
void
sayHello(ostream &out)
{
    extern const char *compileDate;     // from date.cc

    ccprintf(out, "M5 Simulator System\n");
    // display copyright
    ccprintf(out, "%s\n", briefCopyright);
    ccprintf(out, "M5 compiled %d\n", compileDate);
    ccprintf(out, "M5 started %s\n", Time::start);

    char *host = getenv("HOSTNAME");
    if (!host)
        host = getenv("HOST");

    if (host)
        ccprintf(out, "M5 executing on %s\n", host);
}

extern "C" { void init_main(); }

int
main(int argc, char **argv)
{
    // Saze off program name
    myProgName = argv[0];

    sayHello(cerr);

    signal(SIGFPE, SIG_IGN);		// may occur on misspeculated paths
    signal(SIGTRAP, SIG_IGN);
    signal(SIGUSR1, dumpStatsHandler);		// dump intermediate stats
    signal(SIGUSR2, dumprstStatsHandler);	// dump and reset stats
    signal(SIGINT, exitNowHandler);		// dump final stats and exit
    signal(SIGABRT, abortHandler);

    Py_SetProgramName(argv[0]);

    // default path to m5 python code is the currently executing
    // file... Python ZipImporter will find embedded zip archive
    char *pythonpath = argv[0];

    bool interactive = false;
    bool show_help = false;
    bool getopt_done = false;
    int opt_index = 0;

    static struct option long_options[] = {
        {"python", 1, 0, 'p'},
        {"interactive", 0, 0, 'i'},
        {"help", 0, 0, 'h'},
        {0,0,0,0}
    };

    do {
        switch (getopt_long(argc, argv, "+p:ih", long_options, &opt_index)) {
            // -p <path> prepends <path> to PYTHONPATH instead of
            // using built-in zip archive.  Useful when
            // developing/debugging changes to built-in Python
            // libraries, as the new Python can be tested without
            // building a new m5 binary.
          case 'p':
            pythonpath = optarg;
            break;

            // -i forces entry into interactive mode after the
            // supplied script is executed (just like the -i option to
            // the Python interpreter).
          case 'i':
            interactive = true;
            break;

          case 'h':
            show_help = true;
            break;
          case -1:
            getopt_done = true;
            break;

          default:
            fatal("Unrecognized option %c\n", optopt);
        }
    } while (!getopt_done);

    if (show_help) {
        showBriefHelp(cerr);
        exit(1);
    }

    // Fix up argc & argv to hide arguments we just processed.
    // getopt() sets optind to the index of the first non-processed
    // argv element.
    argc -= optind;
    argv += optind;

    // Set up PYTHONPATH to make sure the m5 module is found
    string newpath(pythonpath);

    char *oldpath = getenv("PYTHONPATH");
    if (oldpath != NULL) {
        newpath += ":";
        newpath += oldpath;
    }

    if (setenv("PYTHONPATH", newpath.c_str(), true) == -1)
        fatal("setenv: %s\n", strerror(errno));

    // initialize embedded Python interpreter
    Py_Initialize();
    PySys_SetArgv(argc, argv);

    // initialize SWIG 'main' module
    init_main();

    if (argc > 0) {
        // extra arg(s): first is script file, remaining ones are args
        // to script file
        char *filename = argv[0];
        FILE *fp = fopen(filename, "r");
        if (!fp) {
            fatal("cannot open file '%s'\n", filename);
        }

        PyRun_AnyFile(fp, filename);
    } else {
        // no script file argument... force interactive prompt
        interactive = true;
    }

    if (interactive) {
        // The following code to import readline was copied from Python
        // 2.4.3's Modules/main.c.
        // Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006
        // Python Software Foundation; All Rights Reserved
        // We should only enable this if we're actually using an
        // interactive prompt.
        PyObject *v;
        v = PyImport_ImportModule("readline");
        if (v == NULL)
            PyErr_Clear();
        else
            Py_DECREF(v);

        PyRun_InteractiveLoop(stdin, "stdin");
    }

    // clean up Python intepreter.
    Py_Finalize();
}

/// Initialize C++ configuration.  Exported to Python via SWIG; invoked
/// from m5.instantiate().
void
initialize()
{
    configStream = simout.find("config.out");

    // The configuration database is now complete; start processing it.
    IniFile inifile;
    inifile.load("config.ini");

    // Initialize statistics database
    Stats::InitSimStats();

    // Now process the configuration hierarchy and create the SimObjects.
    ConfigHierarchy configHierarchy(inifile);
    configHierarchy.build();
    configHierarchy.createSimObjects();

    // Parse and check all non-config-hierarchy parameters.
    ParamContext::parseAllContexts(inifile);
    ParamContext::checkAllContexts();

    // Echo all parameter settings to stats file as well.
    ParamContext::showAllContexts(*configStream);

    // Any objects that can't connect themselves until after construction should
    // do so now
    SimObject::connectAll();

    // Do a second pass to finish initializing the sim objects
    SimObject::initAll();

    // Restore checkpointed state, if any.
    configHierarchy.unserializeSimObjects();

    // Done processing the configuration database.
    // Check for unreferenced entries.
    if (inifile.printUnreferenced())
        panic("unreferenced sections/entries in the intermediate ini file");

    SimObject::regAllStats();

    // uncomment the following to get PC-based execution-time profile
#ifdef DO_PROFILE
    init_profile((char *)&_init, (char *)&_fini);
#endif

    // Check to make sure that the stats package is properly initialized
    Stats::check();

    // Reset to put the stats in a consistent state.
    Stats::reset();

    SimStartup();
}

/** Simulate for num_cycles additional cycles.  If num_cycles is -1
 * (the default), do not limit simulation; some other event must
 * terminate the loop.  Exported to Python via SWIG.
 * @return The SimLoopExitEvent that caused the loop to exit.
 */
SimLoopExitEvent *
simulate(Tick num_cycles = -1)
{
    warn("Entering event queue @ %d.  Starting simulation...\n", curTick);

    // Fix up num_cycles.  Special default value -1 means simulate
    // "forever"... schedule event at MaxTick just to be safe.
    // Otherwise it's a delta for additional cycles to simulate past
    // curTick, and thus must be non-negative.
    if (num_cycles == -1)
        num_cycles = MaxTick;
    else if (num_cycles < 0)
        fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles);
    else
        num_cycles = curTick + num_cycles;

    Event *limit_event = new SimLoopExitEvent(num_cycles,
                                              "simulate() limit reached");

    while (1) {
        // there should always be at least one event (the SimLoopExitEvent
        // we just scheduled) in the queue
        assert(!mainEventQueue.empty());
        assert(curTick <= mainEventQueue.nextTick() &&
               "event scheduled in the past");

        // forward current cycle to the time of the first event on the
        // queue
        curTick = mainEventQueue.nextTick();
        Event *exit_event = mainEventQueue.serviceOne();
        if (exit_event != NULL) {
            // hit some kind of exit event; return to Python
            // event must be subclass of SimLoopExitEvent...
            SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event);
            if (se_event == NULL)
                panic("Bogus exit event class!");

            // if we didn't hit limit_event, delete it
            if (se_event != limit_event) {
                assert(limit_event->scheduled());
                limit_event->deschedule();
                delete limit_event;
            }

            return se_event;
        }

        if (async_event) {
            async_event = false;
            if (async_dump) {
                async_dump = false;

                using namespace Stats;
                SetupEvent(Dump, curTick);
            }

            if (async_dumpreset) {
                async_dumpreset = false;

                using namespace Stats;
                SetupEvent(Dump | Reset, curTick);
            }

            if (async_exit) {
                async_exit = false;
                exitSimLoop("user interrupt received");
            }

            if (async_io || async_alarm) {
                async_io = false;
                async_alarm = false;
                pollQueue.service();
            }
        }
    }

    // not reached... only exit is return on SimLoopExitEvent
}

/**
 * Queue of C++ callbacks to invoke on simulator exit.
 */
CallbackQueue exitCallbacks;

/**
 * Register an exit callback.
 */
void
registerExitCallback(Callback *callback)
{
    exitCallbacks.add(callback);
}

/**
 * Do C++ simulator exit processing.  Exported to SWIG to be invoked
 * when simulator terminates via Python's atexit mechanism.
 */
void
doExitCleanup()
{
    exitCallbacks.process();
    exitCallbacks.clear();

    cout.flush();

    ParamContext::cleanupAllContexts();

    // print simulation stats
    Stats::DumpNow();
}
<|endoftext|>


<commit_before>/*
This file is part of khmer, https://github.com/dib-lab/khmer/, and is
Copyright (C) 2010-2015, Michigan State University.
Copyright (C) 2015-2016, The Regents of the University of California.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

    * Neither the name of the Michigan State University nor the names
      of its contributors may be used to endorse or promote products
      derived from this software without specific prior written
      permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
LICENSE (END)

Contact: khmer-project@idyll.org
*/
#ifndef HASHTABLE_HH
#define HASHTABLE_HH

#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>

#include "khmer.hh"
#include "khmer_exception.hh"
#include "kmer_hash.hh"
#include "read_parsers.hh"
#include "storage.hh"

#include "traversal.hh"
#include "subset.hh"

namespace khmer
{
namespace read_parsers
{
struct IParser;
}  // namespace read_parsers
}  // namespace khmer

#define MAX_KEEPER_SIZE int(1e6)

#define next_f(kmer_f, ch) ((((kmer_f) << 2) & bitmask) | (twobit_repr(ch)))
#define next_r(kmer_r, ch) (((kmer_r) >> 2) | (twobit_comp(ch) << rc_left_shift))

#define prev_f(kmer_f, ch) ((kmer_f) >> 2 | twobit_repr(ch) << rc_left_shift)
#define prev_r(kmer_r, ch) ((((kmer_r) << 2) & bitmask) | (twobit_comp(ch)))

#define set_contains(s, e) ((s).find(e) != (s).end())

#define CALLBACK_PERIOD 100000

namespace khmer
{
class Hashtable: public
    KmerFactory  		// Base class implementation of a Bloom ht.
{
    friend class SubsetPartition;
    friend class LabelHash;

protected:
    Storage * store;
    unsigned int    _max_count;
    unsigned int    _max_bigcount;

    //WordLength	    _ksize;
    HashIntoType    bitmask;
    unsigned int    _nbits_sub_1;

    explicit Hashtable( WordLength ksize, Storage * s)
        : KmerFactory( ksize ), store(s),
          _max_count( MAX_KCOUNT ),
          _max_bigcount( MAX_BIGCOUNT )
    {
        _init_bitstuff();
    }

    virtual ~Hashtable( )
    {
        delete store;
    }

    void _init_bitstuff()
    {
        bitmask = 0;
        for (unsigned int i = 0; i < _ksize; i++) {
            bitmask = (bitmask << 2) | 3;
        }
        _nbits_sub_1 = (_ksize*2 - 2);
    }

    explicit Hashtable(const Hashtable&);
    Hashtable& operator=(const Hashtable&);

public:
    // accessor to get 'k'
    const WordLength ksize() const
    {
        return _ksize;
    }

    // various hash functions.
    inline
    virtual
    HashIntoType
    hash_dna(const char * kmer) const {
        return _hash(kmer, _ksize);
    }

    inline
    virtual
    HashIntoType
    hash_dna_top_strand(const char * kmer) const {
        HashIntoType f = 0, r = 0;
        _hash(kmer, _ksize, f, r);
        return f;
    }

    inline
    virtual
    HashIntoType
    hash_dna_bottom_strand(const char * kmer) const {
        HashIntoType f = 0, r = 0;
        _hash(kmer, _ksize, f, r);
        return r;
    }

    inline
    virtual
    std::string
    unhash_dna(HashIntoType hashval) const {
        return _revhash(hashval, _ksize);
    }

    void count(const char * kmer) { store->add(hash_dna(kmer)); }
    void count(HashIntoType khash) { store->add(khash); }
    void add(const char * kmer) { store->add(hash_dna(kmer)); }
    void add(HashIntoType khash) { store->add(khash); }

    // get the count for the given k-mer.
    const BoundedCounterType get_count(const char * kmer) const {
        return store->get_count(hash_dna(kmer));
    }
    const BoundedCounterType get_count(HashIntoType khash) const {
        return store->get_count(khash);
    }

    void save(std::string filename) {
        store->save(filename, _ksize);
    }
    void load(std::string filename) {
        store->load(filename, _ksize);
        _init_bitstuff();
    }

    // count every k-mer in the string.
    unsigned int consume_string(const std::string &s);

    // checks each read for non-ACGT characters
    bool check_and_normalize_read(std::string &read) const;

    // check each read for non-ACGT characters, and then consume it.
    unsigned int check_and_process_read(std::string &read,
                                        bool &is_valid);

    // Count every k-mer in a FASTA or FASTQ file.
    // Note: Yes, the name 'consume_fasta' is a bit misleading,
    //	     but the FASTA format is effectively a subset of the FASTQ format
    //	     and the FASTA portion is what we care about in this case.
    void consume_fasta(
        std::string const   &filename,
        unsigned int	    &total_reads,
        unsigned long long  &n_consumed
    );

    // Count every k-mer from a stream of FASTA or FASTQ reads,
    // using the supplied parser.
    void consume_fasta(
        read_parsers:: IParser *	    parser,
        unsigned int	    &total_reads,
        unsigned long long  &n_consumed
    );

    void set_use_bigcount(bool b) { store->set_use_bigcount(b); }
    bool get_use_bigcount() { return store->get_use_bigcount(); }

    bool median_at_least(const std::string &s,
                         unsigned int cutoff);

    void get_median_count(const std::string &s,
                          BoundedCounterType &median,
                          float &average,
                          float &stddev);

    // number of unique k-mers
    const uint64_t n_unique_kmers() const { return store->n_unique_kmers(); }

    // count number of occupied bins
    const uint64_t n_occupied() const { return store->n_occupied(); }

    // table information
    std::vector<uint64_t> get_tablesizes() const {
        return store->get_tablesizes();
    }
    const size_t n_tables() const { return store->n_tables(); }

    // return all k-mer substrings, on the forward strand.
    void get_kmers(const std::string &s, std::vector<std::string> &kmers)
    const;

    // return hash values for all k-mer substrings
    void get_kmer_hashes(const std::string &s,
                         std::vector<HashIntoType> &kmers) const;

    // return hash values for all k-mer substrings in a SeenSet
    void get_kmer_hashes_as_hashset(const std::string &s,
                                    SeenSet& hashes) const;

    // return counts of all k-mers in this string.
    void get_kmer_counts(const std::string &s,
                         std::vector<BoundedCounterType> &counts) const;

    // get access to raw tables.
    Byte ** get_raw_tables() { return store->get_raw_tables(); }

    // find the minimum k-mer count in the given sequence
    BoundedCounterType get_min_count(const std::string &s);

    // find the maximum k-mer count in the given sequence
    BoundedCounterType get_max_count(const std::string &s);

    // calculate the abundance distribution of kmers in the given file.
    uint64_t * abundance_distribution(read_parsers::IParser * parser,
                                      Hashtable * tracking);
    uint64_t * abundance_distribution(std::string filename,
                                      Hashtable * tracking);

    // return the index of the first position in the sequence with k-mer
    // abundance below min_abund.
    unsigned long trim_on_abundance(std::string seq,
                                    BoundedCounterType min_abund) const;

    // return the index of the first position in the sequence with k-mer
    // abundance above max_abund.
    unsigned long trim_below_abundance(std::string seq,
                                       BoundedCounterType max_abund) const;

    // detect likely positions of errors
    std::vector<unsigned int> find_spectral_error_positions(std::string seq,
            BoundedCounterType min_abund) const;
};

//
// Hashgraph: Extension of Hashtable to support graph operations.
//

class Hashgraph: public Hashtable {

    friend class SubsetPartition;
    friend class LabelHash;
    friend class Traverser;

protected:
    unsigned int _tag_density;

    explicit Hashgraph(WordLength ksize, Storage * s)
        : Hashtable(ksize, s)
    {
        _tag_density = DEFAULT_TAG_DENSITY;
        if (!(_tag_density % 2 == 0)) {
            throw khmer_exception();
        }
        partition = new SubsetPartition(this);
        _all_tags_spin_lock = 0;
    }

    virtual ~Hashgraph( )
    {
        delete partition;
    }

    void _clear_all_partitions()
    {
        if (partition != NULL) {
            partition->_clear_all_partitions();
        }
    }

    uint32_t _all_tags_spin_lock;
public:
    SubsetPartition * partition;
    SeenSet all_tags;
    SeenSet stop_tags;
    SeenSet repart_small_tags;

    virtual void save_tagset(std::string);
    virtual void load_tagset(std::string, bool clear_tags=true);

    void _set_tag_density(unsigned int d)
    {
        // must be odd; can't be set if tags exist.
        if (!(d % 2 == 0) || !all_tags.empty()) {
            throw khmer_exception();
        }
        _tag_density = d;
    }

    unsigned int _get_tag_density() const
    {
        return _tag_density;
    }

    void add_tag(HashIntoType tag)
    {
        all_tags.insert(tag);
    }
    void add_stop_tag(HashIntoType tag)
    {
        stop_tags.insert(tag);
    }

    // Partitioning stuff.

    size_t n_tags() const
    {
        return all_tags.size();
    }

    void divide_tags_into_subsets(unsigned int subset_size, SeenSet& divvy);

    void add_kmer_to_tags(HashIntoType kmer)
    {
        all_tags.insert(kmer);
    }

    void clear_tags()
    {
        all_tags.clear();
    }

    // Count every k-mer in a FASTA or FASTQ file.
    // Tag certain ones on the connectivity graph.
    void consume_fasta_and_tag(
        std::string const	  &filename,
        unsigned int	  &total_reads,
        unsigned long long  &n_consumed
    );

    // Count every k-mer from a stream of FASTA or FASTQ reads,
    // using the supplied parser.
    // Tag certain ones on the connectivity graph.
    void consume_fasta_and_tag(
        read_parsers:: IParser *	    parser,
        unsigned int	    &total_reads,
        unsigned long long  &n_consumed
    );

    void consume_sequence_and_tag(const std::string& seq,
                                  unsigned long long& n_consumed,
                                  SeenSet * new_tags = 0);

    void consume_partitioned_fasta(const std::string &filename,
                                   unsigned int &total_reads,
                                   unsigned long long &n_consumed);

    size_t trim_on_stoptags(std::string sequence) const;

    unsigned int traverse_from_kmer(Kmer start,
                                    unsigned int radius,
                                    KmerSet &keeper,
                                    unsigned int max_count = MAX_KEEPER_SIZE)
    const;

    virtual void print_tagset(std::string);
    virtual void print_stop_tags(std::string);
    virtual void save_stop_tags(std::string);
    void load_stop_tags(std::string filename, bool clear_tags=true);

    void extract_unique_paths(std::string seq,
                              unsigned int min_length,
                              float min_unique_f,
                              std::vector<std::string> &results);

    void calc_connected_graph_size(Kmer node,
                                   unsigned long long& count,
                                   KmerSet& keeper,
                                   const unsigned long long threshold=0,
                                   bool break_on_circum=false) const;

    unsigned int kmer_degree(HashIntoType kmer_f, HashIntoType kmer_r);
    unsigned int kmer_degree(const char * kmer_s);

    //
    void find_high_degree_nodes(const char * sequence,
                                SeenSet& high_degree_nodes) const;

    unsigned int traverse_linear_path(const Kmer start_kmer,
                                      SeenSet &adjacencies,
                                      SeenSet &nodes, Hashtable& bf,
                                      SeenSet &high_degree_nodes) const;

    //
    // for debugging/testing purposes only!
    //

    // check partition map validity.
    void _validate_pmap()
    {
        if (partition) {
            partition->_validate_pmap();
        }
    }

};

class CountingHash : public khmer::Hashgraph
{
public:
    explicit CountingHash(WordLength ksize, std::vector<uint64_t> sizes)
        : Hashgraph(ksize, new ByteStorage(sizes)) { } ;
};

class Hashbits : public Hashgraph {
public:
    explicit Hashbits(WordLength ksize, std::vector<uint64_t> sizes)
        : Hashgraph(ksize, new BitStorage(sizes)) { } ;

    void update_from(const Hashbits &other);
};
}

#define ACQUIRE_ALL_TAGS_SPIN_LOCK \
  while (!__sync_bool_compare_and_swap( &_all_tags_spin_lock, 0, 1 ));

#define RELEASE_ALL_TAGS_SPIN_LOCK \
  __sync_bool_compare_and_swap( &_all_tags_spin_lock, 1, 0 );

#endif // HASHTABLE_HH
<commit_msg>cleanup and documentation<commit_after>/*
This file is part of khmer, https://github.com/dib-lab/khmer/, and is
Copyright (C) 2010-2015, Michigan State University.
Copyright (C) 2015-2016, The Regents of the University of California.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

    * Neither the name of the Michigan State University nor the names
      of its contributors may be used to endorse or promote products
      derived from this software without specific prior written
      permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
LICENSE (END)

Contact: khmer-project@idyll.org
*/
#ifndef HASHTABLE_HH
#define HASHTABLE_HH

#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>

#include "khmer.hh"
#include "khmer_exception.hh"
#include "kmer_hash.hh"
#include "read_parsers.hh"
#include "storage.hh"

#include "traversal.hh"
#include "subset.hh"

namespace khmer
{
namespace read_parsers
{
struct IParser;
}  // namespace read_parsers
}  // namespace khmer

#define MAX_KEEPER_SIZE int(1e6)

#define next_f(kmer_f, ch) ((((kmer_f) << 2) & bitmask) | (twobit_repr(ch)))
#define next_r(kmer_r, ch) (((kmer_r) >> 2) | (twobit_comp(ch) << rc_left_shift))

#define prev_f(kmer_f, ch) ((kmer_f) >> 2 | twobit_repr(ch) << rc_left_shift)
#define prev_r(kmer_r, ch) ((((kmer_r) << 2) & bitmask) | (twobit_comp(ch)))

#define set_contains(s, e) ((s).find(e) != (s).end())

#define CALLBACK_PERIOD 100000

namespace khmer
{
class Hashtable: public
    KmerFactory  		// Base class implementation of a Bloom ht.
{
    friend class SubsetPartition;
    friend class LabelHash;

protected:
    Storage * store;
    unsigned int    _max_count;
    unsigned int    _max_bigcount;

    //WordLength	    _ksize;
    HashIntoType    bitmask;
    unsigned int    _nbits_sub_1;

    explicit Hashtable( WordLength ksize, Storage * s)
        : KmerFactory( ksize ), store(s),
          _max_count( MAX_KCOUNT ),
          _max_bigcount( MAX_BIGCOUNT )
    {
        _init_bitstuff();
    }

    virtual ~Hashtable( )
    {
        delete store;
    }

    void _init_bitstuff()
    {
        bitmask = 0;
        for (unsigned int i = 0; i < _ksize; i++) {
            bitmask = (bitmask << 2) | 3;
        }
        _nbits_sub_1 = (_ksize*2 - 2);
    }

    explicit Hashtable(const Hashtable&);
    Hashtable& operator=(const Hashtable&);

public:
    // accessor to get 'k'
    const WordLength ksize() const
    {
        return _ksize;
    }

    // various hash functions.
    inline
    virtual
    HashIntoType
    hash_dna(const char * kmer) const {
        return _hash(kmer, _ksize);
    }

    inline
    virtual
    HashIntoType
    hash_dna_top_strand(const char * kmer) const {
        HashIntoType f = 0, r = 0;
        _hash(kmer, _ksize, f, r);
        return f;
    }

    inline
    virtual
    HashIntoType
    hash_dna_bottom_strand(const char * kmer) const {
        HashIntoType f = 0, r = 0;
        _hash(kmer, _ksize, f, r);
        return r;
    }

    inline
    virtual
    std::string
    unhash_dna(HashIntoType hashval) const {
        return _revhash(hashval, _ksize);
    }

    void count(const char * kmer) { store->add(hash_dna(kmer)); }
    void count(HashIntoType khash) { store->add(khash); }
    void add(const char * kmer) { store->add(hash_dna(kmer)); }
    void add(HashIntoType khash) { store->add(khash); }

    // get the count for the given k-mer.
    const BoundedCounterType get_count(const char * kmer) const {
        return store->get_count(hash_dna(kmer));
    }
    const BoundedCounterType get_count(HashIntoType khash) const {
        return store->get_count(khash);
    }

    void save(std::string filename) {
        store->save(filename, _ksize);
    }
    void load(std::string filename) {
        store->load(filename, _ksize);
        _init_bitstuff();
    }

    // count every k-mer in the string.
    unsigned int consume_string(const std::string &s);

    // checks each read for non-ACGT characters
    bool check_and_normalize_read(std::string &read) const;

    // check each read for non-ACGT characters, and then consume it.
    unsigned int check_and_process_read(std::string &read,
                                        bool &is_valid);

    // Count every k-mer in a FASTA or FASTQ file.
    // Note: Yes, the name 'consume_fasta' is a bit misleading,
    //	     but the FASTA format is effectively a subset of the FASTQ format
    //	     and the FASTA portion is what we care about in this case.
    void consume_fasta(
        std::string const   &filename,
        unsigned int	    &total_reads,
        unsigned long long  &n_consumed
    );

    // Count every k-mer from a stream of FASTA or FASTQ reads,
    // using the supplied parser.
    void consume_fasta(
        read_parsers:: IParser *	    parser,
        unsigned int	    &total_reads,
        unsigned long long  &n_consumed
    );

    void set_use_bigcount(bool b) { store->set_use_bigcount(b); }
    bool get_use_bigcount() { return store->get_use_bigcount(); }

    bool median_at_least(const std::string &s,
                         unsigned int cutoff);

    void get_median_count(const std::string &s,
                          BoundedCounterType &median,
                          float &average,
                          float &stddev);

    // number of unique k-mers
    const uint64_t n_unique_kmers() const { return store->n_unique_kmers(); }

    // count number of occupied bins
    const uint64_t n_occupied() const { return store->n_occupied(); }

    // table information
    std::vector<uint64_t> get_tablesizes() const {
        return store->get_tablesizes();
    }
    const size_t n_tables() const { return store->n_tables(); }

    // return all k-mer substrings, on the forward strand.
    void get_kmers(const std::string &s, std::vector<std::string> &kmers)
    const;

    // return hash values for all k-mer substrings
    void get_kmer_hashes(const std::string &s,
                         std::vector<HashIntoType> &kmers) const;

    // return hash values for all k-mer substrings in a SeenSet
    void get_kmer_hashes_as_hashset(const std::string &s,
                                    SeenSet& hashes) const;

    // return counts of all k-mers in this string.
    void get_kmer_counts(const std::string &s,
                         std::vector<BoundedCounterType> &counts) const;

    // get access to raw tables.
    Byte ** get_raw_tables() { return store->get_raw_tables(); }

    // find the minimum k-mer count in the given sequence
    BoundedCounterType get_min_count(const std::string &s);

    // find the maximum k-mer count in the given sequence
    BoundedCounterType get_max_count(const std::string &s);

    // calculate the abundance distribution of kmers in the given file.
    uint64_t * abundance_distribution(read_parsers::IParser * parser,
                                      Hashtable * tracking);
    uint64_t * abundance_distribution(std::string filename,
                                      Hashtable * tracking);

    // return the index of the first position in the sequence with k-mer
    // abundance below min_abund.
    unsigned long trim_on_abundance(std::string seq,
                                    BoundedCounterType min_abund) const;

    // return the index of the first position in the sequence with k-mer
    // abundance above max_abund.
    unsigned long trim_below_abundance(std::string seq,
                                       BoundedCounterType max_abund) const;

    // detect likely positions of errors
    std::vector<unsigned int> find_spectral_error_positions(std::string seq,
            BoundedCounterType min_abund) const;
};

//
// Hashgraph: Extension of Hashtable to support graph operations.
//

class Hashgraph: public Hashtable {

    friend class SubsetPartition;
    friend class LabelHash;
    friend class Traverser;

protected:
    unsigned int _tag_density;

    explicit Hashgraph(WordLength ksize, Storage * s)
        : Hashtable(ksize, s)
    {
        _tag_density = DEFAULT_TAG_DENSITY;
        if (!(_tag_density % 2 == 0)) {
            throw khmer_exception();
        }
        partition = new SubsetPartition(this);
        _all_tags_spin_lock = 0;
    }

    // clean up the partition structure.
    virtual ~Hashgraph( )
    {
        delete partition;
    }

    // empty the partition structure
    void _clear_all_partitions()
    {
        if (partition != NULL) {
            partition->_clear_all_partitions();
        }
    }

    uint32_t _all_tags_spin_lock;
public:
    // default master partitioning
    SubsetPartition * partition;

    // tags for sparse graph implementation
    SeenSet all_tags;

    // tags at which to stop traversal
    SeenSet stop_tags;

    // tags used in repartitioning
    SeenSet repart_small_tags;

    // set the minimum density of tagging.
    void _set_tag_density(unsigned int d)
    {
        // must be odd; can't be set if tags exist.
        if (!(d % 2 == 0) || !all_tags.empty()) {
            throw khmer_exception();
        }
        _tag_density = d;
    }

    unsigned int _get_tag_density() const { return _tag_density; }

    void add_tag(HashIntoType tag) { all_tags.insert(tag); }
    void add_stop_tag(HashIntoType tag) { stop_tags.insert(tag); }
    }

    size_t n_tags() const { return all_tags.size(); }

    void divide_tags_into_subsets(unsigned int subset_size, SeenSet& divvy);

    void add_kmer_to_tags(HashIntoType kmer) { all_tags.insert(kmer); }

    void clear_tags() { all_tags.clear(); }

    // Consume reads & build sparse graph.
    void consume_fasta_and_tag(
        std::string const &filename,
        unsigned int &total_reads,
        unsigned long long &n_consumed
    );

    // Count every k-mer from a stream of FASTA or FASTQ reads,
    // using the supplied parser.
    // Tag certain ones on the connectivity graph.
    void consume_fasta_and_tag(
        read_parsers:: IParser * parser,
        unsigned int &total_reads,
        unsigned long long &n_consumed
    );

    // consume a string & add sparse graph nodes.
    void consume_sequence_and_tag(const std::string& seq,
                                  unsigned long long& n_consumed,
                                  SeenSet * new_tags = 0);

    // consume an already-partitioned file & load in the partition IDs
    void consume_partitioned_fasta(const std::string &filename,
                                   unsigned int &total_reads,
                                   unsigned long long &n_consumed);

    // trim the given sequence on stoptags
    size_t trim_on_stoptags(std::string sequence) const;

    // @@
    unsigned int traverse_from_kmer(Kmer start,
                                    unsigned int radius,
                                    KmerSet &keeper,
                                    unsigned int max_count = MAX_KEEPER_SIZE)
    const;

    // print, save, and load the set of tags.
    void print_tagset(std::string);
    void save_tagset(std::string);
    void load_tagset(std::string, bool clear_tags=true);

    // print, save and load the set of stop tags.
    void print_stop_tags(std::string);
    void save_stop_tags(std::string);
    void load_stop_tags(std::string filename, bool clear_tags=true);

    // @@
    void extract_unique_paths(std::string seq,
                              unsigned int min_length,
                              float min_unique_f,
                              std::vector<std::string> &results);

    // @@
    void calc_connected_graph_size(Kmer node,
                                   unsigned long long& count,
                                   KmerSet& keeper,
                                   const unsigned long long threshold=0,
                                   bool break_on_circum=false) const;

    // Calculate the graph degree of the given k-mer.
    unsigned int kmer_degree(HashIntoType kmer_f, HashIntoType kmer_r);
    unsigned int kmer_degree(const char * kmer_s);

    // Find all nodes with a degree > 2.
    void find_high_degree_nodes(const char * sequence,
                                SeenSet& high_degree_nodes) const;

    // Find the maximal linear path (nodes degree <= 2)
    unsigned int traverse_linear_path(const Kmer start_kmer,
                                      SeenSet &adjacencies,
                                      SeenSet &nodes, Hashtable& bf,
                                      SeenSet &high_degree_nodes) const;

    //
    // for debugging/testing purposes only!
    //

    // check partition map validity.
    void _validate_pmap()
    {
        if (partition) {
            partition->_validate_pmap();
        }
    }

};

class CountingHash : public khmer::Hashgraph
{
public:
    explicit CountingHash(WordLength ksize, std::vector<uint64_t> sizes)
        : Hashgraph(ksize, new ByteStorage(sizes)) { } ;
};

class Hashbits : public Hashgraph {
public:
    explicit Hashbits(WordLength ksize, std::vector<uint64_t> sizes)
        : Hashgraph(ksize, new BitStorage(sizes)) { } ;

    void update_from(const Hashbits &other);
};
}

#define ACQUIRE_ALL_TAGS_SPIN_LOCK \
  while (!__sync_bool_compare_and_swap( &_all_tags_spin_lock, 0, 1 ));

#define RELEASE_ALL_TAGS_SPIN_LOCK \
  __sync_bool_compare_and_swap( &_all_tags_spin_lock, 1, 0 );

#endif // HASHTABLE_HH
<|endoftext|>


<commit_before>#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){

    ofSetFrameRate(60);
    ofEnableAntiAliasing();

    // setup font
    fontsize = 320;
    font.load("mono.ttf", fontsize, true, false, true, 0.1);
    font.setLetterSpacing(1.03);

    // default settings
    counter = 0;
    prevTime = 0;
    interval = 500;
    backgroundWhite = true;
    scale = 0.5;

    // load text file into buffer and parse into lines (vector of strings)
    // text from http://bloom0101.org/?parution=to-our-friends
    buffer = ofBufferFromFile("letsdisappear.txt");
    for(auto line: buffer.getLines()){
        words.push_back(line);
    }
    buffer.clear();
}

//--------------------------------------------------------------
void ofApp::update(){

    // minimum interval (how fast this thing can go)
//    if (interval < 50) {
//        interval = 50;
//    }

    // increment the line counter, if elapsed time from previously registered time is greater than set interval
    if (ofGetElapsedTimeMillis() >= interval) {
        if (prevTime <= ofGetElapsedTimeMillis() - interval) {
            prevTime = ofGetElapsedTimeMillis();
            counter++;

            // if line is blank, skip it
            while (words[counter] == "") {
                counter++;
            }

            // reset counter when end is reached
            if (counter >= words.size()) counter = 0;

            // add some random to interval
            float weight = ofRandom(0,1);
            interval = 500 - (250 * weight);

        }
    }

    // set font size so that each string fits to screen width in one line
    float w = font.stringWidth(words[counter]);
    scale = ofGetWidth()*0.97 / w;

    // if line is longer than x, split it into a new vector of strings and display each string

}

//--------------------------------------------------------------
void ofApp::draw(){

    // toggle color
    if (backgroundWhite) {
        ofSetBackgroundColor(255);
        ofSetColor(0);
    } else {
        ofSetBackgroundColor(0);
        ofSetColor(255);
    }

    // see method definition
    drawCross();

    // go to center of screen; draw strings
    // code modified from https://forum.openframeworks.cc/t/oftruetypefont-dynamic-sizing/14977/2 and https://forum.openframeworks.cc/t/oftruetypefont-issue/14928/2
    ofPushMatrix();
        ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
        ofScale(scale, scale, 1);

        string text = words[counter];
        float fontWidth = font.stringWidth(text);
        float fontHeight = font.stringHeight(text);
        font.drawStringAsShapes(text, -fontWidth/2, fontHeight/4);

        // draw counter
        string c = "line " + ofToString(counter);
        float counterWidth = font.stringWidth(c);
        ofSetColor(127);
        font.drawStringAsShapes(c, -counterWidth/2, -ofGetHeight());

    ofPopMatrix();
}

// draw a horizontal and a vertical line across the center of screen
void ofApp::drawCross() {
    ofDrawLine(0,ofGetHeight()/2,ofGetWidth(),ofGetHeight()/2);
    ofDrawLine(ofGetWidth()/2,0,ofGetWidth()/2,ofGetHeight());
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

    // some controls
    if (key == 'b') backgroundWhite = !backgroundWhite;
    if (key == OF_KEY_UP) interval += 10; cout << interval << endl;
    if (key == OF_KEY_DOWN) interval -= 10; cout << interval << endl;
    if (key == OF_KEY_RIGHT) scale *= 1.1;
    if (key == OF_KEY_LEFT) scale *= 0.9;

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<commit_msg>now couts interval for every line<commit_after>#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){

    ofSetFrameRate(60);
    ofEnableAntiAliasing();

    // setup font
    fontsize = 320;
    font.load("mono.ttf", fontsize, true, false, true, 0.1);
    font.setLetterSpacing(1.03);

    // default settings
    counter = 0;
    prevTime = 0;
    interval = 500;
    backgroundWhite = true;
    scale = 0.5;

    // load text file into buffer and parse into lines (vector of strings)
    // text from http://bloom0101.org/?parution=to-our-friends
    buffer = ofBufferFromFile("letsdisappear.txt");
    for(auto line: buffer.getLines()){
        words.push_back(line);
    }
    buffer.clear();
}

//--------------------------------------------------------------
void ofApp::update(){

    // minimum interval (how fast this thing can go)
//    if (interval < 50) {
//        interval = 50;
//    }

    // increment the line counter, if elapsed time from previously registered time is greater than set interval
    if (ofGetElapsedTimeMillis() >= interval) {
        if (prevTime <= ofGetElapsedTimeMillis() - interval) {
            prevTime = ofGetElapsedTimeMillis();
            counter++;

            // if line is blank, skip it
            while (words[counter] == "") {
                counter++;
            }

            // reset counter when end is reached
            if (counter >= words.size()) counter = 0;

            // add some random to interval
            float weight = ofRandom(0,1);
            interval = 500 - (250 * weight);
            cout << interval << endl;

        }
    }

    // set font size so that each string fits to screen width in one line
    float w = font.stringWidth(words[counter]);
    scale = ofGetWidth()*0.97 / w;

    // if line is longer than x, split it into a new vector of strings and display each string

}

//--------------------------------------------------------------
void ofApp::draw(){

    // toggle color
    if (backgroundWhite) {
        ofSetBackgroundColor(255);
        ofSetColor(0);
    } else {
        ofSetBackgroundColor(0);
        ofSetColor(255);
    }

    // see method definition
    drawCross();

    // go to center of screen; draw strings
    // code modified from https://forum.openframeworks.cc/t/oftruetypefont-dynamic-sizing/14977/2 and https://forum.openframeworks.cc/t/oftruetypefont-issue/14928/2
    ofPushMatrix();
        ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
        ofScale(scale, scale, 1);

        string text = words[counter];
        float fontWidth = font.stringWidth(text);
        float fontHeight = font.stringHeight(text);
        font.drawStringAsShapes(text, -fontWidth/2, fontHeight/4);

        // draw counter
        string c = "line " + ofToString(counter);
        float counterWidth = font.stringWidth(c);
        ofSetColor(127);
        font.drawStringAsShapes(c, -counterWidth/2, -ofGetHeight());

    ofPopMatrix();
}

// draw a horizontal and a vertical line across the center of screen
void ofApp::drawCross() {
    ofDrawLine(0,ofGetHeight()/2,ofGetWidth(),ofGetHeight()/2);
    ofDrawLine(ofGetWidth()/2,0,ofGetWidth()/2,ofGetHeight());
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

    // some controls
    if (key == 'b') backgroundWhite = !backgroundWhite;
//    if (key == OF_KEY_UP) {
//        interval += 10;
//        cout << interval << endl;
//    }
//    if (key == OF_KEY_DOWN) {
//        interval -= 10;
//        cout << interval << endl;
//    }
//    if (key == OF_KEY_RIGHT) scale *= 1.1;
//    if (key == OF_KEY_LEFT) scale *= 0.9;

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<|endoftext|>